dragon-graph-lib 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/dragon-graph-lib-global.js +229 -36
- package/src/dragon-graph-lib.css +6 -1
- package/src/dragon-graph-lib.js +227 -36
package/package.json
CHANGED
|
@@ -205,11 +205,6 @@ class Connector extends VisualElement
|
|
|
205
205
|
this.dom_items = {};
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
update_dom()
|
|
209
|
-
{
|
|
210
|
-
this.dom_items.label.textContent = this.label;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
208
|
/**
|
|
214
209
|
* Adds a connection to the connector
|
|
215
210
|
* @param {Connection} connection
|
|
@@ -265,13 +260,10 @@ class NodeInput extends Connector
|
|
|
265
260
|
container.classList.add("dgl-socketed");
|
|
266
261
|
}
|
|
267
262
|
|
|
268
|
-
this.dom_items.label = document.createElement("span");
|
|
269
|
-
this.dom_items.label.textContent = this.name;
|
|
270
|
-
this.dom_items.label.classList.add("dgl-label", "dgl-input-label");
|
|
271
|
-
container.appendChild(this.dom_items.label);
|
|
272
|
-
|
|
273
263
|
if ( this.control )
|
|
274
|
-
container.appendChild(this.control);
|
|
264
|
+
container.appendChild(this.control.to_dom(this.label, this.name));
|
|
265
|
+
else
|
|
266
|
+
container.appendChild(NodeControl.make_label(this.label));
|
|
275
267
|
|
|
276
268
|
return container;
|
|
277
269
|
}
|
|
@@ -288,7 +280,7 @@ class NodeInput extends Connector
|
|
|
288
280
|
this.connections.push(connection);
|
|
289
281
|
|
|
290
282
|
if ( this.control )
|
|
291
|
-
this.control.
|
|
283
|
+
this.control.hide();
|
|
292
284
|
}
|
|
293
285
|
|
|
294
286
|
/**
|
|
@@ -299,7 +291,7 @@ class NodeInput extends Connector
|
|
|
299
291
|
{
|
|
300
292
|
if ( this.control )
|
|
301
293
|
{
|
|
302
|
-
this.control.value
|
|
294
|
+
this.control.set_value(value);
|
|
303
295
|
}
|
|
304
296
|
}
|
|
305
297
|
|
|
@@ -330,7 +322,7 @@ class NodeInput extends Connector
|
|
|
330
322
|
return null;
|
|
331
323
|
}
|
|
332
324
|
|
|
333
|
-
let value = this.control.
|
|
325
|
+
let value = this.control.get_value();
|
|
334
326
|
if ( this.socket && this.socket.multi_input )
|
|
335
327
|
return [value];
|
|
336
328
|
return value;
|
|
@@ -340,7 +332,7 @@ class NodeInput extends Connector
|
|
|
340
332
|
{
|
|
341
333
|
super.disconnect(connection);
|
|
342
334
|
if ( this.control && this.connections.length == 0 )
|
|
343
|
-
this.control.
|
|
335
|
+
this.control.show();
|
|
344
336
|
}
|
|
345
337
|
}
|
|
346
338
|
|
|
@@ -402,7 +394,7 @@ class NodeOutput extends Connector
|
|
|
402
394
|
*/
|
|
403
395
|
get_value()
|
|
404
396
|
{
|
|
405
|
-
if ( this.value
|
|
397
|
+
if ( this.value === undefined || this.node.dirty )
|
|
406
398
|
this.node.evaluate();
|
|
407
399
|
return this.value;
|
|
408
400
|
}
|
|
@@ -415,23 +407,199 @@ function force_default(ev)
|
|
|
415
407
|
}
|
|
416
408
|
|
|
417
409
|
/**
|
|
418
|
-
*
|
|
419
|
-
* @param {string} type Input type
|
|
420
|
-
* @param {object} attrs Input attributes as an object
|
|
421
|
-
* @returns {HTMLInputElement}
|
|
410
|
+
* Custom control interface
|
|
422
411
|
*/
|
|
423
|
-
|
|
412
|
+
class NodeControl
|
|
424
413
|
{
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
414
|
+
/**
|
|
415
|
+
* @param {object} config Control config
|
|
416
|
+
* @param {any} config.default Control default value
|
|
417
|
+
*/
|
|
418
|
+
constructor(config={})
|
|
419
|
+
{
|
|
420
|
+
this.on_change = null;
|
|
421
|
+
this.config = config;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
to_dom(label, name)
|
|
425
|
+
{
|
|
426
|
+
this.element = document.createElement("div");
|
|
427
|
+
this.element.classList.add("dgl-control-parent");
|
|
428
|
+
if ( label.length )
|
|
429
|
+
this.element.appendChild(NodeControl.make_label(label));
|
|
430
|
+
this.setup_dom(this.element, name);
|
|
431
|
+
if ( "default" in this.config )
|
|
432
|
+
this.set_value(this.config.default);
|
|
433
|
+
return this.element;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Sets up the DOM
|
|
438
|
+
* @param {HTMLElement} parent Element to add additional content to
|
|
439
|
+
* @param {name} name Control name
|
|
440
|
+
*/
|
|
441
|
+
setup_dom(_parent, _name)
|
|
442
|
+
{
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Dispatches the change event to update the graph
|
|
447
|
+
*/
|
|
448
|
+
notify_change()
|
|
449
|
+
{
|
|
450
|
+
this.on_change();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Override to return the control value
|
|
455
|
+
* @returns {any} value
|
|
456
|
+
*/
|
|
457
|
+
get_value()
|
|
458
|
+
{
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Override to return set a value to the control
|
|
463
|
+
* @param {any} value
|
|
464
|
+
*/
|
|
465
|
+
set_value(_value)
|
|
466
|
+
{
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Ensures an element uses the default mouse interactions instead of
|
|
471
|
+
* propagating to the node editor
|
|
472
|
+
*/
|
|
473
|
+
use_default_events(element)
|
|
474
|
+
{
|
|
475
|
+
element.addEventListener("mousedown", force_default);
|
|
476
|
+
element.addEventListener("mouseup", force_default);
|
|
477
|
+
element.addEventListener("mousemove", force_default);
|
|
478
|
+
element.addEventListener("wheel", force_default);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Creates a label element
|
|
483
|
+
* @param {string} label Text to display
|
|
484
|
+
*/
|
|
485
|
+
static make_label(label)
|
|
486
|
+
{
|
|
487
|
+
let elem = document.createElement("span");
|
|
488
|
+
elem.textContent = label;
|
|
489
|
+
elem.classList.add("dgl-label", "dgl-input-label");
|
|
490
|
+
return elem;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
set_visibility(value)
|
|
494
|
+
{
|
|
495
|
+
for ( let ch of this.element.children )
|
|
496
|
+
if ( !ch.classList.contains("dgl-label") )
|
|
497
|
+
ch.style.visibility = value;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Hides the control when an input connection is attached
|
|
502
|
+
*/
|
|
503
|
+
hide()
|
|
504
|
+
{
|
|
505
|
+
this.set_visibility("hidden");
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Shows the control when an input connection is detached
|
|
510
|
+
*/
|
|
511
|
+
show()
|
|
512
|
+
{
|
|
513
|
+
this.set_visibility("visible");
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Control for simple input elements
|
|
519
|
+
*/
|
|
520
|
+
class InputControl extends NodeControl
|
|
521
|
+
{
|
|
522
|
+
/**
|
|
523
|
+
* @param {object} config Control config
|
|
524
|
+
* @param {string} config.type Input type
|
|
525
|
+
* @param {object} config.attrs Input attributes
|
|
526
|
+
* @param {any} config.default Default value
|
|
527
|
+
*/
|
|
528
|
+
constructor(config={type: "text"})
|
|
529
|
+
{
|
|
530
|
+
super(config);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
setup_dom(parent, name)
|
|
534
|
+
{
|
|
535
|
+
this.input = document.createElement("input");
|
|
536
|
+
parent.appendChild(this.input);
|
|
537
|
+
this.input.type = this.config.type;
|
|
538
|
+
this.input.classList.add("dgl-control");
|
|
539
|
+
for ( let [k, v] of Object.entries(this.config.attrs ?? {}) )
|
|
540
|
+
this.input.setAttribute(k, v);
|
|
541
|
+
this.use_default_events(this.input);
|
|
542
|
+
this.input.name = name;
|
|
543
|
+
this.input.addEventListener("input", () => this.notify_change());
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
get_value()
|
|
547
|
+
{
|
|
548
|
+
if ( this.config.type == "checkbox" )
|
|
549
|
+
return this.input.checked;
|
|
550
|
+
return this.input.value;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
set_value(value)
|
|
554
|
+
{
|
|
555
|
+
if ( this.config.type == "checkbox" )
|
|
556
|
+
this.input.checked = value;
|
|
557
|
+
else
|
|
558
|
+
this.input.value = value;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Drop-down Control
|
|
564
|
+
*/
|
|
565
|
+
class DropDownControl extends NodeControl
|
|
566
|
+
{
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* @param {object} config Control config
|
|
570
|
+
* @param {Array.<string, string>} config.options Drop down options ([value, display])
|
|
571
|
+
* @param {any} config.default Default value
|
|
572
|
+
*/
|
|
573
|
+
constructor(config={options: []})
|
|
574
|
+
{
|
|
575
|
+
super(config);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
setup_dom(parent, name)
|
|
579
|
+
{
|
|
580
|
+
this.input = document.createElement("select");
|
|
581
|
+
for ( let [value, display] of this.config.options )
|
|
582
|
+
{
|
|
583
|
+
let option = document.createElement("option");
|
|
584
|
+
this.input.appendChild(option);
|
|
585
|
+
option.value = value;
|
|
586
|
+
option.textContent = display ?? value;
|
|
587
|
+
}
|
|
588
|
+
this.input.name = name;
|
|
589
|
+
parent.appendChild(this.input);
|
|
590
|
+
this.use_default_events(this.input);
|
|
591
|
+
this.input.addEventListener("input", () => this.notify_change());
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
get_value()
|
|
595
|
+
{
|
|
596
|
+
return this.input.value;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
set_value(value)
|
|
600
|
+
{
|
|
601
|
+
this.input.value = value;
|
|
602
|
+
}
|
|
435
603
|
}
|
|
436
604
|
|
|
437
605
|
/**
|
|
@@ -473,6 +641,7 @@ class Node extends VisualElement
|
|
|
473
641
|
* @member {number}
|
|
474
642
|
*/
|
|
475
643
|
this.y = 0;
|
|
644
|
+
this.dirty = true;
|
|
476
645
|
}
|
|
477
646
|
|
|
478
647
|
/**
|
|
@@ -575,6 +744,7 @@ class Node extends VisualElement
|
|
|
575
744
|
|
|
576
745
|
evaluate()
|
|
577
746
|
{
|
|
747
|
+
this.dirty = false;
|
|
578
748
|
if ( this.type )
|
|
579
749
|
this.type.evaluate_node(this);
|
|
580
750
|
}
|
|
@@ -694,11 +864,17 @@ class ContextMenu extends VisualElement
|
|
|
694
864
|
|
|
695
865
|
to_dom(editor)
|
|
696
866
|
{
|
|
697
|
-
this.dom = this.
|
|
698
|
-
this.dom.style.display = "none";
|
|
867
|
+
this.dom = this.build(editor);
|
|
699
868
|
return this.dom;
|
|
700
869
|
}
|
|
701
870
|
|
|
871
|
+
build(editor)
|
|
872
|
+
{
|
|
873
|
+
let dom = this.make_menu("dgl-menu", this.actions, editor);
|
|
874
|
+
dom.style.display = "none";
|
|
875
|
+
return dom;
|
|
876
|
+
}
|
|
877
|
+
|
|
702
878
|
make_action(title, action, editor)
|
|
703
879
|
{
|
|
704
880
|
let onclick = action;
|
|
@@ -773,6 +949,18 @@ class ContextMenu extends VisualElement
|
|
|
773
949
|
{
|
|
774
950
|
this.dom.style.display = "none";
|
|
775
951
|
}
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* Rebuilds the DOM element
|
|
955
|
+
*/
|
|
956
|
+
rebuild(editor)
|
|
957
|
+
{
|
|
958
|
+
let parent = this.dom.parentNode;
|
|
959
|
+
let old_e = this.dom;
|
|
960
|
+
let new_e = this.build(editor);
|
|
961
|
+
parent.replaceChild(new_e, old_e);
|
|
962
|
+
this.dom = new_e;
|
|
963
|
+
}
|
|
776
964
|
}
|
|
777
965
|
|
|
778
966
|
/**
|
|
@@ -845,7 +1033,6 @@ class Editor
|
|
|
845
1033
|
this.container.appendChild(this.context_menu.to_dom(this));
|
|
846
1034
|
}
|
|
847
1035
|
|
|
848
|
-
|
|
849
1036
|
/**
|
|
850
1037
|
* Adds a new node to the graph
|
|
851
1038
|
* @param {Node} node
|
|
@@ -865,7 +1052,10 @@ class Editor
|
|
|
865
1052
|
{
|
|
866
1053
|
if ( input.control )
|
|
867
1054
|
{
|
|
868
|
-
input.control.
|
|
1055
|
+
input.control.on_change = () => {
|
|
1056
|
+
node.dirty = true;
|
|
1057
|
+
this._refresh_graph();
|
|
1058
|
+
};
|
|
869
1059
|
}
|
|
870
1060
|
}
|
|
871
1061
|
}
|
|
@@ -896,8 +1086,9 @@ class Editor
|
|
|
896
1086
|
create_node(type, data={})
|
|
897
1087
|
{
|
|
898
1088
|
let node = type.create_node();
|
|
899
|
-
node.set_input_value(data);
|
|
900
1089
|
this.add_node(node);
|
|
1090
|
+
node.set_input_value(data);
|
|
1091
|
+
this._refresh_graph();
|
|
901
1092
|
return node;
|
|
902
1093
|
}
|
|
903
1094
|
|
|
@@ -1333,6 +1524,8 @@ Connection,
|
|
|
1333
1524
|
NodeInput,
|
|
1334
1525
|
NodeOutput,
|
|
1335
1526
|
NodeControl,
|
|
1527
|
+
InputControl,
|
|
1528
|
+
DropDownControl,
|
|
1336
1529
|
Node,
|
|
1337
1530
|
NodeType,
|
|
1338
1531
|
ContextMenu,
|
package/src/dragon-graph-lib.css
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
width: fit-content;
|
|
52
52
|
display: flex;
|
|
53
53
|
flex-flow: column;
|
|
54
|
-
gap:
|
|
54
|
+
gap: var(--dgl-node-padding);
|
|
55
55
|
cursor: pointer;
|
|
56
56
|
user-select: none;
|
|
57
57
|
border: 1px solid var(--dgl-node-text);
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
stroke-width: var( --dgl-connection-width);
|
|
81
81
|
fill: none;
|
|
82
82
|
}
|
|
83
|
+
|
|
83
84
|
.dgl-preview {
|
|
84
85
|
max-width: 20ch;
|
|
85
86
|
}
|
|
@@ -100,6 +101,10 @@
|
|
|
100
101
|
position: relative;
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
.dgl-input-label {
|
|
105
|
+
margin-right: var(--dgl-node-padding);
|
|
106
|
+
}
|
|
107
|
+
|
|
103
108
|
.dgl-output {
|
|
104
109
|
justify-content: end;
|
|
105
110
|
left: calc(var(--dgl-node-padding) + var(--dgl-socket-size) / 2);
|
package/src/dragon-graph-lib.js
CHANGED
|
@@ -204,11 +204,6 @@ class Connector extends VisualElement
|
|
|
204
204
|
this.dom_items = {};
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
update_dom()
|
|
208
|
-
{
|
|
209
|
-
this.dom_items.label.textContent = this.label;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
207
|
/**
|
|
213
208
|
* Adds a connection to the connector
|
|
214
209
|
* @param {Connection} connection
|
|
@@ -264,13 +259,10 @@ export class NodeInput extends Connector
|
|
|
264
259
|
container.classList.add("dgl-socketed");
|
|
265
260
|
}
|
|
266
261
|
|
|
267
|
-
this.dom_items.label = document.createElement("span");
|
|
268
|
-
this.dom_items.label.textContent = this.name;
|
|
269
|
-
this.dom_items.label.classList.add("dgl-label", "dgl-input-label");
|
|
270
|
-
container.appendChild(this.dom_items.label);
|
|
271
|
-
|
|
272
262
|
if ( this.control )
|
|
273
|
-
container.appendChild(this.control);
|
|
263
|
+
container.appendChild(this.control.to_dom(this.label, this.name));
|
|
264
|
+
else
|
|
265
|
+
container.appendChild(NodeControl.make_label(this.label));
|
|
274
266
|
|
|
275
267
|
return container;
|
|
276
268
|
}
|
|
@@ -287,7 +279,7 @@ export class NodeInput extends Connector
|
|
|
287
279
|
this.connections.push(connection);
|
|
288
280
|
|
|
289
281
|
if ( this.control )
|
|
290
|
-
this.control.
|
|
282
|
+
this.control.hide();
|
|
291
283
|
}
|
|
292
284
|
|
|
293
285
|
/**
|
|
@@ -298,7 +290,7 @@ export class NodeInput extends Connector
|
|
|
298
290
|
{
|
|
299
291
|
if ( this.control )
|
|
300
292
|
{
|
|
301
|
-
this.control.value
|
|
293
|
+
this.control.set_value(value);
|
|
302
294
|
}
|
|
303
295
|
}
|
|
304
296
|
|
|
@@ -329,7 +321,7 @@ export class NodeInput extends Connector
|
|
|
329
321
|
return null;
|
|
330
322
|
}
|
|
331
323
|
|
|
332
|
-
let value = this.control.
|
|
324
|
+
let value = this.control.get_value();
|
|
333
325
|
if ( this.socket && this.socket.multi_input )
|
|
334
326
|
return [value];
|
|
335
327
|
return value;
|
|
@@ -339,7 +331,7 @@ export class NodeInput extends Connector
|
|
|
339
331
|
{
|
|
340
332
|
super.disconnect(connection);
|
|
341
333
|
if ( this.control && this.connections.length == 0 )
|
|
342
|
-
this.control.
|
|
334
|
+
this.control.show();
|
|
343
335
|
}
|
|
344
336
|
}
|
|
345
337
|
|
|
@@ -401,7 +393,7 @@ export class NodeOutput extends Connector
|
|
|
401
393
|
*/
|
|
402
394
|
get_value()
|
|
403
395
|
{
|
|
404
|
-
if ( this.value
|
|
396
|
+
if ( this.value === undefined || this.node.dirty )
|
|
405
397
|
this.node.evaluate();
|
|
406
398
|
return this.value;
|
|
407
399
|
}
|
|
@@ -414,23 +406,199 @@ function force_default(ev)
|
|
|
414
406
|
}
|
|
415
407
|
|
|
416
408
|
/**
|
|
417
|
-
*
|
|
418
|
-
* @param {string} type Input type
|
|
419
|
-
* @param {object} attrs Input attributes as an object
|
|
420
|
-
* @returns {HTMLInputElement}
|
|
409
|
+
* Custom control interface
|
|
421
410
|
*/
|
|
422
|
-
export
|
|
411
|
+
export class NodeControl
|
|
423
412
|
{
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
413
|
+
/**
|
|
414
|
+
* @param {object} config Control config
|
|
415
|
+
* @param {any} config.default Control default value
|
|
416
|
+
*/
|
|
417
|
+
constructor(config={})
|
|
418
|
+
{
|
|
419
|
+
this.on_change = null;
|
|
420
|
+
this.config = config;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
to_dom(label, name)
|
|
424
|
+
{
|
|
425
|
+
this.element = document.createElement("div");
|
|
426
|
+
this.element.classList.add("dgl-control-parent");
|
|
427
|
+
if ( label.length )
|
|
428
|
+
this.element.appendChild(NodeControl.make_label(label));
|
|
429
|
+
this.setup_dom(this.element, name);
|
|
430
|
+
if ( "default" in this.config )
|
|
431
|
+
this.set_value(this.config.default);
|
|
432
|
+
return this.element;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Sets up the DOM
|
|
437
|
+
* @param {HTMLElement} parent Element to add additional content to
|
|
438
|
+
* @param {name} name Control name
|
|
439
|
+
*/
|
|
440
|
+
setup_dom(_parent, _name)
|
|
441
|
+
{
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Dispatches the change event to update the graph
|
|
446
|
+
*/
|
|
447
|
+
notify_change()
|
|
448
|
+
{
|
|
449
|
+
this.on_change();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Override to return the control value
|
|
454
|
+
* @returns {any} value
|
|
455
|
+
*/
|
|
456
|
+
get_value()
|
|
457
|
+
{
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Override to return set a value to the control
|
|
462
|
+
* @param {any} value
|
|
463
|
+
*/
|
|
464
|
+
set_value(_value)
|
|
465
|
+
{
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Ensures an element uses the default mouse interactions instead of
|
|
470
|
+
* propagating to the node editor
|
|
471
|
+
*/
|
|
472
|
+
use_default_events(element)
|
|
473
|
+
{
|
|
474
|
+
element.addEventListener("mousedown", force_default);
|
|
475
|
+
element.addEventListener("mouseup", force_default);
|
|
476
|
+
element.addEventListener("mousemove", force_default);
|
|
477
|
+
element.addEventListener("wheel", force_default);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Creates a label element
|
|
482
|
+
* @param {string} label Text to display
|
|
483
|
+
*/
|
|
484
|
+
static make_label(label)
|
|
485
|
+
{
|
|
486
|
+
let elem = document.createElement("span");
|
|
487
|
+
elem.textContent = label;
|
|
488
|
+
elem.classList.add("dgl-label", "dgl-input-label");
|
|
489
|
+
return elem;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
set_visibility(value)
|
|
493
|
+
{
|
|
494
|
+
for ( let ch of this.element.children )
|
|
495
|
+
if ( !ch.classList.contains("dgl-label") )
|
|
496
|
+
ch.style.visibility = value;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Hides the control when an input connection is attached
|
|
501
|
+
*/
|
|
502
|
+
hide()
|
|
503
|
+
{
|
|
504
|
+
this.set_visibility("hidden");
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Shows the control when an input connection is detached
|
|
509
|
+
*/
|
|
510
|
+
show()
|
|
511
|
+
{
|
|
512
|
+
this.set_visibility("visible");
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Control for simple input elements
|
|
518
|
+
*/
|
|
519
|
+
export class InputControl extends NodeControl
|
|
520
|
+
{
|
|
521
|
+
/**
|
|
522
|
+
* @param {object} config Control config
|
|
523
|
+
* @param {string} config.type Input type
|
|
524
|
+
* @param {object} config.attrs Input attributes
|
|
525
|
+
* @param {any} config.default Default value
|
|
526
|
+
*/
|
|
527
|
+
constructor(config={type: "text"})
|
|
528
|
+
{
|
|
529
|
+
super(config);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
setup_dom(parent, name)
|
|
533
|
+
{
|
|
534
|
+
this.input = document.createElement("input");
|
|
535
|
+
parent.appendChild(this.input);
|
|
536
|
+
this.input.type = this.config.type;
|
|
537
|
+
this.input.classList.add("dgl-control");
|
|
538
|
+
for ( let [k, v] of Object.entries(this.config.attrs ?? {}) )
|
|
539
|
+
this.input.setAttribute(k, v);
|
|
540
|
+
this.use_default_events(this.input);
|
|
541
|
+
this.input.name = name;
|
|
542
|
+
this.input.addEventListener("input", () => this.notify_change());
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
get_value()
|
|
546
|
+
{
|
|
547
|
+
if ( this.config.type == "checkbox" )
|
|
548
|
+
return this.input.checked;
|
|
549
|
+
return this.input.value;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
set_value(value)
|
|
553
|
+
{
|
|
554
|
+
if ( this.config.type == "checkbox" )
|
|
555
|
+
this.input.checked = value;
|
|
556
|
+
else
|
|
557
|
+
this.input.value = value;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Drop-down Control
|
|
563
|
+
*/
|
|
564
|
+
export class DropDownControl extends NodeControl
|
|
565
|
+
{
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* @param {object} config Control config
|
|
569
|
+
* @param {Array.<string, string>} config.options Drop down options ([value, display])
|
|
570
|
+
* @param {any} config.default Default value
|
|
571
|
+
*/
|
|
572
|
+
constructor(config={options: []})
|
|
573
|
+
{
|
|
574
|
+
super(config);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
setup_dom(parent, name)
|
|
578
|
+
{
|
|
579
|
+
this.input = document.createElement("select");
|
|
580
|
+
for ( let [value, display] of this.config.options )
|
|
581
|
+
{
|
|
582
|
+
let option = document.createElement("option");
|
|
583
|
+
this.input.appendChild(option);
|
|
584
|
+
option.value = value;
|
|
585
|
+
option.textContent = display ?? value;
|
|
586
|
+
}
|
|
587
|
+
this.input.name = name;
|
|
588
|
+
parent.appendChild(this.input);
|
|
589
|
+
this.use_default_events(this.input);
|
|
590
|
+
this.input.addEventListener("input", () => this.notify_change());
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
get_value()
|
|
594
|
+
{
|
|
595
|
+
return this.input.value;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
set_value(value)
|
|
599
|
+
{
|
|
600
|
+
this.input.value = value;
|
|
601
|
+
}
|
|
434
602
|
}
|
|
435
603
|
|
|
436
604
|
/**
|
|
@@ -472,6 +640,7 @@ export class Node extends VisualElement
|
|
|
472
640
|
* @member {number}
|
|
473
641
|
*/
|
|
474
642
|
this.y = 0;
|
|
643
|
+
this.dirty = true;
|
|
475
644
|
}
|
|
476
645
|
|
|
477
646
|
/**
|
|
@@ -574,6 +743,7 @@ export class Node extends VisualElement
|
|
|
574
743
|
|
|
575
744
|
evaluate()
|
|
576
745
|
{
|
|
746
|
+
this.dirty = false;
|
|
577
747
|
if ( this.type )
|
|
578
748
|
this.type.evaluate_node(this);
|
|
579
749
|
}
|
|
@@ -693,11 +863,17 @@ export class ContextMenu extends VisualElement
|
|
|
693
863
|
|
|
694
864
|
to_dom(editor)
|
|
695
865
|
{
|
|
696
|
-
this.dom = this.
|
|
697
|
-
this.dom.style.display = "none";
|
|
866
|
+
this.dom = this.build(editor);
|
|
698
867
|
return this.dom;
|
|
699
868
|
}
|
|
700
869
|
|
|
870
|
+
build(editor)
|
|
871
|
+
{
|
|
872
|
+
let dom = this.make_menu("dgl-menu", this.actions, editor);
|
|
873
|
+
dom.style.display = "none";
|
|
874
|
+
return dom;
|
|
875
|
+
}
|
|
876
|
+
|
|
701
877
|
make_action(title, action, editor)
|
|
702
878
|
{
|
|
703
879
|
let onclick = action;
|
|
@@ -772,6 +948,18 @@ export class ContextMenu extends VisualElement
|
|
|
772
948
|
{
|
|
773
949
|
this.dom.style.display = "none";
|
|
774
950
|
}
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* Rebuilds the DOM element
|
|
954
|
+
*/
|
|
955
|
+
rebuild(editor)
|
|
956
|
+
{
|
|
957
|
+
let parent = this.dom.parentNode;
|
|
958
|
+
let old_e = this.dom;
|
|
959
|
+
let new_e = this.build(editor);
|
|
960
|
+
parent.replaceChild(new_e, old_e);
|
|
961
|
+
this.dom = new_e;
|
|
962
|
+
}
|
|
775
963
|
}
|
|
776
964
|
|
|
777
965
|
/**
|
|
@@ -844,7 +1032,6 @@ export class Editor
|
|
|
844
1032
|
this.container.appendChild(this.context_menu.to_dom(this));
|
|
845
1033
|
}
|
|
846
1034
|
|
|
847
|
-
|
|
848
1035
|
/**
|
|
849
1036
|
* Adds a new node to the graph
|
|
850
1037
|
* @param {Node} node
|
|
@@ -864,7 +1051,10 @@ export class Editor
|
|
|
864
1051
|
{
|
|
865
1052
|
if ( input.control )
|
|
866
1053
|
{
|
|
867
|
-
input.control.
|
|
1054
|
+
input.control.on_change = () => {
|
|
1055
|
+
node.dirty = true;
|
|
1056
|
+
this._refresh_graph();
|
|
1057
|
+
};
|
|
868
1058
|
}
|
|
869
1059
|
}
|
|
870
1060
|
}
|
|
@@ -895,8 +1085,9 @@ export class Editor
|
|
|
895
1085
|
create_node(type, data={})
|
|
896
1086
|
{
|
|
897
1087
|
let node = type.create_node();
|
|
898
|
-
node.set_input_value(data);
|
|
899
1088
|
this.add_node(node);
|
|
1089
|
+
node.set_input_value(data);
|
|
1090
|
+
this._refresh_graph();
|
|
900
1091
|
return node;
|
|
901
1092
|
}
|
|
902
1093
|
|