Files
ueblueprint/js/template/node/NodeTemplate.js
BarsDev 6ba2705386 Large refactoring and new nodes
* Fix node reference when changing elements

* Fix ScriptVariables parsing

* Fix invariant text and niagara types

* Niagara convert nodes

* Move node tests to own files

* More Niagara tests

* Niagara float and smaller fixes

* More Decoding

* More decoding

* WIP

* Float is real

* WIP

* More types and colors

* Test case and small polish

* WIP

* WIP

* Fix niagara script variables merging

* Fix Niagara variables

* Fixing mirrored ExportPath

* Fix Export paths name adjustments

* Simplify arc calculation

* Simplify a bit arc calculation

* source / destionation => origin / target

* Minor refactoring

* Fix switched link position

* Rename some properties for uniformity

* Fix input escape

* Simplify test

* About window

* Dialog backdrop style

* About dialog touches

* Remove dependency and minot improvement

* Light mode

* Fix link location and css small improvement

* Link direction and minor fixes

* Some minor fixes and refactoring

* Refactoring WIP

* Shorting repetitive bits

* More tests

* Simplify linking tests
2025-02-07 00:36:03 +02:00

175 lines
6.4 KiB
JavaScript
Executable File

import { html, nothing } from "lit"
import nodeSubtitle from "../../decoding/nodeSubtitle.js"
import ElementFactory from "../../element/ElementFactory.js"
import SVGIcon from "../../SVGIcon.js"
import ISelectableDraggableTemplate from "../ISelectableDraggableTemplate.js"
/** @extends {ISelectableDraggableTemplate<NodeElement>} */
export default class NodeTemplate extends ISelectableDraggableTemplate {
static nodeStyleClasses = ["ueb-node-style-default"]
#subtitle
/** @type {() => PinEntity<IEntity>} */
pinInserter
/** @type {HTMLElement} */
inputContainer
/** @type {HTMLElement} */
outputContainer
/** @type {PinElement} */
pinElement
addPinHandler = () => {
const pin = this.pinInserter?.()
if (pin) {
if (this.defaultPin && this.defaultPin.isInput() === pin.isInput()) {
this.defaultPin.before(this.createPinElement(pin))
} else {
(pin.isInput() ? this.inputContainer : this.outputContainer).appendChild(this.createPinElement(pin))
}
this.element.acknowledgeUpdate()
}
}
toggleAdvancedDisplayHandler = () => {
this.element.toggleShowAdvancedPinDisplay()
this.element.requestUpdate()
this.element.updateComplete.then(() => this.element.acknowledgeUpdate())
}
/** @param {PinEntity<IEntity>} pinEntity */
createPinElement(pinEntity) {
const pinElement = /** @type {PinElementConstructor} */(ElementFactory.getConstructor("ueb-pin"))
.newObject(pinEntity, undefined, this.element)
if (this.pinInserter && !this.defaultPin && pinElement.getPinName() === "Default") {
this.defaultPin = pinElement
this.defaultPin.classList.add("ueb-node-variadic-default")
}
return pinElement
}
/** @param {NodeElement} element */
initialize(element) {
super.initialize(element)
this.#subtitle = nodeSubtitle(element.entity)
this.element.classList.add(.../** @type {typeof NodeTemplate} */(this.constructor).nodeStyleClasses)
this.element.style.setProperty("--ueb-node-color", this.element.entity.nodeColor().cssText)
this.pinInserter = this.element.entity.additionalPinInserter()
if (this.pinInserter) {
this.element.classList.add("ueb-node-is-variadic")
}
}
render() {
return html`
<div class="ueb-node-border">
<div class="ueb-node-wrapper">
<div class="ueb-node-top">${this.renderTop()}</div>
<div class="ueb-node-inputs"></div>
<div class="ueb-node-outputs"></div>
${this.pinInserter ? html`
<div class="ueb-node-variadic" @click="${this.addPinHandler}">
Add pin ${SVGIcon.plusCircle}
</div>
`: nothing}
${this.element.entity.isDevelopmentOnly() ? html`
<div class="ueb-node-developmentonly">
<span class="ueb-node-developmentonly-text">Development Only</span>
</div>
` : nothing}
${this.element.advancedPinDisplay ? html`
<div class="ueb-node-expansion" @click="${this.toggleAdvancedDisplayHandler}">
${SVGIcon.expandIcon}
</div>
` : nothing}
</div>
</div>
`
}
renderNodeIcon() {
return this.element.entity.nodeIcon()
}
renderNodeName() {
return this.element.nodeDisplayName
}
renderTop() {
const icon = this.renderNodeIcon()
const name = this.renderNodeName()
return html`
<div class="ueb-node-name">
${icon ? html`
<div class="ueb-node-name-symbol">${icon}</div>
` : nothing}
${name ? html`
<div class="ueb-node-name-text ueb-ellipsis-nowrap-text">
${name}
${this.#subtitle ? html`
<div class="ueb-node-subtitle-text ueb-ellipsis-nowrap-text">${this.#subtitle}</div>
`: nothing}
</div>
` : nothing}
</div>
`
}
/** @param {PropertyValues} changedProperties */
firstUpdated(changedProperties) {
super.firstUpdated(changedProperties)
this.inputContainer = this.element.querySelector(".ueb-node-inputs")
this.outputContainer = this.element.querySelector(".ueb-node-outputs")
this.setupPins()
this.element.updateComplete.then(() => this.element.acknowledgeUpdate())
}
setupPins() {
this.element.nodeNameElement = /** @type {HTMLElement} */(this.element.querySelector(".ueb-node-name-text"))
let hasInput = false
let hasOutput = false
for (const p of this.getPinElements()) {
if (p === this.defaultPin) {
continue
}
if (p.isInput()) {
this.inputContainer.appendChild(p)
hasInput = true
} else if (p.isOutput()) {
this.outputContainer.appendChild(p)
hasOutput = true
}
}
if (this.defaultPin) {
(this.defaultPin.isInput() ? this.inputContainer : this.outputContainer).appendChild(this.defaultPin)
}
if (hasInput) {
this.element.classList.add("ueb-node-has-inputs")
}
if (hasOutput) {
this.element.classList.add("ueb-node-has-outputs")
}
}
getPinElements() {
return this.element.getPinElements()
}
createPinElements() {
return this.element.getPinEntities()
.filter(v => !v.isHidden())
.map(pinEntity => this.createPinElement(pinEntity))
}
/** All the link connected to this node */
getAllConnectedLinks() {
const nodeTitle = this.element.nodeTitle
const query = `ueb-link[data-origin-node="${nodeTitle}"],ueb-link[data-target-node="${nodeTitle}"]`
return /** @type {LinkElement[]} */([...this.blueprint.querySelectorAll(query)])
}
}