Dropdown implementation, switch refactoring

* Various fixes

* Fix tests

* Dropdown names deduced from pin names

* Remove update callbacks

* Fix double pins issue

* return undefined if not switch
This commit is contained in:
barsdeveloper
2023-04-22 12:44:37 +02:00
committed by GitHub
parent e06589bc46
commit 8a96af670e
32 changed files with 1024 additions and 365 deletions

View File

@@ -30,7 +30,7 @@ export default class Configuration {
begin: "ueb-edit-text-begin",
end: "ueb-edit-text-end",
}
static enableZoomIn = ["LeftControl", "RightControl"] // Button to enable more than 0 (1:1) zoom
static enableZoomIn = ["LeftControl", "RightControl"] // Button to enable more than 1:1 zoom
static expandGridSize = 400
static focusEventName = {
begin: "blueprint-focus",
@@ -112,6 +112,7 @@ export default class Configuration {
inputVectorAxisEvent: "/Script/BlueprintGraph.K2Node_InputVectorAxisEvent",
isValid: "/Engine/EditorBlueprintResources/StandardMacros.StandardMacros:IsValid",
knot: "/Script/BlueprintGraph.K2Node_Knot",
linearColor: "/Script/CoreUObject.LinearColor",
macro: "/Script/BlueprintGraph.K2Node_MacroInstance",
makeArray: "/Script/BlueprintGraph.K2Node_MakeArray",
makeMap: "/Script/BlueprintGraph.K2Node_MakeMap",
@@ -120,12 +121,18 @@ export default class Configuration {
pawn: "/Script/Engine.Pawn",
promotableOperator: "/Script/BlueprintGraph.K2Node_PromotableOperator",
reverseForEachLoop: "/Engine/EditorBlueprintResources/StandardMacros.StandardMacros:ReverseForEachLoop",
rotator: "/Script/CoreUObject.Rotator",
select: "/Script/BlueprintGraph.K2Node_Select",
spawnActorFromClass: "/Script/BlueprintGraph.K2Node_SpawnActorFromClass",
switchEnum: "/Script/BlueprintGraph.K2Node_SwitchEnum",
switchInteger: "/Script/BlueprintGraph.K2Node_SwitchInteger",
switchName: "/Script/BlueprintGraph.K2Node_SwitchName",
switchString: "/Script/BlueprintGraph.K2Node_SwitchString",
userDefinedEnum: "/Script/Engine.UserDefinedEnum",
variableGet: "/Script/BlueprintGraph.K2Node_VariableGet",
variableSet: "/Script/BlueprintGraph.K2Node_VariableSet",
vector: "/Script/CoreUObject.Vector",
vector2D: "/Script/CoreUObject.Vector2D",
whileLoop: "/Engine/EditorBlueprintResources/StandardMacros.StandardMacros:WhileLoop",
}
static pinColor = {
@@ -184,6 +191,7 @@ export default class Configuration {
/** @param {ObjectReferenceEntity} objectReferenceEntity */
static subObjectAttributeNameFromReference = (objectReferenceEntity, nameOnly = false) =>
this.subObjectAttributeNamePrefix + (!nameOnly ? "_" + objectReferenceEntity.type : "") + "_" + objectReferenceEntity.path
static switchTargetPattern = /\/Script\/[\w\.\/\:]+K2Node_Switch([A-Z]\w+)+/
static trackingMouseEventName = {
begin: "ueb-tracking-mouse-begin",
end: "ueb-tracking-mouse-end",

View File

@@ -31,6 +31,13 @@ export default class Utility {
}
}
static arrayConverter = {
/** @param {String} value */
fromAttribute: (value, type) => value.split(/(?<!\\),/).map(v => v.trim()),
/** @param {String[]} value */
toAttribute: (value, type) => value.join(","),
}
/** @param {Number} x */
static sigmoid(x, curvature = 1.7) {
return 1 / (1 + (x / (1 - x) ** -curvature))
@@ -316,7 +323,7 @@ export default class Utility {
static clearHTMLWhitespace(value) {
return value
.replaceAll("&nbsp;", "\u00A0") // whitespace
.replaceAll(/<br\s*\/>|<br>/, "\n") // newlines
.replaceAll(/<br\s*\/>|<br>/g, "\n") // newlines
.replaceAll(/(\<!--.*?\-->)/g, "") // html comments
}

View File

@@ -0,0 +1,37 @@
import DropdownTemplate from "../template/pin/DropdownTemplate.js"
import IElement from "./IElement.js"
/** @extends {IElement<Object, DropdownTemplate>} */
export default class DropdownElement extends IElement {
static properties = {
...super.properties,
options: {
type: Object,
},
selected: {
type: String,
},
}
constructor() {
super()
super.initialize({}, new DropdownTemplate())
this.options = /** @type {[String, String][]} */([])
this.selected = ""
}
/** @param {[String, String][]} options */
static newObject(options) {
const result = new DropdownElement()
return result
}
initialize() {
// Initialized in the constructor, this method does nothing
}
getValue() {
return this.template.getSelectedValue()
}
}

View File

@@ -15,8 +15,6 @@ import Configuration from "../Configuration.js"
*/
export default class IElement extends LitElement {
#nextUpdatedCallbacks = []
/** @type {Blueprint} */
#blueprint
get blueprint() {
@@ -83,11 +81,6 @@ export default class IElement extends LitElement {
return this
}
/** @param {PropertyValues} changedProperties */
shouldUpdate(changedProperties) {
return this.isInitialized && this.isConnected
}
setup() {
this.template.setup()
this.isSetup = true
@@ -125,18 +118,6 @@ export default class IElement extends LitElement {
updated(changedProperties) {
super.updated(changedProperties)
this.template.updated(changedProperties)
// Remember the array might change while iterating
for (const f of this.#nextUpdatedCallbacks) {
f(changedProperties)
}
this.#nextUpdatedCallbacks = []
}
addNextUpdatedCallbacks(callback, requestUpdate = false) {
this.#nextUpdatedCallbacks.push(callback)
if (requestUpdate) {
this.requestUpdate()
}
}
acknowledgeDelete() {

View File

@@ -13,7 +13,6 @@ import Utility from "../Utility.js"
import VariableAccessNodeTemplate from "../template/node/VariableAccessNodeTemplate.js"
import VariableConversionNodeTemplate from "../template/node/VariableConversionNodeTemplate.js"
import VariableOperationNodeTemplate from "../template/node/VariableOperationNodeTemplate.js"
import UnknownPinEntity from "../entity/UnknownPinEntity.js"
/**
* @typedef {import("./IDraggableElement.js").DragEvent} DragEvent
@@ -90,7 +89,8 @@ export default class NodeElement extends ISelectableDraggableElement {
// If selected, it will already drag, also must check if under nested comments, it must drag just once
if (!this.selected && !this.#commentDragged) {
this.#commentDragged = true
this.addNextUpdatedCallbacks(() => this.#commentDragged = false)
this.requestUpdate()
this.updateComplete.then(() => this.#commentDragged = false)
this.addLocation(...e.detail.value)
}
}
@@ -193,11 +193,12 @@ export default class NodeElement extends ISelectableDraggableElement {
}
}
getUpdateComplete() {
return Promise.all([
super.getUpdateComplete(),
...this.getPinElements().map(pin => pin.updateComplete)
]).then(() => true)
async getUpdateComplete() {
let result = await super.getUpdateComplete()
for (const pin of this.getPinElements()) {
result &&= await pin.updateComplete
}
return result
}
/** @param {NodeElement} commentNode */

View File

@@ -1,5 +1,7 @@
import BoolPinTemplate from "../template/pin/BoolPinTemplate.js"
import Configuration from "../Configuration.js"
import ElementFactory from "./ElementFactory.js"
import EnumPinTemplate from "../template/pin/EnumPinTemplate.js"
import ExecPinTemplate from "../template/pin/ExecPinTemplate.js"
import Grammar from "../serialization/Grammar.js"
import GuidEntity from "../entity/GuidEntity.js"
@@ -39,18 +41,19 @@ import VectorPinTemplate from "../template/pin/VectorPinTemplate.js"
export default class PinElement extends IElement {
static #inputPinTemplates = {
"/Script/CoreUObject.LinearColor": LinearColorPinTemplate,
"/Script/CoreUObject.Rotator": RotatorPinTemplate,
"/Script/CoreUObject.Vector": VectorPinTemplate,
"/Script/CoreUObject.Vector2D": Vector2DPinTemplate,
"bool": BoolPinTemplate,
"byte": IntPinTemplate,
"enum": EnumPinTemplate,
"int": IntPinTemplate,
"int64": Int64PinTemplate,
"MUTABLE_REFERENCE": ReferencePinTemplate,
"name": NamePinTemplate,
"real": RealPinTemplate,
"string": StringPinTemplate,
[Configuration.nodeType.linearColor]: LinearColorPinTemplate,
[Configuration.nodeType.rotator]: RotatorPinTemplate,
[Configuration.nodeType.vector]: VectorPinTemplate,
[Configuration.nodeType.vector2D]: Vector2DPinTemplate,
}
static properties = {

View File

@@ -1,5 +1,6 @@
import ColorHandlerElement from "./ColorHandlerElement.js"
import ColorSliderElement from "./ColorSliderElement.js"
import DropdownElement from "./DropdownElement.js"
import ElementFactory from "./ElementFactory.js"
import InputElement from "./InputElement.js"
import LinkElement from "./LinkElement.js"
@@ -9,20 +10,17 @@ import SelectorElement from "./SelectorElement.js"
import WindowElement from "./WindowElement.js"
export default function defineElements() {
customElements.define("ueb-color-handler", ColorHandlerElement)
ElementFactory.registerElement("ueb-color-handler", ColorHandlerElement)
customElements.define("ueb-input", InputElement)
ElementFactory.registerElement("ueb-input", InputElement)
customElements.define("ueb-link", LinkElement)
ElementFactory.registerElement("ueb-link", LinkElement)
customElements.define("ueb-node", NodeElement)
ElementFactory.registerElement("ueb-node", NodeElement)
customElements.define("ueb-pin", PinElement)
ElementFactory.registerElement("ueb-pin", PinElement)
customElements.define("ueb-selector", SelectorElement)
ElementFactory.registerElement("ueb-selector", SelectorElement)
customElements.define("ueb-ui-slider", ColorSliderElement)
ElementFactory.registerElement("ueb-ui-slider", ColorSliderElement)
customElements.define("ueb-window", WindowElement)
ElementFactory.registerElement("ueb-window", WindowElement)
const define = (tag, type) => {
customElements.define(tag, type)
ElementFactory.registerElement(tag, type)
}
define("ueb-color-handler", ColorHandlerElement)
define("ueb-dropdown", DropdownElement)
define("ueb-input", InputElement)
define("ueb-link", LinkElement)
define("ueb-node", NodeElement)
define("ueb-pin", PinElement)
define("ueb-selector", SelectorElement)
define("ueb-ui-slider", ColorSliderElement)
define("ueb-window", WindowElement)
}

View File

@@ -81,7 +81,7 @@ export default class IEntity {
if (!suppressWarns) {
if (!(attributeName in attributes)) {
const typeName = value instanceof Array ? `[${value[0].constructor.name}]` : value.constructor.name
const typeName = value instanceof Array ? `[${value[0]?.constructor.name}]` : value.constructor.name
console.warn(
`UEBlueprint: Attribute ${attributeName} (of type ${typeName}) in the serialized data is not `
+ `defined in ${Self.name}.attributes`

View File

@@ -90,6 +90,11 @@ export default class ObjectEntity extends IEntity {
type: ObjectReferenceEntity,
showDefault: false,
},
EnumEntries: {
type: [String],
showDefault: false,
inlined: true,
},
InputKey: {
type: SymbolEntity,
showDefault: false,
@@ -293,6 +298,7 @@ export default class ObjectEntity extends IEntity {
/** @type {ObjectReferenceEntity?} */ this.TargetType
/** @type {MacroGraphReferenceEntity?} */ this.MacroGraphReference
/** @type {ObjectReferenceEntity?} */ this.Enum
/** @type {String[]?} */ this.EnumEntries
/** @type {SymbolEntity?} */ this.InputKey
/** @type {Boolean?} */ this.bOverrideFunction
/** @type {Boolean?} */ this.bInternalEvent
@@ -434,7 +440,14 @@ export default class ObjectEntity extends IEntity {
/** @returns {PinEntity[]} */
getPinEntities() {
return this.CustomProperties.filter(v => v instanceof PinEntity)
return this.CustomProperties.filter(v => v.constructor === PinEntity)
}
switchTarget() {
const switchMatch = this.getClass().match(Configuration.switchTargetPattern)
if (switchMatch) {
return switchMatch[1]
}
}
isEvent() {
@@ -496,11 +509,20 @@ export default class ObjectEntity extends IEntity {
)}`
case Configuration.nodeType.switchEnum:
return `Switch on ${this.Enum?.getName() ?? "Enum"}`
case Configuration.nodeType.switchInteger:
return `Switch on Int`
case Configuration.nodeType.variableGet:
return ""
case Configuration.nodeType.variableSet:
return "SET"
}
let switchTarget = this.switchTarget()
if (switchTarget) {
if (switchTarget[0] !== "E") {
switchTarget = Utility.formatStringName(switchTarget)
}
return `Switch on ${switchTarget}`
}
const keyNameSymbol = this.getHIDAttribute()
if (keyNameSymbol) {
const keyName = keyNameSymbol.toString()
@@ -535,7 +557,7 @@ export default class ObjectEntity extends IEntity {
switch (memberParent) {
case "/Script/Engine.KismetMathLibrary":
if (memberName.startsWith("Conv_")) {
return "" // Conversion nodes do not have visible names
return "" // Conversion nodes do not have visible names
}
if (memberName.startsWith("Percent_")) {
return "%"
@@ -602,8 +624,9 @@ export default class ObjectEntity extends IEntity {
return Configuration.nodeColors.gray
case Configuration.nodeType.dynamicCast:
return Configuration.nodeColors.turquoise
case Configuration.nodeType.switchEnum:
return Configuration.nodeColors.lime
}
if (this.switchTarget()) {
return Configuration.nodeColors.lime
}
if (this.isEvent()) {
return Configuration.nodeColors.red
@@ -645,7 +668,9 @@ export default class ObjectEntity extends IEntity {
case Configuration.nodeType.makeSet: return SVGIcon.makeSet
case Configuration.nodeType.select: return SVGIcon.select
case Configuration.nodeType.spawnActorFromClass: return SVGIcon.spawnActor
case Configuration.nodeType.switchEnum: return SVGIcon.switch
}
if (this.switchTarget()) {
return SVGIcon.switch
}
if (this.nodeDisplayName().startsWith("Break")) {
return SVGIcon.breakStruct

View File

@@ -31,10 +31,10 @@ import VectorEntity from "./VectorEntity.js"
export default class PinEntity extends IEntity {
static #typeEntityMap = {
"/Script/CoreUObject.LinearColor": LinearColorEntity,
"/Script/CoreUObject.Rotator": RotatorEntity,
"/Script/CoreUObject.Vector": VectorEntity,
"/Script/CoreUObject.Vector2D": Vector2DEntity,
[Configuration.nodeType.linearColor]: LinearColorEntity,
[Configuration.nodeType.rotator]: RotatorEntity,
[Configuration.nodeType.vector]: VectorEntity,
[Configuration.nodeType.vector2D]: Vector2DEntity,
"bool": Boolean,
"byte": ByteEntity,
"enum": EnumEntity,
@@ -46,9 +46,9 @@ export default class PinEntity extends IEntity {
"string": String,
}
static #alternativeTypeEntityMap = {
"/Script/CoreUObject.Vector2D": SimpleSerializationVector2DEntity,
"/Script/CoreUObject.Vector": SimpleSerializationVectorEntity,
"/Script/CoreUObject.Rotator": SimpleSerializationRotatorEntity,
[Configuration.nodeType.vector2D]: SimpleSerializationVector2DEntity,
[Configuration.nodeType.vector]: SimpleSerializationVectorEntity,
[Configuration.nodeType.rotator]: SimpleSerializationRotatorEntity,
}
static lookbehind = "Pin"
static attributes = {

View File

@@ -156,6 +156,9 @@ export default class Grammar {
) {
let result = defaultGrammar
if (type instanceof Array) {
if (attribute?.inlined) {
return this.grammarFor(undefined, type[0])
}
result = P.seq(
P.regex(/\(\s*/),
this.grammarFor(undefined, type[0]).sepBy(this.commaSeparation),

View File

@@ -22,7 +22,8 @@ export default class NodeTemplate extends ISelectableDraggableTemplate {
toggleAdvancedDisplayHandler = () => {
this.element.toggleShowAdvancedPinDisplay()
this.element.addNextUpdatedCallbacks(() => this.element.acknowledgeReflow(), true)
this.element.requestUpdate()
this.element.updateComplete.then(() => this.element.acknowledgeReflow())
}
/** @param {NodeElement} element */

View File

@@ -0,0 +1,49 @@
import { html } from "lit"
import ITemplate from "../ITemplate.js"
import MouseIgnore from "../../input/mouse/MouseIgnore.js"
/**
* @typedef {import ("../../element/DropdownElement.js").default} DropdownElement
* @typedef {import("lit").PropertyValues} PropertyValues
*/
/** @extends {ITemplate<DropdownElement>} */
export default class DropdownTemplate extends ITemplate {
/** @type {HTMLSelectElement} */
#selectElement
render() {
return html`
<select class="ueb-pin-input-content">
${this.element.options.map(([k, v]) => html`
<option value="${k}" ?selected="${k === this.element.selected}">${v}</option>
`)}
</select>
`
}
/** @param {PropertyValues} changedProperties */
firstUpdated(changedProperties) {
super.firstUpdated(changedProperties)
this.#selectElement = this.element.querySelector("select")
const event = new Event("input", { bubbles: true })
this.#selectElement.dispatchEvent(event)
}
createInputObjects() {
return [
...super.createInputObjects(),
// Prevents creating links when selecting text and other undesired mouse actions detection
new MouseIgnore(this.element, this.blueprint),
]
}
setSelectedValue(value) {
/** @type {HTMLOptionElement} */(this.element.querySelector(`option[value="${value}"]`)).defaultSelected = true
}
getSelectedValue() {
return this.#selectElement.value
}
}

View File

@@ -0,0 +1,60 @@
import { html } from "lit"
import IInputPinTemplate from "./IInputPinTemplate.js"
/**
* @typedef {import("../../element/DropdownElement.js").default} DropdownElement
* @typedef {import("../../element/PinElement.js").AnyValue} AnyValue
* @typedef {import("../../entity/EnumEntity.js").default} EnumEntity
* @typedef {import("lit").PropertyValues} PropertyValues
*/
/**
* @template {AnyValue} T
* @typedef {import("../../element/PinElement.js").default<T>} PinElement
*/
/** @extends IInputPinTemplate<EnumEntity> */
export default class EnumPinTemplate extends IInputPinTemplate {
static saveEachInputChange = true // Otherwise save only on focus out
/** @type {DropdownElement} */
#dropdownElement
#dropdownEntries = []
setup() {
super.setup()
const enumEntries = this.element.nodeElement.entity.EnumEntries
if (enumEntries) {
this.#dropdownEntries = enumEntries.map(k => [
k,
this.element.nodeElement.getPinEntities().find(pinEntity => k === pinEntity.PinName)
?.PinFriendlyName.toString()
?? k
])
this.element.requestUpdate()
}
}
renderInput() {
const entity = this.element.nodeElement.entity
return html`
<ueb-dropdown
class="ueb-pin-input"
.options="${this.#dropdownEntries}"
.selected="${this.element.defaultValue.value}"
>
</ueb-dropdown>
`
}
/** @param {PropertyValues} changedProperties */
firstUpdated(changedProperties) {
super.firstUpdated(changedProperties)
this.#dropdownElement = this.element.querySelector("ueb-dropdown")
}
getInputs() {
return [this.#dropdownElement.getValue()]
}
}

View File

@@ -1,6 +1,5 @@
import { html } from "lit"
import Configuration from "../../Configuration.js"
import MouseIgnore from "../../input/mouse/MouseIgnore.js"
import PinTemplate from "./PinTemplate.js"
import Utility from "../../Utility.js"
@@ -14,12 +13,10 @@ export default class IInputPinTemplate extends PinTemplate {
static singleLineInput = false
static selectOnFocus = true
static saveEachInputChange = false // Otherwise save only on focus out
/** @type {HTMLElement[]} */
#inputContentElements
get inputContentElements() {
return this.#inputContentElements
}
/** @param {String} value */
static stringFromInputToUE(value) {
@@ -35,8 +32,8 @@ export default class IInputPinTemplate extends PinTemplate {
.replace(/(?<=\n\s*)$/, "\n") // Put back trailing double newline
}
#onFocusOutHandler = () => this.setInputs(this.getInputs(), true)
/** @param {InputEvent} event */
#setInput = () => this.setInputs(this.getInputs(), true)
/** @param {Event} event */
#onInputCheckWrapHandler = event => this.#updateWrapClass(/** @type {HTMLElement} */(event.target))
/** @param {HTMLElement} inputElement*/
@@ -53,38 +50,34 @@ export default class IInputPinTemplate extends PinTemplate {
/** @param {PropertyValues} changedProperties */
firstUpdated(changedProperties) {
super.firstUpdated(changedProperties)
this.#inputContentElements = /** @type {HTMLElement[]} */([...this.element.querySelectorAll("ueb-input")])
if (/** @type {typeof IInputPinTemplate} */(this.constructor).canWrapInput) {
this.element.addEventListener("input", this.#onInputCheckWrapHandler)
this.nameWidth = this.blueprint.scaleCorrect(
this.element.querySelector(".ueb-pin-name").getBoundingClientRect().width
)
this.inputContentElements.forEach(inputElement => this.#updateWrapClass(inputElement))
}
this.#inputContentElements = /** @type {HTMLElement[]} */([...this.element.querySelectorAll("ueb-input")])
}
setup() {
super.setup()
this.#inputContentElements.forEach(element => {
element.addEventListener("focusout", this.#onFocusOutHandler)
if (/** @type {typeof IInputPinTemplate} */(this.constructor).canWrapInput) {
element.addEventListener("input", this.#onInputCheckWrapHandler)
}
})
const Self = /** @type {typeof IInputPinTemplate} */(this.constructor)
if (Self.saveEachInputChange) {
this.element.addEventListener("input", this.#setInput)
} else {
this.element.addEventListener("focusout", this.#setInput)
}
if (/** @type {typeof IInputPinTemplate} */(this.constructor).canWrapInput) {
this.element.addEventListener("input", this.#onInputCheckWrapHandler)
}
}
cleanup() {
super.cleanup()
this.#inputContentElements.forEach(element => {
element.removeEventListener("focusout", this.#onFocusOutHandler)
element.removeEventListener("input", this.#onInputCheckWrapHandler)
})
}
this.element.removeEventListener("input", this.#onInputCheckWrapHandler)
this.element.removeEventListener("input", this.#setInput)
this.element.removeEventListener("focusout", this.#setInput)
createInputObjects() {
return [
...super.createInputObjects(),
...this.#inputContentElements.map(elem => new MouseIgnore(elem, this.blueprint)),
]
}
getInput() {
@@ -107,7 +100,8 @@ export default class IInputPinTemplate extends PinTemplate {
if (updateDefaultValue) {
this.setDefaultValue(values.map(v => IInputPinTemplate.stringFromInputToUE(v)), values)
}
this.element.addNextUpdatedCallbacks(() => this.element.nodeElement.acknowledgeReflow())
this.element.requestUpdate()
this.element.nodeElement.acknowledgeReflow()
}
setDefaultValue(values = [], rawValues = values) {
@@ -118,8 +112,9 @@ export default class IInputPinTemplate extends PinTemplate {
}
renderInput() {
const singleLine = /** @type {typeof IInputPinTemplate} */(this.constructor).singleLineInput
const selectOnFocus = /** @type {typeof IInputPinTemplate} */(this.constructor).selectOnFocus
const Self = /** @type {typeof IInputPinTemplate} */(this.constructor)
const singleLine = Self.singleLineInput
const selectOnFocus = Self.selectOnFocus
return html`
<div class="ueb-pin-input">
<ueb-input .singleLine="${singleLine}" .selectOnFocus="${selectOnFocus}"

View File

@@ -1,6 +1,10 @@
import ITemplate from "../ITemplate.js"
import MouseIgnore from "../../input/mouse/MouseIgnore.js"
/** @typedef {import ("../../element/InputElement").default} InputElement */
/**
* @typedef {import ("../../element/InputElement").default} InputElement
* @typedef {import ("lit").PropertyValues} PropertyValues
*/
/** @extends {ITemplate<InputElement>} */
export default class InputTemplate extends ITemplate {
@@ -17,7 +21,7 @@ export default class InputTemplate extends ITemplate {
getSelection().removeAllRanges() // Deselect eventually selected text inside the input
}
/** @param {InputEvent} e */
/** @param {Event} e */
#inputSingleLineHandler = e =>
/** @type {HTMLElement} */(e.target).querySelectorAll("br").forEach(br => br.remove())
@@ -36,6 +40,21 @@ export default class InputTemplate extends ITemplate {
this.element.contentEditable = "true"
}
/** @param {PropertyValues} changedProperties */
firstUpdated(changedProperties) {
super.firstUpdated(changedProperties)
const event = new Event("input", { bubbles: true })
this.element.dispatchEvent(event)
}
createInputObjects() {
return [
...super.createInputObjects(),
// Prevents creating links when selecting text and other undesired mouse actions detection
new MouseIgnore(this.element, this.blueprint),
]
}
setup() {
super.setup()
this.element.addEventListener("focus", this.#focusHandler)

View File

@@ -9,7 +9,6 @@ export default class IntPinTemplate extends INumericPinTemplate {
setDefaultValue(values = [], rawValues = values) {
const integer = this.element.getDefaultValue(true)
integer.value = values[0]
this.inputContentElements[0].innerText = this.element.getDefaultValue()?.toString() // needed
this.element.requestUpdate()
}

View File

@@ -103,8 +103,8 @@ export default class PinTemplate extends ITemplate {
if (this.element.isInput() && changedProperties.has("isLinked")) {
// When connected, an input may drop its input fields which means the node has to reflow
const node = this.element.nodeElement
node.addNextUpdatedCallbacks(() => node.acknowledgeReflow())
node.requestUpdate()
this.element.requestUpdate()
this.element.updateComplete.then(() => node.acknowledgeReflow())
}
}