Refactoring, various fixes

This commit is contained in:
barsdeveloper
2022-03-24 22:54:41 +01:00
parent 4dd2929a9f
commit 8a4e60c9ae
43 changed files with 937 additions and 589 deletions

View File

View File

View File

View File

View File

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1 +1 @@
.ueb{--ueb-pin-color: white;--ueb-pin-dim-color: #afafaf}.ueb-pin-boolean{--ueb-pin-color: #930000}.ueb-pin-int{--ueb-pin-color: #1fe0ad}.ueb-pin-float{--ueb-pin-color: #9ffb44}.ueb-pin-vector{--ueb-pin-color: #fcc823}.ueb-pin-rotator{--ueb-pin-color: #9eb1fc}.ueb-pin-string{--ueb-pin-color: #fc00d2;--ueb-pin-background: linear-gradient(90deg, #fc00d220, #fc00d280 15%, #fc00d250 85%, transparent)}.ueb-pin-name{--ueb-pin-color: #cb81fc}.ueb-pin-object{--ueb-pin-color: #00a8f2}/*# sourceMappingURL=ueblueprint-node-value-type-color.css.map */
.ueb{--ueb-pin-color: white;--ueb-pin-dim-color: #afafaf}.ueb-pin-boolean{--ueb-pin-color: #4d0000}.ueb-pin-class{--ueb-pin-color: #5800bb}.ueb-pin-float{--ueb-pin-color: #9ffb44}.ueb-pin-int{--ueb-pin-color: #1fe0ad}.ueb-pin-name{--ueb-pin-color: #cb81fc}.ueb-pin-object{--ueb-pin-color: #006603}.ueb-pin-rotator{--ueb-pin-color: #9eb1fc}.ueb-pin-string{--ueb-pin-color: #fc00d2;--ueb-pin-background: linear-gradient(90deg, #fc00d220, #fc00d280 15%, #fc00d250 85%, transparent)}.ueb-pin-vector{--ueb-pin-color: #fcc823}/*# sourceMappingURL=ueblueprint-node-value-type-color.css.map */

View File

@@ -1 +1 @@
{"version":3,"sourceRoot":"","sources":["../../scss/ueblueprint-node-value-type-color.scss"],"names":[],"mappings":"AAAA,KAGI,uBACA,6BAGJ,iBAEI,yBAGJ,aAEI,yBAGJ,eAEI,yBAGJ,gBAEI,yBAGJ,iBAEI,yBAGJ,gBAEI,yBACA,mGAGJ,cAEI,yBAGJ,gBAEI","file":"ueblueprint-node-value-type-color.css"}
{"version":3,"sourceRoot":"","sources":["../../scss/ueblueprint-node-value-type-color.scss"],"names":[],"mappings":"AAAA,KAGI,uBACA,6BAGJ,iBAEI,yBAGJ,eAEI,yBAGJ,eAEI,yBAGJ,aAEI,yBAGJ,cAEI,yBAGJ,gBAGI,yBAGJ,iBAEI,yBAGJ,gBAEI,yBACA,mGAGJ,gBAEI","file":"ueblueprint-node-value-type-color.css"}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"sourceRoot":"","sources":["../../scss/ueblueprint-style.scss"],"names":[],"mappings":"AAAA,WACI,qBACA,iBACA,IACI,kGAIR,WACI,qBACA,mBACA,IACI,sGAIR,cACI,cACA,kBACA,8EACA,+BACA,iBAGJ,qBACI,aACA,kBACA,MACA,QACA,OACA,aACA,0BACA,UAGJ,mBACI,gBAGJ,mBACI,kBACA,aACA,gBACA,qBAGJ,oDACI,gBAGJ,UACI,kFACA,kBACA,eACA,gBACA,kEACA,mEACA,yBACA,iBAEI,s3BA0BJ,gBAEI,sZAQJ,sFACA,gEACA,oDACA,qBACA,gBAGJ,kDACI,gBAGJ,mDACI,eAGJ,qBAGI,eACA,6CAGJ,iBAEI,mBAGJ,iBAEI,kBAGJ,iBAEI,mBAGJ,iBAEI,iBACA,uDAGJ,iBAEI,mBACA,uDAGJ,iBACI,sBACA,uDAGJ,iBACI,iBACA,uDAGJ,iBACI,sBACA,uDAGJ,iBACI,sBACA,uDAGJ,kBAEI,iBACA,uDAGJ,kBAEI,sBACA,uDAGJ,kBAEI,sBACA,uDAGJ,kBACI,kBACA,QACA,SACA,wGAGJ,SACI,cACA,kBACA,sGACA,qCACA,uDACA,sBAGJ,wEACI,YAGJ,iBACI,YACA,YACA,+CAGJ,+BACI,iBACI,kNAIJ,oDACA,0CACA,sDACA,0BACA,oBAGJ,kBACI,kBACA,YACA,gCACA,qCACA,0BACA,gBAGJ,iBACI,kBACA,6DACA,gEACA,8EACA,aACA,gBACA,mBAGJ,eACI,iFACA,qBACA,mBAGJ,eACI,aACA,cACA,WACA,gBACA,mBAGJ,iBACI,kBACA,iBAGJ,kBACI,kBAGJ,QACI,cACA,gBAGJ,wEACI,aAGJ,6EACI,qCACA,iBAGJ,0BACI,iBAGJ,cACI,qBACA,kBACA,YACA,aACA,wBACA,wBAGJ,sBACI,WACA,cACA,kBACA,MACA,QACA,SACA,OACA,sCACA,kBAGJ,2CACI,gCAGJ,qBACI,WACA,cACA,kBACA,qBACA,sBACA,QACA,SACA,kCACA,qCACA,4CAGJ,gEACI,8DACA,8DACA,8DACA,8DACA,oGACA,qGACA,kBACA,wCACA,yCACA,0CACA,4CAGJ,aACI,cACA,kBACA,kBACA,MACA,OACA,QACA,SACA,iBAEI,wlDAmDJ,gBAEI,gQAWJ,oBAEI,wJAOJ,4BAGJ,gDACI,mBAIJ,eACI,mBAGJ,SACI,kEAEA,uEACA,cACA,8CAKA,kBAGJ,aACI,iEACA,kBACA,MACA,OACA,WACA,YACA,eACA,8FACA,iBAGJ,kBACI,mBACA,4BACA,eAGJ,8DAEI,eACA,4BAGJ,iBACI,cACA,mBACA,kBACA,kDACA,qHAOA,sBACA,gBACA,kBACA,4EACA,+BACA,mBACA","file":"ueblueprint-style.css"}
{"version":3,"sourceRoot":"","sources":["../../scss/ueblueprint-style.scss"],"names":[],"mappings":"AAAA,WACI,qBACA,iBACA,IACI,kGAIR,WACI,qBACA,mBACA,IACI,sGAIR,cACI,cACA,kBACA,8EACA,+BACA,iBAGJ,qBACI,aACA,kBACA,MACA,QACA,OACA,aACA,0BACA,UAGJ,mBACI,gBAGJ,mBACI,kBACA,aACA,gBACA,qBAGJ,oDACI,gBAGJ,UACI,kFACA,kBACA,eACA,gBACA,kEACA,mEACA,yBACA,iBAEI,s3BA0BJ,gBAEI,sZAQJ,sFACA,gEACA,oDACA,qBACA,gBAGJ,kDACI,gBAGJ,mDACI,eAGJ,qBAGI,eACA,6CAGJ,iBAEI,mBAGJ,iBAEI,kBAGJ,iBAEI,mBAGJ,iBAEI,iBACA,uDAGJ,iBAEI,mBACA,uDAGJ,iBACI,sBACA,uDAGJ,iBACI,iBACA,uDAGJ,iBACI,sBACA,uDAGJ,iBACI,sBACA,uDAGJ,kBAEI,iBACA,uDAGJ,kBAEI,sBACA,uDAGJ,kBAEI,sBACA,uDAGJ,kBACI,kBACA,QACA,SACA,wGAGJ,SACI,cACA,kBACA,sGACA,qCACA,uDACA,sBAGJ,wEACI,YAGJ,iBACI,YACA,YACA,+CAGJ,+BACI,iBACI,kNAIJ,oDACA,0CACA,sDACA,0BACA,oBAGJ,kBACI,kBACA,YACA,gCACA,qCACA,0BACA,gBAGJ,iBACI,kBACA,6DACA,gEACA,8EACA,aACA,gBACA,mBAGJ,eACI,iFACA,qBACA,mBAGJ,eACI,aACA,cACA,WACA,gBACA,mBAGJ,iBACI,kBACA,iBAGJ,kBACI,kBAGJ,iBACI,aAGJ,iDACI,cAGJ,QACI,cACA,gBAGJ,wEACI,aAGJ,6EACI,qCACA,iBAGJ,0BACI,iBAGJ,cACI,qBACA,kBACA,YACA,aACA,wBACA,wBAGJ,sBACI,WACA,cACA,kBACA,MACA,QACA,SACA,OACA,sCACA,kBAGJ,2CACI,gCAGJ,qBACI,WACA,cACA,kBACA,qBACA,sBACA,QACA,SACA,kCACA,qCACA,4CAGJ,gEACI,8DACA,8DACA,8DACA,8DACA,oGACA,qGACA,kBACA,wCACA,yCACA,0CACA,4CAGJ,aACI,cACA,kBACA,kBACA,MACA,OACA,QACA,SACA,iBAEI,wlDAmDJ,gBAEI,gQAWJ,oBAEI,wJAOJ,4BAGJ,gDACI,mBAIJ,eACI,mBAGJ,SACI,kEAEA,uEACA,cACA,8CAKA,kBAGJ,aACI,iEACA,kBACA,MACA,OACA,WACA,YACA,eACA,8FACA,iBAGJ,kBACI,mBACA,4BACA,eAGJ,8DAEI,eACA,4BAGJ,iBACI,cACA,mBACA,kBACA,kDACA,qHAOA,sBACA,gBACA,kBACA,4EACA,+BACA,mBACA","file":"ueblueprint-style.css"}

823
dist/ueblueprint.js vendored

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@ import Configuration from "./Configuration"
import Copy from "./input/common/Copy"
import IElement from "./element/IElement"
import KeyboardCanc from "./input/keybaord/KeyboardCanc"
import KeyboardEnableZoom from "./input/keybaord/KeyboardEnableZoom"
import KeyboardSelectAll from "./input/keybaord/KeyboardSelectAll"
import LinkElement from "./element/LinkElement"
import MouseScrollGraph from "./input/mouse/MouseScrollGraph"
@@ -121,7 +122,8 @@ export default class Blueprint extends IElement {
moveEverywhere: true,
}),
new Unfocus(this.getGridDOMElement(), this),
new MouseTracking(this.getGridDOMElement(), this)
new MouseTracking(this.getGridDOMElement(), this),
new KeyboardEnableZoom(this.getGridDOMElement(), this),
]
}
@@ -257,7 +259,7 @@ export default class Blueprint extends IElement {
}
setZoom(zoom, center) {
zoom = Utility.clamp(zoom, -12, 0)
zoom = Utility.clamp(zoom, Configuration.minZoom, Configuration.maxZoom)
if (zoom == this.zoom) {
return
}

View File

@@ -1,5 +1,6 @@
export default class Configuration {
static deleteNodesKeyboardKey = "Delete"
static enableZoomIn = ["LeftControl", "RightControl"] // Button to enable more than 0 (1:1) zoom
static expandGridSize = 400
static fontSize = "13px"
static gridAxisLineColor = "black"
@@ -22,11 +23,13 @@ export default class Configuration {
let end = 100 - start
return `M ${start} 0 C ${c1} 0, ${c2} 0, 50 50 S ${end - c1 + start} 100, ${end} 100`
}
static maxZoom = 7
static minZoom = -12
static nodeDeleteEventName = "ueb-node-delete"
static nodeDragEventName = "ueb-node-drag"
static nodeDragLocalEventName = "ueb-node-drag-local"
static nodeRadius = 8 // in pixel
static selectAllKeyboardKey = "Ctrl+A"
static selectAllKeyboardKey = "(bCtrl=True,Key=A)"
static trackingMouseEventName = {
begin: "ueb-tracking-mouse-begin",
end: "ueb-tracking-mouse-end"
@@ -41,6 +44,12 @@ export default class Configuration {
/* UE name: JS name */
"Backspace": "Backspace",
"Tab": "Tab",
"LeftControl": "ControlLeft",
"RightControl": "ControlRight",
"LeftShift": "ShiftLeft",
"RightShift": "ShiftRight",
"LeftAlt": "AltLeft",
"RightAlt": "AltRight",
"Enter": "Enter",
"Pause": "Pause",
"CapsLock": "CapsLock",
@@ -50,23 +59,23 @@ export default class Configuration {
"PageDown": "PageDown",
"End": "End",
"Home": "Home",
"ArrowLeft": "ArrowLeft",
"ArrowUp": "ArrowUp",
"ArrowRight": "ArrowRight",
"ArrowDown": "ArrowDown",
"ArrowLeft": "Left",
"ArrowUp": "Up",
"ArrowRight": "Right",
"ArrowDown": "Down",
"PrintScreen": "PrintScreen",
"Insert": "Insert",
"Delete": "Delete",
"Digit0": "Digit0",
"Digit1": "Digit1",
"Digit2": "Digit2",
"Digit3": "Digit3",
"Digit4": "Digit4",
"Digit5": "Digit5",
"Digit6": "Digit6",
"Digit7": "Digit7",
"Digit8": "Digit8",
"Digit9": "Digit9",
"Zero": "Digit0",
"One": "Digit1",
"Two": "Digit2",
"Three": "Digit3",
"Four": "Digit4",
"Five": "Digit5",
"Six": "Digit6",
"Seven": "Digit7",
"Eight": "Digit8",
"Nine": "Digit9",
"A": "KeyA",
"B": "KeyB",
"C": "KeyC",
@@ -92,21 +101,21 @@ export default class Configuration {
"X": "KeyX",
"Y": "KeyY",
"Z": "KeyZ",
"Numpad0": "Numpad0",
"Numpad1": "Numpad1",
"Numpad2": "Numpad2",
"Numpad3": "Numpad3",
"Numpad4": "Numpad4",
"Numpad5": "Numpad5",
"Numpad6": "Numpad6",
"Numpad7": "Numpad7",
"Numpad8": "Numpad8",
"Numpad9": "Numpad9",
"NumpadMultiply": "NumpadMultiply",
"NumpadAdd": "NumpadAdd",
"NumpadSubtract": "NumpadSubtract",
"NumpadDecimal": "NumpadDecimal",
"NumpadDivide": "NumpadDivide",
"NumPadZero": "Numpad0",
"NumPadOne": "Numpad1",
"NumPadTwo": "Numpad2",
"NumPadThree": "Numpad3",
"NumPadFour": "Numpad4",
"NumPadFive": "Numpad5",
"NumPadSix": "Numpad6",
"NumPadSeven": "Numpad7",
"NumPadEight": "Numpad8",
"NumPadNine": "Numpad9",
"Multiply": "NumpadMultiply",
"Add": "NumpadAdd",
"Subtract": "NumpadSubtract",
"Decimal": "NumpadDecimal",
"Divide": "NumpadDivide",
"F1": "F1",
"F2": "F2",
"F3": "F3",

View File

@@ -9,19 +9,27 @@ export default class IElement extends HTMLElement {
static tagName = ""
/** @type {Blueprint} */
blueprint
/** @type {IEntity} */
entity
/** @type {ITemplate} */
template
/** @type {IContext[]} */
inputObjects = []
/**
* @param {IEntity} entity The entity containing blueprint related data for this graph element
* @param {ITemplate} template The template to render this node
*/
constructor(entity, template) {
super()
/** @type {Blueprint} */
this.blueprint = null
/** @type {IEntity} */
this.entity = entity
/** @type {ITemplate} */
this.template = template
/** @type {IContext[]} */
this.inputObjects = []
}
@@ -39,14 +47,22 @@ export default class IElement extends HTMLElement {
this.inputObjects.forEach(v => v.unlistenDOMElement())
}
createInputObjects() {
return []
}
/**
* @param {IElement} element
*/
/** @param {IElement} element */
isSameGraph(element) {
return this.blueprint && this.blueprint == element?.blueprint
}
/**
* @template {} T
* @param {new () => T} type
* @returns {T}
*/
getInputObject(type) {
return this.inputObjects.find(object => object.constructor == type)
}
// Subclasses will want to override
createInputObjects() {
return []
}
}

View File

@@ -28,7 +28,7 @@ export default class IEntity {
* - A proper value.
*/
const value = Utility.objectGet(options, fullKey)
if (value !== null) {
if (value !== undefined) {
target[property] = value
continue
}

View File

@@ -1,7 +1,7 @@
import IEntity from "./IEntity"
export default class Identifier extends IEntity {
export default class IdentifierEntity extends IEntity {
static attributes = {
value: String,
@@ -15,11 +15,6 @@ export default class Identifier extends IEntity {
}
}
super(options)
/** @type {String} */
this.value
if (!this.value.match(/\w+/)) {
throw new Error("The value must be an identifier (/\w+/).")
}
}
valueOf() {

View File

@@ -1,12 +1,17 @@
import IdentifierEntity from "./IdentifierEntity"
import IEntity from "./IEntity"
export default class KeyBindingEntity extends IEntity {
static attributes = {
bCtrlDown: false,
bAltDown: false,
bShiftDown: false,
Key: String,
CommandName: String,
ActionName: "",
bShift: false,
bCtrl: false,
bAlt: false,
bCmd: false,
Key: IdentifierEntity,
}
constructor(options = {}) {
super(options)
}
}

View File

@@ -1,6 +1,6 @@
import FunctionReferenceEntity from "./FunctionReferenceEntity"
import GuidEntity from "./GuidEntity"
import Identifier from "./Identifier"
import IdentifierEntity from "./IdentifierEntity"
import IEntity from "./IEntity"
import IntegerEntity from "./IntegerEntity"
import ObjectReferenceEntity from "./ObjectReferenceEntity"
@@ -20,7 +20,7 @@ export default class ObjectEntity extends IEntity {
TargetType: new TypeInitialization(ObjectReferenceEntity, false, null),
NodePosX: IntegerEntity,
NodePosY: IntegerEntity,
AdvancedPinDisplay: new TypeInitialization(Identifier, false, null),
AdvancedPinDisplay: new TypeInitialization(IdentifierEntity, false, null),
NodeGuid: GuidEntity,
ErrorType: new TypeInitialization(IntegerEntity, false),
ErrorMsg: new TypeInitialization(String, false, ""),

View File

@@ -72,16 +72,14 @@ export default class PinEntity extends IEntity {
linkTo(targetObjectName, targetPinEntity) {
/** @type {PinReferenceEntity[]} */
this.LinkedTo
const linkFound = this.LinkedTo.find(
/** @type {PinReferenceEntity} */
pinReferenceEntity => {
return pinReferenceEntity.objectName == targetObjectName
&& pinReferenceEntity.pinGuid.valueOf() == targetPinEntity.PinId.valueOf()
})
const linkFound = this.LinkedTo?.find(pinReferenceEntity => {
return pinReferenceEntity.objectName == targetObjectName
&& pinReferenceEntity.pinGuid.valueOf() == targetPinEntity.PinId.valueOf()
})
if (!linkFound) {
this.LinkedTo.push(new PinReferenceEntity({
(this.LinkedTo ?? (this.LinkedTo = [])).push(new PinReferenceEntity({
objectName: targetObjectName,
pinGuid: targetPinEntity.PinId
pinGuid: targetPinEntity.PinId,
}))
return true
}
@@ -95,14 +93,16 @@ export default class PinEntity extends IEntity {
unlinkFrom(targetObjectName, targetPinEntity) {
/** @type {PinReferenceEntity[]} */
this.LinkedTo
const indexElement = this.LinkedTo.findIndex(
/** @type {PinReferenceEntity} */
pinReferenceEntity => {
return pinReferenceEntity.objectName == targetObjectName
&& pinReferenceEntity.pinGuid == targetPinEntity.PinId
})
const indexElement = this.LinkedTo.findIndex(pinReferenceEntity => {
return pinReferenceEntity.objectName == targetObjectName
&& pinReferenceEntity.pinGuid == targetPinEntity.PinId
})
if (indexElement >= 0) {
this.LinkedTo.splice(indexElement, 1)
if (this.LinkedTo.length == 1) {
this.LinkedTo = undefined
} else {
this.LinkedTo.splice(indexElement, 1)
}
return true
}
return false

View File

@@ -1,14 +1,36 @@
export default class IContext {
/** @type {HTMLElement} */
target
/** @type {import("../Blueprint").default}" */
blueprint
/** @type {Object} */
options
#hasFocus = false
get hasFocus() {
return this.#hasFocus
}
set hasFocus(_) {
}
constructor(target, blueprint, options) {
/** @type {HTMLElement} */
this.target = target
/** @type {import("../Blueprint").default}" */
this.blueprint = blueprint
this.options = options
let self = this
this.blueprintFocusHandler = _ => self.listenEvents()
this.blueprintUnfocusHandler = _ => self.unlistenEvents()
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)

View File

@@ -1,76 +1,71 @@
import Configuration from "../../Configuration"
import IContext from "../IContext"
import Parsimmon from "parsimmon"
let P = Parsimmon
class KeyGrammar {
// Creates a grammar where each alternative is the string from ModifierKey mapped to a number for bit or use
ModifierKey = r => P.alt(...Configuration.ModifierKeys.map((v, i) => P.string(v).map(_ => 1 << i)))
Key = r => P.alt(...Object.keys(Configuration.Keys).map(v => P.string(v))).map(v => Configuration.Keys[v])
KeyboardShortcut = r => P.alt(
P.seqMap(
P.seqMap(r.ModifierKey, P.optWhitespace, P.string(Configuration.keysSeparator), (v, _, __) => v)
.atLeast(1)
.map(v => v.reduce((acc, cur) => acc | cur)),
P.optWhitespace,
r.Key,
(modifierKeysFlag, _, key) => ({
key: key,
ctrlKey: Boolean(modifierKeysFlag & (1 << Configuration.ModifierKeys.indexOf("Ctrl"))),
shiftKey: Boolean(modifierKeysFlag & (1 << Configuration.ModifierKeys.indexOf("Shift"))),
altKey: Boolean(modifierKeysFlag & (1 << Configuration.ModifierKeys.indexOf("Alt"))),
metaKey: Boolean(modifierKeysFlag & (1 << Configuration.ModifierKeys.indexOf("Meta")))
})
),
r.Key.map(v => ({ key: v }))
)
.trim(P.optWhitespace)
}
import ISerializer from "../../serialization/ISerializer"
import KeyBindingEntity from "../../entity/KeyBindingEntity"
export default class IKeyboardShortcut extends IContext {
static keyGrammar = P.createLanguage(new KeyGrammar())
/** @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) {
const parsed = ISerializer.grammar.KeyBinding.parse(v)
if (parsed.status) {
return parsed.value
}
}
throw new Error("Unexpected key value")
})
super(target, blueprint, options)
/** @type {String[]} */
this.key = this.options.key
this.ctrlKey = options.ctrlKey ?? false
this.shiftKey = options.shiftKey ?? false
this.altKey = options.altKey ?? false
this.metaKey = options.metaKey ?? false
this.#activationKeys = this.options.activationKeys ?? []
let self = this
/** @param {KeyboardEvent} e */
this.keyDownHandler = e => {
if (
e.code == self.key
&& e.ctrlKey === self.ctrlKey
&& e.shiftKey === self.shiftKey
&& e.altKey === self.altKey
&& e.metaKey === self.metaKey
) {
self.fire()
self.#activationKeys.some(keyEntry =>
keyEntry.bShift === e.shiftKey
&& keyEntry.bCtrl === e.ctrlKey
&& keyEntry.bAlt === e.altKey
&& keyEntry.bCmd === e.metaKey
&& Configuration.Keys[keyEntry.Key] === e.code
)) {
e.preventDefault()
return true
self.fire()
document.removeEventListener("keydown", self.keyDownHandler)
document.addEventListener("keyup", self.keyUpHandler)
}
return false
}
}
/**
* @param {String} keyString
* @returns {Object}
*/
static keyOptionsParse(options, keyString) {
options = {
...options,
...IKeyboardShortcut.keyGrammar.KeyboardShortcut.parse(keyString).value
/** @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?
|| Configuration.Keys[keyEntry.Key] === e.code
)) {
e.preventDefault()
self.unfire()
document.removeEventListener("keyup", this.keyUpHandler)
document.addEventListener("keydown", this.keyDownHandler)
}
}
return options
}
listenEvents() {
@@ -81,6 +76,11 @@ export default class IKeyboardShortcut extends IContext {
document.removeEventListener("keydown", this.keyDownHandler)
}
// Subclasses will want to override
fire() {
}
unfire() {
}
}

View File

@@ -1,7 +1,7 @@
import Configuration from "../../Configuration"
import IKeyboardShortcut from "./IKeyboardShortcut"
export default class KeyvoardCanc extends IKeyboardShortcut {
export default class KeyboardCanc extends IKeyboardShortcut {
/**
* @param {HTMLElement} target
@@ -9,7 +9,10 @@ export default class KeyvoardCanc extends IKeyboardShortcut {
* @param {OBject} options
*/
constructor(target, blueprint, options = {}) {
options = IKeyboardShortcut.keyOptionsParse(options, Configuration.deleteNodesKeyboardKey)
options = {
...options,
activationKeys: Configuration.deleteNodesKeyboardKey
}
super(target, blueprint, options)
}

View File

@@ -0,0 +1,31 @@
import Configuration from "../../Configuration"
import IKeyboardShortcut from "./IKeyboardShortcut"
import Zoom from "../mouse/Zoom"
export default class KeyboardEnableZoom extends IKeyboardShortcut {
/** @type {} */
#zoomInputObject
/**
* @param {HTMLElement} target
* @param {import("../../Blueprint").default} blueprint
* @param {OBject} options
*/
constructor(target, blueprint, options = {}) {
options = {
...options,
activationKeys: Configuration.enableZoomIn
}
super(target, blueprint, options)
}
fire() {
this.zoomInputObject = this.blueprint.getInputObject(Zoom)
zoomInputObject.enableZoonIn = true
}
unfire() {
this.#zoomInputObject.enableZoom = false
}
}

View File

@@ -9,7 +9,10 @@ export default class KeyboardSelectAll extends IKeyboardShortcut {
* @param {Object} options
*/
constructor(target, blueprint, options = {}) {
options = IKeyboardShortcut.keyOptionsParse(options, Configuration.selectAllKeyboardKey)
options = {
...options,
activationKeys: Configuration.selectAllKeyboardKey
}
super(target, blueprint, options)
}

View File

@@ -101,6 +101,7 @@ export default class IMouseClickDrag extends IPointing {
if (self.started) {
self.endDrag()
}
self.unclicked()
if (self.#trackingMouse) {
const dragEvent = self.getEvent(Configuration.trackingMouseEventName.end)
this.target.dispatchEvent(dragEvent)
@@ -146,4 +147,7 @@ export default class IMouseClickDrag extends IPointing {
endDrag() {
}
unclicked(location) {
}
}

View File

@@ -18,7 +18,11 @@ export default class Select extends IMouseClickDrag {
endDrag() {
if (this.started) {
this.selectorElement.finishSelecting()
} else {
}
}
unclicked() {
if (!this.started) {
this.blueprint.unselectAll()
}
}

View File

@@ -2,9 +2,27 @@ import IMouseWheel from "./IMouseWheel"
export default class Zoom extends IMouseWheel {
#enableZoonIn = false
get enableZoonIn() {
return this.#enableZoonIn
}
set enableZoonIn(value) {
value = Boolean(value)
if (value == this.#enableZoonIn) {
return
}
this.#enableZoonIn = value
}
wheel(variation, location) {
let zoomLevel = this.blueprint.getZoom()
zoomLevel -= variation
variation = -variation
if (!this.enableZoonIn && zoomLevel == 0 && variation > 0) {
return
}
zoomLevel += variation
this.blueprint.setZoom(zoomLevel, location)
}
}

View File

@@ -1,7 +1,8 @@
import FunctionReferenceEntity from "../entity/FunctionReferenceEntity"
import GuidEntity from "../entity/GuidEntity"
import Identifier from "../entity/Identifier"
import IdentifierEntity from "../entity/IdentifierEntity"
import IntegerEntity from "../entity/IntegerEntity"
import KeyBindingEntity from "../entity/KeyBindingEntity"
import LocalizedTextEntity from "../entity/LocalizedTextEntity"
import ObjectEntity from "../entity/ObjectEntity"
import ObjectReferenceEntity from "../entity/ObjectReferenceEntity"
@@ -15,102 +16,7 @@ let P = Parsimmon
export default class Grammar {
/** @param {Grammar} r */
InlineWhitespace = r => P.regex(/[^\S\n]+/).desc("inline whitespace")
/** @param {Grammar} r */
InlineOptWhitespace = r => P.regex(/[^\S\n]*/).desc("inline optional whitespace")
/** @param {Grammar} r */
WhitespaceNewline = r => P.regex(/[^\S\n]*\n\s*/).desc("whitespace with at least a newline")
/** @param {Grammar} r */
Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(_ => null).desc("null: ()")
/** @param {Grammar} r */
None = r => P.string("None").map(_ => new ObjectReferenceEntity({ type: "None", path: "" })).desc("none")
/** @param {Grammar} r */
Boolean = r => P.alt(P.string("True"), P.string("False")).map(v => v === "True" ? true : false).desc("either True or False")
/** @param {Grammar} r */
Number = r => P.regex(/[\-\+]?[0-9]+(?:\.[0-9]+)?/).map(Number).desc("a number")
/** @param {Grammar} r */
Integer = r => P.regex(/[\-\+]?[0-9]+/).map(v => new IntegerEntity(v)).desc("an integer")
/** @param {Grammar} r */
String = r => P.regex(/(?:[^"\\]|\\.)*/).wrap(P.string('"'), P.string('"')).desc('string (with possibility to escape the quote using \")')
/** @param {Grammar} r */
Word = r => P.regex(/[a-zA-Z]+/).desc("a word")
/** @param {Grammar} r */
Guid = r => P.regex(/[0-9a-zA-Z]{32}/).map(v => new GuidEntity({ value: v })).desc("32 digit hexadecimal (accepts all the letters for safety) value")
/** @param {Grammar} */
Identifier = r => P.regex(/\w+/).map(v => new Identifier(v))
/** @param {Grammar} r */
PathSymbolEntity = r => P.regex(/[0-9a-zA-Z_]+/).map(v => new PathSymbolEntity({ value: v }))
/** @param {Grammar} r */
ReferencePath = r => P.seq(P.string("/"), r.PathSymbolEntity.map(v => v.toString()).sepBy1(P.string(".")).tieWith("."))
.tie()
.atLeast(2)
.tie()
.desc('a path (words with possibly underscore, separated by ".", separated by "/")')
/** @param {Grammar} r */
Reference = r => P.alt(
r.None,
...[r.ReferencePath.map(path => new ObjectReferenceEntity({ type: "", path: path }))].flatMap(
v => [v, v.trim(P.string('"'))]
),
P.seqMap(
r.Word,
P.optWhitespace,
P.alt(P.string('"'), P.string('\'"')).chain(
result => r.ReferencePath.skip(
P.string(result.split("").reverse().join(""))
)
),
(referenceType, _, referencePath) => new ObjectReferenceEntity({ type: referenceType, path: referencePath })
)
)
/** @param {Grammar} r */
AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".").desc('words separated by ""')
/** @param {Grammar} r */
AttributeAnyValue = r => P.alt(r.Null, r.None, r.Boolean, r.Number, r.Integer, r.String, r.Guid, r.Reference, r.LocalizedText)
/** @param {Grammar} r */
LocalizedText = r => P.seqMap(
P.string(LocalizedTextEntity.lookbehind).skip(P.optWhitespace).skip(P.string("(")),
r.String.trim(P.optWhitespace), // namespace
P.string(","),
r.String.trim(P.optWhitespace), // key
P.string(","),
r.String.trim(P.optWhitespace), // value
P.string(")"),
(_, namespace, __, key, ___, value, ____) => new LocalizedTextEntity({
namespace: namespace,
key: key,
value: value
})
)
/** @param {Grammar} r */
PinReference = r => P.seqMap(
r.PathSymbolEntity,
P.whitespace,
r.Guid,
(objectName, _, pinGuid) => new PinReferenceEntity({
objectName: objectName,
pinGuid: pinGuid
})
)
/* --- Factory --- */
/** @param {Grammar} r */
static getGrammarForType(r, attributeType, defaultGrammar) {
@@ -125,7 +31,7 @@ export default class Grammar {
return r.String
case GuidEntity:
return r.Guid
case Identifier:
case IdentifierEntity:
return r.Identifier
case ObjectReferenceEntity:
return r.Reference
@@ -159,7 +65,7 @@ export default class Grammar {
}
/** @param {Grammar} r */
static CreateAttributeGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) =>
static createAttributeGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) =>
r.AttributeName.skip(valueSeparator)
.chain(attributeName => {
const attributeKey = attributeName.split(".")
@@ -172,7 +78,7 @@ export default class Grammar {
})
/** @param {Grammar} r */
static CreateMultiAttributeGrammar = (r, entityType) =>
static createMultiAttributeGrammar = (r, entityType) =>
/**
* Basically this creates a parser that looks for a string like 'Key (A=False,B="Something",)'
* Then it populates an object of type EntityType with the attribute values found inside the parentheses.
@@ -181,7 +87,7 @@ export default class Grammar {
entityType.lookbehind
? P.seq(P.string(entityType.lookbehind), P.optWhitespace, P.string("("))
: P.string("("),
Grammar.CreateAttributeGrammar(r, entityType)
Grammar.createAttributeGrammar(r, entityType)
.trim(P.optWhitespace)
.sepBy(P.string(","))
.skip(P.regex(/,?/).then(P.optWhitespace)), // Optional trailing comma
@@ -192,11 +98,140 @@ export default class Grammar {
return result
})
/** @param {Grammar} r */
FunctionReference = r => Grammar.CreateMultiAttributeGrammar(r, FunctionReferenceEntity)
/* --- General --- */
/** @param {Grammar} r */
Pin = r => Grammar.CreateMultiAttributeGrammar(r, PinEntity)
InlineWhitespace = r => P.regex(/[^\S\n]+/).desc("inline whitespace")
/** @param {Grammar} r */
InlineOptWhitespace = r => P.regex(/[^\S\n]*/).desc("inline optional whitespace")
/** @param {Grammar} r */
MultilineWhitespace = r => P.regex(/[^\S\n]*\n\s*/).desc("whitespace with at least a newline")
/** @param {Grammar} r */
Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(_ => null).desc("null: ()")
/** @param {Grammar} r */
Boolean = r => P.alt(P.string("True"), P.string("False")).map(v => v === "True" ? true : false)
.desc("either True or False")
/** @param {Grammar} r */
Number = r => P.regex(/[\-\+]?[0-9]+(?:\.[0-9]+)?/).map(Number).desc("a number")
/** @param {Grammar} r */
Word = r => P.regex(/[a-zA-Z]+/).desc("a word")
/** @param {Grammar} r */
String = r => P.regex(/(?:[^"\\]|\\.)*/).wrap(P.string('"'), P.string('"'))
.desc('string (with possibility to escape the quote using \")')
/** @param {Grammar} r */
ReferencePath = r => P.seq(
P.string("/"),
r.PathSymbol
.map(v => v.toString())
.sepBy1(P.string("."))
.tieWith(".")
)
.tie()
.atLeast(2)
.tie()
.desc('a path (words with possibly underscore, separated by ".", separated by "/")')
/** @param {Grammar} r */
AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".").desc('words separated by ""')
/* --- Entity --- */
/** @param {Grammar} r */
None = r => P.string("None").map(_ => new ObjectReferenceEntity({ type: "None", path: "" })).desc("none")
/** @param {Grammar} r */
Integer = r => P.regex(/[\-\+]?[0-9]+/).map(v => new IntegerEntity(v)).desc("an integer")
/** @param {Grammar} r */
Guid = r => P.regex(/[0-9a-zA-Z]{32}/).map(v => new GuidEntity({ value: v }))
.desc("32 digit hexadecimal (accepts all the letters for safety) value")
/** @param {Grammar} */
Identifier = r => P.regex(/\w+/).map(v => new IdentifierEntity(v))
/** @param {Grammar} r */
PathSymbol = r => P.regex(/[0-9a-zA-Z_]+/).map(v => new PathSymbolEntity({ value: v }))
/** @param {Grammar} r */
Reference = r => P.alt(
r.None,
...[r.ReferencePath.map(path => new ObjectReferenceEntity({ type: "", path: path }))]
.flatMap(referencePath => [
referencePath, // version having just path
referencePath.trim(P.string('"')) // Version having path surround with double quotes
]),
P.seqMap(
r.Word, // Goes into referenceType
P.optWhitespace, // Goes into _ (ignored)
P.alt(...[r.ReferencePath].flatMap(referencePath => [
referencePath.wrap(P.string(`"`), P.string(`"`)),
referencePath.wrap(P.string(`'"`), P.string(`"'`))
])), // Goes into referencePath
(referenceType, _, referencePath) => new ObjectReferenceEntity({ type: referenceType, path: referencePath })
),
r.Word.map(type => new ObjectReferenceEntity({ type: type, path: "" })),
)
/** @param {Grammar} r */
LocalizedText = r => P.seqMap(
P.string(LocalizedTextEntity.lookbehind).skip(P.optWhitespace).skip(P.string("(")), // Goes into _ (ignored)
r.String.trim(P.optWhitespace), // Goes into namespace
P.string(","), // Goes into __ (ignored)
r.String.trim(P.optWhitespace), // Goes into key
P.string(","), // Goes into ___ (ignored)
r.String.trim(P.optWhitespace), // Goes into value
P.string(")"), // Goes into ____ (ignored)
(_, namespace, __, key, ___, value, ____) => new LocalizedTextEntity({
namespace: namespace,
key: key,
value: value
})
)
/** @param {Grammar} r */
AttributeAnyValue = r => P.alt(
r.Null,
r.None,
r.Boolean,
r.Number,
r.Integer,
r.String,
r.Guid,
r.Reference,
r.LocalizedText)
/** @param {Grammar} r */
PinReference = r => P.seqMap(
r.PathSymbol, // Goes into objectNAme
P.whitespace, // Goes into _ (ignored)
r.Guid, // Goes into pinGuid
(objectName, _, pinGuid) => new PinReferenceEntity({
objectName: objectName,
pinGuid: pinGuid
})
)
/** @param {Grammar} r */
FunctionReference = r => Grammar.createMultiAttributeGrammar(r, FunctionReferenceEntity)
/** @param {Grammar} r */
KeyBinding = r => P.alt(
r.Identifier.map(identifier => new KeyBindingEntity({
Key: identifier
})),
Grammar.createMultiAttributeGrammar(r, KeyBindingEntity)
)
/** @param {Grammar} r */
Pin = r => Grammar.createMultiAttributeGrammar(r, PinEntity)
/** @param {Grammar} r */
CustomProperties = r =>
@@ -216,10 +251,10 @@ export default class Grammar {
P
.alt(
r.CustomProperties,
Grammar.CreateAttributeGrammar(r, ObjectEntity)
Grammar.createAttributeGrammar(r, ObjectEntity)
)
.sepBy1(P.whitespace),
P.seq(r.WhitespaceNewline, P.string("End"), P.whitespace, P.string("Object")),
P.seq(r.MultilineWhitespace, P.string("End"), P.whitespace, P.string("Object")),
(_, attributes, __) => {
let result = new ObjectEntity()
attributes.forEach(attributeSetter => attributeSetter(result))

View File

@@ -2,7 +2,9 @@ import CustomSerializer from "./CustomSerializer"
import FunctionReferenceEntity from "../entity/FunctionReferenceEntity"
import GeneralSerializer from "./GeneralSerializer"
import GuidEntity from "../entity/GuidEntity"
import IdentifierEntity from "../entity/IdentifierEntity"
import IntegerEntity from "../entity/IntegerEntity"
import KeyBindingEntity from "../entity/KeyBindingEntity"
import LocalizedTextEntity from "../entity/LocalizedTextEntity"
import ObjectEntity from "../entity/ObjectEntity"
import ObjectReferenceEntity from "../entity/ObjectReferenceEntity"
@@ -12,29 +14,39 @@ import PinEntity from "../entity/PinEntity"
import PinReferenceEntity from "../entity/PinReferenceEntity"
import SerializerFactory from "./SerializerFactory"
import ToStringSerializer from "./ToStringSerializer"
import Identifier from "../entity/Identifier"
export default function initializeSerializerFactory() {
SerializerFactory.registerSerializer(
ObjectEntity,
new ObjectSerializer()
)
SerializerFactory.registerSerializer(
PinEntity,
new GeneralSerializer(v => `${PinEntity.lookbehind} (${v})`, PinEntity, "", ",", true)
)
SerializerFactory.registerSerializer(
FunctionReferenceEntity,
new GeneralSerializer(v => `(${v})`, FunctionReferenceEntity, "", ",", false)
)
SerializerFactory.registerSerializer(
KeyBindingEntity,
new GeneralSerializer(v => `(${v})`, KeyBindingEntity, "", ",", false)
)
SerializerFactory.registerSerializer(
LocalizedTextEntity,
new GeneralSerializer(v => `${LocalizedTextEntity.lookbehind}(${v})`, LocalizedTextEntity, "", ", ", false, "", _ => "")
)
SerializerFactory.registerSerializer(
PinReferenceEntity,
new GeneralSerializer(v => v, PinReferenceEntity, "", " ", false, "", _ => "")
)
SerializerFactory.registerSerializer(
ObjectReferenceEntity,
new CustomSerializer(
@@ -45,8 +57,12 @@ export default function initializeSerializerFactory() {
: ""
))
)
SerializerFactory.registerSerializer(Identifier, new ToStringSerializer(Identifier))
SerializerFactory.registerSerializer(IdentifierEntity, new ToStringSerializer(IdentifierEntity))
SerializerFactory.registerSerializer(PathSymbolEntity, new ToStringSerializer(PathSymbolEntity))
SerializerFactory.registerSerializer(GuidEntity, new ToStringSerializer(GuidEntity))
SerializerFactory.registerSerializer(IntegerEntity, new ToStringSerializer(IntegerEntity))
}

View File

@@ -28,6 +28,9 @@ export default class NodeTemplate extends SelectableDraggableTemplate {
<div class="ueb-node-outputs"></div>
</div>
</div>
<div class="ueb-node-expand">
<span class="ueb-node-expand-icon"></span>
</div>
</div>
`
}

View File

@@ -12,7 +12,6 @@ export default class SelectorTemplate extends ITemplate {
*/
apply(selector) {
super.apply(selector)
selector.classList.add("ueb-positioned")
this.applyFinishSelecting(selector)
}

View File

@@ -18,7 +18,7 @@ export default {
copy({
targets: [
{
src: ["font/*"],
src: ["assets/fonts/*"],
dest: "dist/font"
}
]

View File

@@ -6,12 +6,12 @@
}
.ueb-pin-boolean {
$ueb-pin-color : #930000;
$ueb-pin-color : rgb(30%, 0, 0);
--ueb-pin-color: #{$ueb-pin-color};
}
.ueb-pin-int {
$ueb-pin-color : #1fe0ad;
.ueb-pin-class {
$ueb-pin-color : #5800bb;
--ueb-pin-color: #{$ueb-pin-color};
}
@@ -20,8 +20,19 @@
--ueb-pin-color: #{$ueb-pin-color};
}
.ueb-pin-vector {
$ueb-pin-color : #fcc823;
.ueb-pin-int {
$ueb-pin-color : #1fe0ad;
--ueb-pin-color: #{$ueb-pin-color};
}
.ueb-pin-name {
$ueb-pin-color : #cb81fc;
--ueb-pin-color: #{$ueb-pin-color};
}
.ueb-pin-object {
$ueb-pin-color : #00a8f2;
$ueb-pin-color : rgba(0%, 40%, 01%);
--ueb-pin-color: #{$ueb-pin-color};
}
@@ -36,12 +47,7 @@
--ueb-pin-background: linear-gradient(90deg, #fc00d220, #fc00d280 15%, #fc00d250 85%, transparent);
}
.ueb-pin-name {
$ueb-pin-color : #cb81fc;
--ueb-pin-color: #{$ueb-pin-color};
}
.ueb-pin-object {
$ueb-pin-color : #00a8f2;
.ueb-pin-vector {
$ueb-pin-color : #fcc823;
--ueb-pin-color: #{$ueb-pin-color};
}

View File

@@ -262,6 +262,14 @@ ueb-blueprint[data-drag-scrolling="false"][data-selecting="false"] ueb-node {
padding-right: 8px;
}
.ueb-node-expand {
display: none;
}
ueb-node[data-advanced-display] .ueb-node-expand {
display: block;
}
ueb-pin {
display: block;
padding: 1px 2px;