@metadev/daga 1.4.0 → 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 +26 -2
- package/assets/styles/_property-editor.scss +225 -157
- package/assets/styles/daga.scss +149 -156
- package/fesm2022/metadev-daga.mjs +1536 -584
- 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 +4 -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 +13 -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,6 +4424,7 @@ 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
|
/**
|
|
@@ -4130,6 +4438,7 @@ class DiagramModel {
|
|
|
4130
4438
|
this.description = undefined;
|
|
4131
4439
|
this.createdAt = new Date();
|
|
4132
4440
|
this.updatedAt = new Date();
|
|
4441
|
+
this.logicalClock = 0;
|
|
4133
4442
|
this.nodes.clear();
|
|
4134
4443
|
this.sections.clear();
|
|
4135
4444
|
this.ports.clear();
|
|
@@ -4140,21 +4449,77 @@ class DiagramModel {
|
|
|
4140
4449
|
}
|
|
4141
4450
|
}
|
|
4142
4451
|
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
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.
|
|
4497
|
+
*/
|
|
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
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
|
|
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();
|
|
@@ -4487,6 +4853,13 @@ class DiagramCanvas {
|
|
|
4487
4853
|
getPointerLocationRelativeToBody(event) {
|
|
4488
4854
|
return d3.pointer(this.getEventHoldingCoordinates(event), d3.select('body').node());
|
|
4489
4855
|
}
|
|
4856
|
+
getPointerLocationRelativeToScreen(event) {
|
|
4857
|
+
const pointerLocationRelativeToBody = this.getPointerLocationRelativeToBody(event);
|
|
4858
|
+
return [
|
|
4859
|
+
pointerLocationRelativeToBody[0] - window.scrollX,
|
|
4860
|
+
pointerLocationRelativeToBody[1] - window.scrollY
|
|
4861
|
+
];
|
|
4862
|
+
}
|
|
4490
4863
|
updateModelInView() {
|
|
4491
4864
|
this.updateNodesInView();
|
|
4492
4865
|
this.updateSectionsInView();
|
|
@@ -4497,7 +4870,10 @@ class DiagramCanvas {
|
|
|
4497
4870
|
updateNodesInView(...ids) {
|
|
4498
4871
|
let updateSelection = this.selectCanvasNodes()
|
|
4499
4872
|
.selectAll('g.diagram-node')
|
|
4500
|
-
.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);
|
|
4501
4877
|
const exitSelection = updateSelection.exit();
|
|
4502
4878
|
const enterSelection = updateSelection
|
|
4503
4879
|
.enter()
|
|
@@ -4522,7 +4898,8 @@ class DiagramCanvas {
|
|
|
4522
4898
|
.call(d3
|
|
4523
4899
|
.drag()
|
|
4524
4900
|
.on(DragEvents.Start, (event, d) => {
|
|
4525
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
4901
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
4902
|
+
!d.removed) {
|
|
4526
4903
|
cursorStyle(CursorStyle.Grabbing);
|
|
4527
4904
|
this.draggingFrom = [event.x, event.y];
|
|
4528
4905
|
this.currentAction = new MoveNodeAction(this, d.id, d.coords, [0, 0]);
|
|
@@ -4532,7 +4909,8 @@ class DiagramCanvas {
|
|
|
4532
4909
|
}
|
|
4533
4910
|
})
|
|
4534
4911
|
.on(DragEvents.Drag, (event, d) => {
|
|
4535
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
4912
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
4913
|
+
!d.removed) {
|
|
4536
4914
|
const newNodeCoords = [
|
|
4537
4915
|
event.x - d.width / 2,
|
|
4538
4916
|
event.y - d.height / 2
|
|
@@ -4541,7 +4919,8 @@ class DiagramCanvas {
|
|
|
4541
4919
|
}
|
|
4542
4920
|
})
|
|
4543
4921
|
.on(DragEvents.End, (event, d) => {
|
|
4544
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
4922
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
4923
|
+
!d.removed) {
|
|
4545
4924
|
// prevent drag behavior if mouse hasn't moved
|
|
4546
4925
|
if ((this.draggingFrom[0] !== event.x ||
|
|
4547
4926
|
this.draggingFrom[1] !== event.y) &&
|
|
@@ -4554,10 +4933,8 @@ class DiagramCanvas {
|
|
|
4554
4933
|
newNodeCoords = this.getClosestGridPoint(newNodeCoords);
|
|
4555
4934
|
}
|
|
4556
4935
|
this.currentAction.to = newNodeCoords;
|
|
4557
|
-
this.currentAction.
|
|
4936
|
+
this.currentAction.do();
|
|
4558
4937
|
this.actionQueue.add(this.currentAction);
|
|
4559
|
-
}
|
|
4560
|
-
else {
|
|
4561
4938
|
this.currentAction = undefined;
|
|
4562
4939
|
}
|
|
4563
4940
|
}
|
|
@@ -4621,13 +4998,15 @@ class DiagramCanvas {
|
|
|
4621
4998
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
4622
4999
|
.on(Events.MouseOver, (event, d) => {
|
|
4623
5000
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4624
|
-
d.type.resizableX
|
|
5001
|
+
d.type.resizableX &&
|
|
5002
|
+
!d.removed) {
|
|
4625
5003
|
cursorStyle(CursorStyle.EWResize);
|
|
4626
5004
|
}
|
|
4627
5005
|
})
|
|
4628
5006
|
.on(Events.MouseOut, (event, d) => {
|
|
4629
5007
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4630
|
-
d.type.resizableX
|
|
5008
|
+
d.type.resizableX &&
|
|
5009
|
+
!d.removed) {
|
|
4631
5010
|
cursorStyle();
|
|
4632
5011
|
}
|
|
4633
5012
|
})
|
|
@@ -4635,7 +5014,8 @@ class DiagramCanvas {
|
|
|
4635
5014
|
.drag()
|
|
4636
5015
|
.on(DragEvents.Start, (event, d) => {
|
|
4637
5016
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4638
|
-
d.type.resizableX
|
|
5017
|
+
d.type.resizableX &&
|
|
5018
|
+
!d.removed) {
|
|
4639
5019
|
cursorStyle(CursorStyle.EWResize);
|
|
4640
5020
|
this.currentAction = new StretchNodeAction(this, d.id, Side.Left, d.width, d.width);
|
|
4641
5021
|
}
|
|
@@ -4645,14 +5025,17 @@ class DiagramCanvas {
|
|
|
4645
5025
|
})
|
|
4646
5026
|
.on(DragEvents.Drag, (event, d) => {
|
|
4647
5027
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4648
|
-
d.type.resizableX
|
|
5028
|
+
d.type.resizableX &&
|
|
5029
|
+
!d.removed) {
|
|
4649
5030
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4650
5031
|
d.stretch(Side.Left, d.coords[0] - pointerCoords[0]);
|
|
4651
5032
|
}
|
|
4652
5033
|
})
|
|
4653
5034
|
.on(DragEvents.End, (event, d) => {
|
|
4654
5035
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4655
|
-
d.type.resizableX
|
|
5036
|
+
d.type.resizableX &&
|
|
5037
|
+
!d.removed &&
|
|
5038
|
+
this.currentAction instanceof StretchNodeAction) {
|
|
4656
5039
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4657
5040
|
if (this.snapToGrid) {
|
|
4658
5041
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -4672,13 +5055,15 @@ class DiagramCanvas {
|
|
|
4672
5055
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
4673
5056
|
.on(Events.MouseOver, (event, d) => {
|
|
4674
5057
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4675
|
-
d.type.resizableY
|
|
5058
|
+
d.type.resizableY &&
|
|
5059
|
+
!d.removed) {
|
|
4676
5060
|
cursorStyle(CursorStyle.NSResize);
|
|
4677
5061
|
}
|
|
4678
5062
|
})
|
|
4679
5063
|
.on(Events.MouseOut, (event, d) => {
|
|
4680
5064
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4681
|
-
d.type.resizableY
|
|
5065
|
+
d.type.resizableY &&
|
|
5066
|
+
!d.removed) {
|
|
4682
5067
|
cursorStyle();
|
|
4683
5068
|
}
|
|
4684
5069
|
})
|
|
@@ -4686,7 +5071,8 @@ class DiagramCanvas {
|
|
|
4686
5071
|
.drag()
|
|
4687
5072
|
.on(DragEvents.Start, (event, d) => {
|
|
4688
5073
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4689
|
-
d.type.resizableY
|
|
5074
|
+
d.type.resizableY &&
|
|
5075
|
+
!d.removed) {
|
|
4690
5076
|
cursorStyle(CursorStyle.NSResize);
|
|
4691
5077
|
this.currentAction = new StretchNodeAction(this, d.id, Side.Top, d.height, d.height);
|
|
4692
5078
|
}
|
|
@@ -4696,14 +5082,17 @@ class DiagramCanvas {
|
|
|
4696
5082
|
})
|
|
4697
5083
|
.on(DragEvents.Drag, (event, d) => {
|
|
4698
5084
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4699
|
-
d.type.resizableY
|
|
5085
|
+
d.type.resizableY &&
|
|
5086
|
+
!d.removed) {
|
|
4700
5087
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4701
5088
|
d.stretch(Side.Top, d.coords[1] - pointerCoords[1]);
|
|
4702
5089
|
}
|
|
4703
5090
|
})
|
|
4704
5091
|
.on(DragEvents.End, (event, d) => {
|
|
4705
5092
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4706
|
-
d.type.resizableY
|
|
5093
|
+
d.type.resizableY &&
|
|
5094
|
+
!d.removed &&
|
|
5095
|
+
this.currentAction instanceof StretchNodeAction) {
|
|
4707
5096
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4708
5097
|
if (this.snapToGrid) {
|
|
4709
5098
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -4723,13 +5112,15 @@ class DiagramCanvas {
|
|
|
4723
5112
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
4724
5113
|
.on(Events.MouseOver, (event, d) => {
|
|
4725
5114
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4726
|
-
d.type.resizableX
|
|
5115
|
+
d.type.resizableX &&
|
|
5116
|
+
!d.removed) {
|
|
4727
5117
|
cursorStyle(CursorStyle.EWResize);
|
|
4728
5118
|
}
|
|
4729
5119
|
})
|
|
4730
5120
|
.on(Events.MouseOut, (event, d) => {
|
|
4731
5121
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4732
|
-
d.type.resizableX
|
|
5122
|
+
d.type.resizableX &&
|
|
5123
|
+
!d.removed) {
|
|
4733
5124
|
cursorStyle();
|
|
4734
5125
|
}
|
|
4735
5126
|
})
|
|
@@ -4737,7 +5128,8 @@ class DiagramCanvas {
|
|
|
4737
5128
|
.drag()
|
|
4738
5129
|
.on(DragEvents.Start, (event, d) => {
|
|
4739
5130
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4740
|
-
d.type.resizableX
|
|
5131
|
+
d.type.resizableX &&
|
|
5132
|
+
!d.removed) {
|
|
4741
5133
|
cursorStyle(CursorStyle.EWResize);
|
|
4742
5134
|
this.currentAction = new StretchNodeAction(this, d.id, Side.Right, d.width, d.width);
|
|
4743
5135
|
}
|
|
@@ -4747,14 +5139,17 @@ class DiagramCanvas {
|
|
|
4747
5139
|
})
|
|
4748
5140
|
.on(DragEvents.Drag, (event, d) => {
|
|
4749
5141
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4750
|
-
d.type.resizableX
|
|
5142
|
+
d.type.resizableX &&
|
|
5143
|
+
!d.removed) {
|
|
4751
5144
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4752
5145
|
d.stretch(Side.Right, pointerCoords[0] - (d.coords[0] + d.width));
|
|
4753
5146
|
}
|
|
4754
5147
|
})
|
|
4755
5148
|
.on(DragEvents.End, (event, d) => {
|
|
4756
5149
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4757
|
-
d.type.resizableX
|
|
5150
|
+
d.type.resizableX &&
|
|
5151
|
+
!d.removed &&
|
|
5152
|
+
this.currentAction instanceof StretchNodeAction) {
|
|
4758
5153
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4759
5154
|
if (this.snapToGrid) {
|
|
4760
5155
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -4774,13 +5169,15 @@ class DiagramCanvas {
|
|
|
4774
5169
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
4775
5170
|
.on(Events.MouseOver, (event, d) => {
|
|
4776
5171
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4777
|
-
d.type.resizableY
|
|
5172
|
+
d.type.resizableY &&
|
|
5173
|
+
!d.removed) {
|
|
4778
5174
|
cursorStyle(CursorStyle.NSResize);
|
|
4779
5175
|
}
|
|
4780
5176
|
})
|
|
4781
5177
|
.on(Events.MouseOut, (event, d) => {
|
|
4782
5178
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4783
|
-
d.type.resizableY
|
|
5179
|
+
d.type.resizableY &&
|
|
5180
|
+
!d.removed) {
|
|
4784
5181
|
cursorStyle();
|
|
4785
5182
|
}
|
|
4786
5183
|
})
|
|
@@ -4788,7 +5185,8 @@ class DiagramCanvas {
|
|
|
4788
5185
|
.drag()
|
|
4789
5186
|
.on(DragEvents.Start, (event, d) => {
|
|
4790
5187
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4791
|
-
d.type.resizableY
|
|
5188
|
+
d.type.resizableY &&
|
|
5189
|
+
!d.removed) {
|
|
4792
5190
|
cursorStyle(CursorStyle.NSResize);
|
|
4793
5191
|
this.currentAction = new StretchNodeAction(this, d.id, Side.Bottom, d.height, d.height);
|
|
4794
5192
|
}
|
|
@@ -4798,14 +5196,17 @@ class DiagramCanvas {
|
|
|
4798
5196
|
})
|
|
4799
5197
|
.on(DragEvents.Drag, (event, d) => {
|
|
4800
5198
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4801
|
-
d.type.resizableY
|
|
5199
|
+
d.type.resizableY &&
|
|
5200
|
+
!d.removed) {
|
|
4802
5201
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4803
5202
|
d.stretch(Side.Bottom, pointerCoords[1] - (d.coords[1] + d.height));
|
|
4804
5203
|
}
|
|
4805
5204
|
})
|
|
4806
5205
|
.on(DragEvents.End, (event, d) => {
|
|
4807
5206
|
if (this.canUserPerformAction(DiagramActions.StretchNode) &&
|
|
4808
|
-
d.type.resizableY
|
|
5207
|
+
d.type.resizableY &&
|
|
5208
|
+
!d.removed &&
|
|
5209
|
+
this.currentAction instanceof StretchNodeAction) {
|
|
4809
5210
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
4810
5211
|
if (this.snapToGrid) {
|
|
4811
5212
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -4817,7 +5218,9 @@ class DiagramCanvas {
|
|
|
4817
5218
|
}
|
|
4818
5219
|
cursorStyle();
|
|
4819
5220
|
}));
|
|
4820
|
-
mergeSelection
|
|
5221
|
+
mergeSelection
|
|
5222
|
+
.attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
|
|
5223
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1));
|
|
4821
5224
|
mergeSelection
|
|
4822
5225
|
.filter('.shaped-look')
|
|
4823
5226
|
.select('path')
|
|
@@ -4981,7 +5384,10 @@ class DiagramCanvas {
|
|
|
4981
5384
|
updateSectionsInView(...ids) {
|
|
4982
5385
|
let updateSelection = this.selectCanvasSections()
|
|
4983
5386
|
.selectAll('g.diagram-section')
|
|
4984
|
-
.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);
|
|
4985
5391
|
const exitSelection = updateSelection.exit();
|
|
4986
5392
|
const enterSelection = updateSelection
|
|
4987
5393
|
.enter()
|
|
@@ -5006,7 +5412,8 @@ class DiagramCanvas {
|
|
|
5006
5412
|
.call(d3
|
|
5007
5413
|
.drag()
|
|
5008
5414
|
.on(DragEvents.Start, (event, d) => {
|
|
5009
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
5415
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
5416
|
+
!d.removed) {
|
|
5010
5417
|
const node = d.node;
|
|
5011
5418
|
cursorStyle(CursorStyle.Grabbing);
|
|
5012
5419
|
this.draggingFrom = [event.x, event.y];
|
|
@@ -5017,7 +5424,8 @@ class DiagramCanvas {
|
|
|
5017
5424
|
}
|
|
5018
5425
|
})
|
|
5019
5426
|
.on(DragEvents.Drag, (event, d) => {
|
|
5020
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
5427
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
5428
|
+
!d.removed) {
|
|
5021
5429
|
const node = d.node;
|
|
5022
5430
|
const newNodeCoords = [
|
|
5023
5431
|
event.x - node.width / 2,
|
|
@@ -5027,7 +5435,8 @@ class DiagramCanvas {
|
|
|
5027
5435
|
}
|
|
5028
5436
|
})
|
|
5029
5437
|
.on(DragEvents.End, (event, d) => {
|
|
5030
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
5438
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
5439
|
+
!d.removed) {
|
|
5031
5440
|
const node = d.node;
|
|
5032
5441
|
// prevent drag behavior if mouse hasn't moved
|
|
5033
5442
|
if ((this.draggingFrom[0] !== event.x ||
|
|
@@ -5041,10 +5450,8 @@ class DiagramCanvas {
|
|
|
5041
5450
|
newNodeCoords = this.getClosestGridPoint(newNodeCoords);
|
|
5042
5451
|
}
|
|
5043
5452
|
this.currentAction.to = newNodeCoords;
|
|
5044
|
-
this.currentAction.
|
|
5453
|
+
this.currentAction.do();
|
|
5045
5454
|
this.actionQueue.add(this.currentAction);
|
|
5046
|
-
}
|
|
5047
|
-
else {
|
|
5048
5455
|
this.currentAction = undefined;
|
|
5049
5456
|
}
|
|
5050
5457
|
}
|
|
@@ -5108,13 +5515,15 @@ class DiagramCanvas {
|
|
|
5108
5515
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
5109
5516
|
.on(Events.MouseOver, (event, d) => {
|
|
5110
5517
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5111
|
-
d.node?.type?.resizableX
|
|
5518
|
+
d.node?.type?.resizableX &&
|
|
5519
|
+
!d.removed) {
|
|
5112
5520
|
cursorStyle(CursorStyle.EWResize);
|
|
5113
5521
|
}
|
|
5114
5522
|
})
|
|
5115
5523
|
.on(Events.MouseOut, (event, d) => {
|
|
5116
5524
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5117
|
-
d.node?.type?.resizableX
|
|
5525
|
+
d.node?.type?.resizableX &&
|
|
5526
|
+
!d.removed) {
|
|
5118
5527
|
cursorStyle();
|
|
5119
5528
|
}
|
|
5120
5529
|
})
|
|
@@ -5122,7 +5531,8 @@ class DiagramCanvas {
|
|
|
5122
5531
|
.drag()
|
|
5123
5532
|
.on(DragEvents.Start, (event, d) => {
|
|
5124
5533
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5125
|
-
d.node?.type?.resizableX
|
|
5534
|
+
d.node?.type?.resizableX &&
|
|
5535
|
+
!d.removed) {
|
|
5126
5536
|
cursorStyle(CursorStyle.EWResize);
|
|
5127
5537
|
this.currentAction = new StretchSectionAction(this, d.id, Side.Left, d.width, d.width);
|
|
5128
5538
|
}
|
|
@@ -5132,14 +5542,17 @@ class DiagramCanvas {
|
|
|
5132
5542
|
})
|
|
5133
5543
|
.on(DragEvents.Drag, (event, d) => {
|
|
5134
5544
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5135
|
-
d.node?.type?.resizableX
|
|
5545
|
+
d.node?.type?.resizableX &&
|
|
5546
|
+
!d.removed) {
|
|
5136
5547
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5137
5548
|
d.node.stretchSections(Side.Left, d.coords[0] - pointerCoords[0], d.indexXInNode, d.indexYInNode);
|
|
5138
5549
|
}
|
|
5139
5550
|
})
|
|
5140
5551
|
.on(DragEvents.End, (event, d) => {
|
|
5141
5552
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5142
|
-
d.node?.type?.resizableX
|
|
5553
|
+
d.node?.type?.resizableX &&
|
|
5554
|
+
!d.removed &&
|
|
5555
|
+
this.currentAction instanceof StretchSectionAction) {
|
|
5143
5556
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5144
5557
|
if (this.snapToGrid) {
|
|
5145
5558
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -5159,13 +5572,15 @@ class DiagramCanvas {
|
|
|
5159
5572
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
5160
5573
|
.on(Events.MouseOver, (event, d) => {
|
|
5161
5574
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5162
|
-
d.node?.type?.resizableY
|
|
5575
|
+
d.node?.type?.resizableY &&
|
|
5576
|
+
!d.removed) {
|
|
5163
5577
|
cursorStyle(CursorStyle.NSResize);
|
|
5164
5578
|
}
|
|
5165
5579
|
})
|
|
5166
5580
|
.on(Events.MouseOut, (event, d) => {
|
|
5167
5581
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5168
|
-
d.node?.type?.resizableY
|
|
5582
|
+
d.node?.type?.resizableY &&
|
|
5583
|
+
!d.removed) {
|
|
5169
5584
|
cursorStyle();
|
|
5170
5585
|
}
|
|
5171
5586
|
})
|
|
@@ -5173,7 +5588,8 @@ class DiagramCanvas {
|
|
|
5173
5588
|
.drag()
|
|
5174
5589
|
.on(DragEvents.Start, (event, d) => {
|
|
5175
5590
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5176
|
-
d.node?.type?.resizableY
|
|
5591
|
+
d.node?.type?.resizableY &&
|
|
5592
|
+
!d.removed) {
|
|
5177
5593
|
cursorStyle(CursorStyle.NSResize);
|
|
5178
5594
|
this.currentAction = new StretchSectionAction(this, d.id, Side.Top, d.height, d.height);
|
|
5179
5595
|
}
|
|
@@ -5183,14 +5599,17 @@ class DiagramCanvas {
|
|
|
5183
5599
|
})
|
|
5184
5600
|
.on(DragEvents.Drag, (event, d) => {
|
|
5185
5601
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5186
|
-
d.node?.type?.resizableY
|
|
5602
|
+
d.node?.type?.resizableY &&
|
|
5603
|
+
!d.removed) {
|
|
5187
5604
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5188
5605
|
d.node.stretchSections(Side.Top, d.coords[1] - pointerCoords[1], d.indexXInNode, d.indexYInNode);
|
|
5189
5606
|
}
|
|
5190
5607
|
})
|
|
5191
5608
|
.on(DragEvents.End, (event, d) => {
|
|
5192
5609
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5193
|
-
d.node?.type?.resizableY
|
|
5610
|
+
d.node?.type?.resizableY &&
|
|
5611
|
+
!d.removed &&
|
|
5612
|
+
this.currentAction instanceof StretchSectionAction) {
|
|
5194
5613
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5195
5614
|
if (this.snapToGrid) {
|
|
5196
5615
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -5210,13 +5629,15 @@ class DiagramCanvas {
|
|
|
5210
5629
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
5211
5630
|
.on(Events.MouseOver, (event, d) => {
|
|
5212
5631
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5213
|
-
d.node?.type?.resizableX
|
|
5632
|
+
d.node?.type?.resizableX &&
|
|
5633
|
+
!d.removed) {
|
|
5214
5634
|
cursorStyle(CursorStyle.EWResize);
|
|
5215
5635
|
}
|
|
5216
5636
|
})
|
|
5217
5637
|
.on(Events.MouseOut, (event, d) => {
|
|
5218
5638
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5219
|
-
d.node?.type?.resizableX
|
|
5639
|
+
d.node?.type?.resizableX &&
|
|
5640
|
+
!d.removed) {
|
|
5220
5641
|
cursorStyle();
|
|
5221
5642
|
}
|
|
5222
5643
|
})
|
|
@@ -5224,7 +5645,8 @@ class DiagramCanvas {
|
|
|
5224
5645
|
.drag()
|
|
5225
5646
|
.on(DragEvents.Start, (event, d) => {
|
|
5226
5647
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5227
|
-
d.node?.type?.resizableX
|
|
5648
|
+
d.node?.type?.resizableX &&
|
|
5649
|
+
!d.removed) {
|
|
5228
5650
|
cursorStyle(CursorStyle.EWResize);
|
|
5229
5651
|
this.currentAction = new StretchSectionAction(this, d.id, Side.Right, d.width, d.width);
|
|
5230
5652
|
}
|
|
@@ -5234,14 +5656,17 @@ class DiagramCanvas {
|
|
|
5234
5656
|
})
|
|
5235
5657
|
.on(DragEvents.Drag, (event, d) => {
|
|
5236
5658
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5237
|
-
d.node?.type?.resizableX
|
|
5659
|
+
d.node?.type?.resizableX &&
|
|
5660
|
+
!d.removed) {
|
|
5238
5661
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5239
5662
|
d.node.stretchSections(Side.Right, pointerCoords[0] - (d.coords[0] + d.width), d.indexXInNode, d.indexYInNode);
|
|
5240
5663
|
}
|
|
5241
5664
|
})
|
|
5242
5665
|
.on(DragEvents.End, (event, d) => {
|
|
5243
5666
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5244
|
-
d.node?.type?.resizableX
|
|
5667
|
+
d.node?.type?.resizableX &&
|
|
5668
|
+
!d.removed &&
|
|
5669
|
+
this.currentAction instanceof StretchSectionAction) {
|
|
5245
5670
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5246
5671
|
if (this.snapToGrid) {
|
|
5247
5672
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -5261,13 +5686,15 @@ class DiagramCanvas {
|
|
|
5261
5686
|
.attr('stroke-width', `${RESIZER_THICKNESS}px`)
|
|
5262
5687
|
.on(Events.MouseOver, (event, d) => {
|
|
5263
5688
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5264
|
-
d.node?.type?.resizableY
|
|
5689
|
+
d.node?.type?.resizableY &&
|
|
5690
|
+
!d.removed) {
|
|
5265
5691
|
cursorStyle(CursorStyle.NSResize);
|
|
5266
5692
|
}
|
|
5267
5693
|
})
|
|
5268
5694
|
.on(Events.MouseOut, (event, d) => {
|
|
5269
5695
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5270
|
-
d.node?.type?.resizableY
|
|
5696
|
+
d.node?.type?.resizableY &&
|
|
5697
|
+
!d.removed) {
|
|
5271
5698
|
cursorStyle();
|
|
5272
5699
|
}
|
|
5273
5700
|
})
|
|
@@ -5275,7 +5702,8 @@ class DiagramCanvas {
|
|
|
5275
5702
|
.drag()
|
|
5276
5703
|
.on(DragEvents.Start, (event, d) => {
|
|
5277
5704
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5278
|
-
d.node?.type?.resizableY
|
|
5705
|
+
d.node?.type?.resizableY &&
|
|
5706
|
+
!d.removed) {
|
|
5279
5707
|
cursorStyle(CursorStyle.NSResize);
|
|
5280
5708
|
this.currentAction = new StretchSectionAction(this, d.id, Side.Bottom, d.height, d.height);
|
|
5281
5709
|
}
|
|
@@ -5285,14 +5713,17 @@ class DiagramCanvas {
|
|
|
5285
5713
|
})
|
|
5286
5714
|
.on(DragEvents.Drag, (event, d) => {
|
|
5287
5715
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5288
|
-
d.node?.type?.resizableY
|
|
5716
|
+
d.node?.type?.resizableY &&
|
|
5717
|
+
!d.removed) {
|
|
5289
5718
|
const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5290
5719
|
d.node.stretchSections(Side.Bottom, pointerCoords[1] - (d.coords[1] + d.height), d.indexXInNode, d.indexYInNode);
|
|
5291
5720
|
}
|
|
5292
5721
|
})
|
|
5293
5722
|
.on(DragEvents.End, (event, d) => {
|
|
5294
5723
|
if (this.canUserPerformAction(DiagramActions.StretchSection) &&
|
|
5295
|
-
d.node?.type?.resizableY
|
|
5724
|
+
d.node?.type?.resizableY &&
|
|
5725
|
+
!d.removed &&
|
|
5726
|
+
this.currentAction instanceof StretchSectionAction) {
|
|
5296
5727
|
let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
|
|
5297
5728
|
if (this.snapToGrid) {
|
|
5298
5729
|
pointerCoords = this.getClosestGridPoint(pointerCoords);
|
|
@@ -5304,7 +5735,9 @@ class DiagramCanvas {
|
|
|
5304
5735
|
}
|
|
5305
5736
|
cursorStyle();
|
|
5306
5737
|
}));
|
|
5307
|
-
mergeSelection
|
|
5738
|
+
mergeSelection
|
|
5739
|
+
.attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
|
|
5740
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1));
|
|
5308
5741
|
mergeSelection
|
|
5309
5742
|
.filter('.shaped-look')
|
|
5310
5743
|
.select('path')
|
|
@@ -5483,7 +5916,10 @@ class DiagramCanvas {
|
|
|
5483
5916
|
updatePortsInView(...ids) {
|
|
5484
5917
|
let updateSelection = this.selectCanvasPorts()
|
|
5485
5918
|
.selectAll('g.diagram-port')
|
|
5486
|
-
.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);
|
|
5487
5923
|
const exitSelection = updateSelection.exit();
|
|
5488
5924
|
const enterSelection = updateSelection
|
|
5489
5925
|
.enter()
|
|
@@ -5522,7 +5958,8 @@ class DiagramCanvas {
|
|
|
5522
5958
|
.call(d3
|
|
5523
5959
|
.drag()
|
|
5524
5960
|
.on(DragEvents.Start, (event, d) => {
|
|
5525
|
-
if (this.canUserPerformAction(DiagramActions.AddConnection)
|
|
5961
|
+
if (this.canUserPerformAction(DiagramActions.AddConnection) &&
|
|
5962
|
+
!d.removed) {
|
|
5526
5963
|
cursorStyle(CursorStyle.Grabbing);
|
|
5527
5964
|
this.startConnection(d);
|
|
5528
5965
|
// should be true after having called this.startConnection()
|
|
@@ -5533,9 +5970,13 @@ class DiagramCanvas {
|
|
|
5533
5970
|
.attr('fill', 'none');
|
|
5534
5971
|
}
|
|
5535
5972
|
}
|
|
5973
|
+
else {
|
|
5974
|
+
cursorStyle(CursorStyle.NotAllowed);
|
|
5975
|
+
}
|
|
5536
5976
|
})
|
|
5537
|
-
.on(DragEvents.Drag, (event) => {
|
|
5538
|
-
if (this.canUserPerformAction(DiagramActions.AddConnection)
|
|
5977
|
+
.on(DragEvents.Drag, (event, d) => {
|
|
5978
|
+
if (this.canUserPerformAction(DiagramActions.AddConnection) &&
|
|
5979
|
+
!d.removed) {
|
|
5539
5980
|
if (this.unfinishedConnection !== undefined) {
|
|
5540
5981
|
const endCoords = [event.x, event.y];
|
|
5541
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));
|
|
@@ -5560,9 +6001,9 @@ class DiagramCanvas {
|
|
|
5560
6001
|
}
|
|
5561
6002
|
}
|
|
5562
6003
|
})
|
|
5563
|
-
.on(DragEvents.End, (event) => {
|
|
5564
|
-
if (this.canUserPerformAction(DiagramActions.AddConnection)
|
|
5565
|
-
|
|
6004
|
+
.on(DragEvents.End, (event, d) => {
|
|
6005
|
+
if (this.canUserPerformAction(DiagramActions.AddConnection) &&
|
|
6006
|
+
!d.removed) {
|
|
5566
6007
|
this.unfinishedConnectionTracer?.remove();
|
|
5567
6008
|
if (this.mainUserHighlight instanceof DiagramPort) {
|
|
5568
6009
|
this.finishConnection(this.mainUserHighlight);
|
|
@@ -5598,10 +6039,12 @@ class DiagramCanvas {
|
|
|
5598
6039
|
this.dropConnection();
|
|
5599
6040
|
}
|
|
5600
6041
|
}
|
|
6042
|
+
cursorStyle();
|
|
5601
6043
|
}));
|
|
5602
6044
|
enterSelection.append('circle');
|
|
5603
6045
|
mergeSelection
|
|
5604
6046
|
.attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
|
|
6047
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1))
|
|
5605
6048
|
.select('circle')
|
|
5606
6049
|
.attr('cx', 0)
|
|
5607
6050
|
.attr('cy', 0)
|
|
@@ -5612,7 +6055,10 @@ class DiagramCanvas {
|
|
|
5612
6055
|
.attr('opacity', (d) => (d.highlighted || d.selected ? 0.5 : 0));
|
|
5613
6056
|
}
|
|
5614
6057
|
updateConnectionsInView(...ids) {
|
|
5615
|
-
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));
|
|
5616
6062
|
if (this.unfinishedConnection) {
|
|
5617
6063
|
connectionList.push(this.unfinishedConnection);
|
|
5618
6064
|
}
|
|
@@ -5675,6 +6121,7 @@ class DiagramCanvas {
|
|
|
5675
6121
|
.append('text')
|
|
5676
6122
|
.style('user-select', 'none');
|
|
5677
6123
|
mergeSelection
|
|
6124
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1))
|
|
5678
6125
|
.select('path.diagram-connection-path')
|
|
5679
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))
|
|
5680
6127
|
.attr('marker-start', (d) => `url(#${d.id}-start-marker)`)
|
|
@@ -5700,7 +6147,10 @@ class DiagramCanvas {
|
|
|
5700
6147
|
updateFieldsInView(...ids) {
|
|
5701
6148
|
let updateSelection = this.selectCanvasFields()
|
|
5702
6149
|
.selectAll('foreignObject.diagram-field')
|
|
5703
|
-
.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);
|
|
5704
6154
|
const exitSelection = updateSelection.exit();
|
|
5705
6155
|
const enterSelection = updateSelection
|
|
5706
6156
|
.enter()
|
|
@@ -5726,7 +6176,9 @@ class DiagramCanvas {
|
|
|
5726
6176
|
}
|
|
5727
6177
|
})
|
|
5728
6178
|
.on(Events.DoubleClick, (event, d) => {
|
|
5729
|
-
if (this.canUserPerformAction(DiagramActions.EditField) &&
|
|
6179
|
+
if (this.canUserPerformAction(DiagramActions.EditField) &&
|
|
6180
|
+
d.editable &&
|
|
6181
|
+
!d.removed) {
|
|
5730
6182
|
this.currentAction = new EditFieldAction(this, d.id, d.text, '');
|
|
5731
6183
|
this.createInputField(d.text, d.coords, d.width, d.height, d.fontSize, d.fontFamily || DIAGRAM_FIELD_DEFAULTS.fontFamily, (text) => {
|
|
5732
6184
|
d.text = text;
|
|
@@ -5743,7 +6195,8 @@ class DiagramCanvas {
|
|
|
5743
6195
|
.call(d3
|
|
5744
6196
|
.drag()
|
|
5745
6197
|
.on(DragEvents.Start, (event, d) => {
|
|
5746
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
6198
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
6199
|
+
!d.removed) {
|
|
5747
6200
|
if (d.rootElement instanceof DiagramNode ||
|
|
5748
6201
|
d.rootElement instanceof DiagramSection) {
|
|
5749
6202
|
const node = d.rootElement instanceof DiagramNode
|
|
@@ -5759,7 +6212,8 @@ class DiagramCanvas {
|
|
|
5759
6212
|
}
|
|
5760
6213
|
})
|
|
5761
6214
|
.on(DragEvents.Drag, (event, d) => {
|
|
5762
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
6215
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
6216
|
+
!d.removed) {
|
|
5763
6217
|
if (d.rootElement instanceof DiagramNode ||
|
|
5764
6218
|
d.rootElement instanceof DiagramSection) {
|
|
5765
6219
|
const node = d.rootElement instanceof DiagramNode
|
|
@@ -5774,7 +6228,8 @@ class DiagramCanvas {
|
|
|
5774
6228
|
}
|
|
5775
6229
|
})
|
|
5776
6230
|
.on(DragEvents.End, (event, d) => {
|
|
5777
|
-
if (this.canUserPerformAction(DiagramActions.MoveNode)
|
|
6231
|
+
if (this.canUserPerformAction(DiagramActions.MoveNode) &&
|
|
6232
|
+
!d.removed) {
|
|
5778
6233
|
if (d.rootElement instanceof DiagramNode ||
|
|
5779
6234
|
d.rootElement instanceof DiagramSection) {
|
|
5780
6235
|
const node = d.rootElement instanceof DiagramNode
|
|
@@ -5792,10 +6247,8 @@ class DiagramCanvas {
|
|
|
5792
6247
|
newNodeCoords = this.getClosestGridPoint(newNodeCoords);
|
|
5793
6248
|
}
|
|
5794
6249
|
this.currentAction.to = newNodeCoords;
|
|
5795
|
-
this.currentAction.
|
|
6250
|
+
this.currentAction.do();
|
|
5796
6251
|
this.actionQueue.add(this.currentAction);
|
|
5797
|
-
}
|
|
5798
|
-
else {
|
|
5799
6252
|
this.currentAction = undefined;
|
|
5800
6253
|
}
|
|
5801
6254
|
}
|
|
@@ -5821,6 +6274,7 @@ class DiagramCanvas {
|
|
|
5821
6274
|
.attr('width', (d) => `${d.width}px`)
|
|
5822
6275
|
.attr('height', (d) => `${d.height}px`)
|
|
5823
6276
|
.attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
|
|
6277
|
+
.attr('opacity', (d) => (d.removed ? 0.5 : 1))
|
|
5824
6278
|
.select('div')
|
|
5825
6279
|
.style('justify-content', (d) => d.horizontalAlign === HorizontalAlign.Center
|
|
5826
6280
|
? 'center'
|
|
@@ -6189,7 +6643,7 @@ class DiagramCanvas {
|
|
|
6189
6643
|
const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, this.unfinishedConnection.start?.id, port.id);
|
|
6190
6644
|
// clean up the previous unfinished connection
|
|
6191
6645
|
this.dropConnection();
|
|
6192
|
-
addConnectionAction.
|
|
6646
|
+
addConnectionAction.do();
|
|
6193
6647
|
this.actionQueue.add(addConnectionAction);
|
|
6194
6648
|
}
|
|
6195
6649
|
else if (this.unfinishedConnection.type.canFinishOnType(this.unfinishedConnection?.start?.getNode()?.type?.id || '') &&
|
|
@@ -6197,7 +6651,7 @@ class DiagramCanvas {
|
|
|
6197
6651
|
const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, port.id, this.unfinishedConnection.start?.id);
|
|
6198
6652
|
// clean up the previous unfinished connection
|
|
6199
6653
|
this.dropConnection();
|
|
6200
|
-
addConnectionAction.
|
|
6654
|
+
addConnectionAction.do();
|
|
6201
6655
|
this.actionQueue.add(addConnectionAction);
|
|
6202
6656
|
}
|
|
6203
6657
|
else {
|
|
@@ -6221,7 +6675,7 @@ class DiagramCanvas {
|
|
|
6221
6675
|
: port.id);
|
|
6222
6676
|
// clean up the previous unfinished connection
|
|
6223
6677
|
this.dropConnection();
|
|
6224
|
-
addConnectionAction.
|
|
6678
|
+
addConnectionAction.do();
|
|
6225
6679
|
this.actionQueue.add(addConnectionAction);
|
|
6226
6680
|
}
|
|
6227
6681
|
else {
|
|
@@ -6310,7 +6764,10 @@ class DiagramCanvas {
|
|
|
6310
6764
|
// check if there have been changes in the previously selected ValueSet,
|
|
6311
6765
|
// and create an UpdateValuesAction if there have
|
|
6312
6766
|
if (!equals(this.propertyEditorValues, this.propertyEditorSelection?.valueSet.getValues())) {
|
|
6313
|
-
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);
|
|
6314
6771
|
this.actionQueue.add(currentAction);
|
|
6315
6772
|
this.propertyEditorValues = undefined;
|
|
6316
6773
|
}
|
|
@@ -6674,7 +7131,7 @@ class DiagramButtonsComponent {
|
|
|
6674
7131
|
this.canvas.actionQueue.redo();
|
|
6675
7132
|
}
|
|
6676
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 }); }
|
|
6677
|
-
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"] }] }); }
|
|
6678
7135
|
}
|
|
6679
7136
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DiagramButtonsComponent, decorators: [{
|
|
6680
7137
|
type: Component,
|
|
@@ -6713,7 +7170,7 @@ class ErrorsComponent {
|
|
|
6713
7170
|
this.Side = Side;
|
|
6714
7171
|
}
|
|
6715
7172
|
ngAfterViewInit() {
|
|
6716
|
-
merge(
|
|
7173
|
+
merge(this.canvas.validatorChanges$, this.canvas.diagramChanges$)
|
|
6717
7174
|
.pipe(
|
|
6718
7175
|
// delay to avoid errors of variables changing right after checking
|
|
6719
7176
|
delay(1), map(() => this.validate()))
|
|
@@ -6742,7 +7199,7 @@ class ErrorsComponent {
|
|
|
6742
7199
|
// TODO: IF ERROR IS IN AN ELEMENT BUT NOT IN A SPECIFIC PROPERTY, WE COULD HIGHLIGHT THE ELEMENT
|
|
6743
7200
|
}
|
|
6744
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 }); }
|
|
6745
|
-
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"] }] }); }
|
|
6746
7203
|
}
|
|
6747
7204
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ErrorsComponent, decorators: [{
|
|
6748
7205
|
type: Component,
|
|
@@ -6877,7 +7334,7 @@ class PaletteComponent {
|
|
|
6877
7334
|
.drag()
|
|
6878
7335
|
.on(DragEvents.Drag, (event) => {
|
|
6879
7336
|
if (this.canvas.canUserPerformAction(DiagramActions.AddNode)) {
|
|
6880
|
-
const pointerCoords = this.canvas.
|
|
7337
|
+
const pointerCoords = this.canvas.getPointerLocationRelativeToScreen(event);
|
|
6881
7338
|
if (pointerCoords.length < 2 ||
|
|
6882
7339
|
isNaN(pointerCoords[0]) ||
|
|
6883
7340
|
isNaN(pointerCoords[1])) {
|
|
@@ -6893,7 +7350,7 @@ class PaletteComponent {
|
|
|
6893
7350
|
.on(DragEvents.Start, (event) => {
|
|
6894
7351
|
if (this.canvas.canUserPerformAction(DiagramActions.AddNode)) {
|
|
6895
7352
|
d3.select('body').style('cursor', 'grabbing');
|
|
6896
|
-
const pointerCoords = this.canvas.
|
|
7353
|
+
const pointerCoords = this.canvas.getPointerLocationRelativeToScreen(event);
|
|
6897
7354
|
if (pointerCoords.length < 2 ||
|
|
6898
7355
|
isNaN(pointerCoords[0]) ||
|
|
6899
7356
|
isNaN(pointerCoords[1])) {
|
|
@@ -6906,7 +7363,7 @@ class PaletteComponent {
|
|
|
6906
7363
|
.style('z-index', 1);
|
|
6907
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
|
|
6908
7365
|
if (type.isUnique &&
|
|
6909
|
-
this.canvas.model.nodes.find(type.id) !== undefined) {
|
|
7366
|
+
this.canvas.model.nodes.find((n) => !n.removed && n.type.id === type.id) !== undefined) {
|
|
6910
7367
|
cursorStyle(CursorStyle.NotAllowed);
|
|
6911
7368
|
}
|
|
6912
7369
|
}
|
|
@@ -6922,18 +7379,18 @@ class PaletteComponent {
|
|
|
6922
7379
|
.style('z-index', 'auto');
|
|
6923
7380
|
// try to place node
|
|
6924
7381
|
if (type.isUnique &&
|
|
6925
|
-
this.canvas.model.nodes.find(type.id) !== undefined) {
|
|
7382
|
+
this.canvas.model.nodes.find((n) => !n.removed && n.type.id === type.id) !== undefined) {
|
|
6926
7383
|
// can't place, it's unique and that node is already in the model
|
|
6927
7384
|
return;
|
|
6928
7385
|
}
|
|
6929
|
-
const
|
|
6930
|
-
if (
|
|
6931
|
-
isNaN(
|
|
6932
|
-
isNaN(
|
|
7386
|
+
const pointerCoordsRelativeToScreen = this.canvas.getPointerLocationRelativeToScreen(event);
|
|
7387
|
+
if (pointerCoordsRelativeToScreen.length < 2 ||
|
|
7388
|
+
isNaN(pointerCoordsRelativeToScreen[0]) ||
|
|
7389
|
+
isNaN(pointerCoordsRelativeToScreen[1])) {
|
|
6933
7390
|
// can't place, position is incorrect
|
|
6934
7391
|
return;
|
|
6935
7392
|
}
|
|
6936
|
-
const element = document.elementFromPoint(
|
|
7393
|
+
const element = document.elementFromPoint(pointerCoordsRelativeToScreen[0], pointerCoordsRelativeToScreen[1]);
|
|
6937
7394
|
if (element &&
|
|
6938
7395
|
!this.canvas.selectCanvasView().node()?.contains(element)) {
|
|
6939
7396
|
// can't place, node hasn't been dropped on the canvas
|
|
@@ -6954,7 +7411,7 @@ class PaletteComponent {
|
|
|
6954
7411
|
newNodeCoords = this.canvas.getClosestGridPoint(newNodeCoords);
|
|
6955
7412
|
}
|
|
6956
7413
|
const addNodeAction = new AddNodeAction(this.canvas, type, newNodeCoords, templateConfig.label, templateConfig.values);
|
|
6957
|
-
addNodeAction.
|
|
7414
|
+
addNodeAction.do();
|
|
6958
7415
|
this.canvas.actionQueue.add(addNodeAction);
|
|
6959
7416
|
// reset cursor
|
|
6960
7417
|
cursorStyle();
|
|
@@ -7131,7 +7588,7 @@ class PaletteComponent {
|
|
|
7131
7588
|
}
|
|
7132
7589
|
}
|
|
7133
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 }); }
|
|
7134
|
-
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"] }] }); }
|
|
7135
7592
|
}
|
|
7136
7593
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: PaletteComponent, decorators: [{
|
|
7137
7594
|
type: Component,
|
|
@@ -7153,20 +7610,291 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
7153
7610
|
type: Input
|
|
7154
7611
|
}] } });
|
|
7155
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
|
+
|
|
7156
7884
|
/**
|
|
7157
7885
|
* Editor of a property of text list type within a property editor.
|
|
7158
|
-
* @see TextList
|
|
7886
|
+
* @see Type.TextList
|
|
7159
7887
|
* @see PropertyEditor
|
|
7160
7888
|
* @see ValueSet
|
|
7161
7889
|
* @private
|
|
7162
7890
|
*/
|
|
7163
7891
|
class TextListEditorComponent {
|
|
7164
|
-
set value(
|
|
7165
|
-
if (
|
|
7892
|
+
set value(value) {
|
|
7893
|
+
if (value === this._value) {
|
|
7166
7894
|
return;
|
|
7167
7895
|
}
|
|
7168
|
-
const initialAndEmpty =
|
|
7169
|
-
this._value =
|
|
7896
|
+
const initialAndEmpty = value.length === 0 && this._value.length === 0;
|
|
7897
|
+
this._value = value;
|
|
7170
7898
|
if (initialAndEmpty) {
|
|
7171
7899
|
this.valueChange.emit(this._value);
|
|
7172
7900
|
}
|
|
@@ -7215,11 +7943,11 @@ class TextListEditorComponent {
|
|
|
7215
7943
|
}
|
|
7216
7944
|
}
|
|
7217
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 }); }
|
|
7218
|
-
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"] }] }); }
|
|
7219
7947
|
}
|
|
7220
7948
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TextListEditorComponent, decorators: [{
|
|
7221
7949
|
type: Component,
|
|
7222
|
-
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" }]
|
|
7223
7951
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { value: [{
|
|
7224
7952
|
type: Input
|
|
7225
7953
|
}], valueInput: [{
|
|
@@ -7232,18 +7960,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
7232
7960
|
|
|
7233
7961
|
/**
|
|
7234
7962
|
* Editor of a property of text map type within a property editor.
|
|
7235
|
-
* @see TextMap
|
|
7963
|
+
* @see Type.TextMap
|
|
7236
7964
|
* @see PropertyEditor
|
|
7237
7965
|
* @see ValueSet
|
|
7238
7966
|
* @private
|
|
7239
7967
|
*/
|
|
7240
7968
|
class TextMapEditorComponent {
|
|
7241
|
-
set value(
|
|
7242
|
-
if (
|
|
7969
|
+
set value(value) {
|
|
7970
|
+
if (value === this._value) {
|
|
7243
7971
|
return;
|
|
7244
7972
|
}
|
|
7245
|
-
const initialAndEmpty = Object.keys(
|
|
7246
|
-
this._value =
|
|
7973
|
+
const initialAndEmpty = Object.keys(value).length === 0 && Object.keys(this._value).length === 0;
|
|
7974
|
+
this._value = value;
|
|
7247
7975
|
if (initialAndEmpty) {
|
|
7248
7976
|
this.valueChange.emit(this._value);
|
|
7249
7977
|
}
|
|
@@ -7298,11 +8026,11 @@ class TextMapEditorComponent {
|
|
|
7298
8026
|
}
|
|
7299
8027
|
}
|
|
7300
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 }); }
|
|
7301
|
-
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"] }] }); }
|
|
7302
8030
|
}
|
|
7303
8031
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TextMapEditorComponent, decorators: [{
|
|
7304
8032
|
type: Component,
|
|
7305
|
-
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" }]
|
|
7306
8034
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { value: [{
|
|
7307
8035
|
type: Input
|
|
7308
8036
|
}], keyInput: [{
|
|
@@ -7326,7 +8054,8 @@ class ObjectEditorComponent {
|
|
|
7326
8054
|
return this.canvasProvider.getCanvas();
|
|
7327
8055
|
}
|
|
7328
8056
|
get userCanEdit() {
|
|
7329
|
-
return this.canvas.canUserPerformAction(DiagramActions.UpdateValues)
|
|
8057
|
+
return (this.canvas.canUserPerformAction(DiagramActions.UpdateValues) &&
|
|
8058
|
+
this.valueSet?.rootElement?.['removed'] !== true);
|
|
7330
8059
|
}
|
|
7331
8060
|
get valueSet() {
|
|
7332
8061
|
return this._valueSet;
|
|
@@ -7343,10 +8072,6 @@ class ObjectEditorComponent {
|
|
|
7343
8072
|
this.depth = 0;
|
|
7344
8073
|
// Attributes for the template
|
|
7345
8074
|
this.Type = Type;
|
|
7346
|
-
this.booleanRadioItems = [
|
|
7347
|
-
{ value: false, label: 'No' },
|
|
7348
|
-
{ value: true, label: 'Yes' }
|
|
7349
|
-
];
|
|
7350
8075
|
}
|
|
7351
8076
|
displayProperty(property) {
|
|
7352
8077
|
if (this.valueSet === undefined) {
|
|
@@ -7398,24 +8123,35 @@ class ObjectEditorComponent {
|
|
|
7398
8123
|
}
|
|
7399
8124
|
}
|
|
7400
8125
|
}
|
|
7401
|
-
|
|
8126
|
+
dateToLocalDatetimeString(date) {
|
|
7402
8127
|
if (typeof date === 'string') {
|
|
7403
8128
|
return date;
|
|
7404
8129
|
}
|
|
7405
|
-
|
|
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);
|
|
7406
8141
|
}
|
|
7407
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 }); }
|
|
7408
|
-
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"] }] }); }
|
|
7409
8144
|
}
|
|
7410
8145
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ObjectEditorComponent, decorators: [{
|
|
7411
8146
|
type: Component,
|
|
7412
8147
|
args: [{ standalone: true, selector: 'daga-object-editor', imports: [
|
|
8148
|
+
AutocompleteComponent,
|
|
7413
8149
|
CommonModule,
|
|
7414
|
-
LuxModule,
|
|
7415
8150
|
FormsModule,
|
|
8151
|
+
OptionListEditorComponent,
|
|
7416
8152
|
TextListEditorComponent,
|
|
7417
8153
|
TextMapEditorComponent
|
|
7418
|
-
], 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" }]
|
|
7419
8155
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: CanvasProviderService }], propDecorators: { valueSet: [{
|
|
7420
8156
|
type: Input
|
|
7421
8157
|
}], depth: [{
|
|
@@ -7474,11 +8210,11 @@ class PropertyEditorComponent {
|
|
|
7474
8210
|
}
|
|
7475
8211
|
}
|
|
7476
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 }); }
|
|
7477
|
-
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"] }] }); }
|
|
7478
8214
|
}
|
|
7479
8215
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: PropertyEditorComponent, decorators: [{
|
|
7480
8216
|
type: Component,
|
|
7481
|
-
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" }]
|
|
7482
8218
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { panel: [{
|
|
7483
8219
|
type: ViewChild,
|
|
7484
8220
|
args: ['panel']
|
|
@@ -7544,7 +8280,7 @@ class DiagramEditorComponent {
|
|
|
7544
8280
|
this.canvasProvider.initCanvasView(this.appendTo.nativeElement);
|
|
7545
8281
|
}
|
|
7546
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 }); }
|
|
7547
|
-
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" }] }); }
|
|
7548
8284
|
}
|
|
7549
8285
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DiagramEditorComponent, decorators: [{
|
|
7550
8286
|
type: Component,
|
|
@@ -7585,7 +8321,8 @@ class DagaExporter {
|
|
|
7585
8321
|
updatedAt: model.updatedAt,
|
|
7586
8322
|
nodes: [],
|
|
7587
8323
|
connections: [],
|
|
7588
|
-
data: model.valueSet.getValues()
|
|
8324
|
+
data: model.valueSet.getValues(),
|
|
8325
|
+
logicalClock: model.logicalClock
|
|
7589
8326
|
};
|
|
7590
8327
|
if (model.id) {
|
|
7591
8328
|
result.id = model.id;
|
|
@@ -7593,7 +8330,7 @@ class DagaExporter {
|
|
|
7593
8330
|
if (model.description) {
|
|
7594
8331
|
result.description = model.description;
|
|
7595
8332
|
}
|
|
7596
|
-
for (const node of model.nodes) {
|
|
8333
|
+
for (const node of model.nodes.filter((e) => !e.removed)) {
|
|
7597
8334
|
const sections = [];
|
|
7598
8335
|
for (const section of node.sections) {
|
|
7599
8336
|
const ports = [];
|
|
@@ -7625,7 +8362,7 @@ class DagaExporter {
|
|
|
7625
8362
|
label: port.label?.text || ''
|
|
7626
8363
|
});
|
|
7627
8364
|
}
|
|
7628
|
-
|
|
8365
|
+
const newNode = {
|
|
7629
8366
|
id: node.id,
|
|
7630
8367
|
type: node.type.id,
|
|
7631
8368
|
sections,
|
|
@@ -7635,9 +8372,13 @@ class DagaExporter {
|
|
|
7635
8372
|
width: node.width,
|
|
7636
8373
|
height: node.height,
|
|
7637
8374
|
data: node.valueSet.getValues()
|
|
7638
|
-
}
|
|
8375
|
+
};
|
|
8376
|
+
if (node.coordsTimestamp) {
|
|
8377
|
+
newNode.coordsTimestamp = node.coordsTimestamp;
|
|
8378
|
+
}
|
|
8379
|
+
result.nodes.push(newNode);
|
|
7639
8380
|
}
|
|
7640
|
-
for (const connection of model.connections) {
|
|
8381
|
+
for (const connection of model.connections.filter((e) => !e.removed)) {
|
|
7641
8382
|
result.connections.push({
|
|
7642
8383
|
id: connection.id,
|
|
7643
8384
|
type: connection.type.id,
|
|
@@ -7670,6 +8411,9 @@ class DagaImporter {
|
|
|
7670
8411
|
model.type = data.type;
|
|
7671
8412
|
model.createdAt = new Date(data.createdAt);
|
|
7672
8413
|
model.updatedAt = new Date(data.updatedAt);
|
|
8414
|
+
if (data.logicalClock) {
|
|
8415
|
+
model.logicalClock = data.logicalClock;
|
|
8416
|
+
}
|
|
7673
8417
|
for (const node of data.nodes || []) {
|
|
7674
8418
|
const newNodeType = model.nodes.types.get(node.type);
|
|
7675
8419
|
if (newNodeType) {
|
|
@@ -7677,6 +8421,9 @@ class DagaImporter {
|
|
|
7677
8421
|
model.nodes.add(newNode);
|
|
7678
8422
|
newNode.width = node.width;
|
|
7679
8423
|
newNode.height = node.height;
|
|
8424
|
+
if (node.coordsTimestamp) {
|
|
8425
|
+
newNode.coordsTimestamp = node.coordsTimestamp;
|
|
8426
|
+
}
|
|
7680
8427
|
if (node.label) {
|
|
7681
8428
|
// add node label
|
|
7682
8429
|
if (newNodeType.label) {
|
|
@@ -7920,8 +8667,7 @@ class DagaModule {
|
|
|
7920
8667
|
TextMapEditorComponent,
|
|
7921
8668
|
PropertyEditorComponent,
|
|
7922
8669
|
CommonModule,
|
|
7923
|
-
FormsModule,
|
|
7924
|
-
LuxModule], exports: [DiagramComponent, DiagramEditorComponent] }); }
|
|
8670
|
+
FormsModule], exports: [DiagramComponent, DiagramEditorComponent] }); }
|
|
7925
8671
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DagaModule, providers: [DagaConfigurationService, CanvasProviderService], imports: [CollapseButtonComponent,
|
|
7926
8672
|
DiagramButtonsComponent,
|
|
7927
8673
|
DiagramEditorComponent,
|
|
@@ -7932,8 +8678,7 @@ class DagaModule {
|
|
|
7932
8678
|
TextMapEditorComponent,
|
|
7933
8679
|
PropertyEditorComponent,
|
|
7934
8680
|
CommonModule,
|
|
7935
|
-
FormsModule
|
|
7936
|
-
LuxModule] }); }
|
|
8681
|
+
FormsModule] }); }
|
|
7937
8682
|
}
|
|
7938
8683
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DagaModule, decorators: [{
|
|
7939
8684
|
type: NgModule,
|
|
@@ -7951,17 +8696,224 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
7951
8696
|
TextMapEditorComponent,
|
|
7952
8697
|
PropertyEditorComponent,
|
|
7953
8698
|
CommonModule,
|
|
7954
|
-
FormsModule
|
|
7955
|
-
LuxModule
|
|
8699
|
+
FormsModule
|
|
7956
8700
|
],
|
|
7957
8701
|
exports: [DiagramComponent, DiagramEditorComponent],
|
|
7958
8702
|
providers: [DagaConfigurationService, CanvasProviderService]
|
|
7959
8703
|
}]
|
|
7960
8704
|
}] });
|
|
7961
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
|
+
|
|
7962
8914
|
/**
|
|
7963
8915
|
* Generated bundle index. Do not edit.
|
|
7964
8916
|
*/
|
|
7965
8917
|
|
|
7966
|
-
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 };
|
|
7967
8919
|
//# sourceMappingURL=metadev-daga.mjs.map
|