diff --git a/dist/font/roboto-bold.woff b/dist/font/roboto-bold.woff
old mode 100755
new mode 100644
diff --git a/dist/font/roboto-bold.woff2 b/dist/font/roboto-bold.woff2
old mode 100755
new mode 100644
diff --git a/dist/font/roboto-light.woff b/dist/font/roboto-light.woff
old mode 100755
new mode 100644
diff --git a/dist/font/roboto-light.woff2 b/dist/font/roboto-light.woff2
old mode 100755
new mode 100644
diff --git a/dist/font/roboto-regular.woff b/dist/font/roboto-regular.woff
old mode 100755
new mode 100644
diff --git a/dist/font/roboto-regular.woff2 b/dist/font/roboto-regular.woff2
old mode 100755
new mode 100644
diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js
index 2920532..371289c 100755
--- a/dist/ueblueprint.js
+++ b/dist/ueblueprint.js
@@ -143,27 +143,27 @@ class Configuration {
*/
const html = String.raw;
-// @ts-check
-
-/**
- * @typedef {import("../element/IElement").default} IElement
- */
-class ITemplate {
-
- /**
- * @param {IElement} entity
- */
- render(entity) {
- return ""
- }
-
- /**
- * @param {IElement} element
- */
- apply(element) {
- // TODO replace with the safer element.setHTML(...) when it will be availableBreack
- element.innerHTML = this.render(element);
- }
+// @ts-check
+
+/**
+ * @typedef {import("../element/IElement").default} IElement
+ */
+class ITemplate {
+
+ /**
+ * @param {IElement} entity
+ */
+ render(entity) {
+ return ""
+ }
+
+ /**
+ * @param {IElement} element
+ */
+ apply(element) {
+ // TODO replace with the safer element.setHTML(...) when it will be availableBreack
+ element.innerHTML = this.render(element);
+ }
}
// @ts-check
@@ -493,71 +493,71 @@ class FastSelectionModel {
}
-// @ts-check
-
-/**
- * @typedef {import("../Blueprint").default} Blueprint
- * @typedef {import("../entity/IEntity").default} IEntity
- * @typedef {import("../input/IContext").default} IContext
- * @typedef {import("../template/ITemplate").default} ITemplate
- */
-
-class IElement extends HTMLElement {
-
- static tagName = ""
-
- /** @type {Blueprint} */
- blueprint
-
- /** @type {IEntity} */
- entity
-
- /** @type {ITemplate} */
- template
-
- /** @type {IContext[]} */
- inputObjects = []
-
- constructor(entity, template) {
- super();
- this.blueprint = null;
- this.entity = entity;
- this.template = template;
- this.inputObjects = [];
- }
-
- getTemplate() {
- return this.template
- }
-
- connectedCallback() {
- this.blueprint = this.closest("ueb-blueprint");
- this.template.apply(this);
- this.inputObjects = this.createInputObjects();
- }
-
- disconnectedCallback() {
- this.inputObjects.forEach(v => v.unlistenDOMElement());
- }
-
- /** @param {IElement} element */
- isSameGraph(element) {
- return this.blueprint && this.blueprint == element?.blueprint
- }
-
- /**
- * @template {IContext} T
- * @param {new (...args: any[]) => T} type
- * @returns {T}
- */
- getInputObject(type) {
- return /** @type {T} */ (this.inputObjects.find(object => object.constructor == type))
- }
-
- // Subclasses will want to override
- createInputObjects() {
- return []
- }
+// @ts-check
+
+/**
+ * @typedef {import("../Blueprint").default} Blueprint
+ * @typedef {import("../entity/IEntity").default} IEntity
+ * @typedef {import("../input/IContext").default} IContext
+ * @typedef {import("../template/ITemplate").default} ITemplate
+ */
+
+class IElement extends HTMLElement {
+
+ static tagName = ""
+
+ /** @type {Blueprint} */
+ blueprint
+
+ /** @type {IEntity} */
+ entity
+
+ /** @type {ITemplate} */
+ template
+
+ /** @type {IContext[]} */
+ inputObjects = []
+
+ constructor(entity, template) {
+ super();
+ this.blueprint = null;
+ this.entity = entity;
+ this.template = template;
+ this.inputObjects = [];
+ }
+
+ getTemplate() {
+ return this.template
+ }
+
+ connectedCallback() {
+ this.blueprint = this.closest("ueb-blueprint");
+ this.template.apply(this);
+ this.inputObjects = this.createInputObjects();
+ }
+
+ disconnectedCallback() {
+ this.inputObjects.forEach(v => v.unlistenDOMElement());
+ }
+
+ /** @param {IElement} element */
+ isSameGraph(element) {
+ return this.blueprint && this.blueprint == element?.blueprint
+ }
+
+ /**
+ * @template {IContext} T
+ * @param {new (...args: any[]) => T} type
+ * @returns {T}
+ */
+ getInputObject(type) {
+ return /** @type {T} */ (this.inputObjects.find(object => object.constructor == type))
+ }
+
+ // Subclasses will want to override
+ createInputObjects() {
+ return []
+ }
}
// @ts-check
@@ -608,43 +608,43 @@ class SelectorTemplate extends ITemplate {
}
}
-// @ts-check
-
-class SelectorElement extends IElement {
-
- static tagName = "ueb-selector"
-
- constructor() {
- super({}, new SelectorTemplate());
- this.selectionModel = null;
- /** @type {SelectorTemplate} */
- this.template;
- }
-
- /**
- * Create a selection rectangle starting from the specified position
- * @param {Number[]} initialPosition - Selection rectangle initial position (relative to the .ueb-grid element)
- */
- startSelecting(initialPosition) {
- this.template.applyStartSelecting(this, initialPosition);
- 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) {
- this.template.applyDoSelecting(this, finalPosition);
- this.selectionModel.selectTo(finalPosition);
- }
-
- finishSelecting() {
- this.template.applyFinishSelecting(this);
- this.selectionModel = null;
- }
-}
-
+// @ts-check
+
+class SelectorElement extends IElement {
+
+ static tagName = "ueb-selector"
+
+ constructor() {
+ super({}, new SelectorTemplate());
+ this.selectionModel = null;
+ /** @type {SelectorTemplate} */
+ this.template;
+ }
+
+ /**
+ * Create a selection rectangle starting from the specified position
+ * @param {Number[]} initialPosition - Selection rectangle initial position (relative to the .ueb-grid element)
+ */
+ startSelecting(initialPosition) {
+ this.template.applyStartSelecting(this, initialPosition);
+ 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) {
+ this.template.applyDoSelecting(this, finalPosition);
+ this.selectionModel.selectTo(finalPosition);
+ }
+
+ finishSelecting() {
+ this.template.applyFinishSelecting(this);
+ this.selectionModel = null;
+ }
+}
+
customElements.define(SelectorElement.tagName, SelectorElement);
// @ts-check
@@ -791,62 +791,62 @@ class BlueprintTemplate extends ITemplate {
}
}
-// @ts-check
-
-/**
- * @typedef {import("../Blueprint").default} Blueprint
- */
-class IContext {
-
- /** @type {HTMLElement} */
- target
-
- /** @type {Blueprint} */
- blueprint
-
- /** @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;
- self.listenEvents();
- };
- this.blueprintUnfocusHandler = _ => {
- self.unlistenEvents();
- this.#hasFocus = false;
- };
- if (options?.wantsFocusCallback ?? false) {
- this.blueprint.addEventListener("blueprint-focus", this.blueprintFocusHandler);
- this.blueprint.addEventListener("blueprint-unfocus", this.blueprintUnfocusHandler);
- }
- }
-
- unlistenDOMElement() {
- this.unlistenEvents();
- this.blueprint.removeEventListener("blueprint-focus", this.blueprintFocusHandler);
- this.blueprint.removeEventListener("blueprint-unfocus", this.blueprintUnfocusHandler);
- }
-
- /* Subclasses will probabily override the following methods */
- listenEvents() {
- }
-
- unlistenEvents() {
- }
+// @ts-check
+
+/**
+ * @typedef {import("../Blueprint").default} Blueprint
+ */
+class IContext {
+
+ /** @type {HTMLElement} */
+ target
+
+ /** @type {Blueprint} */
+ blueprint
+
+ /** @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;
+ self.listenEvents();
+ };
+ this.blueprintUnfocusHandler = _ => {
+ self.unlistenEvents();
+ this.#hasFocus = false;
+ };
+ if (options?.wantsFocusCallback ?? false) {
+ this.blueprint.addEventListener("blueprint-focus", this.blueprintFocusHandler);
+ this.blueprint.addEventListener("blueprint-unfocus", this.blueprintUnfocusHandler);
+ }
+ }
+
+ unlistenDOMElement() {
+ this.unlistenEvents();
+ this.blueprint.removeEventListener("blueprint-focus", this.blueprintFocusHandler);
+ this.blueprint.removeEventListener("blueprint-unfocus", this.blueprintUnfocusHandler);
+ }
+
+ /* Subclasses will probabily override the following methods */
+ listenEvents() {
+ }
+
+ unlistenEvents() {
+ }
}
// @ts-check
@@ -998,66 +998,66 @@ class Utility {
}
}
-// @ts-check
-
-class IEntity {
-
- static attributes = {}
-
- 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 of Object.getOwnPropertyNames(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 !== undefined) {
- target[property] = value;
- continue
- }
- let defaultValue = properties[property];
- if (defaultValue instanceof TypeInitialization) {
- if (!defaultValue.showDefault) {
- target[property] = undefined; // to preserve the order
- continue
- }
- defaultValue = defaultValue.value;
- }
- if (defaultValue instanceof Array) {
- target[property] = [];
- continue
- }
- if (defaultValue instanceof Function) {
- defaultValue = TypeInitialization.sanitize(new defaultValue());
- }
- target[property] = TypeInitialization.sanitize(defaultValue);
- }
- };
- // @ts-expect-error
- defineAllAttributes([], this, this.constructor.attributes);
- }
-
- empty() {
- return true
- }
+// @ts-check
+
+class IEntity {
+
+ static attributes = {}
+
+ 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 of Object.getOwnPropertyNames(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 !== undefined) {
+ target[property] = value;
+ continue
+ }
+ let defaultValue = properties[property];
+ if (defaultValue instanceof TypeInitialization) {
+ if (!defaultValue.showDefault) {
+ target[property] = undefined; // to preserve the order
+ continue
+ }
+ defaultValue = defaultValue.value;
+ }
+ if (defaultValue instanceof Array) {
+ target[property] = [];
+ continue
+ }
+ if (defaultValue instanceof Function) {
+ defaultValue = TypeInitialization.sanitize(new defaultValue());
+ }
+ target[property] = TypeInitialization.sanitize(defaultValue);
+ }
+ };
+ // @ts-expect-error
+ defineAllAttributes([], this, this.constructor.attributes);
+ }
+
+ empty() {
+ return true
+ }
}
// @ts-check
@@ -1130,32 +1130,32 @@ class GuidEntity extends IEntity {
}
}
-// @ts-check
-
-class IdentifierEntity extends IEntity {
-
- static attributes = {
- value: String,
- }
-
- constructor(options = {}) {
- // Not instanceof to pick also primitive string
- if (options.constructor === String) {
- options = {
- value: options
- };
- }
- super(options);
- /** @type {String} */ this.value;
- }
-
- valueOf() {
- return this.value
- }
-
- toString() {
- return this.value
- }
+// @ts-check
+
+class IdentifierEntity extends IEntity {
+
+ static attributes = {
+ value: String,
+ }
+
+ constructor(options = {}) {
+ // Not instanceof to pick also primitive string
+ if (options.constructor === String) {
+ options = {
+ value: options
+ };
+ }
+ super(options);
+ /** @type {String} */ this.value;
+ }
+
+ valueOf() {
+ return this.value
+ }
+
+ toString() {
+ return this.value
+ }
}
// @ts-check
@@ -1188,28 +1188,28 @@ class IntegerEntity extends IEntity {
}
}
-// @ts-check
-
-class KeyBindingEntity extends IEntity {
-
- static attributes = {
- ActionName: "",
- bShift: false,
- bCtrl: false,
- bAlt: false,
- bCmd: false,
- Key: IdentifierEntity,
- }
-
- constructor(options = {}) {
- super(options);
- /** @type {String} */ this.ActionName;
- /** @type {Boolean} */ this.bShift;
- /** @type {Boolean} */ this.bCtrl;
- /** @type {Boolean} */ this.bAlt;
- /** @type {Boolean} */ this.bCmd;
- /** @type {IdentifierEntity} */ this.Key;
- }
+// @ts-check
+
+class KeyBindingEntity extends IEntity {
+
+ static attributes = {
+ ActionName: "",
+ bShift: false,
+ bCtrl: false,
+ bAlt: false,
+ bCmd: false,
+ Key: IdentifierEntity,
+ }
+
+ constructor(options = {}) {
+ super(options);
+ /** @type {String} */ this.ActionName;
+ /** @type {Boolean} */ this.bShift;
+ /** @type {Boolean} */ this.bCtrl;
+ /** @type {Boolean} */ this.bAlt;
+ /** @type {Boolean} */ this.bCmd;
+ /** @type {IdentifierEntity} */ this.Key;
+ }
}
// @ts-check
@@ -1732,84 +1732,84 @@ class SerializerFactory {
}
}
-// @ts-check
-
-class ISerializer {
-
- static grammar = Parsimmon.createLanguage(new Grammar())
-
- constructor(entityType, prefix, separator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) {
- this.entityType = entityType;
- this.prefix = prefix ?? "";
- this.separator = separator ?? ",";
- this.trailingSeparator = trailingSeparator ?? false;
- this.attributeValueConjunctionSign = attributeValueConjunctionSign ?? "=";
- this.attributeKeyPrinter = attributeKeyPrinter ?? (k => k.join("."));
- }
-
- writeValue(value) {
- if (value === null) {
- return "()"
- }
- const serialize = v => SerializerFactory.getSerializer(Utility.getType(v)).write(v);
- // This is an exact match (and not instanceof) to hit also primitive types (by accessing value.constructor they are converted to objects automatically)
- switch (value?.constructor) {
- case Function:
- return this.writeValue(value())
- case Boolean:
- return Utility.FirstCapital(value.toString())
- case Number:
- return value.toString()
- case String:
- return `"${value}"`
- }
- if (value instanceof Array) {
- return `(${value.map(v => serialize(v) + ",").join("")})`
- }
- if (value instanceof IEntity) {
- return serialize(value)
- }
- }
-
- /**
- * @param {String[]} key
- * @param {Object} object
- * @returns {String}
- */
- subWrite(key, object) {
- let result = "";
- let fullKey = key.concat("");
- const last = fullKey.length - 1;
- 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 (value !== undefined && this.showProperty(object, fullKey, value)) {
- result += (result.length ? this.separator : "")
- + this.prefix
- + this.attributeKeyPrinter(fullKey)
- + this.attributeValueConjunctionSign
- + this.writeValue(value);
- }
- }
- if (this.trailingSeparator && result.length && fullKey.length === 1) {
- // append separator at the end if asked and there was printed content
- result += this.separator;
- }
- return result
- }
-
- showProperty(object, attributeKey, attributeValue) {
- const attributes = this.entityType.attributes;
- const attribute = Utility.objectGet(attributes, attributeKey);
- if (attribute instanceof TypeInitialization) {
- return !Utility.equals(attribute.value, attributeValue) || attribute.showDefault
- }
- return true
- }
+// @ts-check
+
+class ISerializer {
+
+ static grammar = Parsimmon.createLanguage(new Grammar())
+
+ constructor(entityType, prefix, separator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) {
+ this.entityType = entityType;
+ this.prefix = prefix ?? "";
+ this.separator = separator ?? ",";
+ this.trailingSeparator = trailingSeparator ?? false;
+ this.attributeValueConjunctionSign = attributeValueConjunctionSign ?? "=";
+ this.attributeKeyPrinter = attributeKeyPrinter ?? (k => k.join("."));
+ }
+
+ writeValue(value) {
+ if (value === null) {
+ return "()"
+ }
+ const serialize = v => SerializerFactory.getSerializer(Utility.getType(v)).write(v);
+ // This is an exact match (and not instanceof) to hit also primitive types (by accessing value.constructor they are converted to objects automatically)
+ switch (value?.constructor) {
+ case Function:
+ return this.writeValue(value())
+ case Boolean:
+ return Utility.FirstCapital(value.toString())
+ case Number:
+ return value.toString()
+ case String:
+ return `"${value}"`
+ }
+ if (value instanceof Array) {
+ return `(${value.map(v => serialize(v) + ",").join("")})`
+ }
+ if (value instanceof IEntity) {
+ return serialize(value)
+ }
+ }
+
+ /**
+ * @param {String[]} key
+ * @param {Object} object
+ * @returns {String}
+ */
+ subWrite(key, object) {
+ let result = "";
+ let fullKey = key.concat("");
+ const last = fullKey.length - 1;
+ 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 (value !== undefined && this.showProperty(object, fullKey, value)) {
+ result += (result.length ? this.separator : "")
+ + this.prefix
+ + this.attributeKeyPrinter(fullKey)
+ + this.attributeValueConjunctionSign
+ + this.writeValue(value);
+ }
+ }
+ if (this.trailingSeparator && result.length && fullKey.length === 1) {
+ // append separator at the end if asked and there was printed content
+ result += this.separator;
+ }
+ return result
+ }
+
+ showProperty(object, attributeKey, attributeValue) {
+ const attributes = this.entityType.attributes;
+ const attribute = Utility.objectGet(attributes, attributeKey);
+ if (attribute instanceof TypeInitialization) {
+ return !Utility.equals(attribute.value, attributeValue) || attribute.showDefault
+ }
+ return true
+ }
}
// @ts-check
@@ -1899,90 +1899,90 @@ class Copy extends IContext {
}
}
-// @ts-check
-
-class IKeyboardShortcut extends IContext {
-
- /** @type {KeyBindingEntity[]} */
- #activationKeys
-
- constructor(target, blueprint, options = {}) {
- options.wantsFocusCallback = true;
- options.activationKeys ??= [];
- if (!(options.activationKeys instanceof Array)) {
- options.activationKeys = [options.activationKeys];
- }
- options.activationKeys = options.activationKeys.map(v => {
- if (v instanceof KeyBindingEntity) {
- return v
- }
- if (v.constructor === String) {
- // @ts-expect-error
- const parsed = ISerializer.grammar.KeyBinding.parse(v);
- if (parsed.status) {
- return parsed.value
- }
- }
- throw new Error("Unexpected key value")
- });
-
- super(target, blueprint, options);
-
- this.#activationKeys = this.options.activationKeys ?? [];
-
- const wantsShift = keyEntry => keyEntry.bShift || keyEntry.Key == "LeftShift" || keyEntry.Key == "RightShift";
- const wantsCtrl = keyEntry => keyEntry.bCtrl || keyEntry.Key == "LeftControl" || keyEntry.Key == "RightControl";
- const wantsAlt = keyEntry => keyEntry.bAlt || keyEntry.Key == "LeftAlt" || keyEntry.Key == "RightAlt";
-
- let self = this;
- /** @param {KeyboardEvent} e */
- this.keyDownHandler = e => {
- if (
- self.#activationKeys.some(keyEntry =>
- wantsShift(keyEntry) == e.shiftKey
- && wantsCtrl(keyEntry) == e.ctrlKey
- && wantsAlt(keyEntry) == e.altKey
- && this.blueprint.settings.Keys[keyEntry.Key] == e.code
- )) {
- self.fire();
- document.removeEventListener("keydown", self.keyDownHandler);
- document.addEventListener("keyup", self.keyUpHandler);
- }
- };
-
- /** @param {KeyboardEvent} e */
- this.keyUpHandler = e => {
- if (
- self.#activationKeys.some(keyEntry =>
- 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?
- || this.blueprint.settings.Keys[keyEntry.Key] == e.code
- )) {
- self.unfire();
- document.removeEventListener("keyup", this.keyUpHandler);
- document.addEventListener("keydown", this.keyDownHandler);
- }
- };
-
- }
-
- listenEvents() {
- document.addEventListener("keydown", this.keyDownHandler);
- }
-
- unlistenEvents() {
- document.removeEventListener("keydown", this.keyDownHandler);
- }
-
- // Subclasses will want to override
-
- fire() {
- }
-
- unfire() {
- }
+// @ts-check
+
+class IKeyboardShortcut extends IContext {
+
+ /** @type {KeyBindingEntity[]} */
+ #activationKeys
+
+ constructor(target, blueprint, options = {}) {
+ options.wantsFocusCallback = true;
+ options.activationKeys ??= [];
+ if (!(options.activationKeys instanceof Array)) {
+ options.activationKeys = [options.activationKeys];
+ }
+ options.activationKeys = options.activationKeys.map(v => {
+ if (v instanceof KeyBindingEntity) {
+ return v
+ }
+ if (v.constructor === String) {
+ // @ts-expect-error
+ const parsed = ISerializer.grammar.KeyBinding.parse(v);
+ if (parsed.status) {
+ return parsed.value
+ }
+ }
+ throw new Error("Unexpected key value")
+ });
+
+ super(target, blueprint, options);
+
+ this.#activationKeys = this.options.activationKeys ?? [];
+
+ const wantsShift = keyEntry => keyEntry.bShift || keyEntry.Key == "LeftShift" || keyEntry.Key == "RightShift";
+ const wantsCtrl = keyEntry => keyEntry.bCtrl || keyEntry.Key == "LeftControl" || keyEntry.Key == "RightControl";
+ const wantsAlt = keyEntry => keyEntry.bAlt || keyEntry.Key == "LeftAlt" || keyEntry.Key == "RightAlt";
+
+ let self = this;
+ /** @param {KeyboardEvent} e */
+ this.keyDownHandler = e => {
+ if (
+ self.#activationKeys.some(keyEntry =>
+ wantsShift(keyEntry) == e.shiftKey
+ && wantsCtrl(keyEntry) == e.ctrlKey
+ && wantsAlt(keyEntry) == e.altKey
+ && this.blueprint.settings.Keys[keyEntry.Key] == e.code
+ )) {
+ self.fire();
+ document.removeEventListener("keydown", self.keyDownHandler);
+ document.addEventListener("keyup", self.keyUpHandler);
+ }
+ };
+
+ /** @param {KeyboardEvent} e */
+ this.keyUpHandler = e => {
+ if (
+ self.#activationKeys.some(keyEntry =>
+ 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?
+ || this.blueprint.settings.Keys[keyEntry.Key] == e.code
+ )) {
+ self.unfire();
+ document.removeEventListener("keyup", this.keyUpHandler);
+ document.addEventListener("keydown", this.keyDownHandler);
+ }
+ };
+
+ }
+
+ listenEvents() {
+ document.addEventListener("keydown", this.keyDownHandler);
+ }
+
+ unlistenEvents() {
+ document.removeEventListener("keydown", this.keyDownHandler);
+ }
+
+ // Subclasses will want to override
+
+ fire() {
+ }
+
+ unfire() {
+ }
}
// @ts-check
@@ -2007,72 +2007,72 @@ class KeyboardCanc extends IKeyboardShortcut {
}
}
-// @ts-check
-
-class IPointing extends IContext {
-
- constructor(target, blueprint, options) {
- super(target, blueprint, options);
- this.movementSpace = this.blueprint?.getGridDOMElement() ?? document.documentElement;
- }
-
- /**
- * @param {MouseEvent} mouseEvent
- */
- locationFromEvent(mouseEvent) {
- return this.blueprint.compensateTranslation(
- Utility.convertLocation(
- [mouseEvent.clientX, mouseEvent.clientY],
- this.movementSpace))
- }
+// @ts-check
+
+class IPointing extends IContext {
+
+ constructor(target, blueprint, options) {
+ super(target, blueprint, options);
+ this.movementSpace = this.blueprint?.getGridDOMElement() ?? document.documentElement;
+ }
+
+ /**
+ * @param {MouseEvent} mouseEvent
+ */
+ locationFromEvent(mouseEvent) {
+ return this.blueprint.compensateTranslation(
+ Utility.convertLocation(
+ [mouseEvent.clientX, mouseEvent.clientY],
+ this.movementSpace))
+ }
}
-// @ts-check
-
-class IMouseWheel extends IPointing {
-
- /** @type {(e: WheelEvent) => void} */
- #mouseWheelHandler
-
- /** @type {(e: WheelEvent) => void} */
- #mouseParentWheelHandler
-
- /**
- * @param {HTMLElement} target
- * @param {import("../../Blueprint").default} blueprint
- * @param {Object} options
- */
- constructor(target, blueprint, options) {
- options.wantsFocusCallback = true;
- super(target, blueprint, options);
- this.looseTarget = options?.looseTarget ?? true;
- let self = this;
-
- this.#mouseWheelHandler = e => {
- e.preventDefault();
- const location = self.locationFromEvent(e);
- self.wheel(Math.sign(e.deltaY), location);
- };
- this.#mouseParentWheelHandler = e => e.preventDefault();
-
- if (this.blueprint.focused) {
- this.movementSpace.addEventListener("wheel", this.#mouseWheelHandler, false);
- }
- }
-
- listenEvents() {
- this.movementSpace.addEventListener("wheel", this.#mouseWheelHandler, false);
- this.movementSpace.parentElement?.addEventListener("wheel", this.#mouseParentWheelHandler);
- }
-
- unlistenEvents() {
- this.movementSpace.removeEventListener("wheel", this.#mouseWheelHandler, false);
- this.movementSpace.parentElement?.removeEventListener("wheel", this.#mouseParentWheelHandler);
- }
-
- /* Subclasses will override the following method */
- wheel(variation, location) {
- }
+// @ts-check
+
+class IMouseWheel extends IPointing {
+
+ /** @type {(e: WheelEvent) => void} */
+ #mouseWheelHandler
+
+ /** @type {(e: WheelEvent) => void} */
+ #mouseParentWheelHandler
+
+ /**
+ * @param {HTMLElement} target
+ * @param {import("../../Blueprint").default} blueprint
+ * @param {Object} options
+ */
+ constructor(target, blueprint, options) {
+ options.wantsFocusCallback = true;
+ super(target, blueprint, options);
+ this.looseTarget = options?.looseTarget ?? true;
+ let self = this;
+
+ this.#mouseWheelHandler = e => {
+ e.preventDefault();
+ const location = self.locationFromEvent(e);
+ self.wheel(Math.sign(e.deltaY), location);
+ };
+ this.#mouseParentWheelHandler = e => e.preventDefault();
+
+ if (this.blueprint.focused) {
+ this.movementSpace.addEventListener("wheel", this.#mouseWheelHandler, false);
+ }
+ }
+
+ listenEvents() {
+ this.movementSpace.addEventListener("wheel", this.#mouseWheelHandler, false);
+ this.movementSpace.parentElement?.addEventListener("wheel", this.#mouseParentWheelHandler);
+ }
+
+ unlistenEvents() {
+ this.movementSpace.removeEventListener("wheel", this.#mouseWheelHandler, false);
+ this.movementSpace.parentElement?.removeEventListener("wheel", this.#mouseParentWheelHandler);
+ }
+
+ /* Subclasses will override the following method */
+ wheel(variation, location) {
+ }
}
// @ts-check
@@ -2104,34 +2104,34 @@ class Zoom extends IMouseWheel {
}
}
-// @ts-check
-
-class KeyboardEnableZoom extends IKeyboardShortcut {
-
- /** @type {} */
- #zoomInputObject
-
- /**
- * @param {HTMLElement} target
- * @param {import("../../Blueprint").default} blueprint
- * @param {Object} options
- */
- constructor(target, blueprint, options = {}) {
- options = {
- ...options,
- activationKeys: blueprint.settings.enableZoomIn
- };
- super(target, blueprint, options);
- }
-
- fire() {
- this.#zoomInputObject = this.blueprint.getInputObject(Zoom);
- this.#zoomInputObject.enableZoonIn = true;
- }
-
- unfire() {
- this.#zoomInputObject.enableZoonIn = false;
- }
+// @ts-check
+
+class KeyboardEnableZoom extends IKeyboardShortcut {
+
+ /** @type {} */
+ #zoomInputObject
+
+ /**
+ * @param {HTMLElement} target
+ * @param {import("../../Blueprint").default} blueprint
+ * @param {Object} options
+ */
+ constructor(target, blueprint, options = {}) {
+ options = {
+ ...options,
+ activationKeys: blueprint.settings.enableZoomIn
+ };
+ super(target, blueprint, options);
+ }
+
+ fire() {
+ this.#zoomInputObject = this.blueprint.getInputObject(Zoom);
+ this.#zoomInputObject.enableZoonIn = true;
+ }
+
+ unfire() {
+ this.#zoomInputObject.enableZoonIn = false;
+ }
}
// @ts-check
@@ -2322,360 +2322,362 @@ class LinkTemplate extends ITemplate {
}
}
-// @ts-check
-
-/**
- * @typedef {import("./PinElement").default} PinElement
- * @typedef {import("./LinkMessageElement").default} LinkMessageElement
- */
-class LinkElement extends IElement {
-
- static tagName = "ueb-link"
- /** @type {PinElement} */
- #source
- /** @type {PinElement} */
- #destination
- #nodeDeleteHandler
- #nodeDragSourceHandler
- #nodeDragDestinatonHandler
- sourceLocation = [0, 0]
- /** @type {SVGPathElement} */
- pathElement
- /** @type {LinkMessageElement} */
- linkMessageElement
- originatesFromInput = false
- destinationLocation = [0, 0]
-
- /**
- * @param {PinElement} source
- * @param {PinElement} destination
- */
- constructor(source, destination) {
- super({}, new LinkTemplate());
- /** @type {import("../template/LinkTemplate").default} */
- this.template;
- const self = this;
- this.#nodeDeleteHandler = _ => self.remove();
- this.#nodeDragSourceHandler = e => self.addSourceLocation(e.detail.value);
- this.#nodeDragDestinatonHandler = e => self.addDestinationLocation(e.detail.value);
- if (source) {
- this.setSourcePin(source);
- }
- if (destination) {
- this.setDestinationPin(destination);
- }
- if (source && destination) {
- this.#linkPins();
- }
- }
-
- #linkPins() {
- this.#source.linkTo(this.#destination);
- this.#destination.linkTo(this.#source);
- }
-
- #unlinkPins() {
- if (this.#source && this.#destination) {
- this.#source.unlinkFrom(this.#destination);
- this.#destination.unlinkFrom(this.#source);
- }
- }
-
- disconnectedCallback() {
- super.disconnectedCallback();
- this.#unlinkPins();
- }
-
- /**
- * @returns {Number[]}
- */
- getSourceLocation() {
- return this.sourceLocation
- }
-
- /**
- * @param {Number[]} offset
- */
- addSourceLocation(offset) {
- const location = [
- this.sourceLocation[0] + offset[0],
- this.sourceLocation[1] + offset[1]
- ];
- this.sourceLocation = location;
- this.template.applyFullLocation(this);
- }
-
- /**
- * @param {Number[]} location
- */
- setSourceLocation(location = null) {
- if (location == null) {
- location = this.#source.template.getLinkLocation(this.#source);
- }
- this.sourceLocation = location;
- this.template.applySourceLocation(this);
- }
-
- /**
- * @returns {Number[]}
- */
- getDestinationLocation() {
- return this.destinationLocation
- }
-
- /**
- * @param {Number[]} offset
- */
- addDestinationLocation(offset) {
- const location = [
- this.destinationLocation[0] + offset[0],
- this.destinationLocation[1] + offset[1]
- ];
- this.setDestinationLocation(location);
- }
-
- /**
- * @param {Number[]} location
- */
- setDestinationLocation(location = null) {
- if (location == null) {
- location = this.#destination.template.getLinkLocation(this.#destination);
- }
- this.destinationLocation = location;
- this.template.applyFullLocation(this);
- }
-
- /**
- * @returns {PinElement}
- */
- getSourcePin() {
- return this.#source
- }
-
- /**
- * @param {PinElement} pin
- */
- setSourcePin(pin) {
- if (this.#source) {
- const nodeElement = this.#source.getNodeElement();
- nodeElement.removeEventListener(this.blueprint.settings.nodeDeleteEventName, this.#nodeDeleteHandler);
- nodeElement.removeEventListener(this.blueprint.settings.nodeDragLocalEventName, this.#nodeDragSourceHandler);
- if (this.#destination) {
- this.#unlinkPins();
- }
- }
- this.#source = pin;
- if (this.#source) {
- const nodeElement = this.#source.getNodeElement();
- this.originatesFromInput = pin.isInput();
- nodeElement.addEventListener(this.blueprint.settings.nodeDeleteEventName, this.#nodeDeleteHandler);
- nodeElement.addEventListener(this.blueprint.settings.nodeDragLocalEventName, this.#nodeDragSourceHandler);
- this.setSourceLocation();
- if (this.#destination) {
- this.#linkPins();
- }
- }
- }
-
- /**
- * @returns {PinElement}
- */
- getDestinationPin() {
- return this.#destination
- }
-
- /**
- * @param {PinElement} pin
- */
- setDestinationPin(pin) {
- if (this.#destination) {
- const nodeElement = this.#destination.getNodeElement();
- nodeElement.removeEventListener(this.blueprint.settings.nodeDeleteEventName, this.#nodeDeleteHandler);
- nodeElement.removeEventListener(this.blueprint.settings.nodeDragLocalEventName, this.#nodeDragDestinatonHandler);
- if (this.#source) {
- this.#unlinkPins();
- }
- }
- this.#destination = pin;
- if (this.#destination) {
- const nodeElement = this.#destination.getNodeElement();
- nodeElement.addEventListener(this.blueprint.settings.nodeDeleteEventName, this.#nodeDeleteHandler);
- nodeElement.addEventListener(this.blueprint.settings.nodeDragLocalEventName, this.#nodeDragDestinatonHandler);
- this.setDestinationLocation();
- if (this.#source) {
- this.#linkPins();
- }
- }
- }
-
- /**
- * @param {LinkMessageElement} linkMessage
- */
- setLinkMessage(linkMessage) {
- if (linkMessage) {
- this.template.applyLinkMessage(this, linkMessage);
- } else if (this.linkMessageElement) {
- this.linkMessageElement.remove();
- this.linkMessageElement = null;
- }
- }
-
- startDragging() {
- this.template.applyStartDragging(this);
- }
-
- finishDragging() {
- this.template.applyFinishDragging(this);
- }
-}
-
+// @ts-check
+
+/**
+ * @typedef {import("./PinElement").default} PinElement
+ * @typedef {import("./LinkMessageElement").default} LinkMessageElement
+ */
+class LinkElement extends IElement {
+
+ static tagName = "ueb-link"
+ /** @type {PinElement} */
+ #source
+ /** @type {PinElement} */
+ #destination
+ #nodeDeleteHandler
+ #nodeDragSourceHandler
+ #nodeDragDestinatonHandler
+ sourceLocation = [0, 0]
+ /** @type {SVGPathElement} */
+ pathElement
+ /** @type {LinkMessageElement} */
+ linkMessageElement
+ originatesFromInput = false
+ destinationLocation = [0, 0]
+
+ /**
+ * @param {PinElement} source
+ * @param {PinElement} destination
+ */
+ constructor(source, destination) {
+ super({}, new LinkTemplate());
+ /** @type {import("../template/LinkTemplate").default} */
+ this.template;
+ const self = this;
+ this.#nodeDeleteHandler = _ => self.remove();
+ this.#nodeDragSourceHandler = e => self.addSourceLocation(e.detail.value);
+ this.#nodeDragDestinatonHandler = e => self.addDestinationLocation(e.detail.value);
+ if (source) {
+ this.setSourcePin(source);
+ }
+ if (destination) {
+ this.setDestinationPin(destination);
+ }
+ if (source && destination) {
+ this.#linkPins();
+ }
+ }
+
+ #linkPins() {
+ this.#source.linkTo(this.#destination);
+ this.#destination.linkTo(this.#source);
+ }
+
+ #unlinkPins() {
+ if (this.#source && this.#destination) {
+ this.#source.unlinkFrom(this.#destination);
+ this.#destination.unlinkFrom(this.#source);
+ }
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ this.#unlinkPins();
+ }
+
+ /**
+ * @returns {Number[]}
+ */
+ getSourceLocation() {
+ return this.sourceLocation
+ }
+
+ /**
+ * @param {Number[]} offset
+ */
+ addSourceLocation(offset) {
+ const location = [
+ this.sourceLocation[0] + offset[0],
+ this.sourceLocation[1] + offset[1]
+ ];
+ this.sourceLocation = location;
+ this.template.applyFullLocation(this);
+ }
+
+ /**
+ * @param {Number[]} location
+ */
+ setSourceLocation(location = null) {
+ if (location == null) {
+ location = this.#source.template.getLinkLocation(this.#source);
+ }
+ this.sourceLocation = location;
+ this.template.applySourceLocation(this);
+ }
+
+ /**
+ * @returns {Number[]}
+ */
+ getDestinationLocation() {
+ return this.destinationLocation
+ }
+
+ /**
+ * @param {Number[]} offset
+ */
+ addDestinationLocation(offset) {
+ const location = [
+ this.destinationLocation[0] + offset[0],
+ this.destinationLocation[1] + offset[1]
+ ];
+ this.setDestinationLocation(location);
+ }
+
+ /**
+ * @param {Number[]} location
+ */
+ setDestinationLocation(location = null) {
+ if (location == null) {
+ location = this.#destination.template.getLinkLocation(this.#destination);
+ }
+ this.destinationLocation = location;
+ this.template.applyFullLocation(this);
+ }
+
+ /**
+ * @returns {PinElement}
+ */
+ getSourcePin() {
+ return this.#source
+ }
+
+ /**
+ * @param {PinElement} pin
+ */
+ setSourcePin(pin) {
+ if (this.#source) {
+ const settings = this.#source.blueprint.settings;
+ const nodeElement = this.#source.getNodeElement();
+ nodeElement.removeEventListener(settings.nodeDeleteEventName, this.#nodeDeleteHandler);
+ nodeElement.removeEventListener(settings.nodeDragLocalEventName, this.#nodeDragSourceHandler);
+ if (this.#destination) {
+ this.#unlinkPins();
+ }
+ }
+ this.#source = pin;
+ if (this.#source) {
+ const nodeElement = this.#source.getNodeElement();
+ const settings = this.#source.blueprint.settings;
+ this.originatesFromInput = pin.isInput();
+ nodeElement.addEventListener(settings.nodeDeleteEventName, this.#nodeDeleteHandler);
+ nodeElement.addEventListener(settings.nodeDragLocalEventName, this.#nodeDragSourceHandler);
+ this.setSourceLocation();
+ if (this.#destination) {
+ this.#linkPins();
+ }
+ }
+ }
+
+ /**
+ * @returns {PinElement}
+ */
+ getDestinationPin() {
+ return this.#destination
+ }
+
+ /**
+ * @param {PinElement} pin
+ */
+ setDestinationPin(pin) {
+ if (this.#destination) {
+ const nodeElement = this.#destination.getNodeElement();
+ nodeElement.removeEventListener(this.blueprint.settings.nodeDeleteEventName, this.#nodeDeleteHandler);
+ nodeElement.removeEventListener(this.blueprint.settings.nodeDragLocalEventName, this.#nodeDragDestinatonHandler);
+ if (this.#source) {
+ this.#unlinkPins();
+ }
+ }
+ this.#destination = pin;
+ if (this.#destination) {
+ const nodeElement = this.#destination.getNodeElement();
+ nodeElement.addEventListener(this.blueprint.settings.nodeDeleteEventName, this.#nodeDeleteHandler);
+ nodeElement.addEventListener(this.blueprint.settings.nodeDragLocalEventName, this.#nodeDragDestinatonHandler);
+ this.setDestinationLocation();
+ if (this.#source) {
+ this.#linkPins();
+ }
+ }
+ }
+
+ /**
+ * @param {LinkMessageElement} linkMessage
+ */
+ setLinkMessage(linkMessage) {
+ if (linkMessage) {
+ this.template.applyLinkMessage(this, linkMessage);
+ } else if (this.linkMessageElement) {
+ this.linkMessageElement.remove();
+ this.linkMessageElement = null;
+ }
+ }
+
+ startDragging() {
+ this.template.applyStartDragging(this);
+ }
+
+ finishDragging() {
+ this.template.applyFinishDragging(this);
+ }
+}
+
customElements.define(LinkElement.tagName, LinkElement);
-// @ts-check
-
-/**
- * This class manages the ui gesture of mouse click and drag. Tha actual operations are implemented by the subclasses.
- */
-class IMouseClickDrag extends IPointing {
-
- /** @type {(e: MouseEvent) => void} */
- #mouseDownHandler
-
- /** @type {(e: MouseEvent) => void} */
- #mouseStartedMovingHandler
-
- /** @type {(e: MouseEvent) => void} */
- #mouseMoveHandler
-
- /** @type {(e: MouseEvent) => void} */
- #mouseUpHandler
-
- #trackingMouse = false
-
- started = false
-
- 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.consumeClickEvent = options?.consumeClickEvent ?? true;
- 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) {
- if (this.consumeClickEvent) {
- e.stopImmediatePropagation(); // Captured, don't call anyone else
- }
- // Attach the listeners
- movementListenedElement.addEventListener("mousemove", self.#mouseStartedMovingHandler);
- document.addEventListener("mouseup", self.#mouseUpHandler);
- self.clickedPosition = self.locationFromEvent(e);
- self.clicked(self.clickedPosition);
- }
- break
- default:
- if (!self.exitAnyButton) {
- self.#mouseUpHandler(e);
- }
- break
- }
- };
-
- this.#mouseStartedMovingHandler = e => {
- if (this.consumeClickEvent) {
- e.stopImmediatePropagation(); // Captured, don't call anyone else
- }
- // Delegate from now on to self.#mouseMoveHandler
- movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler);
- movementListenedElement.addEventListener("mousemove", self.#mouseMoveHandler);
- // Handler calls e.preventDefault() when it receives the event, this means dispatchEvent returns false
- const dragEvent = self.getEvent(this.blueprint.settings.trackingMouseEventName.begin);
- self.#trackingMouse = this.target.dispatchEvent(dragEvent) == false;
- // Do actual actions
- self.startDrag();
- self.started = true;
- };
-
- this.#mouseMoveHandler = e => {
- if (this.consumeClickEvent) {
- e.stopImmediatePropagation(); // Captured, don't call anyone else
- }
- const location = self.locationFromEvent(e);
- const movement = [e.movementX, e.movementY];
- self.dragTo(location, movement);
- if (self.#trackingMouse) {
- self.blueprint.mousePosition = self.locationFromEvent(e);
- }
- };
-
- this.#mouseUpHandler = e => {
- if (!self.exitAnyButton || e.button == self.clickButton) {
- if (this.consumeClickEvent) {
- e.stopImmediatePropagation(); // Captured, don't call anyone else
- }
- // Remove the handlers of "mousemove" and "mouseup"
- movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler);
- movementListenedElement.removeEventListener("mousemove", self.#mouseMoveHandler);
- document.removeEventListener("mouseup", self.#mouseUpHandler);
- if (self.started) {
- self.endDrag();
- }
- self.unclicked();
- if (self.#trackingMouse) {
- const dragEvent = self.getEvent(this.blueprint.settings.trackingMouseEventName.end);
- this.target.dispatchEvent(dragEvent);
- self.#trackingMouse = false;
- }
- self.started = false;
- }
- };
-
- this.target.addEventListener("mousedown", this.#mouseDownHandler);
- if (this.clickButton == 2) {
- this.target.addEventListener("contextmenu", e => e.preventDefault());
- }
- }
-
- getEvent(eventName) {
- return new CustomEvent(eventName, {
- detail: {
- tracker: this
- },
- bubbles: true,
- cancelable: true
- })
- }
-
- unlistenDOMElement() {
- super.unlistenDOMElement();
- this.target.removeEventListener("mousedown", this.#mouseDownHandler);
- if (this.clickButton == 2) ;
- }
-
- /* Subclasses will override the following methods */
- clicked(location) {
- }
-
- startDrag(location) {
- }
-
- dragTo(location, movement) {
- }
-
- endDrag() {
- }
-
- unclicked(location) {
- }
+// @ts-check
+
+/**
+ * This class manages the ui gesture of mouse click and drag. Tha actual operations are implemented by the subclasses.
+ */
+class IMouseClickDrag extends IPointing {
+
+ /** @type {(e: MouseEvent) => void} */
+ #mouseDownHandler
+
+ /** @type {(e: MouseEvent) => void} */
+ #mouseStartedMovingHandler
+
+ /** @type {(e: MouseEvent) => void} */
+ #mouseMoveHandler
+
+ /** @type {(e: MouseEvent) => void} */
+ #mouseUpHandler
+
+ #trackingMouse = false
+
+ started = false
+
+ 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.consumeClickEvent = options?.consumeClickEvent ?? true;
+ 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) {
+ if (this.consumeClickEvent) {
+ e.stopImmediatePropagation(); // Captured, don't call anyone else
+ }
+ // Attach the listeners
+ movementListenedElement.addEventListener("mousemove", self.#mouseStartedMovingHandler);
+ document.addEventListener("mouseup", self.#mouseUpHandler);
+ self.clickedPosition = self.locationFromEvent(e);
+ self.clicked(self.clickedPosition);
+ }
+ break
+ default:
+ if (!self.exitAnyButton) {
+ self.#mouseUpHandler(e);
+ }
+ break
+ }
+ };
+
+ this.#mouseStartedMovingHandler = e => {
+ if (this.consumeClickEvent) {
+ e.stopImmediatePropagation(); // Captured, don't call anyone else
+ }
+ // Delegate from now on to self.#mouseMoveHandler
+ movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler);
+ movementListenedElement.addEventListener("mousemove", self.#mouseMoveHandler);
+ // Handler calls e.preventDefault() when it receives the event, this means dispatchEvent returns false
+ const dragEvent = self.getEvent(this.blueprint.settings.trackingMouseEventName.begin);
+ self.#trackingMouse = this.target.dispatchEvent(dragEvent) == false;
+ // Do actual actions
+ self.startDrag();
+ self.started = true;
+ };
+
+ this.#mouseMoveHandler = e => {
+ if (this.consumeClickEvent) {
+ e.stopImmediatePropagation(); // Captured, don't call anyone else
+ }
+ const location = self.locationFromEvent(e);
+ const movement = [e.movementX, e.movementY];
+ self.dragTo(location, movement);
+ if (self.#trackingMouse) {
+ self.blueprint.mousePosition = self.locationFromEvent(e);
+ }
+ };
+
+ this.#mouseUpHandler = e => {
+ if (!self.exitAnyButton || e.button == self.clickButton) {
+ if (this.consumeClickEvent) {
+ e.stopImmediatePropagation(); // Captured, don't call anyone else
+ }
+ // Remove the handlers of "mousemove" and "mouseup"
+ movementListenedElement.removeEventListener("mousemove", self.#mouseStartedMovingHandler);
+ movementListenedElement.removeEventListener("mousemove", self.#mouseMoveHandler);
+ document.removeEventListener("mouseup", self.#mouseUpHandler);
+ if (self.started) {
+ self.endDrag();
+ }
+ self.unclicked();
+ if (self.#trackingMouse) {
+ const dragEvent = self.getEvent(this.blueprint.settings.trackingMouseEventName.end);
+ this.target.dispatchEvent(dragEvent);
+ self.#trackingMouse = false;
+ }
+ self.started = false;
+ }
+ };
+
+ this.target.addEventListener("mousedown", this.#mouseDownHandler);
+ if (this.clickButton == 2) {
+ this.target.addEventListener("contextmenu", e => e.preventDefault());
+ }
+ }
+
+ getEvent(eventName) {
+ return new CustomEvent(eventName, {
+ detail: {
+ tracker: this
+ },
+ bubbles: true,
+ cancelable: true
+ })
+ }
+
+ unlistenDOMElement() {
+ super.unlistenDOMElement();
+ this.target.removeEventListener("mousedown", this.#mouseDownHandler);
+ if (this.clickButton == 2) ;
+ }
+
+ /* Subclasses will override the following methods */
+ clicked(location) {
+ }
+
+ startDrag(location) {
+ }
+
+ dragTo(location, movement) {
+ }
+
+ endDrag() {
+ }
+
+ unclicked(location) {
+ }
}
// @ts-check
@@ -2818,193 +2820,193 @@ class MouseMoveNodes extends IMouseClickDrag {
}
}
-// @ts-check
-
-/**
- * @typedef {import("../template/SelectableDraggableTemplate").default} SelectableDraggableTemplate
- * @typedef {import("../entity/IntegerEntity").default} IntegerEntity
- */
-class ISelectableDraggableElement extends IElement {
-
- constructor(...args) {
- super(...args);
- this.dragObject = null;
- this.location = [0, 0];
- this.selected = false;
- /** @type {SelectableDraggableTemplate} */
- this.template;
-
- let self = this;
- this.dragHandler = (e) => {
- self.addLocation(e.detail.value);
- };
- }
-
- createInputObjects() {
- return [
- new MouseMoveNodes(this, this.blueprint, {
- looseTarget: true
- }),
- ]
- }
-
- /**
- * @param {Number[]} value
- */
- setLocation(value = [0, 0]) {
- const d = [value[0] - this.location[0], value[1] - this.location[1]];
- this.location = value;
- this.template.applyLocation(this);
- if (this.blueprint) {
- const dragLocalEvent = new CustomEvent(this.blueprint.settings.nodeDragLocalEventName, {
- detail: {
- value: d
- },
- bubbles: false,
- cancelable: true
- });
- this.dispatchEvent(dragLocalEvent);
- }
- }
-
- addLocation(value) {
- this.setLocation([this.location[0] + value[0], this.location[1] + value[1]]);
- }
-
- setSelected(value = true) {
- if (this.selected == value) {
- return
- }
- this.selected = value;
- if (this.selected) {
- this.blueprint.addEventListener(this.blueprint.settings.nodeDragEventName, this.dragHandler);
- } else {
- this.blueprint.removeEventListener(this.blueprint.settings.nodeDragEventName, this.dragHandler);
- }
- this.template.applySelected(this);
- }
-
- dispatchDragEvent(value) {
- if (!this.selected) {
- this.blueprint.unselectAll();
- this.setSelected(true);
- }
- const dragEvent = new CustomEvent(this.blueprint.settings.nodeDragEventName, {
- detail: {
- value: value
- },
- bubbles: true,
- cancelable: true
- });
- this.dispatchEvent(dragEvent);
- }
-
- snapToGrid() {
- let snappedLocation = this.blueprint.snapToGrid(this.location);
- if (this.location[0] != snappedLocation[0] || this.location[1] != snappedLocation[1]) {
- this.setLocation(snappedLocation);
- }
- }
+// @ts-check
+
+/**
+ * @typedef {import("../template/SelectableDraggableTemplate").default} SelectableDraggableTemplate
+ * @typedef {import("../entity/IntegerEntity").default} IntegerEntity
+ */
+class ISelectableDraggableElement extends IElement {
+
+ constructor(...args) {
+ super(...args);
+ this.dragObject = null;
+ this.location = [0, 0];
+ this.selected = false;
+ /** @type {SelectableDraggableTemplate} */
+ this.template;
+
+ let self = this;
+ this.dragHandler = (e) => {
+ self.addLocation(e.detail.value);
+ };
+ }
+
+ createInputObjects() {
+ return [
+ new MouseMoveNodes(this, this.blueprint, {
+ looseTarget: true
+ }),
+ ]
+ }
+
+ /**
+ * @param {Number[]} value
+ */
+ setLocation(value = [0, 0]) {
+ const d = [value[0] - this.location[0], value[1] - this.location[1]];
+ this.location = value;
+ this.template.applyLocation(this);
+ if (this.blueprint) {
+ const dragLocalEvent = new CustomEvent(this.blueprint.settings.nodeDragLocalEventName, {
+ detail: {
+ value: d
+ },
+ bubbles: false,
+ cancelable: true
+ });
+ this.dispatchEvent(dragLocalEvent);
+ }
+ }
+
+ addLocation(value) {
+ this.setLocation([this.location[0] + value[0], this.location[1] + value[1]]);
+ }
+
+ setSelected(value = true) {
+ if (this.selected == value) {
+ return
+ }
+ this.selected = value;
+ if (this.selected) {
+ this.blueprint.addEventListener(this.blueprint.settings.nodeDragEventName, this.dragHandler);
+ } else {
+ this.blueprint.removeEventListener(this.blueprint.settings.nodeDragEventName, this.dragHandler);
+ }
+ this.template.applySelected(this);
+ }
+
+ dispatchDragEvent(value) {
+ if (!this.selected) {
+ this.blueprint.unselectAll();
+ this.setSelected(true);
+ }
+ const dragEvent = new CustomEvent(this.blueprint.settings.nodeDragEventName, {
+ detail: {
+ value: value
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ this.dispatchEvent(dragEvent);
+ }
+
+ snapToGrid() {
+ let snappedLocation = this.blueprint.snapToGrid(this.location);
+ if (this.location[0] != snappedLocation[0] || this.location[1] != snappedLocation[1]) {
+ this.setLocation(snappedLocation);
+ }
+ }
}
-// @ts-check
-
-/**
- * @typedef {import("../element/LinkMessageElement").default} LinkMessageElement
- */
-class LinkMessageTemplate extends ITemplate {
-
- /**
- * @param {LinkMessageElement} linkMessage
- */
- render(linkMessage) {
- return html`
-
-
- `
- }
-
- /**
- * Applies the style to the element.
- * @param {LinkMessageElement} linkMessage
- */
- apply(linkMessage) {
- super.apply(linkMessage);
- const linkMessageSetup = _ => linkMessage.querySelector(".ueb-link-message").innerText = linkMessage.message(
- linkMessage.linkElement.getSourcePin(),
- linkMessage.linkElement.getDestinationPin()
- );
- linkMessage.linkElement = linkMessage.closest(LinkElement.tagName);
- if (linkMessage.linkElement) {
- linkMessageSetup();
- } else {
- window.customElements.whenDefined(linkMessage.constructor.tagName).then(linkMessage);
- }
- }
-
+// @ts-check
+
+/**
+ * @typedef {import("../element/LinkMessageElement").default} LinkMessageElement
+ */
+class LinkMessageTemplate extends ITemplate {
+
+ /**
+ * @param {LinkMessageElement} linkMessage
+ */
+ render(linkMessage) {
+ return html`
+
+
+ `
+ }
+
+ /**
+ * Applies the style to the element.
+ * @param {LinkMessageElement} linkMessage
+ */
+ apply(linkMessage) {
+ super.apply(linkMessage);
+ const linkMessageSetup = _ => linkMessage.querySelector(".ueb-link-message").innerText = linkMessage.message(
+ linkMessage.linkElement.getSourcePin(),
+ linkMessage.linkElement.getDestinationPin()
+ );
+ linkMessage.linkElement = linkMessage.closest(LinkElement.tagName);
+ if (linkMessage.linkElement) {
+ linkMessageSetup();
+ } else {
+ window.customElements.whenDefined(linkMessage.constructor.tagName).then(linkMessage);
+ }
+ }
+
+}
+
+// @ts-check
+
+/**
+ * @typedef {import("./PinElement").default} PinElement
+ * @typedef {import("./LinkElement").default} LinkElement
+ * @typedef {(sourcePin: PinElement, destinationPin: PinElement) => String} LinkRetrieval
+ */
+class LinkMessageElement extends IElement {
+
+ static tagName = "ueb-link-message"
+ static convertType = _ => new LinkMessageElement(
+ "ueb-icon-conver-type",
+ /** @type {LinkRetrieval} */
+ (s, d) => `Convert ${s.getType()} to ${d.getType()}.`
+ )
+ static correct = _ => new LinkMessageElement(
+ "ueb-icon-correct",
+ /** @type {LinkRetrieval} */
+ (s, d) => ""
+ )
+ static directionsIncompatible = _ => new LinkMessageElement(
+ "ueb-icon-directions-incompatible",
+ /** @type {LinkRetrieval} */
+ (s, d) => "Directions are not compatbile."
+ )
+ static placeNode = _ => new LinkMessageElement(
+ "ueb-icon-place-node",
+ /** @type {LinkRetrieval} */
+ (s, d) => "Place a new node."
+ )
+ static replaceLink = _ => new LinkMessageElement(
+ "ueb-icon-replace-link",
+ /** @type {LinkRetrieval} */
+ (s, d) => "Replace existing input connections."
+ )
+ static sameNode = _ => new LinkMessageElement(
+ "ueb-icon-same-node",
+ /** @type {LinkRetrieval} */
+ (s, d) => "Both are on the same node."
+ )
+ static typesIncompatible = _ => new LinkMessageElement(
+ "ueb-icon-types-incompatible",
+ /** @type {LinkRetrieval} */
+ (s, d) => `${s.getType()} is not compatible with ${d.getType()}.`
+ )
+
+ /** @type {String} */
+ icon
+ /** @type {String} */
+ message
+ /** @type {LinkElement} */
+ linkElement
+
+ constructor(icon, message) {
+ super({}, new LinkMessageTemplate());
+ this.icon = icon;
+ this.message = message;
+ }
+
}
-// @ts-check
-
-/**
- * @typedef {import("./PinElement").default} PinElement
- * @typedef {import("./LinkElement").default} LinkElement
- * @typedef {(sourcePin: PinElement, destinationPin: PinElement) => String} LinkRetrieval
- */
-class LinkMessageElement extends IElement {
-
- static tagName = "ueb-link-message"
- static convertType = _ => new LinkMessageElement(
- "ueb-icon-conver-type",
- /** @type {LinkRetrieval} */
- (s, d) => `Convert ${s.getType()} to ${d.getType()}.`
- )
- static correct = _ => new LinkMessageElement(
- "ueb-icon-correct",
- /** @type {LinkRetrieval} */
- (s, d) => ""
- )
- static directionsIncompatible = _ => new LinkMessageElement(
- "ueb-icon-directions-incompatible",
- /** @type {LinkRetrieval} */
- (s, d) => "Directions are not compatbile."
- )
- static placeNode = _ => new LinkMessageElement(
- "ueb-icon-place-node",
- /** @type {LinkRetrieval} */
- (s, d) => "Place a new node."
- )
- static replaceLink = _ => new LinkMessageElement(
- "ueb-icon-replace-link",
- /** @type {LinkRetrieval} */
- (s, d) => "Replace existing input connections."
- )
- static sameNode = _ => new LinkMessageElement(
- "ueb-icon-same-node",
- /** @type {LinkRetrieval} */
- (s, d) => "Both are on the same node."
- )
- static typesIncompatible = _ => new LinkMessageElement(
- "ueb-icon-types-incompatible",
- /** @type {LinkRetrieval} */
- (s, d) => `${s.getType()} is not compatible with ${d.getType()}.`
- )
-
- /** @type {String} */
- icon
- /** @type {String} */
- message
- /** @type {LinkElement} */
- linkElement
-
- constructor(icon, message) {
- super({}, new LinkMessageTemplate());
- this.icon = icon;
- this.message = message;
- }
-
-}
-
customElements.define(LinkMessageElement.tagName, LinkMessageElement);
// @ts-check
@@ -3206,185 +3208,185 @@ class PinTemplate extends ITemplate {
}
}
-// @ts-check
-
-/**
- * @typedef {import("../element/PinElement").default} PinElement
- */
-class ExecPinTemplate extends PinTemplate {
-
- /**
- * @param {PinElement} pin
- */
- renderIcon(pin) {
- return html`
-
- `
- }
+// @ts-check
+
+/**
+ * @typedef {import("../element/PinElement").default} PinElement
+ */
+class ExecPinTemplate extends PinTemplate {
+
+ /**
+ * @param {PinElement} pin
+ */
+ renderIcon(pin) {
+ return html`
+
+ `
+ }
}
-// @ts-check
-
-/**
- * @typedef {import("../element/PinElement").default} PinElement
- */
-class StringPinTemplate extends PinTemplate {
-
- /**
- * @param {PinElement} pin
- */
- renderInput(pin) {
- const stopEventPropagation = "e => stopPropagation()";
- return html`
-
-
-
- `
- }
+// @ts-check
+
+/**
+ * @typedef {import("../element/PinElement").default} PinElement
+ */
+class StringPinTemplate extends PinTemplate {
+
+ /**
+ * @param {PinElement} pin
+ */
+ renderInput(pin) {
+ const stopEventPropagation = "e => stopPropagation()";
+ return html`
+
+
+
+ `
+ }
+}
+
+// @ts-check
+
+/**
+ * @typedef {import("../entity/GuidEntity").default} GuidEntity
+ * @typedef {import("../entity/PinEntity").default} PinEntity
+ * @typedef {import("./NodeElement").default} NodeElement
+ */
+class PinElement extends IElement {
+
+ static tagName = "ueb-pin"
+
+ static #typeTemplateMap = {
+ "exec": ExecPinTemplate,
+ "string": StringPinTemplate,
+ }
+
+ /** @type {NodeElement} */
+ nodeElement
+
+ /** @type {HTMLElement} */
+ clickableElement
+
+ /** @type {String} */
+ #color
+
+ constructor(entity) {
+ super(
+ entity,
+ new (PinElement.#typeTemplateMap[entity.getType()] ?? PinTemplate)()
+ );
+
+ /** @type {PinEntity} */
+ this.entity;
+
+ /** @type {PinTemplate} */
+ this.template;
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this.#color = window.getComputedStyle(this).getPropertyValue("--ueb-pin-color");
+ }
+
+ createInputObjects() {
+ return [
+ new MouseCreateLink(this.clickableElement, this.blueprint, {
+ moveEverywhere: true,
+ looseTarget: true
+ }),
+ ]
+ }
+
+ /** @return {GuidEntity} */
+ GetPinId() {
+ return this.entity.PinId
+ }
+
+ /** @return {String} */
+ GetPinIdValue() {
+ return this.GetPinId().value
+ }
+
+ /**
+ * @returns {String}
+ */
+ getPinName() {
+ return this.entity.PinName
+ }
+
+ /**
+ * @returns {String}
+ */
+ getPinDisplayName() {
+ return this.entity.PinName
+ }
+
+ isInput() {
+ return this.entity.isInput()
+ }
+
+ isOutput() {
+ return this.entity.isOutput()
+ }
+
+ isConnected() {
+ return this.entity.isConnected()
+ }
+
+ getType() {
+ return this.entity.getType()
+ }
+
+ getClickableElement() {
+ return this.clickableElement
+ }
+
+ getColor() {
+ return this.#color
+ }
+
+ /**
+ * Returns The exact location where the link originates from or arrives at.
+ * @returns {Number[]} The location array
+ */
+ getLinkLocation() {
+ return this.template.getLinkLocation(this)
+ }
+
+ /**
+ * @returns {NodeElement}
+ */
+ getNodeElement() {
+ return this.closest("ueb-node")
+ }
+
+ getLinks() {
+ return this.entity.LinkedTo?.map(pinReference =>
+ pinReference
+ ) ?? []
+ }
+
+ /**
+ * @param {PinElement} targetPinElement
+ */
+ linkTo(targetPinElement) {
+ this.entity.linkTo(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity);
+ this.template.applyConnected(this);
+ }
+
+ /**
+ * @param {PinElement} targetPinElement
+ */
+ unlinkFrom(targetPinElement) {
+ this.entity.unlinkFrom(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity);
+ this.template.applyConnected(this);
+ }
}
-// @ts-check
-
-/**
- * @typedef {import("../entity/GuidEntity").default} GuidEntity
- * @typedef {import("../entity/PinEntity").default} PinEntity
- * @typedef {import("./NodeElement").default} NodeElement
- */
-class PinElement extends IElement {
-
- static tagName = "ueb-pin"
-
- static #typeTemplateMap = {
- "exec": ExecPinTemplate,
- "string": StringPinTemplate,
- }
-
- /** @type {NodeElement} */
- nodeElement
-
- /** @type {HTMLElement} */
- clickableElement
-
- /** @type {String} */
- #color
-
- constructor(entity) {
- super(
- entity,
- new (PinElement.#typeTemplateMap[entity.getType()] ?? PinTemplate)()
- );
-
- /** @type {PinEntity} */
- this.entity;
-
- /** @type {PinTemplate} */
- this.template;
- }
-
- connectedCallback() {
- super.connectedCallback();
- this.#color = window.getComputedStyle(this).getPropertyValue("--ueb-pin-color");
- }
-
- createInputObjects() {
- return [
- new MouseCreateLink(this.clickableElement, this.blueprint, {
- moveEverywhere: true,
- looseTarget: true
- }),
- ]
- }
-
- /** @return {GuidEntity} */
- GetPinId() {
- return this.entity.PinId
- }
-
- /** @return {String} */
- GetPinIdValue() {
- return this.GetPinId().value
- }
-
- /**
- * @returns {String}
- */
- getPinName() {
- return this.entity.PinName
- }
-
- /**
- * @returns {String}
- */
- getPinDisplayName() {
- return this.entity.PinName
- }
-
- isInput() {
- return this.entity.isInput()
- }
-
- isOutput() {
- return this.entity.isOutput()
- }
-
- isConnected() {
- return this.entity.isConnected()
- }
-
- getType() {
- return this.entity.getType()
- }
-
- getClickableElement() {
- return this.clickableElement
- }
-
- getColor() {
- return this.#color
- }
-
- /**
- * Returns The exact location where the link originates from or arrives at.
- * @returns {Number[]} The location array
- */
- getLinkLocation() {
- return this.template.getLinkLocation(this)
- }
-
- /**
- * @returns {NodeElement}
- */
- getNodeElement() {
- return this.closest("ueb-node")
- }
-
- getLinks() {
- return this.entity.LinkedTo?.map(pinReference =>
- pinReference
- ) ?? []
- }
-
- /**
- * @param {PinElement} targetPinElement
- */
- linkTo(targetPinElement) {
- this.entity.linkTo(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity);
- this.template.applyConnected(this);
- }
-
- /**
- * @param {PinElement} targetPinElement
- */
- unlinkFrom(targetPinElement) {
- this.entity.unlinkFrom(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity);
- this.template.applyConnected(this);
- }
-}
-
customElements.define(PinElement.tagName, PinElement);
// @ts-check
@@ -3483,73 +3485,73 @@ class NodeTemplate extends SelectableDraggableTemplate {
}
}
-// @ts-check
-
-class NodeElement extends ISelectableDraggableElement {
-
- static tagName = "ueb-node"
-
- /**
- * @param {ObjectEntity} entity
- */
- constructor(entity) {
- super(entity, new NodeTemplate());
- /** @type {ObjectEntity} */
- this.entity;
- /** @type {NodeTemplate} */
- this.template;
- this.dragLinkObjects = [];
- super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value]);
- }
-
- static fromSerializedObject(str) {
- let entity = SerializerFactory.getSerializer(ObjectEntity).read(str);
- return new NodeElement(entity)
- }
-
- disconnectedCallback() {
- super.disconnectedCallback();
- this.dispatchDeleteEvent();
- }
-
- getNodeName() {
- return this.entity.getName()
- }
-
- getPinElements() {
- return this.template.getPinElements(this)
- }
-
- /**
- * @returns {PinEntity[]}
- */
- getPinEntities() {
- return this.entity.CustomProperties.filter(v => v instanceof PinEntity)
- }
-
- connectedCallback() {
- this.getAttribute("type")?.trim();
- super.connectedCallback();
- }
-
- setLocation(value = [0, 0]) {
- let nodeType = this.entity.NodePosX.constructor;
- // @ts-expect-error
- this.entity.NodePosX = new nodeType(value[0]);
- // @ts-expect-error
- this.entity.NodePosY = new nodeType(value[1]);
- super.setLocation(value);
- }
-
- dispatchDeleteEvent(value) {
- let deleteEvent = new CustomEvent(this.blueprint.settings.nodeDeleteEventName, {
- bubbles: true,
- cancelable: true,
- });
- this.dispatchEvent(deleteEvent);
- }
-}
-
+// @ts-check
+
+class NodeElement extends ISelectableDraggableElement {
+
+ static tagName = "ueb-node"
+
+ /**
+ * @param {ObjectEntity} entity
+ */
+ constructor(entity) {
+ super(entity, new NodeTemplate());
+ /** @type {ObjectEntity} */
+ this.entity;
+ /** @type {NodeTemplate} */
+ this.template;
+ this.dragLinkObjects = [];
+ super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value]);
+ }
+
+ static fromSerializedObject(str) {
+ let entity = SerializerFactory.getSerializer(ObjectEntity).read(str);
+ return new NodeElement(entity)
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ this.dispatchDeleteEvent();
+ }
+
+ getNodeName() {
+ return this.entity.getName()
+ }
+
+ getPinElements() {
+ return this.template.getPinElements(this)
+ }
+
+ /**
+ * @returns {PinEntity[]}
+ */
+ getPinEntities() {
+ return this.entity.CustomProperties.filter(v => v instanceof PinEntity)
+ }
+
+ connectedCallback() {
+ this.getAttribute("type")?.trim();
+ super.connectedCallback();
+ }
+
+ setLocation(value = [0, 0]) {
+ let nodeType = this.entity.NodePosX.constructor;
+ // @ts-expect-error
+ this.entity.NodePosX = new nodeType(value[0]);
+ // @ts-expect-error
+ this.entity.NodePosY = new nodeType(value[1]);
+ super.setLocation(value);
+ }
+
+ dispatchDeleteEvent(value) {
+ let deleteEvent = new CustomEvent(this.blueprint.settings.nodeDeleteEventName, {
+ bubbles: true,
+ cancelable: true,
+ });
+ this.dispatchEvent(deleteEvent);
+ }
+}
+
customElements.define(NodeElement.tagName, NodeElement);
// @ts-check
diff --git a/js/element/LinkElement.js b/js/element/LinkElement.js
index 680c208..0e2c28a 100644
--- a/js/element/LinkElement.js
+++ b/js/element/LinkElement.js
@@ -137,9 +137,10 @@ export default class LinkElement extends IElement {
*/
setSourcePin(pin) {
if (this.#source) {
+ const settings = this.#source.blueprint.settings
const nodeElement = this.#source.getNodeElement()
- nodeElement.removeEventListener(this.blueprint.settings.nodeDeleteEventName, this.#nodeDeleteHandler)
- nodeElement.removeEventListener(this.blueprint.settings.nodeDragLocalEventName, this.#nodeDragSourceHandler)
+ nodeElement.removeEventListener(settings.nodeDeleteEventName, this.#nodeDeleteHandler)
+ nodeElement.removeEventListener(settings.nodeDragLocalEventName, this.#nodeDragSourceHandler)
if (this.#destination) {
this.#unlinkPins()
}
@@ -147,9 +148,10 @@ export default class LinkElement extends IElement {
this.#source = pin
if (this.#source) {
const nodeElement = this.#source.getNodeElement()
+ const settings = this.#source.blueprint.settings
this.originatesFromInput = pin.isInput()
- nodeElement.addEventListener(this.blueprint.settings.nodeDeleteEventName, this.#nodeDeleteHandler)
- nodeElement.addEventListener(this.blueprint.settings.nodeDragLocalEventName, this.#nodeDragSourceHandler)
+ nodeElement.addEventListener(settings.nodeDeleteEventName, this.#nodeDeleteHandler)
+ nodeElement.addEventListener(settings.nodeDragLocalEventName, this.#nodeDragSourceHandler)
this.setSourceLocation()
if (this.#destination) {
this.#linkPins()
diff --git a/package.json b/package.json
index c91e39c..81c19b2 100755
--- a/package.json
+++ b/package.json
@@ -34,4 +34,4 @@
"dependencies": {
"parsimmon": "^1.18.0"
}
-}
\ No newline at end of file
+}