diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js index 56b9ed3..d728a44 100755 --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -518,6 +518,13 @@ class IElement extends HTMLElement { createInputObjects() { return [] } + + /** + * @param {IElement} element + */ + isSameGraph(element) { + return this.blueprint && this.blueprint == element?.blueprint + } } /** @@ -812,6 +819,26 @@ class Utility { return location } + /** + * Gets a value from an object, gives defaultValue in case of failure + * @param {Object} target 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(target, keys, defaultValue = undefined) { + if (!(keys instanceof Array)) { + console.error("Expected keys to be an array."); + } + if (keys.length == 0 || !(keys[0] in target) || target[keys[0]] === undefined) { + return defaultValue + } + if (keys.length == 1) { + return target[keys[0]] + } + return Utility.objectGet(target[keys[0]], keys.slice(1), defaultValue) + } + /** * Sets a value in an object * @param {Object} target Object holding the data @@ -820,7 +847,7 @@ class Utility { * @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) { + static objectSet(target, keys, value, create = false, defaultDictType = Object) { if (!(keys instanceof Array)) { console.error("Expected keys to be an array."); } @@ -831,33 +858,13 @@ class Utility { } } else if (keys.length > 0) { if (create && !(target[keys[0]] instanceof Object)) { - target[keys[0]] = {}; + target[keys[0]] = new defaultDictType(); } - return Utility.objectSet(target[keys[0]], keys.slice(1), value, create) + return Utility.objectSet(target[keys[0]], keys.slice(1), value, create, defaultDictType) } 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 instanceof Array)) { - console.error("Expected keys to be an array."); - } - if (keys.length == 0 || !(keys[0] in source) || source[keys[0]] === undefined) { - 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); @@ -865,7 +872,6 @@ class Utility { } /** - * * @param {String} value */ static FirstCapital(value) { @@ -910,7 +916,7 @@ class IEntity { const defineAllAttributes = (prefix, target, properties) => { let fullKey = prefix.concat(""); const last = fullKey.length - 1; - for (let property in properties) { + for (let property of Object.getOwnPropertyNames(properties)) { fullKey[last] = property; // Not instanceof because all objects are instenceof Object, exact match needed if (properties[property]?.constructor === Object) { @@ -920,7 +926,7 @@ class IEntity { } /* * The value can either be: - * - Array: can contain multiple values, its property is assigned multiple times like (X=1, X=4, X="Hello World") + * - 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. @@ -933,6 +939,7 @@ class IEntity { let defaultValue = properties[property]; if (defaultValue instanceof TypeInitialization) { if (!defaultValue.showDefault) { + target[property] = undefined; // to preserve the order continue } defaultValue = defaultValue.value; @@ -955,7 +962,7 @@ class ObjectReferenceEntity extends IEntity { static attributes = { type: String, - path: String + path: String, } } @@ -963,17 +970,14 @@ class FunctionReferenceEntity extends IEntity { static attributes = { MemberParent: ObjectReferenceEntity, - MemberName: "" + MemberName: "", } - - /** @type {ObjectReferenceEntity} */ MemberParent - /** @type {String} */ MemberName } class GuidEntity extends IEntity { static attributes = { - value: String + value: String, } static generateGuid(random = true) { @@ -988,6 +992,10 @@ class GuidEntity extends IEntity { return new GuidEntity({ value: guid }) } + valueOf() { + return this.value + } + toString() { return this.value } @@ -996,13 +1004,13 @@ class GuidEntity extends IEntity { class IntegerEntity extends IEntity { static attributes = { - value: Number + value: Number, } constructor(options = {}) { - if (options.constructor === Number || options.constructor === String) { + if (options.constructor == Number || options.constructor == String) { options = { - value: options + value: options, }; } super(options); @@ -1024,14 +1032,14 @@ class LocalizedTextEntity extends IEntity { static attributes = { namespace: String, key: String, - value: String + value: String, } } class PathSymbolEntity extends IEntity { static attributes = { - value: String + value: String, } toString() { @@ -1043,7 +1051,7 @@ class PinReferenceEntity extends IEntity { static attributes = { objectName: PathSymbolEntity, - pinGuid: GuidEntity + pinGuid: GuidEntity, } } @@ -1113,13 +1121,13 @@ class PinEntity extends IEntity { linkTo(targetObjectName, targetPinEntity) { /** @type {PinReferenceEntity[]} */ this.LinkedTo; - const linkExists = this.LinkedTo.find( + const linkFound = this.LinkedTo.find( /** @type {PinReferenceEntity} */ pinReferenceEntity => { return pinReferenceEntity.objectName == targetObjectName - && pinReferenceEntity.pinGuid == targetPinEntity.PinId + && pinReferenceEntity.pinGuid.valueOf() == targetPinEntity.PinId.valueOf() }); - if (!linkExists) { + if (!linkFound) { this.LinkedTo.push(new PinReferenceEntity({ objectName: targetObjectName, pinGuid: targetPinEntity.PinId @@ -1159,7 +1167,7 @@ class VariableReferenceEntity extends IEntity { static attributes = { MemberName: String, MemberGuid: GuidEntity, - bSelfContext: false + bSelfContext: false, } } @@ -1178,11 +1186,11 @@ class ObjectEntity extends IEntity { NodeGuid: GuidEntity, ErrorType: new TypeInitialization(IntegerEntity, false), ErrorMsg: new TypeInitialization(String, false, ""), - CustomProperties: [PinEntity] + CustomProperties: [PinEntity], } /** - * @returns {String} The name of the node + * @returns {String} */ getName() { return this.Name @@ -1427,14 +1435,14 @@ class ISerializer { let result = ""; let fullKey = key.concat(""); const last = fullKey.length - 1; - for (const property in object) { + for (const property of Object.getOwnPropertyNames(object)) { fullKey[last] = property; const value = object[property]; if (object[property]?.constructor === Object) { // Recursive call when finding an object result += (result.length ? this.separator : "") + this.subWrite(fullKey, value); - } else if (this.showProperty(fullKey, value)) { + } else if (value !== undefined && this.showProperty(fullKey, value)) { result += (result.length ? this.separator : "") + this.prefix + this.attributeKeyPrinter(fullKey) @@ -1507,7 +1515,7 @@ ${this.subWrite([], object) + object .CustomProperties.map(pin => this.separator + this.prefix + "CustomProperties " + SerializerFactory.getSerializer(PinEntity).write(pin)) .join("")} -End Object`; +End Object\n`; return result } } @@ -1804,7 +1812,7 @@ class LinkTemplate extends ITemplate { c2 = Math.min(c2, LinkTemplate.c2DecreasingValue(width)); const d = Configuration.linkRightSVGPath(start, c1, c2); // TODO move to CSS when Firefox will support property d and css will have enough functions - link.pathElement.setAttribute("d", d); + link.pathElement?.setAttribute("d", d); } /** @@ -2088,6 +2096,7 @@ class IMouseClickDrag extends IPointing { } // Attach the listeners movementListenedElement.addEventListener("mousemove", self.#mouseStartedMovingHandler); + document.addEventListener("mouseup", self.#mouseUpHandler); self.clickedPosition = self.locationFromEvent(e); self.clicked(self.clickedPosition); } @@ -2108,7 +2117,6 @@ class IMouseClickDrag extends IPointing { // Delegate from now on to self.#mouseMoveHandler movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler); movementListenedElement.addEventListener("mousemove", self.#mouseMoveHandler); - document.addEventListener("mouseup", self.#mouseUpHandler); // Handler calls e.preventDefault() when it receives the event, this means dispatchEvent returns false const dragEvent = self.getEvent(Configuration.trackingMouseEventName.begin); self.#trackingMouse = this.target.dispatchEvent(dragEvent) == false; @@ -2140,7 +2148,9 @@ class IMouseClickDrag extends IPointing { movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler); movementListenedElement.removeEventListener("mousemove", self.#mouseMoveHandler); document.removeEventListener("mouseup", self.#mouseUpHandler); - self.endDrag(); + if (self.started) { + self.endDrag(); + } if (self.#trackingMouse) { const dragEvent = self.getEvent(Configuration.trackingMouseEventName.end); this.target.dispatchEvent(dragEvent); @@ -2265,6 +2275,38 @@ class MouseTracking extends IPointing { } } +/** + * @template Key + * @template Value + */ +class MultiKeyWeakMap { + + map = new WeakMap() + + constructor() { + return new Proxy(this.map, this) + } + + /** + * @param {WeakMap} target + * @param {Key} p + * @param {*} receiver + * @returns {Value} + */ + get(target, p, receiver) { + return Utility.objectGet(target, p) + } + + /** + * @param {WeakMap} target + * @param {Key} p + * @param {Value} value + */ + set(target, p, value) { + return Utility.objectSet(target, p, value, true, WeakMap) + } +} + /** * @typedef {import("../../element/ISelectableDraggableElement").default} ISelectableDraggableElement */ @@ -2628,15 +2670,14 @@ class PinTemplate extends ITemplate { "ueb-pin-" + sanitizeText(pin.getType()) ); pin.clickableElement = pin; - window.customElements.whenDefined(NodeElement.tagName).then(pin.nodeElement = pin.closest(NodeElement.tagName)); + window.customElements.whenDefined("ueb-node").then(pin.nodeElement = pin.closest("ueb-node")); pin.getLinks().forEach(pinReference => { - const targetPin = pin.blueprint.getPin(pinReference.pinGuid); + const targetPin = pin.blueprint.getPin(pinReference); if (targetPin) { const [sourcePin, destinationPin] = pin.isOutput() ? [pin, targetPin] : [targetPin, pin]; pin.blueprint.addGraphElement(new LinkElement(sourcePin, destinationPin)); } }); - } /** @@ -2706,6 +2747,11 @@ class PinElement extends IElement { return this.entity.PinId } + /** @type {GuidEntity} */ + GetPinIdValue() { + return this.GetPinId().value + } + /** * @returns {String} */ @@ -2752,14 +2798,17 @@ class PinElement extends IElement { return this.template.getLinkLocation(this) } + /** + * @returns {NodeElement} + */ getNodeElement() { return this.closest("ueb-node") } getLinks() { - return this.entity.LinkedTo.map(pinReference => + return this.entity.LinkedTo?.map(pinReference => pinReference - ) + ) ?? [] } /** @@ -3103,8 +3152,21 @@ class Zoom extends IMouseWheel { class Blueprint extends IElement { static tagName = "ueb-blueprint" - /** @type {WeakMap} */ - #pinGuidMap = new WeakMap() + /** @type {MultiKeyWeakMap} */ + #pinGuidMap = new Proxy(new MultiKeyWeakMap(), { + get(target, p, receiver) { + if (p instanceof PinReferenceEntity) { + p = [p.objectName, p.pinGuid]; + } + return Reflect.get(target, p) + }, + set(target, p, value) { + if (p instanceof PinReferenceEntity) { + p = [p.objectName, p.pinGuid]; + } + return Reflect.set(target, p, value) + } + }) /** @type {number} */ gridSize = Configuration.gridSize /** @type {NodeElement[]}" */ @@ -3386,10 +3448,10 @@ class Blueprint extends IElement { } /** - * @param {GuidEntity} guid + * @param {PinReferenceEntity} pinReference */ - getPin(guid) { - return this.#pinGuidMap[guid] + getPin(pinReference) { + return this.#pinGuidMap[pinReference] } /** @@ -3431,7 +3493,12 @@ class Blueprint extends IElement { if (element instanceof NodeElement) { this.nodes.push(element); element.getPinElements().forEach( - pinElement => this.#pinGuidMap[pinElement.GetPinId()] = pinElement + pinElement => this.#pinGuidMap[ + new PinReferenceEntity({ + objectName: pinElement.getNodeElement().getNodeName(), + pinGuid: pinElement.GetPinId(), + }) + ] = pinElement ); } else if (element instanceof LinkElement) { this.links.push(element); @@ -3556,7 +3623,7 @@ function initializeSerializerFactory() { ); SerializerFactory.registerSerializer( LocalizedTextEntity, - new GeneralSerializer(v => `${LocalizedTextEntity.lookbehind}(${v})`, LocalizedTextEntity, "", ",", false, "", _ => "") + new GeneralSerializer(v => `${LocalizedTextEntity.lookbehind}(${v})`, LocalizedTextEntity, "", ", ", false, "", _ => "") ); SerializerFactory.registerSerializer( PinReferenceEntity, diff --git a/js/Blueprint.js b/js/Blueprint.js index 3bb1848..b345db3 100755 --- a/js/Blueprint.js +++ b/js/Blueprint.js @@ -7,6 +7,7 @@ import KeyboardSelectAll from "./input/keybaord/KeyboardSelectAll" import LinkElement from "./element/LinkElement" import MouseScrollGraph from "./input/mouse/MouseScrollGraph" import MouseTracking from "./input/mouse/MouseTracking" +import MultiKeyWeakMap from "./MultiKeyMap" import NodeElement from "./element/NodeElement" import Paste from "./input/common/Paste" import Select from "./input/mouse/Select" @@ -14,6 +15,7 @@ import SelectorElement from "./element/SelectorElement" import Unfocus from "./input/mouse/Unfocus" import Utility from "./Utility" import Zoom from "./input/mouse/Zoom" +import PinReferenceEntity from "./entity/PinReferenceEntity" /** * @typedef {import("./entity/GuidEntity").default} GuidEntity @@ -22,8 +24,21 @@ import Zoom from "./input/mouse/Zoom" export default class Blueprint extends IElement { static tagName = "ueb-blueprint" - /** @type {WeakMap} */ - #pinGuidMap = new WeakMap() + /** @type {MultiKeyWeakMap} */ + #pinGuidMap = new Proxy(new MultiKeyWeakMap(), { + get(target, p, receiver) { + if (p instanceof PinReferenceEntity) { + p = [p.objectName, p.pinGuid] + } + return Reflect.get(target, p) + }, + set(target, p, value) { + if (p instanceof PinReferenceEntity) { + p = [p.objectName, p.pinGuid] + } + return Reflect.set(target, p, value) + } + }) /** @type {number} */ gridSize = Configuration.gridSize /** @type {NodeElement[]}" */ @@ -305,10 +320,10 @@ export default class Blueprint extends IElement { } /** - * @param {GuidEntity} guid + * @param {PinReferenceEntity} pinReference */ - getPin(guid) { - return this.#pinGuidMap[guid] + getPin(pinReference) { + return this.#pinGuidMap[pinReference] } /** @@ -350,7 +365,12 @@ export default class Blueprint extends IElement { if (element instanceof NodeElement) { this.nodes.push(element) element.getPinElements().forEach( - pinElement => this.#pinGuidMap[pinElement.GetPinId()] = pinElement + pinElement => this.#pinGuidMap[ + new PinReferenceEntity({ + objectName: pinElement.getNodeElement().getNodeName(), + pinGuid: pinElement.GetPinId(), + }) + ] = pinElement ) } else if (element instanceof LinkElement) { this.links.push(element) diff --git a/js/MultiKeyMap.js b/js/MultiKeyMap.js new file mode 100644 index 0000000..7b72e72 --- /dev/null +++ b/js/MultiKeyMap.js @@ -0,0 +1,33 @@ +import Utility from "./Utility" + +/** + * @template Key + * @template Value + */ +export default class MultiKeyWeakMap { + + map = new WeakMap() + + constructor() { + return new Proxy(this.map, this) + } + + /** + * @param {WeakMap} target + * @param {Key} p + * @param {*} receiver + * @returns {Value} + */ + get(target, p, receiver) { + return Utility.objectGet(target, p) + } + + /** + * @param {WeakMap} target + * @param {Key} p + * @param {Value} value + */ + set(target, p, value) { + return Utility.objectSet(target, p, value, true, WeakMap) + } +} \ No newline at end of file diff --git a/js/Utility.js b/js/Utility.js index fbbe774..128fdca 100755 --- a/js/Utility.js +++ b/js/Utility.js @@ -30,6 +30,26 @@ export default class Utility { return location } + /** + * Gets a value from an object, gives defaultValue in case of failure + * @param {Object} target 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(target, keys, defaultValue = undefined) { + if (!(keys instanceof Array)) { + console.error("Expected keys to be an array.") + } + if (keys.length == 0 || !(keys[0] in target) || target[keys[0]] === undefined) { + return defaultValue + } + if (keys.length == 1) { + return target[keys[0]] + } + return Utility.objectGet(target[keys[0]], keys.slice(1), defaultValue) + } + /** * Sets a value in an object * @param {Object} target Object holding the data @@ -38,7 +58,7 @@ export default class Utility { * @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) { + static objectSet(target, keys, value, create = false, defaultDictType = Object) { if (!(keys instanceof Array)) { console.error("Expected keys to be an array.") } @@ -49,33 +69,13 @@ export default class Utility { } } else if (keys.length > 0) { if (create && !(target[keys[0]] instanceof Object)) { - target[keys[0]] = {} + target[keys[0]] = new defaultDictType() } - return Utility.objectSet(target[keys[0]], keys.slice(1), value, create) + return Utility.objectSet(target[keys[0]], keys.slice(1), value, create, defaultDictType) } 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 instanceof Array)) { - console.error("Expected keys to be an array.") - } - if (keys.length == 0 || !(keys[0] in source) || source[keys[0]] === undefined) { - 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) @@ -83,7 +83,6 @@ export default class Utility { } /** - * * @param {String} value */ static FirstCapital(value) { diff --git a/js/element/IElement.js b/js/element/IElement.js index 80facd7..9e9fd68 100644 --- a/js/element/IElement.js +++ b/js/element/IElement.js @@ -42,4 +42,11 @@ export default class IElement extends HTMLElement { createInputObjects() { return [] } + + /** + * @param {IElement} element + */ + isSameGraph(element) { + return this.blueprint && this.blueprint == element?.blueprint + } } diff --git a/js/element/NodeElement.js b/js/element/NodeElement.js index e067ed1..37f7d72 100644 --- a/js/element/NodeElement.js +++ b/js/element/NodeElement.js @@ -2,8 +2,8 @@ import Configuration from "../Configuration" import ISelectableDraggableElement from "./ISelectableDraggableElement" import NodeTemplate from "../template/NodeTemplate" import ObjectEntity from "../entity/ObjectEntity" -import PinEntity from "../entity/PinEntity" import SerializerFactory from "../serialization/SerializerFactory" +import PinEntity from "../entity/PinEntity" export default class NodeElement extends ISelectableDraggableElement { diff --git a/js/element/PinElement.js b/js/element/PinElement.js index 59ca5cf..909157d 100644 --- a/js/element/PinElement.js +++ b/js/element/PinElement.js @@ -46,6 +46,11 @@ export default class PinElement extends IElement { return this.entity.PinId } + /** @type {GuidEntity} */ + GetPinIdValue() { + return this.GetPinId().value + } + /** * @returns {String} */ @@ -92,14 +97,17 @@ export default class PinElement extends IElement { return this.template.getLinkLocation(this) } + /** + * @returns {NodeElement} + */ getNodeElement() { return this.closest("ueb-node") } getLinks() { - return this.entity.LinkedTo.map(pinReference => + return this.entity.LinkedTo?.map(pinReference => pinReference - ) + ) ?? [] } /** diff --git a/js/entity/FunctionReferenceEntity.js b/js/entity/FunctionReferenceEntity.js index 77921a3..d7524fc 100755 --- a/js/entity/FunctionReferenceEntity.js +++ b/js/entity/FunctionReferenceEntity.js @@ -5,9 +5,6 @@ export default class FunctionReferenceEntity extends IEntity { static attributes = { MemberParent: ObjectReferenceEntity, - MemberName: "" + MemberName: "", } - - /** @type {ObjectReferenceEntity} */ MemberParent - /** @type {String} */ MemberName } diff --git a/js/entity/GuidEntity.js b/js/entity/GuidEntity.js index eaa16d7..ab4de12 100755 --- a/js/entity/GuidEntity.js +++ b/js/entity/GuidEntity.js @@ -4,7 +4,7 @@ import IEntity from "./IEntity" export default class GuidEntity extends IEntity { static attributes = { - value: String + value: String, } static generateGuid(random = true) { @@ -19,6 +19,10 @@ export default class GuidEntity extends IEntity { return new GuidEntity({ value: guid }) } + valueOf() { + return this.value + } + toString() { return this.value } diff --git a/js/entity/IEntity.js b/js/entity/IEntity.js index b0e2c72..f2e06bd 100644 --- a/js/entity/IEntity.js +++ b/js/entity/IEntity.js @@ -12,7 +12,7 @@ export default class IEntity { const defineAllAttributes = (prefix, target, properties) => { let fullKey = prefix.concat("") const last = fullKey.length - 1 - for (let property in properties) { + for (let property of Object.getOwnPropertyNames(properties)) { fullKey[last] = property // Not instanceof because all objects are instenceof Object, exact match needed if (properties[property]?.constructor === Object) { @@ -22,7 +22,7 @@ export default class IEntity { } /* * The value can either be: - * - Array: can contain multiple values, its property is assigned multiple times like (X=1, X=4, X="Hello World") + * - 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. @@ -35,6 +35,7 @@ export default class IEntity { let defaultValue = properties[property] if (defaultValue instanceof TypeInitialization) { if (!defaultValue.showDefault) { + target[property] = undefined // to preserve the order continue } defaultValue = defaultValue.value diff --git a/js/entity/IntegerEntity.js b/js/entity/IntegerEntity.js index e593f20..5e20d03 100755 --- a/js/entity/IntegerEntity.js +++ b/js/entity/IntegerEntity.js @@ -3,13 +3,13 @@ import IEntity from "./IEntity" export default class IntegerEntity extends IEntity { static attributes = { - value: Number + value: Number, } constructor(options = {}) { - if (options.constructor === Number || options.constructor === String) { + if (options.constructor == Number || options.constructor == String) { options = { - value: options + value: options, } } super(options) diff --git a/js/entity/LocalizedTextEntity.js b/js/entity/LocalizedTextEntity.js index a35fe46..3d1cd59 100755 --- a/js/entity/LocalizedTextEntity.js +++ b/js/entity/LocalizedTextEntity.js @@ -6,6 +6,6 @@ export default class LocalizedTextEntity extends IEntity { static attributes = { namespace: String, key: String, - value: String + value: String, } } diff --git a/js/entity/ObjectEntity.js b/js/entity/ObjectEntity.js index cd54c29..a1a6c16 100755 --- a/js/entity/ObjectEntity.js +++ b/js/entity/ObjectEntity.js @@ -22,11 +22,11 @@ export default class ObjectEntity extends IEntity { NodeGuid: GuidEntity, ErrorType: new TypeInitialization(IntegerEntity, false), ErrorMsg: new TypeInitialization(String, false, ""), - CustomProperties: [PinEntity] + CustomProperties: [PinEntity], } /** - * @returns {String} The name of the node + * @returns {String} */ getName() { return this.Name diff --git a/js/entity/ObjectReferenceEntity.js b/js/entity/ObjectReferenceEntity.js index 84d3571..3458f11 100755 --- a/js/entity/ObjectReferenceEntity.js +++ b/js/entity/ObjectReferenceEntity.js @@ -4,6 +4,6 @@ export default class ObjectReferenceEntity extends IEntity { static attributes = { type: String, - path: String + path: String, } } diff --git a/js/entity/PathSymbolEntity.js b/js/entity/PathSymbolEntity.js index b995eb1..ea6d518 100755 --- a/js/entity/PathSymbolEntity.js +++ b/js/entity/PathSymbolEntity.js @@ -3,7 +3,7 @@ import IEntity from "./IEntity" export default class PathSymbolEntity extends IEntity { static attributes = { - value: String + value: String, } toString() { diff --git a/js/entity/PinEntity.js b/js/entity/PinEntity.js index ebe5c4a..fa87f86 100755 --- a/js/entity/PinEntity.js +++ b/js/entity/PinEntity.js @@ -71,13 +71,13 @@ export default class PinEntity extends IEntity { linkTo(targetObjectName, targetPinEntity) { /** @type {PinReferenceEntity[]} */ this.LinkedTo - const linkExists = this.LinkedTo.find( + const linkFound = this.LinkedTo.find( /** @type {PinReferenceEntity} */ pinReferenceEntity => { return pinReferenceEntity.objectName == targetObjectName - && pinReferenceEntity.pinGuid == targetPinEntity.PinId + && pinReferenceEntity.pinGuid.valueOf() == targetPinEntity.PinId.valueOf() }) - if (!linkExists) { + if (!linkFound) { this.LinkedTo.push(new PinReferenceEntity({ objectName: targetObjectName, pinGuid: targetPinEntity.PinId diff --git a/js/entity/PinReferenceEntity.js b/js/entity/PinReferenceEntity.js index 9e3d175..3c4770e 100755 --- a/js/entity/PinReferenceEntity.js +++ b/js/entity/PinReferenceEntity.js @@ -6,6 +6,6 @@ export default class PinReferenceEntity extends IEntity { static attributes = { objectName: PathSymbolEntity, - pinGuid: GuidEntity + pinGuid: GuidEntity, } } diff --git a/js/entity/VariableReferenceEntity.js b/js/entity/VariableReferenceEntity.js index c7f0bc9..9a538eb 100755 --- a/js/entity/VariableReferenceEntity.js +++ b/js/entity/VariableReferenceEntity.js @@ -6,6 +6,6 @@ export default class VariableReferenceEntity extends IEntity { static attributes = { MemberName: String, MemberGuid: GuidEntity, - bSelfContext: false + bSelfContext: false, } } diff --git a/js/input/mouse/IMouseClickDrag.js b/js/input/mouse/IMouseClickDrag.js index b277ea4..a47d6a4 100644 --- a/js/input/mouse/IMouseClickDrag.js +++ b/js/input/mouse/IMouseClickDrag.js @@ -46,6 +46,7 @@ export default class IMouseClickDrag extends IPointing { } // Attach the listeners movementListenedElement.addEventListener("mousemove", self.#mouseStartedMovingHandler) + document.addEventListener("mouseup", self.#mouseUpHandler) self.clickedPosition = self.locationFromEvent(e) self.clicked(self.clickedPosition) } @@ -66,7 +67,6 @@ export default class IMouseClickDrag extends IPointing { // Delegate from now on to self.#mouseMoveHandler movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler) movementListenedElement.addEventListener("mousemove", self.#mouseMoveHandler) - document.addEventListener("mouseup", self.#mouseUpHandler) // Handler calls e.preventDefault() when it receives the event, this means dispatchEvent returns false const dragEvent = self.getEvent(Configuration.trackingMouseEventName.begin) self.#trackingMouse = this.target.dispatchEvent(dragEvent) == false @@ -98,7 +98,9 @@ export default class IMouseClickDrag extends IPointing { movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler) movementListenedElement.removeEventListener("mousemove", self.#mouseMoveHandler) document.removeEventListener("mouseup", self.#mouseUpHandler) - self.endDrag() + if (self.started) { + self.endDrag() + } if (self.#trackingMouse) { const dragEvent = self.getEvent(Configuration.trackingMouseEventName.end) this.target.dispatchEvent(dragEvent) diff --git a/js/serialization/ISerializer.js b/js/serialization/ISerializer.js index 83a350d..0065c17 100644 --- a/js/serialization/ISerializer.js +++ b/js/serialization/ISerializer.js @@ -51,14 +51,14 @@ export default class ISerializer { let result = "" let fullKey = key.concat("") const last = fullKey.length - 1 - for (const property in object) { + for (const property of Object.getOwnPropertyNames(object)) { fullKey[last] = property const value = object[property] if (object[property]?.constructor === Object) { // Recursive call when finding an object result += (result.length ? this.separator : "") + this.subWrite(fullKey, value) - } else if (this.showProperty(fullKey, value)) { + } else if (value !== undefined && this.showProperty(fullKey, value)) { result += (result.length ? this.separator : "") + this.prefix + this.attributeKeyPrinter(fullKey) diff --git a/js/serialization/ObjectSerializer.js b/js/serialization/ObjectSerializer.js index 12cb2ff..f667ebb 100755 --- a/js/serialization/ObjectSerializer.js +++ b/js/serialization/ObjectSerializer.js @@ -51,7 +51,7 @@ ${this.subWrite([], object) + object .CustomProperties.map(pin => this.separator + this.prefix + "CustomProperties " + SerializerFactory.getSerializer(PinEntity).write(pin)) .join("")} -End Object` +End Object\n` return result } } diff --git a/js/serialization/initializeSerializerFactory.js b/js/serialization/initializeSerializerFactory.js index 26d85e7..9086587 100755 --- a/js/serialization/initializeSerializerFactory.js +++ b/js/serialization/initializeSerializerFactory.js @@ -28,7 +28,7 @@ export default function initializeSerializerFactory() { ) SerializerFactory.registerSerializer( LocalizedTextEntity, - new GeneralSerializer(v => `${LocalizedTextEntity.lookbehind}(${v})`, LocalizedTextEntity, "", ",", false, "", _ => "") + new GeneralSerializer(v => `${LocalizedTextEntity.lookbehind}(${v})`, LocalizedTextEntity, "", ", ", false, "", _ => "") ) SerializerFactory.registerSerializer( PinReferenceEntity, diff --git a/js/template/LinkTemplate.js b/js/template/LinkTemplate.js index 88812c9..25e27f2 100755 --- a/js/template/LinkTemplate.js +++ b/js/template/LinkTemplate.js @@ -154,7 +154,7 @@ export default class LinkTemplate extends ITemplate { c2 = Math.min(c2, LinkTemplate.c2DecreasingValue(width)) const d = Configuration.linkRightSVGPath(start, c1, c2) // TODO move to CSS when Firefox will support property d and css will have enough functions - link.pathElement.setAttribute("d", d) + link.pathElement?.setAttribute("d", d) } /** diff --git a/js/template/PinTemplate.js b/js/template/PinTemplate.js index 9fd81ad..2addee4 100755 --- a/js/template/PinTemplate.js +++ b/js/template/PinTemplate.js @@ -1,7 +1,6 @@ import html from "./html" import ITemplate from "./ITemplate" import LinkElement from "../element/LinkElement" -import NodeElement from "../element/NodeElement" import sanitizeText from "./sanitizeText" import Utility from "../Utility" @@ -41,15 +40,14 @@ export default class PinTemplate extends ITemplate { "ueb-pin-" + sanitizeText(pin.getType()) ) pin.clickableElement = pin - window.customElements.whenDefined(NodeElement.tagName).then(pin.nodeElement = pin.closest(NodeElement.tagName)) + window.customElements.whenDefined("ueb-node").then(pin.nodeElement = pin.closest("ueb-node")) pin.getLinks().forEach(pinReference => { - const targetPin = pin.blueprint.getPin(pinReference.pinGuid) + const targetPin = pin.blueprint.getPin(pinReference) if (targetPin) { const [sourcePin, destinationPin] = pin.isOutput() ? [pin, targetPin] : [targetPin, pin] pin.blueprint.addGraphElement(new LinkElement(sourcePin, destinationPin)) } }) - } /** diff --git a/rollup.config.js b/rollup.config.js index a20213e..7887b55 100755 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,8 +1,8 @@ -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' +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',