diff --git a/dist/css/ueblueprint-node-value-type-color.css b/dist/css/ueblueprint-node-value-type-color.css old mode 100644 new mode 100755 diff --git a/dist/css/ueblueprint-node-value-type-color.css.map b/dist/css/ueblueprint-node-value-type-color.css.map old mode 100644 new mode 100755 diff --git a/dist/css/ueblueprint-style.css b/dist/css/ueblueprint-style.css old mode 100644 new mode 100755 diff --git a/dist/css/ueblueprint-style.css.map b/dist/css/ueblueprint-style.css.map old mode 100644 new mode 100755 diff --git a/dist/font/roboto-bold.woff b/dist/font/roboto-bold.woff old mode 100644 new mode 100755 diff --git a/dist/font/roboto-bold.woff2 b/dist/font/roboto-bold.woff2 old mode 100644 new mode 100755 diff --git a/dist/font/roboto-light.woff b/dist/font/roboto-light.woff old mode 100644 new mode 100755 diff --git a/dist/font/roboto-light.woff2 b/dist/font/roboto-light.woff2 old mode 100644 new mode 100755 diff --git a/dist/font/roboto-regular.woff b/dist/font/roboto-regular.woff old mode 100644 new mode 100755 diff --git a/dist/font/roboto-regular.woff2 b/dist/font/roboto-regular.woff2 old mode 100644 new mode 100755 diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js old mode 100644 new mode 100755 index d0781fa..7e49c7b --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -302,20 +302,30 @@ class FastSelectionModel { } +/** + * @typedef {import("../Blueprint").default} Blueprint + * @typedef {import("../entity/Entity").default} Entity + * @typedef {import("../input/Context").default} Context + * @typedef {import("../template/Template").default} Template + */ + class GraphElement extends HTMLElement { /** * - * @param {import("../template/Template").default} template The template to render this node + * @param {Entity} entity The entity containing blueprint related data for this graph element + * @param {Template} template The template to render this node */ constructor(entity, template) { super(); - /** @type {import("../Blueprint").default}" */ + /** @type {Blueprint}" */ this.blueprint = null; - /** @type {import("../entity/Entity").default}" */ + /** @type {Entity}" */ this.entity = entity; - /** @type {import("../template/Template").default}" */ + /** @type {Template}" */ this.template = template; + /** @type {Context[]} */ + this.inputObjects = []; } getTemplate() { @@ -325,9 +335,15 @@ class GraphElement extends HTMLElement { connectedCallback() { this.blueprint = this.closest("ueb-blueprint"); this.template.apply(this); + this.inputObjects = this.createInputObjects(); } disconnectedCallback() { + this.inputObjects.forEach(v => v.unlistenDOMElement()); + } + + createInputObjects() { + return [] } } @@ -569,6 +585,14 @@ class BlueprintTemplate extends Template { } } +class Configuration { + + static deleteNodesKeyboardKey = "Delete" + static expandGridSize = 400 + static gridSize = 16 + static gridSnap = 16 +} + class Context { constructor(target, blueprint, options) { @@ -577,19 +601,19 @@ class Context { /** @type {import("../Blueprint").default}" */ this.blueprint = blueprint; this.options = options; + let self = this; + this.blueprintFocusHandler = _ => self.blueprintFocused(); + this.blueprintUnfocusHandler = _ => self.blueprintUnfocused(); if (options?.wantsFocusCallback ?? false) { - let self = this; - this.blueprintfocusHandler = _ => self.blueprintFocused(); - this.blueprintunfocusHandler = _ => self.blueprintUnfocused(); - this.blueprint.addEventListener("blueprintfocus", this.blueprintfocusHandler); - this.blueprint.addEventListener("blueprintunfocus", this.blueprintunfocusHandler); + this.blueprint.addEventListener("blueprint-focus", this.blueprintFocusHandler); + this.blueprint.addEventListener("blueprint-unfocus", this.blueprintUnfocusHandler); } } unlistenDOMElement() { this.blueprintUnfocused(); - this.blueprint.removeEventListener("blueprintfocus", this.blueprintfocusHandler); - this.blueprint.removeEventListener("blueprintunfocus", this.blueprintunfocusHandler); + this.blueprint.removeEventListener("blueprint-focus", this.blueprintFocusHandler); + this.blueprint.removeEventListener("blueprint-unfocus", this.blueprintUnfocusHandler); } @@ -883,6 +907,7 @@ class PinReferenceEntity extends Entity { class PinEntity$1 extends Entity { + static lookbehind = "Pin" static attributes = { PinId: GuidEntity, PinName: "", @@ -1099,25 +1124,28 @@ class Grammar { } } // Meta grammar - static CreateAttributeGrammar = (r, attributeGrammar, attributeSupplier, valueSeparator = P.string("=").trim(P.optWhitespace)) => - attributeGrammar.skip(valueSeparator) + static CreateAttributeGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) => + r.AttributeName.skip(valueSeparator) .chain(attributeName => { const attributeKey = attributeName.split("."); - const attribute = attributeSupplier(attributeKey); + const attribute = Utility.objectGet(entityType.attributes, attributeKey); let attributeValueGrammar = Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue); + // Returns attributeSetter: a function called with an object as argument that will set the correct attribute value return attributeValueGrammar.map(attributeValue => entity => Utility.objectSet(entity, attributeKey, attributeValue, true) - ) // returns attributeSetter: a function called with an object as argument that will set the correct attribute value + ) }) // Meta grammar - static CreateMultiAttributeGrammar = (r, keyGrammar, entityType, attributeSupplier) => + static CreateMultiAttributeGrammar = (r, entityType) => /** * Basically this creates a parser that looks for a string like 'Key (A=False,B="Something",)' * Then it populates an object of type EntityType with the attribute values found inside the parentheses. */ P.seqMap( - P.seq(keyGrammar, P.optWhitespace, P.string("(")), - Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeSupplier) + entityType.lookbehind + ? P.seq(P.string(entityType.lookbehind), P.optWhitespace, P.string("(")) + : P.string("("), + Grammar.CreateAttributeGrammar(r, entityType) .trim(P.optWhitespace) .sepBy(P.string(",")) .skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma @@ -1127,18 +1155,8 @@ class Grammar { attributes.forEach(attributeSetter => attributeSetter(result)); return result }) - FunctionReference = r => Grammar.CreateMultiAttributeGrammar( - r, - P.succeed(), - FunctionReferenceEntity, - attributeKey => Utility.objectGet(FunctionReferenceEntity.attributes, attributeKey) - ) - Pin = r => Grammar.CreateMultiAttributeGrammar( - r, - P.string("Pin"), - PinEntity$1, - attributeKey => Utility.objectGet(PinEntity$1.attributes, attributeKey) - ) + FunctionReference = r => Grammar.CreateMultiAttributeGrammar(r, FunctionReferenceEntity) + Pin = r => Grammar.CreateMultiAttributeGrammar(r, PinEntity$1) CustomProperties = r => P.string("CustomProperties") .then(P.whitespace) @@ -1155,7 +1173,7 @@ class Grammar { P .alt( r.CustomProperties, - Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeKey => Utility.objectGet(ObjectEntity.attributes, attributeKey)) + Grammar.CreateAttributeGrammar(r, ObjectEntity) ) .sepBy1(P.whitespace), P.seq(r.WhitespaceNewline, P.string("End"), P.whitespace, P.string("Object")), @@ -1317,15 +1335,15 @@ class Copy extends Context { super(target, blueprint, options); this.serializer = new ObjectSerializer(); let self = this; - this.copyHandle = _ => self.copied(); + this.copyHandler = _ => self.copied(); } blueprintFocused() { - document.body.addEventListener("copy", this.copyHandle); + document.body.addEventListener("copy", this.copyHandler); } blueprintUnfocused() { - document.body.removeEventListener("copy", this.copyHandle); + document.body.removeEventListener("copy", this.copyHandler); } copied() { @@ -1476,99 +1494,50 @@ class DragScroll extends MouseClickDrag { } } -class KeyboardShortcut extends Context { +/** + * @typedef {import("../graph/GraphLink").default} GraphLink + */ +class LinkTemplate extends Template { - constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true; - super(target, blueprint, options); - - /** @type {String[]} */ - this.key = this.options.key; - this.ctrlKey = options.ctrlKey ?? false; - this.shiftKey = options.shiftKey ?? false; - this.altKey = options.altKey ?? false; - this.metaKey = options.metaKey ?? false; - - let self = this; - this.keyDownHandler = e => { - if ( - e.code == self.key - && e.ctrlKey === self.ctrlKey - && e.shiftKey === self.shiftKey - && e.altKey === self.altKey - && e.metaKey === self.metaKey - ) { - self.fire(); - } - }; + /** + * Computes the html content of the target element. + * @param {GraphLink} link Link connecting two graph nodes + * @returns The result html + */ + render(link) { + return html` + + + + ` } /** - * - * @param {String} keyString - * @returns {Object} + * Applies the style to the element. + * @param {GraphLink} link Element of the graph */ - static keyOptionsParse(options, keyString) { - options.key = keyString; - return options - } + apply(link) { + super.apply(link); - blueprintFocused() { - document.addEventListener("keydown", this.keyDownHandler); } - blueprintUnfocused() { - document.removeEventListener("keydown", this.keyDownHandler); - } - - fire() { - } -} - -class Configuration { - - static deleteNodesKeyboardKey = "Delete" - static expandGridSize = 400 - static gridSize = 16 - static gridSnap = 16 -} - -class KeyvoardCanc extends KeyboardShortcut { - /** - * - * @param {HTMLElement} target - * @param {import("../Blueprint").default} blueprint - * @param {OBject} options + * Applies the style relative to the source pin location. + * @param {GraphLink} link Link element */ - constructor(target, blueprint, options = {}) { - options = KeyboardShortcut.keyOptionsParse(options, Configuration.deleteNodesKeyboardKey); - super(target, blueprint, options); + applySourceLocation(link, initialPosition) { + // Set initial position + link.style.setProperty("--ueb-link-from-x", sanitizeText(initialPosition[0])); + link.style.setProperty("--ueb-link-from-y", sanitizeText(initialPosition[1])); } - fire() { - this.blueprint.removeGraphElement(...this.blueprint.getNodes(true)); - } -} - -class MouseTracking extends Pointing { - - constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true; - super(target, blueprint, options); - - let self = this; - this.mousemoveHandler = e => { - self.blueprint.entity.mousePosition = self.getLocation(e); - }; - } - - blueprintFocused() { - this.target.addEventListener("mousemove", this.mousemoveHandler); - } - - blueprintUnfocused() { - this.target.removeEventListener("mousemove", this.mousemoveHandler); + /** + * Applies the style relative to the destination pin location. + * @param {GraphLink} link Link element + */ + applyDestinationLocation(link, finalPosition) { + link.style.setProperty("--ueb-link-to-x", sanitizeText(finalPosition[0])); + link.style.setProperty("--ueb-link-to-y", sanitizeText(finalPosition[1])); } } @@ -1631,112 +1600,6 @@ class DragLink extends MouseClickDrag { } } -/** - * @typedef {import("../graph/GraphLink").default} GraphLink - */ -class LinkTemplate extends Template { - - /** - * Computes the html content of the target element. - * @param {GraphLink} link Link connecting two graph nodes - * @returns The result html - */ - render(link) { - return html` - - - - ` - } - - /** - * Applies the style to the element. - * @param {GraphLink} link Element of the graph - */ - apply(link) { - super.apply(link); - - } - - /** - * Applies the style relative to the source pin location. - * @param {GraphLink} link Link element - */ - applySourceLocation(link, initialPosition) { - // Set initial position - link.style.setProperty("--ueb-link-from-x", sanitizeText(initialPosition[0])); - link.style.setProperty("--ueb-link-from-y", sanitizeText(initialPosition[1])); - } - - /** - * Applies the style relative to the destination pin location. - * @param {GraphLink} link Link element - */ - applyDestinationLocation(link, finalPosition) { - link.style.setProperty("--ueb-link-to-x", sanitizeText(finalPosition[0])); - link.style.setProperty("--ueb-link-to-y", sanitizeText(finalPosition[1])); - } -} - -/** - * @type {import("./GraphPin").default} GraphPin - */ -class GraphLink extends GraphElement { - - /** @type {GraphPin} */ - #source - /** @type {GraphPin} */ - #destination - #nodeDeleteHandler = _ => this.blueprint.removeGraphElement(this) - #nodeDragSourceHandler = _ => this.setSourceLocation(this.#source.getLinkLocation()) - #nodeDragDestinatonHandler = _ => this.setDestinationLocation(this.#destination.getLinkLocation()) - - /** - * @param {?GraphPin} source - * @param {?GraphPin} destination - */ - constructor(source, destination) { - super(this, new LinkTemplate()); - /** @type {import("../template/LinkTemplate").default} */ - this.template; - this.setSource(source); - this.setDestination(destination); - } - - setSourceLocation(location) { - this.template.applySourceLocation(this.#source.getLinkLocation()); - } - - setDestinationLocation(location) { - this.template.applyDestinationLocation(this.#destination.getLinkLocation()); - } - - /** - * @param {GraphPin} graphPin - */ - setSourcePin(graphPin) { - this.#source?.removeEventListener("ueb-node-delete", this.#nodeDeleteHandler); - this.#source?.removeEventListener("ueb-node-drag", this.#nodeDragSourceHandler); - this.#source = graphPin; - this.#source?.addEventListener("ueb-node-delete", this.#nodeDeleteHandler); - this.#source?.addEventListener("ueb-node-drag", this.#nodeDragSourceHandler); - } - - /** - * - * @param {GraphPin} graphPin - */ - setDestinationPin(graphPin) { - this.#destination?.removeEventListener("ueb-node-delete", this.#nodeDeleteHandler); - this.#destination?.removeEventListener("ueb-node-drag", this.#nodeDragDestinatonHandler); - this.#destination = graphPin; - this.#destination?.addEventListener("ueb-node-delete", this.#nodeDeleteHandler); - this.#destination?.addEventListener("ueb-node-drag", this.#nodeDragDestinatonHandler); - } -} - -customElements.define("ueb-link", GraphLink); - class GraphPin extends GraphElement { constructor(entity) { @@ -1747,11 +1610,12 @@ class GraphPin extends GraphElement { this.clickableElement = null; } - connectedCallback() { - super.connectedCallback(); - new DragLink(this.clickableElement, this.blueprint, { - moveEverywhere: true - }); + createInputObjects() { + return [ + new DragLink(this.clickableElement, this.blueprint, { + moveEverywhere: true + }), + ] } /** @@ -1802,6 +1666,65 @@ class GraphPin extends GraphElement { customElements.define("ueb-pin", GraphPin); +/** + * @type {import("./GraphPin").default} GraphPin + */ +class GraphLink extends GraphElement { + + /** @type {GraphPin} */ + #source + /** @type {GraphPin} */ + #destination + #nodeDeleteHandler = _ => this.blueprint.removeGraphElement(this) + #nodeDragSourceHandler = _ => this.setSourceLocation(this.#source.getLinkLocation()) + #nodeDragDestinatonHandler = _ => this.setDestinationLocation(this.#destination.getLinkLocation()) + + /** + * @param {?GraphPin} source + * @param {?GraphPin} destination + */ + constructor(source, destination) { + super(this, new LinkTemplate()); + /** @type {import("../template/LinkTemplate").default} */ + this.template; + this.setSource(source); + this.setDestination(destination); + } + + setSourceLocation(location) { + this.template.applySourceLocation(this.#source.getLinkLocation()); + } + + setDestinationLocation(location) { + this.template.applyDestinationLocation(this.#destination.getLinkLocation()); + } + + /** + * @param {GraphPin} graphPin + */ + setSourcePin(graphPin) { + this.#source?.removeEventListener("ueb-node-delete", this.#nodeDeleteHandler); + this.#source?.removeEventListener("ueb-node-drag", this.#nodeDragSourceHandler); + this.#source = graphPin; + this.#source?.addEventListener("ueb-node-delete", this.#nodeDeleteHandler); + this.#source?.addEventListener("ueb-node-drag", this.#nodeDragSourceHandler); + } + + /** + * + * @param {GraphPin} graphPin + */ + setDestinationPin(graphPin) { + this.#destination?.removeEventListener("ueb-node-delete", this.#nodeDeleteHandler); + this.#destination?.removeEventListener("ueb-node-drag", this.#nodeDragDestinatonHandler); + this.#destination = graphPin; + this.#destination?.addEventListener("ueb-node-delete", this.#nodeDeleteHandler); + this.#destination?.addEventListener("ueb-node-drag", this.#nodeDragDestinatonHandler); + } +} + +customElements.define("ueb-link", GraphLink); + /** * @typedef {import("../graph/SelectableDraggable").default} SelectableDraggable */ @@ -1956,16 +1879,12 @@ class SelectableDraggable extends GraphElement { }; } - connectedCallback() { - super.connectedCallback(); - this.dragObject = new DragMove(this, this.blueprint, { - looseTarget: true - }); - } - - disconnectedCallback() { - super.disconnectedCallback(); - this.dragObject.unlistenDOMElement(); + createInputObjects() { + return [ + new DragMove(this, this.blueprint, { + looseTarget: true + }), + ] } setLocation(value = [0, 0]) { @@ -2025,10 +1944,6 @@ class GraphNode extends SelectableDraggable { return new GraphNode(entity) } - connectedCallback() { - super.connectedCallback(); - } - disconnectedCallback() { super.disconnectedCallback(); this.dispatchDeleteEvent(); @@ -2065,6 +1980,94 @@ class GraphNode extends SelectableDraggable { customElements.define("ueb-node", GraphNode); +class KeyboardShortcut extends Context { + + constructor(target, blueprint, options = {}) { + options.wantsFocusCallback = true; + super(target, blueprint, options); + + /** @type {String[]} */ + this.key = this.options.key; + this.ctrlKey = options.ctrlKey ?? false; + this.shiftKey = options.shiftKey ?? false; + this.altKey = options.altKey ?? false; + this.metaKey = options.metaKey ?? false; + + let self = this; + this.keyDownHandler = e => { + if ( + e.code == self.key + && e.ctrlKey === self.ctrlKey + && e.shiftKey === self.shiftKey + && e.altKey === self.altKey + && e.metaKey === self.metaKey + ) { + self.fire(); + } + }; + } + + /** + * + * @param {String} keyString + * @returns {Object} + */ + static keyOptionsParse(options, keyString) { + options.key = keyString; + return options + } + + blueprintFocused() { + document.addEventListener("keydown", this.keyDownHandler); + } + + blueprintUnfocused() { + document.removeEventListener("keydown", this.keyDownHandler); + } + + fire() { + } +} + +class KeyvoardCanc extends KeyboardShortcut { + + /** + * + * @param {HTMLElement} target + * @param {import("../Blueprint").default} blueprint + * @param {OBject} options + */ + constructor(target, blueprint, options = {}) { + options = KeyboardShortcut.keyOptionsParse(options, Configuration.deleteNodesKeyboardKey); + super(target, blueprint, options); + } + + fire() { + this.blueprint.removeGraphElement(...this.blueprint.getNodes(true)); + } +} + +class MouseTracking extends Pointing { + + constructor(target, blueprint, options = {}) { + options.wantsFocusCallback = true; + super(target, blueprint, options); + + let self = this; + this.mousemoveHandler = e => { + self.blueprint.entity.mousePosition = self.getLocation(e); + }; + } + + blueprintFocused() { + this.target.addEventListener("mousemove", this.mousemoveHandler); + } + + blueprintUnfocused() { + this.target.removeEventListener("mousemove", this.mousemoveHandler); + } +} + class Paste extends Context { constructor(target, blueprint, options = {}) { @@ -2299,30 +2302,28 @@ class Blueprint extends GraphElement { this.template.applyTranlate(this); } - connectedCallback() { - super.connectedCallback(); - - this.copyObject = new Copy(this.getGridDOMElement(), this); - this.pasteObject = new Paste(this.getGridDOMElement(), this); - this.cancObject = new KeyvoardCanc(this.getGridDOMElement(), this); - - this.zoomObject = new Zoom(this.getGridDOMElement(), this, { - looseTarget: true, - }); - this.selectObject = new Select(this.getGridDOMElement(), this, { - clickButton: 0, - exitAnyButton: true, - moveEverywhere: true, - }); - this.dragObject = new DragScroll(this.getGridDOMElement(), this, { - clickButton: 2, - exitAnyButton: false, - looseTarget: true, - moveEverywhere: true, - }); - - this.unfocusObject = new Unfocus(this.getGridDOMElement(), this); - this.mouseTrackingObject = new MouseTracking(this.getGridDOMElement(), this); + createInputObjects() { + return [ + new Copy(this.getGridDOMElement(), this), + new Paste(this.getGridDOMElement(), this), + new KeyvoardCanc(this.getGridDOMElement(), this), + new Zoom(this.getGridDOMElement(), this, { + looseTarget: true, + }), + new Select(this.getGridDOMElement(), this, { + clickButton: 0, + exitAnyButton: true, + moveEverywhere: true, + }), + new DragScroll(this.getGridDOMElement(), this, { + clickButton: 2, + exitAnyButton: false, + looseTarget: true, + moveEverywhere: true, + }), + new Unfocus(this.getGridDOMElement(), this), + new MouseTracking(this.getGridDOMElement(), this), + ] } getGridDOMElement() { @@ -2332,9 +2333,6 @@ class Blueprint extends GraphElement { disconnectedCallback() { super.disconnectedCallback(); setSelected(false); - this.dragObject.unlistenDOMElement(); - this.selectObject.unlistenDOMElement(); - this.pasteObject.unlistenDOMElement(); } getScroll() { @@ -2570,7 +2568,7 @@ class Blueprint extends GraphElement { if (this.focused == value) { return; } - let event = new CustomEvent(value ? "blueprintfocus" : "blueprintunfocus"); + let event = new CustomEvent(value ? "blueprint-focus" : "blueprint-unfocus"); this.focused = value; this.dataset.focused = this.focused; if (!this.focused) { diff --git a/font/roboto-bold.woff b/font/roboto-bold.woff old mode 100644 new mode 100755 diff --git a/font/roboto-bold.woff2 b/font/roboto-bold.woff2 old mode 100644 new mode 100755 diff --git a/font/roboto-light.woff b/font/roboto-light.woff old mode 100644 new mode 100755 diff --git a/font/roboto-light.woff2 b/font/roboto-light.woff2 old mode 100644 new mode 100755 diff --git a/font/roboto-regular.woff b/font/roboto-regular.woff old mode 100644 new mode 100755 diff --git a/font/roboto-regular.woff2 b/font/roboto-regular.woff2 old mode 100644 new mode 100755 diff --git a/js/Blueprint.js b/js/Blueprint.js index d937759..01e508a 100755 --- a/js/Blueprint.js +++ b/js/Blueprint.js @@ -1,7 +1,10 @@ import BlueprintTemplate from "./template/BlueprintTemplate" +import Configuration from "./Configuration" import Copy from "./input/Copy" import DragScroll from "./input/DragScroll" import GraphElement from "./graph/GraphElement" +import GraphLink from "./graph/GraphLink" +import GraphNode from "./graph/GraphNode" import GraphSelector from "./graph/GraphSelector" import KeyboardCanc from "./input/KeyboardCanc" import MouseTracking from "./input/MouseTracking" @@ -10,9 +13,6 @@ import Select from "./input/Select" import Unfocus from "./input/Unfocus" import Utility from "./Utility" import Zoom from "./input/Zoom" -import GraphNode from "./graph/GraphNode" -import GraphLink from "./graph/GraphLink" -import Configuration from "./Configuration" export default class Blueprint extends GraphElement { @@ -93,30 +93,28 @@ export default class Blueprint extends GraphElement { this.template.applyTranlate(this) } - connectedCallback() { - super.connectedCallback() - - this.copyObject = new Copy(this.getGridDOMElement(), this) - this.pasteObject = new Paste(this.getGridDOMElement(), this) - this.cancObject = new KeyboardCanc(this.getGridDOMElement(), this) - - this.zoomObject = new Zoom(this.getGridDOMElement(), this, { - looseTarget: true, - }) - this.selectObject = new Select(this.getGridDOMElement(), this, { - clickButton: 0, - exitAnyButton: true, - moveEverywhere: true, - }) - this.dragObject = new DragScroll(this.getGridDOMElement(), this, { - clickButton: 2, - exitAnyButton: false, - looseTarget: true, - moveEverywhere: true, - }) - - this.unfocusObject = new Unfocus(this.getGridDOMElement(), this) - this.mouseTrackingObject = new MouseTracking(this.getGridDOMElement(), this) + createInputObjects() { + return [ + new Copy(this.getGridDOMElement(), this), + new Paste(this.getGridDOMElement(), this), + new KeyboardCanc(this.getGridDOMElement(), this), + new Zoom(this.getGridDOMElement(), this, { + looseTarget: true, + }), + new Select(this.getGridDOMElement(), this, { + clickButton: 0, + exitAnyButton: true, + moveEverywhere: true, + }), + new DragScroll(this.getGridDOMElement(), this, { + clickButton: 2, + exitAnyButton: false, + looseTarget: true, + moveEverywhere: true, + }), + new Unfocus(this.getGridDOMElement(), this), + new MouseTracking(this.getGridDOMElement(), this), + ] } getGridDOMElement() { @@ -126,9 +124,6 @@ export default class Blueprint extends GraphElement { disconnectedCallback() { super.disconnectedCallback() setSelected(false) - this.dragObject.unlistenDOMElement() - this.selectObject.unlistenDOMElement() - this.pasteObject.unlistenDOMElement() } getScroll() { @@ -364,7 +359,7 @@ export default class Blueprint extends GraphElement { if (this.focused == value) { return; } - let event = new CustomEvent(value ? "blueprintfocus" : "blueprintunfocus") + let event = new CustomEvent(value ? "blueprint-focus" : "blueprint-unfocus") this.focused = value this.dataset.focused = this.focused if (!this.focused) { diff --git a/js/Configuration.js b/js/Configuration.js old mode 100644 new mode 100755 index d5153aa..b5c8138 --- a/js/Configuration.js +++ b/js/Configuration.js @@ -1,7 +1,7 @@ -export default class Configuration { - - static deleteNodesKeyboardKey = "Delete" - static expandGridSize = 400 - static gridSize = 16 - static gridSnap = 16 -} +export default class Configuration { + + static deleteNodesKeyboardKey = "Delete" + static expandGridSize = 400 + static gridSize = 16 + static gridSnap = 16 +} diff --git a/js/action/Actions.js b/js/action/Actions.js old mode 100644 new mode 100755 index b444f1f..8b35a67 --- a/js/action/Actions.js +++ b/js/action/Actions.js @@ -1,8 +1,8 @@ -export default class Action { - - apply() { - } - - revert() { - } +export default class Action { + + apply() { + } + + revert() { + } } \ No newline at end of file diff --git a/js/entity/KeyBinding.js b/js/entity/KeyBinding.js new file mode 100755 index 0000000..b3e8005 --- /dev/null +++ b/js/entity/KeyBinding.js @@ -0,0 +1,16 @@ +import Entity from "./Entity" + +export default class KeyBinding extends Entity { + + static attributes = { + bCtrlDown: false, + bAltDown: false, + bShiftDown: false, + Key: String, + CommandName: String, + } + + getAttributes() { + return KeyBinding.attributes + } +} diff --git a/js/entity/PathSymbolEntity.js b/js/entity/PathSymbolEntity.js old mode 100644 new mode 100755 index 6db4172..aff0238 --- a/js/entity/PathSymbolEntity.js +++ b/js/entity/PathSymbolEntity.js @@ -1,16 +1,16 @@ -import Entity from "./Entity" - -export default class PathSymbolEntity extends Entity { - - static attributes = { - value: String - } - - getAttributes() { - return PathSymbolEntity.attributes - } - - toString() { - return this.value - } -} +import Entity from "./Entity" + +export default class PathSymbolEntity extends Entity { + + static attributes = { + value: String + } + + getAttributes() { + return PathSymbolEntity.attributes + } + + toString() { + return this.value + } +} diff --git a/js/entity/PinEntity.js b/js/entity/PinEntity.js index c0a75bb..78a1318 100755 --- a/js/entity/PinEntity.js +++ b/js/entity/PinEntity.js @@ -7,6 +7,7 @@ import TypeInitialization from "./TypeInitialization" export default class PinEntity extends Entity { + static lookbehind = "Pin" static attributes = { PinId: GuidEntity, PinName: "", diff --git a/js/graph/GraphElement.js b/js/graph/GraphElement.js index e86e801..c510686 100755 --- a/js/graph/GraphElement.js +++ b/js/graph/GraphElement.js @@ -1,17 +1,27 @@ +/** + * @typedef {import("../Blueprint").default} Blueprint + * @typedef {import("../entity/Entity").default} Entity + * @typedef {import("../input/Context").default} Context + * @typedef {import("../template/Template").default} Template + */ + export default class GraphElement extends HTMLElement { /** * - * @param {import("../template/Template").default} template The template to render this node + * @param {Entity} entity The entity containing blueprint related data for this graph element + * @param {Template} template The template to render this node */ constructor(entity, template) { super() - /** @type {import("../Blueprint").default}" */ + /** @type {Blueprint}" */ this.blueprint = null - /** @type {import("../entity/Entity").default}" */ + /** @type {Entity}" */ this.entity = entity - /** @type {import("../template/Template").default}" */ + /** @type {Template}" */ this.template = template + /** @type {Context[]} */ + this.inputObjects = [] } getTemplate() { @@ -21,8 +31,14 @@ export default class GraphElement extends HTMLElement { connectedCallback() { this.blueprint = this.closest("ueb-blueprint") this.template.apply(this) + this.inputObjects = this.createInputObjects() } disconnectedCallback() { + this.inputObjects.forEach(v => v.unlistenDOMElement()) + } + + createInputObjects() { + return [] } } diff --git a/js/graph/GraphLink.js b/js/graph/GraphLink.js index 3f20d8f..6847112 100755 --- a/js/graph/GraphLink.js +++ b/js/graph/GraphLink.js @@ -17,8 +17,8 @@ export default class GraphLink extends GraphElement { #nodeDragDestinatonHandler = _ => this.setDestinationLocation(this.#destination.getLinkLocation()) /** - * @param {?GraphPin} source - * @param {?GraphPin} destination + * @param {?GraphPin} source + * @param {?GraphPin} destination */ constructor(source, destination) { super(this, new LinkTemplate()) diff --git a/js/graph/GraphNode.js b/js/graph/GraphNode.js index 0050226..1e0f755 100755 --- a/js/graph/GraphNode.js +++ b/js/graph/GraphNode.js @@ -23,10 +23,6 @@ export default class GraphNode extends SelectableDraggable { return new GraphNode(entity) } - connectedCallback() { - super.connectedCallback() - } - disconnectedCallback() { super.disconnectedCallback() this.dispatchDeleteEvent() diff --git a/js/graph/GraphPin.js b/js/graph/GraphPin.js old mode 100644 new mode 100755 index 95ca1ba..3e95f3d --- a/js/graph/GraphPin.js +++ b/js/graph/GraphPin.js @@ -1,69 +1,70 @@ -import GraphElement from "./GraphElement" -import PinTemplate from "../template/PinTemplate" -import DragLink from "../input/DragLink" -import GraphLink from "./GraphLink" - -export default class GraphPin extends GraphElement { - - constructor(entity) { - super(entity, new PinTemplate()) - /** @type {import("../entity/PinEntity").default} */ - this.entity - /** @type {HTMLElement} */ - this.clickableElement = null - } - - connectedCallback() { - super.connectedCallback() - new DragLink(this.clickableElement, this.blueprint, { - moveEverywhere: true - }) - } - - /** - * - * @returns {String} - */ - getPinDisplayName() { - return this.entity.PinName - } - - getAttributes() { - return PinEntity.attributes - } - - isInput() { - return this.entity.isInput() - } - - isOutput() { - return this.entity.isOutput() - } - - isConnected() { - return this.entity.isConnected() - } - - getType() { - return this.entity.getType() - } - - /** - * - * @returns {GraphLink} The link created - */ - dragLink() { - let link = new GraphLink(this) - return link - } - - /** - * Returns The exact location where the link originates from or arrives at. - * @returns {Number[]} The location array - */ - getLinkLocation() { - return [0, 0]; - } -} - -customElements.define("ueb-pin", GraphPin) +import GraphElement from "./GraphElement" +import PinTemplate from "../template/PinTemplate" +import DragLink from "../input/DragLink" +import GraphLink from "./GraphLink" + +export default class GraphPin extends GraphElement { + + constructor(entity) { + super(entity, new PinTemplate()) + /** @type {import("../entity/PinEntity").default} */ + this.entity + /** @type {HTMLElement} */ + this.clickableElement = null + } + + createInputObjects() { + return [ + new DragLink(this.clickableElement, this.blueprint, { + moveEverywhere: true + }), + ] + } + + /** + * + * @returns {String} + */ + getPinDisplayName() { + return this.entity.PinName + } + + getAttributes() { + return PinEntity.attributes + } + + isInput() { + return this.entity.isInput() + } + + isOutput() { + return this.entity.isOutput() + } + + isConnected() { + return this.entity.isConnected() + } + + getType() { + return this.entity.getType() + } + + /** + * + * @returns {GraphLink} The link created + */ + dragLink() { + let link = new GraphLink(this) + return link + } + + /** + * Returns The exact location where the link originates from or arrives at. + * @returns {Number[]} The location array + */ + getLinkLocation() { + return [0, 0]; + } +} + +customElements.define("ueb-pin", GraphPin) diff --git a/js/graph/SelectableDraggable.js b/js/graph/SelectableDraggable.js index 09f8b39..b065a0f 100755 --- a/js/graph/SelectableDraggable.js +++ b/js/graph/SelectableDraggable.js @@ -17,16 +17,12 @@ export default class SelectableDraggable extends GraphElement { } } - connectedCallback() { - super.connectedCallback() - this.dragObject = new DragMove(this, this.blueprint, { - looseTarget: true - }) - } - - disconnectedCallback() { - super.disconnectedCallback() - this.dragObject.unlistenDOMElement() + createInputObjects() { + return [ + new DragMove(this, this.blueprint, { + looseTarget: true + }), + ] } setLocation(value = [0, 0]) { diff --git a/js/input/Context.js b/js/input/Context.js old mode 100644 new mode 100755 index 974834d..9eceb0e --- a/js/input/Context.js +++ b/js/input/Context.js @@ -1,31 +1,31 @@ -export default class Context { - - constructor(target, blueprint, options) { - /** @type {HTMLElement} */ - this.target = target - /** @type {import("../Blueprint").default}" */ - this.blueprint = blueprint - this.options = options - if (options?.wantsFocusCallback ?? false) { - let self = this - this.blueprintfocusHandler = _ => self.blueprintFocused() - this.blueprintunfocusHandler = _ => self.blueprintUnfocused() - this.blueprint.addEventListener("blueprintfocus", this.blueprintfocusHandler) - this.blueprint.addEventListener("blueprintunfocus", this.blueprintunfocusHandler) - } - } - - unlistenDOMElement() { - this.blueprintUnfocused() - this.blueprint.removeEventListener("blueprintfocus", this.blueprintfocusHandler) - this.blueprint.removeEventListener("blueprintunfocus", this.blueprintunfocusHandler) - } - - - /* Subclasses will probabily override the following methods */ - blueprintFocused() { - } - - blueprintUnfocused() { - } -} +export default class Context { + + constructor(target, blueprint, options) { + /** @type {HTMLElement} */ + this.target = target + /** @type {import("../Blueprint").default}" */ + this.blueprint = blueprint + this.options = options + let self = this + this.blueprintFocusHandler = _ => self.blueprintFocused() + this.blueprintUnfocusHandler = _ => self.blueprintUnfocused() + if (options?.wantsFocusCallback ?? false) { + this.blueprint.addEventListener("blueprint-focus", this.blueprintFocusHandler) + this.blueprint.addEventListener("blueprint-unfocus", this.blueprintUnfocusHandler) + } + } + + unlistenDOMElement() { + this.blueprintUnfocused() + this.blueprint.removeEventListener("blueprint-focus", this.blueprintFocusHandler) + this.blueprint.removeEventListener("blueprint-unfocus", this.blueprintUnfocusHandler) + } + + + /* Subclasses will probabily override the following methods */ + blueprintFocused() { + } + + blueprintUnfocused() { + } +} diff --git a/js/input/Copy.js b/js/input/Copy.js old mode 100644 new mode 100755 index 1a9e5f0..862ff7d --- a/js/input/Copy.js +++ b/js/input/Copy.js @@ -1,26 +1,26 @@ -import Context from "./Context" -import ObjectSerializer from "../serialization/ObjectSerializer" - -export default class Copy extends Context { - - constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true - super(target, blueprint, options) - this.serializer = new ObjectSerializer() - let self = this - this.copyHandle = _ => self.copied() - } - - blueprintFocused() { - document.body.addEventListener("copy", this.copyHandle) - } - - blueprintUnfocused() { - document.body.removeEventListener("copy", this.copyHandle) - } - - copied() { - const value = this.blueprint.getNodes(true).map(node => this.serializer.write(node.entity)).join("\n") - navigator.clipboard.writeText(value) - } -} +import Context from "./Context" +import ObjectSerializer from "../serialization/ObjectSerializer" + +export default class Copy extends Context { + + constructor(target, blueprint, options = {}) { + options.wantsFocusCallback = true + super(target, blueprint, options) + this.serializer = new ObjectSerializer() + let self = this + this.copyHandler = _ => self.copied() + } + + blueprintFocused() { + document.body.addEventListener("copy", this.copyHandler) + } + + blueprintUnfocused() { + document.body.removeEventListener("copy", this.copyHandler) + } + + copied() { + const value = this.blueprint.getNodes(true).map(node => this.serializer.write(node.entity)).join("\n") + navigator.clipboard.writeText(value) + } +} diff --git a/js/input/KeyboardCanc.js b/js/input/KeyboardCanc.js old mode 100644 new mode 100755 index 75e01a6..0c90d9d --- a/js/input/KeyboardCanc.js +++ b/js/input/KeyboardCanc.js @@ -1,21 +1,21 @@ -import KeyboardShortcut from "./KeyboardShortcut" -import Configuration from "../Configuration" - - -export default class KeyvoardCanc extends KeyboardShortcut { - - /** - * - * @param {HTMLElement} target - * @param {import("../Blueprint").default} blueprint - * @param {OBject} options - */ - constructor(target, blueprint, options = {}) { - options = KeyboardShortcut.keyOptionsParse(options, Configuration.deleteNodesKeyboardKey) - super(target, blueprint, options) - } - - fire() { - this.blueprint.removeGraphElement(...this.blueprint.getNodes(true)) - } +import KeyboardShortcut from "./KeyboardShortcut" +import Configuration from "../Configuration" + + +export default class KeyvoardCanc extends KeyboardShortcut { + + /** + * + * @param {HTMLElement} target + * @param {import("../Blueprint").default} blueprint + * @param {OBject} options + */ + constructor(target, blueprint, options = {}) { + options = KeyboardShortcut.keyOptionsParse(options, Configuration.deleteNodesKeyboardKey) + super(target, blueprint, options) + } + + fire() { + this.blueprint.removeGraphElement(...this.blueprint.getNodes(true)) + } } \ No newline at end of file diff --git a/js/input/KeyboardShortcut.js b/js/input/KeyboardShortcut.js old mode 100644 new mode 100755 index 8509e74..f621cff --- a/js/input/KeyboardShortcut.js +++ b/js/input/KeyboardShortcut.js @@ -1,50 +1,50 @@ -import Context from "./Context" - -export default class KeyboardShortcut extends Context { - - constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true - super(target, blueprint, options) - - /** @type {String[]} */ - this.key = this.options.key - this.ctrlKey = options.ctrlKey ?? false - this.shiftKey = options.shiftKey ?? false - this.altKey = options.altKey ?? false - this.metaKey = options.metaKey ?? false - - let self = this - this.keyDownHandler = e => { - if ( - e.code == self.key - && e.ctrlKey === self.ctrlKey - && e.shiftKey === self.shiftKey - && e.altKey === self.altKey - && e.metaKey === self.metaKey - ) { - self.fire() - } - } - } - - /** - * - * @param {String} keyString - * @returns {Object} - */ - static keyOptionsParse(options, keyString) { - options.key = keyString - return options - } - - blueprintFocused() { - document.addEventListener("keydown", this.keyDownHandler) - } - - blueprintUnfocused() { - document.removeEventListener("keydown", this.keyDownHandler) - } - - fire() { - } -} +import Context from "./Context" + +export default class KeyboardShortcut extends Context { + + constructor(target, blueprint, options = {}) { + options.wantsFocusCallback = true + super(target, blueprint, options) + + /** @type {String[]} */ + this.key = this.options.key + this.ctrlKey = options.ctrlKey ?? false + this.shiftKey = options.shiftKey ?? false + this.altKey = options.altKey ?? false + this.metaKey = options.metaKey ?? false + + let self = this + this.keyDownHandler = e => { + if ( + e.code == self.key + && e.ctrlKey === self.ctrlKey + && e.shiftKey === self.shiftKey + && e.altKey === self.altKey + && e.metaKey === self.metaKey + ) { + self.fire() + } + } + } + + /** + * + * @param {String} keyString + * @returns {Object} + */ + static keyOptionsParse(options, keyString) { + options.key = keyString + return options + } + + blueprintFocused() { + document.addEventListener("keydown", this.keyDownHandler) + } + + blueprintUnfocused() { + document.removeEventListener("keydown", this.keyDownHandler) + } + + fire() { + } +} diff --git a/js/input/MouseTracking.js b/js/input/MouseTracking.js old mode 100644 new mode 100755 index c8f9cf7..8cbf720 --- a/js/input/MouseTracking.js +++ b/js/input/MouseTracking.js @@ -1,22 +1,22 @@ -import Pointing from "./Pointing" - -export default class MouseTracking extends Pointing { - - constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true - super(target, blueprint, options) - - let self = this - this.mousemoveHandler = e => { - self.blueprint.entity.mousePosition = self.getLocation(e) - } - } - - blueprintFocused() { - this.target.addEventListener("mousemove", this.mousemoveHandler) - } - - blueprintUnfocused() { - this.target.removeEventListener("mousemove", this.mousemoveHandler) - } -} +import Pointing from "./Pointing" + +export default class MouseTracking extends Pointing { + + constructor(target, blueprint, options = {}) { + options.wantsFocusCallback = true + super(target, blueprint, options) + + let self = this + this.mousemoveHandler = e => { + self.blueprint.entity.mousePosition = self.getLocation(e) + } + } + + blueprintFocused() { + this.target.addEventListener("mousemove", this.mousemoveHandler) + } + + blueprintUnfocused() { + this.target.removeEventListener("mousemove", this.mousemoveHandler) + } +} diff --git a/js/input/Paste.js b/js/input/Paste.js old mode 100644 new mode 100755 index 7559a1d..4198f99 --- a/js/input/Paste.js +++ b/js/input/Paste.js @@ -1,50 +1,50 @@ -import GraphNode from "../graph/GraphNode" -import ObjectSerializer from "../serialization/ObjectSerializer" -import Context from "./Context" - -export default class Paste extends Context { - - constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true - super(target, blueprint, options) - this.serializer = new ObjectSerializer() - let self = this - this.pasteHandle = e => self.pasted(e.clipboardData.getData("Text")) - } - - blueprintFocused() { - document.body.addEventListener("paste", this.pasteHandle) - } - - blueprintUnfocused() { - document.body.removeEventListener("paste", this.pasteHandle) - } - - pasted(value) { - let top = 0 - let left = 0 - let count = 0 - let nodes = this.serializer.readMultiple(value).map(entity => { - let node = new GraphNode(entity) - top += node.location[1] - left += node.location[0] - ++count - return node - }) - top /= count - left /= count - if (nodes.length > 0) { - this.blueprint.unselectAll() - } - let mousePosition = this.blueprint.entity.mousePosition - this.blueprint.addGraphElement(...nodes) - nodes.forEach(node => { - const locationOffset = [ - mousePosition[0] - left, - mousePosition[1] - top, - ] - node.addLocation(this.blueprint.compensateTranslation(locationOffset)) - node.setSelected(true) - }) - } -} +import GraphNode from "../graph/GraphNode" +import ObjectSerializer from "../serialization/ObjectSerializer" +import Context from "./Context" + +export default class Paste extends Context { + + constructor(target, blueprint, options = {}) { + options.wantsFocusCallback = true + super(target, blueprint, options) + this.serializer = new ObjectSerializer() + let self = this + this.pasteHandle = e => self.pasted(e.clipboardData.getData("Text")) + } + + blueprintFocused() { + document.body.addEventListener("paste", this.pasteHandle) + } + + blueprintUnfocused() { + document.body.removeEventListener("paste", this.pasteHandle) + } + + pasted(value) { + let top = 0 + let left = 0 + let count = 0 + let nodes = this.serializer.readMultiple(value).map(entity => { + let node = new GraphNode(entity) + top += node.location[1] + left += node.location[0] + ++count + return node + }) + top /= count + left /= count + if (nodes.length > 0) { + this.blueprint.unselectAll() + } + let mousePosition = this.blueprint.entity.mousePosition + this.blueprint.addGraphElement(...nodes) + nodes.forEach(node => { + const locationOffset = [ + mousePosition[0] - left, + mousePosition[1] - top, + ] + node.addLocation(this.blueprint.compensateTranslation(locationOffset)) + node.setSelected(true) + }) + } +} diff --git a/js/input/Unfocus.js b/js/input/Unfocus.js old mode 100644 new mode 100755 index 32efaf6..6dd8234 --- a/js/input/Unfocus.js +++ b/js/input/Unfocus.js @@ -1,35 +1,35 @@ -import Context from "./Context" - -export default class Unfocus extends Context { - - constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true - super(target, blueprint, options) - - let self = this - this.clickHandler = e => self.clickedSomewhere(e) - if (this.blueprint.focuse) { - document.addEventListener("click", this.clickHandler) - } - } - - /** - * - * @param {MouseEvent} e - */ - clickedSomewhere(e) { - // If target is inside the blueprint grid - if (e.target.closest("ueb-blueprint")) { - return - } - this.blueprint.setFocused(false) - } - - blueprintFocused() { - document.addEventListener("click", this.clickHandler) - } - - blueprintUnfocused() { - document.removeEventListener("click", this.clickHandler) - } -} +import Context from "./Context" + +export default class Unfocus extends Context { + + constructor(target, blueprint, options = {}) { + options.wantsFocusCallback = true + super(target, blueprint, options) + + let self = this + this.clickHandler = e => self.clickedSomewhere(e) + if (this.blueprint.focuse) { + document.addEventListener("click", this.clickHandler) + } + } + + /** + * + * @param {MouseEvent} e + */ + clickedSomewhere(e) { + // If target is inside the blueprint grid + if (e.target.closest("ueb-blueprint")) { + return + } + this.blueprint.setFocused(false) + } + + blueprintFocused() { + document.addEventListener("click", this.clickHandler) + } + + blueprintUnfocused() { + document.removeEventListener("click", this.clickHandler) + } +} diff --git a/js/serialization/CustomSerializer.js b/js/serialization/CustomSerializer.js old mode 100644 new mode 100755 index 02222df..ca242a9 --- a/js/serialization/CustomSerializer.js +++ b/js/serialization/CustomSerializer.js @@ -1,14 +1,14 @@ -import GeneralSerializer from "./GeneralSerializer" - -export default class CustomSerializer extends GeneralSerializer { - - constructor(objectWriter, entityType) { - super(undefined, entityType) - this.objectWriter = objectWriter - } - - write(object) { - let result = this.objectWriter(object) - return result - } -} +import GeneralSerializer from "./GeneralSerializer" + +export default class CustomSerializer extends GeneralSerializer { + + constructor(objectWriter, entityType) { + super(undefined, entityType) + this.objectWriter = objectWriter + } + + write(object) { + let result = this.objectWriter(object) + return result + } +} diff --git a/js/serialization/Grammar.js b/js/serialization/Grammar.js index a52f1ae..5e6799b 100755 --- a/js/serialization/Grammar.js +++ b/js/serialization/Grammar.js @@ -113,25 +113,28 @@ export default class Grammar { } } // Meta grammar - static CreateAttributeGrammar = (r, attributeGrammar, attributeSupplier, valueSeparator = P.string("=").trim(P.optWhitespace)) => - attributeGrammar.skip(valueSeparator) + static CreateAttributeGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) => + r.AttributeName.skip(valueSeparator) .chain(attributeName => { const attributeKey = attributeName.split(".") - const attribute = attributeSupplier(attributeKey) + const attribute = Utility.objectGet(entityType.attributes, attributeKey) let attributeValueGrammar = Grammar.getGrammarForType(r, attribute, r.AttributeAnyValue) + // Returns attributeSetter: a function called with an object as argument that will set the correct attribute value return attributeValueGrammar.map(attributeValue => entity => Utility.objectSet(entity, attributeKey, attributeValue, true) - ) // returns attributeSetter: a function called with an object as argument that will set the correct attribute value + ) }) // Meta grammar - static CreateMultiAttributeGrammar = (r, keyGrammar, entityType, attributeSupplier) => + static CreateMultiAttributeGrammar = (r, entityType) => /** * Basically this creates a parser that looks for a string like 'Key (A=False,B="Something",)' * Then it populates an object of type EntityType with the attribute values found inside the parentheses. */ P.seqMap( - P.seq(keyGrammar, P.optWhitespace, P.string("(")), - Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeSupplier) + entityType.lookbehind + ? P.seq(P.string(entityType.lookbehind), P.optWhitespace, P.string("(")) + : P.string("("), + Grammar.CreateAttributeGrammar(r, entityType) .trim(P.optWhitespace) .sepBy(P.string(",")) .skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma @@ -141,18 +144,8 @@ export default class Grammar { attributes.forEach(attributeSetter => attributeSetter(result)) return result }) - FunctionReference = r => Grammar.CreateMultiAttributeGrammar( - r, - P.succeed(), - FunctionReferenceEntity, - attributeKey => Utility.objectGet(FunctionReferenceEntity.attributes, attributeKey) - ) - Pin = r => Grammar.CreateMultiAttributeGrammar( - r, - P.string("Pin"), - PinEntity, - attributeKey => Utility.objectGet(PinEntity.attributes, attributeKey) - ) + FunctionReference = r => Grammar.CreateMultiAttributeGrammar(r, FunctionReferenceEntity) + Pin = r => Grammar.CreateMultiAttributeGrammar(r, PinEntity) CustomProperties = r => P.string("CustomProperties") .then(P.whitespace) @@ -169,7 +162,7 @@ export default class Grammar { P .alt( r.CustomProperties, - Grammar.CreateAttributeGrammar(r, r.AttributeName, attributeKey => Utility.objectGet(ObjectEntity.attributes, attributeKey)) + Grammar.CreateAttributeGrammar(r, ObjectEntity) ) .sepBy1(P.whitespace), P.seq(r.WhitespaceNewline, P.string("End"), P.whitespace, P.string("Object")), diff --git a/js/serialization/ToStringSerializer.js b/js/serialization/ToStringSerializer.js old mode 100644 new mode 100755 index 10b4f1f..560500e --- a/js/serialization/ToStringSerializer.js +++ b/js/serialization/ToStringSerializer.js @@ -1,13 +1,13 @@ -import GeneralSerializer from "./GeneralSerializer" - -export default class ToStringSerializer extends GeneralSerializer { - - constructor(entityType) { - super(undefined, entityType) - } - - write(object) { - let result = object.toString() - return result - } -} +import GeneralSerializer from "./GeneralSerializer" + +export default class ToStringSerializer extends GeneralSerializer { + + constructor(entityType) { + super(undefined, entityType) + } + + write(object) { + let result = object.toString() + return result + } +} diff --git a/js/serialization/initializeSerializerFactory.js b/js/serialization/initializeSerializerFactory.js old mode 100644 new mode 100755 index 93feb94..2986f36 --- a/js/serialization/initializeSerializerFactory.js +++ b/js/serialization/initializeSerializerFactory.js @@ -1,50 +1,50 @@ -import CustomSerializer from "./CustomSerializer" -import FunctionReferenceEntity from "../entity/FunctionReferenceEntity" -import GeneralSerializer from "./GeneralSerializer" -import GuidEntity from "../entity/GuidEntity" -import IntegerEntity from "../entity/IntegerEntity" -import LocalizedTextEntity from "../entity/LocalizedTextEntity" -import ObjectEntity from "../entity/ObjectEntity" -import ObjectReferenceEntity from "../entity/ObjectReferenceEntity" -import ObjectSerializer from "./ObjectSerializer" -import PathSymbolEntity from "../entity/PathSymbolEntity" -import PinEntity from "../entity/PinEntity" -import PinReferenceEntity from "../entity/PinReferenceEntity" -import SerializerFactory from "./SerializerFactory" -import ToStringSerializer from "./ToStringSerializer" - -export default function initializeSerializerFactory() { - SerializerFactory.registerSerializer( - ObjectEntity, - new ObjectSerializer() - ) - SerializerFactory.registerSerializer( - PinEntity, - new GeneralSerializer(v => `Pin (${v})`, PinEntity, "", ",", true) - ) - SerializerFactory.registerSerializer( - FunctionReferenceEntity, - new GeneralSerializer(v => `(${v})`, FunctionReferenceEntity, "", ",", false) - ) - SerializerFactory.registerSerializer( - LocalizedTextEntity, - new GeneralSerializer(v => `NSLOCTEXT(${v})`, LocalizedTextEntity, "", ",", false, "", _ => "") - ) - SerializerFactory.registerSerializer( - PinReferenceEntity, - new GeneralSerializer(v => v, PinReferenceEntity, "", " ", false, "", _ => "") - ) - SerializerFactory.registerSerializer( - ObjectReferenceEntity, - new CustomSerializer( - /** @param {ObjectReferenceEntity} objectReference */ - objectReference => (objectReference.type ?? "") + ( - objectReference.path - ? objectReference.type ? `'"${objectReference.path}"'` : objectReference.path - : "" - )) - ) - SerializerFactory.registerSerializer(PathSymbolEntity, new ToStringSerializer(PathSymbolEntity)) - SerializerFactory.registerSerializer(GuidEntity, new ToStringSerializer(GuidEntity)) - SerializerFactory.registerSerializer(IntegerEntity, new ToStringSerializer(IntegerEntity)) -} +import CustomSerializer from "./CustomSerializer" +import FunctionReferenceEntity from "../entity/FunctionReferenceEntity" +import GeneralSerializer from "./GeneralSerializer" +import GuidEntity from "../entity/GuidEntity" +import IntegerEntity from "../entity/IntegerEntity" +import LocalizedTextEntity from "../entity/LocalizedTextEntity" +import ObjectEntity from "../entity/ObjectEntity" +import ObjectReferenceEntity from "../entity/ObjectReferenceEntity" +import ObjectSerializer from "./ObjectSerializer" +import PathSymbolEntity from "../entity/PathSymbolEntity" +import PinEntity from "../entity/PinEntity" +import PinReferenceEntity from "../entity/PinReferenceEntity" +import SerializerFactory from "./SerializerFactory" +import ToStringSerializer from "./ToStringSerializer" + +export default function initializeSerializerFactory() { + SerializerFactory.registerSerializer( + ObjectEntity, + new ObjectSerializer() + ) + SerializerFactory.registerSerializer( + PinEntity, + new GeneralSerializer(v => `Pin (${v})`, PinEntity, "", ",", true) + ) + SerializerFactory.registerSerializer( + FunctionReferenceEntity, + new GeneralSerializer(v => `(${v})`, FunctionReferenceEntity, "", ",", false) + ) + SerializerFactory.registerSerializer( + LocalizedTextEntity, + new GeneralSerializer(v => `NSLOCTEXT(${v})`, LocalizedTextEntity, "", ",", false, "", _ => "") + ) + SerializerFactory.registerSerializer( + PinReferenceEntity, + new GeneralSerializer(v => v, PinReferenceEntity, "", " ", false, "", _ => "") + ) + SerializerFactory.registerSerializer( + ObjectReferenceEntity, + new CustomSerializer( + /** @param {ObjectReferenceEntity} objectReference */ + objectReference => (objectReference.type ?? "") + ( + objectReference.path + ? objectReference.type ? `'"${objectReference.path}"'` : objectReference.path + : "" + )) + ) + SerializerFactory.registerSerializer(PathSymbolEntity, new ToStringSerializer(PathSymbolEntity)) + SerializerFactory.registerSerializer(GuidEntity, new ToStringSerializer(GuidEntity)) + SerializerFactory.registerSerializer(IntegerEntity, new ToStringSerializer(IntegerEntity)) +} diff --git a/js/template/LinkTemplate.js b/js/template/LinkTemplate.js old mode 100644 new mode 100755 index 05e51a6..7f1889f --- a/js/template/LinkTemplate.js +++ b/js/template/LinkTemplate.js @@ -1,49 +1,49 @@ -import html from "./html" -import Template from "./Template" - -/** - * @typedef {import("../graph/GraphLink").default} GraphLink - */ -export default class LinkTemplate extends Template { - - /** - * Computes the html content of the target element. - * @param {GraphLink} link Link connecting two graph nodes - * @returns The result html - */ - render(link) { - return html` - - - - ` - } - - /** - * Applies the style to the element. - * @param {GraphLink} link Element of the graph - */ - apply(link) { - super.apply(link) - - } - - /** - * Applies the style relative to the source pin location. - * @param {GraphLink} link Link element - */ - applySourceLocation(link, initialPosition) { - // Set initial position - link.style.setProperty("--ueb-link-from-x", sanitizeText(initialPosition[0])) - link.style.setProperty("--ueb-link-from-y", sanitizeText(initialPosition[1])) - } - - /** - * Applies the style relative to the destination pin location. - * @param {GraphLink} link Link element - */ - applyDestinationLocation(link, finalPosition) { - link.style.setProperty("--ueb-link-to-x", sanitizeText(finalPosition[0])) - link.style.setProperty("--ueb-link-to-y", sanitizeText(finalPosition[1])) - } -} +import html from "./html" +import Template from "./Template" + +/** + * @typedef {import("../graph/GraphLink").default} GraphLink + */ +export default class LinkTemplate extends Template { + + /** + * Computes the html content of the target element. + * @param {GraphLink} link Link connecting two graph nodes + * @returns The result html + */ + render(link) { + return html` + + + + ` + } + + /** + * Applies the style to the element. + * @param {GraphLink} link Element of the graph + */ + apply(link) { + super.apply(link) + + } + + /** + * Applies the style relative to the source pin location. + * @param {GraphLink} link Link element + */ + applySourceLocation(link, initialPosition) { + // Set initial position + link.style.setProperty("--ueb-link-from-x", sanitizeText(initialPosition[0])) + link.style.setProperty("--ueb-link-from-y", sanitizeText(initialPosition[1])) + } + + /** + * Applies the style relative to the destination pin location. + * @param {GraphLink} link Link element + */ + applyDestinationLocation(link, finalPosition) { + link.style.setProperty("--ueb-link-to-x", sanitizeText(finalPosition[0])) + link.style.setProperty("--ueb-link-to-y", sanitizeText(finalPosition[1])) + } +} diff --git a/js/template/PinTemplate.js b/js/template/PinTemplate.js old mode 100644 new mode 100755 index 156207b..f906900 --- a/js/template/PinTemplate.js +++ b/js/template/PinTemplate.js @@ -1,38 +1,38 @@ -import html from "./html" -import sanitizeText from "./sanitizeText" -import Template from "./Template" - -/** - * @typedef {import("../graph/GraphPin").default} GraphPin - */ -export default class PinTemplate extends Template { - - /** - * Computes the html content of the pin. - * @param {GraphPin} pin Pin entity - * @returns The result html - */ - render(pin) { - if (pin.isInput()) { - return html` - - ${sanitizeText(pin.getPinDisplayName())} - ` - } else { - return html` - ${sanitizeText(pin.getPinDisplayName())} - - ` - } - } - - /** - * Applies the style to the element. - * @param {GraphPin} pin Element of the graph - */ - apply(pin) { - super.apply(pin) - pin.classList.add("ueb-node-" + pin.isInput() ? "input" : "output", "ueb-node-value-" + sanitizeText(pin.getType())) - pin.clickableElement = pin.querySelector(".ueb-node-value-icon") - } +import html from "./html" +import sanitizeText from "./sanitizeText" +import Template from "./Template" + +/** + * @typedef {import("../graph/GraphPin").default} GraphPin + */ +export default class PinTemplate extends Template { + + /** + * Computes the html content of the pin. + * @param {GraphPin} pin Pin entity + * @returns The result html + */ + render(pin) { + if (pin.isInput()) { + return html` + + ${sanitizeText(pin.getPinDisplayName())} + ` + } else { + return html` + ${sanitizeText(pin.getPinDisplayName())} + + ` + } + } + + /** + * Applies the style to the element. + * @param {GraphPin} pin Element of the graph + */ + apply(pin) { + super.apply(pin) + pin.classList.add("ueb-node-" + pin.isInput() ? "input" : "output", "ueb-node-value-" + sanitizeText(pin.getType())) + pin.clickableElement = pin.querySelector(".ueb-node-value-icon") + } } \ No newline at end of file diff --git a/js/template/SelectableDraggableTemplate.js b/js/template/SelectableDraggableTemplate.js old mode 100644 new mode 100755 index c5ca426..829c9c6 --- a/js/template/SelectableDraggableTemplate.js +++ b/js/template/SelectableDraggableTemplate.js @@ -1,29 +1,29 @@ -import sanitizeText from "./sanitizeText" -import Template from "./Template" - -/** - * @typedef {import("../graph/SelectableDraggable").default} SelectableDraggable - */ -export default class SelectableDraggableTemplate extends Template { - - /** - * Returns the html elements rendered from this template. - * @param {SelectableDraggable} element Element of the graph - */ - applyLocation(element) { - element.style.setProperty("--ueb-position-x", sanitizeText(element.location[0])) - element.style.setProperty("--ueb-position-y", sanitizeText(element.location[1])) - } - - /** - * Returns the html elements rendered from this template. - * @param {SelectableDraggable} element Element of the graph - */ - applySelected(element) { - if (element.selected) { - element.classList.add("ueb-selected") - } else { - element.classList.remove("ueb-selected") - } - } -} +import sanitizeText from "./sanitizeText" +import Template from "./Template" + +/** + * @typedef {import("../graph/SelectableDraggable").default} SelectableDraggable + */ +export default class SelectableDraggableTemplate extends Template { + + /** + * Returns the html elements rendered from this template. + * @param {SelectableDraggable} element Element of the graph + */ + applyLocation(element) { + element.style.setProperty("--ueb-position-x", sanitizeText(element.location[0])) + element.style.setProperty("--ueb-position-y", sanitizeText(element.location[1])) + } + + /** + * Returns the html elements rendered from this template. + * @param {SelectableDraggable} element Element of the graph + */ + applySelected(element) { + if (element.selected) { + element.classList.add("ueb-selected") + } else { + element.classList.remove("ueb-selected") + } + } +} diff --git a/js/template/SelectorTemplate.js b/js/template/SelectorTemplate.js old mode 100644 new mode 100755 index 5430e8c..5b653ee --- a/js/template/SelectorTemplate.js +++ b/js/template/SelectorTemplate.js @@ -1,49 +1,49 @@ -import sanitizeText from "./sanitizeText" -import Template from "./Template" - -/** - * @typedef {import("../graph/GraphSelector").default} GraphSelector - */ -export default class SelectorTemplate extends Template { - - /** - * Applies the style to the element. - * @param {GraphSelector} selector Selector element - */ - apply(selector) { - super.apply(selector) - selector.classList.add("ueb-selector") - this.applyFinishSelecting(selector) - } - - /** - * Applies the style relative to selection beginning. - * @param {GraphSelector} selector Selector element - */ - applyStartSelecting(selector, initialPosition) { - // Set initial position - selector.style.setProperty("--ueb-select-from-x", sanitizeText(initialPosition[0])) - selector.style.setProperty("--ueb-select-from-y", sanitizeText(initialPosition[1])) - // Final position coincide with the initial position, at the beginning of selection - selector.style.setProperty("--ueb-select-to-x", sanitizeText(initialPosition[0])) - selector.style.setProperty("--ueb-select-to-y", sanitizeText(initialPosition[1])) - selector.dataset.selecting = "true" - } - - /** - * Applies the style relative to selection. - * @param {GraphSelector} selector Selector element - */ - applyDoSelecting(selector, finalPosition) { - selector.style.setProperty("--ueb-select-to-x", sanitizeText(finalPosition[0])) - selector.style.setProperty("--ueb-select-to-y", sanitizeText(finalPosition[1])) - } - - /** - * Applies the style relative to selection finishing. - * @param {GraphSelector} selector Selector element - */ - applyFinishSelecting(selector) { - selector.dataset.selecting = "false" - } -} +import sanitizeText from "./sanitizeText" +import Template from "./Template" + +/** + * @typedef {import("../graph/GraphSelector").default} GraphSelector + */ +export default class SelectorTemplate extends Template { + + /** + * Applies the style to the element. + * @param {GraphSelector} selector Selector element + */ + apply(selector) { + super.apply(selector) + selector.classList.add("ueb-selector") + this.applyFinishSelecting(selector) + } + + /** + * Applies the style relative to selection beginning. + * @param {GraphSelector} selector Selector element + */ + applyStartSelecting(selector, initialPosition) { + // Set initial position + selector.style.setProperty("--ueb-select-from-x", sanitizeText(initialPosition[0])) + selector.style.setProperty("--ueb-select-from-y", sanitizeText(initialPosition[1])) + // Final position coincide with the initial position, at the beginning of selection + selector.style.setProperty("--ueb-select-to-x", sanitizeText(initialPosition[0])) + selector.style.setProperty("--ueb-select-to-y", sanitizeText(initialPosition[1])) + selector.dataset.selecting = "true" + } + + /** + * Applies the style relative to selection. + * @param {GraphSelector} selector Selector element + */ + applyDoSelecting(selector, finalPosition) { + selector.style.setProperty("--ueb-select-to-x", sanitizeText(finalPosition[0])) + selector.style.setProperty("--ueb-select-to-y", sanitizeText(finalPosition[1])) + } + + /** + * Applies the style relative to selection finishing. + * @param {GraphSelector} selector Selector element + */ + applyFinishSelecting(selector) { + selector.dataset.selecting = "false" + } +} diff --git a/js/template/html.js b/js/template/html.js old mode 100644 new mode 100755 index 73b15be..856a94c --- a/js/template/html.js +++ b/js/template/html.js @@ -1,2 +1,2 @@ -const html = String.raw -export default html +const html = String.raw +export default html diff --git a/js/template/sanitizeText.js b/js/template/sanitizeText.js old mode 100644 new mode 100755 index bd75b4c..2802629 --- a/js/template/sanitizeText.js +++ b/js/template/sanitizeText.js @@ -1,18 +1,18 @@ -const div = document.createElement("div") - -const tagReplacement = { - '&': '&', - '<': '<', - '>': '>', - "'": ''', - '"': '"' -} - -function sanitizeText(value) { - if (value.constructor === String) { - return value.replace(/[&<>'"]/g, tag => tagReplacement[tag]) - } - return value -} - +const div = document.createElement("div") + +const tagReplacement = { + '&': '&', + '<': '<', + '>': '>', + "'": ''', + '"': '"' +} + +function sanitizeText(value) { + if (value.constructor === String) { + return value.replace(/[&<>'"]/g, tag => tagReplacement[tag]) + } + return value +} + export default sanitizeText \ No newline at end of file diff --git a/package.json b/package.json old mode 100644 new mode 100755 index 2433244..064e9be --- a/package.json +++ b/package.json @@ -1,37 +1,37 @@ -{ - "name": "ueblueprint", - "version": "1.0.0", - "description": "Unreal Engine's Blueprint visualisation library", - "main": "ueblueprint.js", - "scripts": { - "build": "rollup --config && sass scss:dist/css --style=compressed" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/barsdeveloper/ueblueprint.git" - }, - "keywords": [ - "unreal", - "engine", - "blueprint" - ], - "author": "barsdeveloper", - "license": "MIT", - "bugs": { - "url": "https://github.com/barsdeveloper/ueblueprint/issues" - }, - "homepage": "https://github.com/barsdeveloper/ueblueprint#readme", - "devDependencies": { - "@rollup/plugin-commonjs": "^21.0.0", - "@rollup/plugin-node-resolve": "^13.0.5", - "rollup": "^2.58.0", - "rollup-plugin-copy": "^3.4.0", - "rollup-plugin-minify-html-template-literals": "^1.2.0", - "rollup-plugin-terser": "^7.0.2", - "sass": "^1.45.1", - "terser": "^5.9.0" - }, - "dependencies": { - "parsimmon": "^1.18.0" - } -} \ No newline at end of file +{ + "name": "ueblueprint", + "version": "1.0.0", + "description": "Unreal Engine's Blueprint visualisation library", + "main": "ueblueprint.js", + "scripts": { + "build": "rollup --config && sass scss:dist/css --style=compressed" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/barsdeveloper/ueblueprint.git" + }, + "keywords": [ + "unreal", + "engine", + "blueprint" + ], + "author": "barsdeveloper", + "license": "MIT", + "bugs": { + "url": "https://github.com/barsdeveloper/ueblueprint/issues" + }, + "homepage": "https://github.com/barsdeveloper/ueblueprint#readme", + "devDependencies": { + "@rollup/plugin-commonjs": "^21.0.0", + "@rollup/plugin-node-resolve": "^13.0.5", + "rollup": "^2.58.0", + "rollup-plugin-copy": "^3.4.0", + "rollup-plugin-minify-html-template-literals": "^1.2.0", + "rollup-plugin-terser": "^7.0.2", + "sass": "^1.45.1", + "terser": "^5.9.0" + }, + "dependencies": { + "parsimmon": "^1.18.0" + } +} diff --git a/rollup.config.js b/rollup.config.js old mode 100644 new mode 100755 index b0129ba..5b42cc6 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,27 +1,27 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import minifyHTML from 'rollup-plugin-minify-html-template-literals' -import commonjs from '@rollup/plugin-commonjs' -import { terser } from 'rollup-plugin-terser' -import copy from 'rollup-plugin-copy' - -export default { - input: 'js/export.js', - output: { - file: 'dist/ueblueprint.js', - format: 'es' - }, - plugins: [ - nodeResolve({ browser: true }), - //minifyHTML(), - commonjs(), - //terser() - copy({ - targets: [ - { - src: ["font/*"], - dest: "dist/font" - } - ] - }) - ] +import { nodeResolve } from '@rollup/plugin-node-resolve' +import minifyHTML from 'rollup-plugin-minify-html-template-literals' +import commonjs from '@rollup/plugin-commonjs' +import { terser } from 'rollup-plugin-terser' +import copy from 'rollup-plugin-copy' + +export default { + input: 'js/export.js', + output: { + file: 'dist/ueblueprint.js', + format: 'es' + }, + plugins: [ + nodeResolve({ browser: true }), + //minifyHTML(), + commonjs(), + //terser() + copy({ + targets: [ + { + src: ["font/*"], + dest: "dist/font" + } + ] + }) + ] } \ No newline at end of file diff --git a/scss/ueblueprint-node-value-type-color.scss b/scss/ueblueprint-node-value-type-color.scss old mode 100644 new mode 100755 index 4f9aa69..201db48 --- a/scss/ueblueprint-node-value-type-color.scss +++ b/scss/ueblueprint-node-value-type-color.scss @@ -1,45 +1,45 @@ -.ueb { - $ueb-node-value-color : white; - --ueb-node-value-color: #{$ueb-node-value-color}; -} - -.ueb-node-value-boolean { - $ueb-node-value-color : #930000; - --ueb-node-value-color: #{$ueb-node-value-color}; -} - -.ueb-node-value-integer { - $ueb-node-value-color : #1fe0ad; - --ueb-node-value-color: #{$ueb-node-value-color}; -} - -.ueb-node-value-float { - $ueb-node-value-color : #9ffb44; - --ueb-node-value-color: #{$ueb-node-value-color}; -} - -.ueb-node-value-vector { - $ueb-node-value-color : #fcc823; - --ueb-node-value-color: #{$ueb-node-value-color}; -} - -.ueb-node-value-rotator { - $ueb-node-value-color : #9eb1fc; - --ueb-node-value-color: #{$ueb-node-value-color}; -} - -.ueb-node-value-string { - $ueb-node-value-color : #fc00d2; - --ueb-node-value-color : #{$ueb-node-value-color}; - --ueb-node-value-background: linear-gradient(90deg, #fc00d220, #fc00d280 15%, #fc00d250 85%, transparent); -} - -.ueb-node-value-name { - $ueb-node-value-color : #cb81fc; - --ueb-node-value-color: #{$ueb-node-value-color}; -} - -.ueb-node-value-objectreference { - $ueb-node-value-color : #00a8f2; - --ueb-node-value-color: #{$ueb-node-value-color}; +.ueb { + $ueb-node-value-color : white; + --ueb-node-value-color: #{$ueb-node-value-color}; +} + +.ueb-node-value-boolean { + $ueb-node-value-color : #930000; + --ueb-node-value-color: #{$ueb-node-value-color}; +} + +.ueb-node-value-integer { + $ueb-node-value-color : #1fe0ad; + --ueb-node-value-color: #{$ueb-node-value-color}; +} + +.ueb-node-value-float { + $ueb-node-value-color : #9ffb44; + --ueb-node-value-color: #{$ueb-node-value-color}; +} + +.ueb-node-value-vector { + $ueb-node-value-color : #fcc823; + --ueb-node-value-color: #{$ueb-node-value-color}; +} + +.ueb-node-value-rotator { + $ueb-node-value-color : #9eb1fc; + --ueb-node-value-color: #{$ueb-node-value-color}; +} + +.ueb-node-value-string { + $ueb-node-value-color : #fc00d2; + --ueb-node-value-color : #{$ueb-node-value-color}; + --ueb-node-value-background: linear-gradient(90deg, #fc00d220, #fc00d280 15%, #fc00d250 85%, transparent); +} + +.ueb-node-value-name { + $ueb-node-value-color : #cb81fc; + --ueb-node-value-color: #{$ueb-node-value-color}; +} + +.ueb-node-value-objectreference { + $ueb-node-value-color : #00a8f2; + --ueb-node-value-color: #{$ueb-node-value-color}; } \ No newline at end of file diff --git a/scss/ueblueprint-style.css b/scss/ueblueprint-style.css old mode 100644 new mode 100755 index ad0a6b9..b9e766f --- a/scss/ueblueprint-style.css +++ b/scss/ueblueprint-style.css @@ -1,431 +1,431 @@ -@font-face { - font-family: "Roboto"; - font-style : light; - src : - url("../font/roboto-light.woff2") format("woff2"), - url("../font/roboto-light.woff") format("woff"); -} - -@font-face { - font-family: "Roboto"; - font-style : regular; - src : - url("../font/roboto-regular.woff2") format("woff2"), - url("../font/roboto-regular.woff") format("woff"); -} - -:root { - --ueb-fron-size : 13px; - --ueb-viewport-height : 30rem; - --ueb-viewport-width : 100%; - --ueb-grid-size : 16px; - --ueb-grid-line-width : 2px; - --ueb-grid-line-color : #353535; - --ueb-grid-set : 8; - --ueb-grid-set-line-color : #161616; - --ueb-grid-axis-line-color: black; - --ueb-grid-snap : 16px; - --ueb-node-radius : 8px; -} - -ueb-blueprint { - display : block; - position : relative; - font-family: Roboto, Noto, Oxygen, Ubuntu, "Open Sans", "Helvetica Neue", sans-serif; - font-size : var(--ueb-fron-size); - user-select: none; -} - -.ueb-viewport-header { - display : flex; - position : absolute; - top : 0; - right : 0; - left : 0; - height : 1.5em; - background: rgba(0, 0, 0, 0.5); - z-index : 1; -} - -.ueb-viewport-zoom { - color: #4d4d4db7; -} - -.ueb-viewport-body { - position : relative; - height : var(--ueb-viewport-height); - width : var(--ueb-viewport-width); - overflow : hidden; - scrollbar-width: 0; -} - -ueb-blueprint[data-focused="true"] .ueb-viewport-body { - overflow: scroll; -} - -.ueb-grid { - --ueb-grid-line-actual-width: calc(var(--ueb-grid-line-width) / var(--ueb-scale)); - position : absolute; - min-width : 100%; - min-height : 100%; - width : calc((100% + var(--ueb-additional-x) * 1px) / var(--ueb-scale)); - height : calc((100% + var(--ueb-additional-y) * 1px) / var(--ueb-scale)); - background-color : #262626; - background-image : - /* Axis lines */ - linear-gradient(var(--ueb-grid-axis-line-color), - var(--ueb-grid-axis-line-color)), - linear-gradient(var(--ueb-grid-axis-line-color), - var(--ueb-grid-axis-line-color)), - /* Dark bigger grid */ - linear-gradient(to right, - var(--ueb-grid-set-line-color), - var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width), - transparent var(--ueb-grid-line-actual-width), - transparent), - linear-gradient(to bottom, - var(--ueb-grid-set-line-color), - var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width), - transparent var(--ueb-grid-line-actual-width), - transparent), - /* Light grid */ - linear-gradient(to right, - var(--ueb-grid-line-color), - var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width), - transparent var(--ueb-grid-line-actual-width), - transparent), - linear-gradient(to bottom, - var(--ueb-grid-line-color), - var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width), - transparent var(--ueb-grid-line-actual-width), - transparent); - background-size: - /* Axis lines */ - 100% var(--ueb-grid-line-actual-width), - var(--ueb-grid-line-actual-width) 100%, - /* Dark bigger grid */ - calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)), - calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)), - /* Light grid */ - var(--ueb-grid-actual-size) var(--ueb-grid-actual-size), - var(--ueb-grid-actual-size) var(--ueb-grid-actual-size); - background-position: calc(var(--ueb-translate-x) * 1px) calc(var(--ueb-translate-y) * 1px); - background-repeat : repeat-x, repeat-y, repeat, repeat, repeat, repeat; - transform : scale(var(--ueb-scale), var(--ueb-scale)); - transform-origin : 0 0; - overflow : hidden; -} - -.ueb-grid[data-drag-scrolling="true"] { - cursor: grabbing; -} - -.ueb-zoom--.ueb, -.ueb { - /* 16/16 */ - --ueb-scale : 1; - --ueb-grid-actual-size: var(--ueb-grid-size); -} - -.ueb-zoom--1.ueb { - /* 14/16 */ - --ueb-scale: 0.875; -} - -.ueb-zoom--2.ueb { - /* 12/16 */ - --ueb-scale: 0.75; -} - -.ueb-zoom--3.ueb { - /* 10.8/16 */ - --ueb-scale: 0.675; -} - -.ueb-zoom--4.ueb { - /* 8/16 */ - --ueb-scale : 0.5; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2); -} - -.ueb-zoom--5.ueb { - /* 6/16 */ - --ueb-scale : 0.375; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2); -} - -.ueb-zoom--6.ueb { - --ueb-scale : 0.333333; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); -} - -.ueb-zoom--7.ueb { - --ueb-scale : 0.3; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); -} - -.ueb-zoom--8.ueb { - --ueb-scale : 0.266666; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); -} - -.ueb-zoom--9.ueb { - --ueb-scale : 0.233333; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); -} - -.ueb-zoom--10.ueb { - /* 12/16 */ - --ueb-scale : 0.2; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); -} - -.ueb-zoom--11.ueb { - /* 12/16 */ - --ueb-scale : 0.166666; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6); -} - -.ueb-zoom--12.ueb { - /* 12/16 */ - --ueb-scale : 0.133333; - --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6); -} - -.ueb-grid-content { - position : relative; - width : 0; - height : 0; - transform: translateX(calc(var(--ueb-translate-x) * 1px)) translateY(calc(var(--ueb-translate-y) * 1px)); -} - -ueb-node { - display : block; - position : absolute; - transform : translateX(calc(var(--ueb-position-x) * 1px)) translateY(calc(var(--ueb-position-y) * 1px)); - border-radius: var(--ueb-node-radius); - box-shadow : 0 0 1px 0 black, 1px 4px 6px 0 rgba(0, 0, 0, 0.3); - will-change : transform; -} - -.ueb-grid[data-drag-scrolling="false"] ueb-selector[data-selecting="false"]~ueb-node { - cursor: move; -} - -.ueb-node-border { - margin : -3px; - padding : 3px; - border-radius: calc(var(--ueb-node-radius) * 1.4); -} - -.ueb-selected { - z-index: 1; -} - -.ueb-selected>.ueb-node-border { - background-image: - linear-gradient(to right, #f1b000 0%, #f1b000 100%), - linear-gradient(to bottom, #f1b000 0%, #cc6700 100%), - linear-gradient(to right, #cc6700 0%, #cc6700 100%), - linear-gradient(to bottom, #f1b000 0%, #cc6700 100%); - background-size : 100% 7px, 7px 100%, 100% 7px, 7px 100%; - background-position: top, right, bottom, left; - background-repeat : repeat-x, repeat-y, repeat-x, repeat-y; - outline : 3px solid #cc6700; - outline-offset : -6px; -} - -.ueb-node-content { - position : relative; - padding : 1px; - box-shadow : inset 0 0 2px 0 black; - border-radius: var(--ueb-node-radius); - background : rgba(0, 0, 0, 0.7); - overflow : hidden; -} - -.ueb-node-header { - padding : 0.2em 0.7em; - box-shadow : inset 0 1px 2px 0 #313631, inset 0 2px 0 0 #92c381; - border-radius: var(--ueb-node-radius) var(--ueb-node-radius) 0 0; - background : linear-gradient(170deg, #5f815a 0%, #5f815a 50%, transparent 100%); - color : #c0c0c0; - font-weight : 600; - white-space : nowrap; -} - -.ueb-node-name { - background: radial-gradient(closest-side, rgba(0, 0, 0, 0.5) 0%, transparent 90%); - margin : -0.1em -1.6em; - padding : 0.1em 1.6em; -} - -.ueb-node-body { - display : flex; - padding : 6px 0; - color : white; - font-weight: 100; - white-space: nowrap; -} - -.ueb-node-inputs { - margin-right: auto; - padding-left: 8px; -} - -.ueb-node-outputs { - padding-right: 8px; -} - -ueb-pin { - display: block; - padding: 1px 2px; -} - -.ueb-grid[data-drag-scrolling="false"] { - cursor: default; -} - -ueb-selector[data-selecting="false"]~ueb-node ueb-pin:hover { - background: var(--ueb-node-value-background); -} - -.ueb-grid[data-drag-scrolling="false"] ueb-selector[data-selecting="false"]~ueb-node ueb-pin .ueb-node-value-icon { - cursor: crosshair; -} - -.ueb-node-value-icon { - display : inline-block; - position : relative; - width : 0.85em; - height : 0.85em; - vertical-align: baseline; - margin : 0 0.4em -1px 0.1em; -} - -.ueb-node-value-icon::before { - content : ""; - display : block; - position : absolute; - top : 0; - right : 0; - bottom : 0; - left : 0; - border : 2px solid var(--ueb-node-value-color); - border-radius: 50%; -} - -.ueb-node-value-fill::before { - background: var(--ueb-node-value-color); -} - -.ueb-node-value-icon::after { - content : ""; - display : block; - position : absolute; - top : calc(50% - 0.3em); - left : calc(100% + 1px); - width : 0; - height : 0; - border-top : 0.3em solid transparent; - border-bottom: 0.3em solid transparent; - border-left : 0.3em solid var(--ueb-node-value-color); -} - -.ueb-selector { - display : block; - position : absolute; - visibility: hidden; - top : 0; - left : 0; - width : 0; - height : 0; - background-image: - /* Top */ - repeating-linear-gradient(90deg, - transparent, - transparent calc(1px / var(--ueb-scale)), - white calc(2px / var(--ueb-scale)), - white calc(7px / var(--ueb-scale)), - transparent calc(7px / var(--ueb-scale)), - transparent calc(11px / var(--ueb-scale))), - repeating-linear-gradient(90deg, - black, - black calc(8px / var(--ueb-scale)), - transparent calc(9px / var(--ueb-scale)), - transparent calc(11px / var(--ueb-scale))), - /* Bottom */ - repeating-linear-gradient(90deg, - transparent, - transparent calc(1px / var(--ueb-scale)), - white calc(2px / var(--ueb-scale)), - white calc(7px / var(--ueb-scale)), - transparent calc(7px / var(--ueb-scale)), - transparent calc(11px / var(--ueb-scale))), - repeating-linear-gradient(90deg, - black, - black calc(8px / var(--ueb-scale)), - transparent calc(9px / var(--ueb-scale)), - transparent calc(11px / var(--ueb-scale))), - /* Left */ - repeating-linear-gradient(180deg, - transparent, - transparent calc(1px / var(--ueb-scale)), - white calc(1px / var(--ueb-scale)), - white calc(7px / var(--ueb-scale)), - transparent calc(7px / var(--ueb-scale)), - transparent calc(11px / var(--ueb-scale))), - repeating-linear-gradient(180deg, - black, - black calc(8px / var(--ueb-scale)), - transparent calc(9px / var(--ueb-scale)), - transparent calc(11px / var(--ueb-scale))), - /* Right */ - repeating-linear-gradient(0deg, - transparent, - transparent calc(1px / var(--ueb-scale)), - white calc(2px / var(--ueb-scale)), - white calc(7px / var(--ueb-scale)), - transparent calc(7px / var(--ueb-scale)), - transparent calc(11px / var(--ueb-scale))), - repeating-linear-gradient(0deg, - black, - black calc(8px / var(--ueb-scale)), - transparent calc(9px / var(--ueb-scale)), - transparent calc(11px / var(--ueb-scale))); - background-size: - /* Top */ - 100% calc(1px / var(--ueb-scale)), - 100% calc(3px / var(--ueb-scale)), - /* Bottom */ - 100% calc(1px / var(--ueb-scale)), - 100% calc(3px / var(--ueb-scale)), - /* Left */ - calc(1px / var(--ueb-scale)) 100%, - calc(3px / var(--ueb-scale)) 100%, - /* Right */ - calc(1px / var(--ueb-scale)) 100%, - calc(3px / var(--ueb-scale)) 100%; - background-position: - /* Top */ - 0 calc(1px / var(--ueb-scale)), 0 0, - /* Bottom */ - 0 calc(100% - 1px / var(--ueb-scale)), 0 100%, - /* Left */ - calc(1px / var(--ueb-scale)) 0, 0 0, - /* Right */ - calc(100% - 1px / var(--ueb-scale)) 0, 100% 0; - background-repeat: no-repeat; -} - -ueb-selector>* { - visibility: visible; -} - -ueb-selector[data-selecting="true"] { - visibility: visible; - top : min(var(--ueb-select-from-y) * 1px, var(--ueb-select-to-y) * 1px); - left : min(var(--ueb-select-from-x) * 1px, var(--ueb-select-to-x) * 1px); - width : calc(max(var(--ueb-select-from-x) - var(--ueb-select-to-x), var(--ueb-select-to-x) - var(--ueb-select-from-x)) * 1px); - height : calc(max(var(--ueb-select-from-y) - var(--ueb-select-to-y), var(--ueb-select-to-y) - var(--ueb-select-from-y)) * 1px); +@font-face { + font-family: "Roboto"; + font-style : light; + src : + url("../font/roboto-light.woff2") format("woff2"), + url("../font/roboto-light.woff") format("woff"); +} + +@font-face { + font-family: "Roboto"; + font-style : regular; + src : + url("../font/roboto-regular.woff2") format("woff2"), + url("../font/roboto-regular.woff") format("woff"); +} + +:root { + --ueb-fron-size : 13px; + --ueb-viewport-height : 30rem; + --ueb-viewport-width : 100%; + --ueb-grid-size : 16px; + --ueb-grid-line-width : 2px; + --ueb-grid-line-color : #353535; + --ueb-grid-set : 8; + --ueb-grid-set-line-color : #161616; + --ueb-grid-axis-line-color: black; + --ueb-grid-snap : 16px; + --ueb-node-radius : 8px; +} + +ueb-blueprint { + display : block; + position : relative; + font-family: Roboto, Noto, Oxygen, Ubuntu, "Open Sans", "Helvetica Neue", sans-serif; + font-size : var(--ueb-fron-size); + user-select: none; +} + +.ueb-viewport-header { + display : flex; + position : absolute; + top : 0; + right : 0; + left : 0; + height : 1.5em; + background: rgba(0, 0, 0, 0.5); + z-index : 1; +} + +.ueb-viewport-zoom { + color: #4d4d4db7; +} + +.ueb-viewport-body { + position : relative; + height : var(--ueb-viewport-height); + width : var(--ueb-viewport-width); + overflow : hidden; + scrollbar-width: 0; +} + +ueb-blueprint[data-focused="true"] .ueb-viewport-body { + overflow: scroll; +} + +.ueb-grid { + --ueb-grid-line-actual-width: calc(var(--ueb-grid-line-width) / var(--ueb-scale)); + position : absolute; + min-width : 100%; + min-height : 100%; + width : calc((100% + var(--ueb-additional-x) * 1px) / var(--ueb-scale)); + height : calc((100% + var(--ueb-additional-y) * 1px) / var(--ueb-scale)); + background-color : #262626; + background-image : + /* Axis lines */ + linear-gradient(var(--ueb-grid-axis-line-color), + var(--ueb-grid-axis-line-color)), + linear-gradient(var(--ueb-grid-axis-line-color), + var(--ueb-grid-axis-line-color)), + /* Dark bigger grid */ + linear-gradient(to right, + var(--ueb-grid-set-line-color), + var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width), + transparent var(--ueb-grid-line-actual-width), + transparent), + linear-gradient(to bottom, + var(--ueb-grid-set-line-color), + var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width), + transparent var(--ueb-grid-line-actual-width), + transparent), + /* Light grid */ + linear-gradient(to right, + var(--ueb-grid-line-color), + var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width), + transparent var(--ueb-grid-line-actual-width), + transparent), + linear-gradient(to bottom, + var(--ueb-grid-line-color), + var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width), + transparent var(--ueb-grid-line-actual-width), + transparent); + background-size: + /* Axis lines */ + 100% var(--ueb-grid-line-actual-width), + var(--ueb-grid-line-actual-width) 100%, + /* Dark bigger grid */ + calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)), + calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)), + /* Light grid */ + var(--ueb-grid-actual-size) var(--ueb-grid-actual-size), + var(--ueb-grid-actual-size) var(--ueb-grid-actual-size); + background-position: calc(var(--ueb-translate-x) * 1px) calc(var(--ueb-translate-y) * 1px); + background-repeat : repeat-x, repeat-y, repeat, repeat, repeat, repeat; + transform : scale(var(--ueb-scale), var(--ueb-scale)); + transform-origin : 0 0; + overflow : hidden; +} + +.ueb-grid[data-drag-scrolling="true"] { + cursor: grabbing; +} + +.ueb-zoom--.ueb, +.ueb { + /* 16/16 */ + --ueb-scale : 1; + --ueb-grid-actual-size: var(--ueb-grid-size); +} + +.ueb-zoom--1.ueb { + /* 14/16 */ + --ueb-scale: 0.875; +} + +.ueb-zoom--2.ueb { + /* 12/16 */ + --ueb-scale: 0.75; +} + +.ueb-zoom--3.ueb { + /* 10.8/16 */ + --ueb-scale: 0.675; +} + +.ueb-zoom--4.ueb { + /* 8/16 */ + --ueb-scale : 0.5; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2); +} + +.ueb-zoom--5.ueb { + /* 6/16 */ + --ueb-scale : 0.375; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2); +} + +.ueb-zoom--6.ueb { + --ueb-scale : 0.333333; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); +} + +.ueb-zoom--7.ueb { + --ueb-scale : 0.3; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); +} + +.ueb-zoom--8.ueb { + --ueb-scale : 0.266666; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); +} + +.ueb-zoom--9.ueb { + --ueb-scale : 0.233333; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); +} + +.ueb-zoom--10.ueb { + /* 12/16 */ + --ueb-scale : 0.2; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3); +} + +.ueb-zoom--11.ueb { + /* 12/16 */ + --ueb-scale : 0.166666; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6); +} + +.ueb-zoom--12.ueb { + /* 12/16 */ + --ueb-scale : 0.133333; + --ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6); +} + +.ueb-grid-content { + position : relative; + width : 0; + height : 0; + transform: translateX(calc(var(--ueb-translate-x) * 1px)) translateY(calc(var(--ueb-translate-y) * 1px)); +} + +ueb-node { + display : block; + position : absolute; + transform : translateX(calc(var(--ueb-position-x) * 1px)) translateY(calc(var(--ueb-position-y) * 1px)); + border-radius: var(--ueb-node-radius); + box-shadow : 0 0 1px 0 black, 1px 4px 6px 0 rgba(0, 0, 0, 0.3); + will-change : transform; +} + +.ueb-grid[data-drag-scrolling="false"] ueb-selector[data-selecting="false"]~ueb-node { + cursor: move; +} + +.ueb-node-border { + margin : -3px; + padding : 3px; + border-radius: calc(var(--ueb-node-radius) * 1.4); +} + +.ueb-selected { + z-index: 1; +} + +.ueb-selected>.ueb-node-border { + background-image: + linear-gradient(to right, #f1b000 0%, #f1b000 100%), + linear-gradient(to bottom, #f1b000 0%, #cc6700 100%), + linear-gradient(to right, #cc6700 0%, #cc6700 100%), + linear-gradient(to bottom, #f1b000 0%, #cc6700 100%); + background-size : 100% 7px, 7px 100%, 100% 7px, 7px 100%; + background-position: top, right, bottom, left; + background-repeat : repeat-x, repeat-y, repeat-x, repeat-y; + outline : 3px solid #cc6700; + outline-offset : -6px; +} + +.ueb-node-content { + position : relative; + padding : 1px; + box-shadow : inset 0 0 2px 0 black; + border-radius: var(--ueb-node-radius); + background : rgba(0, 0, 0, 0.7); + overflow : hidden; +} + +.ueb-node-header { + padding : 0.2em 0.7em; + box-shadow : inset 0 1px 2px 0 #313631, inset 0 2px 0 0 #92c381; + border-radius: var(--ueb-node-radius) var(--ueb-node-radius) 0 0; + background : linear-gradient(170deg, #5f815a 0%, #5f815a 50%, transparent 100%); + color : #c0c0c0; + font-weight : 600; + white-space : nowrap; +} + +.ueb-node-name { + background: radial-gradient(closest-side, rgba(0, 0, 0, 0.5) 0%, transparent 90%); + margin : -0.1em -1.6em; + padding : 0.1em 1.6em; +} + +.ueb-node-body { + display : flex; + padding : 6px 0; + color : white; + font-weight: 100; + white-space: nowrap; +} + +.ueb-node-inputs { + margin-right: auto; + padding-left: 8px; +} + +.ueb-node-outputs { + padding-right: 8px; +} + +ueb-pin { + display: block; + padding: 1px 2px; +} + +.ueb-grid[data-drag-scrolling="false"] { + cursor: default; +} + +ueb-selector[data-selecting="false"]~ueb-node ueb-pin:hover { + background: var(--ueb-node-value-background); +} + +.ueb-grid[data-drag-scrolling="false"] ueb-selector[data-selecting="false"]~ueb-node ueb-pin .ueb-node-value-icon { + cursor: crosshair; +} + +.ueb-node-value-icon { + display : inline-block; + position : relative; + width : 0.85em; + height : 0.85em; + vertical-align: baseline; + margin : 0 0.4em -1px 0.1em; +} + +.ueb-node-value-icon::before { + content : ""; + display : block; + position : absolute; + top : 0; + right : 0; + bottom : 0; + left : 0; + border : 2px solid var(--ueb-node-value-color); + border-radius: 50%; +} + +.ueb-node-value-fill::before { + background: var(--ueb-node-value-color); +} + +.ueb-node-value-icon::after { + content : ""; + display : block; + position : absolute; + top : calc(50% - 0.3em); + left : calc(100% + 1px); + width : 0; + height : 0; + border-top : 0.3em solid transparent; + border-bottom: 0.3em solid transparent; + border-left : 0.3em solid var(--ueb-node-value-color); +} + +.ueb-selector { + display : block; + position : absolute; + visibility: hidden; + top : 0; + left : 0; + width : 0; + height : 0; + background-image: + /* Top */ + repeating-linear-gradient(90deg, + transparent, + transparent calc(1px / var(--ueb-scale)), + white calc(2px / var(--ueb-scale)), + white calc(7px / var(--ueb-scale)), + transparent calc(7px / var(--ueb-scale)), + transparent calc(11px / var(--ueb-scale))), + repeating-linear-gradient(90deg, + black, + black calc(8px / var(--ueb-scale)), + transparent calc(9px / var(--ueb-scale)), + transparent calc(11px / var(--ueb-scale))), + /* Bottom */ + repeating-linear-gradient(90deg, + transparent, + transparent calc(1px / var(--ueb-scale)), + white calc(2px / var(--ueb-scale)), + white calc(7px / var(--ueb-scale)), + transparent calc(7px / var(--ueb-scale)), + transparent calc(11px / var(--ueb-scale))), + repeating-linear-gradient(90deg, + black, + black calc(8px / var(--ueb-scale)), + transparent calc(9px / var(--ueb-scale)), + transparent calc(11px / var(--ueb-scale))), + /* Left */ + repeating-linear-gradient(180deg, + transparent, + transparent calc(1px / var(--ueb-scale)), + white calc(1px / var(--ueb-scale)), + white calc(7px / var(--ueb-scale)), + transparent calc(7px / var(--ueb-scale)), + transparent calc(11px / var(--ueb-scale))), + repeating-linear-gradient(180deg, + black, + black calc(8px / var(--ueb-scale)), + transparent calc(9px / var(--ueb-scale)), + transparent calc(11px / var(--ueb-scale))), + /* Right */ + repeating-linear-gradient(0deg, + transparent, + transparent calc(1px / var(--ueb-scale)), + white calc(2px / var(--ueb-scale)), + white calc(7px / var(--ueb-scale)), + transparent calc(7px / var(--ueb-scale)), + transparent calc(11px / var(--ueb-scale))), + repeating-linear-gradient(0deg, + black, + black calc(8px / var(--ueb-scale)), + transparent calc(9px / var(--ueb-scale)), + transparent calc(11px / var(--ueb-scale))); + background-size: + /* Top */ + 100% calc(1px / var(--ueb-scale)), + 100% calc(3px / var(--ueb-scale)), + /* Bottom */ + 100% calc(1px / var(--ueb-scale)), + 100% calc(3px / var(--ueb-scale)), + /* Left */ + calc(1px / var(--ueb-scale)) 100%, + calc(3px / var(--ueb-scale)) 100%, + /* Right */ + calc(1px / var(--ueb-scale)) 100%, + calc(3px / var(--ueb-scale)) 100%; + background-position: + /* Top */ + 0 calc(1px / var(--ueb-scale)), 0 0, + /* Bottom */ + 0 calc(100% - 1px / var(--ueb-scale)), 0 100%, + /* Left */ + calc(1px / var(--ueb-scale)) 0, 0 0, + /* Right */ + calc(100% - 1px / var(--ueb-scale)) 0, 100% 0; + background-repeat: no-repeat; +} + +ueb-selector>* { + visibility: visible; +} + +ueb-selector[data-selecting="true"] { + visibility: visible; + top : min(var(--ueb-select-from-y) * 1px, var(--ueb-select-to-y) * 1px); + left : min(var(--ueb-select-from-x) * 1px, var(--ueb-select-to-x) * 1px); + width : calc(max(var(--ueb-select-from-x) - var(--ueb-select-to-x), var(--ueb-select-to-x) - var(--ueb-select-from-x)) * 1px); + height : calc(max(var(--ueb-select-from-y) - var(--ueb-select-to-y), var(--ueb-select-to-y) - var(--ueb-select-from-y)) * 1px); } \ No newline at end of file