From 8ef5f3dab4538cebbd41d1ddb04599e9b04b4798 Mon Sep 17 00:00:00 2001 From: barsdeveloper Date: Sun, 10 Oct 2021 13:52:13 +0200 Subject: [PATCH] Added template concept --- js/GraphEntity.js | 13 +- js/SelectableDraggable.js | 4 +- js/UEBlueprint.js | 55 ++----- js/UEBlueprintObject.js | 76 +-------- js/template/BlueprintTemplate.js | 48 ++++++ js/template/NodeTemplate.js | 64 ++++++++ js/template/Template.js | 22 +++ ueblueprint.js | 270 ++++++++++++++++++------------- 8 files changed, 320 insertions(+), 232 deletions(-) create mode 100644 js/template/BlueprintTemplate.js create mode 100644 js/template/NodeTemplate.js create mode 100644 js/template/Template.js diff --git a/js/GraphEntity.js b/js/GraphEntity.js index 77c1907..c06f02f 100644 --- a/js/GraphEntity.js +++ b/js/GraphEntity.js @@ -2,21 +2,24 @@ * A Graph Entity is an element that can stay directly (as a first child) on the blueprint grid. Those entities are either nodes or links */ export default class GraphEntity extends HTMLElement { - constructor() { + /** + * + * @param {import("./template/Template").default} template The template to render this node + */ + constructor(template) { super() /** @type {import("./UEBlueprint").EBlueprint}" */ this.blueprint = null + this.template = template } connectedCallback() { this.blueprint = this.closest('u-blueprint') - let aDiv = document.createElement('div') - aDiv.innerHTML = this.render() - this.appendChild(aDiv.firstElementChild) + this.append(...this.template.getElements(this)) } // Subclasses want to rewrite this render() { - return "" + return '' } } \ No newline at end of file diff --git a/js/SelectableDraggable.js b/js/SelectableDraggable.js index b4872c2..7e67203 100644 --- a/js/SelectableDraggable.js +++ b/js/SelectableDraggable.js @@ -3,8 +3,8 @@ import GraphEntity from "./GraphEntity" export default class SelectableDraggable extends GraphEntity { - constructor() { - super() + constructor(template) { + super(template) this.dragObject = null this.location = [0, 0] this.selected = false diff --git a/js/UEBlueprint.js b/js/UEBlueprint.js index bb30ab3..120dca3 100644 --- a/js/UEBlueprint.js +++ b/js/UEBlueprint.js @@ -4,51 +4,20 @@ import Select from "./input/Select" import Zoom from "./input/Zoom" import FastSelectionModel from "./selection/FastSelectionModel" import SimpleSelectionModel from "./selection/SimpleSelectionModel" +import GraphEntity from "./GraphEntity" +import BlueprintTemplate from "./template/BlueprintTemplate" /** * @typedef {import("./UEBlueprintObject").default} UEBlueprintObject */ -export default class UEBlueprint extends HTMLElement { - - headerTemplate() { - return ` -
-
1:1
-
- ` - } - - overlayTemplate() { - return ` -
- ` - } - - viewportTemplate() { - return ` -
-
-
-
-
-
-
- ` - } - - static getElement(template) { - let div = document.createElement('div') - div.innerHTML = template - return div.firstElementChild - } +export default class UEBlueprint extends GraphEntity { insertChildren() { this.querySelector('[data-nodes]').append(...this.nodes) } constructor() { - super() + super(new BlueprintTemplate()) /** @type {UEBlueprintObject[]}" */ this.nodes = new Array() this.expandGridSize = 400 @@ -95,17 +64,21 @@ export default class UEBlueprint extends HTMLElement { } connectedCallback() { + super.connectedCallback() this.classList.add('ueb', `ueb-zoom-${this.zoom}`) - this.headerElement = this.constructor.getElement(this.headerTemplate()) - this.appendChild(this.headerElement) - this.overlayElement = this.constructor.getElement(this.overlayTemplate()) - this.appendChild(this.overlayElement) - this.viewportElement = this.constructor.getElement(this.viewportTemplate()) - this.appendChild(this.viewportElement) + this.headerElement = this.querySelector('.ueb-node-header') + console.assert(this.headerElement, "Header element not provided by the template.") + this.overlayElement = this.querySelector('.ueb-viewport-overlay') + console.assert(this.overlayElement, "Overlay element not provided by the template.") + this.viewportElement = this.querySelector('.ueb-viewport-body') + console.assert(this.viewportElement, "Viewport element not provided by the template.") this.gridElement = this.viewportElement.querySelector('.ueb-grid') + console.assert(this.gridElement, "Grid element not provided by the template.") this.selectorElement = this.viewportElement.querySelector('.ueb-selector') + console.assert(this.selectorElement, "Selector element not provided by the template.") this.nodesContainerElement = this.querySelector('[data-nodes]') + console.assert(this.nodesContainerElement, "Nodes container element not provided by the template.") this.insertChildren() this.dragObject = new DragScroll(this.getGridDOMElement(), this, { diff --git a/js/UEBlueprintObject.js b/js/UEBlueprintObject.js index f1908d0..9f2b350 100644 --- a/js/UEBlueprintObject.js +++ b/js/UEBlueprintObject.js @@ -1,79 +1,13 @@ import SelectableDraggable from "./SelectableDraggable" +import NodeTemplate from "./template/NodeTemplate" export default class UEBlueprintObject extends SelectableDraggable { - static classInputs = [/* - { - name: "Input Example", - type: 'integer' - } - */] - static classOutputs = [/* - { - name: "Return Value", - type: 'string' - }*/ - ] - static classInFlow = false - static classOutFlow = false - static className = 'Empty node' - - header() { - return ` -
- - - ${this.constructor.className} - -
- ` - } - - body() { - return ` -
-
- ${this.constructor.classInputs.forEach((input, index) => ` -
- - ${input.name} -
- `) ?? ''} -
-
- ${this.constructor.classOutputs.forEach((output, index) => ` -
- ${output.name} - -
- `) ?? ''} -
-
- ` - } - - render() { - return ` -
-
- ${this.header()} - ${this.body()} -
-
-` - } constructor() { - super() - this.inputs = this.constructor.classInputs.map(value => { - return { - connected: null - } - }) - this.outputs = this.constructor.classOutputs.map(value => { - return { - connected: null - } - }) + super(new NodeTemplate()) + this.graphNodeName = 'N/A' + this.inputs = [] + this.outputs = [] } connectedCallback() { diff --git a/js/template/BlueprintTemplate.js b/js/template/BlueprintTemplate.js new file mode 100644 index 0000000..2be497a --- /dev/null +++ b/js/template/BlueprintTemplate.js @@ -0,0 +1,48 @@ +import Template from "./Template"; + +export default class BlueprintTemplate extends Template { + header(element) { + return ` +
+
1:1
+
+ ` + } + + overlay() { + return ` +
+ ` + } + + /** + * + * @param {import("../UEBlueprint").default} element + * @returns + */ + viewport(element) { + return ` +
+
+
+
+
+
+
+ ` + } + + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + render(element) { + return ` + ${this.header(element)} + ${this.overlay(element)} + ${this.viewport(element)} + ` + } +} \ No newline at end of file diff --git a/js/template/NodeTemplate.js b/js/template/NodeTemplate.js new file mode 100644 index 0000000..fd325cb --- /dev/null +++ b/js/template/NodeTemplate.js @@ -0,0 +1,64 @@ +import Template from "./Template" + +export default class NodeTemplate extends Template { + + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + header(element) { + return ` +
+ + + ${element.graphNodeName} + +
+ ` + } + + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + body(element) { + return ` +
+
+ ${element.inputs.forEach((input, index) => ` +
+ + ${input.name} +
+ `) ?? ''} +
+
+ ${element.outputs.forEach((output, index) => ` +
+ ${output.name} + +
+ `) ?? ''} +
+
+ ` + } + + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + render(element) { + return ` +
+
+ ${this.header(element)} + ${this.body(element)} +
+
+ ` + } +} \ No newline at end of file diff --git a/js/template/Template.js b/js/template/Template.js new file mode 100644 index 0000000..d5689d3 --- /dev/null +++ b/js/template/Template.js @@ -0,0 +1,22 @@ +export default class Template { + + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + render(element) { + return `` + } + + /** + * Returns the html elements rendered by this template. + * @param {HTMLElement} element Target element + * @returns The rendered elements + */ + getElements(element) { + let aDiv = document.createElement('div') + aDiv.innerHTML = this.render(element) + return aDiv.childNodes + } +} \ No newline at end of file diff --git a/ueblueprint.js b/ueblueprint.js index e89d2c7..6bfa9aa 100644 --- a/ueblueprint.js +++ b/ueblueprint.js @@ -8,12 +8,12 @@ class Utility { } } -class UPointing { +class Pointing { constructor(target, blueprint, options) { /** @type {HTMLElement} */ this.target = target; - /** @type {import("../UEBlueprint").default}" */ + /** @type {import("../UEBlueprint").EBlueprint}" */ this.blueprint = blueprint; this.movementSpace = this.blueprint?.getGridDOMElement() ?? document.documentElement; } @@ -32,7 +32,7 @@ class UPointing { /** * This class manages the ui gesture of mouse click and drag. Tha actual operations are implemented by the subclasses. */ -class UMouseClickDrag extends UPointing { +class MouseClickDrag extends Pointing { constructor(target, blueprint, options) { super(target, blueprint, options); this.clickButton = options?.clickButton ?? 0; @@ -128,7 +128,7 @@ class UMouseClickDrag extends UPointing { } } -class UDragScroll extends UMouseClickDrag { +class DragScroll extends MouseClickDrag { dragTo(location, movement) { this.blueprint.scrollDelta([-movement[0], -movement[1]]); @@ -136,7 +136,7 @@ class UDragScroll extends UMouseClickDrag { } -class USelect extends UMouseClickDrag { +class Select extends MouseClickDrag { constructor(target, blueprint, options) { super(target, blueprint, options); @@ -161,12 +161,12 @@ class USelect extends UMouseClickDrag { } } -class UMouseWheel extends UPointing { +class MouseWheel extends Pointing { /** * * @param {HTMLElement} target - * @param {import("../UEBlueprint").default} blueprint + * @param {import("../UEBlueprint").EBlueprint} blueprint * @param {Object} options */ constructor(target, blueprint, options) { @@ -191,7 +191,7 @@ class UMouseWheel extends UPointing { } } -class UZoom extends UMouseWheel { +class Zoom extends MouseWheel { wheel(variation, location) { let zoomLevel = this.blueprint.getZoom(); zoomLevel -= variation; @@ -517,11 +517,56 @@ class FastSelectionModel { } /** - * @typedef {import("./UEBlueprintObject").default} UEBlueprintObject + * A Graph Entity is an element that can stay directly (as a first child) on the blueprint grid. Those entities are either nodes or links */ -class UEBlueprint extends HTMLElement { +class GraphEntity extends HTMLElement { + /** + * + * @param {import("./template/Template").default} template The template to render this node + */ + constructor(template) { + super(); + /** @type {import("./UEBlueprint").EBlueprint}" */ + this.blueprint = null; + this.template = template; + } - headerTemplate() { + connectedCallback() { + this.blueprint = this.closest('u-blueprint'); + this.append(...this.template.getElements(this)); + } + + // Subclasses want to rewrite this + render() { + return '' + } +} + +class Template { + + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + render(element) { + return `` + } + + /** + * Returns the html elements rendered by this template. + * @param {HTMLElement} element Target element + * @returns The rendered elements + */ + getElements(element) { + let aDiv = document.createElement('div'); + aDiv.innerHTML = this.render(element); + return aDiv.childNodes + } +} + +class BlueprintTemplate extends Template { + header(element) { return `
1:1
@@ -529,17 +574,22 @@ class UEBlueprint extends HTMLElement { ` } - overlayTemplate() { + overlay() { return `
` } - viewportTemplate() { + /** + * + * @param {import("../UEBlueprint").default} element + * @returns + */ + viewport(element) { return `
+ style="--ueb-additional-x:${element.additional[0]}; --ueb-additional-y:${element.additional[1]}; --ueb-translate-x:${element.translateValue[0]}; --ueb-translate-y:${element.translateValue[1]}">
@@ -548,18 +598,31 @@ class UEBlueprint extends HTMLElement { ` } - static getElement(template) { - let div = document.createElement('div'); - div.innerHTML = template; - return div.firstElementChild + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + render(element) { + return ` + ${this.header(element)} + ${this.overlay(element)} + ${this.viewport(element)} + ` } +} + +/** + * @typedef {import("./UEBlueprintObject").default} UEBlueprintObject + */ +class UEBlueprint extends GraphEntity { insertChildren() { this.querySelector('[data-nodes]').append(...this.nodes); } constructor() { - super(); + super(new BlueprintTemplate()); /** @type {UEBlueprintObject[]}" */ this.nodes = new Array(); this.expandGridSize = 400; @@ -605,30 +668,34 @@ class UEBlueprint extends HTMLElement { } connectedCallback() { + super.connectedCallback(); this.classList.add('ueb', `ueb-zoom-${this.zoom}`); - this.headerElement = this.constructor.getElement(this.headerTemplate()); - this.appendChild(this.headerElement); - this.overlayElement = this.constructor.getElement(this.overlayTemplate()); - this.appendChild(this.overlayElement); - this.viewportElement = this.constructor.getElement(this.viewportTemplate()); - this.appendChild(this.viewportElement); + this.headerElement = this.querySelector('.ueb-node-header'); + console.assert(this.headerElement, "Header element not provided by the template."); + this.overlayElement = this.querySelector('.ueb-viewport-overlay'); + console.assert(this.overlayElement, "Overlay element not provided by the template."); + this.viewportElement = this.querySelector('.ueb-viewport-body'); + console.assert(this.viewportElement, "Viewport element not provided by the template."); this.gridElement = this.viewportElement.querySelector('.ueb-grid'); + console.assert(this.gridElement, "Grid element not provided by the template."); this.selectorElement = this.viewportElement.querySelector('.ueb-selector'); + console.assert(this.selectorElement, "Selector element not provided by the template."); this.nodesContainerElement = this.querySelector('[data-nodes]'); + console.assert(this.nodesContainerElement, "Nodes container element not provided by the template."); this.insertChildren(); - this.dragObject = new UDragScroll(this.getGridDOMElement(), this, { + this.dragObject = new DragScroll(this.getGridDOMElement(), this, { clickButton: 2, moveEverywhere: true, exitAnyButton: false }); - this.zoomObject = new UZoom(this.getGridDOMElement(), this, { + this.zoomObject = new Zoom(this.getGridDOMElement(), this, { looseTarget: true }); - this.selectObject = new USelect(this.getGridDOMElement(), this, { + this.selectObject = new Select(this.getGridDOMElement(), this, { clickButton: 0, moveEverywhere: true, exitAnyButton: true @@ -885,7 +952,7 @@ class UEBlueprint extends HTMLElement { customElements.define('u-blueprint', UEBlueprint); -class UDrag extends UMouseClickDrag { +class Drag extends MouseClickDrag { constructor(target, blueprint, options) { super(target, blueprint, options); this.stepSize = parseInt(options?.stepSize); @@ -925,30 +992,10 @@ class UDrag extends UMouseClickDrag { } } -class UGraphEntity extends HTMLElement { - constructor() { - super(); - /** @type {import("./UEBlueprint").default}" */ - this.blueprint = null; - } +class SelectableDraggable extends GraphEntity { - connectedCallback() { - this.blueprint = this.closest('u-blueprint'); - let aDiv = document.createElement('div'); - aDiv.innerHTML = this.render(); - this.appendChild(aDiv.firstElementChild); - } - - // Subclasses want to rewrite this - render() { - return "" - } -} - -class USelectableDraggable extends UGraphEntity { - - constructor() { - super(); + constructor(template) { + super(template); this.dragObject = null; this.location = [0, 0]; this.selected = false; @@ -961,7 +1008,7 @@ class USelectableDraggable extends UGraphEntity { connectedCallback() { super.connectedCallback(); - this.dragObject = new UDrag(this, null, { // UDrag doesn't need blueprint + this.dragObject = new Drag(this, null, { // UDrag doesn't need blueprint looseTarget: true }); } @@ -1013,50 +1060,45 @@ class USelectableDraggable extends UGraphEntity { } -class UEBlueprintObject extends USelectableDraggable { - static classInputs = [/* - { - name: "Input Example", - type: 'integer' - } - */] - static classOutputs = [/* - { - name: "Return Value", - type: 'string' - }*/ - ] - static classInFlow = false - static classOutFlow = false - static className = 'Empty node' +class NodeTemplate extends Template { - header() { + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + header(element) { return `
- ${this.constructor.className} + ${element.graphNodeName}
` } - body() { + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + body(element) { return `
- ${this.constructor.classInputs.forEach((input, index) => ` + ${element.inputs.forEach((input, index) => `
- + ${input.name}
`) ?? ''}
- ${this.constructor.classOutputs.forEach((output, index) => ` + ${element.outputs.forEach((output, index) => `
${output.name} - +
`) ?? ''}
@@ -1064,29 +1106,30 @@ class UEBlueprintObject extends USelectableDraggable { ` } - render() { + /** + * Computes the html content of the target element. + * @param {HTMLElement} element Target element + * @returns The computed html + */ + render(element) { return `
- ${this.header()} - ${this.body()} + ${this.header(element)} + ${this.body(element)}
-` + ` } +} + +class UEBlueprintObject extends SelectableDraggable { constructor() { - super(); - this.inputs = this.constructor.classInputs.map(value => { - return { - connected: null - } - }); - this.outputs = this.constructor.classOutputs.map(value => { - return { - connected: null - } - }); + super(new NodeTemplate()); + this.graphNodeName = 'N/A'; + this.inputs = []; + this.outputs = []; } connectedCallback() { @@ -1102,19 +1145,24 @@ class UEBlueprintObject extends USelectableDraggable { customElements.define('u-object', UEBlueprintObject); -class FGuid { +class Guid { + static generateGuid() { + let result = ""; + let random = new Uint32Array(4); + crypto.getRandomValues(random); + random.forEach(n => { + this.result += ('00000000' + n.toString(16).toUpperCase()).slice(-8); + }); + return result + } + constructor(guid) { if (guid?.constructor?.name === 'String') { this.value = guid; } else if (guid?.constructor?.name === 'FGuid') { this.value = guid.value; } else { - let random = new Uint32Array(4); - crypto.getRandomValues(random); - this.value = ""; - random.forEach(n => { - this.value += ('00000000' + n.toString(16).toUpperCase()).slice(-8); - }); + this.value = Guid.generateGuid(); } } @@ -1123,9 +1171,9 @@ class FGuid { } } -class UGraphPin { +class GraphPin { constructor(Options) { - this.PinId = new FGuid(Options?.PinId); + this.PinId = new Guid(Options?.PinId); this.PinName = Options?.PinName ?? ""; this.PinToolTip = Options?.PinToolTip ?? ""; this.PinType = { @@ -1137,15 +1185,7 @@ class UGraphPin { bIsReference: Options?.PinType?.bIsReference ?? false, bIsConst: Options?.PinType?.bIsConst ?? false, bIsWeakPointer: Options?.PinType?.bIsWeakPointer ?? false, - bIsUObjectWrapper: Options?.PinType?.bIsUObjectWrapper ?? false, - alpha: Object.assign({}, { - ciao: 1, - arrivederci: "2", - beta: { - autunno: "autunno", - inverno: "inverno" - } - }) + bIsUObjectWrapper: Options?.PinType?.bIsUObjectWrapper ?? false }; this.LinkedTo = Options?.LinkedTo ?? null; this.DefaultValue = Options?.DefaultValue ?? true; @@ -1181,19 +1221,23 @@ class UGraphPin { prefix += prefix != "" ? "." : ""; for (const property in object) { if (object[property]?.constructor?.name === 'Object') { - result += UGraphPin.subSerialize(prefix + property, object[property]); + result += GraphPin.subSerialize(prefix + property, object[property]); } else { - result += `${prefix + property}=${UGraphPin.serializeValue(object[property])},`; + result += `${prefix + property}=${GraphPin.serializeValue(object[property])},`; } } return result } serialize() { - let result = `Pin (${this.constructor.subSerialize('', this)})`; + let result = `CustomProperties Pin (${this.constructor.subSerialize('', this)})`; return result } + toString() { + return this.serialize() + } + } -export { UEBlueprint, UEBlueprintObject, UGraphPin }; +export { UEBlueprint, UEBlueprintObject, GraphPin as UGraphPin };