From e901932953de706da7cf676245146896a5c9eabd Mon Sep 17 00:00:00 2001 From: barsdeveloper Date: Sat, 2 Apr 2022 11:13:34 +0200 Subject: [PATCH] WIP --- dist/ueblueprint.js | 470 +++++++++++-------- js/Blueprint.js | 23 +- js/Configuration.js | 4 + js/Utility.js | 1 - js/element/ISelectableDraggableElement.js | 1 - js/element/LinkElement.js | 1 - js/element/NodeElement.js | 1 - js/element/PinElement.js | 8 +- js/entity/PinEntity.js | 6 +- js/input/IContext.js | 31 +- js/input/common/Copy.js | 2 +- js/input/common/Paste.js | 2 +- js/input/keybaord/IKeyboardShortcut.js | 10 +- js/input/keybaord/KeyboardEnableZoom.js | 2 +- js/input/keybaord/KeyboardIgnoreSelectAll.js | 26 + js/input/keybaord/KeyboardSelectAll.js | 5 +- js/input/mouse/IMouseClickDrag.js | 10 +- js/input/mouse/IMouseWheel.js | 2 +- js/input/mouse/MouseTracking.js | 2 +- js/input/mouse/Unfocus.js | 10 +- js/selection/FastSelectionModel.js | 31 +- js/template/BlueprintTemplate.js | 1 - js/template/LinkTemplate.js | 1 - js/template/NodeTemplate.js | 2 +- js/template/PinTemplate.js | 10 +- js/template/StringPinTemplate.js | 9 +- 26 files changed, 392 insertions(+), 279 deletions(-) create mode 100755 js/input/keybaord/KeyboardIgnoreSelectAll.js diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js index 371289c..7000f32 100755 --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -1,143 +1,5 @@ // @ts-check -class Configuration { - deleteNodesKeyboardKey = "Delete" - enableZoomIn = ["LeftControl", "RightControl"] // Button to enable more than 0 (1:1) zoom - expandGridSize = 400 - fontSize = "12px" - gridAxisLineColor = "black" - gridExpandThreshold = 0.25 // remaining size factor threshold to cause an expansion event - gridShrinkThreshold = 4 // exceding size factor threshold to cause a shrink event - gridLineColor = "#353535" - gridLineWidth = 1 // pixel - gridSet = 8 - gridSetLineColor = "#161616" - gridSize = 16 // pixel - keysSeparator = "+" - linkCurveHeight = 15 // pixel - linkCurveWidth = 80 // pixel - linkMinWidth = 100 // pixel - /** - * @param {Number} start - * @param {Number} c1 - * @param {Number} c2 - */ - linkRightSVGPath = (start, c1, c2) => { - let end = 100 - start; - return `M ${start} 0 C ${c1} 0, ${c2} 0, 50 50 S ${end - c1 + start} 100, ${end} 100` - } - maxZoom = 7 - minZoom = -12 - nodeDeleteEventName = "ueb-node-delete" - nodeDragEventName = "ueb-node-drag" - nodeDragLocalEventName = "ueb-node-drag-local" - nodeRadius = 8 // in pixel - selectAllKeyboardKey = "(bCtrl=True,Key=A)" - trackingMouseEventName = { - begin: "ueb-tracking-mouse-begin", - end: "ueb-tracking-mouse-end" - } - ModifierKeys = [ - "Ctrl", - "Shift", - "Alt", - "Meta" - ] - Keys = { - /* UE name: JS name */ - "Backspace": "Backspace", - "Tab": "Tab", - "LeftControl": "ControlLeft", - "RightControl": "ControlRight", - "LeftShift": "ShiftLeft", - "RightShift": "ShiftRight", - "LeftAlt": "AltLeft", - "RightAlt": "AltRight", - "Enter": "Enter", - "Pause": "Pause", - "CapsLock": "CapsLock", - "Escape": "Escape", - "Space": "Space", - "PageUp": "PageUp", - "PageDown": "PageDown", - "End": "End", - "Home": "Home", - "ArrowLeft": "Left", - "ArrowUp": "Up", - "ArrowRight": "Right", - "ArrowDown": "Down", - "PrintScreen": "PrintScreen", - "Insert": "Insert", - "Delete": "Delete", - "Zero": "Digit0", - "One": "Digit1", - "Two": "Digit2", - "Three": "Digit3", - "Four": "Digit4", - "Five": "Digit5", - "Six": "Digit6", - "Seven": "Digit7", - "Eight": "Digit8", - "Nine": "Digit9", - "A": "KeyA", - "B": "KeyB", - "C": "KeyC", - "D": "KeyD", - "E": "KeyE", - "F": "KeyF", - "G": "KeyG", - "H": "KeyH", - "I": "KeyI", - "K": "KeyK", - "L": "KeyL", - "M": "KeyM", - "N": "KeyN", - "O": "KeyO", - "P": "KeyP", - "Q": "KeyQ", - "R": "KeyR", - "S": "KeyS", - "T": "KeyT", - "U": "KeyU", - "V": "KeyV", - "W": "KeyW", - "X": "KeyX", - "Y": "KeyY", - "Z": "KeyZ", - "NumPadZero": "Numpad0", - "NumPadOne": "Numpad1", - "NumPadTwo": "Numpad2", - "NumPadThree": "Numpad3", - "NumPadFour": "Numpad4", - "NumPadFive": "Numpad5", - "NumPadSix": "Numpad6", - "NumPadSeven": "Numpad7", - "NumPadEight": "Numpad8", - "NumPadNine": "Numpad9", - "Multiply": "NumpadMultiply", - "Add": "NumpadAdd", - "Subtract": "NumpadSubtract", - "Decimal": "NumpadDecimal", - "Divide": "NumpadDivide", - "F1": "F1", - "F2": "F2", - "F3": "F3", - "F4": "F4", - "F5": "F5", - "F6": "F6", - "F7": "F7", - "F8": "F8", - "F9": "F9", - "F10": "F10", - "F11": "F11", - "F12": "F12", - "NumLock": "NumLock", - "ScrollLock": "ScrollLock", - } -} - -// @ts-check - /** * This solves the sole purpose of providing compression capability for html inside template literals strings. Check rollup.config.js function minifyHTML() */ @@ -331,27 +193,27 @@ class OrderedIndexArray { /** * @typedef {{ - * primaryInf: number, - * primarySup: number, - * secondaryInf: number, - * secondarySup: number + * primaryInf: Number, + * primarySup: Number, + * secondaryInf: Number, + * secondarySup: Number * }} BoundariesInfo * @typedef {{ - * primaryBoundary: number, - * secondaryBoundary: number, - * insertionPosition: number, - * rectangle: number - * onSecondaryAxis: Boolean + * primaryBoundary: Number, + * secondaryBoundary: Number, + * insertionPosition?: Number, + * rectangle: Number + * onSecondaryAxis: Boolean * }} Metadata - * @typedef {numeric} Rectangle + * @typedef {any} Rectangle */ class FastSelectionModel { /** - * @param {number[]} initialPosition Coordinates of the starting point of selection [primaryAxisValue, secondaryAxisValue]. + * @param {Number[]} initialPosition Coordinates of the starting point of selection [primaryAxisValue, secondaryAxisValue]. * @param {Rectangle[]} rectangles Rectangles that can be selected by this object. * @param {(rect: Rectangle) => BoundariesInfo} boundariesFunc A function that, given a rectangle, it provides the boundaries of such rectangle. - * @param {(rect: Rectangle, selected: bool) => void} selectFunc A function that selects or deselects individual rectangles. + * @param {(rect: Rectangle, selected: Boolean) => void} selectFunc A function that selects or deselects individual rectangles. */ constructor(initialPosition, rectangles, boundariesFunc, selectFunc) { this.initialPosition = initialPosition; @@ -402,7 +264,7 @@ class FastSelectionModel { }); this.primaryOrder.currentPosition = this.primaryOrder.getPosition(this.initialPosition[0]); this.secondaryOrder.currentPosition = this.secondaryOrder.getPosition(this.initialPosition[1]); - this.computeBoundaries(this.initialPosition); + this.computeBoundaries(); } computeBoundaries() { @@ -455,7 +317,7 @@ class FastSelectionModel { this.secondaryOrder.remove(index); } } - this.computeBoundaries(finalPosition); + this.computeBoundaries(); this.selectTo(finalPosition); }; @@ -473,7 +335,7 @@ class FastSelectionModel { const secondaryBoundaryCrossed = (index, added) => { this.selectFunc(this.rectangles[index], added); - this.computeBoundaries(finalPosition); + this.computeBoundaries(); this.selectTo(finalPosition); }; @@ -490,7 +352,6 @@ class FastSelectionModel { } this.finalPosition = finalPosition; } - } // @ts-check @@ -791,6 +652,148 @@ class BlueprintTemplate extends ITemplate { } } +// @ts-check + +class Configuration { + deleteNodesKeyboardKey = "Delete" + editTextEventName = { + begin: "ueb-edit-text-begin", + end: "ueb-edit-text-end" + } + enableZoomIn = ["LeftControl", "RightControl"] // Button to enable more than 0 (1:1) zoom + expandGridSize = 400 + fontSize = "12px" + gridAxisLineColor = "black" + gridExpandThreshold = 0.25 // remaining size factor threshold to cause an expansion event + gridShrinkThreshold = 4 // exceding size factor threshold to cause a shrink event + gridLineColor = "#353535" + gridLineWidth = 1 // pixel + gridSet = 8 + gridSetLineColor = "#161616" + gridSize = 16 // pixel + keysSeparator = "+" + linkCurveHeight = 15 // pixel + linkCurveWidth = 80 // pixel + linkMinWidth = 100 // pixel + /** + * @param {Number} start + * @param {Number} c1 + * @param {Number} c2 + */ + linkRightSVGPath = (start, c1, c2) => { + let end = 100 - start; + return `M ${start} 0 C ${c1} 0, ${c2} 0, 50 50 S ${end - c1 + start} 100, ${end} 100` + } + maxZoom = 7 + minZoom = -12 + nodeDeleteEventName = "ueb-node-delete" + nodeDragEventName = "ueb-node-drag" + nodeDragLocalEventName = "ueb-node-drag-local" + nodeRadius = 8 // in pixel + selectAllKeyboardKey = "(bCtrl=True,Key=A)" + trackingMouseEventName = { + begin: "ueb-tracking-mouse-begin", + end: "ueb-tracking-mouse-end" + } + ModifierKeys = [ + "Ctrl", + "Shift", + "Alt", + "Meta" + ] + Keys = { + /* UE name: JS name */ + "Backspace": "Backspace", + "Tab": "Tab", + "LeftControl": "ControlLeft", + "RightControl": "ControlRight", + "LeftShift": "ShiftLeft", + "RightShift": "ShiftRight", + "LeftAlt": "AltLeft", + "RightAlt": "AltRight", + "Enter": "Enter", + "Pause": "Pause", + "CapsLock": "CapsLock", + "Escape": "Escape", + "Space": "Space", + "PageUp": "PageUp", + "PageDown": "PageDown", + "End": "End", + "Home": "Home", + "ArrowLeft": "Left", + "ArrowUp": "Up", + "ArrowRight": "Right", + "ArrowDown": "Down", + "PrintScreen": "PrintScreen", + "Insert": "Insert", + "Delete": "Delete", + "Zero": "Digit0", + "One": "Digit1", + "Two": "Digit2", + "Three": "Digit3", + "Four": "Digit4", + "Five": "Digit5", + "Six": "Digit6", + "Seven": "Digit7", + "Eight": "Digit8", + "Nine": "Digit9", + "A": "KeyA", + "B": "KeyB", + "C": "KeyC", + "D": "KeyD", + "E": "KeyE", + "F": "KeyF", + "G": "KeyG", + "H": "KeyH", + "I": "KeyI", + "K": "KeyK", + "L": "KeyL", + "M": "KeyM", + "N": "KeyN", + "O": "KeyO", + "P": "KeyP", + "Q": "KeyQ", + "R": "KeyR", + "S": "KeyS", + "T": "KeyT", + "U": "KeyU", + "V": "KeyV", + "W": "KeyW", + "X": "KeyX", + "Y": "KeyY", + "Z": "KeyZ", + "NumPadZero": "Numpad0", + "NumPadOne": "Numpad1", + "NumPadTwo": "Numpad2", + "NumPadThree": "Numpad3", + "NumPadFour": "Numpad4", + "NumPadFive": "Numpad5", + "NumPadSix": "Numpad6", + "NumPadSeven": "Numpad7", + "NumPadEight": "Numpad8", + "NumPadNine": "Numpad9", + "Multiply": "NumpadMultiply", + "Add": "NumpadAdd", + "Subtract": "NumpadSubtract", + "Decimal": "NumpadDecimal", + "Divide": "NumpadDivide", + "F1": "F1", + "F2": "F2", + "F3": "F3", + "F4": "F4", + "F5": "F5", + "F6": "F6", + "F7": "F7", + "F8": "F8", + "F9": "F9", + "F10": "F10", + "F11": "F11", + "F12": "F12", + "NumLock": "NumLock", + "ScrollLock": "ScrollLock", + } +} + // @ts-check /** @@ -807,38 +810,33 @@ class IContext { /** @type {Object} */ options - #hasFocus = false - - get hasFocus() { - return this.#hasFocus - } - - set hasFocus(_) { - } - constructor(target, blueprint, options) { this.target = target; this.blueprint = blueprint; this.options = options; let self = this; - this.blueprintFocusHandler = _ => { - this.#hasFocus = true; + this.listenHandler = _ => { self.listenEvents(); }; - this.blueprintUnfocusHandler = _ => { + this.unlistenHandler = _ => { self.unlistenEvents(); - this.#hasFocus = false; }; - if (options?.wantsFocusCallback ?? false) { - this.blueprint.addEventListener("blueprint-focus", this.blueprintFocusHandler); - this.blueprint.addEventListener("blueprint-unfocus", this.blueprintUnfocusHandler); + if (options?.listenOnFocus ?? false) { + this.blueprint.addEventListener("blueprint-focus", this.listenHandler); + this.blueprint.addEventListener("blueprint-unfocus", this.unlistenHandler); + } + if (options?.unlistenOnEditText ?? false) { + this.blueprint.addEventListener(this.blueprint.settings.editTextEventName.begin, this.unlistenHandler); + this.blueprint.addEventListener(this.blueprint.settings.editTextEventName.end, this.listenHandler); } } unlistenDOMElement() { this.unlistenEvents(); - this.blueprint.removeEventListener("blueprint-focus", this.blueprintFocusHandler); - this.blueprint.removeEventListener("blueprint-unfocus", this.blueprintUnfocusHandler); + this.blueprint.removeEventListener("blueprint-focus", this.listenHandler); + this.blueprint.removeEventListener("blueprint-unfocus", this.unlistenHandler); + this.blueprint.removeEventListener(this.blueprint.settings.editTextEventName.begin, this.unlistenHandler); + this.blueprint.removeEventListener(this.blueprint.settings.editTextEventName.end, this.listenHandler); } /* Subclasses will probabily override the following methods */ @@ -1347,7 +1345,11 @@ class PinEntity extends IEntity { return !this.bHidden && this.Direction === "EGPD_Output" } - isConnected() { + /** + * + * @returns {Boolean} + */ + isLinked() { return this.LinkedTo?.length > 0 ?? false } @@ -1878,7 +1880,7 @@ class Copy extends IContext { #copyHandler constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true; + options.listenOnFocus = true; super(target, blueprint, options); this.serializer = new ObjectSerializer(); let self = this; @@ -1907,7 +1909,7 @@ class IKeyboardShortcut extends IContext { #activationKeys constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true; + options.listenOnFocus = true; options.activationKeys ??= []; if (!(options.activationKeys instanceof Array)) { options.activationKeys = [options.activationKeys]; @@ -1944,6 +1946,9 @@ class IKeyboardShortcut extends IContext { && wantsAlt(keyEntry) == e.altKey && this.blueprint.settings.Keys[keyEntry.Key] == e.code )) { + if (options.consumeEvent) { + e.stopImmediatePropagation(); + } self.fire(); document.removeEventListener("keydown", self.keyDownHandler); document.addEventListener("keyup", self.keyUpHandler); @@ -1957,9 +1962,12 @@ class IKeyboardShortcut extends IContext { keyEntry.bShift && e.key == "Shift" || keyEntry.bCtrl && e.key == "Control" || keyEntry.bAlt && e.key == "Alt" - || keyEntry.bCmd && e.key == "Meta" // Unsure about this, what key is that? + || keyEntry.bCmd && e.key == "Meta" || this.blueprint.settings.Keys[keyEntry.Key] == e.code )) { + if (options.consumeEvent) { + e.stopImmediatePropagation(); + } self.unfire(); document.removeEventListener("keyup", this.keyUpHandler); document.addEventListener("keydown", this.keyDownHandler); @@ -2043,7 +2051,7 @@ class IMouseWheel extends IPointing { * @param {Object} options */ constructor(target, blueprint, options) { - options.wantsFocusCallback = true; + options.listenOnFocus = true; super(target, blueprint, options); this.looseTarget = options?.looseTarget ?? true; let self = this; @@ -2108,7 +2116,7 @@ class Zoom extends IMouseWheel { class KeyboardEnableZoom extends IKeyboardShortcut { - /** @type {} */ + /** @type {Zoom} */ #zoomInputObject /** @@ -2136,11 +2144,14 @@ class KeyboardEnableZoom extends IKeyboardShortcut { // @ts-check +/** + * @typedef {import("../../Blueprint").default} Blueprint + */ class KeyboardSelectAll extends IKeyboardShortcut { /** * @param {HTMLElement} target - * @param {import("../../Blueprint").default} blueprint + * @param {Blueprint} blueprint * @param {Object} options */ constructor(target, blueprint, options = {}) { @@ -2562,7 +2573,7 @@ class IMouseClickDrag extends IPointing { this.exitAnyButton = options?.exitAnyButton ?? true; this.moveEverywhere = options?.moveEverywhere ?? false; this.looseTarget = options?.looseTarget ?? false; - this.consumeClickEvent = options?.consumeClickEvent ?? true; + this.consumeEvent = options?.consumeEvent ?? true; this.clickedPosition = [0, 0]; const movementListenedElement = this.moveEverywhere ? document.documentElement : this.movementSpace; @@ -2574,7 +2585,7 @@ class IMouseClickDrag extends IPointing { case self.clickButton: // Either doesn't matter or consider the click only when clicking on the parent, not descandants if (self.looseTarget || e.target == e.currentTarget) { - if (this.consumeClickEvent) { + if (this.consumeEvent) { e.stopImmediatePropagation(); // Captured, don't call anyone else } // Attach the listeners @@ -2593,7 +2604,7 @@ class IMouseClickDrag extends IPointing { }; this.#mouseStartedMovingHandler = e => { - if (this.consumeClickEvent) { + if (this.consumeEvent) { e.stopImmediatePropagation(); // Captured, don't call anyone else } // Delegate from now on to self.#mouseMoveHandler @@ -2608,7 +2619,7 @@ class IMouseClickDrag extends IPointing { }; this.#mouseMoveHandler = e => { - if (this.consumeClickEvent) { + if (this.consumeEvent) { e.stopImmediatePropagation(); // Captured, don't call anyone else } const location = self.locationFromEvent(e); @@ -2621,7 +2632,7 @@ class IMouseClickDrag extends IPointing { this.#mouseUpHandler = e => { if (!self.exitAnyButton || e.button == self.clickButton) { - if (this.consumeClickEvent) { + if (this.consumeEvent) { e.stopImmediatePropagation(); // Captured, don't call anyone else } // Remove the handlers of "mousemove" and "mouseup" @@ -2714,7 +2725,7 @@ class MouseTracking extends IPointing { #trackingMouseGaveBackHandler constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true; + options.listenOnFocus = true; super(target, blueprint, options); let self = this; @@ -3120,6 +3131,10 @@ class MouseCreateLink extends IMouseClickDrag { */ class PinTemplate extends ITemplate { + hasInput() { + return false + } + /** * Computes the html content of the pin. * @param {PinElement} pin html element @@ -3180,7 +3195,9 @@ class PinTemplate extends ITemplate { const targetPin = pin.blueprint.getPin(pinReference); if (targetPin) { const [sourcePin, destinationPin] = pin.isOutput() ? [pin, targetPin] : [targetPin, pin]; - pin.blueprint.addGraphElement(new LinkElement(sourcePin, destinationPin)); + pin.blueprint.addGraphElement( + new LinkElement(/** @type {PinElement} */(sourcePin), /** @type {PinElement} */(destinationPin)) + ); } }); } @@ -3190,7 +3207,7 @@ class PinTemplate extends ITemplate { * @param {PinElement} pin */ applyConnected(pin) { - if (pin.isConnected()) { + if (pin.isLinked()) { pin.classList.add("ueb-pin-fill"); } else { pin.classList.remove("ueb-pin-fill"); @@ -3234,21 +3251,50 @@ class ExecPinTemplate extends PinTemplate { */ class StringPinTemplate extends PinTemplate { + hasInput() { + return true + } + /** * @param {PinElement} pin */ renderInput(pin) { - const stopEventPropagation = "e => stopPropagation()"; return html` + onfocus="_ => this.closest('ueb-blueprint').editText = true" + onfocusout="_ => this.closest('ueb-blueprint').editText = false" + > ` } } +// @ts-check + +class KeyboardIgnoreSelectAll extends KeyboardSelectAll { + + /** + * @param {HTMLElement} target + * @param {any} blueprint + * @param {Object} options + */ + constructor(target, blueprint, options = {}) { + options = { + ...options, + activationKeys: blueprint.settings.selectAllKeyboardKey + }; + super(target, blueprint, options); + } + + fire() { + } + + unfire() { + + } +} + // @ts-check /** @@ -3298,6 +3344,9 @@ class PinElement extends IElement { moveEverywhere: true, looseTarget: true }), + new KeyboardIgnoreSelectAll(this, this.blueprint, { + consumeEvent: true + }) ] } @@ -3333,8 +3382,8 @@ class PinElement extends IElement { return this.entity.isOutput() } - isConnected() { - return this.entity.isConnected() + isLinked() { + return this.entity.isLinked() } getType() { @@ -3463,7 +3512,7 @@ class NodeTemplate extends SelectableDraggableTemplate { } node.dataset.name = node.getNodeName(); if (node.entity.AdvancedPinDisplay) { - node.dataset.advancedDisplay = node.entity.AdvancedPinDisplay; + node.dataset.advancedDisplay = node.entity.AdvancedPinDisplay.toString(); } node.style.setProperty("--ueb-position-x", sanitizeText(node.location[0])); node.style.setProperty("--ueb-position-y", sanitizeText(node.location[1])); @@ -3561,7 +3610,7 @@ class Paste extends IContext { #pasteHandle constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true; + options.listenOnFocus = true; super(target, blueprint, options); this.serializer = new ObjectSerializer(); let self = this; @@ -3641,22 +3690,22 @@ class Select extends IMouseClickDrag { class Unfocus extends IContext { - /** @type {(e: WheelEvent) => void} */ + /** @type {(e: MouseEvent) => void} */ #clickHandler constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true; + options.listenOnFocus = true; super(target, blueprint, options); let self = this; - this.#clickHandler = e => self.clickedSomewhere(e.target); - if (this.blueprint.focuse) { + this.#clickHandler = e => self.clickedSomewhere(/** @type {HTMLElement} */(e.target)); + if (this.blueprint.focus) { document.addEventListener("click", this.#clickHandler); } } /** - * @param {HTMLElement} e + * @param {HTMLElement} target */ clickedSomewhere(target) { // If target is outside the blueprint grid @@ -3703,13 +3752,13 @@ class Blueprint extends IElement { set translateValue(value) { this.#translateValue = value; } - /** @type {number} */ + /** @type {Number} */ gridSize /** @type {NodeElement[]}" */ nodes = [] /** @type {LinkElement[]}" */ links = [] - /** @type {number[]} */ + /** @type {Number[]} */ mousePosition = [0, 0] /** @type {HTMLElement} */ gridElement = null @@ -3721,7 +3770,7 @@ class Blueprint extends IElement { selectorElement = null /** @type {HTMLElement} */ nodesContainerElement = null - /** @type {number} */ + /** @type {Number} */ zoom = 0 /** @type {HTMLElement} */ headerElement = null @@ -3760,8 +3809,8 @@ class Blueprint extends IElement { } /** - * @param {number} x - * @param {number} y + * @param {Number} x + * @param {Number} y */ #expand(x, y) { // TODO remove @@ -3773,8 +3822,8 @@ class Blueprint extends IElement { } /** - * @param {number} x - * @param {number} y + * @param {Number} x + * @param {Number} y */ #translate(x, y) { x = Math.round(x); @@ -4110,6 +4159,15 @@ class Blueprint extends IElement { } this.dispatchEvent(event); } + + dispatchEditTextEvent(value) { + const event = new CustomEvent( + value + ? this.settings.editTextEventName.begin + : this.settings.editTextEventName.end + ); + this.dispatchEvent(event); + } } customElements.define(Blueprint.tagName, Blueprint); diff --git a/js/Blueprint.js b/js/Blueprint.js index 9e4df54..77246ea 100755 --- a/js/Blueprint.js +++ b/js/Blueprint.js @@ -45,13 +45,13 @@ export default class Blueprint extends IElement { set translateValue(value) { this.#translateValue = value } - /** @type {number} */ + /** @type {Number} */ gridSize /** @type {NodeElement[]}" */ nodes = [] /** @type {LinkElement[]}" */ links = [] - /** @type {number[]} */ + /** @type {Number[]} */ mousePosition = [0, 0] /** @type {HTMLElement} */ gridElement = null @@ -63,7 +63,7 @@ export default class Blueprint extends IElement { selectorElement = null /** @type {HTMLElement} */ nodesContainerElement = null - /** @type {number} */ + /** @type {Number} */ zoom = 0 /** @type {HTMLElement} */ headerElement = null @@ -102,8 +102,8 @@ export default class Blueprint extends IElement { } /** - * @param {number} x - * @param {number} y + * @param {Number} x + * @param {Number} y */ #expand(x, y) { // TODO remove @@ -115,8 +115,8 @@ export default class Blueprint extends IElement { } /** - * @param {number} x - * @param {number} y + * @param {Number} x + * @param {Number} y */ #translate(x, y) { x = Math.round(x) @@ -452,6 +452,15 @@ export default class Blueprint extends IElement { } this.dispatchEvent(event) } + + dispatchEditTextEvent(value) { + const event = new CustomEvent( + value + ? this.settings.editTextEventName.begin + : this.settings.editTextEventName.end + ) + this.dispatchEvent(event) + } } customElements.define(Blueprint.tagName, Blueprint) diff --git a/js/Configuration.js b/js/Configuration.js index 61f5d53..4545384 100755 --- a/js/Configuration.js +++ b/js/Configuration.js @@ -2,6 +2,10 @@ export default class Configuration { deleteNodesKeyboardKey = "Delete" + editTextEventName = { + begin: "ueb-edit-text-begin", + end: "ueb-edit-text-end" + } enableZoomIn = ["LeftControl", "RightControl"] // Button to enable more than 0 (1:1) zoom expandGridSize = 400 fontSize = "12px" diff --git a/js/Utility.js b/js/Utility.js index 6009ff6..e2dbb8d 100755 --- a/js/Utility.js +++ b/js/Utility.js @@ -1,6 +1,5 @@ // @ts-check -import Configuration from "./Configuration" import TypeInitialization from "./entity/TypeInitialization" export default class Utility { diff --git a/js/element/ISelectableDraggableElement.js b/js/element/ISelectableDraggableElement.js index a6945f0..2374266 100644 --- a/js/element/ISelectableDraggableElement.js +++ b/js/element/ISelectableDraggableElement.js @@ -1,6 +1,5 @@ // @ts-check -import Configuration from "../Configuration" import IElement from "./IElement" import MouseMoveNodes from "../input/mouse/MouseMoveNodes" diff --git a/js/element/LinkElement.js b/js/element/LinkElement.js index 0e2c28a..e9d6687 100644 --- a/js/element/LinkElement.js +++ b/js/element/LinkElement.js @@ -1,6 +1,5 @@ // @ts-check -import Configuration from "../Configuration" import IElement from "./IElement" import LinkTemplate from "../template/LinkTemplate" diff --git a/js/element/NodeElement.js b/js/element/NodeElement.js index 116233b..20d5455 100644 --- a/js/element/NodeElement.js +++ b/js/element/NodeElement.js @@ -1,6 +1,5 @@ // @ts-check -import Configuration from "../Configuration" import ISelectableDraggableElement from "./ISelectableDraggableElement" import NodeTemplate from "../template/NodeTemplate" import ObjectEntity from "../entity/ObjectEntity" diff --git a/js/element/PinElement.js b/js/element/PinElement.js index 1269d56..d7e388c 100644 --- a/js/element/PinElement.js +++ b/js/element/PinElement.js @@ -5,6 +5,7 @@ import MouseCreateLink from "../input/mouse/MouseCreateLink" import PinTemplate from "../template/PinTemplate" import ExecPinTemplate from "../template/ExecPinTemplate" import StringPinTemplate from "../template/StringPinTemplate" +import KeyboardIgnoreSelectAll from "../input/keybaord/KeyboardIgnoreSelectAll" /** * @typedef {import("../entity/GuidEntity").default} GuidEntity @@ -53,6 +54,9 @@ export default class PinElement extends IElement { moveEverywhere: true, looseTarget: true }), + new KeyboardIgnoreSelectAll(this, this.blueprint, { + consumeEvent: true + }) ] } @@ -88,8 +92,8 @@ export default class PinElement extends IElement { return this.entity.isOutput() } - isConnected() { - return this.entity.isConnected() + isLinked() { + return this.entity.isLinked() } getType() { diff --git a/js/entity/PinEntity.js b/js/entity/PinEntity.js index 012bf37..d4ff586 100755 --- a/js/entity/PinEntity.js +++ b/js/entity/PinEntity.js @@ -83,7 +83,11 @@ export default class PinEntity extends IEntity { return !this.bHidden && this.Direction === "EGPD_Output" } - isConnected() { + /** + * + * @returns {Boolean} + */ + isLinked() { return this.LinkedTo?.length > 0 ?? false } diff --git a/js/input/IContext.js b/js/input/IContext.js index 174fb06..6ff5a55 100644 --- a/js/input/IContext.js +++ b/js/input/IContext.js @@ -14,38 +14,33 @@ export default class IContext { /** @type {Object} */ options - #hasFocus = false - - get hasFocus() { - return this.#hasFocus - } - - set hasFocus(_) { - } - constructor(target, blueprint, options) { this.target = target this.blueprint = blueprint this.options = options let self = this - this.blueprintFocusHandler = _ => { - this.#hasFocus = true + this.listenHandler = _ => { self.listenEvents() } - this.blueprintUnfocusHandler = _ => { + this.unlistenHandler = _ => { self.unlistenEvents() - this.#hasFocus = false } - if (options?.wantsFocusCallback ?? false) { - this.blueprint.addEventListener("blueprint-focus", this.blueprintFocusHandler) - this.blueprint.addEventListener("blueprint-unfocus", this.blueprintUnfocusHandler) + if (options?.listenOnFocus ?? false) { + this.blueprint.addEventListener("blueprint-focus", this.listenHandler) + this.blueprint.addEventListener("blueprint-unfocus", this.unlistenHandler) + } + if (options?.unlistenOnEditText ?? false) { + this.blueprint.addEventListener(this.blueprint.settings.editTextEventName.begin, this.unlistenHandler) + this.blueprint.addEventListener(this.blueprint.settings.editTextEventName.end, this.listenHandler) } } unlistenDOMElement() { this.unlistenEvents() - this.blueprint.removeEventListener("blueprint-focus", this.blueprintFocusHandler) - this.blueprint.removeEventListener("blueprint-unfocus", this.blueprintUnfocusHandler) + this.blueprint.removeEventListener("blueprint-focus", this.listenHandler) + this.blueprint.removeEventListener("blueprint-unfocus", this.unlistenHandler) + this.blueprint.removeEventListener(this.blueprint.settings.editTextEventName.begin, this.unlistenHandler) + this.blueprint.removeEventListener(this.blueprint.settings.editTextEventName.end, this.listenHandler) } /* Subclasses will probabily override the following methods */ diff --git a/js/input/common/Copy.js b/js/input/common/Copy.js index c98be1d..56f709e 100755 --- a/js/input/common/Copy.js +++ b/js/input/common/Copy.js @@ -8,7 +8,7 @@ export default class Copy extends IContext { #copyHandler constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true + options.listenOnFocus = true super(target, blueprint, options) this.serializer = new ObjectSerializer() let self = this diff --git a/js/input/common/Paste.js b/js/input/common/Paste.js index cd3ad83..a54ce3b 100755 --- a/js/input/common/Paste.js +++ b/js/input/common/Paste.js @@ -9,7 +9,7 @@ export default class Paste extends IContext { #pasteHandle constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true + options.listenOnFocus = true super(target, blueprint, options) this.serializer = new ObjectSerializer() let self = this diff --git a/js/input/keybaord/IKeyboardShortcut.js b/js/input/keybaord/IKeyboardShortcut.js index b972c75..84663a1 100644 --- a/js/input/keybaord/IKeyboardShortcut.js +++ b/js/input/keybaord/IKeyboardShortcut.js @@ -10,7 +10,7 @@ export default class IKeyboardShortcut extends IContext { #activationKeys constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true + options.listenOnFocus = true options.activationKeys ??= [] if (!(options.activationKeys instanceof Array)) { options.activationKeys = [options.activationKeys] @@ -47,6 +47,9 @@ export default class IKeyboardShortcut extends IContext { && wantsAlt(keyEntry) == e.altKey && this.blueprint.settings.Keys[keyEntry.Key] == e.code )) { + if (options.consumeEvent) { + e.stopImmediatePropagation() + } self.fire() document.removeEventListener("keydown", self.keyDownHandler) document.addEventListener("keyup", self.keyUpHandler) @@ -60,9 +63,12 @@ export default class IKeyboardShortcut extends IContext { keyEntry.bShift && e.key == "Shift" || keyEntry.bCtrl && e.key == "Control" || keyEntry.bAlt && e.key == "Alt" - || keyEntry.bCmd && e.key == "Meta" // Unsure about this, what key is that? + || keyEntry.bCmd && e.key == "Meta" || this.blueprint.settings.Keys[keyEntry.Key] == e.code )) { + if (options.consumeEvent) { + e.stopImmediatePropagation() + } self.unfire() document.removeEventListener("keyup", this.keyUpHandler) document.addEventListener("keydown", this.keyDownHandler) diff --git a/js/input/keybaord/KeyboardEnableZoom.js b/js/input/keybaord/KeyboardEnableZoom.js index e3e4320..1aa3667 100644 --- a/js/input/keybaord/KeyboardEnableZoom.js +++ b/js/input/keybaord/KeyboardEnableZoom.js @@ -5,7 +5,7 @@ import Zoom from "../mouse/Zoom" export default class KeyboardEnableZoom extends IKeyboardShortcut { - /** @type {} */ + /** @type {Zoom} */ #zoomInputObject /** diff --git a/js/input/keybaord/KeyboardIgnoreSelectAll.js b/js/input/keybaord/KeyboardIgnoreSelectAll.js new file mode 100755 index 0000000..f873ef2 --- /dev/null +++ b/js/input/keybaord/KeyboardIgnoreSelectAll.js @@ -0,0 +1,26 @@ +// @ts-check + +import KeyboardSelectAll from "./KeyboardSelectAll" + +export default class KeyboardIgnoreSelectAll extends KeyboardSelectAll { + + /** + * @param {HTMLElement} target + * @param {any} blueprint + * @param {Object} options + */ + constructor(target, blueprint, options = {}) { + options = { + ...options, + activationKeys: blueprint.settings.selectAllKeyboardKey + } + super(target, blueprint, options) + } + + fire() { + } + + unfire() { + + } +} diff --git a/js/input/keybaord/KeyboardSelectAll.js b/js/input/keybaord/KeyboardSelectAll.js index ddd692a..e12071e 100755 --- a/js/input/keybaord/KeyboardSelectAll.js +++ b/js/input/keybaord/KeyboardSelectAll.js @@ -2,11 +2,14 @@ import IKeyboardShortcut from "./IKeyboardShortcut" +/** + * @typedef {import("../../Blueprint").default} Blueprint + */ export default class KeyboardSelectAll extends IKeyboardShortcut { /** * @param {HTMLElement} target - * @param {import("../../Blueprint").default} blueprint + * @param {Blueprint} blueprint * @param {Object} options */ constructor(target, blueprint, options = {}) { diff --git a/js/input/mouse/IMouseClickDrag.js b/js/input/mouse/IMouseClickDrag.js index 46a3f17..bace2ce 100644 --- a/js/input/mouse/IMouseClickDrag.js +++ b/js/input/mouse/IMouseClickDrag.js @@ -29,7 +29,7 @@ export default class IMouseClickDrag extends IPointing { this.exitAnyButton = options?.exitAnyButton ?? true this.moveEverywhere = options?.moveEverywhere ?? false this.looseTarget = options?.looseTarget ?? false - this.consumeClickEvent = options?.consumeClickEvent ?? true + this.consumeEvent = options?.consumeEvent ?? true this.clickedPosition = [0, 0] const movementListenedElement = this.moveEverywhere ? document.documentElement : this.movementSpace @@ -41,7 +41,7 @@ export default class IMouseClickDrag extends IPointing { case self.clickButton: // Either doesn't matter or consider the click only when clicking on the parent, not descandants if (self.looseTarget || e.target == e.currentTarget) { - if (this.consumeClickEvent) { + if (this.consumeEvent) { e.stopImmediatePropagation() // Captured, don't call anyone else } // Attach the listeners @@ -60,7 +60,7 @@ export default class IMouseClickDrag extends IPointing { } this.#mouseStartedMovingHandler = e => { - if (this.consumeClickEvent) { + if (this.consumeEvent) { e.stopImmediatePropagation() // Captured, don't call anyone else } // Delegate from now on to self.#mouseMoveHandler @@ -75,7 +75,7 @@ export default class IMouseClickDrag extends IPointing { } this.#mouseMoveHandler = e => { - if (this.consumeClickEvent) { + if (this.consumeEvent) { e.stopImmediatePropagation() // Captured, don't call anyone else } const location = self.locationFromEvent(e) @@ -88,7 +88,7 @@ export default class IMouseClickDrag extends IPointing { this.#mouseUpHandler = e => { if (!self.exitAnyButton || e.button == self.clickButton) { - if (this.consumeClickEvent) { + if (this.consumeEvent) { e.stopImmediatePropagation() // Captured, don't call anyone else } // Remove the handlers of "mousemove" and "mouseup" diff --git a/js/input/mouse/IMouseWheel.js b/js/input/mouse/IMouseWheel.js index f8a2ec5..72456da 100644 --- a/js/input/mouse/IMouseWheel.js +++ b/js/input/mouse/IMouseWheel.js @@ -16,7 +16,7 @@ export default class IMouseWheel extends IPointing { * @param {Object} options */ constructor(target, blueprint, options) { - options.wantsFocusCallback = true + options.listenOnFocus = true super(target, blueprint, options) this.looseTarget = options?.looseTarget ?? true let self = this diff --git a/js/input/mouse/MouseTracking.js b/js/input/mouse/MouseTracking.js index 31fc4a9..2f8da43 100755 --- a/js/input/mouse/MouseTracking.js +++ b/js/input/mouse/MouseTracking.js @@ -17,7 +17,7 @@ export default class MouseTracking extends IPointing { #trackingMouseGaveBackHandler constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true + options.listenOnFocus = true super(target, blueprint, options) let self = this diff --git a/js/input/mouse/Unfocus.js b/js/input/mouse/Unfocus.js index d26a0ed..9e57cae 100755 --- a/js/input/mouse/Unfocus.js +++ b/js/input/mouse/Unfocus.js @@ -4,22 +4,22 @@ import IContext from "../IContext" export default class Unfocus extends IContext { - /** @type {(e: WheelEvent) => void} */ + /** @type {(e: MouseEvent) => void} */ #clickHandler constructor(target, blueprint, options = {}) { - options.wantsFocusCallback = true + options.listenOnFocus = true super(target, blueprint, options) let self = this - this.#clickHandler = e => self.clickedSomewhere(e.target) - if (this.blueprint.focuse) { + this.#clickHandler = e => self.clickedSomewhere(/** @type {HTMLElement} */(e.target)) + if (this.blueprint.focus) { document.addEventListener("click", this.#clickHandler) } } /** - * @param {HTMLElement} e + * @param {HTMLElement} target */ clickedSomewhere(target) { // If target is outside the blueprint grid diff --git a/js/selection/FastSelectionModel.js b/js/selection/FastSelectionModel.js index 40135ee..f6c819b 100755 --- a/js/selection/FastSelectionModel.js +++ b/js/selection/FastSelectionModel.js @@ -4,27 +4,27 @@ import OrderedIndexArray from "./OrderedIndexArray" /** * @typedef {{ - * primaryInf: number, - * primarySup: number, - * secondaryInf: number, - * secondarySup: number + * primaryInf: Number, + * primarySup: Number, + * secondaryInf: Number, + * secondarySup: Number * }} BoundariesInfo * @typedef {{ - * primaryBoundary: number, - * secondaryBoundary: number, - * insertionPosition: number, - * rectangle: number - * onSecondaryAxis: Boolean + * primaryBoundary: Number, + * secondaryBoundary: Number, + * insertionPosition?: Number, + * rectangle: Number + * onSecondaryAxis: Boolean * }} Metadata - * @typedef {numeric} Rectangle + * @typedef {any} Rectangle */ export default class FastSelectionModel { /** - * @param {number[]} initialPosition Coordinates of the starting point of selection [primaryAxisValue, secondaryAxisValue]. + * @param {Number[]} initialPosition Coordinates of the starting point of selection [primaryAxisValue, secondaryAxisValue]. * @param {Rectangle[]} rectangles Rectangles that can be selected by this object. * @param {(rect: Rectangle) => BoundariesInfo} boundariesFunc A function that, given a rectangle, it provides the boundaries of such rectangle. - * @param {(rect: Rectangle, selected: bool) => void} selectFunc A function that selects or deselects individual rectangles. + * @param {(rect: Rectangle, selected: Boolean) => void} selectFunc A function that selects or deselects individual rectangles. */ constructor(initialPosition, rectangles, boundariesFunc, selectFunc) { this.initialPosition = initialPosition @@ -75,7 +75,7 @@ export default class FastSelectionModel { }) this.primaryOrder.currentPosition = this.primaryOrder.getPosition(this.initialPosition[0]) this.secondaryOrder.currentPosition = this.secondaryOrder.getPosition(this.initialPosition[1]) - this.computeBoundaries(this.initialPosition) + this.computeBoundaries() } computeBoundaries() { @@ -128,7 +128,7 @@ export default class FastSelectionModel { this.secondaryOrder.remove(index) } } - this.computeBoundaries(finalPosition) + this.computeBoundaries() this.selectTo(finalPosition) } @@ -146,7 +146,7 @@ export default class FastSelectionModel { const secondaryBoundaryCrossed = (index, added) => { this.selectFunc(this.rectangles[index], added) - this.computeBoundaries(finalPosition) + this.computeBoundaries() this.selectTo(finalPosition) } @@ -163,5 +163,4 @@ export default class FastSelectionModel { } this.finalPosition = finalPosition } - } diff --git a/js/template/BlueprintTemplate.js b/js/template/BlueprintTemplate.js index 0696cb3..00e87b3 100755 --- a/js/template/BlueprintTemplate.js +++ b/js/template/BlueprintTemplate.js @@ -1,6 +1,5 @@ // @ts-check -import Configuration from "../Configuration" import html from "./html" import ITemplate from "./ITemplate" import sanitizeText from "./sanitizeText" diff --git a/js/template/LinkTemplate.js b/js/template/LinkTemplate.js index 5e3a790..c0ba94c 100755 --- a/js/template/LinkTemplate.js +++ b/js/template/LinkTemplate.js @@ -1,6 +1,5 @@ // @ts-check -import Configuration from "../Configuration" import html from "./html" import ITemplate from "./ITemplate" import sanitizeText from "./sanitizeText" diff --git a/js/template/NodeTemplate.js b/js/template/NodeTemplate.js index 516f2bb..f62570a 100755 --- a/js/template/NodeTemplate.js +++ b/js/template/NodeTemplate.js @@ -48,7 +48,7 @@ export default class NodeTemplate extends SelectableDraggableTemplate { } node.dataset.name = node.getNodeName() if (node.entity.AdvancedPinDisplay) { - node.dataset.advancedDisplay = node.entity.AdvancedPinDisplay + node.dataset.advancedDisplay = node.entity.AdvancedPinDisplay.toString() } node.style.setProperty("--ueb-position-x", sanitizeText(node.location[0])) node.style.setProperty("--ueb-position-y", sanitizeText(node.location[1])) diff --git a/js/template/PinTemplate.js b/js/template/PinTemplate.js index f3579f5..dae6d17 100755 --- a/js/template/PinTemplate.js +++ b/js/template/PinTemplate.js @@ -12,6 +12,10 @@ import Utility from "../Utility" */ export default class PinTemplate extends ITemplate { + hasInput() { + return false + } + /** * Computes the html content of the pin. * @param {PinElement} pin html element @@ -72,7 +76,9 @@ export default class PinTemplate extends ITemplate { const targetPin = pin.blueprint.getPin(pinReference) if (targetPin) { const [sourcePin, destinationPin] = pin.isOutput() ? [pin, targetPin] : [targetPin, pin] - pin.blueprint.addGraphElement(new LinkElement(sourcePin, destinationPin)) + pin.blueprint.addGraphElement( + new LinkElement(/** @type {PinElement} */(sourcePin), /** @type {PinElement} */(destinationPin)) + ) } }) } @@ -82,7 +88,7 @@ export default class PinTemplate extends ITemplate { * @param {PinElement} pin */ applyConnected(pin) { - if (pin.isConnected()) { + if (pin.isLinked()) { pin.classList.add("ueb-pin-fill") } else { pin.classList.remove("ueb-pin-fill") diff --git a/js/template/StringPinTemplate.js b/js/template/StringPinTemplate.js index 5dd22fa..baf110d 100644 --- a/js/template/StringPinTemplate.js +++ b/js/template/StringPinTemplate.js @@ -8,6 +8,10 @@ import PinTemplate from "./PinTemplate" */ export default class StringPinTemplate extends PinTemplate { + hasInput() { + return true + } + /** * @param {PinElement} pin */ @@ -16,8 +20,9 @@ export default class StringPinTemplate extends PinTemplate { return html` + onfocus="_ => this.closest('ueb-blueprint').editText = true" + onfocusout="_ => this.closest('ueb-blueprint').editText = false" + > ` }