diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js index f4cc044..f9188b3 100644 --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -1,2225 +1 @@ -/** @typedef {import("./graph/GraphNode").default} GraphNode */ -class BlueprintData { - - constructor() { - /** @type {GraphNode[]}" */ - this.nodes = new Array(); - this.expandGridSize = 400; - /** @type {number[]} */ - this.additional = /*[2 * this.expandGridSize, 2 * this.expandGridSize]*/[0, 0]; - /** @type {number[]} */ - this.translateValue = /*[this.expandGridSize, this.expandGridSize]*/[0, 0]; - /** @type {number[]} */ - this.mousePosition = [0, 0]; - } -} - -/** - * @typedef {import(""../entity/Entity"").default} Entity - */ -class Template { - - /** - * Computes the html content of the target element. - * @param {Entity} entity Entity representing the element - * @returns The computed html - */ - render(entity) { - return "" - } - - /** - * Returns the html elements rendered by this template. - * @param {Entity} entity Entity representing the element - * @returns The rendered elements - */ - getElements(entity) { - let aDiv = document.createElement("div"); - aDiv.innerHTML = this.render(entity); - return aDiv.childNodes - } -} - -class BlueprintTemplate extends Template { - header(element) { - return ` -
- ` - } - - overlay() { - return ` - - ` - } - - /** - * - * @param {import("../Blueprint").Blueprint} element - * @returns - */ - viewport(element) { - return ` - - ` - } - - /** - * Computes the html content of the target element. - * @param {HTMLElement} element Target element - * @returns The computed html - */ - render(element) { - return ` - ${this.header(element)} - ${this.overlay(element)} - ${this.viewport(element)} - ` - } -} - -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.blueprint.removeEventListener("blueprintfocus", this.blueprintfocusHandler); - this.blueprint.removeEventListener("blueprintunfocus", this.blueprintunfocusHandler); - } - - blueprintFocused() { - } - - blueprintUnfocused() { - } -} - -class TypeInitialization { - - static sanitize(value) { - if (!(value instanceof Object)) { - return value // Is already primitive - } - if (value instanceof Boolean || value instanceof Number || value instanceof String) { - return value.valueOf() - } - return value - } - - /** - * - * @param {typeof Object} type - * @param {boolean} showDefault - * @param {*} value - */ - constructor(type, showDefault = true, value = undefined) { - if (value === undefined) { - value = TypeInitialization.sanitize(new type()); - } - this.value = value; - this.showDefault = showDefault; - this.type = type; - } -} - -class Utility { - static clamp(val, min, max) { - return Math.min(Math.max(val, min), max) - } - - static getScale(element) { - return getComputedStyle(element).getPropertyValue("--ueb-scale") - } - - /** - * Sets a value in an object - * @param {String[]} keys The chained keys to access from object in order to set the value - * @param {any} value Value to be set - * @param {Object} target Object holding the data - * @param {Boolean} create Whether to create or not the key in case it doesn't exist - * @returns {Boolean} Returns true on succes, false otherwise - */ - static objectSet(target, keys, value, create = false) { - if (keys.constructor != Array) { - console.error("Expected keys to be an array."); - } - if (keys.length == 1) { - if (create || keys[0] in target) { - target[keys[0]] = value; - return true - } - } else if (keys.length > 0) { - return Utility.objectSet(target[keys[0]], keys.slice(1), value, create) - } - return false - } - - /** - * Gets a value from an object, gives defaultValue in case of failure - * @param {Object} source Object holding the data - * @param {String[]} keys The chained keys to access from object in order to get the value - * @param {any} defaultValue Value to return in case from doesn't have it - * @returns {any} The value in from corresponding to the keys or defaultValue otherwise - */ - static objectGet(source, keys, defaultValue = null) { - if (keys.constructor != Array) { - console.error("Expected keys to be an array."); - } - if (keys.length == 0 || !(keys[0] in source)) { - return defaultValue - } - if (keys.length == 1) { - return source[keys[0]] - } - return Utility.objectGet(source[keys[0]], keys.slice(1), defaultValue) - } - - static equals(a, b) { - a = TypeInitialization.sanitize(a); - b = TypeInitialization.sanitize(b); - return a === b - } - - /** - * - * @param {String} value - */ - static FirstCapital(value) { - return value.charAt(0).toUpperCase() + value.substring(1) - } - - static getType(value) { - let constructor = value?.constructor; - switch (constructor) { - case TypeInitialization: - return value.type - case Function: - return value - default: - return constructor - } - } -} - -class Pointing extends Context { - - constructor(target, blueprint, options) { - super(target, blueprint, options); - this.movementSpace = this.blueprint?.getGridDOMElement() ?? document.documentElement; - } - - /** - * - * @param {MouseEvent} mouseEvent - * @returns - */ - getLocation(mouseEvent) { - const scaleCorrection = 1 / Utility.getScale(this.target); - const targetOffset = this.movementSpace.getBoundingClientRect(); - let location = [ - (mouseEvent.clientX - targetOffset.x) * scaleCorrection, - (mouseEvent.clientY - targetOffset.y) * scaleCorrection - ]; - return location - } -} - -/** - * This class manages the ui gesture of mouse click and drag. Tha actual operations are implemented by the subclasses. - */ -class MouseClickDrag extends Pointing { - - constructor(target, blueprint, options) { - super(target, blueprint, options); - this.clickButton = options?.clickButton ?? 0; - this.exitAnyButton = options?.exitAnyButton ?? true; - this.moveEverywhere = options?.moveEverywhere ?? false; - this.looseTarget = options?.looseTarget ?? false; - this.started = false; - this.clickedPosition = [0, 0]; - - const movementListenedElement = this.moveEverywhere ? document.documentElement : this.movementSpace; - let self = this; - - this.mouseDownHandler = e => { - this.blueprint.setFocused(true); - switch (e.button) { - 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) { - e.stopPropagation(); - self.started = false; - // Attach the listeners - movementListenedElement.addEventListener("mousemove", self.mouseStartedMovingHandler); - document.addEventListener("mouseup", self.mouseUpHandler); - self.clickedPosition = self.getLocation(e); - self.clicked(self.clickedPosition); - } - break - default: - if (!self.exitAnyButton) { - self.mouseUpHandler(e); - } - break - } - }; - - this.mouseStartedMovingHandler = e => { - e.preventDefault(); - e.stopPropagation(); - - // Delegate from now on to self.mouseMoveHandler - movementListenedElement.removeEventListener("mousemove", self.mouseStartedMovingHandler); - movementListenedElement.addEventListener("mousemove", self.mouseMoveHandler); - - // Do actual actions - self.startDrag(); - self.started = true; - }; - - this.mouseMoveHandler = e => { - e.preventDefault(); - e.stopPropagation(); - const location = self.getLocation(e); - const movement = [e.movementX, e.movementY]; - self.dragTo(location, movement); - }; - - this.mouseUpHandler = e => { - if (!self.exitAnyButton || e.button == self.clickButton) { - // Remove the handlers of "mousemove" and "mouseup" - movementListenedElement.removeEventListener("mousemove", self.mouseStartedMovingHandler); - movementListenedElement.removeEventListener("mousemove", self.mouseMoveHandler); - document.removeEventListener("mouseup", self.mouseUpHandler); - self.endDrag(); - } - }; - - this.target.addEventListener("mousedown", this.mouseDownHandler); - if (this.clickButton == 2) { - this.target.addEventListener("contextmenu", this.preventDefault); - } - } - - preventDefault(e) { - e.preventDefault(); - } - - unlistenDOMElement() { - super.unlistenDOMElement(); - this.target.removeEventListener("mousedown", this.mouseDownHandler); - if (this.clickButton == 2) { - this.target.removeEventListener("contextmenu", this.preventDefault); - } blueprintunfocusHandler; - } - - /* Subclasses will override the following methods */ - clicked(location) { - } - - startDrag() { - } - - dragTo(location, movement) { - } - - endDrag() { - } -} - -class DragScroll extends MouseClickDrag { - - dragTo(location, movement) { - this.blueprint.scrollDelta([-movement[0], -movement[1]]); - } -} - -class GraphElement extends HTMLElement { - - /** - * - * @param {import("../template/Template").default} template The template to render this node - */ - constructor(entity, template) { - super(); - /** @type {import("../Blueprint").default}" */ - this.blueprint = null; - this.entity = entity; - this.template = template; - } - - connectedCallback() { - this.blueprint = this.closest("u-blueprint"); - this.append(...this.template.getElements(this.entity)); - } -} - -class OrderedIndexArray { - - /** - * @param {(arrayElement: number) => number} compareFunction A function that, given acouple of elements of the array telles what order are they on. - * @param {(number|array)} value Initial length or array to copy from - */ - constructor(comparisonValueSupplier = (a) => a, value = null) { - this.array = new Uint32Array(value); - this.comparisonValueSupplier = comparisonValueSupplier; - this.length = 0; - this.currentPosition = 0; - } - - /** - * - * @param {number} index The index of the value to return - * @returns The element of the array - */ - get(index) { - if (index >= 0 && index < this.length) { - return this.array[index] - } - return null - } - - /** - * Returns the array used by this object. - * @returns The array. - */ - getArray() { - return this.array - } - - /** - * Get the position that the value supplied should (or does) occupy in the aray. - * @param {number} value The value to look for (it doesn't have to be part of the array). - * @returns The position index. - */ - getPosition(value) { - let l = 0; - let r = this.length; - while (l < r) { - let m = Math.floor((l + r) / 2); - if (this.comparisonValueSupplier(this.array[m]) < value) { - l = m + 1; - } else { - r = m; - } - } - return l - } - - reserve(length) { - if (this.array.length < length) { - let newArray = new Uint32Array(length); - newArray.set(this.array); - this.array = newArray; - } - } - - /** - * Inserts the element in the array. - * @param element {number} The value to insert into the array. - * @returns {number} The position into occupied by value into the array. - */ - insert(element, comparisonValue = null) { - let position = this.getPosition(this.comparisonValueSupplier(element)); - if ( - position < this.currentPosition - || comparisonValue != null && position == this.currentPosition && this.comparisonValueSupplier(element) < comparisonValue) { - ++this.currentPosition; - } - /* - let newArray = new Uint32Array(this.array.length + 1) - newArray.set(this.array.subarray(0, position), 0) - newArray[position] = element - newArray.set(this.array.subarray(position), position + 1) - this.array = newArray - */ - this.shiftRight(position); - this.array[position] = element; - ++this.length; - return position - } - - /** - * Removes the element from the array. - * @param {number} value The value of the element to be remove. - */ - remove(element) { - let position = this.getPosition(this.comparisonValueSupplier(element)); - if (this.array[position] == element) { - this.removeAt(position); - } - } - - /** - * Removes the element into the specified position from the array. - * @param {number} position The index of the element to be remove. - */ - removeAt(position) { - if (position < this.currentPosition) { - --this.currentPosition; - } - /* - let newArray = new Uint32Array(this.array.length - 1) - newArray.set(this.array.subarray(0, position), 0) - newArray.set(this.array.subarray(position + 1), position) - this.array = newArray - */ - this.shiftLeft(position); - --this.length; - return position - } - - getNext() { - if (this.currentPosition >= 0 && this.currentPosition < this.length) { - return this.get(this.currentPosition) - } - return null - } - - getNextValue() { - if (this.currentPosition >= 0 && this.currentPosition < this.length) { - return this.comparisonValueSupplier(this.get(this.currentPosition)) - } else { - return Number.MAX_SAFE_INTEGER - } - } - - getPrev() { - if (this.currentPosition > 0) { - return this.get(this.currentPosition - 1) - } - return null - } - - getPrevValue() { - if (this.currentPosition > 0) { - return this.comparisonValueSupplier(this.get(this.currentPosition - 1)) - } else { - return Number.MIN_SAFE_INTEGER - } - } - - shiftLeft(leftLimit, steps = 1) { - this.array.set(this.array.subarray(leftLimit + steps), leftLimit); - } - - shiftRight(leftLimit, steps = 1) { - this.array.set(this.array.subarray(leftLimit, -steps), leftLimit + steps); - } -} - -class FastSelectionModel { - - /** - * @typedef {{ - * primaryInf: number, - * primarySup: number, - * secondaryInf: number, - * secondarySup: number - * }} BoundariesInfo - * @typedef {{ - * primaryBoundary: number, - * secondaryBoundary: number, - * insertionPosition: number, - * rectangle: number - * onSecondaryAxis: Boolean - * }} Metadata - * @typedef {numeric} Rectangle - * @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. - */ - constructor(initialPosition, rectangles, boundariesFunc, selectFunc) { - this.initialPosition = initialPosition; - this.finalPosition = initialPosition; - /** @type Metadata[] */ - this.metadata = new Array(rectangles.length); - this.primaryOrder = new OrderedIndexArray((element) => this.metadata[element].primaryBoundary); - this.secondaryOrder = new OrderedIndexArray((element) => this.metadata[element].secondaryBoundary); - this.selectFunc = selectFunc; - this.rectangles = rectangles; - this.primaryOrder.reserve(this.rectangles.length); - this.secondaryOrder.reserve(this.rectangles.length); - rectangles.forEach((rect, index) => { - /** @type Metadata */ - let rectangleMetadata = { - primaryBoundary: this.initialPosition[0], - secondaryBoundary: this.initialPosition[1], - rectangle: index, // used to move both expandings inside the this.metadata array - onSecondaryAxis: false - }; - this.metadata[index] = rectangleMetadata; - selectFunc(rect, false); // Initially deselected (Eventually) - const rectangleBoundaries = boundariesFunc(rect); - - // Secondary axis first because it may be inserted in this.secondaryOrder during the primary axis check - if (this.initialPosition[1] < rectangleBoundaries.secondaryInf) { // Initial position is before the rectangle - rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondaryInf; - } else if (rectangleBoundaries.secondarySup < this.initialPosition[1]) { // Initial position is after the rectangle - rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondarySup; - } else { - rectangleMetadata.onSecondaryAxis = true; - } - - if (this.initialPosition[0] < rectangleBoundaries.primaryInf) { // Initial position is before the rectangle - rectangleMetadata.primaryBoundary = rectangleBoundaries.primaryInf; - this.primaryOrder.insert(index); - } else if (rectangleBoundaries.primarySup < this.initialPosition[0]) { // Initial position is after the rectangle - rectangleMetadata.primaryBoundary = rectangleBoundaries.primarySup; - this.primaryOrder.insert(index); - } else { // Initial lays inside the rectangle (considering just this axis) - // Secondary order depends on primary order, if primary boundaries are not satisfied, the element is not watched for secondary ones - if (rectangleBoundaries.secondarySup < this.initialPosition[1] || this.initialPosition[1] < rectangleBoundaries.secondaryInf) { - this.secondaryOrder.insert(index); - } else { - selectFunc(rect, true); - } - } - }); - this.primaryOrder.currentPosition = this.primaryOrder.getPosition(this.initialPosition[0]); - this.secondaryOrder.currentPosition = this.secondaryOrder.getPosition(this.initialPosition[1]); - this.computeBoundaries(this.initialPosition); - } - - computeBoundaries() { - this.boundaries = { - // Primary axis negative expanding - primaryN: { - v: this.primaryOrder.getPrevValue(), - i: this.primaryOrder.getPrev() - }, - primaryP: { - v: this.primaryOrder.getNextValue(), - i: this.primaryOrder.getNext() - }, - // Secondary axis negative expanding - secondaryN: { - v: this.secondaryOrder.getPrevValue(), - i: this.secondaryOrder.getPrev() - }, - // Secondary axis positive expanding - secondaryP: { - v: this.secondaryOrder.getNextValue(), - i: this.secondaryOrder.getNext() - } - }; - } - - selectTo(finalPosition) { - const direction = [ - Math.sign(finalPosition[0] - this.initialPosition[0]), - Math.sign(finalPosition[1] - this.initialPosition[1]) - ]; - const primaryBoundaryCrossed = (index, added) => { - if (this.metadata[index].onSecondaryAxis) { - this.selectFunc(this.rectangles[index], added); - } else { - if (added) { - this.secondaryOrder.insert(index, finalPosition[1]); - const secondaryBoundary = this.metadata[index].secondaryBoundary; - if ( - // If inserted before the current position - Math.sign(finalPosition[1] - secondaryBoundary) == direction[1] - // And after initial position - && Math.sign(secondaryBoundary - this.initialPosition[1]) == direction[1] - ) { - // Secondary axis is already satisfied then - this.selectFunc(this.rectangles[index], true); - } - } else { - this.selectFunc(this.rectangles[index], false); - this.secondaryOrder.remove(index); - } - } - this.computeBoundaries(finalPosition); - this.selectTo(finalPosition); - }; - - if (finalPosition[0] < this.boundaries.primaryN.v) { - --this.primaryOrder.currentPosition; - primaryBoundaryCrossed( - this.boundaries.primaryN.i, - this.initialPosition[0] > this.boundaries.primaryN.v && finalPosition[0] < this.initialPosition[0]); - } else if (finalPosition[0] > this.boundaries.primaryP.v) { - ++this.primaryOrder.currentPosition; - primaryBoundaryCrossed( - this.boundaries.primaryP.i, - this.initialPosition[0] < this.boundaries.primaryP.v && this.initialPosition[0] < finalPosition[0]); - } - - - const secondaryBoundaryCrossed = (index, added) => { - this.selectFunc(this.rectangles[index], added); - this.computeBoundaries(finalPosition); - this.selectTo(finalPosition); - }; - - if (finalPosition[1] < this.boundaries.secondaryN.v) { - --this.secondaryOrder.currentPosition; - secondaryBoundaryCrossed( - this.boundaries.secondaryN.i, - this.initialPosition[1] > this.boundaries.secondaryN.v && finalPosition[1] < this.initialPosition[1]); - } else if (finalPosition[1] > this.boundaries.secondaryP.v) { - ++this.secondaryOrder.currentPosition; - secondaryBoundaryCrossed( - this.boundaries.secondaryP.i, - this.initialPosition[1] < this.boundaries.secondaryP.v && this.initialPosition[1] < finalPosition[1]); - } - this.finalPosition = finalPosition; - } - -} - -class GraphSelector extends GraphElement { - - constructor() { - super({}, new Template()); - /** - * @type {import("./GraphSelector").default} - */ - this.selectionModel = null; - } - - connectedCallback() { - super.connectedCallback(); - this.classList.add("ueb-selector"); - this.dataset.selecting = "false"; - } - - /** - * Create a selection rectangle starting from the specified position - * @param {number[]} initialPosition - Selection rectangle initial position (relative to the .ueb-grid element) - */ - startSelecting(initialPosition) { - initialPosition = this.blueprint.compensateTranslation(initialPosition); - // Set initial position - this.style.setProperty("--ueb-select-from-x", initialPosition[0]); - this.style.setProperty("--ueb-select-from-y", initialPosition[1]); - // Final position coincide with the initial position, at the beginning of selection - this.style.setProperty("--ueb-select-to-x", initialPosition[0]); - this.style.setProperty("--ueb-select-to-y", initialPosition[1]); - this.dataset.selecting = "true"; - this.selectionModel = new FastSelectionModel(initialPosition, this.blueprint.getNodes(), this.blueprint.nodeBoundariesSupplier, this.blueprint.nodeSelectToggleFunction); - } - - /** - * Move selection rectagle to the specified final position. The initial position was specified by startSelecting() - * @param {number[]} finalPosition - Selection rectangle final position (relative to the .ueb-grid element) - */ - doSelecting(finalPosition) { - finalPosition = this.blueprint.compensateTranslation(finalPosition); - this.style.setProperty("--ueb-select-to-x", finalPosition[0]); - this.style.setProperty("--ueb-select-to-y", finalPosition[1]); - this.selectionModel.selectTo(finalPosition); - } - - finishSelecting() { - this.dataset.selecting = "false"; - this.selectionModel = null; - } -} - -customElements.define("u-selector", GraphSelector); - -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 Entity { - - constructor(options = {}) { - /** - * - * @param {String[]} prefix - * @param {Object} target - * @param {Object} properties - */ - const defineAllAttributes = (prefix, target, properties) => { - let fullKey = prefix.concat(""); - const last = fullKey.length - 1; - for (let property in properties) { - fullKey[last] = property; - // Not instanceof because all objects are instenceof Object, exact match needed - if (properties[property]?.constructor === Object) { - target[property] = {}; - defineAllAttributes(fullKey, target[property], properties[property]); - continue - } - /* - * The value can either be: - * - Array: can contain multiple values, its property is assigned multiple times like (X=1, X=4, X="Hello World") - * - TypeInitialization: contains the maximum amount of information about the attribute. - * - A type: the default value will be default constructed object without arguments. - * - A proper value. - */ - const value = Utility.objectGet(options, fullKey); - if (value !== null) { - target[property] = value; - continue - } - let defaultValue = properties[property]; - if (defaultValue instanceof TypeInitialization) { - if (!defaultValue.showDefault) { - continue - } - defaultValue = defaultValue.value; - } - if (defaultValue instanceof Array) { - target[property] = []; - continue - } - if (defaultValue instanceof Function) { - defaultValue = TypeInitialization.sanitize(new defaultValue()); - } - target[property] = defaultValue; - } - }; - defineAllAttributes([], this, this.getAttributes()); - } -} - -class GuidEntity extends Entity { - - static attributes = { - value: String - } - - static generateGuid(random = true) { - let values = new Uint32Array(4); - if (random === true) { - crypto.getRandomValues(values); - } - let guid = ""; - values.forEach(n => { - guid += ("0".repeat(8) + n.toString(16).toUpperCase()).slice(-8); - }); - return new GuidEntity({ valud: guid }) - } - - getAttributes() { - return GuidEntity.attributes - } - - toString() { - return this.value - } -} - -class LocalizedTextEntity extends Entity { - - static attributes = { - namespace: String, - key: String, - value: String - } - - getAttributes() { - return LocalizedTextEntity.attributes - } -} - -class ObjectReferenceEntity extends Entity { - - static attributes = { - type: String, - path: String - } - - getAttributes() { - return ObjectReferenceEntity.attributes - } -} - -class PathSymbolEntity extends Entity { - - static attributes = { - value: String - } - - getAttributes() { - return PathSymbolEntity.attributes - } - - toString() { - return this.value - } -} - -class PinReferenceEntity extends Entity { - - static attributes = { - objectName: PathSymbolEntity, - pinGuid: GuidEntity - } - - getAttributes() { - return PinReferenceEntity.attributes - } -} - -class PinEntity extends Entity { - - static attributes = { - PinId: GuidEntity, - PinName: "", - PinFriendlyName: new TypeInitialization(LocalizedTextEntity, false, null), - PinToolTip: "", - Direction: new TypeInitialization(String, false, ""), - PinType: { - PinCategory: "", - PinSubCategory: "", - PinSubCategoryObject: ObjectReferenceEntity, - PinSubCategoryMemberReference: null, - PinValueType: null, - ContainerType: ObjectReferenceEntity, - bIsReference: false, - bIsConst: false, - bIsWeakPointer: false, - bIsUObjectWrapper: false - }, - LinkedTo: [PinReferenceEntity], - DefaultValue: "", - AutogeneratedDefaultValue: "", - PersistentGuid: GuidEntity, - bHidden: false, - bNotConnectable: false, - bDefaultValueIsReadOnly: false, - bDefaultValueIsIgnored: false, - bAdvancedView: false, - bOrphanedPin: false, - } - - getAttributes() { - return PinEntity.attributes - } - - /** - * - * @returns {String} - */ - getPinDisplayName() { - return this.PinName - } - - isOutput() { - if (this.Direction === "EGPD_Output") { - return true - } - } -} - -/** - * @typedef {import("../entity/ObjectEntity").default} ObjectEntity - */ -class NodeTemplate extends Template { - - /** - * Computes the html content of the target element. - * @param {ObjectEntity} entity Entity representing the element - * @returns The computed html - */ - header(entity) { - return ` -