@metadev/daga 1.4.1 → 1.4.2
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/Changelog.md +18 -1
- package/assets/styles/_property-editor.scss +225 -157
- package/assets/styles/daga.scss +149 -156
- package/fesm2022/metadev-daga.mjs +1537 -592
- package/fesm2022/metadev-daga.mjs.map +1 -1
- package/index.d.ts +5 -3
- package/lib/daga.module.d.ts +4 -5
- package/lib/diagram-editor/diagram/collab/collab-action.d.ts +90 -0
- package/lib/diagram-editor/diagram/collab/collab-client.d.ts +57 -0
- package/lib/diagram-editor/diagram/collab/collab-engine.d.ts +46 -0
- package/lib/diagram-editor/diagram/collab/message-types.d.ts +97 -0
- package/lib/diagram-editor/diagram/collab/primitives.d.ts +15 -0
- package/lib/diagram-editor/diagram/converters/daga-model.d.ts +3 -0
- package/lib/diagram-editor/diagram/diagram-action.d.ts +27 -19
- package/lib/diagram-editor/diagram/diagram-canvas.d.ts +3 -1
- package/lib/diagram-editor/diagram/diagram-connection.d.ts +35 -3
- package/lib/diagram-editor/diagram/diagram-element.d.ts +7 -2
- package/lib/diagram-editor/diagram/diagram-field.d.ts +13 -2
- package/lib/diagram-editor/diagram/diagram-model.d.ts +6 -0
- package/lib/diagram-editor/diagram/diagram-node.d.ts +67 -3
- package/lib/diagram-editor/diagram/diagram-port.d.ts +28 -2
- package/lib/diagram-editor/diagram/diagram-property.d.ts +143 -19
- package/lib/diagram-editor/diagram/diagram-section.d.ts +40 -3
- package/lib/interfaces/canvas.d.ts +7 -0
- package/lib/property-editor/autocomplete/autocomplete.component.d.ts +39 -0
- package/lib/{object-editor → property-editor/object-editor}/object-editor.component.d.ts +5 -6
- package/lib/property-editor/option-list-editor/option-list-editor.component.d.ts +29 -0
- package/lib/{text-list-editor → property-editor/text-list-editor}/text-list-editor.component.d.ts +2 -2
- package/lib/{text-map-editor → property-editor/text-map-editor}/text-map-editor.component.d.ts +2 -2
- package/package.json +3 -3
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as i1 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { ElementRef, Component, Input, Injectable, ViewChild, EventEmitter, Output, NgModule } from '@angular/core';
|
|
5
5
|
import * as d3 from 'd3';
|
|
6
|
-
import * as
|
|
6
|
+
import * as i2 from '@angular/forms';
|
|
7
7
|
import { FormsModule } from '@angular/forms';
|
|
8
|
-
import * as i3 from '@metadev/lux';
|
|
9
|
-
import { LuxModule } from '@metadev/lux';
|
|
10
8
|
import { Subject, merge, delay, map } from 'rxjs';
|
|
9
|
+
import { v4 } from 'uuid';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* An enumeration of the possible sides of a rectangle and directions parallel to the axes of coordinates.
|
|
@@ -243,6 +242,100 @@ const addIfNotExists = (arr, obj) => {
|
|
|
243
242
|
return arr;
|
|
244
243
|
};
|
|
245
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Returns whether the incoming timestamp wins over the existing timestamp.
|
|
247
|
+
*
|
|
248
|
+
* In the DiagramModel, timestamps that have never been set are left undefined;
|
|
249
|
+
* `timestampWins` treats that as an "initial timestamp" that loses to all LogicalTimestamps.
|
|
250
|
+
*/
|
|
251
|
+
function timestampWins(incoming, existing) {
|
|
252
|
+
if (existing === undefined)
|
|
253
|
+
return true;
|
|
254
|
+
if (incoming[0] > existing[0])
|
|
255
|
+
return true;
|
|
256
|
+
if (incoming[0] === existing[0]) {
|
|
257
|
+
// In case of equality, declare the incoming timestamp the "winner".
|
|
258
|
+
// This occurs if a client reuses a timestamp for multiple actions in a row,
|
|
259
|
+
// in which case the last created should win.
|
|
260
|
+
return incoming[1] >= existing[1];
|
|
261
|
+
}
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Collaborative action which consists of adding a node.
|
|
267
|
+
* @see AddNodeAction
|
|
268
|
+
* @private
|
|
269
|
+
*/
|
|
270
|
+
class AddNodeCollabAction {
|
|
271
|
+
constructor(canvas, id, nodeTypeId, coords, label, values) {
|
|
272
|
+
this.canvas = canvas;
|
|
273
|
+
this.id = id;
|
|
274
|
+
this.nodeTypeId = nodeTypeId;
|
|
275
|
+
this.coords = coords;
|
|
276
|
+
this.label = label;
|
|
277
|
+
this.values = values;
|
|
278
|
+
}
|
|
279
|
+
do() {
|
|
280
|
+
const node = this.canvas.model.nodes.new(this.nodeTypeId, this.coords, this.id);
|
|
281
|
+
if (this.values !== undefined) {
|
|
282
|
+
node.valueSet.setValues(structuredClone({
|
|
283
|
+
...node.valueSet.getValues(),
|
|
284
|
+
...this.values
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
if (node.label) {
|
|
288
|
+
node.label.text = this.label || '';
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
serialize() {
|
|
292
|
+
return {
|
|
293
|
+
type: 'add',
|
|
294
|
+
id: this.id,
|
|
295
|
+
nodeTypeId: this.nodeTypeId,
|
|
296
|
+
coords: this.coords,
|
|
297
|
+
label: this.label,
|
|
298
|
+
values: this.values
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
static deserialize(canvas, serialized) {
|
|
302
|
+
return new AddNodeCollabAction(canvas, serialized.id, serialized.nodeTypeId, serialized.coords, serialized.label, serialized.values);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Collaborative action which consists of moving a node.
|
|
307
|
+
* @see MoveNodeAction
|
|
308
|
+
* @private
|
|
309
|
+
*/
|
|
310
|
+
class MoveNodeCollabAction {
|
|
311
|
+
constructor(canvas, nodeId, to, timestamp) {
|
|
312
|
+
this.canvas = canvas;
|
|
313
|
+
this.nodeId = nodeId;
|
|
314
|
+
this.to = to;
|
|
315
|
+
this.timestamp = timestamp;
|
|
316
|
+
}
|
|
317
|
+
do() {
|
|
318
|
+
const node = this.canvas.model.nodes.get(this.nodeId);
|
|
319
|
+
if (!node)
|
|
320
|
+
return;
|
|
321
|
+
if (timestampWins(this.timestamp, node.coordsTimestamp)) {
|
|
322
|
+
node.move(this.to);
|
|
323
|
+
node.coordsTimestamp = this.timestamp;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
serialize() {
|
|
327
|
+
return {
|
|
328
|
+
type: 'move',
|
|
329
|
+
nodeId: this.nodeId,
|
|
330
|
+
to: this.to,
|
|
331
|
+
timestamp: this.timestamp
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
static deserialize(canvas, serialized) {
|
|
335
|
+
return new MoveNodeCollabAction(canvas, serialized.nodeId, serialized.to, serialized.timestamp);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
246
339
|
/**
|
|
247
340
|
* A queue of recent actions taken by the user that can be undone and redone.
|
|
248
341
|
* @private
|
|
@@ -362,38 +455,71 @@ var DiagramActions;
|
|
|
362
455
|
* @private
|
|
363
456
|
*/
|
|
364
457
|
class AddNodeAction {
|
|
365
|
-
constructor(canvas, type, coords, label, values
|
|
458
|
+
constructor(canvas, type, coords, label, values) {
|
|
366
459
|
this.canvas = canvas;
|
|
367
460
|
this.type = type;
|
|
368
461
|
this.coords = coords;
|
|
369
462
|
this.label = label;
|
|
370
463
|
this.values = values;
|
|
371
|
-
this.id =
|
|
464
|
+
this.id = this.canvas.collabEngine.freshId();
|
|
465
|
+
}
|
|
466
|
+
do() {
|
|
467
|
+
const collabAction = new AddNodeCollabAction(this.canvas, this.id, this.type.id, this.coords, this.label, this.values);
|
|
468
|
+
this.canvas.collabEngine.doCollaboratively(collabAction);
|
|
372
469
|
}
|
|
373
470
|
undo() {
|
|
374
|
-
|
|
375
|
-
|
|
471
|
+
const node = this.canvas.model.nodes.get(this.id);
|
|
472
|
+
if (node) {
|
|
473
|
+
node.removed = true;
|
|
474
|
+
for (const section of node.sections) {
|
|
475
|
+
section.removed = true;
|
|
476
|
+
for (const port of section.ports) {
|
|
477
|
+
port.removed = true;
|
|
478
|
+
port.updateInView();
|
|
479
|
+
}
|
|
480
|
+
if (section.label) {
|
|
481
|
+
section.label.removed = true;
|
|
482
|
+
section.label.updateInView();
|
|
483
|
+
}
|
|
484
|
+
section.updateInView();
|
|
485
|
+
}
|
|
486
|
+
for (const port of node.ports) {
|
|
487
|
+
port.removed = true;
|
|
488
|
+
port.updateInView();
|
|
489
|
+
}
|
|
490
|
+
if (node.label) {
|
|
491
|
+
node.label.removed = true;
|
|
492
|
+
node.label.updateInView();
|
|
493
|
+
}
|
|
494
|
+
node.updateInView();
|
|
376
495
|
}
|
|
377
496
|
}
|
|
378
497
|
redo() {
|
|
379
|
-
const node = this.canvas.model.nodes.
|
|
380
|
-
if (
|
|
381
|
-
node.
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
498
|
+
const node = this.canvas.model.nodes.get(this.id);
|
|
499
|
+
if (node) {
|
|
500
|
+
node.removed = false;
|
|
501
|
+
for (const section of node.sections) {
|
|
502
|
+
section.removed = false;
|
|
503
|
+
for (const port of section.ports) {
|
|
504
|
+
port.removed = false;
|
|
505
|
+
port.updateInView();
|
|
506
|
+
}
|
|
507
|
+
if (section.label) {
|
|
508
|
+
section.label.removed = false;
|
|
509
|
+
section.label.updateInView();
|
|
510
|
+
}
|
|
511
|
+
section.updateInView();
|
|
512
|
+
}
|
|
513
|
+
for (const port of node.ports) {
|
|
514
|
+
port.removed = false;
|
|
515
|
+
port.updateInView();
|
|
516
|
+
}
|
|
517
|
+
if (node.label) {
|
|
518
|
+
node.label.removed = false;
|
|
519
|
+
node.label.updateInView();
|
|
520
|
+
}
|
|
521
|
+
node.updateInView();
|
|
388
522
|
}
|
|
389
|
-
// reset our ids in case they were automatically generated
|
|
390
|
-
this.id = node.id;
|
|
391
|
-
this.sectionIds = node.sections.map((s) => s.id);
|
|
392
|
-
this.sectionPortIds = node.sections.map((s) => s.ports.map((p) => p.id));
|
|
393
|
-
this.sectionPortLabelIds = node.sections.map((s) => s.ports.map((p) => p.label?.id));
|
|
394
|
-
this.portIds = node.ports.map((p) => p.id);
|
|
395
|
-
this.portLabelIds = node.ports.map((p) => p.label?.id);
|
|
396
|
-
this.labelId = node.label?.id;
|
|
397
523
|
}
|
|
398
524
|
}
|
|
399
525
|
/**
|
|
@@ -408,11 +534,16 @@ class MoveNodeAction {
|
|
|
408
534
|
this.from = from;
|
|
409
535
|
this.to = to;
|
|
410
536
|
}
|
|
537
|
+
do() {
|
|
538
|
+
const collabAction = new MoveNodeCollabAction(this.canvas, this.nodeId, this.to, this.canvas.collabEngine.freshTimestamp());
|
|
539
|
+
this.canvas.collabEngine.doCollaboratively(collabAction);
|
|
540
|
+
}
|
|
411
541
|
undo() {
|
|
412
|
-
this.canvas
|
|
542
|
+
const collabAction = new MoveNodeCollabAction(this.canvas, this.nodeId, this.from, this.canvas.collabEngine.freshTimestamp());
|
|
543
|
+
this.canvas.collabEngine.doCollaboratively(collabAction);
|
|
413
544
|
}
|
|
414
545
|
redo() {
|
|
415
|
-
this.
|
|
546
|
+
this.do();
|
|
416
547
|
}
|
|
417
548
|
}
|
|
418
549
|
/**
|
|
@@ -428,15 +559,18 @@ class StretchNodeAction {
|
|
|
428
559
|
this.from = from;
|
|
429
560
|
this.to = to;
|
|
430
561
|
}
|
|
562
|
+
do() {
|
|
563
|
+
this.canvas.model.nodes
|
|
564
|
+
.get(this.nodeId)
|
|
565
|
+
?.stretch(this.direction, this.to - this.from);
|
|
566
|
+
}
|
|
431
567
|
undo() {
|
|
432
568
|
this.canvas.model.nodes
|
|
433
569
|
.get(this.nodeId)
|
|
434
570
|
?.stretch(this.direction, this.from - this.to);
|
|
435
571
|
}
|
|
436
572
|
redo() {
|
|
437
|
-
this.
|
|
438
|
-
.get(this.nodeId)
|
|
439
|
-
?.stretch(this.direction, this.to - this.from);
|
|
573
|
+
this.do();
|
|
440
574
|
}
|
|
441
575
|
}
|
|
442
576
|
/**
|
|
@@ -452,20 +586,23 @@ class StretchSectionAction {
|
|
|
452
586
|
this.from = from;
|
|
453
587
|
this.to = to;
|
|
454
588
|
}
|
|
455
|
-
|
|
589
|
+
do() {
|
|
456
590
|
const section = this.canvas.model.sections.get(this.sectionId);
|
|
457
591
|
const node = section?.node;
|
|
458
592
|
if (node) {
|
|
459
|
-
node.stretchSections(this.direction, this.
|
|
593
|
+
node.stretchSections(this.direction, this.to - this.from, section.indexXInNode, section.indexYInNode);
|
|
460
594
|
}
|
|
461
595
|
}
|
|
462
|
-
|
|
596
|
+
undo() {
|
|
463
597
|
const section = this.canvas.model.sections.get(this.sectionId);
|
|
464
598
|
const node = section?.node;
|
|
465
599
|
if (node) {
|
|
466
|
-
node.stretchSections(this.direction, this.
|
|
600
|
+
node.stretchSections(this.direction, this.from - this.to, section.indexXInNode, section.indexYInNode);
|
|
467
601
|
}
|
|
468
602
|
}
|
|
603
|
+
redo() {
|
|
604
|
+
this.do();
|
|
605
|
+
}
|
|
469
606
|
}
|
|
470
607
|
/**
|
|
471
608
|
* Action which consists of adding a connection.
|
|
@@ -480,12 +617,7 @@ class AddConnectionAction {
|
|
|
480
617
|
this.endId = endId;
|
|
481
618
|
this.id = id;
|
|
482
619
|
}
|
|
483
|
-
|
|
484
|
-
if (this.id) {
|
|
485
|
-
this.canvas.model.connections.remove(this.id);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
redo() {
|
|
620
|
+
do() {
|
|
489
621
|
const start = this.canvas.model.ports.get(this.startId);
|
|
490
622
|
const end = this.canvas.model.ports.get(this.endId);
|
|
491
623
|
if (start && end) {
|
|
@@ -494,6 +626,24 @@ class AddConnectionAction {
|
|
|
494
626
|
this.id = connection.id;
|
|
495
627
|
}
|
|
496
628
|
}
|
|
629
|
+
undo() {
|
|
630
|
+
if (this.id) {
|
|
631
|
+
const connection = this.canvas.model.connections.get(this.id);
|
|
632
|
+
if (connection) {
|
|
633
|
+
connection.removed = true;
|
|
634
|
+
connection.updateInView();
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
redo() {
|
|
639
|
+
if (this.id) {
|
|
640
|
+
const connection = this.canvas.model.connections.get(this.id);
|
|
641
|
+
if (connection) {
|
|
642
|
+
connection.removed = false;
|
|
643
|
+
connection.updateInView();
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
497
647
|
}
|
|
498
648
|
/**
|
|
499
649
|
* Action which consists of editing the text of a field.
|
|
@@ -507,18 +657,21 @@ class EditFieldAction {
|
|
|
507
657
|
this.from = from;
|
|
508
658
|
this.to = to;
|
|
509
659
|
}
|
|
510
|
-
|
|
660
|
+
do() {
|
|
511
661
|
const field = this.canvas.model.fields.get(this.fieldId);
|
|
512
662
|
if (field) {
|
|
513
|
-
field.text = this.
|
|
663
|
+
field.text = this.to;
|
|
514
664
|
}
|
|
515
665
|
}
|
|
516
|
-
|
|
666
|
+
undo() {
|
|
517
667
|
const field = this.canvas.model.fields.get(this.fieldId);
|
|
518
668
|
if (field) {
|
|
519
|
-
field.text = this.
|
|
669
|
+
field.text = this.from;
|
|
520
670
|
}
|
|
521
671
|
}
|
|
672
|
+
redo() {
|
|
673
|
+
this.do();
|
|
674
|
+
}
|
|
522
675
|
}
|
|
523
676
|
/**
|
|
524
677
|
* Action which consists of editing the values of a value set.
|
|
@@ -540,11 +693,14 @@ class UpdateValuesAction {
|
|
|
540
693
|
return (this.model.nodes.get(this.id) || this.model.connections.get(this.id))?.valueSet;
|
|
541
694
|
}
|
|
542
695
|
}
|
|
696
|
+
do() {
|
|
697
|
+
this.getValueSet()?.overwriteValues(this.to);
|
|
698
|
+
}
|
|
543
699
|
undo() {
|
|
544
|
-
this.getValueSet()?.
|
|
700
|
+
this.getValueSet()?.overwriteValues(this.from);
|
|
545
701
|
}
|
|
546
702
|
redo() {
|
|
547
|
-
this.
|
|
703
|
+
this.do();
|
|
548
704
|
}
|
|
549
705
|
}
|
|
550
706
|
/**
|
|
@@ -552,274 +708,153 @@ class UpdateValuesAction {
|
|
|
552
708
|
* @private
|
|
553
709
|
*/
|
|
554
710
|
class RemoveAction {
|
|
555
|
-
constructor(model,
|
|
556
|
-
this.nodes = [];
|
|
557
|
-
this.nodeIds = [];
|
|
558
|
-
this.sections = [];
|
|
559
|
-
this.sectionIds = [];
|
|
560
|
-
this.ports = [];
|
|
561
|
-
this.portIds = [];
|
|
562
|
-
this.connections = [];
|
|
563
|
-
this.connectionIds = [];
|
|
564
|
-
this.fields = [];
|
|
565
|
-
this.fieldIds = [];
|
|
711
|
+
constructor(model, nodeIds, sectionIds, portIds, connectionIds, fieldIds) {
|
|
566
712
|
this.model = model;
|
|
567
|
-
this.
|
|
568
|
-
this.
|
|
569
|
-
this.
|
|
570
|
-
this.
|
|
571
|
-
this.
|
|
572
|
-
// if a node is deleted, its label, ports and sections must also be deleted
|
|
573
|
-
for (const node of this.nodes) {
|
|
574
|
-
if (node.label) {
|
|
575
|
-
addIfNotExists(this.fields, node.label);
|
|
576
|
-
}
|
|
577
|
-
for (const port of node.ports) {
|
|
578
|
-
addIfNotExists(this.ports, port);
|
|
579
|
-
}
|
|
580
|
-
for (const section of node.sections) {
|
|
581
|
-
addIfNotExists(this.sections, section);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
// if a section is deleted, its label and ports must also be deleted
|
|
585
|
-
for (const section of this.sections) {
|
|
586
|
-
if (section.label) {
|
|
587
|
-
addIfNotExists(this.fields, section.label);
|
|
588
|
-
}
|
|
589
|
-
for (const port of section.ports) {
|
|
590
|
-
addIfNotExists(this.ports, port);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
// if a port is deleted, its label and connections must also be deleted
|
|
594
|
-
for (const port of this.ports) {
|
|
595
|
-
if (port.label) {
|
|
596
|
-
addIfNotExists(this.fields, port.label);
|
|
597
|
-
}
|
|
598
|
-
for (const connection of port.outgoingConnections) {
|
|
599
|
-
addIfNotExists(this.connections, connection);
|
|
600
|
-
}
|
|
601
|
-
for (const connection of port.incomingConnections) {
|
|
602
|
-
addIfNotExists(this.connections, connection);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
this.nodeIds = this.nodes.map((n) => n.id);
|
|
606
|
-
this.sectionIds = this.sections.map((s) => s.id);
|
|
607
|
-
this.portIds = this.ports.map((p) => p.id);
|
|
608
|
-
this.connectionIds = this.connections.map((c) => c.id);
|
|
609
|
-
this.fieldIds = this.fields.map((f) => f.id);
|
|
713
|
+
this.nodeIds = nodeIds;
|
|
714
|
+
this.sectionIds = sectionIds;
|
|
715
|
+
this.portIds = portIds;
|
|
716
|
+
this.connectionIds = connectionIds;
|
|
717
|
+
this.fieldIds = fieldIds;
|
|
610
718
|
}
|
|
611
|
-
|
|
612
|
-
for (const
|
|
613
|
-
this.model.nodes.
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
for (const port of this.ports) {
|
|
619
|
-
this.model.ports.add(port);
|
|
620
|
-
}
|
|
621
|
-
for (const connection of this.connections) {
|
|
622
|
-
this.model.connections.add(connection);
|
|
623
|
-
}
|
|
624
|
-
for (const field of this.fields) {
|
|
625
|
-
this.model.fields.add(field);
|
|
626
|
-
}
|
|
627
|
-
for (const node of this.nodes) {
|
|
628
|
-
if (node.label) {
|
|
629
|
-
const label = this.model.fields.get(node.label.id);
|
|
630
|
-
if (label) {
|
|
631
|
-
node.label = label;
|
|
719
|
+
do() {
|
|
720
|
+
for (const nodeId of this.nodeIds) {
|
|
721
|
+
const node = this.model.nodes.get(nodeId);
|
|
722
|
+
if (node) {
|
|
723
|
+
node.removed = true;
|
|
724
|
+
for (const section of node.sections) {
|
|
725
|
+
addIfNotExists(this.sectionIds, section.id);
|
|
632
726
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
for (const nodePort of node.ports) {
|
|
636
|
-
const port = this.model.ports.get(nodePort.id);
|
|
637
|
-
if (port) {
|
|
638
|
-
ports.push(port);
|
|
727
|
+
for (const port of node.ports) {
|
|
728
|
+
addIfNotExists(this.portIds, port.id);
|
|
639
729
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
const sections = [];
|
|
643
|
-
for (const nodeSection of node.sections) {
|
|
644
|
-
const section = this.model.sections.get(nodeSection.id);
|
|
645
|
-
if (section) {
|
|
646
|
-
sections.push(section);
|
|
730
|
+
if (node.label) {
|
|
731
|
+
addIfNotExists(this.fieldIds, node.label.id);
|
|
647
732
|
}
|
|
648
733
|
}
|
|
649
|
-
node.sections = sections;
|
|
650
734
|
}
|
|
651
|
-
for (const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
}
|
|
658
|
-
if (section.label) {
|
|
659
|
-
const label = this.model.fields.get(section.label.id);
|
|
660
|
-
if (label) {
|
|
661
|
-
section.label = label;
|
|
735
|
+
for (const sectionId of this.sectionIds) {
|
|
736
|
+
const section = this.model.sections.get(sectionId);
|
|
737
|
+
if (section) {
|
|
738
|
+
section.removed = true;
|
|
739
|
+
for (const port of section.ports) {
|
|
740
|
+
addIfNotExists(this.portIds, port.id);
|
|
662
741
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
for (const sectionPort of section.ports) {
|
|
666
|
-
const port = this.model.ports.get(sectionPort.id);
|
|
667
|
-
if (port) {
|
|
668
|
-
ports.push(port);
|
|
742
|
+
if (section.label) {
|
|
743
|
+
addIfNotExists(this.fieldIds, section.label.id);
|
|
669
744
|
}
|
|
670
745
|
}
|
|
671
|
-
section.ports = ports;
|
|
672
746
|
}
|
|
673
|
-
for (const
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
if (port.label) {
|
|
682
|
-
const label = this.model.fields.get(port.label.id);
|
|
683
|
-
if (label) {
|
|
684
|
-
port.label = label;
|
|
747
|
+
for (const portId of this.portIds) {
|
|
748
|
+
const port = this.model.ports.get(portId);
|
|
749
|
+
if (port) {
|
|
750
|
+
port.removed = true;
|
|
751
|
+
for (const connection of port.outgoingConnections) {
|
|
752
|
+
addIfNotExists(this.connectionIds, connection.id);
|
|
685
753
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
for (const portOutgoingConnection of port.outgoingConnections) {
|
|
689
|
-
const connection = this.model.connections.get(portOutgoingConnection.id);
|
|
690
|
-
if (connection) {
|
|
691
|
-
outgoingConnections.push(connection);
|
|
754
|
+
for (const connection of port.incomingConnections) {
|
|
755
|
+
addIfNotExists(this.connectionIds, connection.id);
|
|
692
756
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
const incomingConnections = [];
|
|
696
|
-
for (const portIncomingConnection of port.incomingConnections) {
|
|
697
|
-
const connection = this.model.connections.get(portIncomingConnection.id);
|
|
698
|
-
if (connection) {
|
|
699
|
-
incomingConnections.push(connection);
|
|
757
|
+
if (port.label) {
|
|
758
|
+
addIfNotExists(this.fieldIds, port.label.id);
|
|
700
759
|
}
|
|
701
760
|
}
|
|
702
|
-
port.incomingConnections = incomingConnections;
|
|
703
761
|
}
|
|
704
|
-
for (const
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
connection.setStart(start);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
if (connection.end) {
|
|
712
|
-
const end = this.model.ports.get(connection.end.id);
|
|
713
|
-
if (end) {
|
|
714
|
-
connection.setEnd(end);
|
|
715
|
-
}
|
|
762
|
+
for (const connectionId of this.connectionIds) {
|
|
763
|
+
const connection = this.model.connections.get(connectionId);
|
|
764
|
+
if (connection) {
|
|
765
|
+
connection.removed = true;
|
|
716
766
|
}
|
|
717
767
|
}
|
|
718
|
-
for (const
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
this.model.ports.get(field.rootElement.id);
|
|
723
|
-
if (rootElement) {
|
|
724
|
-
field.rootElement = rootElement;
|
|
725
|
-
}
|
|
768
|
+
for (const fieldId of this.fieldIds) {
|
|
769
|
+
const field = this.model.fields.get(fieldId);
|
|
770
|
+
if (field) {
|
|
771
|
+
field.removed = true;
|
|
726
772
|
}
|
|
727
773
|
}
|
|
728
774
|
// update view
|
|
729
|
-
this.model.canvas?.
|
|
775
|
+
this.model.canvas?.updateNodesInView(...this.nodeIds);
|
|
776
|
+
this.model.canvas?.updateSectionsInView(...this.sectionIds);
|
|
777
|
+
this.model.canvas?.updatePortsInView(...this.portIds);
|
|
778
|
+
this.model.canvas?.updateConnectionsInView(...this.connectionIds);
|
|
779
|
+
this.model.canvas?.updateFieldsInView(...this.fieldIds);
|
|
730
780
|
}
|
|
731
|
-
|
|
732
|
-
this.nodes = [];
|
|
733
|
-
this.sections = [];
|
|
734
|
-
this.ports = [];
|
|
735
|
-
this.connections = [];
|
|
736
|
-
this.fields = [];
|
|
737
|
-
// make shallow copies of the elements with their relationships
|
|
781
|
+
undo() {
|
|
738
782
|
for (const nodeId of this.nodeIds) {
|
|
739
783
|
const node = this.model.nodes.get(nodeId);
|
|
740
784
|
if (node) {
|
|
741
|
-
|
|
742
|
-
if (nodeCopy.label) {
|
|
743
|
-
nodeCopy.label = clone(nodeCopy.label);
|
|
744
|
-
}
|
|
745
|
-
nodeCopy.ports = nodeCopy.ports.map((p) => clone(p));
|
|
746
|
-
nodeCopy.sections = nodeCopy.sections.map((s) => clone(s));
|
|
747
|
-
this.nodes.push(nodeCopy);
|
|
785
|
+
node.removed = false;
|
|
748
786
|
}
|
|
749
787
|
}
|
|
750
788
|
for (const sectionId of this.sectionIds) {
|
|
751
789
|
const section = this.model.sections.get(sectionId);
|
|
752
790
|
if (section) {
|
|
753
|
-
|
|
754
|
-
if (sectionCopy.label) {
|
|
755
|
-
sectionCopy.label = clone(sectionCopy.label);
|
|
756
|
-
}
|
|
757
|
-
sectionCopy.ports = sectionCopy.ports.map((p) => clone(p));
|
|
758
|
-
this.sections.push(sectionCopy);
|
|
791
|
+
section.removed = false;
|
|
759
792
|
}
|
|
760
793
|
}
|
|
761
794
|
for (const portId of this.portIds) {
|
|
762
795
|
const port = this.model.ports.get(portId);
|
|
763
796
|
if (port) {
|
|
764
|
-
|
|
765
|
-
if (portCopy.rootElement) {
|
|
766
|
-
portCopy.rootElement = clone(portCopy.rootElement);
|
|
767
|
-
}
|
|
768
|
-
if (portCopy.label) {
|
|
769
|
-
portCopy.label = clone(portCopy.label);
|
|
770
|
-
}
|
|
771
|
-
portCopy.outgoingConnections = portCopy.outgoingConnections.map((c) => clone(c));
|
|
772
|
-
portCopy.incomingConnections = portCopy.incomingConnections.map((c) => clone(c));
|
|
773
|
-
this.ports.push(portCopy);
|
|
797
|
+
port.removed = false;
|
|
774
798
|
}
|
|
775
799
|
}
|
|
776
800
|
for (const connectionId of this.connectionIds) {
|
|
777
801
|
const connection = this.model.connections.get(connectionId);
|
|
778
802
|
if (connection) {
|
|
779
|
-
|
|
780
|
-
if (connectionCopy.start) {
|
|
781
|
-
connectionCopy.start = clone(connectionCopy.start);
|
|
782
|
-
}
|
|
783
|
-
if (connectionCopy.end) {
|
|
784
|
-
connectionCopy.end = clone(connectionCopy.end);
|
|
785
|
-
}
|
|
786
|
-
this.connections.push(connectionCopy);
|
|
803
|
+
connection.removed = false;
|
|
787
804
|
}
|
|
788
805
|
}
|
|
789
806
|
for (const fieldId of this.fieldIds) {
|
|
790
807
|
const field = this.model.fields.get(fieldId);
|
|
791
808
|
if (field) {
|
|
792
|
-
|
|
793
|
-
if (fieldCopy.rootElement) {
|
|
794
|
-
fieldCopy.rootElement = clone(fieldCopy.rootElement);
|
|
795
|
-
}
|
|
796
|
-
this.fields.push(fieldCopy);
|
|
809
|
+
field.removed = false;
|
|
797
810
|
}
|
|
798
811
|
}
|
|
799
|
-
//
|
|
812
|
+
// update view
|
|
813
|
+
this.model.canvas?.updateNodesInView(...this.nodeIds);
|
|
814
|
+
this.model.canvas?.updateSectionsInView(...this.sectionIds);
|
|
815
|
+
this.model.canvas?.updatePortsInView(...this.portIds);
|
|
816
|
+
this.model.canvas?.updateConnectionsInView(...this.connectionIds);
|
|
817
|
+
this.model.canvas?.updateFieldsInView(...this.fieldIds);
|
|
818
|
+
}
|
|
819
|
+
redo() {
|
|
800
820
|
for (const nodeId of this.nodeIds) {
|
|
801
|
-
this.model.nodes.
|
|
821
|
+
const node = this.model.nodes.get(nodeId);
|
|
822
|
+
if (node) {
|
|
823
|
+
node.removed = true;
|
|
824
|
+
}
|
|
802
825
|
}
|
|
803
826
|
for (const sectionId of this.sectionIds) {
|
|
804
|
-
this.model.sections.
|
|
827
|
+
const section = this.model.sections.get(sectionId);
|
|
828
|
+
if (section) {
|
|
829
|
+
section.removed = true;
|
|
830
|
+
}
|
|
805
831
|
}
|
|
806
832
|
for (const portId of this.portIds) {
|
|
807
|
-
this.model.ports.
|
|
833
|
+
const port = this.model.ports.get(portId);
|
|
834
|
+
if (port) {
|
|
835
|
+
port.removed = true;
|
|
836
|
+
}
|
|
808
837
|
}
|
|
809
838
|
for (const connectionId of this.connectionIds) {
|
|
810
|
-
this.model.connections.
|
|
839
|
+
const connection = this.model.connections.get(connectionId);
|
|
840
|
+
if (connection) {
|
|
841
|
+
connection.removed = true;
|
|
842
|
+
}
|
|
811
843
|
}
|
|
812
844
|
for (const fieldId of this.fieldIds) {
|
|
813
|
-
this.model.fields.
|
|
845
|
+
const field = this.model.fields.get(fieldId);
|
|
846
|
+
if (field) {
|
|
847
|
+
field.removed = true;
|
|
848
|
+
}
|
|
814
849
|
}
|
|
850
|
+
// update view
|
|
851
|
+
this.model.canvas?.updateNodesInView(...this.nodeIds);
|
|
852
|
+
this.model.canvas?.updateSectionsInView(...this.sectionIds);
|
|
853
|
+
this.model.canvas?.updatePortsInView(...this.portIds);
|
|
854
|
+
this.model.canvas?.updateConnectionsInView(...this.connectionIds);
|
|
855
|
+
this.model.canvas?.updateFieldsInView(...this.fieldIds);
|
|
815
856
|
}
|
|
816
857
|
}
|
|
817
|
-
const clone = (obj) => {
|
|
818
|
-
if (obj === undefined || obj === null) {
|
|
819
|
-
return obj;
|
|
820
|
-
}
|
|
821
|
-
return Object.create(obj);
|
|
822
|
-
};
|
|
823
858
|
|
|
824
859
|
/**
|
|
825
860
|
* A two dimensional array of elements of the given class that can extend infinitely in any direction, both positive and negative.
|
|
@@ -1516,7 +1551,7 @@ class PriorityLayout {
|
|
|
1516
1551
|
const gapSize = (model.canvas?.gridSize || 0) * 2;
|
|
1517
1552
|
const nodesToBeArranged = [...model.nodes];
|
|
1518
1553
|
const nodeArrangement = [];
|
|
1519
|
-
const nodesWithMaximumPriorityToBeArranged = model.nodes.filter(
|
|
1554
|
+
const nodesWithMaximumPriorityToBeArranged = model.nodes.filter((n) => !n.removed && n.getPriority() >= maximumPriority);
|
|
1520
1555
|
const nodesWithMaximumPriority = [];
|
|
1521
1556
|
if (nodesWithMaximumPriorityToBeArranged.length > 1) {
|
|
1522
1557
|
// use bfs to sort nodes by distance to the first node
|
|
@@ -2296,6 +2331,21 @@ const stickyNotePath = (x, y, width, height) => {
|
|
|
2296
2331
|
return `M ${x} ${y} L ${x + (3 * width) / 4} ${y} L ${x + (3 * width) / 4} ${y + height / 4} L ${x + (3 * width) / 4} ${y} L ${x + width} ${y + height / 4} L ${x + (3 * width) / 4} ${y + height / 4} L ${x + width} ${y + height / 4} L ${x + width} ${y + height} L ${x} ${y + height} Z`;
|
|
2297
2332
|
};
|
|
2298
2333
|
|
|
2334
|
+
var CursorStyle;
|
|
2335
|
+
(function (CursorStyle) {
|
|
2336
|
+
CursorStyle["AllScroll"] = "all-scroll";
|
|
2337
|
+
CursorStyle["Auto"] = "auto";
|
|
2338
|
+
CursorStyle["EWResize"] = "ew-resize";
|
|
2339
|
+
CursorStyle["Grab"] = "grab";
|
|
2340
|
+
CursorStyle["Grabbing"] = "grabbing";
|
|
2341
|
+
CursorStyle["Move"] = "move";
|
|
2342
|
+
CursorStyle["NoDrop"] = "no-drop";
|
|
2343
|
+
CursorStyle["NSResize"] = "ns-resize";
|
|
2344
|
+
CursorStyle["NotAllowed"] = "not-allowed";
|
|
2345
|
+
CursorStyle["ZoomIn"] = "zoom-in";
|
|
2346
|
+
CursorStyle["ZoomOut"] = "zoom-out";
|
|
2347
|
+
})(CursorStyle || (CursorStyle = {}));
|
|
2348
|
+
|
|
2299
2349
|
const numberOfColumns = (s) => {
|
|
2300
2350
|
return Math.max(...s.split('\n').map((a) => a.length));
|
|
2301
2351
|
};
|
|
@@ -2329,6 +2379,11 @@ class DiagramElement {
|
|
|
2329
2379
|
* @private
|
|
2330
2380
|
*/
|
|
2331
2381
|
this.selected = false;
|
|
2382
|
+
/**
|
|
2383
|
+
* Whether this diagram element has been removed.
|
|
2384
|
+
* @private
|
|
2385
|
+
*/
|
|
2386
|
+
this.removed = false;
|
|
2332
2387
|
this.model = model;
|
|
2333
2388
|
this._id = id;
|
|
2334
2389
|
}
|
|
@@ -2410,16 +2465,16 @@ class DiagramEntitySet {
|
|
|
2410
2465
|
* @public
|
|
2411
2466
|
* @returns An array containing the entities of this set that meet the given criteria.
|
|
2412
2467
|
*/
|
|
2413
|
-
filter() {
|
|
2414
|
-
return this.
|
|
2468
|
+
filter(predicate) {
|
|
2469
|
+
return this.entities.filter(predicate);
|
|
2415
2470
|
}
|
|
2416
2471
|
/**
|
|
2417
2472
|
* Gets an entity of this set matching specific criteria.
|
|
2418
2473
|
* @public
|
|
2419
2474
|
* @returns An entity of this set.
|
|
2420
2475
|
*/
|
|
2421
|
-
find() {
|
|
2422
|
-
return this.entities.
|
|
2476
|
+
find(predicate) {
|
|
2477
|
+
return this.entities.find(predicate);
|
|
2423
2478
|
}
|
|
2424
2479
|
/**
|
|
2425
2480
|
* Gets an entity from this set.
|
|
@@ -2474,7 +2529,7 @@ class Property {
|
|
|
2474
2529
|
}
|
|
2475
2530
|
}
|
|
2476
2531
|
/**
|
|
2477
|
-
* The type that a property can
|
|
2532
|
+
* The type that a property can have.
|
|
2478
2533
|
* @see Property
|
|
2479
2534
|
* @private
|
|
2480
2535
|
*/
|
|
@@ -2492,6 +2547,10 @@ var Type;
|
|
|
2492
2547
|
* A type whose value must be a date.
|
|
2493
2548
|
*/
|
|
2494
2549
|
Type["Date"] = "date";
|
|
2550
|
+
/**
|
|
2551
|
+
* A type whose value must be a date with a time.
|
|
2552
|
+
*/
|
|
2553
|
+
Type["Datetime"] = "datetime";
|
|
2495
2554
|
/**
|
|
2496
2555
|
* A type whose value must be a number.
|
|
2497
2556
|
*/
|
|
@@ -2506,6 +2565,7 @@ var Type;
|
|
|
2506
2565
|
Type["Option"] = "option";
|
|
2507
2566
|
/**
|
|
2508
2567
|
* A type whose value must be a list of values picked from a set of options.
|
|
2568
|
+
* @see Type.Option
|
|
2509
2569
|
*/
|
|
2510
2570
|
Type["OptionList"] = "option-list";
|
|
2511
2571
|
/**
|
|
@@ -2569,6 +2629,13 @@ class ValueSet {
|
|
|
2569
2629
|
this.rootElement = rootElement;
|
|
2570
2630
|
this.resetValues();
|
|
2571
2631
|
}
|
|
2632
|
+
/**
|
|
2633
|
+
* Get the value of the root element attribute under the given keys.
|
|
2634
|
+
* If given an array of keys, the value is found under repeated lookups to enable obtaining nested values.
|
|
2635
|
+
* @private
|
|
2636
|
+
* @param rootAttribute A key or array of keys to look up in the root element.
|
|
2637
|
+
* @returns The value if it could be found, `undefined` if nothing could be found.
|
|
2638
|
+
*/
|
|
2572
2639
|
getRootElementValue(rootAttribute) {
|
|
2573
2640
|
if (typeof rootAttribute === 'string') {
|
|
2574
2641
|
return this.rootElement[rootAttribute];
|
|
@@ -2586,6 +2653,15 @@ class ValueSet {
|
|
|
2586
2653
|
}
|
|
2587
2654
|
return undefined;
|
|
2588
2655
|
}
|
|
2656
|
+
/**
|
|
2657
|
+
* Set the value of the root element's attribute under the given keys.
|
|
2658
|
+
* If given an array of keys, the value is found under repeated lookups to enable setting nested values.
|
|
2659
|
+
* If the root element has a function `updateInView()`, it is called upon successful setting of the value.
|
|
2660
|
+
* If the root element's attribute doesn't exist, it does nothing.
|
|
2661
|
+
* @private
|
|
2662
|
+
* @param rootAttribute A key or array of keys to look up in the root element.
|
|
2663
|
+
* @param value The value to set the root element's attribute to.
|
|
2664
|
+
*/
|
|
2589
2665
|
setRootElementValue(rootAttribute, value) {
|
|
2590
2666
|
if (typeof rootAttribute === 'string') {
|
|
2591
2667
|
this.rootElement[rootAttribute] = value;
|
|
@@ -2600,35 +2676,69 @@ class ValueSet {
|
|
|
2600
2676
|
}
|
|
2601
2677
|
rootSubelement = rootSubelement[rootSubattribute];
|
|
2602
2678
|
}
|
|
2679
|
+
if (rootSubelement === null || rootSubelement === undefined) {
|
|
2680
|
+
return;
|
|
2681
|
+
}
|
|
2603
2682
|
rootSubelement[rootAttribute[rootAttribute.length - 1]] = value;
|
|
2604
2683
|
}
|
|
2684
|
+
if (typeof this.rootElement['updateInView'] === 'function') {
|
|
2685
|
+
this.rootElement['updateInView']();
|
|
2686
|
+
}
|
|
2605
2687
|
}
|
|
2688
|
+
/**
|
|
2689
|
+
* Obtain the value under the given key.
|
|
2690
|
+
* @private
|
|
2691
|
+
* @param key A key.
|
|
2692
|
+
* @returns The value under the given key.
|
|
2693
|
+
*/
|
|
2606
2694
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2607
2695
|
getValue(key) {
|
|
2608
2696
|
const rootAttribute = this.propertySet.getProperty(key)?.rootAttribute;
|
|
2609
2697
|
if (rootAttribute !== undefined && rootAttribute !== null) {
|
|
2610
2698
|
this.values[key] = this.getRootElementValue(rootAttribute);
|
|
2611
2699
|
}
|
|
2612
|
-
|
|
2700
|
+
const property = this.propertySet.getProperty(key);
|
|
2701
|
+
if (property.type === Type.Object) {
|
|
2702
|
+
return this.valueSets[key].getValues();
|
|
2703
|
+
}
|
|
2704
|
+
else {
|
|
2705
|
+
return this.values[key];
|
|
2706
|
+
}
|
|
2613
2707
|
}
|
|
2708
|
+
/**
|
|
2709
|
+
* Obtain all the values in the set.
|
|
2710
|
+
* @private
|
|
2711
|
+
* @returns An object containing all the values in the set.
|
|
2712
|
+
*/
|
|
2614
2713
|
getValues() {
|
|
2615
2714
|
const result = {};
|
|
2616
2715
|
for (const key in this.propertySet.propertyMap) {
|
|
2617
2716
|
const property = this.propertySet.getProperty(key);
|
|
2618
|
-
if (property.type === Type.Object
|
|
2619
|
-
this.valueSets[key].hasAnySetValue()) {
|
|
2717
|
+
if (property.type === Type.Object) {
|
|
2620
2718
|
result[key] = this.valueSets[key].getValues();
|
|
2621
2719
|
}
|
|
2622
|
-
else
|
|
2720
|
+
else {
|
|
2623
2721
|
result[key] = this.getValue(key);
|
|
2624
2722
|
}
|
|
2625
2723
|
}
|
|
2626
2724
|
return result;
|
|
2627
2725
|
}
|
|
2726
|
+
/**
|
|
2727
|
+
* Check if the value under the key is not empty.
|
|
2728
|
+
* @private
|
|
2729
|
+
* @param key A key.
|
|
2730
|
+
* @returns `true` if the value under the key is empty, `false` otherwise.
|
|
2731
|
+
*/
|
|
2628
2732
|
hasValue(key) {
|
|
2629
2733
|
const value = this.getValue(key);
|
|
2630
2734
|
return !empty(value);
|
|
2631
2735
|
}
|
|
2736
|
+
/**
|
|
2737
|
+
* Check if the value under the key is not empty or the default value.
|
|
2738
|
+
* @private
|
|
2739
|
+
* @param key A key.
|
|
2740
|
+
* @returns `true` if the value under the key is empty or the default value, `false` otherwise.
|
|
2741
|
+
*/
|
|
2632
2742
|
hasSetValue(key) {
|
|
2633
2743
|
const value = this.getValue(key);
|
|
2634
2744
|
const property = this.propertySet.getProperty(key);
|
|
@@ -2637,6 +2747,11 @@ class ValueSet {
|
|
|
2637
2747
|
}
|
|
2638
2748
|
return !empty(value) && !equals(value, property?.defaultValue);
|
|
2639
2749
|
}
|
|
2750
|
+
/**
|
|
2751
|
+
* Check if any of the values in the set are not empty or the default value.
|
|
2752
|
+
* @private
|
|
2753
|
+
* @returns `true` if any of the values in the set are not empty or the default value, `false` otherwise.
|
|
2754
|
+
*/
|
|
2640
2755
|
hasAnySetValue() {
|
|
2641
2756
|
for (const property of this.propertySet.propertyList) {
|
|
2642
2757
|
if (this.hasSetValue(property.name)) {
|
|
@@ -2645,58 +2760,84 @@ class ValueSet {
|
|
|
2645
2760
|
}
|
|
2646
2761
|
return false;
|
|
2647
2762
|
}
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
return false;
|
|
2655
|
-
}
|
|
2763
|
+
/**
|
|
2764
|
+
* Set the value under the given key.
|
|
2765
|
+
* @private
|
|
2766
|
+
* @param key A key.
|
|
2767
|
+
* @param value A value.
|
|
2768
|
+
*/
|
|
2656
2769
|
setValue(key, value) {
|
|
2657
|
-
this.values[key] = value;
|
|
2658
2770
|
const property = this.propertySet.getProperty(key);
|
|
2659
2771
|
if (property) {
|
|
2772
|
+
if (property.type === Type.Object) {
|
|
2773
|
+
this.valueSets[key].setValues(value);
|
|
2774
|
+
}
|
|
2775
|
+
else {
|
|
2776
|
+
this.values[key] = value;
|
|
2777
|
+
}
|
|
2660
2778
|
const rootAttribute = property.rootAttribute;
|
|
2661
2779
|
if (rootAttribute !== undefined && rootAttribute !== null) {
|
|
2662
2780
|
this.setRootElementValue(rootAttribute, value);
|
|
2663
|
-
if (typeof this.rootElement['updateInView'] === 'function') {
|
|
2664
|
-
this.rootElement['updateInView']();
|
|
2665
|
-
}
|
|
2666
2781
|
}
|
|
2667
2782
|
this.displayProperty(property);
|
|
2668
2783
|
}
|
|
2669
2784
|
}
|
|
2785
|
+
/**
|
|
2786
|
+
* Reset all values and then set them to the given values.
|
|
2787
|
+
* @private
|
|
2788
|
+
* @param values An object containing all values to set the values to.
|
|
2789
|
+
*/
|
|
2670
2790
|
setValues(values) {
|
|
2671
2791
|
this.resetValues();
|
|
2672
|
-
for (const key in
|
|
2792
|
+
for (const key in values) {
|
|
2673
2793
|
const property = this.propertySet.getProperty(key);
|
|
2674
|
-
if (
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
this.setValue(key, values[key]);
|
|
2680
|
-
}
|
|
2794
|
+
if (property.type === Type.Object) {
|
|
2795
|
+
this.valueSets[key].setValues(values[key]);
|
|
2796
|
+
}
|
|
2797
|
+
else {
|
|
2798
|
+
this.setValue(key, values[key]);
|
|
2681
2799
|
}
|
|
2682
2800
|
}
|
|
2683
2801
|
}
|
|
2684
|
-
|
|
2685
|
-
|
|
2802
|
+
/**
|
|
2803
|
+
* Writes the given values over the value set's existing values without resetting the existing values.
|
|
2804
|
+
* @private
|
|
2805
|
+
* @param values An object containing all values to set the values to.
|
|
2806
|
+
*/
|
|
2807
|
+
overwriteValues(values) {
|
|
2808
|
+
for (const key in values) {
|
|
2809
|
+
const property = this.propertySet.getProperty(key);
|
|
2810
|
+
if (property.type === Type.Object) {
|
|
2811
|
+
this.valueSets[key].overwriteValues(values[key]);
|
|
2812
|
+
}
|
|
2813
|
+
else {
|
|
2814
|
+
this.setValue(key, values[key]);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2686
2817
|
}
|
|
2818
|
+
/**
|
|
2819
|
+
* Set all the values of this set to the defaults.
|
|
2820
|
+
* If this set has a root element and any of its properties have root attributes, the root element's attributes are also set to the property's default value if one is provided.
|
|
2821
|
+
* @private
|
|
2822
|
+
*/
|
|
2687
2823
|
resetValues() {
|
|
2688
2824
|
this.displayedProperties = [];
|
|
2689
2825
|
this.hiddenProperties = [];
|
|
2690
2826
|
for (const key in this.propertySet.propertyMap) {
|
|
2691
2827
|
const property = this.propertySet.getProperty(key);
|
|
2692
2828
|
const rootAttribute = property.rootAttribute;
|
|
2693
|
-
if (
|
|
2694
|
-
this.
|
|
2829
|
+
if (property.type === Type.Object) {
|
|
2830
|
+
this.valueSets[key] = this.constructSubValueSet(key);
|
|
2695
2831
|
}
|
|
2696
2832
|
else {
|
|
2697
2833
|
this.values[key] = structuredClone(property.defaultValue);
|
|
2698
|
-
|
|
2699
|
-
|
|
2834
|
+
}
|
|
2835
|
+
if (rootAttribute !== undefined && rootAttribute !== null) {
|
|
2836
|
+
if (property.defaultValue !== undefined) {
|
|
2837
|
+
this.setRootElementValue(rootAttribute, this.values[key]);
|
|
2838
|
+
}
|
|
2839
|
+
else {
|
|
2840
|
+
this.values[key] = this.getRootElementValue(rootAttribute);
|
|
2700
2841
|
}
|
|
2701
2842
|
}
|
|
2702
2843
|
if (property.basic) {
|
|
@@ -2707,37 +2848,56 @@ class ValueSet {
|
|
|
2707
2848
|
}
|
|
2708
2849
|
}
|
|
2709
2850
|
}
|
|
2710
|
-
displayProperty(property) {
|
|
2711
|
-
if (!this.displayedProperties.includes(property)) {
|
|
2712
|
-
this.displayedProperties.push(property);
|
|
2713
|
-
removeIfExists(this.hiddenProperties, property);
|
|
2714
|
-
}
|
|
2715
|
-
}
|
|
2716
|
-
hideProperty(property) {
|
|
2717
|
-
if (!this.hiddenProperties.includes(property)) {
|
|
2718
|
-
this.hiddenProperties.push(property);
|
|
2719
|
-
removeIfExists(this.displayedProperties, property);
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
2851
|
/**
|
|
2723
2852
|
* Constructs a ValueSet with its corresponding PropertySet representing the values of the object.
|
|
2853
|
+
* @private
|
|
2854
|
+
* @param key Key that the ValueSet is under.
|
|
2855
|
+
* @returns The constructed ValueSet.
|
|
2724
2856
|
*/
|
|
2725
2857
|
constructSubValueSet(key) {
|
|
2726
2858
|
const property = this.propertySet.getProperty(key);
|
|
2727
2859
|
const propertySet = new PropertySet(property.properties);
|
|
2728
2860
|
const valueSet = new ValueSet(propertySet, this.rootElement);
|
|
2729
|
-
|
|
2730
|
-
this.values[key] = {
|
|
2731
|
-
...valueSet.values,
|
|
2732
|
-
...this.values[key]
|
|
2733
|
-
};
|
|
2734
|
-
valueSet.values = this.values[key];
|
|
2861
|
+
valueSet.overwriteValues(structuredClone(property.defaultValue));
|
|
2735
2862
|
return valueSet;
|
|
2736
2863
|
}
|
|
2864
|
+
/**
|
|
2865
|
+
* Get the ValueSet under the given key when there are nested ValueSets.
|
|
2866
|
+
* @private
|
|
2867
|
+
* @param key A key.
|
|
2868
|
+
* @returns A ValueSet.
|
|
2869
|
+
*/
|
|
2737
2870
|
getSubValueSet(key) {
|
|
2738
2871
|
return this.valueSets[key];
|
|
2739
2872
|
}
|
|
2873
|
+
/**
|
|
2874
|
+
* Move the given property to the list of displayed properties.
|
|
2875
|
+
* @private
|
|
2876
|
+
* @param property A property.
|
|
2877
|
+
*/
|
|
2878
|
+
displayProperty(property) {
|
|
2879
|
+
if (!this.displayedProperties.includes(property)) {
|
|
2880
|
+
this.displayedProperties.push(property);
|
|
2881
|
+
removeIfExists(this.hiddenProperties, property);
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
/**
|
|
2885
|
+
* Move the given property to the list of hidden properties.
|
|
2886
|
+
* @private
|
|
2887
|
+
* @param property A property.
|
|
2888
|
+
*/
|
|
2889
|
+
hideProperty(property) {
|
|
2890
|
+
if (!this.hiddenProperties.includes(property)) {
|
|
2891
|
+
this.hiddenProperties.push(property);
|
|
2892
|
+
removeIfExists(this.displayedProperties, property);
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2740
2895
|
}
|
|
2896
|
+
/**
|
|
2897
|
+
* Check if the given value is not empty.
|
|
2898
|
+
* @param a A value.
|
|
2899
|
+
* @returns `true` if the given value is not `undefined`, `null`, `''`, `[]` or `{}`; `false` otherwise.
|
|
2900
|
+
*/
|
|
2741
2901
|
const empty = (a) => {
|
|
2742
2902
|
return (a === undefined ||
|
|
2743
2903
|
a === null ||
|
|
@@ -2745,9 +2905,47 @@ const empty = (a) => {
|
|
|
2745
2905
|
(a instanceof Array && a.length === 0) ||
|
|
2746
2906
|
(a instanceof Object && Object.keys(a).length === 0));
|
|
2747
2907
|
};
|
|
2908
|
+
/**
|
|
2909
|
+
* Check whether the given values are equal.
|
|
2910
|
+
* @param a A value.
|
|
2911
|
+
* @param b A value.
|
|
2912
|
+
* @returns `true` if the given values are equal, `false` otherwise.
|
|
2913
|
+
*/
|
|
2748
2914
|
const equals = (a, b) => {
|
|
2749
2915
|
return a === b || JSON.stringify(a) === JSON.stringify(b);
|
|
2750
2916
|
};
|
|
2917
|
+
/**
|
|
2918
|
+
* Calculate the differences between the given values and return two objects, each containing the keys for which the values are different in each argument, containing the different values.
|
|
2919
|
+
* @param a A dictionary.
|
|
2920
|
+
* @param b A dictionary.
|
|
2921
|
+
* @returns A tuple of two values with each containing the keys that have a different value in the corresponding argument compared to the other argument.
|
|
2922
|
+
*/
|
|
2923
|
+
const diff = (a, b) => {
|
|
2924
|
+
const aDiff = {};
|
|
2925
|
+
const bDiff = {};
|
|
2926
|
+
const allKeys = [];
|
|
2927
|
+
for (const key in a) {
|
|
2928
|
+
allKeys.push(key);
|
|
2929
|
+
}
|
|
2930
|
+
for (const key in b) {
|
|
2931
|
+
if (!(key in a)) {
|
|
2932
|
+
allKeys.push(key);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
for (const key of allKeys) {
|
|
2936
|
+
if (isObject(a[key]) && isObject(b[key])) {
|
|
2937
|
+
[aDiff[key], bDiff[key]] = diff(a[key], b[key]);
|
|
2938
|
+
}
|
|
2939
|
+
else {
|
|
2940
|
+
if (!equals(a[key], b[key])) {
|
|
2941
|
+
aDiff[key] = a[key];
|
|
2942
|
+
bDiff[key] = b[key];
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
return [aDiff, bDiff];
|
|
2947
|
+
};
|
|
2948
|
+
const isObject = (x) => typeof x === 'object' && !!x;
|
|
2751
2949
|
|
|
2752
2950
|
let idTicker$4 = 0;
|
|
2753
2951
|
/**
|
|
@@ -2869,6 +3067,12 @@ class DiagramConnection extends DiagramElement {
|
|
|
2869
3067
|
updateInView() {
|
|
2870
3068
|
this.model.canvas?.updateConnectionsInView(this.id);
|
|
2871
3069
|
}
|
|
3070
|
+
/**
|
|
3071
|
+
* Set the start of this connection to the given port or reset this connection's starting port if `undefined`.
|
|
3072
|
+
* Add or remove this connection from the list of outgoing connections of ports correspondingly.
|
|
3073
|
+
* @public
|
|
3074
|
+
* @param start A port.
|
|
3075
|
+
*/
|
|
2872
3076
|
setStart(start) {
|
|
2873
3077
|
if (this.start !== start) {
|
|
2874
3078
|
if (this.start !== undefined) {
|
|
@@ -2887,6 +3091,12 @@ class DiagramConnection extends DiagramElement {
|
|
|
2887
3091
|
}
|
|
2888
3092
|
this.updateInView();
|
|
2889
3093
|
}
|
|
3094
|
+
/**
|
|
3095
|
+
* Set the end of this connection to the given port or reset this connection's ending port if `undefined`.
|
|
3096
|
+
* Add or remove this connection from the list of incoming connections of ports correspondingly.
|
|
3097
|
+
* @public
|
|
3098
|
+
* @param end A port.
|
|
3099
|
+
*/
|
|
2890
3100
|
setEnd(end) {
|
|
2891
3101
|
if (this.end !== end) {
|
|
2892
3102
|
if (this.end !== undefined) {
|
|
@@ -2905,6 +3115,11 @@ class DiagramConnection extends DiagramElement {
|
|
|
2905
3115
|
}
|
|
2906
3116
|
this.updateInView();
|
|
2907
3117
|
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Reassign the start and end ports of this connection to ports with less distance between them that have the same root element.
|
|
3120
|
+
* If no ports with less distance between them are found, do nothing.
|
|
3121
|
+
* @public
|
|
3122
|
+
*/
|
|
2908
3123
|
tighten() {
|
|
2909
3124
|
if (this.start?.rootElement && this.end?.rootElement) {
|
|
2910
3125
|
const tighterStartPort =
|
|
@@ -2942,15 +3157,44 @@ class DiagramConnection extends DiagramElement {
|
|
|
2942
3157
|
}
|
|
2943
3158
|
}
|
|
2944
3159
|
class DiagramConnectionSet extends DiagramEntitySet {
|
|
3160
|
+
/**
|
|
3161
|
+
* Instance a set of connections for the given model. This method is used internally.
|
|
3162
|
+
* @private
|
|
3163
|
+
*/
|
|
2945
3164
|
constructor(model) {
|
|
2946
3165
|
super();
|
|
3166
|
+
/**
|
|
3167
|
+
* Set of the possible types of connection that the connections of this set can have.
|
|
3168
|
+
* @public
|
|
3169
|
+
*/
|
|
2947
3170
|
this.types = new DiagramEntitySet();
|
|
2948
3171
|
this.model = model;
|
|
2949
3172
|
}
|
|
3173
|
+
/**
|
|
3174
|
+
* Instance a new connection and add it to this set.
|
|
3175
|
+
* @public
|
|
3176
|
+
* @param type The type of the connection given as either the type itself or the id of the type.
|
|
3177
|
+
* @param start The start port of the connection.
|
|
3178
|
+
* @param end The end port of the connection.
|
|
3179
|
+
* @param id The id of the connection. Should be left undefined unless a specific id is required.
|
|
3180
|
+
* @returns The instanced connection.
|
|
3181
|
+
*/
|
|
2950
3182
|
new(type, start, end, id) {
|
|
2951
|
-
|
|
3183
|
+
let connectionType;
|
|
3184
|
+
if (type instanceof DiagramConnectionType) {
|
|
3185
|
+
connectionType = type;
|
|
3186
|
+
}
|
|
3187
|
+
else {
|
|
3188
|
+
const foundConnectionType = this.types.get(type);
|
|
3189
|
+
if (foundConnectionType === undefined) {
|
|
3190
|
+
throw new TypeError(`Connection type with id '${type}' could not be found.`);
|
|
3191
|
+
}
|
|
3192
|
+
connectionType = foundConnectionType;
|
|
3193
|
+
}
|
|
3194
|
+
const connection = new DiagramConnection(this.model, connectionType, start, end, id);
|
|
2952
3195
|
super.add(connection);
|
|
2953
3196
|
connection.updateInView();
|
|
3197
|
+
connection.valueSet.resetValues();
|
|
2954
3198
|
return connection;
|
|
2955
3199
|
}
|
|
2956
3200
|
remove(id) {
|
|
@@ -2965,30 +3209,6 @@ class DiagramConnectionSet extends DiagramEntitySet {
|
|
|
2965
3209
|
connection.updateInView();
|
|
2966
3210
|
}
|
|
2967
3211
|
}
|
|
2968
|
-
filter(type, threshold) {
|
|
2969
|
-
return this.entities.filter((e) => {
|
|
2970
|
-
let matches = true;
|
|
2971
|
-
if (type !== undefined && matches) {
|
|
2972
|
-
matches = matches && e.type.id === type;
|
|
2973
|
-
}
|
|
2974
|
-
if (threshold !== undefined && matches) {
|
|
2975
|
-
matches = matches && e.getPriority() >= threshold;
|
|
2976
|
-
}
|
|
2977
|
-
return matches;
|
|
2978
|
-
});
|
|
2979
|
-
}
|
|
2980
|
-
find(type, threshold) {
|
|
2981
|
-
return this.entities.find((e) => {
|
|
2982
|
-
let matches = true;
|
|
2983
|
-
if (type !== undefined && matches) {
|
|
2984
|
-
matches = matches && e.type.id === type;
|
|
2985
|
-
}
|
|
2986
|
-
if (threshold !== undefined && matches) {
|
|
2987
|
-
matches = matches && e.getPriority() >= threshold;
|
|
2988
|
-
}
|
|
2989
|
-
return matches;
|
|
2990
|
-
});
|
|
2991
|
-
}
|
|
2992
3212
|
}
|
|
2993
3213
|
|
|
2994
3214
|
let idTicker$3 = 0;
|
|
@@ -3100,6 +3320,11 @@ class DiagramSection extends DiagramElement {
|
|
|
3100
3320
|
getPriority() {
|
|
3101
3321
|
return (this.node?.type?.sectionGrid?.sections?.[this.indexYInNode]?.[this.indexXInNode]?.priority || DIAGRAM_SECTION_DEFAULTS.priority);
|
|
3102
3322
|
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Get the port of this section which is closest to the given coordinates.
|
|
3325
|
+
* @param coords A point in the diagram.
|
|
3326
|
+
* @returns The port of this section closest to the given coordinates, `undefined` if this section has no ports.
|
|
3327
|
+
*/
|
|
3103
3328
|
getClosestPortToPoint(coords) {
|
|
3104
3329
|
if (this.ports.length === 0) {
|
|
3105
3330
|
return undefined;
|
|
@@ -3114,6 +3339,11 @@ class DiagramSection extends DiagramElement {
|
|
|
3114
3339
|
return closestPort;
|
|
3115
3340
|
}
|
|
3116
3341
|
}
|
|
3342
|
+
/**
|
|
3343
|
+
* Get all incoming connections of all ports of this section.
|
|
3344
|
+
* @public
|
|
3345
|
+
* @returns A list of connections.
|
|
3346
|
+
*/
|
|
3117
3347
|
getIncomingConnections() {
|
|
3118
3348
|
const result = [];
|
|
3119
3349
|
for (const port of this.ports) {
|
|
@@ -3123,6 +3353,11 @@ class DiagramSection extends DiagramElement {
|
|
|
3123
3353
|
}
|
|
3124
3354
|
return result;
|
|
3125
3355
|
}
|
|
3356
|
+
/**
|
|
3357
|
+
* Get all outgoing connections of all ports of this section.
|
|
3358
|
+
* @public
|
|
3359
|
+
* @returns A list of connections.
|
|
3360
|
+
*/
|
|
3126
3361
|
getOutgoingConnections() {
|
|
3127
3362
|
const result = [];
|
|
3128
3363
|
for (const port of this.ports) {
|
|
@@ -3132,6 +3367,11 @@ class DiagramSection extends DiagramElement {
|
|
|
3132
3367
|
}
|
|
3133
3368
|
return result;
|
|
3134
3369
|
}
|
|
3370
|
+
/**
|
|
3371
|
+
* Get all connections of all ports of this section.
|
|
3372
|
+
* @public
|
|
3373
|
+
* @returns A list of connections.
|
|
3374
|
+
*/
|
|
3135
3375
|
getConnections() {
|
|
3136
3376
|
const result = [];
|
|
3137
3377
|
for (const port of this.ports) {
|
|
@@ -3144,6 +3384,11 @@ class DiagramSection extends DiagramElement {
|
|
|
3144
3384
|
}
|
|
3145
3385
|
return result;
|
|
3146
3386
|
}
|
|
3387
|
+
/**
|
|
3388
|
+
* Change the coordinates of this section to the given coordinates and move its ports and labels correspondingly.
|
|
3389
|
+
* @public
|
|
3390
|
+
* @param coords A point in the diagram.
|
|
3391
|
+
*/
|
|
3147
3392
|
move(coords) {
|
|
3148
3393
|
const coordDifferences = [
|
|
3149
3394
|
coords[0] - this.coords[0],
|
|
@@ -3165,6 +3410,12 @@ class DiagramSection extends DiagramElement {
|
|
|
3165
3410
|
this.getConnections().forEach((c) => c.tighten());
|
|
3166
3411
|
this.updateInView();
|
|
3167
3412
|
}
|
|
3413
|
+
/**
|
|
3414
|
+
* Change the dimensions of this section in the given direction by the given amount.
|
|
3415
|
+
* @public
|
|
3416
|
+
* @param direction A direction.
|
|
3417
|
+
* @param distance A distance.
|
|
3418
|
+
*/
|
|
3168
3419
|
stretch(direction, distance) {
|
|
3169
3420
|
const oldCoordsX = [this.coords[0], this.coords[0] + this.width];
|
|
3170
3421
|
const oldCoordsY = [this.coords[1], this.coords[1] + this.height];
|
|
@@ -3221,11 +3472,19 @@ class DiagramSection extends DiagramElement {
|
|
|
3221
3472
|
}
|
|
3222
3473
|
}
|
|
3223
3474
|
class DiagramSectionSet extends DiagramEntitySet {
|
|
3475
|
+
/**
|
|
3476
|
+
* Instance a set of sections for the given model. This method is used internally.
|
|
3477
|
+
* @private
|
|
3478
|
+
*/
|
|
3224
3479
|
constructor(model) {
|
|
3225
3480
|
super();
|
|
3226
3481
|
this.model = model;
|
|
3227
3482
|
}
|
|
3228
|
-
|
|
3483
|
+
/**
|
|
3484
|
+
* Instance a new section and add it to this set. This method is normally called when instancing an element with a section and it is rarely called by itself.
|
|
3485
|
+
* @private
|
|
3486
|
+
*/
|
|
3487
|
+
new(node, indexXInNode, indexYInNode, coords, width, height, id) {
|
|
3229
3488
|
const section = new DiagramSection(this.model, node, indexXInNode, indexYInNode, coords, width, height, id);
|
|
3230
3489
|
super.add(section);
|
|
3231
3490
|
section.updateInView();
|
|
@@ -3240,7 +3499,7 @@ class DiagramSectionSet extends DiagramEntitySet {
|
|
|
3240
3499
|
const port = this.model.ports.new(section, [
|
|
3241
3500
|
section.coords[0] + (portConfig?.coords?.[0] || 0),
|
|
3242
3501
|
section.coords[1] + (portConfig?.coords?.[1] || 0)
|
|
3243
|
-
], portConfig?.direction
|
|
3502
|
+
], portConfig?.direction);
|
|
3244
3503
|
if (portConfig.label) {
|
|
3245
3504
|
const labelConfiguration = {
|
|
3246
3505
|
...DIAGRAM_FIELD_DEFAULTS,
|
|
@@ -3270,9 +3529,7 @@ class DiagramSectionSet extends DiagramEntitySet {
|
|
|
3270
3529
|
default:
|
|
3271
3530
|
labelCoords = port.coords;
|
|
3272
3531
|
}
|
|
3273
|
-
this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit
|
|
3274
|
-
? portLabelIds[i]
|
|
3275
|
-
: undefined);
|
|
3532
|
+
this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
|
|
3276
3533
|
}
|
|
3277
3534
|
}
|
|
3278
3535
|
}
|
|
@@ -3286,7 +3543,7 @@ class DiagramSectionSet extends DiagramEntitySet {
|
|
|
3286
3543
|
this.model.fields.new(section, [
|
|
3287
3544
|
section.coords[0] + labelConfiguration.margin,
|
|
3288
3545
|
section.coords[1] + labelConfiguration.margin
|
|
3289
|
-
], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, section.width - labelConfiguration.margin * 2, section.height - labelConfiguration.margin * 2, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit
|
|
3546
|
+
], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, section.width - labelConfiguration.margin * 2, section.height - labelConfiguration.margin * 2, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
|
|
3290
3547
|
}
|
|
3291
3548
|
return section;
|
|
3292
3549
|
}
|
|
@@ -3311,22 +3568,6 @@ class DiagramSectionSet extends DiagramEntitySet {
|
|
|
3311
3568
|
section.updateInView();
|
|
3312
3569
|
}
|
|
3313
3570
|
}
|
|
3314
|
-
filter(threshold) {
|
|
3315
|
-
return this.entities.filter((e) => {
|
|
3316
|
-
if (threshold !== undefined) {
|
|
3317
|
-
return e.getPriority() >= threshold;
|
|
3318
|
-
}
|
|
3319
|
-
return true;
|
|
3320
|
-
});
|
|
3321
|
-
}
|
|
3322
|
-
find(threshold) {
|
|
3323
|
-
return this.entities.find((e) => {
|
|
3324
|
-
if (threshold !== undefined) {
|
|
3325
|
-
return e.getPriority() >= threshold;
|
|
3326
|
-
}
|
|
3327
|
-
return true;
|
|
3328
|
-
});
|
|
3329
|
-
}
|
|
3330
3571
|
}
|
|
3331
3572
|
|
|
3332
3573
|
let idTicker$2 = 0;
|
|
@@ -3446,6 +3687,11 @@ class DiagramNode extends DiagramElement {
|
|
|
3446
3687
|
getPriority() {
|
|
3447
3688
|
return this.type.priority;
|
|
3448
3689
|
}
|
|
3690
|
+
/**
|
|
3691
|
+
* Get the port of this node which is closest to the given coordinates.
|
|
3692
|
+
* @param coords A point in the diagram.
|
|
3693
|
+
* @returns The port of this node closest to the given coordinates, `undefined` if this node has no ports.
|
|
3694
|
+
*/
|
|
3449
3695
|
getClosestPortToPoint(coords) {
|
|
3450
3696
|
if (this.ports.length === 0) {
|
|
3451
3697
|
return undefined;
|
|
@@ -3460,6 +3706,11 @@ class DiagramNode extends DiagramElement {
|
|
|
3460
3706
|
return closestPort;
|
|
3461
3707
|
}
|
|
3462
3708
|
}
|
|
3709
|
+
/**
|
|
3710
|
+
* Get all incoming connections of all ports of this node, not including incoming connections of sections of this node.
|
|
3711
|
+
* @public
|
|
3712
|
+
* @returns A list of connections.
|
|
3713
|
+
*/
|
|
3463
3714
|
getIncomingConnections() {
|
|
3464
3715
|
const result = [];
|
|
3465
3716
|
for (const port of this.ports) {
|
|
@@ -3469,6 +3720,11 @@ class DiagramNode extends DiagramElement {
|
|
|
3469
3720
|
}
|
|
3470
3721
|
return result;
|
|
3471
3722
|
}
|
|
3723
|
+
/**
|
|
3724
|
+
* Get all outgoing connections of all ports of this node, not including outgoing connections of sections of this node.
|
|
3725
|
+
* @public
|
|
3726
|
+
* @returns A list of connections.
|
|
3727
|
+
*/
|
|
3472
3728
|
getOutgoingConnections() {
|
|
3473
3729
|
const result = [];
|
|
3474
3730
|
for (const port of this.ports) {
|
|
@@ -3478,6 +3734,11 @@ class DiagramNode extends DiagramElement {
|
|
|
3478
3734
|
}
|
|
3479
3735
|
return result;
|
|
3480
3736
|
}
|
|
3737
|
+
/**
|
|
3738
|
+
* Get all connections of all ports of this node, not including connections of sections of this node.
|
|
3739
|
+
* @public
|
|
3740
|
+
* @returns A list of connections.
|
|
3741
|
+
*/
|
|
3481
3742
|
getConnections() {
|
|
3482
3743
|
const result = [];
|
|
3483
3744
|
for (const port of this.ports) {
|
|
@@ -3490,6 +3751,11 @@ class DiagramNode extends DiagramElement {
|
|
|
3490
3751
|
}
|
|
3491
3752
|
return result;
|
|
3492
3753
|
}
|
|
3754
|
+
/**
|
|
3755
|
+
* Get all nodes that have a direct connection to this node, not including nodes that have a direct connection to sections of this node.
|
|
3756
|
+
* @public
|
|
3757
|
+
* @returns A list of nodes.
|
|
3758
|
+
*/
|
|
3493
3759
|
getAdjacentNodes() {
|
|
3494
3760
|
const result = [];
|
|
3495
3761
|
for (const port of this.ports) {
|
|
@@ -3508,6 +3774,11 @@ class DiagramNode extends DiagramElement {
|
|
|
3508
3774
|
}
|
|
3509
3775
|
return result;
|
|
3510
3776
|
}
|
|
3777
|
+
/**
|
|
3778
|
+
* Change the coordinates of this node to the given coordinates and move its sections, ports and labels correspondingly.
|
|
3779
|
+
* @public
|
|
3780
|
+
* @param coords A point in the diagram.
|
|
3781
|
+
*/
|
|
3511
3782
|
move(coords) {
|
|
3512
3783
|
const coordDifferences = [
|
|
3513
3784
|
coords[0] - this.coords[0],
|
|
@@ -3535,6 +3806,12 @@ class DiagramNode extends DiagramElement {
|
|
|
3535
3806
|
this.getConnections().forEach((c) => c.tighten());
|
|
3536
3807
|
this.updateInView();
|
|
3537
3808
|
}
|
|
3809
|
+
/**
|
|
3810
|
+
* Change the dimensions of this node in the given direction by the given amount without changing the dimensions of the sections of this node.
|
|
3811
|
+
* @public
|
|
3812
|
+
* @param direction A direction.
|
|
3813
|
+
* @param distance A distance.
|
|
3814
|
+
*/
|
|
3538
3815
|
stretch(direction, distance) {
|
|
3539
3816
|
const oldCoordsX = [this.coords[0], this.coords[0] + this.width];
|
|
3540
3817
|
const oldCoordsY = [this.coords[1], this.coords[1] + this.height];
|
|
@@ -3588,6 +3865,14 @@ class DiagramNode extends DiagramElement {
|
|
|
3588
3865
|
// we ignore this.sections, the stretching of a node with sections is handled in the stretchSections method
|
|
3589
3866
|
this.updateInView();
|
|
3590
3867
|
}
|
|
3868
|
+
/**
|
|
3869
|
+
* Change the dimensions of this node and its sections in the given direction by the given amount, with the sections of the given index being stretched.
|
|
3870
|
+
* @public
|
|
3871
|
+
* @param direction A direction.
|
|
3872
|
+
* @param distance A distance.
|
|
3873
|
+
* @param indexX A section index.
|
|
3874
|
+
* @param indexY A section index.
|
|
3875
|
+
*/
|
|
3591
3876
|
stretchSections(direction, distance, indexX, indexY) {
|
|
3592
3877
|
let minimumStretchableDistance = Number.NEGATIVE_INFINITY;
|
|
3593
3878
|
switch (direction) {
|
|
@@ -3668,50 +3953,71 @@ class DiagramNode extends DiagramElement {
|
|
|
3668
3953
|
}
|
|
3669
3954
|
}
|
|
3670
3955
|
class DiagramNodeSet extends DiagramEntitySet {
|
|
3956
|
+
/**
|
|
3957
|
+
* Instance a set of nodes for the given model. This method is used internally.
|
|
3958
|
+
* @private
|
|
3959
|
+
*/
|
|
3671
3960
|
constructor(model) {
|
|
3672
3961
|
super();
|
|
3962
|
+
/**
|
|
3963
|
+
* Set of the possible types of node that the nodes of this set can have.
|
|
3964
|
+
* @public
|
|
3965
|
+
*/
|
|
3673
3966
|
this.types = new DiagramEntitySet();
|
|
3674
3967
|
this.model = model;
|
|
3675
3968
|
}
|
|
3676
|
-
|
|
3677
|
-
|
|
3969
|
+
/**
|
|
3970
|
+
* Instance a new node and add it to this set.
|
|
3971
|
+
* @public
|
|
3972
|
+
* @param type The type of the node given as either the type itself or the id of the type.
|
|
3973
|
+
* @param coords The coordinates of the top left corner of the node in the diagram.
|
|
3974
|
+
* @param id The id of the node. Should be left undefined unless a specific id is required.
|
|
3975
|
+
* @returns The instanced node.
|
|
3976
|
+
*/
|
|
3977
|
+
new(type, coords, id) {
|
|
3978
|
+
let nodeType;
|
|
3979
|
+
if (type instanceof DiagramNodeType) {
|
|
3980
|
+
nodeType = type;
|
|
3981
|
+
}
|
|
3982
|
+
else {
|
|
3983
|
+
const foundNodeType = this.types.get(type);
|
|
3984
|
+
if (foundNodeType === undefined) {
|
|
3985
|
+
throw new TypeError(`Node type with id '${type}' could not be found.`);
|
|
3986
|
+
}
|
|
3987
|
+
nodeType = foundNodeType;
|
|
3988
|
+
}
|
|
3989
|
+
const node = new DiagramNode(this.model, nodeType, coords, id);
|
|
3678
3990
|
super.add(node);
|
|
3679
3991
|
node.updateInView();
|
|
3680
3992
|
// add node sections
|
|
3681
|
-
if (
|
|
3993
|
+
if (nodeType.sectionGrid !== null) {
|
|
3682
3994
|
// create sections
|
|
3683
|
-
let
|
|
3684
|
-
let
|
|
3685
|
-
|
|
3686
|
-
let
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
DIAGRAM_SECTION_DEFAULT_HEIGHT, sectionIds && sectionIds.length > sectionCount
|
|
3691
|
-
? sectionIds[sectionCount]
|
|
3692
|
-
: undefined, sectionPortIds && sectionPortIds.length > sectionCount
|
|
3693
|
-
? sectionPortIds[sectionCount]
|
|
3694
|
-
: undefined, sectionPortLabelIds && sectionPortLabelIds.length > sectionCount
|
|
3695
|
-
? sectionPortLabelIds[sectionCount]
|
|
3696
|
-
: undefined);
|
|
3697
|
-
++sectionCount;
|
|
3995
|
+
let heightAccumulator = node.coords[1] + (nodeType.sectionGrid.margin || 0);
|
|
3996
|
+
for (let j = 0; j < nodeType.sectionGrid.sections.length; ++j) {
|
|
3997
|
+
let widthAccumulator = node.coords[0] + (nodeType.sectionGrid.margin || 0);
|
|
3998
|
+
for (let i = 0; i < nodeType.sectionGrid.sections[j].length; ++i) {
|
|
3999
|
+
this.model.sections.new(node, i, j, [widthAccumulator, heightAccumulator], nodeType.sectionGrid.defaultWidths?.[i] ||
|
|
4000
|
+
DIAGRAM_SECTION_DEFAULT_WIDTH, nodeType.sectionGrid.defaultHeights?.[j] ||
|
|
4001
|
+
DIAGRAM_SECTION_DEFAULT_HEIGHT);
|
|
3698
4002
|
widthAccumulator +=
|
|
3699
|
-
(
|
|
3700
|
-
DIAGRAM_SECTION_DEFAULT_WIDTH) +
|
|
4003
|
+
(nodeType.sectionGrid.defaultWidths?.[i] ||
|
|
4004
|
+
DIAGRAM_SECTION_DEFAULT_WIDTH) +
|
|
4005
|
+
(nodeType.sectionGrid.margin || 0);
|
|
3701
4006
|
}
|
|
3702
4007
|
heightAccumulator +=
|
|
3703
|
-
(
|
|
3704
|
-
DIAGRAM_SECTION_DEFAULT_HEIGHT) +
|
|
4008
|
+
(nodeType.sectionGrid.defaultHeights?.[j] ||
|
|
4009
|
+
DIAGRAM_SECTION_DEFAULT_HEIGHT) +
|
|
4010
|
+
(nodeType.sectionGrid.margin || 0);
|
|
3705
4011
|
}
|
|
3706
4012
|
}
|
|
3707
4013
|
// add node ports
|
|
3708
|
-
if (
|
|
3709
|
-
for (let i = 0; i <
|
|
3710
|
-
const portConfig =
|
|
4014
|
+
if (nodeType.ports.length > 0) {
|
|
4015
|
+
for (let i = 0; i < nodeType.ports.length; ++i) {
|
|
4016
|
+
const portConfig = nodeType.ports[i];
|
|
3711
4017
|
const port = this.model.ports.new(node, [
|
|
3712
4018
|
node.coords[0] + portConfig.coords[0],
|
|
3713
4019
|
node.coords[1] + portConfig.coords[1]
|
|
3714
|
-
], portConfig.direction
|
|
4020
|
+
], portConfig.direction);
|
|
3715
4021
|
if (portConfig.label) {
|
|
3716
4022
|
const labelConfiguration = {
|
|
3717
4023
|
...DIAGRAM_FIELD_DEFAULTS,
|
|
@@ -3741,23 +4047,22 @@ class DiagramNodeSet extends DiagramEntitySet {
|
|
|
3741
4047
|
default:
|
|
3742
4048
|
labelCoords = port.coords;
|
|
3743
4049
|
}
|
|
3744
|
-
this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit
|
|
3745
|
-
? portLabelIds[i]
|
|
3746
|
-
: undefined);
|
|
4050
|
+
this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
|
|
3747
4051
|
}
|
|
3748
4052
|
}
|
|
3749
4053
|
}
|
|
3750
4054
|
// add node label
|
|
3751
|
-
if (
|
|
4055
|
+
if (nodeType.label) {
|
|
3752
4056
|
const labelConfiguration = {
|
|
3753
4057
|
...DIAGRAM_FIELD_DEFAULTS,
|
|
3754
|
-
...
|
|
4058
|
+
...nodeType.label
|
|
3755
4059
|
};
|
|
3756
4060
|
this.model.fields.new(node, [
|
|
3757
4061
|
node.coords[0] + labelConfiguration.margin,
|
|
3758
4062
|
node.coords[1] + labelConfiguration.margin
|
|
3759
|
-
], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, node.width - labelConfiguration.margin * 2, node.height - labelConfiguration.margin * 2, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit
|
|
4063
|
+
], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, node.width - labelConfiguration.margin * 2, node.height - labelConfiguration.margin * 2, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
|
|
3760
4064
|
}
|
|
4065
|
+
node.valueSet.resetValues();
|
|
3761
4066
|
node.model.canvas?.fitNodeInView(node.id);
|
|
3762
4067
|
return node;
|
|
3763
4068
|
}
|
|
@@ -3782,14 +4087,6 @@ class DiagramNodeSet extends DiagramEntitySet {
|
|
|
3782
4087
|
node.updateInView();
|
|
3783
4088
|
}
|
|
3784
4089
|
}
|
|
3785
|
-
filter(type, threshold) {
|
|
3786
|
-
return this.entities.filter((e) => (type !== undefined ? e.type.id === type : true) &&
|
|
3787
|
-
(threshold !== undefined ? e.type.priority >= threshold : true));
|
|
3788
|
-
}
|
|
3789
|
-
find(type, threshold) {
|
|
3790
|
-
return this.entities.find((e) => (type !== undefined ? e.type.id === type : true) &&
|
|
3791
|
-
(threshold !== undefined ? e.type.priority >= threshold : true));
|
|
3792
|
-
}
|
|
3793
4090
|
}
|
|
3794
4091
|
|
|
3795
4092
|
let idTicker$1 = 0;
|
|
@@ -3839,12 +4136,27 @@ class DiagramPort extends DiagramElement {
|
|
|
3839
4136
|
updateInView() {
|
|
3840
4137
|
this.model.canvas?.updatePortsInView(this.id);
|
|
3841
4138
|
}
|
|
4139
|
+
/**
|
|
4140
|
+
* Add a connection to this port's list of outgoing connections.
|
|
4141
|
+
* @public
|
|
4142
|
+
* @param connection A connection.
|
|
4143
|
+
*/
|
|
3842
4144
|
startConnection(connection) {
|
|
3843
4145
|
this.outgoingConnections.push(connection);
|
|
3844
4146
|
}
|
|
4147
|
+
/**
|
|
4148
|
+
* Add a connection to this port's list of incoming connections.
|
|
4149
|
+
* @public
|
|
4150
|
+
* @param connection A connection.
|
|
4151
|
+
*/
|
|
3845
4152
|
finishConnection(connection) {
|
|
3846
4153
|
this.incomingConnections.push(connection);
|
|
3847
4154
|
}
|
|
4155
|
+
/**
|
|
4156
|
+
* Get the root node of this port, which is either its rootElement if it's a node or it's rootElement's node if it's a section.
|
|
4157
|
+
* @public
|
|
4158
|
+
* @returns A node if it could be found, `undefined` otherwise.
|
|
4159
|
+
*/
|
|
3848
4160
|
getNode() {
|
|
3849
4161
|
if (this.rootElement instanceof DiagramNode) {
|
|
3850
4162
|
return this.rootElement;
|
|
@@ -3857,6 +4169,11 @@ class DiagramPort extends DiagramElement {
|
|
|
3857
4169
|
getPriority() {
|
|
3858
4170
|
return this.rootElement?.getPriority() || DEFAULT_PRIORITY;
|
|
3859
4171
|
}
|
|
4172
|
+
/**
|
|
4173
|
+
* Change the coordinates of this port to the given coordinates and move its labels correspondingly.
|
|
4174
|
+
* @public
|
|
4175
|
+
* @param coords A point in the diagram.
|
|
4176
|
+
*/
|
|
3860
4177
|
move(coords) {
|
|
3861
4178
|
const coordDifferences = [
|
|
3862
4179
|
coords[0] - this.coords[0],
|
|
@@ -3882,10 +4199,18 @@ class DiagramPort extends DiagramElement {
|
|
|
3882
4199
|
}
|
|
3883
4200
|
}
|
|
3884
4201
|
class DiagramPortSet extends DiagramEntitySet {
|
|
4202
|
+
/**
|
|
4203
|
+
* Instance a set of ports for the given model. This method is used internally.
|
|
4204
|
+
* @private
|
|
4205
|
+
*/
|
|
3885
4206
|
constructor(model) {
|
|
3886
4207
|
super();
|
|
3887
4208
|
this.model = model;
|
|
3888
4209
|
}
|
|
4210
|
+
/**
|
|
4211
|
+
* Instance a new port and add it to this set. This method is normally called when instancing an element with a port and it is rarely called by itself.
|
|
4212
|
+
* @private
|
|
4213
|
+
*/
|
|
3889
4214
|
new(rootElement, coords, direction, id) {
|
|
3890
4215
|
const port = new DiagramPort(this.model, rootElement, coords, direction, id);
|
|
3891
4216
|
super.add(port);
|
|
@@ -3921,22 +4246,6 @@ class DiagramPortSet extends DiagramEntitySet {
|
|
|
3921
4246
|
port.updateInView();
|
|
3922
4247
|
}
|
|
3923
4248
|
}
|
|
3924
|
-
filter(threshold) {
|
|
3925
|
-
return this.entities.filter((e) => {
|
|
3926
|
-
if (threshold !== undefined) {
|
|
3927
|
-
return e.getPriority() >= threshold;
|
|
3928
|
-
}
|
|
3929
|
-
return true;
|
|
3930
|
-
});
|
|
3931
|
-
}
|
|
3932
|
-
find(threshold) {
|
|
3933
|
-
return this.entities.find((e) => {
|
|
3934
|
-
if (threshold !== undefined) {
|
|
3935
|
-
return e.getPriority() >= threshold;
|
|
3936
|
-
}
|
|
3937
|
-
return true;
|
|
3938
|
-
});
|
|
3939
|
-
}
|
|
3940
4249
|
}
|
|
3941
4250
|
|
|
3942
4251
|
let idTicker = 0;
|
|
@@ -4016,6 +4325,11 @@ class DiagramField extends DiagramElement {
|
|
|
4016
4325
|
updateInView() {
|
|
4017
4326
|
this.model.canvas?.updateFieldsInView(this.id);
|
|
4018
4327
|
}
|
|
4328
|
+
/**
|
|
4329
|
+
* Change the coordinates of this field to the given coordinates.
|
|
4330
|
+
* @public
|
|
4331
|
+
* @param coords A point in the diagram.
|
|
4332
|
+
*/
|
|
4019
4333
|
move(coords) {
|
|
4020
4334
|
this.coords = coords;
|
|
4021
4335
|
this.updateInView();
|
|
@@ -4025,10 +4339,18 @@ class DiagramField extends DiagramElement {
|
|
|
4025
4339
|
}
|
|
4026
4340
|
}
|
|
4027
4341
|
class DiagramFieldSet extends DiagramEntitySet {
|
|
4342
|
+
/**
|
|
4343
|
+
* Instance a set of fields for the given model. This method is used internally.
|
|
4344
|
+
* @private
|
|
4345
|
+
*/
|
|
4028
4346
|
constructor(model) {
|
|
4029
4347
|
super();
|
|
4030
4348
|
this.model = model;
|
|
4031
4349
|
}
|
|
4350
|
+
/**
|
|
4351
|
+
* Instance a new field and add it to this set. This method is normally called when instancing an element with a field and it is rarely called by itself.
|
|
4352
|
+
* @private
|
|
4353
|
+
*/
|
|
4032
4354
|
new(rootElement, coords, fontSize, fontFamily, color, selectedColor, width, height, horizontalAlign, verticalAlign, text, editable, fit, id) {
|
|
4033
4355
|
const field = new DiagramField(this.model, rootElement, coords, width, height, fontSize, fontFamily, color, selectedColor, horizontalAlign, verticalAlign, text, editable, fit, id);
|
|
4034
4356
|
super.add(field);
|
|
@@ -4056,26 +4378,11 @@ class DiagramFieldSet extends DiagramEntitySet {
|
|
|
4056
4378
|
field.updateInView();
|
|
4057
4379
|
}
|
|
4058
4380
|
}
|
|
4059
|
-
filter(threshold) {
|
|
4060
|
-
return this.entities.filter((e) => {
|
|
4061
|
-
if (threshold !== undefined) {
|
|
4062
|
-
return e.getPriority() >= threshold;
|
|
4063
|
-
}
|
|
4064
|
-
return true;
|
|
4065
|
-
});
|
|
4066
|
-
}
|
|
4067
|
-
find(threshold) {
|
|
4068
|
-
return this.entities.find((e) => {
|
|
4069
|
-
if (threshold !== undefined) {
|
|
4070
|
-
return e.getPriority() >= threshold;
|
|
4071
|
-
}
|
|
4072
|
-
return true;
|
|
4073
|
-
});
|
|
4074
|
-
}
|
|
4075
4381
|
}
|
|
4076
4382
|
|
|
4077
4383
|
/**
|
|
4078
4384
|
* Stores the data of a diagram.
|
|
4385
|
+
* Represents the state of the diagram.
|
|
4079
4386
|
* @public
|
|
4080
4387
|
*/
|
|
4081
4388
|
class DiagramModel {
|
|
@@ -4117,44 +4424,102 @@ class DiagramModel {
|
|
|
4117
4424
|
this.type = type;
|
|
4118
4425
|
this.createdAt = new Date();
|
|
4119
4426
|
this.updatedAt = new Date();
|
|
4427
|
+
this.logicalClock = 0;
|
|
4120
4428
|
this.valueSet = new ValueSet(new PropertySet(properties), this);
|
|
4121
4429
|
}
|
|
4122
4430
|
/**
|
|
4123
|
-
* Deletes everything in this diagram.
|
|
4124
|
-
* @public
|
|
4431
|
+
* Deletes everything in this diagram.
|
|
4432
|
+
* @public
|
|
4433
|
+
*/
|
|
4434
|
+
clear() {
|
|
4435
|
+
this.canvas?.cancelAllUserActions();
|
|
4436
|
+
this.id = undefined;
|
|
4437
|
+
this.name = '';
|
|
4438
|
+
this.description = undefined;
|
|
4439
|
+
this.createdAt = new Date();
|
|
4440
|
+
this.updatedAt = new Date();
|
|
4441
|
+
this.logicalClock = 0;
|
|
4442
|
+
this.nodes.clear();
|
|
4443
|
+
this.sections.clear();
|
|
4444
|
+
this.ports.clear();
|
|
4445
|
+
this.connections.clear();
|
|
4446
|
+
this.fields.clear();
|
|
4447
|
+
this.valueSet.resetValues();
|
|
4448
|
+
this.canvas?.updateModelInView();
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
|
|
4452
|
+
/**
|
|
4453
|
+
* A collaboration engine, which manages collaboration for a diagram.
|
|
4454
|
+
* @private
|
|
4455
|
+
*/
|
|
4456
|
+
class CollabEngine {
|
|
4457
|
+
constructor(canvas) {
|
|
4458
|
+
/**
|
|
4459
|
+
* Whether we have joined (or are joining) a room on the server.
|
|
4460
|
+
*/
|
|
4461
|
+
this.isInRoom = false;
|
|
4462
|
+
this.canvas = canvas;
|
|
4463
|
+
this.replicaId = v4();
|
|
4464
|
+
}
|
|
4465
|
+
/**
|
|
4466
|
+
* Returns a fresh timestamp, suitable for use by new CollabActions.
|
|
4467
|
+
*/
|
|
4468
|
+
freshTimestamp() {
|
|
4469
|
+
this.canvas.model.logicalClock++;
|
|
4470
|
+
return [this.canvas.model.logicalClock, this.replicaId];
|
|
4471
|
+
}
|
|
4472
|
+
/**
|
|
4473
|
+
* Returns a fresh unique ID, suitable for use by new CollabActions.
|
|
4474
|
+
*/
|
|
4475
|
+
freshId() {
|
|
4476
|
+
// For more compressible saves, consider using a [dot ID](https://mattweidner.com/2023/09/26/crdt-survey-3.html#unique-ids-dots) instead of a new UUID each time.
|
|
4477
|
+
return v4();
|
|
4478
|
+
}
|
|
4479
|
+
/**
|
|
4480
|
+
* Performs the action - immediately locally, and eventually for remote collaborators.
|
|
4481
|
+
*/
|
|
4482
|
+
doCollaboratively(action) {
|
|
4483
|
+
// Perform the action locally.
|
|
4484
|
+
// Note: if this errors, it will prevent the action from performing collaboratively.
|
|
4485
|
+
action.do();
|
|
4486
|
+
if (this.onSend) {
|
|
4487
|
+
// Send the action to the server.
|
|
4488
|
+
const serialized = action.serialize();
|
|
4489
|
+
this.onSend(serialized);
|
|
4490
|
+
}
|
|
4491
|
+
}
|
|
4492
|
+
/**
|
|
4493
|
+
* Processes a message received from the server.
|
|
4494
|
+
*
|
|
4495
|
+
* The message is assumed to be non-redundant (in particular, not one of
|
|
4496
|
+
* our own messages) and delivered after all prior messages on the server.
|
|
4125
4497
|
*/
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4498
|
+
receive(message) {
|
|
4499
|
+
// Update local logical clock.
|
|
4500
|
+
if ('timestamp' in message) {
|
|
4501
|
+
this.canvas.model.logicalClock = Math.max(this.canvas.model.logicalClock, message.timestamp[0]);
|
|
4502
|
+
}
|
|
4503
|
+
// Perform CollabAction.
|
|
4504
|
+
switch (message.type) {
|
|
4505
|
+
case 'add': {
|
|
4506
|
+
const action = AddNodeCollabAction.deserialize(this.canvas, message);
|
|
4507
|
+
action.do();
|
|
4508
|
+
break;
|
|
4509
|
+
}
|
|
4510
|
+
case 'move': {
|
|
4511
|
+
const action = MoveNodeCollabAction.deserialize(this.canvas, message);
|
|
4512
|
+
action.do();
|
|
4513
|
+
break;
|
|
4514
|
+
}
|
|
4515
|
+
default: {
|
|
4516
|
+
const exhaustiveMessage = message;
|
|
4517
|
+
console.error('Unknown CollabAction type, skipping:', exhaustiveMessage);
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4140
4520
|
}
|
|
4141
4521
|
}
|
|
4142
4522
|
|
|
4143
|
-
var CursorStyle;
|
|
4144
|
-
(function (CursorStyle) {
|
|
4145
|
-
CursorStyle["AllScroll"] = "all-scroll";
|
|
4146
|
-
CursorStyle["Auto"] = "auto";
|
|
4147
|
-
CursorStyle["EWResize"] = "ew-resize";
|
|
4148
|
-
CursorStyle["Grab"] = "grab";
|
|
4149
|
-
CursorStyle["Grabbing"] = "grabbing";
|
|
4150
|
-
CursorStyle["Move"] = "move";
|
|
4151
|
-
CursorStyle["NoDrop"] = "no-drop";
|
|
4152
|
-
CursorStyle["NSResize"] = "ns-resize";
|
|
4153
|
-
CursorStyle["NotAllowed"] = "not-allowed";
|
|
4154
|
-
CursorStyle["ZoomIn"] = "zoom-in";
|
|
4155
|
-
CursorStyle["ZoomOut"] = "zoom-out";
|
|
4156
|
-
})(CursorStyle || (CursorStyle = {}));
|
|
4157
|
-
|
|
4158
4523
|
/**
|
|
4159
4524
|
* Thickness of the invisible path around a connection used to make it easier to click on, in pixels.
|
|
4160
4525
|
* @private
|
|
@@ -4206,6 +4571,7 @@ class DiagramCanvas {
|
|
|
4206
4571
|
this.userActions = config.userActions || {};
|
|
4207
4572
|
this.validators = [];
|
|
4208
4573
|
this.actionQueue = new ActionQueue(this, ACTION_QUEUE_SIZE);
|
|
4574
|
+
this.collabEngine = new CollabEngine(this);
|
|
4209
4575
|
// load node types
|
|
4210
4576
|
if (config.nodeTypes) {
|
|
4211
4577
|
for (const nodeTypeConfig of config.nodeTypes) {
|
|
@@ -4275,30 +4641,30 @@ class DiagramCanvas {
|
|
|
4275
4641
|
this.canUserPerformAction(DiagramActions.Remove)) {
|
|
4276
4642
|
// delete selection
|
|
4277
4643
|
if (this.userSelection.length > 0) {
|
|
4278
|
-
const
|
|
4279
|
-
const
|
|
4280
|
-
const
|
|
4281
|
-
const
|
|
4282
|
-
const
|
|
4644
|
+
const nodeIdsToBeDeleted = [];
|
|
4645
|
+
const sectionIdsToBeDeleted = [];
|
|
4646
|
+
const portIdsToBeDeleted = [];
|
|
4647
|
+
const connectionIdsToBeDeleted = [];
|
|
4648
|
+
const fieldIdsToBeDeleted = [];
|
|
4283
4649
|
for (const userSelectionElement of this.userSelection) {
|
|
4284
4650
|
if (userSelectionElement instanceof DiagramNode) {
|
|
4285
|
-
|
|
4651
|
+
nodeIdsToBeDeleted.push(userSelectionElement.id);
|
|
4286
4652
|
}
|
|
4287
4653
|
else if (userSelectionElement instanceof DiagramSection) {
|
|
4288
|
-
|
|
4654
|
+
sectionIdsToBeDeleted.push(userSelectionElement.id);
|
|
4289
4655
|
}
|
|
4290
4656
|
else if (userSelectionElement instanceof DiagramPort) {
|
|
4291
|
-
|
|
4657
|
+
portIdsToBeDeleted.push(userSelectionElement.id);
|
|
4292
4658
|
}
|
|
4293
4659
|
else if (userSelectionElement instanceof DiagramConnection) {
|
|
4294
|
-
|
|
4660
|
+
connectionIdsToBeDeleted.push(userSelectionElement.id);
|
|
4295
4661
|
}
|
|
4296
4662
|
else if (userSelectionElement instanceof DiagramField) {
|
|
4297
|
-
|
|
4663
|
+
fieldIdsToBeDeleted.push(userSelectionElement.id);
|
|
4298
4664
|
}
|
|
4299
4665
|
}
|
|
4300
|
-
const removeAction = new RemoveAction(this.model,
|
|
4301
|
-
removeAction.
|
|
4666
|
+
const removeAction = new RemoveAction(this.model, nodeIdsToBeDeleted, sectionIdsToBeDeleted, portIdsToBeDeleted, connectionIdsToBeDeleted, fieldIdsToBeDeleted);
|
|
4667
|
+
removeAction.do();
|
|
4302
4668
|
this.actionQueue.add(removeAction);
|
|
4303
4669
|
}
|
|
4304
4670
|
this.cancelAllUserActions();
|
|
@@ -4504,7 +4870,10 @@ class DiagramCanvas {
|
|
|
4504
4870
|
updateNodesInView(...ids) {
|
|
4505
4871
|
let updateSelection = this.selectCanvasNodes()
|
|
4506
4872
|
.selectAll('g.diagram-node')
|
|
4507
|
-
.data(this.model.nodes.filter(
|
|
4873
|
+
.data(this.model.nodes.filter((e) => !e.removed &&
|
|
4874
|
+
(this.priorityThreshold !== undefined
|
|
4875
|
+
? e.getPriority() >= this.priorityThreshold
|
|
4876
|
+
: true)), (d) => d.id);
|
|
4508
4877
|
const exitSelection = updateSelection.exit();
|
|
4509
4878
|
const enterSelection = updateSelection
|
|
4510
4879
|
.enter()
|
|
@@ -4529,7 +4898,8 @@ class DiagramCanvas {
|
|
|
4529
4898
|
.call(d3
|
|
4530
4899
|
.drag()
|
|
4531
4900
|
.on(DragEvents.Start, (event, d) => {
|
|
4532
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
4901
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
4902
|
+
!d.removed) {
|
|
4533
4903
|
cursorStyle(CursorStyle.Grabbing);
|
|
4534
4904
|
this.draggingFrom = [event.x, event.y];
|
|
4535
4905
|
this.currentAction = new MoveNodeAction(this, d.id, d.coords, [0, 0]);
|
|
@@ -4539,7 +4909,8 @@ class DiagramCanvas {
|
|
|
4539
4909
|
}
|
|
4540
4910
|
})
|
|
4541
4911
|
.on(DragEvents.Drag, (event, d) => {
|
|
4542
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
4912
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
4913
|
+
!d.removed) {
|
|
4543
4914
|
const newNodeCoords = [
|
|
4544
4915
|
event.x - d.width / 2,
|
|
4545
4916
|
event.y - d.height / 2
|
|
@@ -4548,7 +4919,8 @@ class DiagramCanvas {
|
|
|
4548
4919
|
}
|
|
4549
4920
|
})
|
|
4550
4921
|
.on(DragEvents.End, (event, d) => {
|
|
4551
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
4922
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
4923
|
+
!d.removed) {
|
|
4552
4924
|
// prevent drag behavior if mouse hasn't moved
|
|
4553
4925
|
if ((this.draggingFrom[0] !== event.x ||
|
|
4554
4926
|
this.draggingFrom[1] !== event.y) &&
|
|
@@ -4561,10 +4933,8 @@ class DiagramCanvas {
|
|
|
4561
4933
|
newNodeCoords = this.getClosestGridPoint(newNodeCoords);
|
|
4562
4934
|
}
|
|
4563
4935
|
this.currentAction.to = newNodeCoords;
|
|
4564
|
-
this.currentAction.
|
|
4936
|
+
this.currentAction.do();
|
|
4565
4937
|
this.actionQueue.add(this.currentAction);
|
|
4566
|
-
}
|
|
4567
|
-
else {
|
|
4568
4938
|
this.currentAction = undefined;
|
|
4569
4939
|
}
|
|
4570
4940
|
}
|
|
@@ -4628,13 +4998,15 @@ class DiagramCanvas {
|
|
|
4628
4998
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
4629
4999
|
.on(Events.MouseOver, (event, d) => {
|
|
4630
5000
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4631
|
-
d.type.resizableX
|
|
5001
|
+
d.type.resizableX &&
|
|
5002
|
+
!d.removed) {
|
|
4632
5003
|
cursorStyle(CursorStyle.EWResize);
|
|
4633
5004
|
}
|
|
4634
5005
|
})
|
|
4635
5006
|
.on(Events.MouseOut, (event, d) => {
|
|
4636
5007
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4637
|
-
d.type.resizableX
|
|
5008
|
+
d.type.resizableX &&
|
|
5009
|
+
!d.removed) {
|
|
4638
5010
|
cursorStyle();
|
|
4639
5011
|
}
|
|
4640
5012
|
})
|
|
@@ -4642,7 +5014,8 @@ class DiagramCanvas {
|
|
|
4642
5014
|
.drag()
|
|
4643
5015
|
.on(DragEvents.Start, (event, d) => {
|
|
4644
5016
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4645
|
-
d.type.resizableX
|
|
5017
|
+
d.type.resizableX &&
|
|
5018
|
+
!d.removed) {
|
|
4646
5019
|
cursorStyle(CursorStyle.EWResize);
|
|
4647
5020
|
this.currentAction = new StretchNodeAction(this, d.id, Side.Left, d.width, d.width);
|
|
4648
5021
|
}
|
|
@@ -4652,14 +5025,17 @@ class DiagramCanvas {
|
|
|
4652
5025
|
})
|
|
4653
5026
|
.on(DragEvents.Drag, (event, d) => {
|
|
4654
5027
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4655
|
-
d.type.resizableX
|
|
5028
|
+
d.type.resizableX &&
|
|
5029
|
+
!d.removed) {
|
|
4656
5030
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4657
5031
|
d.stretch(Side.Left, d.coords[0] - pointerCoords[0]);
|
|
4658
5032
|
}
|
|
4659
5033
|
})
|
|
4660
5034
|
.on(DragEvents.End, (event, d) => {
|
|
4661
5035
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4662
|
-
d.type.resizableX
|
|
5036
|
+
d.type.resizableX &&
|
|
5037
|
+
!d.removed &&
|
|
5038
|
+
this.currentAction instanceof StretchNodeAction) {
|
|
4663
5039
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4664
5040
|
if (this.snapToGrid) {
|
|
4665
5041
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -4679,13 +5055,15 @@ class DiagramCanvas {
|
|
|
4679
5055
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
4680
5056
|
.on(Events.MouseOver, (event, d) => {
|
|
4681
5057
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4682
|
-
d.type.resizableY
|
|
5058
|
+
d.type.resizableY &&
|
|
5059
|
+
!d.removed) {
|
|
4683
5060
|
cursorStyle(CursorStyle.NSResize);
|
|
4684
5061
|
}
|
|
4685
5062
|
})
|
|
4686
5063
|
.on(Events.MouseOut, (event, d) => {
|
|
4687
5064
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4688
|
-
d.type.resizableY
|
|
5065
|
+
d.type.resizableY &&
|
|
5066
|
+
!d.removed) {
|
|
4689
5067
|
cursorStyle();
|
|
4690
5068
|
}
|
|
4691
5069
|
})
|
|
@@ -4693,7 +5071,8 @@ class DiagramCanvas {
|
|
|
4693
5071
|
.drag()
|
|
4694
5072
|
.on(DragEvents.Start, (event, d) => {
|
|
4695
5073
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4696
|
-
d.type.resizableY
|
|
5074
|
+
d.type.resizableY &&
|
|
5075
|
+
!d.removed) {
|
|
4697
5076
|
cursorStyle(CursorStyle.NSResize);
|
|
4698
5077
|
this.currentAction = new StretchNodeAction(this, d.id, Side.Top, d.height, d.height);
|
|
4699
5078
|
}
|
|
@@ -4703,14 +5082,17 @@ class DiagramCanvas {
|
|
|
4703
5082
|
})
|
|
4704
5083
|
.on(DragEvents.Drag, (event, d) => {
|
|
4705
5084
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4706
|
-
d.type.resizableY
|
|
5085
|
+
d.type.resizableY &&
|
|
5086
|
+
!d.removed) {
|
|
4707
5087
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4708
5088
|
d.stretch(Side.Top, d.coords[1] - pointerCoords[1]);
|
|
4709
5089
|
}
|
|
4710
5090
|
})
|
|
4711
5091
|
.on(DragEvents.End, (event, d) => {
|
|
4712
5092
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4713
|
-
d.type.resizableY
|
|
5093
|
+
d.type.resizableY &&
|
|
5094
|
+
!d.removed &&
|
|
5095
|
+
this.currentAction instanceof StretchNodeAction) {
|
|
4714
5096
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4715
5097
|
if (this.snapToGrid) {
|
|
4716
5098
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -4730,13 +5112,15 @@ class DiagramCanvas {
|
|
|
4730
5112
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
4731
5113
|
.on(Events.MouseOver, (event, d) => {
|
|
4732
5114
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4733
|
-
d.type.resizableX
|
|
5115
|
+
d.type.resizableX &&
|
|
5116
|
+
!d.removed) {
|
|
4734
5117
|
cursorStyle(CursorStyle.EWResize);
|
|
4735
5118
|
}
|
|
4736
5119
|
})
|
|
4737
5120
|
.on(Events.MouseOut, (event, d) => {
|
|
4738
5121
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4739
|
-
d.type.resizableX
|
|
5122
|
+
d.type.resizableX &&
|
|
5123
|
+
!d.removed) {
|
|
4740
5124
|
cursorStyle();
|
|
4741
5125
|
}
|
|
4742
5126
|
})
|
|
@@ -4744,7 +5128,8 @@ class DiagramCanvas {
|
|
|
4744
5128
|
.drag()
|
|
4745
5129
|
.on(DragEvents.Start, (event, d) => {
|
|
4746
5130
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4747
|
-
d.type.resizableX
|
|
5131
|
+
d.type.resizableX &&
|
|
5132
|
+
!d.removed) {
|
|
4748
5133
|
cursorStyle(CursorStyle.EWResize);
|
|
4749
5134
|
this.currentAction = new StretchNodeAction(this, d.id, Side.Right, d.width, d.width);
|
|
4750
5135
|
}
|
|
@@ -4754,14 +5139,17 @@ class DiagramCanvas {
|
|
|
4754
5139
|
})
|
|
4755
5140
|
.on(DragEvents.Drag, (event, d) => {
|
|
4756
5141
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4757
|
-
d.type.resizableX
|
|
5142
|
+
d.type.resizableX &&
|
|
5143
|
+
!d.removed) {
|
|
4758
5144
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4759
5145
|
d.stretch(Side.Right, pointerCoords[0] - (d.coords[0] + d.width));
|
|
4760
5146
|
}
|
|
4761
5147
|
})
|
|
4762
5148
|
.on(DragEvents.End, (event, d) => {
|
|
4763
5149
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4764
|
-
d.type.resizableX
|
|
5150
|
+
d.type.resizableX &&
|
|
5151
|
+
!d.removed &&
|
|
5152
|
+
this.currentAction instanceof StretchNodeAction) {
|
|
4765
5153
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4766
5154
|
if (this.snapToGrid) {
|
|
4767
5155
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -4781,13 +5169,15 @@ class DiagramCanvas {
|
|
|
4781
5169
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
4782
5170
|
.on(Events.MouseOver, (event, d) => {
|
|
4783
5171
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4784
|
-
d.type.resizableY
|
|
5172
|
+
d.type.resizableY &&
|
|
5173
|
+
!d.removed) {
|
|
4785
5174
|
cursorStyle(CursorStyle.NSResize);
|
|
4786
5175
|
}
|
|
4787
5176
|
})
|
|
4788
5177
|
.on(Events.MouseOut, (event, d) => {
|
|
4789
5178
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4790
|
-
d.type.resizableY
|
|
5179
|
+
d.type.resizableY &&
|
|
5180
|
+
!d.removed) {
|
|
4791
5181
|
cursorStyle();
|
|
4792
5182
|
}
|
|
4793
5183
|
})
|
|
@@ -4795,7 +5185,8 @@ class DiagramCanvas {
|
|
|
4795
5185
|
.drag()
|
|
4796
5186
|
.on(DragEvents.Start, (event, d) => {
|
|
4797
5187
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4798
|
-
d.type.resizableY
|
|
5188
|
+
d.type.resizableY &&
|
|
5189
|
+
!d.removed) {
|
|
4799
5190
|
cursorStyle(CursorStyle.NSResize);
|
|
4800
5191
|
this.currentAction = new StretchNodeAction(this, d.id, Side.Bottom, d.height, d.height);
|
|
4801
5192
|
}
|
|
@@ -4805,14 +5196,17 @@ class DiagramCanvas {
|
|
|
4805
5196
|
})
|
|
4806
5197
|
.on(DragEvents.Drag, (event, d) => {
|
|
4807
5198
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4808
|
-
d.type.resizableY
|
|
5199
|
+
d.type.resizableY &&
|
|
5200
|
+
!d.removed) {
|
|
4809
5201
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4810
5202
|
d.stretch(Side.Bottom, pointerCoords[1] - (d.coords[1] + d.height));
|
|
4811
5203
|
}
|
|
4812
5204
|
})
|
|
4813
5205
|
.on(DragEvents.End, (event, d) => {
|
|
4814
5206
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4815
|
-
d.type.resizableY
|
|
5207
|
+
d.type.resizableY &&
|
|
5208
|
+
!d.removed &&
|
|
5209
|
+
this.currentAction instanceof StretchNodeAction) {
|
|
4816
5210
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4817
5211
|
if (this.snapToGrid) {
|
|
4818
5212
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -4824,7 +5218,9 @@ class DiagramCanvas {
|
|
|
4824
5218
|
}
|
|
4825
5219
|
cursorStyle();
|
|
4826
5220
|
}));
|
|
4827
|
-
mergeSelection
|
|
5221
|
+
mergeSelection
|
|
5222
|
+
.attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
|
|
5223
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1));
|
|
4828
5224
|
mergeSelection
|
|
4829
5225
|
.filter('.shaped-look')
|
|
4830
5226
|
.select('path')
|
|
@@ -4988,7 +5384,10 @@ class DiagramCanvas {
|
|
|
4988
5384
|
updateSectionsInView(...ids) {
|
|
4989
5385
|
let updateSelection = this.selectCanvasSections()
|
|
4990
5386
|
.selectAll('g.diagram-section')
|
|
4991
|
-
.data(this.model.sections.filter(
|
|
5387
|
+
.data(this.model.sections.filter((e) => !e.removed &&
|
|
5388
|
+
(this.priorityThreshold !== undefined
|
|
5389
|
+
? e.getPriority() >= this.priorityThreshold
|
|
5390
|
+
: true)), (d) => d.id);
|
|
4992
5391
|
const exitSelection = updateSelection.exit();
|
|
4993
5392
|
const enterSelection = updateSelection
|
|
4994
5393
|
.enter()
|
|
@@ -5013,7 +5412,8 @@ class DiagramCanvas {
|
|
|
5013
5412
|
.call(d3
|
|
5014
5413
|
.drag()
|
|
5015
5414
|
.on(DragEvents.Start, (event, d) => {
|
|
5016
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
5415
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
5416
|
+
!d.removed) {
|
|
5017
5417
|
const node = d.node;
|
|
5018
5418
|
cursorStyle(CursorStyle.Grabbing);
|
|
5019
5419
|
this.draggingFrom = [event.x, event.y];
|
|
@@ -5024,7 +5424,8 @@ class DiagramCanvas {
|
|
|
5024
5424
|
}
|
|
5025
5425
|
})
|
|
5026
5426
|
.on(DragEvents.Drag, (event, d) => {
|
|
5027
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
5427
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
5428
|
+
!d.removed) {
|
|
5028
5429
|
const node = d.node;
|
|
5029
5430
|
const newNodeCoords = [
|
|
5030
5431
|
event.x - node.width / 2,
|
|
@@ -5034,7 +5435,8 @@ class DiagramCanvas {
|
|
|
5034
5435
|
}
|
|
5035
5436
|
})
|
|
5036
5437
|
.on(DragEvents.End, (event, d) => {
|
|
5037
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
5438
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
5439
|
+
!d.removed) {
|
|
5038
5440
|
const node = d.node;
|
|
5039
5441
|
// prevent drag behavior if mouse hasn't moved
|
|
5040
5442
|
if ((this.draggingFrom[0] !== event.x ||
|
|
@@ -5048,10 +5450,8 @@ class DiagramCanvas {
|
|
|
5048
5450
|
newNodeCoords = this.getClosestGridPoint(newNodeCoords);
|
|
5049
5451
|
}
|
|
5050
5452
|
this.currentAction.to = newNodeCoords;
|
|
5051
|
-
this.currentAction.
|
|
5453
|
+
this.currentAction.do();
|
|
5052
5454
|
this.actionQueue.add(this.currentAction);
|
|
5053
|
-
}
|
|
5054
|
-
else {
|
|
5055
5455
|
this.currentAction = undefined;
|
|
5056
5456
|
}
|
|
5057
5457
|
}
|
|
@@ -5115,13 +5515,15 @@ class DiagramCanvas {
|
|
|
5115
5515
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
5116
5516
|
.on(Events.MouseOver, (event, d) => {
|
|
5117
5517
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5118
|
-
d.node?.type?.resizableX
|
|
5518
|
+
d.node?.type?.resizableX &&
|
|
5519
|
+
!d.removed) {
|
|
5119
5520
|
cursorStyle(CursorStyle.EWResize);
|
|
5120
5521
|
}
|
|
5121
5522
|
})
|
|
5122
5523
|
.on(Events.MouseOut, (event, d) => {
|
|
5123
5524
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5124
|
-
d.node?.type?.resizableX
|
|
5525
|
+
d.node?.type?.resizableX &&
|
|
5526
|
+
!d.removed) {
|
|
5125
5527
|
cursorStyle();
|
|
5126
5528
|
}
|
|
5127
5529
|
})
|
|
@@ -5129,7 +5531,8 @@ class DiagramCanvas {
|
|
|
5129
5531
|
.drag()
|
|
5130
5532
|
.on(DragEvents.Start, (event, d) => {
|
|
5131
5533
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5132
|
-
d.node?.type?.resizableX
|
|
5534
|
+
d.node?.type?.resizableX &&
|
|
5535
|
+
!d.removed) {
|
|
5133
5536
|
cursorStyle(CursorStyle.EWResize);
|
|
5134
5537
|
this.currentAction = new StretchSectionAction(this, d.id, Side.Left, d.width, d.width);
|
|
5135
5538
|
}
|
|
@@ -5139,14 +5542,17 @@ class DiagramCanvas {
|
|
|
5139
5542
|
})
|
|
5140
5543
|
.on(DragEvents.Drag, (event, d) => {
|
|
5141
5544
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5142
|
-
d.node?.type?.resizableX
|
|
5545
|
+
d.node?.type?.resizableX &&
|
|
5546
|
+
!d.removed) {
|
|
5143
5547
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5144
5548
|
d.node.stretchSections(Side.Left, d.coords[0] - pointerCoords[0], d.indexXInNode, d.indexYInNode);
|
|
5145
5549
|
}
|
|
5146
5550
|
})
|
|
5147
5551
|
.on(DragEvents.End, (event, d) => {
|
|
5148
5552
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5149
|
-
d.node?.type?.resizableX
|
|
5553
|
+
d.node?.type?.resizableX &&
|
|
5554
|
+
!d.removed &&
|
|
5555
|
+
this.currentAction instanceof StretchSectionAction) {
|
|
5150
5556
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5151
5557
|
if (this.snapToGrid) {
|
|
5152
5558
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -5166,13 +5572,15 @@ class DiagramCanvas {
|
|
|
5166
5572
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
5167
5573
|
.on(Events.MouseOver, (event, d) => {
|
|
5168
5574
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5169
|
-
d.node?.type?.resizableY
|
|
5575
|
+
d.node?.type?.resizableY &&
|
|
5576
|
+
!d.removed) {
|
|
5170
5577
|
cursorStyle(CursorStyle.NSResize);
|
|
5171
5578
|
}
|
|
5172
5579
|
})
|
|
5173
5580
|
.on(Events.MouseOut, (event, d) => {
|
|
5174
5581
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5175
|
-
d.node?.type?.resizableY
|
|
5582
|
+
d.node?.type?.resizableY &&
|
|
5583
|
+
!d.removed) {
|
|
5176
5584
|
cursorStyle();
|
|
5177
5585
|
}
|
|
5178
5586
|
})
|
|
@@ -5180,7 +5588,8 @@ class DiagramCanvas {
|
|
|
5180
5588
|
.drag()
|
|
5181
5589
|
.on(DragEvents.Start, (event, d) => {
|
|
5182
5590
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5183
|
-
d.node?.type?.resizableY
|
|
5591
|
+
d.node?.type?.resizableY &&
|
|
5592
|
+
!d.removed) {
|
|
5184
5593
|
cursorStyle(CursorStyle.NSResize);
|
|
5185
5594
|
this.currentAction = new StretchSectionAction(this, d.id, Side.Top, d.height, d.height);
|
|
5186
5595
|
}
|
|
@@ -5190,14 +5599,17 @@ class DiagramCanvas {
|
|
|
5190
5599
|
})
|
|
5191
5600
|
.on(DragEvents.Drag, (event, d) => {
|
|
5192
5601
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5193
|
-
d.node?.type?.resizableY
|
|
5602
|
+
d.node?.type?.resizableY &&
|
|
5603
|
+
!d.removed) {
|
|
5194
5604
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5195
5605
|
d.node.stretchSections(Side.Top, d.coords[1] - pointerCoords[1], d.indexXInNode, d.indexYInNode);
|
|
5196
5606
|
}
|
|
5197
5607
|
})
|
|
5198
5608
|
.on(DragEvents.End, (event, d) => {
|
|
5199
5609
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5200
|
-
d.node?.type?.resizableY
|
|
5610
|
+
d.node?.type?.resizableY &&
|
|
5611
|
+
!d.removed &&
|
|
5612
|
+
this.currentAction instanceof StretchSectionAction) {
|
|
5201
5613
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5202
5614
|
if (this.snapToGrid) {
|
|
5203
5615
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -5217,13 +5629,15 @@ class DiagramCanvas {
|
|
|
5217
5629
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
5218
5630
|
.on(Events.MouseOver, (event, d) => {
|
|
5219
5631
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5220
|
-
d.node?.type?.resizableX
|
|
5632
|
+
d.node?.type?.resizableX &&
|
|
5633
|
+
!d.removed) {
|
|
5221
5634
|
cursorStyle(CursorStyle.EWResize);
|
|
5222
5635
|
}
|
|
5223
5636
|
})
|
|
5224
5637
|
.on(Events.MouseOut, (event, d) => {
|
|
5225
5638
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5226
|
-
d.node?.type?.resizableX
|
|
5639
|
+
d.node?.type?.resizableX &&
|
|
5640
|
+
!d.removed) {
|
|
5227
5641
|
cursorStyle();
|
|
5228
5642
|
}
|
|
5229
5643
|
})
|
|
@@ -5231,7 +5645,8 @@ class DiagramCanvas {
|
|
|
5231
5645
|
.drag()
|
|
5232
5646
|
.on(DragEvents.Start, (event, d) => {
|
|
5233
5647
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5234
|
-
d.node?.type?.resizableX
|
|
5648
|
+
d.node?.type?.resizableX &&
|
|
5649
|
+
!d.removed) {
|
|
5235
5650
|
cursorStyle(CursorStyle.EWResize);
|
|
5236
5651
|
this.currentAction = new StretchSectionAction(this, d.id, Side.Right, d.width, d.width);
|
|
5237
5652
|
}
|
|
@@ -5241,14 +5656,17 @@ class DiagramCanvas {
|
|
|
5241
5656
|
})
|
|
5242
5657
|
.on(DragEvents.Drag, (event, d) => {
|
|
5243
5658
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5244
|
-
d.node?.type?.resizableX
|
|
5659
|
+
d.node?.type?.resizableX &&
|
|
5660
|
+
!d.removed) {
|
|
5245
5661
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5246
5662
|
d.node.stretchSections(Side.Right, pointerCoords[0] - (d.coords[0] + d.width), d.indexXInNode, d.indexYInNode);
|
|
5247
5663
|
}
|
|
5248
5664
|
})
|
|
5249
5665
|
.on(DragEvents.End, (event, d) => {
|
|
5250
5666
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5251
|
-
d.node?.type?.resizableX
|
|
5667
|
+
d.node?.type?.resizableX &&
|
|
5668
|
+
!d.removed &&
|
|
5669
|
+
this.currentAction instanceof StretchSectionAction) {
|
|
5252
5670
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5253
5671
|
if (this.snapToGrid) {
|
|
5254
5672
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -5268,13 +5686,15 @@ class DiagramCanvas {
|
|
|
5268
5686
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
5269
5687
|
.on(Events.MouseOver, (event, d) => {
|
|
5270
5688
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5271
|
-
d.node?.type?.resizableY
|
|
5689
|
+
d.node?.type?.resizableY &&
|
|
5690
|
+
!d.removed) {
|
|
5272
5691
|
cursorStyle(CursorStyle.NSResize);
|
|
5273
5692
|
}
|
|
5274
5693
|
})
|
|
5275
5694
|
.on(Events.MouseOut, (event, d) => {
|
|
5276
5695
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5277
|
-
d.node?.type?.resizableY
|
|
5696
|
+
d.node?.type?.resizableY &&
|
|
5697
|
+
!d.removed) {
|
|
5278
5698
|
cursorStyle();
|
|
5279
5699
|
}
|
|
5280
5700
|
})
|
|
@@ -5282,7 +5702,8 @@ class DiagramCanvas {
|
|
|
5282
5702
|
.drag()
|
|
5283
5703
|
.on(DragEvents.Start, (event, d) => {
|
|
5284
5704
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5285
|
-
d.node?.type?.resizableY
|
|
5705
|
+
d.node?.type?.resizableY &&
|
|
5706
|
+
!d.removed) {
|
|
5286
5707
|
cursorStyle(CursorStyle.NSResize);
|
|
5287
5708
|
this.currentAction = new StretchSectionAction(this, d.id, Side.Bottom, d.height, d.height);
|
|
5288
5709
|
}
|
|
@@ -5292,14 +5713,17 @@ class DiagramCanvas {
|
|
|
5292
5713
|
})
|
|
5293
5714
|
.on(DragEvents.Drag, (event, d) => {
|
|
5294
5715
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5295
|
-
d.node?.type?.resizableY
|
|
5716
|
+
d.node?.type?.resizableY &&
|
|
5717
|
+
!d.removed) {
|
|
5296
5718
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5297
5719
|
d.node.stretchSections(Side.Bottom, pointerCoords[1] - (d.coords[1] + d.height), d.indexXInNode, d.indexYInNode);
|
|
5298
5720
|
}
|
|
5299
5721
|
})
|
|
5300
5722
|
.on(DragEvents.End, (event, d) => {
|
|
5301
5723
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5302
|
-
d.node?.type?.resizableY
|
|
5724
|
+
d.node?.type?.resizableY &&
|
|
5725
|
+
!d.removed &&
|
|
5726
|
+
this.currentAction instanceof StretchSectionAction) {
|
|
5303
5727
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5304
5728
|
if (this.snapToGrid) {
|
|
5305
5729
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -5311,7 +5735,9 @@ class DiagramCanvas {
|
|
|
5311
5735
|
}
|
|
5312
5736
|
cursorStyle();
|
|
5313
5737
|
}));
|
|
5314
|
-
mergeSelection
|
|
5738
|
+
mergeSelection
|
|
5739
|
+
.attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
|
|
5740
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1));
|
|
5315
5741
|
mergeSelection
|
|
5316
5742
|
.filter('.shaped-look')
|
|
5317
5743
|
.select('path')
|
|
@@ -5490,7 +5916,10 @@ class DiagramCanvas {
|
|
|
5490
5916
|
updatePortsInView(...ids) {
|
|
5491
5917
|
let updateSelection = this.selectCanvasPorts()
|
|
5492
5918
|
.selectAll('g.diagram-port')
|
|
5493
|
-
.data(this.model.ports.filter(
|
|
5919
|
+
.data(this.model.ports.filter((e) => !e.removed &&
|
|
5920
|
+
(this.priorityThreshold !== undefined
|
|
5921
|
+
? e.getPriority() >= this.priorityThreshold
|
|
5922
|
+
: true)), (d) => d.id);
|
|
5494
5923
|
const exitSelection = updateSelection.exit();
|
|
5495
5924
|
const enterSelection = updateSelection
|
|
5496
5925
|
.enter()
|
|
@@ -5529,7 +5958,8 @@ class DiagramCanvas {
|
|
|
5529
5958
|
.call(d3
|
|
5530
5959
|
.drag()
|
|
5531
5960
|
.on(DragEvents.Start, (event, d) => {
|
|
5532
|
-
if (this.canUserPerformAction(DiagramActions.AddConnection)
|
|
5961
|
+
if (this.canUserPerformAction(DiagramActions.AddConnection) &&
|
|
5962
|
+
!d.removed) {
|
|
5533
5963
|
cursorStyle(CursorStyle.Grabbing);
|
|
5534
5964
|
this.startConnection(d);
|
|
5535
5965
|
// should be true after having called this.startConnection()
|
|
@@ -5540,9 +5970,13 @@ class DiagramCanvas {
|
|
|
5540
5970
|
.attr('fill', 'none');
|
|
5541
5971
|
}
|
|
5542
5972
|
}
|
|
5973
|
+
else {
|
|
5974
|
+
cursorStyle(CursorStyle.NotAllowed);
|
|
5975
|
+
}
|
|
5543
5976
|
})
|
|
5544
|
-
.on(DragEvents.Drag, (event) => {
|
|
5545
|
-
if (this.canUserPerformAction(DiagramActions.AddConnection)
|
|
5977
|
+
.on(DragEvents.Drag, (event, d) => {
|
|
5978
|
+
if (this.canUserPerformAction(DiagramActions.AddConnection) &&
|
|
5979
|
+
!d.removed) {
|
|
5546
5980
|
if (this.unfinishedConnection !== undefined) {
|
|
5547
5981
|
const endCoords = [event.x, event.y];
|
|
5548
5982
|
this.unfinishedConnectionTracer?.attr('d', getConnectionPath(this.unfinishedConnection.type.shape, this.unfinishedConnection.startCoords, endCoords, this.unfinishedConnection.startDirection, this.unfinishedConnection.endDirection, this.unfinishedConnection.type.width, this.unfinishedConnection.startMarkerLook?.markerWidth, this.unfinishedConnection.endMarkerLook?.markerWidth));
|
|
@@ -5567,9 +6001,9 @@ class DiagramCanvas {
|
|
|
5567
6001
|
}
|
|
5568
6002
|
}
|
|
5569
6003
|
})
|
|
5570
|
-
.on(DragEvents.End, (event) => {
|
|
5571
|
-
if (this.canUserPerformAction(DiagramActions.AddConnection)
|
|
5572
|
-
|
|
6004
|
+
.on(DragEvents.End, (event, d) => {
|
|
6005
|
+
if (this.canUserPerformAction(DiagramActions.AddConnection) &&
|
|
6006
|
+
!d.removed) {
|
|
5573
6007
|
this.unfinishedConnectionTracer?.remove();
|
|
5574
6008
|
if (this.mainUserHighlight instanceof DiagramPort) {
|
|
5575
6009
|
this.finishConnection(this.mainUserHighlight);
|
|
@@ -5605,10 +6039,12 @@ class DiagramCanvas {
|
|
|
5605
6039
|
this.dropConnection();
|
|
5606
6040
|
}
|
|
5607
6041
|
}
|
|
6042
|
+
cursorStyle();
|
|
5608
6043
|
}));
|
|
5609
6044
|
enterSelection.append('circle');
|
|
5610
6045
|
mergeSelection
|
|
5611
6046
|
.attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
|
|
6047
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1))
|
|
5612
6048
|
.select('circle')
|
|
5613
6049
|
.attr('cx', 0)
|
|
5614
6050
|
.attr('cy', 0)
|
|
@@ -5619,7 +6055,10 @@ class DiagramCanvas {
|
|
|
5619
6055
|
.attr('opacity', (d) => (d.highlighted || d.selected ? 0.5 : 0));
|
|
5620
6056
|
}
|
|
5621
6057
|
updateConnectionsInView(...ids) {
|
|
5622
|
-
const connectionList = this.model.connections.filter(
|
|
6058
|
+
const connectionList = this.model.connections.filter((e) => !e.removed &&
|
|
6059
|
+
(this.priorityThreshold !== undefined
|
|
6060
|
+
? e.getPriority() >= this.priorityThreshold
|
|
6061
|
+
: true));
|
|
5623
6062
|
if (this.unfinishedConnection) {
|
|
5624
6063
|
connectionList.push(this.unfinishedConnection);
|
|
5625
6064
|
}
|
|
@@ -5682,6 +6121,7 @@ class DiagramCanvas {
|
|
|
5682
6121
|
.append('text')
|
|
5683
6122
|
.style('user-select', 'none');
|
|
5684
6123
|
mergeSelection
|
|
6124
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1))
|
|
5685
6125
|
.select('path.diagram-connection-path')
|
|
5686
6126
|
.attr('d', (d) => getConnectionPath(d.type.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.type.width, d.startMarkerLook?.markerWidth, d.endMarkerLook?.markerWidth))
|
|
5687
6127
|
.attr('marker-start', (d) => `url(#${d.id}-start-marker)`)
|
|
@@ -5707,7 +6147,10 @@ class DiagramCanvas {
|
|
|
5707
6147
|
updateFieldsInView(...ids) {
|
|
5708
6148
|
let updateSelection = this.selectCanvasFields()
|
|
5709
6149
|
.selectAll('foreignObject.diagram-field')
|
|
5710
|
-
.data(this.model.fields.filter(
|
|
6150
|
+
.data(this.model.fields.filter((e) => !e.removed &&
|
|
6151
|
+
(this.priorityThreshold !== undefined
|
|
6152
|
+
? e.getPriority() >= this.priorityThreshold
|
|
6153
|
+
: true)), (d) => d.id);
|
|
5711
6154
|
const exitSelection = updateSelection.exit();
|
|
5712
6155
|
const enterSelection = updateSelection
|
|
5713
6156
|
.enter()
|
|
@@ -5733,7 +6176,9 @@ class DiagramCanvas {
|
|
|
5733
6176
|
}
|
|
5734
6177
|
})
|
|
5735
6178
|
.on(Events.DoubleClick, (event, d) => {
|
|
5736
|
-
if (this.canUserPerformAction(DiagramActions.EditField) &&
|
|
6179
|
+
if (this.canUserPerformAction(DiagramActions.EditField) &&
|
|
6180
|
+
d.editable &&
|
|
6181
|
+
!d.removed) {
|
|
5737
6182
|
this.currentAction = new EditFieldAction(this, d.id, d.text, '');
|
|
5738
6183
|
this.createInputField(d.text, d.coords, d.width, d.height, d.fontSize, d.fontFamily || DIAGRAM_FIELD_DEFAULTS.fontFamily, (text) => {
|
|
5739
6184
|
d.text = text;
|
|
@@ -5750,7 +6195,8 @@ class DiagramCanvas {
|
|
|
5750
6195
|
.call(d3
|
|
5751
6196
|
.drag()
|
|
5752
6197
|
.on(DragEvents.Start, (event, d) => {
|
|
5753
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
6198
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
6199
|
+
!d.removed) {
|
|
5754
6200
|
if (d.rootElement instanceof DiagramNode ||
|
|
5755
6201
|
d.rootElement instanceof DiagramSection) {
|
|
5756
6202
|
const node = d.rootElement instanceof DiagramNode
|
|
@@ -5766,7 +6212,8 @@ class DiagramCanvas {
|
|
|
5766
6212
|
}
|
|
5767
6213
|
})
|
|
5768
6214
|
.on(DragEvents.Drag, (event, d) => {
|
|
5769
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
6215
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
6216
|
+
!d.removed) {
|
|
5770
6217
|
if (d.rootElement instanceof DiagramNode ||
|
|
5771
6218
|
d.rootElement instanceof DiagramSection) {
|
|
5772
6219
|
const node = d.rootElement instanceof DiagramNode
|
|
@@ -5781,7 +6228,8 @@ class DiagramCanvas {
|
|
|
5781
6228
|
}
|
|
5782
6229
|
})
|
|
5783
6230
|
.on(DragEvents.End, (event, d) => {
|
|
5784
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
6231
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
6232
|
+
!d.removed) {
|
|
5785
6233
|
if (d.rootElement instanceof DiagramNode ||
|
|
5786
6234
|
d.rootElement instanceof DiagramSection) {
|
|
5787
6235
|
const node = d.rootElement instanceof DiagramNode
|
|
@@ -5799,10 +6247,8 @@ class DiagramCanvas {
|
|
|
5799
6247
|
newNodeCoords = this.getClosestGridPoint(newNodeCoords);
|
|
5800
6248
|
}
|
|
5801
6249
|
this.currentAction.to = newNodeCoords;
|
|
5802
|
-
this.currentAction.
|
|
6250
|
+
this.currentAction.do();
|
|
5803
6251
|
this.actionQueue.add(this.currentAction);
|
|
5804
|
-
}
|
|
5805
|
-
else {
|
|
5806
6252
|
this.currentAction = undefined;
|
|
5807
6253
|
}
|
|
5808
6254
|
}
|
|
@@ -5828,6 +6274,7 @@ class DiagramCanvas {
|
|
|
5828
6274
|
.attr('width', (d) => `${d.width}px`)
|
|
5829
6275
|
.attr('height', (d) => `${d.height}px`)
|
|
5830
6276
|
.attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
|
|
6277
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1))
|
|
5831
6278
|
.select('div')
|
|
5832
6279
|
.style('justify-content', (d) => d.horizontalAlign === HorizontalAlign.Center
|
|
5833
6280
|
? 'center'
|
|
@@ -6196,7 +6643,7 @@ class DiagramCanvas {
|
|
|
6196
6643
|
const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, this.unfinishedConnection.start?.id, port.id);
|
|
6197
6644
|
// clean up the previous unfinished connection
|
|
6198
6645
|
this.dropConnection();
|
|
6199
|
-
addConnectionAction.
|
|
6646
|
+
addConnectionAction.do();
|
|
6200
6647
|
this.actionQueue.add(addConnectionAction);
|
|
6201
6648
|
}
|
|
6202
6649
|
else if (this.unfinishedConnection.type.canFinishOnType(this.unfinishedConnection?.start?.getNode()?.type?.id || '') &&
|
|
@@ -6204,7 +6651,7 @@ class DiagramCanvas {
|
|
|
6204
6651
|
const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, port.id, this.unfinishedConnection.start?.id);
|
|
6205
6652
|
// clean up the previous unfinished connection
|
|
6206
6653
|
this.dropConnection();
|
|
6207
|
-
addConnectionAction.
|
|
6654
|
+
addConnectionAction.do();
|
|
6208
6655
|
this.actionQueue.add(addConnectionAction);
|
|
6209
6656
|
}
|
|
6210
6657
|
else {
|
|
@@ -6228,7 +6675,7 @@ class DiagramCanvas {
|
|
|
6228
6675
|
: port.id);
|
|
6229
6676
|
// clean up the previous unfinished connection
|
|
6230
6677
|
this.dropConnection();
|
|
6231
|
-
addConnectionAction.
|
|
6678
|
+
addConnectionAction.do();
|
|
6232
6679
|
this.actionQueue.add(addConnectionAction);
|
|
6233
6680
|
}
|
|
6234
6681
|
else {
|
|
@@ -6317,7 +6764,10 @@ class DiagramCanvas {
|
|
|
6317
6764
|
// check if there have been changes in the previously selected ValueSet,
|
|
6318
6765
|
// and create an UpdateValuesAction if there have
|
|
6319
6766
|
if (!equals(this.propertyEditorValues, this.propertyEditorSelection?.valueSet.getValues())) {
|
|
6320
|
-
const
|
|
6767
|
+
const from = this.propertyEditorValues;
|
|
6768
|
+
const to = structuredClone(this.propertyEditorSelection?.valueSet.getValues());
|
|
6769
|
+
const [fromDiff, toDiff] = diff(from, to);
|
|
6770
|
+
const currentAction = new UpdateValuesAction(this.model, previousSelectionId, fromDiff, toDiff);
|
|
6321
6771
|
this.actionQueue.add(currentAction);
|
|
6322
6772
|
this.propertyEditorValues = undefined;
|
|
6323
6773
|
}
|
|
@@ -6681,7 +7131,7 @@ class DiagramButtonsComponent {
|
|
|
6681
7131
|
this.canvas.actionQueue.redo();
|
|
6682
7132
|
}
|
|
6683
7133
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DiagramButtonsComponent, deps: [{ token: CanvasProviderService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6684
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: DiagramButtonsComponent, isStandalone: true, selector: "daga-diagram-buttons", inputs: { location: "location", direction: "direction", enableFilter: "enableFilter", enableLayout: "enableLayout", enableUndoRedo: "enableUndoRedo", enableZoom: "enableZoom", zoomRate: "zoomRate" }, viewQueries: [{ propertyName: "collapsableButtons", first: true, predicate: ["collapsableButtons"], descendants: true }], ngImport: i0, template: "<div class=\"diagram-buttons {{ location }} {{ direction }}\">\r\n <button\r\n *ngIf=\"enableZoom && canvas.canUserPerformAction(DiagramActions.Zoom)\"\r\n class=\"zoom-in\"\r\n (click)=\"zoomIn()\"\r\n >\r\n <span class=\"tooltip\">Zoom in</span>\r\n </button>\r\n <button\r\n *ngIf=\"enableZoom && canvas.canUserPerformAction(DiagramActions.Zoom)\"\r\n class=\"zoom-out\"\r\n (click)=\"zoomOut()\"\r\n >\r\n <span class=\"tooltip\">Zoom out</span>\r\n </button>\r\n <div #collapsableButtons class=\"collapsable-buttons collapsed\">\r\n <button\r\n *ngIf=\"enableZoom && canvas.canUserPerformAction(DiagramActions.Zoom)\"\r\n class=\"center\"\r\n (click)=\"center()\"\r\n >\r\n <span class=\"tooltip\">Fit diagram to screen</span>\r\n </button>\r\n <button *ngIf=\"enableUndoRedo\" class=\"undo\" (click)=\"undo()\">\r\n <span class=\"tooltip\">Undo</span>\r\n </button>\r\n <button *ngIf=\"enableUndoRedo\" class=\"redo\" (click)=\"redo()\">\r\n <span class=\"tooltip\">Redo</span>\r\n </button>\r\n <button\r\n *ngIf=\"enableLayout && canvas.layoutFormat\"\r\n class=\"layout\"\r\n (click)=\"layout()\"\r\n >\r\n <span class=\"tooltip\">Apply layout</span>\r\n </button>\r\n <button\r\n *ngIf=\"enableFilter\"\r\n class=\"filter\"\r\n [class]=\"filterOn ? 'on' : 'off'\"\r\n (click)=\"filter()\"\r\n >\r\n <span class=\"tooltip\">Apply filter</span>\r\n </button>\r\n </div>\r\n <button class=\"more-options\" (click)=\"toggleCollapse()\">\r\n <span *ngIf=\"!collapsed\" class=\"tooltip\">Less options</span>\r\n <span *ngIf=\"collapsed\" class=\"tooltip\">More options</span>\r\n </button>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type:
|
|
7134
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: DiagramButtonsComponent, isStandalone: true, selector: "daga-diagram-buttons", inputs: { location: "location", direction: "direction", enableFilter: "enableFilter", enableLayout: "enableLayout", enableUndoRedo: "enableUndoRedo", enableZoom: "enableZoom", zoomRate: "zoomRate" }, viewQueries: [{ propertyName: "collapsableButtons", first: true, predicate: ["collapsableButtons"], descendants: true }], ngImport: i0, template: "<div class=\"diagram-buttons {{ location }} {{ direction }}\">\r\n <button\r\n *ngIf=\"enableZoom && canvas.canUserPerformAction(DiagramActions.Zoom)\"\r\n class=\"zoom-in\"\r\n (click)=\"zoomIn()\"\r\n >\r\n <span class=\"tooltip\">Zoom in</span>\r\n </button>\r\n <button\r\n *ngIf=\"enableZoom && canvas.canUserPerformAction(DiagramActions.Zoom)\"\r\n class=\"zoom-out\"\r\n (click)=\"zoomOut()\"\r\n >\r\n <span class=\"tooltip\">Zoom out</span>\r\n </button>\r\n <div #collapsableButtons class=\"collapsable-buttons collapsed\">\r\n <button\r\n *ngIf=\"enableZoom && canvas.canUserPerformAction(DiagramActions.Zoom)\"\r\n class=\"center\"\r\n (click)=\"center()\"\r\n >\r\n <span class=\"tooltip\">Fit diagram to screen</span>\r\n </button>\r\n <button *ngIf=\"enableUndoRedo\" class=\"undo\" (click)=\"undo()\">\r\n <span class=\"tooltip\">Undo</span>\r\n </button>\r\n <button *ngIf=\"enableUndoRedo\" class=\"redo\" (click)=\"redo()\">\r\n <span class=\"tooltip\">Redo</span>\r\n </button>\r\n <button\r\n *ngIf=\"enableLayout && canvas.layoutFormat\"\r\n class=\"layout\"\r\n (click)=\"layout()\"\r\n >\r\n <span class=\"tooltip\">Apply layout</span>\r\n </button>\r\n <button\r\n *ngIf=\"enableFilter\"\r\n class=\"filter\"\r\n [class]=\"filterOn ? 'on' : 'off'\"\r\n (click)=\"filter()\"\r\n >\r\n <span class=\"tooltip\">Apply filter</span>\r\n </button>\r\n </div>\r\n <button class=\"more-options\" (click)=\"toggleCollapse()\">\r\n <span *ngIf=\"!collapsed\" class=\"tooltip\">Less options</span>\r\n <span *ngIf=\"collapsed\" class=\"tooltip\">More options</span>\r\n </button>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
|
|
6685
7135
|
}
|
|
6686
7136
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DiagramButtonsComponent, decorators: [{
|
|
6687
7137
|
type: Component,
|
|
@@ -6749,7 +7199,7 @@ class ErrorsComponent {
|
|
|
6749
7199
|
// TODO: IF ERROR IS IN AN ELEMENT BUT NOT IN A SPECIFIC PROPERTY, WE COULD HIGHLIGHT THE ELEMENT
|
|
6750
7200
|
}
|
|
6751
7201
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ErrorsComponent, deps: [{ token: CanvasProviderService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6752
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: ErrorsComponent, isStandalone: true, selector: "daga-errors", viewQueries: [{ propertyName: "errorsContainer", first: true, predicate: ["errors"], descendants: true }], ngImport: i0, template: "<div #errorsContainer class=\"errors\">\n <div\n *ngIf=\"errors.length === 0\"\n class=\"errors-summary no-errors prevent-user-select\"\n >\n <span>No errors found</span>\n </div>\n <div\n *ngIf=\"errors.length > 0\"\n class=\"errors-summary with-errors prevent-user-select\"\n >\n <span>{{ errors.length }} errors found</span>\n <div class=\"collapse-button-container\">\n <daga-collapse-button\n [collapsableSelector]=\"errorsContainer\"\n [collapsableAdditionalSelector]=\"'.error-panel'\"\n [direction]=\"Side.Top\"\n [rule]=\"'display'\"\n [collapsedValue]=\"'none'\"\n [visibleValue]=\"'block'\"\n />\n </div>\n </div>\n <div *ngIf=\"errors.length > 0\" class=\"error-panel\">\n <ol>\n <li\n *ngFor=\"let error of errors; index as i\"\n (click)=\"showError(error)\"\n [innerHTML]=\"error.message\"\n ></li>\n </ol>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type:
|
|
7202
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: ErrorsComponent, isStandalone: true, selector: "daga-errors", viewQueries: [{ propertyName: "errorsContainer", first: true, predicate: ["errors"], descendants: true }], ngImport: i0, template: "<div #errorsContainer class=\"errors\">\n <div\n *ngIf=\"errors.length === 0\"\n class=\"errors-summary no-errors prevent-user-select\"\n >\n <span>No errors found</span>\n </div>\n <div\n *ngIf=\"errors.length > 0\"\n class=\"errors-summary with-errors prevent-user-select\"\n >\n <span>{{ errors.length }} errors found</span>\n <div class=\"collapse-button-container\">\n <daga-collapse-button\n [collapsableSelector]=\"errorsContainer\"\n [collapsableAdditionalSelector]=\"'.error-panel'\"\n [direction]=\"Side.Top\"\n [rule]=\"'display'\"\n [collapsedValue]=\"'none'\"\n [visibleValue]=\"'block'\"\n />\n </div>\n </div>\n <div *ngIf=\"errors.length > 0\" class=\"error-panel\">\n <ol>\n <li\n *ngFor=\"let error of errors; index as i\"\n (click)=\"showError(error)\"\n [innerHTML]=\"error.message\"\n ></li>\n </ol>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CollapseButtonComponent, selector: "daga-collapse-button", inputs: ["collapsableSelector", "collapsableAdditionalSelector", "collapsed", "disabled", "direction", "rule", "collapsedValue", "visibleValue"] }] }); }
|
|
6753
7203
|
}
|
|
6754
7204
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ErrorsComponent, decorators: [{
|
|
6755
7205
|
type: Component,
|
|
@@ -6913,7 +7363,7 @@ class PaletteComponent {
|
|
|
6913
7363
|
.style('z-index', 1);
|
|
6914
7364
|
// when trying to place a unique node in a diagram that already has a node of that type, set cursor style to not allowed
|
|
6915
7365
|
if (type.isUnique &&
|
|
6916
|
-
this.canvas.model.nodes.find(type.id) !== undefined) {
|
|
7366
|
+
this.canvas.model.nodes.find((n) => !n.removed && n.type.id === type.id) !== undefined) {
|
|
6917
7367
|
cursorStyle(CursorStyle.NotAllowed);
|
|
6918
7368
|
}
|
|
6919
7369
|
}
|
|
@@ -6929,7 +7379,7 @@ class PaletteComponent {
|
|
|
6929
7379
|
.style('z-index', 'auto');
|
|
6930
7380
|
// try to place node
|
|
6931
7381
|
if (type.isUnique &&
|
|
6932
|
-
this.canvas.model.nodes.find(type.id) !== undefined) {
|
|
7382
|
+
this.canvas.model.nodes.find((n) => !n.removed && n.type.id === type.id) !== undefined) {
|
|
6933
7383
|
// can't place, it's unique and that node is already in the model
|
|
6934
7384
|
return;
|
|
6935
7385
|
}
|
|
@@ -6961,7 +7411,7 @@ class PaletteComponent {
|
|
|
6961
7411
|
newNodeCoords = this.canvas.getClosestGridPoint(newNodeCoords);
|
|
6962
7412
|
}
|
|
6963
7413
|
const addNodeAction = new AddNodeAction(this.canvas, type, newNodeCoords, templateConfig.label, templateConfig.values);
|
|
6964
|
-
addNodeAction.
|
|
7414
|
+
addNodeAction.do();
|
|
6965
7415
|
this.canvas.actionQueue.add(addNodeAction);
|
|
6966
7416
|
// reset cursor
|
|
6967
7417
|
cursorStyle();
|
|
@@ -7138,7 +7588,7 @@ class PaletteComponent {
|
|
|
7138
7588
|
}
|
|
7139
7589
|
}
|
|
7140
7590
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: PaletteComponent, deps: [{ token: CanvasProviderService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7141
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: PaletteComponent, isStandalone: true, selector: "daga-palette", inputs: { palettes: "palettes", currentPalette: "currentPalette", currentCategory: "currentCategory", location: "location", direction: "direction", width: "width" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true }], ngImport: i0, template: "<div #panel class=\"panel {{ location }} {{ direction }}\">\n <daga-collapse-button\n #collapseButton\n [direction]=\"direction\"\n [collapsableSelector]=\"panel\"\n collapsableAdditionalSelector=\".panel-content\"\n rule=\"display\"\n collapsedValue=\"none\"\n visibleValue=\"block\"\n />\n <div class=\"panel-content\">\n <div *ngIf=\"palettes.length > 1\" class=\"panel-tabs\">\n <div\n *ngFor=\"let palette of palettes\"\n class=\"panel-tab\"\n [class]=\"palette === currentPalette ? 'current-tab' : ''\"\n (click)=\"switchPalette(palette)\"\n >\n {{ palette.name }}\n </div>\n </div>\n <div class=\"palette-view\"></div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type:
|
|
7591
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: PaletteComponent, isStandalone: true, selector: "daga-palette", inputs: { palettes: "palettes", currentPalette: "currentPalette", currentCategory: "currentCategory", location: "location", direction: "direction", width: "width" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true }], ngImport: i0, template: "<div #panel class=\"panel {{ location }} {{ direction }}\">\n <daga-collapse-button\n #collapseButton\n [direction]=\"direction\"\n [collapsableSelector]=\"panel\"\n collapsableAdditionalSelector=\".panel-content\"\n rule=\"display\"\n collapsedValue=\"none\"\n visibleValue=\"block\"\n />\n <div class=\"panel-content\">\n <div *ngIf=\"palettes.length > 1\" class=\"panel-tabs\">\n <div\n *ngFor=\"let palette of palettes\"\n class=\"panel-tab\"\n [class]=\"palette === currentPalette ? 'current-tab' : ''\"\n (click)=\"switchPalette(palette)\"\n >\n {{ palette.name }}\n </div>\n </div>\n <div class=\"palette-view\"></div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CollapseButtonComponent, selector: "daga-collapse-button", inputs: ["collapsableSelector", "collapsableAdditionalSelector", "collapsed", "disabled", "direction", "rule", "collapsedValue", "visibleValue"] }] }); }
|
|
7142
7592
|
}
|
|
7143
7593
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: PaletteComponent, decorators: [{
|
|
7144
7594
|
type: Component,
|
|
@@ -7160,20 +7610,291 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
7160
7610
|
type: Input
|
|
7161
7611
|
}] } });
|
|
7162
7612
|
|
|
7613
|
+
const LOST_FOCUS_TIME_WINDOW_MS = 200;
|
|
7614
|
+
/**
|
|
7615
|
+
* Combobox with autocomplete.
|
|
7616
|
+
* @see PropertyEditor
|
|
7617
|
+
* @see ValueSet
|
|
7618
|
+
* @private
|
|
7619
|
+
*/
|
|
7620
|
+
class AutocompleteComponent {
|
|
7621
|
+
set value(value) {
|
|
7622
|
+
if (value === this._value) {
|
|
7623
|
+
return;
|
|
7624
|
+
}
|
|
7625
|
+
this._value = value;
|
|
7626
|
+
this.valueInput = this.getLabelOfValue(value);
|
|
7627
|
+
}
|
|
7628
|
+
get value() {
|
|
7629
|
+
return this._value;
|
|
7630
|
+
}
|
|
7631
|
+
constructor(cdr) {
|
|
7632
|
+
this.cdr = cdr;
|
|
7633
|
+
this.valueInput = '';
|
|
7634
|
+
this.disabled = false;
|
|
7635
|
+
this.showOptions = false;
|
|
7636
|
+
this.valueChange = new EventEmitter();
|
|
7637
|
+
}
|
|
7638
|
+
getLabelOfValue(value) {
|
|
7639
|
+
for (const option of this.options) {
|
|
7640
|
+
if (option.key === value) {
|
|
7641
|
+
return option.label;
|
|
7642
|
+
}
|
|
7643
|
+
}
|
|
7644
|
+
return `${value}`;
|
|
7645
|
+
}
|
|
7646
|
+
onKeyup(event) {
|
|
7647
|
+
if (!this.disabled) {
|
|
7648
|
+
switch (event.key) {
|
|
7649
|
+
case Keys.PageDown:
|
|
7650
|
+
if (this.focusIndex === undefined) {
|
|
7651
|
+
this.focusOnOption(0);
|
|
7652
|
+
this.scrollToOption(0);
|
|
7653
|
+
}
|
|
7654
|
+
else {
|
|
7655
|
+
this.focusOnOption(this.focusIndex + 5);
|
|
7656
|
+
this.scrollToOption(this.focusIndex);
|
|
7657
|
+
}
|
|
7658
|
+
event.preventDefault();
|
|
7659
|
+
break;
|
|
7660
|
+
case Keys.ArrowDown:
|
|
7661
|
+
if (this.focusIndex === undefined) {
|
|
7662
|
+
this.focusOnOption(0);
|
|
7663
|
+
this.scrollToOption(0);
|
|
7664
|
+
}
|
|
7665
|
+
else {
|
|
7666
|
+
this.focusOnOption(this.focusIndex + 1);
|
|
7667
|
+
this.scrollToOption(this.focusIndex);
|
|
7668
|
+
}
|
|
7669
|
+
event.preventDefault();
|
|
7670
|
+
break;
|
|
7671
|
+
case Keys.PageUp:
|
|
7672
|
+
if (this.focusIndex === undefined) {
|
|
7673
|
+
this.focusOnOption(this.options.length - 1);
|
|
7674
|
+
this.scrollToOption(this.options.length - 1);
|
|
7675
|
+
}
|
|
7676
|
+
else {
|
|
7677
|
+
this.focusOnOption(this.focusIndex - 5);
|
|
7678
|
+
this.scrollToOption(this.focusIndex);
|
|
7679
|
+
}
|
|
7680
|
+
event.preventDefault();
|
|
7681
|
+
break;
|
|
7682
|
+
case Keys.ArrowUp:
|
|
7683
|
+
if (this.focusIndex === undefined) {
|
|
7684
|
+
this.focusOnOption(this.options.length - 1);
|
|
7685
|
+
this.scrollToOption(this.options.length - 1);
|
|
7686
|
+
}
|
|
7687
|
+
else {
|
|
7688
|
+
this.focusOnOption(this.focusIndex - 1);
|
|
7689
|
+
this.scrollToOption(this.focusIndex);
|
|
7690
|
+
}
|
|
7691
|
+
event.preventDefault();
|
|
7692
|
+
break;
|
|
7693
|
+
case Keys.Escape:
|
|
7694
|
+
this.closeOptions();
|
|
7695
|
+
event.preventDefault();
|
|
7696
|
+
break;
|
|
7697
|
+
case Keys.Enter:
|
|
7698
|
+
this.complete(this.options[this.focusIndex || 0]);
|
|
7699
|
+
event.preventDefault();
|
|
7700
|
+
break;
|
|
7701
|
+
default:
|
|
7702
|
+
this.openOptions();
|
|
7703
|
+
}
|
|
7704
|
+
}
|
|
7705
|
+
}
|
|
7706
|
+
openOptions() {
|
|
7707
|
+
if (!this.disabled) {
|
|
7708
|
+
const mustContain = normalizeString(this.valueInput.trim());
|
|
7709
|
+
this.currentOptions = [];
|
|
7710
|
+
this.currentLabelStarts = [];
|
|
7711
|
+
this.currentLabelMatches = [];
|
|
7712
|
+
this.currentLabelEnds = [];
|
|
7713
|
+
for (const option of this.options) {
|
|
7714
|
+
const normalizedLabel = normalizeString(option.label);
|
|
7715
|
+
const position = normalizedLabel.indexOf(mustContain);
|
|
7716
|
+
if (position >= 0) {
|
|
7717
|
+
const labelStart = option.label.substring(0, position);
|
|
7718
|
+
const labelMatch = option.label.substring(position, position + mustContain.length);
|
|
7719
|
+
const labelEnd = option.label.substring(position + mustContain.length);
|
|
7720
|
+
this.currentOptions.push(option);
|
|
7721
|
+
this.currentLabelStarts.push(labelStart);
|
|
7722
|
+
this.currentLabelMatches.push(labelMatch);
|
|
7723
|
+
this.currentLabelEnds.push(labelEnd);
|
|
7724
|
+
}
|
|
7725
|
+
}
|
|
7726
|
+
this.showOptions = true;
|
|
7727
|
+
}
|
|
7728
|
+
}
|
|
7729
|
+
closeOptions() {
|
|
7730
|
+
this.showOptions = false;
|
|
7731
|
+
}
|
|
7732
|
+
focusOnOption(index) {
|
|
7733
|
+
if (!this.disabled) {
|
|
7734
|
+
this.focusIndex = index;
|
|
7735
|
+
if (index === undefined) {
|
|
7736
|
+
return;
|
|
7737
|
+
}
|
|
7738
|
+
if (index < 0) {
|
|
7739
|
+
this.focusIndex = 0;
|
|
7740
|
+
}
|
|
7741
|
+
if (index >= this.options.length) {
|
|
7742
|
+
this.focusIndex = this.options.length - 1;
|
|
7743
|
+
}
|
|
7744
|
+
}
|
|
7745
|
+
}
|
|
7746
|
+
onLostFocus() {
|
|
7747
|
+
setTimeout(() => {
|
|
7748
|
+
this.closeOptions();
|
|
7749
|
+
}, LOST_FOCUS_TIME_WINDOW_MS);
|
|
7750
|
+
}
|
|
7751
|
+
scrollToOption(index) {
|
|
7752
|
+
const target = this.mainElement.nativeElement.querySelectorAll('li')[index];
|
|
7753
|
+
if (target) {
|
|
7754
|
+
target.scrollIntoView({ block: 'center' });
|
|
7755
|
+
}
|
|
7756
|
+
}
|
|
7757
|
+
clearInput() {
|
|
7758
|
+
if (!this.disabled) {
|
|
7759
|
+
this.value = undefined;
|
|
7760
|
+
this.valueInput = '';
|
|
7761
|
+
this.showOptions = false;
|
|
7762
|
+
this.focusIndex = undefined;
|
|
7763
|
+
}
|
|
7764
|
+
}
|
|
7765
|
+
complete(option) {
|
|
7766
|
+
if (!this.disabled) {
|
|
7767
|
+
this.value = option;
|
|
7768
|
+
this.valueInput = option.label;
|
|
7769
|
+
this.showOptions = false;
|
|
7770
|
+
this.focusIndex = undefined;
|
|
7771
|
+
this.valueChange.emit(option.key);
|
|
7772
|
+
}
|
|
7773
|
+
}
|
|
7774
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AutocompleteComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7775
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: AutocompleteComponent, isStandalone: true, selector: "daga-autocomplete", inputs: { value: "value", valueInput: "valueInput", options: "options", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, viewQueries: [{ propertyName: "mainElement", first: true, predicate: ["main"], descendants: true, static: true }], ngImport: i0, template: "<div\r\n #main\r\n class=\"autocomplete\"\r\n [class]=\"showOptions ? 'showing-options' : ''\"\r\n (blur)=\"closeOptions()\"\r\n>\r\n <div class=\"autocomplete-input\">\r\n <input\r\n [(ngModel)]=\"valueInput\"\r\n [disabled]=\"disabled\"\r\n (keyup)=\"onKeyup($event)\"\r\n (focus)=\"openOptions()\"\r\n (blur)=\"onLostFocus()\"\r\n />\r\n <button\r\n *ngIf=\"valueInput !== ''\"\r\n class=\"clear\"\r\n (click)=\"clearInput()\"\r\n ></button>\r\n </div>\r\n <div class=\"autocomplete-options\">\r\n <ul class=\"autocomplete-option-list\">\r\n <li\r\n *ngFor=\"let option of currentOptions; let index = index\"\r\n class=\"autocomplete-option\"\r\n [class]=\"index === focusIndex ? 'focused' : ''\"\r\n (mousemove)=\"focusOnOption(index)\"\r\n (click)=\"complete(option)\"\r\n >\r\n <span>{{ currentLabelStarts[index] }}</span>\r\n <span class=\"match\">{{ currentLabelMatches[index] }}</span>\r\n <span>{{ currentLabelEnds[index] }}</span>\r\n </li>\r\n </ul>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
|
|
7776
|
+
}
|
|
7777
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: AutocompleteComponent, decorators: [{
|
|
7778
|
+
type: Component,
|
|
7779
|
+
args: [{ standalone: true, selector: 'daga-autocomplete', imports: [CommonModule, FormsModule], template: "<div\r\n #main\r\n class=\"autocomplete\"\r\n [class]=\"showOptions ? 'showing-options' : ''\"\r\n (blur)=\"closeOptions()\"\r\n>\r\n <div class=\"autocomplete-input\">\r\n <input\r\n [(ngModel)]=\"valueInput\"\r\n [disabled]=\"disabled\"\r\n (keyup)=\"onKeyup($event)\"\r\n (focus)=\"openOptions()\"\r\n (blur)=\"onLostFocus()\"\r\n />\r\n <button\r\n *ngIf=\"valueInput !== ''\"\r\n class=\"clear\"\r\n (click)=\"clearInput()\"\r\n ></button>\r\n </div>\r\n <div class=\"autocomplete-options\">\r\n <ul class=\"autocomplete-option-list\">\r\n <li\r\n *ngFor=\"let option of currentOptions; let index = index\"\r\n class=\"autocomplete-option\"\r\n [class]=\"index === focusIndex ? 'focused' : ''\"\r\n (mousemove)=\"focusOnOption(index)\"\r\n (click)=\"complete(option)\"\r\n >\r\n <span>{{ currentLabelStarts[index] }}</span>\r\n <span class=\"match\">{{ currentLabelMatches[index] }}</span>\r\n <span>{{ currentLabelEnds[index] }}</span>\r\n </li>\r\n </ul>\r\n </div>\r\n</div>\r\n" }]
|
|
7780
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { mainElement: [{
|
|
7781
|
+
type: ViewChild,
|
|
7782
|
+
args: ['main', { static: true }]
|
|
7783
|
+
}], value: [{
|
|
7784
|
+
type: Input
|
|
7785
|
+
}], valueInput: [{
|
|
7786
|
+
type: Input
|
|
7787
|
+
}], options: [{
|
|
7788
|
+
type: Input
|
|
7789
|
+
}], disabled: [{
|
|
7790
|
+
type: Input
|
|
7791
|
+
}], valueChange: [{
|
|
7792
|
+
type: Output
|
|
7793
|
+
}] } });
|
|
7794
|
+
const normalizeString = (a) => (a || '')
|
|
7795
|
+
.toLowerCase()
|
|
7796
|
+
.normalize('NFD')
|
|
7797
|
+
.replace(/[\u0300-\u036f]/g, '');
|
|
7798
|
+
|
|
7799
|
+
/**
|
|
7800
|
+
* Editor of a property of text list type within a property editor.
|
|
7801
|
+
* @see Type.TextList
|
|
7802
|
+
* @see PropertyEditor
|
|
7803
|
+
* @see ValueSet
|
|
7804
|
+
* @private
|
|
7805
|
+
*/
|
|
7806
|
+
class OptionListEditorComponent {
|
|
7807
|
+
set value(value) {
|
|
7808
|
+
if (value === this._value) {
|
|
7809
|
+
return;
|
|
7810
|
+
}
|
|
7811
|
+
const initialAndEmpty = value.length === 0 && this._value.length === 0;
|
|
7812
|
+
this._value = value;
|
|
7813
|
+
this.labelsOfValue = [];
|
|
7814
|
+
for (const key of this._value) {
|
|
7815
|
+
this.labelsOfValue.push(this.getLabelOfValue(key));
|
|
7816
|
+
}
|
|
7817
|
+
if (initialAndEmpty) {
|
|
7818
|
+
this.valueChange.emit(this._value);
|
|
7819
|
+
}
|
|
7820
|
+
}
|
|
7821
|
+
get value() {
|
|
7822
|
+
return this._value;
|
|
7823
|
+
}
|
|
7824
|
+
constructor(cdr) {
|
|
7825
|
+
this.cdr = cdr;
|
|
7826
|
+
this._value = [];
|
|
7827
|
+
this.labelsOfValue = [];
|
|
7828
|
+
this.options = [];
|
|
7829
|
+
this.valueInput = undefined;
|
|
7830
|
+
this.disabled = false;
|
|
7831
|
+
this.valueChange = new EventEmitter();
|
|
7832
|
+
}
|
|
7833
|
+
getLabelOfValue(value) {
|
|
7834
|
+
for (const option of this.options) {
|
|
7835
|
+
if (option.key === value) {
|
|
7836
|
+
return option.label;
|
|
7837
|
+
}
|
|
7838
|
+
}
|
|
7839
|
+
return `${value}`;
|
|
7840
|
+
}
|
|
7841
|
+
removeFromValue(index) {
|
|
7842
|
+
if (this._value.length > index) {
|
|
7843
|
+
this._value.splice(index, 1);
|
|
7844
|
+
this.labelsOfValue.splice(index, 1);
|
|
7845
|
+
this.valueChange.emit(this._value);
|
|
7846
|
+
}
|
|
7847
|
+
this.cdr.detectChanges();
|
|
7848
|
+
}
|
|
7849
|
+
addToValue() {
|
|
7850
|
+
if (this.valueInput !== undefined) {
|
|
7851
|
+
this._value.push(this.valueInput);
|
|
7852
|
+
this.labelsOfValue.push(this.getLabelOfValue(this.valueInput));
|
|
7853
|
+
this.valueChange.emit(this._value);
|
|
7854
|
+
this.clearInput();
|
|
7855
|
+
this.cdr.detectChanges();
|
|
7856
|
+
}
|
|
7857
|
+
}
|
|
7858
|
+
clearInput() {
|
|
7859
|
+
this.valueInput = '';
|
|
7860
|
+
}
|
|
7861
|
+
onKeyUp(event) {
|
|
7862
|
+
if (event.key === 'Enter') {
|
|
7863
|
+
this.addToValue();
|
|
7864
|
+
}
|
|
7865
|
+
}
|
|
7866
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: OptionListEditorComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7867
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: OptionListEditorComponent, isStandalone: true, selector: "daga-option-list-editor", inputs: { value: "value", options: "options", valueInput: "valueInput", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div *ngFor=\"let item of value; let index = index\" class=\"value-item-element\">\r\n <span class=\"input\">{{ labelsOfValue[index] }}</span>\r\n <button\r\n *ngIf=\"!disabled\"\r\n class=\"property-button\"\r\n (click)=\"removeFromValue(index)\"\r\n >\r\n <div class=\"icon close-icon\"></div>\r\n </button>\r\n</div>\r\n<div *ngIf=\"!disabled\" class=\"value-item-input\">\r\n <div class=\"input relatively-positioned\">\r\n <daga-autocomplete\r\n [disabled]=\"disabled\"\r\n [options]=\"options || []\"\r\n [(value)]=\"valueInput\"\r\n />\r\n </div>\r\n <button class=\"property-button\" (click)=\"addToValue()\">\r\n <div class=\"icon add-icon\"></div>\r\n </button>\r\n</div>\r\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "daga-autocomplete", inputs: ["value", "valueInput", "options", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }] }); }
|
|
7868
|
+
}
|
|
7869
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: OptionListEditorComponent, decorators: [{
|
|
7870
|
+
type: Component,
|
|
7871
|
+
args: [{ standalone: true, selector: 'daga-option-list-editor', imports: [AutocompleteComponent, CommonModule, FormsModule], template: "<div *ngFor=\"let item of value; let index = index\" class=\"value-item-element\">\r\n <span class=\"input\">{{ labelsOfValue[index] }}</span>\r\n <button\r\n *ngIf=\"!disabled\"\r\n class=\"property-button\"\r\n (click)=\"removeFromValue(index)\"\r\n >\r\n <div class=\"icon close-icon\"></div>\r\n </button>\r\n</div>\r\n<div *ngIf=\"!disabled\" class=\"value-item-input\">\r\n <div class=\"input relatively-positioned\">\r\n <daga-autocomplete\r\n [disabled]=\"disabled\"\r\n [options]=\"options || []\"\r\n [(value)]=\"valueInput\"\r\n />\r\n </div>\r\n <button class=\"property-button\" (click)=\"addToValue()\">\r\n <div class=\"icon add-icon\"></div>\r\n </button>\r\n</div>\r\n" }]
|
|
7872
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { value: [{
|
|
7873
|
+
type: Input
|
|
7874
|
+
}], options: [{
|
|
7875
|
+
type: Input
|
|
7876
|
+
}], valueInput: [{
|
|
7877
|
+
type: Input
|
|
7878
|
+
}], disabled: [{
|
|
7879
|
+
type: Input
|
|
7880
|
+
}], valueChange: [{
|
|
7881
|
+
type: Output
|
|
7882
|
+
}] } });
|
|
7883
|
+
|
|
7163
7884
|
/**
|
|
7164
7885
|
* Editor of a property of text list type within a property editor.
|
|
7165
|
-
* @see TextList
|
|
7886
|
+
* @see Type.TextList
|
|
7166
7887
|
* @see PropertyEditor
|
|
7167
7888
|
* @see ValueSet
|
|
7168
7889
|
* @private
|
|
7169
7890
|
*/
|
|
7170
7891
|
class TextListEditorComponent {
|
|
7171
|
-
set value(
|
|
7172
|
-
if (
|
|
7892
|
+
set value(value) {
|
|
7893
|
+
if (value === this._value) {
|
|
7173
7894
|
return;
|
|
7174
7895
|
}
|
|
7175
|
-
const initialAndEmpty =
|
|
7176
|
-
this._value =
|
|
7896
|
+
const initialAndEmpty = value.length === 0 && this._value.length === 0;
|
|
7897
|
+
this._value = value;
|
|
7177
7898
|
if (initialAndEmpty) {
|
|
7178
7899
|
this.valueChange.emit(this._value);
|
|
7179
7900
|
}
|
|
@@ -7222,11 +7943,11 @@ class TextListEditorComponent {
|
|
|
7222
7943
|
}
|
|
7223
7944
|
}
|
|
7224
7945
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TextListEditorComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7225
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: TextListEditorComponent, isStandalone: true, selector: "daga-text-list-editor", inputs: { value: "value", valueInput: "valueInput", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div *ngFor=\"let item of value; let index = index\" class=\"value-item-element\">\n <
|
|
7946
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: TextListEditorComponent, isStandalone: true, selector: "daga-text-list-editor", inputs: { value: "value", valueInput: "valueInput", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div *ngFor=\"let item of value; let index = index\" class=\"value-item-element\">\r\n <input\r\n class=\"input\"\r\n type=\"text\"\r\n [disabled]=\"disabled\"\r\n [value]=\"item\"\r\n (focusout)=\"editFromValue(getValueFromEvent($event), index)\"\r\n />\r\n <button\r\n *ngIf=\"!disabled\"\r\n class=\"property-button\"\r\n (click)=\"removeFromValue(index)\"\r\n >\r\n <div class=\"icon close-icon\"></div>\r\n </button>\r\n</div>\r\n<div *ngIf=\"!disabled\" class=\"value-item-input\">\r\n <div class=\"input relatively-positioned\">\r\n <input type=\"text\" (keyup)=\"onKeyUp($event)\" [(ngModel)]=\"valueInput\" />\r\n <button\r\n *ngIf=\"valueInput !== ''\"\r\n class=\"clear\"\r\n (click)=\"clearInput()\"\r\n ></button>\r\n </div>\r\n <button class=\"property-button\" (click)=\"addToValue()\">\r\n <div class=\"icon add-icon\"></div>\r\n </button>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
|
|
7226
7947
|
}
|
|
7227
7948
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TextListEditorComponent, decorators: [{
|
|
7228
7949
|
type: Component,
|
|
7229
|
-
args: [{ standalone: true, selector: 'daga-text-list-editor', imports: [CommonModule,
|
|
7950
|
+
args: [{ standalone: true, selector: 'daga-text-list-editor', imports: [CommonModule, FormsModule], template: "<div *ngFor=\"let item of value; let index = index\" class=\"value-item-element\">\r\n <input\r\n class=\"input\"\r\n type=\"text\"\r\n [disabled]=\"disabled\"\r\n [value]=\"item\"\r\n (focusout)=\"editFromValue(getValueFromEvent($event), index)\"\r\n />\r\n <button\r\n *ngIf=\"!disabled\"\r\n class=\"property-button\"\r\n (click)=\"removeFromValue(index)\"\r\n >\r\n <div class=\"icon close-icon\"></div>\r\n </button>\r\n</div>\r\n<div *ngIf=\"!disabled\" class=\"value-item-input\">\r\n <div class=\"input relatively-positioned\">\r\n <input type=\"text\" (keyup)=\"onKeyUp($event)\" [(ngModel)]=\"valueInput\" />\r\n <button\r\n *ngIf=\"valueInput !== ''\"\r\n class=\"clear\"\r\n (click)=\"clearInput()\"\r\n ></button>\r\n </div>\r\n <button class=\"property-button\" (click)=\"addToValue()\">\r\n <div class=\"icon add-icon\"></div>\r\n </button>\r\n</div>\r\n" }]
|
|
7230
7951
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { value: [{
|
|
7231
7952
|
type: Input
|
|
7232
7953
|
}], valueInput: [{
|
|
@@ -7239,18 +7960,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
7239
7960
|
|
|
7240
7961
|
/**
|
|
7241
7962
|
* Editor of a property of text map type within a property editor.
|
|
7242
|
-
* @see TextMap
|
|
7963
|
+
* @see Type.TextMap
|
|
7243
7964
|
* @see PropertyEditor
|
|
7244
7965
|
* @see ValueSet
|
|
7245
7966
|
* @private
|
|
7246
7967
|
*/
|
|
7247
7968
|
class TextMapEditorComponent {
|
|
7248
|
-
set value(
|
|
7249
|
-
if (
|
|
7969
|
+
set value(value) {
|
|
7970
|
+
if (value === this._value) {
|
|
7250
7971
|
return;
|
|
7251
7972
|
}
|
|
7252
|
-
const initialAndEmpty = Object.keys(
|
|
7253
|
-
this._value =
|
|
7973
|
+
const initialAndEmpty = Object.keys(value).length === 0 && Object.keys(this._value).length === 0;
|
|
7974
|
+
this._value = value;
|
|
7254
7975
|
if (initialAndEmpty) {
|
|
7255
7976
|
this.valueChange.emit(this._value);
|
|
7256
7977
|
}
|
|
@@ -7305,11 +8026,11 @@ class TextMapEditorComponent {
|
|
|
7305
8026
|
}
|
|
7306
8027
|
}
|
|
7307
8028
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TextMapEditorComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7308
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: TextMapEditorComponent, isStandalone: true, selector: "daga-text-map-editor", inputs: { value: "value", keyInput: "keyInput", valueInput: "valueInput", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div *ngFor=\"let item of value | keyvalue\" class=\"value-item-element\">\n <
|
|
8029
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: TextMapEditorComponent, isStandalone: true, selector: "daga-text-map-editor", inputs: { value: "value", keyInput: "keyInput", valueInput: "valueInput", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div *ngFor=\"let item of value | keyvalue\" class=\"value-item-element\">\r\n <input\r\n class=\"input\"\r\n type=\"text\"\r\n [disabled]=\"disabled\"\r\n [value]=\"item.key\"\r\n (focusout)=\"editKey(item.key, getValueFromEvent($event))\"\r\n />\r\n <input\r\n class=\"input\"\r\n type=\"text\"\r\n [disabled]=\"disabled\"\r\n [value]=\"item.value\"\r\n (focusout)=\"editValue(item.key, getValueFromEvent($event))\"\r\n />\r\n <button\r\n *ngIf=\"!disabled\"\r\n class=\"property-button\"\r\n (click)=\"removeFromValue(item.key)\"\r\n >\r\n <div class=\"icon close-icon\"></div>\r\n </button>\r\n</div>\r\n<div *ngIf=\"!disabled\" class=\"value-item-input\">\r\n <div class=\"input relatively-positioned\">\r\n <input type=\"text\" (keyup)=\"onKeyUp($event)\" [(ngModel)]=\"keyInput\" />\r\n <button\r\n *ngIf=\"keyInput !== ''\"\r\n class=\"clear\"\r\n (click)=\"clearKeyInput()\"\r\n ></button>\r\n </div>\r\n <div class=\"input relatively-positioned\">\r\n <input type=\"text\" (keyup)=\"onKeyUp($event)\" [(ngModel)]=\"valueInput\" />\r\n <button\r\n *ngIf=\"valueInput !== ''\"\r\n class=\"clear\"\r\n (click)=\"clearValueInput()\"\r\n ></button>\r\n </div>\r\n <button class=\"property-button\" (click)=\"addToValue()\">\r\n <div class=\"icon add-icon\"></div>\r\n </button>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
|
|
7309
8030
|
}
|
|
7310
8031
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TextMapEditorComponent, decorators: [{
|
|
7311
8032
|
type: Component,
|
|
7312
|
-
args: [{ standalone: true, selector: 'daga-text-map-editor', imports: [CommonModule,
|
|
8033
|
+
args: [{ standalone: true, selector: 'daga-text-map-editor', imports: [CommonModule, FormsModule], template: "<div *ngFor=\"let item of value | keyvalue\" class=\"value-item-element\">\r\n <input\r\n class=\"input\"\r\n type=\"text\"\r\n [disabled]=\"disabled\"\r\n [value]=\"item.key\"\r\n (focusout)=\"editKey(item.key, getValueFromEvent($event))\"\r\n />\r\n <input\r\n class=\"input\"\r\n type=\"text\"\r\n [disabled]=\"disabled\"\r\n [value]=\"item.value\"\r\n (focusout)=\"editValue(item.key, getValueFromEvent($event))\"\r\n />\r\n <button\r\n *ngIf=\"!disabled\"\r\n class=\"property-button\"\r\n (click)=\"removeFromValue(item.key)\"\r\n >\r\n <div class=\"icon close-icon\"></div>\r\n </button>\r\n</div>\r\n<div *ngIf=\"!disabled\" class=\"value-item-input\">\r\n <div class=\"input relatively-positioned\">\r\n <input type=\"text\" (keyup)=\"onKeyUp($event)\" [(ngModel)]=\"keyInput\" />\r\n <button\r\n *ngIf=\"keyInput !== ''\"\r\n class=\"clear\"\r\n (click)=\"clearKeyInput()\"\r\n ></button>\r\n </div>\r\n <div class=\"input relatively-positioned\">\r\n <input type=\"text\" (keyup)=\"onKeyUp($event)\" [(ngModel)]=\"valueInput\" />\r\n <button\r\n *ngIf=\"valueInput !== ''\"\r\n class=\"clear\"\r\n (click)=\"clearValueInput()\"\r\n ></button>\r\n </div>\r\n <button class=\"property-button\" (click)=\"addToValue()\">\r\n <div class=\"icon add-icon\"></div>\r\n </button>\r\n</div>\r\n" }]
|
|
7313
8034
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { value: [{
|
|
7314
8035
|
type: Input
|
|
7315
8036
|
}], keyInput: [{
|
|
@@ -7333,7 +8054,8 @@ class ObjectEditorComponent {
|
|
|
7333
8054
|
return this.canvasProvider.getCanvas();
|
|
7334
8055
|
}
|
|
7335
8056
|
get userCanEdit() {
|
|
7336
|
-
return this.canvas.canUserPerformAction(DiagramActions.UpdateValues)
|
|
8057
|
+
return (this.canvas.canUserPerformAction(DiagramActions.UpdateValues) &&
|
|
8058
|
+
this.valueSet?.rootElement?.['removed'] !== true);
|
|
7337
8059
|
}
|
|
7338
8060
|
get valueSet() {
|
|
7339
8061
|
return this._valueSet;
|
|
@@ -7350,10 +8072,6 @@ class ObjectEditorComponent {
|
|
|
7350
8072
|
this.depth = 0;
|
|
7351
8073
|
// Attributes for the template
|
|
7352
8074
|
this.Type = Type;
|
|
7353
|
-
this.booleanRadioItems = [
|
|
7354
|
-
{ value: false, label: 'No' },
|
|
7355
|
-
{ value: true, label: 'Yes' }
|
|
7356
|
-
];
|
|
7357
8075
|
}
|
|
7358
8076
|
displayProperty(property) {
|
|
7359
8077
|
if (this.valueSet === undefined) {
|
|
@@ -7405,24 +8123,35 @@ class ObjectEditorComponent {
|
|
|
7405
8123
|
}
|
|
7406
8124
|
}
|
|
7407
8125
|
}
|
|
7408
|
-
|
|
8126
|
+
dateToLocalDatetimeString(date) {
|
|
7409
8127
|
if (typeof date === 'string') {
|
|
7410
8128
|
return date;
|
|
7411
8129
|
}
|
|
7412
|
-
|
|
8130
|
+
if (date === null || date === undefined || isNaN(date.valueOf())) {
|
|
8131
|
+
return '';
|
|
8132
|
+
}
|
|
8133
|
+
const offsetDate = new Date(date);
|
|
8134
|
+
const timezoneOffset = offsetDate.getTimezoneOffset();
|
|
8135
|
+
offsetDate.setMinutes(offsetDate.getMinutes() - timezoneOffset);
|
|
8136
|
+
return offsetDate.toISOString().substring(0, 19); // for user friendliness, we trim off the milliseconds
|
|
8137
|
+
}
|
|
8138
|
+
localDatetimeStringToDate(string) {
|
|
8139
|
+
// with no timezone specified, the local time is assumed
|
|
8140
|
+
return new Date(string);
|
|
7413
8141
|
}
|
|
7414
8142
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ObjectEditorComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: CanvasProviderService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7415
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: ObjectEditorComponent, isStandalone: true, selector: "daga-object-editor", inputs: { valueSet: "valueSet", depth: "depth" }, ngImport: i0, template: "<div\n *ngFor=\"let property of valueSet?.displayedProperties || []\"\n class=\"property\"\n [class]=\"property.name + ' depth-' + depth\"\n>\n <p class=\"property-name\">\n {{ property.name }}\n <button class=\"property-button\" (click)=\"hideProperty(property.name)\">\n <div class=\"icon hide-icon\"></div>\n </button>\n </p>\n\n <
|
|
8143
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: ObjectEditorComponent, isStandalone: true, selector: "daga-object-editor", inputs: { valueSet: "valueSet", depth: "depth" }, ngImport: i0, template: "<div\r\n *ngFor=\"let property of valueSet?.displayedProperties || []\"\r\n class=\"property\"\r\n [class]=\"property.name + ' depth-' + depth\"\r\n>\r\n <p class=\"property-name\">\r\n {{ property.name }}\r\n <button class=\"property-button\" (click)=\"hideProperty(property.name)\">\r\n <div class=\"icon hide-icon\"></div>\r\n </button>\r\n </p>\r\n\r\n <input\r\n *ngIf=\"property.type === Type.Text\"\r\n type=\"text\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <textarea\r\n *ngIf=\"property.type === Type.TextArea\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n ></textarea>\r\n <input\r\n *ngIf=\"property.type === Type.Number\"\r\n type=\"number\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Color\"\r\n type=\"text\"\r\n pattern=\"#\\d{6}\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Datetime\"\r\n type=\"datetime-local\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"dateToLocalDatetimeString(valueSet?.getValue(property.name))\"\r\n (ngModelChange)=\"setValue(property, localDatetimeStringToDate($event))\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Date\"\r\n type=\"date\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Time\"\r\n type=\"time\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Url\"\r\n type=\"url\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <div class=\"radio\" *ngIf=\"property.type === Type.Boolean\">\r\n <label class=\"radio-item radio-start\">\r\n <input\r\n type=\"radio\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [name]=\"property.name\"\r\n value=\"false\"\r\n [checked]=\"valueSet?.getValue(property.name) === false\"\r\n (change)=\"setValue(property, false)\"\r\n />\r\n No\r\n </label>\r\n <label class=\"radio-item radio-end\">\r\n <input\r\n type=\"radio\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [name]=\"property.name\"\r\n value=\"true\"\r\n [checked]=\"valueSet?.getValue(property.name) === true\"\r\n (change)=\"setValue(property, true)\"\r\n />\r\n Yes\r\n </label>\r\n </div>\r\n <div class=\"relatively-positioned\" *ngIf=\"property.type === Type.Option\">\r\n <daga-autocomplete\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [options]=\"property.options || []\"\r\n [value]=\"valueSet?.getValue(property.name)\"\r\n (valueChange)=\"setValue(property, $event)\"\r\n />\r\n </div>\r\n <daga-option-list-editor\r\n *ngIf=\"property.type === Type.OptionList\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [options]=\"property.options || []\"\r\n [value]=\"valueSet?.getValue(property.name)\"\r\n (valueChange)=\"setValue(property, $event)\"\r\n ></daga-option-list-editor>\r\n <daga-text-list-editor\r\n *ngIf=\"property.type === Type.TextList\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [value]=\"valueSet?.getValue(property.name)\"\r\n (valueChange)=\"setValue(property, $event)\"\r\n ></daga-text-list-editor>\r\n <daga-text-map-editor\r\n *ngIf=\"property.type === Type.TextMap\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [value]=\"valueSet?.getValue(property.name)\"\r\n (valueChange)=\"setValue(property, $event)\"\r\n ></daga-text-map-editor>\r\n <div *ngIf=\"property.type === Type.Object\" class=\"left-bar\">\r\n <daga-object-editor\r\n [valueSet]=\"valueSet?.getSubValueSet(property.name)\"\r\n [depth]=\"depth + 1\"\r\n ></daga-object-editor>\r\n </div>\r\n</div>\r\n<div class=\"property\" *ngIf=\"valueSet && valueSet.hiddenProperties.length > 0\">\r\n <p class=\"property-name\">Add property:</p>\r\n <select (change)=\"displayProperty($event)\">\r\n <option value=\"\">Select a property</option>\r\n <option\r\n *ngFor=\"let property of valueSet?.hiddenProperties || []\"\r\n [value]=\"property.name\"\r\n >\r\n {{ property.name }}\r\n </option>\r\n </select>\r\n</div>\r\n", dependencies: [{ kind: "component", type: ObjectEditorComponent, selector: "daga-object-editor", inputs: ["valueSet", "depth"] }, { kind: "component", type: AutocompleteComponent, selector: "daga-autocomplete", inputs: ["value", "valueInput", "options", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: OptionListEditorComponent, selector: "daga-option-list-editor", inputs: ["value", "options", "valueInput", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: TextListEditorComponent, selector: "daga-text-list-editor", inputs: ["value", "valueInput", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: TextMapEditorComponent, selector: "daga-text-map-editor", inputs: ["value", "keyInput", "valueInput", "disabled"], outputs: ["valueChange"] }] }); }
|
|
7416
8144
|
}
|
|
7417
8145
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ObjectEditorComponent, decorators: [{
|
|
7418
8146
|
type: Component,
|
|
7419
8147
|
args: [{ standalone: true, selector: 'daga-object-editor', imports: [
|
|
8148
|
+
AutocompleteComponent,
|
|
7420
8149
|
CommonModule,
|
|
7421
|
-
LuxModule,
|
|
7422
8150
|
FormsModule,
|
|
8151
|
+
OptionListEditorComponent,
|
|
7423
8152
|
TextListEditorComponent,
|
|
7424
8153
|
TextMapEditorComponent
|
|
7425
|
-
], template: "<div\n *ngFor=\"let property of valueSet?.displayedProperties || []\"\n class=\"property\"\n [class]=\"property.name + ' depth-' + depth\"\n>\n <p class=\"property-name\">\n {{ property.name }}\n <button class=\"property-button\" (click)=\"hideProperty(property.name)\">\n <div class=\"icon hide-icon\"></div>\n </button>\n </p>\n\n <
|
|
8154
|
+
], template: "<div\r\n *ngFor=\"let property of valueSet?.displayedProperties || []\"\r\n class=\"property\"\r\n [class]=\"property.name + ' depth-' + depth\"\r\n>\r\n <p class=\"property-name\">\r\n {{ property.name }}\r\n <button class=\"property-button\" (click)=\"hideProperty(property.name)\">\r\n <div class=\"icon hide-icon\"></div>\r\n </button>\r\n </p>\r\n\r\n <input\r\n *ngIf=\"property.type === Type.Text\"\r\n type=\"text\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <textarea\r\n *ngIf=\"property.type === Type.TextArea\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n ></textarea>\r\n <input\r\n *ngIf=\"property.type === Type.Number\"\r\n type=\"number\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Color\"\r\n type=\"text\"\r\n pattern=\"#\\d{6}\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Datetime\"\r\n type=\"datetime-local\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"dateToLocalDatetimeString(valueSet?.getValue(property.name))\"\r\n (ngModelChange)=\"setValue(property, localDatetimeStringToDate($event))\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Date\"\r\n type=\"date\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Time\"\r\n type=\"time\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <input\r\n *ngIf=\"property.type === Type.Url\"\r\n type=\"url\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [ngModel]=\"valueSet?.getValue(property.name)\"\r\n (ngModelChange)=\"setValue(property, $event)\"\r\n />\r\n <div class=\"radio\" *ngIf=\"property.type === Type.Boolean\">\r\n <label class=\"radio-item radio-start\">\r\n <input\r\n type=\"radio\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [name]=\"property.name\"\r\n value=\"false\"\r\n [checked]=\"valueSet?.getValue(property.name) === false\"\r\n (change)=\"setValue(property, false)\"\r\n />\r\n No\r\n </label>\r\n <label class=\"radio-item radio-end\">\r\n <input\r\n type=\"radio\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [name]=\"property.name\"\r\n value=\"true\"\r\n [checked]=\"valueSet?.getValue(property.name) === true\"\r\n (change)=\"setValue(property, true)\"\r\n />\r\n Yes\r\n </label>\r\n </div>\r\n <div class=\"relatively-positioned\" *ngIf=\"property.type === Type.Option\">\r\n <daga-autocomplete\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [options]=\"property.options || []\"\r\n [value]=\"valueSet?.getValue(property.name)\"\r\n (valueChange)=\"setValue(property, $event)\"\r\n />\r\n </div>\r\n <daga-option-list-editor\r\n *ngIf=\"property.type === Type.OptionList\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [options]=\"property.options || []\"\r\n [value]=\"valueSet?.getValue(property.name)\"\r\n (valueChange)=\"setValue(property, $event)\"\r\n ></daga-option-list-editor>\r\n <daga-text-list-editor\r\n *ngIf=\"property.type === Type.TextList\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [value]=\"valueSet?.getValue(property.name)\"\r\n (valueChange)=\"setValue(property, $event)\"\r\n ></daga-text-list-editor>\r\n <daga-text-map-editor\r\n *ngIf=\"property.type === Type.TextMap\"\r\n [disabled]=\"!property.editable || !userCanEdit\"\r\n [value]=\"valueSet?.getValue(property.name)\"\r\n (valueChange)=\"setValue(property, $event)\"\r\n ></daga-text-map-editor>\r\n <div *ngIf=\"property.type === Type.Object\" class=\"left-bar\">\r\n <daga-object-editor\r\n [valueSet]=\"valueSet?.getSubValueSet(property.name)\"\r\n [depth]=\"depth + 1\"\r\n ></daga-object-editor>\r\n </div>\r\n</div>\r\n<div class=\"property\" *ngIf=\"valueSet && valueSet.hiddenProperties.length > 0\">\r\n <p class=\"property-name\">Add property:</p>\r\n <select (change)=\"displayProperty($event)\">\r\n <option value=\"\">Select a property</option>\r\n <option\r\n *ngFor=\"let property of valueSet?.hiddenProperties || []\"\r\n [value]=\"property.name\"\r\n >\r\n {{ property.name }}\r\n </option>\r\n </select>\r\n</div>\r\n" }]
|
|
7426
8155
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: CanvasProviderService }], propDecorators: { valueSet: [{
|
|
7427
8156
|
type: Input
|
|
7428
8157
|
}], depth: [{
|
|
@@ -7481,11 +8210,11 @@ class PropertyEditorComponent {
|
|
|
7481
8210
|
}
|
|
7482
8211
|
}
|
|
7483
8212
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: PropertyEditorComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7484
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: PropertyEditorComponent, isStandalone: true, selector: "daga-property-editor", inputs: { location: "location", direction: "direction", width: "width", valueSet: "valueSet" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true }], ngImport: i0, template: "<div #panel class=\"panel bottom {{ location }} {{ direction }}\">\n <daga-collapse-button\n [disabled]=\"\n !valueSet ||\n !valueSet.propertySet ||\n !valueSet.propertySet.hasProperties()\n \"\n [direction]=\"direction\"\n [collapsableSelector]=\"panel\"\n collapsableAdditionalSelector=\".panel-content\"\n rule=\"display\"\n collapsedValue=\"none\"\n visibleValue=\"block\"\n />\n <div\n *ngIf=\"\n valueSet
|
|
8213
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: PropertyEditorComponent, isStandalone: true, selector: "daga-property-editor", inputs: { location: "location", direction: "direction", width: "width", valueSet: "valueSet" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true }], ngImport: i0, template: "<div #panel class=\"panel bottom {{ location }} {{ direction }}\">\r\n <daga-collapse-button\r\n #collapse\r\n [disabled]=\"\r\n !valueSet ||\r\n !valueSet.propertySet ||\r\n !valueSet.propertySet.hasProperties()\r\n \"\r\n [direction]=\"direction\"\r\n [collapsableSelector]=\"panel\"\r\n collapsableAdditionalSelector=\".panel-content\"\r\n rule=\"display\"\r\n collapsedValue=\"none\"\r\n visibleValue=\"block\"\r\n />\r\n <div\r\n *ngIf=\"\r\n valueSet &&\r\n valueSet.propertySet &&\r\n valueSet.propertySet.hasProperties() &&\r\n !collapse.collapsed\r\n \"\r\n class=\"panel-content\"\r\n >\r\n <p *ngIf=\"title\" class=\"title\">{{ title }}</p>\r\n <daga-object-editor [valueSet]=\"valueSet\"></daga-object-editor>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CollapseButtonComponent, selector: "daga-collapse-button", inputs: ["collapsableSelector", "collapsableAdditionalSelector", "collapsed", "disabled", "direction", "rule", "collapsedValue", "visibleValue"] }, { kind: "component", type: ObjectEditorComponent, selector: "daga-object-editor", inputs: ["valueSet", "depth"] }] }); }
|
|
7485
8214
|
}
|
|
7486
8215
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: PropertyEditorComponent, decorators: [{
|
|
7487
8216
|
type: Component,
|
|
7488
|
-
args: [{ standalone: true, selector: 'daga-property-editor', imports: [CommonModule, CollapseButtonComponent, ObjectEditorComponent], template: "<div #panel class=\"panel bottom {{ location }} {{ direction }}\">\n <daga-collapse-button\n [disabled]=\"\n !valueSet ||\n !valueSet.propertySet ||\n !valueSet.propertySet.hasProperties()\n \"\n [direction]=\"direction\"\n [collapsableSelector]=\"panel\"\n collapsableAdditionalSelector=\".panel-content\"\n rule=\"display\"\n collapsedValue=\"none\"\n visibleValue=\"block\"\n />\n <div\n *ngIf=\"\n valueSet
|
|
8217
|
+
args: [{ standalone: true, selector: 'daga-property-editor', imports: [CommonModule, CollapseButtonComponent, ObjectEditorComponent], template: "<div #panel class=\"panel bottom {{ location }} {{ direction }}\">\r\n <daga-collapse-button\r\n #collapse\r\n [disabled]=\"\r\n !valueSet ||\r\n !valueSet.propertySet ||\r\n !valueSet.propertySet.hasProperties()\r\n \"\r\n [direction]=\"direction\"\r\n [collapsableSelector]=\"panel\"\r\n collapsableAdditionalSelector=\".panel-content\"\r\n rule=\"display\"\r\n collapsedValue=\"none\"\r\n visibleValue=\"block\"\r\n />\r\n <div\r\n *ngIf=\"\r\n valueSet &&\r\n valueSet.propertySet &&\r\n valueSet.propertySet.hasProperties() &&\r\n !collapse.collapsed\r\n \"\r\n class=\"panel-content\"\r\n >\r\n <p *ngIf=\"title\" class=\"title\">{{ title }}</p>\r\n <daga-object-editor [valueSet]=\"valueSet\"></daga-object-editor>\r\n </div>\r\n</div>\r\n" }]
|
|
7489
8218
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { panel: [{
|
|
7490
8219
|
type: ViewChild,
|
|
7491
8220
|
args: ['panel']
|
|
@@ -7551,7 +8280,7 @@ class DiagramEditorComponent {
|
|
|
7551
8280
|
this.canvasProvider.initCanvasView(this.appendTo.nativeElement);
|
|
7552
8281
|
}
|
|
7553
8282
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DiagramEditorComponent, deps: [{ token: DagaConfigurationService }, { token: CanvasProviderService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7554
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: DiagramEditorComponent, isStandalone: true, selector: "daga-diagram-editor", viewQueries: [{ propertyName: "appendTo", first: true, predicate: ["appendTo"], descendants: true }, { propertyName: "diagramButtons", first: true, predicate: ["diagramButtons"], descendants: true }, { propertyName: "palette", first: true, predicate: ["palette"], descendants: true }, { propertyName: "propertyEditor", first: true, predicate: ["propertyEditor"], descendants: true }], ngImport: i0, template: "<div class=\"append-to\" #appendTo></div>\n<daga-diagram-buttons\n *ngIf=\"config.components?.buttons?.exists !== false\"\n #diagramButtons\n [location]=\"config.components?.buttons?.location || Corner.BottomRight\"\n [direction]=\"config.components?.buttons?.direction || Side.Top\"\n [enableFilter]=\"config.components?.buttons?.enableFilter !== false\"\n [enableLayout]=\"config.components?.buttons?.enableLayout !== false\"\n [enableUndoRedo]=\"config.components?.buttons?.enableUndoRedo !== false\"\n [enableZoom]=\"config.components?.buttons?.enableZoom !== false\"\n [zoomRate]=\"config.components?.buttons?.zoomRate || 2\"\n/>\n<daga-palette\n *ngIf=\"\n config.components?.palette?.exists !== false &&\n config.components?.palette?.sections &&\n (config.components?.palette?.sections?.length || 0) > 0\n \"\n #palette\n [location]=\"config.components?.palette?.location || Corner.TopLeft\"\n [direction]=\"config.components?.palette?.direction || Side.Bottom\"\n [width]=\"config.components?.palette?.width || '12rem'\"\n [palettes]=\"config.components?.palette?.sections || []\"\n/>\n<daga-property-editor\n *ngIf=\"config.components?.propertyEditor?.exists !== false\"\n #propertyEditor\n [location]=\"config.components?.propertyEditor?.location || Corner.TopRight\"\n [direction]=\"config.components?.propertyEditor?.direction || Side.Bottom\"\n [width]=\"config.components?.propertyEditor?.width || '24rem'\"\n/>\n<daga-errors *ngIf=\"config.components?.errors?.exists !== false\" />\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type:
|
|
8283
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: DiagramEditorComponent, isStandalone: true, selector: "daga-diagram-editor", viewQueries: [{ propertyName: "appendTo", first: true, predicate: ["appendTo"], descendants: true }, { propertyName: "diagramButtons", first: true, predicate: ["diagramButtons"], descendants: true }, { propertyName: "palette", first: true, predicate: ["palette"], descendants: true }, { propertyName: "propertyEditor", first: true, predicate: ["propertyEditor"], descendants: true }], ngImport: i0, template: "<div class=\"append-to\" #appendTo></div>\n<daga-diagram-buttons\n *ngIf=\"config.components?.buttons?.exists !== false\"\n #diagramButtons\n [location]=\"config.components?.buttons?.location || Corner.BottomRight\"\n [direction]=\"config.components?.buttons?.direction || Side.Top\"\n [enableFilter]=\"config.components?.buttons?.enableFilter !== false\"\n [enableLayout]=\"config.components?.buttons?.enableLayout !== false\"\n [enableUndoRedo]=\"config.components?.buttons?.enableUndoRedo !== false\"\n [enableZoom]=\"config.components?.buttons?.enableZoom !== false\"\n [zoomRate]=\"config.components?.buttons?.zoomRate || 2\"\n/>\n<daga-palette\n *ngIf=\"\n config.components?.palette?.exists !== false &&\n config.components?.palette?.sections &&\n (config.components?.palette?.sections?.length || 0) > 0\n \"\n #palette\n [location]=\"config.components?.palette?.location || Corner.TopLeft\"\n [direction]=\"config.components?.palette?.direction || Side.Bottom\"\n [width]=\"config.components?.palette?.width || '12rem'\"\n [palettes]=\"config.components?.palette?.sections || []\"\n/>\n<daga-property-editor\n *ngIf=\"config.components?.propertyEditor?.exists !== false\"\n #propertyEditor\n [location]=\"config.components?.propertyEditor?.location || Corner.TopRight\"\n [direction]=\"config.components?.propertyEditor?.direction || Side.Bottom\"\n [width]=\"config.components?.propertyEditor?.width || '24rem'\"\n/>\n<daga-errors *ngIf=\"config.components?.errors?.exists !== false\" />\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: DiagramButtonsComponent, selector: "daga-diagram-buttons", inputs: ["location", "direction", "enableFilter", "enableLayout", "enableUndoRedo", "enableZoom", "zoomRate"] }, { kind: "component", type: PaletteComponent, selector: "daga-palette", inputs: ["palettes", "currentPalette", "currentCategory", "location", "direction", "width"] }, { kind: "component", type: PropertyEditorComponent, selector: "daga-property-editor", inputs: ["location", "direction", "width", "valueSet"] }, { kind: "component", type: ErrorsComponent, selector: "daga-errors" }] }); }
|
|
7555
8284
|
}
|
|
7556
8285
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DiagramEditorComponent, decorators: [{
|
|
7557
8286
|
type: Component,
|
|
@@ -7592,7 +8321,8 @@ class DagaExporter {
|
|
|
7592
8321
|
updatedAt: model.updatedAt,
|
|
7593
8322
|
nodes: [],
|
|
7594
8323
|
connections: [],
|
|
7595
|
-
data: model.valueSet.getValues()
|
|
8324
|
+
data: model.valueSet.getValues(),
|
|
8325
|
+
logicalClock: model.logicalClock
|
|
7596
8326
|
};
|
|
7597
8327
|
if (model.id) {
|
|
7598
8328
|
result.id = model.id;
|
|
@@ -7600,7 +8330,7 @@ class DagaExporter {
|
|
|
7600
8330
|
if (model.description) {
|
|
7601
8331
|
result.description = model.description;
|
|
7602
8332
|
}
|
|
7603
|
-
for (const node of model.nodes) {
|
|
8333
|
+
for (const node of model.nodes.filter((e) => !e.removed)) {
|
|
7604
8334
|
const sections = [];
|
|
7605
8335
|
for (const section of node.sections) {
|
|
7606
8336
|
const ports = [];
|
|
@@ -7632,7 +8362,7 @@ class DagaExporter {
|
|
|
7632
8362
|
label: port.label?.text || ''
|
|
7633
8363
|
});
|
|
7634
8364
|
}
|
|
7635
|
-
|
|
8365
|
+
const newNode = {
|
|
7636
8366
|
id: node.id,
|
|
7637
8367
|
type: node.type.id,
|
|
7638
8368
|
sections,
|
|
@@ -7642,9 +8372,13 @@ class DagaExporter {
|
|
|
7642
8372
|
width: node.width,
|
|
7643
8373
|
height: node.height,
|
|
7644
8374
|
data: node.valueSet.getValues()
|
|
7645
|
-
}
|
|
8375
|
+
};
|
|
8376
|
+
if (node.coordsTimestamp) {
|
|
8377
|
+
newNode.coordsTimestamp = node.coordsTimestamp;
|
|
8378
|
+
}
|
|
8379
|
+
result.nodes.push(newNode);
|
|
7646
8380
|
}
|
|
7647
|
-
for (const connection of model.connections) {
|
|
8381
|
+
for (const connection of model.connections.filter((e) => !e.removed)) {
|
|
7648
8382
|
result.connections.push({
|
|
7649
8383
|
id: connection.id,
|
|
7650
8384
|
type: connection.type.id,
|
|
@@ -7677,6 +8411,9 @@ class DagaImporter {
|
|
|
7677
8411
|
model.type = data.type;
|
|
7678
8412
|
model.createdAt = new Date(data.createdAt);
|
|
7679
8413
|
model.updatedAt = new Date(data.updatedAt);
|
|
8414
|
+
if (data.logicalClock) {
|
|
8415
|
+
model.logicalClock = data.logicalClock;
|
|
8416
|
+
}
|
|
7680
8417
|
for (const node of data.nodes || []) {
|
|
7681
8418
|
const newNodeType = model.nodes.types.get(node.type);
|
|
7682
8419
|
if (newNodeType) {
|
|
@@ -7684,6 +8421,9 @@ class DagaImporter {
|
|
|
7684
8421
|
model.nodes.add(newNode);
|
|
7685
8422
|
newNode.width = node.width;
|
|
7686
8423
|
newNode.height = node.height;
|
|
8424
|
+
if (node.coordsTimestamp) {
|
|
8425
|
+
newNode.coordsTimestamp = node.coordsTimestamp;
|
|
8426
|
+
}
|
|
7687
8427
|
if (node.label) {
|
|
7688
8428
|
// add node label
|
|
7689
8429
|
if (newNodeType.label) {
|
|
@@ -7927,8 +8667,7 @@ class DagaModule {
|
|
|
7927
8667
|
TextMapEditorComponent,
|
|
7928
8668
|
PropertyEditorComponent,
|
|
7929
8669
|
CommonModule,
|
|
7930
|
-
FormsModule,
|
|
7931
|
-
LuxModule], exports: [DiagramComponent, DiagramEditorComponent] }); }
|
|
8670
|
+
FormsModule], exports: [DiagramComponent, DiagramEditorComponent] }); }
|
|
7932
8671
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DagaModule, providers: [DagaConfigurationService, CanvasProviderService], imports: [CollapseButtonComponent,
|
|
7933
8672
|
DiagramButtonsComponent,
|
|
7934
8673
|
DiagramEditorComponent,
|
|
@@ -7939,8 +8678,7 @@ class DagaModule {
|
|
|
7939
8678
|
TextMapEditorComponent,
|
|
7940
8679
|
PropertyEditorComponent,
|
|
7941
8680
|
CommonModule,
|
|
7942
|
-
FormsModule
|
|
7943
|
-
LuxModule] }); }
|
|
8681
|
+
FormsModule] }); }
|
|
7944
8682
|
}
|
|
7945
8683
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DagaModule, decorators: [{
|
|
7946
8684
|
type: NgModule,
|
|
@@ -7958,17 +8696,224 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
7958
8696
|
TextMapEditorComponent,
|
|
7959
8697
|
PropertyEditorComponent,
|
|
7960
8698
|
CommonModule,
|
|
7961
|
-
FormsModule
|
|
7962
|
-
LuxModule
|
|
8699
|
+
FormsModule
|
|
7963
8700
|
],
|
|
7964
8701
|
exports: [DiagramComponent, DiagramEditorComponent],
|
|
7965
8702
|
providers: [DagaConfigurationService, CanvasProviderService]
|
|
7966
8703
|
}]
|
|
7967
8704
|
}] });
|
|
7968
8705
|
|
|
8706
|
+
const VERSION = '0.0.1';
|
|
8707
|
+
/**
|
|
8708
|
+
* The client that communicates with the daga-server over WebSockets.
|
|
8709
|
+
*
|
|
8710
|
+
* Use this to create and join rooms.
|
|
8711
|
+
* @public
|
|
8712
|
+
*/
|
|
8713
|
+
class CollabClient {
|
|
8714
|
+
constructor(dagaServer, userId) {
|
|
8715
|
+
this.sendQueue = [];
|
|
8716
|
+
/**
|
|
8717
|
+
* Joined sessions by locator.
|
|
8718
|
+
*/
|
|
8719
|
+
this.sessions = new Map();
|
|
8720
|
+
/**
|
|
8721
|
+
* Created but unacked sessions by refId.
|
|
8722
|
+
*/
|
|
8723
|
+
this.pendingSessions = new Map();
|
|
8724
|
+
this.dagaServer = dagaServer;
|
|
8725
|
+
this.userId = userId;
|
|
8726
|
+
this.clientId = v4();
|
|
8727
|
+
this.ws = new WebSocket(this.dagaServer, 'esgrima');
|
|
8728
|
+
this.ws.addEventListener('open', this.onOpen.bind(this));
|
|
8729
|
+
this.ws.addEventListener('message', this.onMessage.bind(this));
|
|
8730
|
+
this.ws.addEventListener('close', this.onClose.bind(this));
|
|
8731
|
+
this.ws.addEventListener('error', this.onError.bind(this));
|
|
8732
|
+
this.send({
|
|
8733
|
+
type: 'HELO',
|
|
8734
|
+
clientId: this.clientId,
|
|
8735
|
+
userId: this.userId,
|
|
8736
|
+
version: VERSION,
|
|
8737
|
+
ts: now()
|
|
8738
|
+
});
|
|
8739
|
+
}
|
|
8740
|
+
onOpen() {
|
|
8741
|
+
// Send queued messages.
|
|
8742
|
+
for (const serialized of this.sendQueue) {
|
|
8743
|
+
this.ws.send(serialized);
|
|
8744
|
+
}
|
|
8745
|
+
this.sendQueue = [];
|
|
8746
|
+
}
|
|
8747
|
+
onMessage(e) {
|
|
8748
|
+
const serialized = e.data;
|
|
8749
|
+
const message = JSON.parse(serialized);
|
|
8750
|
+
this.receive(message);
|
|
8751
|
+
}
|
|
8752
|
+
onClose(e) {
|
|
8753
|
+
console.error('WebSocket closed', e);
|
|
8754
|
+
}
|
|
8755
|
+
onError(e) {
|
|
8756
|
+
console.error('WebSocket error', e);
|
|
8757
|
+
}
|
|
8758
|
+
/**
|
|
8759
|
+
* Internal send method. Use instead of calling ws.send directly.
|
|
8760
|
+
*/
|
|
8761
|
+
send(message) {
|
|
8762
|
+
const serialized = JSON.stringify(message);
|
|
8763
|
+
if (this.ws.readyState === WebSocket.OPEN) {
|
|
8764
|
+
this.ws.send(serialized);
|
|
8765
|
+
}
|
|
8766
|
+
else {
|
|
8767
|
+
// Queue until after we connect.
|
|
8768
|
+
this.sendQueue.push(serialized);
|
|
8769
|
+
}
|
|
8770
|
+
}
|
|
8771
|
+
/**
|
|
8772
|
+
* Internal receive method. Use instead of handling ws receive events directly.
|
|
8773
|
+
*/
|
|
8774
|
+
receive(message) {
|
|
8775
|
+
switch (message.type) {
|
|
8776
|
+
case 'EACK': {
|
|
8777
|
+
const session = this.sessions.get(message.locator);
|
|
8778
|
+
if (session === undefined) {
|
|
8779
|
+
throw new Error(`EACK for unknown locator: "${message.locator}"`);
|
|
8780
|
+
}
|
|
8781
|
+
const initialModel = message.initialModel;
|
|
8782
|
+
new DagaImporter().import(session.canvas.model, initialModel);
|
|
8783
|
+
this.startSyncing(session);
|
|
8784
|
+
session.joinRoomResolve?.();
|
|
8785
|
+
session.joinRoomResolve = undefined;
|
|
8786
|
+
break;
|
|
8787
|
+
}
|
|
8788
|
+
case 'ADD': {
|
|
8789
|
+
const session = this.sessions.get(message.locator);
|
|
8790
|
+
if (session === undefined) {
|
|
8791
|
+
throw new Error(`ADD for unknown locator: "${message.locator}"`);
|
|
8792
|
+
}
|
|
8793
|
+
const action = message.payload;
|
|
8794
|
+
session.canvas.collabEngine.receive(action);
|
|
8795
|
+
break;
|
|
8796
|
+
}
|
|
8797
|
+
case 'CACK': {
|
|
8798
|
+
const session = this.pendingSessions.get(message.refId);
|
|
8799
|
+
if (session === undefined) {
|
|
8800
|
+
throw new Error(`CACK for unknown refId: "${message.refId}"`);
|
|
8801
|
+
}
|
|
8802
|
+
session.locator = message.locator;
|
|
8803
|
+
this.pendingSessions.delete(message.refId);
|
|
8804
|
+
this.sessions.set(session.locator, session);
|
|
8805
|
+
session.createRoomResolve?.(session.locator);
|
|
8806
|
+
session.createRoomResolve = undefined;
|
|
8807
|
+
// Deliver queued AddMessages now that we have a locator.
|
|
8808
|
+
for (const message of session.addQueue) {
|
|
8809
|
+
this.send({ ...message, locator: session.locator });
|
|
8810
|
+
}
|
|
8811
|
+
session.addQueue = [];
|
|
8812
|
+
}
|
|
8813
|
+
}
|
|
8814
|
+
}
|
|
8815
|
+
/**
|
|
8816
|
+
* Creates and joins a room. The given canvas becomes collaborative, starting
|
|
8817
|
+
* with its current model.
|
|
8818
|
+
*
|
|
8819
|
+
* Returns a Promise that resolves with the new room's locator once joined.
|
|
8820
|
+
* @public
|
|
8821
|
+
*/
|
|
8822
|
+
createAndJoinRoom(canvas) {
|
|
8823
|
+
if (canvas.collabEngine.isInRoom) {
|
|
8824
|
+
throw new Error('Canvas is already in a room');
|
|
8825
|
+
}
|
|
8826
|
+
canvas.collabEngine.isInRoom = true;
|
|
8827
|
+
const refId = v4();
|
|
8828
|
+
const initialModel = new DagaExporter().export(canvas.model);
|
|
8829
|
+
this.send({
|
|
8830
|
+
type: 'CREA',
|
|
8831
|
+
clientId: this.clientId,
|
|
8832
|
+
userId: this.userId,
|
|
8833
|
+
refId,
|
|
8834
|
+
initialModel,
|
|
8835
|
+
ts: now()
|
|
8836
|
+
});
|
|
8837
|
+
const session = {
|
|
8838
|
+
canvas,
|
|
8839
|
+
locator: null,
|
|
8840
|
+
addQueue: []
|
|
8841
|
+
};
|
|
8842
|
+
this.pendingSessions.set(refId, session);
|
|
8843
|
+
// We need to start queuing local AddMessages immediately, in case the user edits
|
|
8844
|
+
// the diagram while the CREA message is in-flight.
|
|
8845
|
+
this.startSyncing(session);
|
|
8846
|
+
return new Promise((resolve) => {
|
|
8847
|
+
session.createRoomResolve = resolve;
|
|
8848
|
+
});
|
|
8849
|
+
}
|
|
8850
|
+
/**
|
|
8851
|
+
* Joins the room with the given locator. The given canvas becomes collaborative,
|
|
8852
|
+
* **replacing** its current model with the room's model.
|
|
8853
|
+
*
|
|
8854
|
+
* Returns a Promise that resolves once the room has been joined and loaded into
|
|
8855
|
+
* the canvas. You should hide or lock the canvas until it resolves, since any
|
|
8856
|
+
* user inputs before then will be overwritten.
|
|
8857
|
+
* @public
|
|
8858
|
+
*/
|
|
8859
|
+
joinRoom(canvas, locator) {
|
|
8860
|
+
if (canvas.collabEngine.isInRoom) {
|
|
8861
|
+
throw new Error('Canvas is already in a room');
|
|
8862
|
+
}
|
|
8863
|
+
canvas.collabEngine.isInRoom = true;
|
|
8864
|
+
this.send({
|
|
8865
|
+
type: 'ENRO',
|
|
8866
|
+
clientId: this.clientId,
|
|
8867
|
+
userId: this.userId,
|
|
8868
|
+
locator,
|
|
8869
|
+
ts: now()
|
|
8870
|
+
});
|
|
8871
|
+
const session = {
|
|
8872
|
+
canvas,
|
|
8873
|
+
locator,
|
|
8874
|
+
addQueue: []
|
|
8875
|
+
};
|
|
8876
|
+
this.sessions.set(locator, session);
|
|
8877
|
+
return new Promise((resolve) => {
|
|
8878
|
+
session.joinRoomResolve = resolve;
|
|
8879
|
+
});
|
|
8880
|
+
}
|
|
8881
|
+
startSyncing(session) {
|
|
8882
|
+
// Sync AddMessages from us to the server.
|
|
8883
|
+
session.canvas.collabEngine.onSend = (action) => {
|
|
8884
|
+
if (session.locator === null) {
|
|
8885
|
+
// Queue until we receive the locator in the CACK message.
|
|
8886
|
+
session.addQueue.push({
|
|
8887
|
+
type: 'ADD',
|
|
8888
|
+
clientId: this.clientId,
|
|
8889
|
+
userId: this.userId,
|
|
8890
|
+
payload: action,
|
|
8891
|
+
ts: now()
|
|
8892
|
+
});
|
|
8893
|
+
}
|
|
8894
|
+
else {
|
|
8895
|
+
this.send({
|
|
8896
|
+
type: 'ADD',
|
|
8897
|
+
clientId: this.clientId,
|
|
8898
|
+
userId: this.userId,
|
|
8899
|
+
locator: session.locator,
|
|
8900
|
+
payload: action,
|
|
8901
|
+
ts: now()
|
|
8902
|
+
});
|
|
8903
|
+
}
|
|
8904
|
+
};
|
|
8905
|
+
}
|
|
8906
|
+
}
|
|
8907
|
+
/**
|
|
8908
|
+
* Returns the current timestamp for a message's ts field.
|
|
8909
|
+
*/
|
|
8910
|
+
function now() {
|
|
8911
|
+
return new Date().toISOString();
|
|
8912
|
+
}
|
|
8913
|
+
|
|
7969
8914
|
/**
|
|
7970
8915
|
* Generated bundle index. Do not edit.
|
|
7971
8916
|
*/
|
|
7972
8917
|
|
|
7973
|
-
export { ACTION_QUEUE_SIZE, ActionQueue, AddConnectionAction, AddNodeAction, AdjacencyLayout, BreadthAdjacencyLayout, BreadthLayout, CanvasProviderService, ClosedShape, CollapseButtonComponent, Corner, DagaConfigurationService, DagaExporter, DagaImporter, DagaModule, DiagramActions, DiagramButtonsComponent, DiagramCanvas, DiagramComponent, DiagramConnection, DiagramConnectionSet, DiagramConnectionType, DiagramEditorComponent, DiagramElement, DiagramEntitySet, DiagramField, DiagramFieldSet, DiagramModel, DiagramNode, DiagramNodeSet, DiagramNodeType, DiagramPort, DiagramPortSet, DiagramSection, DiagramSectionSet, EditFieldAction, ErrorsComponent, ForceLayout, HorizontalAlign, HorizontalLayout, LineShape, LineStyle, MoveNodeAction, ObjectEditorComponent, PaletteComponent, PriorityLayout, Property, PropertyEditorComponent, PropertySet, RemoveAction, Side, StretchNodeAction, TextListEditorComponent, TextMapEditorComponent, Type, UpdateValuesAction, ValueSet, VerticalAlign, VerticalLayout, layouts };
|
|
8918
|
+
export { ACTION_QUEUE_SIZE, ActionQueue, AddConnectionAction, AddNodeAction, AdjacencyLayout, BreadthAdjacencyLayout, BreadthLayout, CanvasProviderService, ClosedShape, CollabClient, CollapseButtonComponent, Corner, DagaConfigurationService, DagaExporter, DagaImporter, DagaModule, DiagramActions, DiagramButtonsComponent, DiagramCanvas, DiagramComponent, DiagramConnection, DiagramConnectionSet, DiagramConnectionType, DiagramEditorComponent, DiagramElement, DiagramEntitySet, DiagramField, DiagramFieldSet, DiagramModel, DiagramNode, DiagramNodeSet, DiagramNodeType, DiagramPort, DiagramPortSet, DiagramSection, DiagramSectionSet, EditFieldAction, ErrorsComponent, ForceLayout, HorizontalAlign, HorizontalLayout, LineShape, LineStyle, MoveNodeAction, ObjectEditorComponent, PaletteComponent, PriorityLayout, Property, PropertyEditorComponent, PropertySet, RemoveAction, Side, StretchNodeAction, TextListEditorComponent, TextMapEditorComponent, Type, UpdateValuesAction, ValueSet, VerticalAlign, VerticalLayout, layouts };
|
|
7974
8919
|
//# sourceMappingURL=metadev-daga.mjs.map
|