@processmaker/modeler 1.25.0 → 1.27.0
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/dist/img/clipboard.bcc7796a.svg +1 -0
- package/dist/modeler.common.js +1250 -595
- package/dist/modeler.common.js.map +1 -1
- package/dist/modeler.umd.js +1250 -595
- package/dist/modeler.umd.js.map +1 -1
- package/dist/modeler.umd.min.js +3 -3
- package/dist/modeler.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/assets/clipboard.svg +1 -0
- package/src/components/crown/crownButtons/copyButton.vue +3 -3
- package/src/components/crown/crownButtons/duplicateButton.vue +40 -0
- package/src/components/crown/crownConfig/crownConfig.vue +7 -0
- package/src/components/crown/crownMultiselect/crownMultiselect.vue +15 -6
- package/src/components/hotkeys/copyPaste.js +23 -0
- package/src/components/hotkeys/main.js +3 -1
- package/src/components/inspectors/InspectorPanel.vue +1 -0
- package/src/components/modeler/Modeler.vue +145 -1
- package/src/components/modeler/Selection.vue +39 -4
- package/src/components/nodes/node.js +39 -0
- package/src/components/toolbar/ToolBar.vue +101 -11
- package/src/components/toolbar/breadcrumb/Breadcrumb.vue +7 -0
- package/src/components/toolbar/toolbar.scss +28 -1
- package/src/store.js +18 -0
- package/src/undoRedoStore.js +45 -0
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path fill="#fff" d="M280 64h40c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128C0 92.7 28.7 64 64 64h40 9.6C121 27.5 153.3 0 192 0s71 27.5 78.4 64H280zM64 112c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320c8.8 0 16-7.2 16-16V128c0-8.8-7.2-16-16-16H304v24c0 13.3-10.7 24-24 24H192 104c-13.3 0-24-10.7-24-24V112H64zm128-8a24 24 0 1 0 0-48 24 24 0 1 0 0 48z"/></svg>
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
aria-hidden="true"
|
|
14
14
|
>
|
|
15
15
|
</crown-button>
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
</template>
|
|
18
18
|
|
|
19
19
|
<script>
|
|
20
20
|
import CrownButton from '@/components/crown/crownButtons/crownButton';
|
|
21
|
-
import copyIcon from '@/assets/
|
|
21
|
+
import copyIcon from '@/assets/clipboard.svg';
|
|
22
22
|
import validCopyElements from '@/components/crown/crownButtons/validCopyElements';
|
|
23
23
|
|
|
24
24
|
export default {
|
|
@@ -33,7 +33,7 @@ export default {
|
|
|
33
33
|
},
|
|
34
34
|
methods: {
|
|
35
35
|
copyElement() {
|
|
36
|
-
this.$emit('copy-element'
|
|
36
|
+
this.$emit('copy-element');
|
|
37
37
|
},
|
|
38
38
|
},
|
|
39
39
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<crown-button
|
|
3
|
+
v-if="node.isBpmnType(...validCopyElements)"
|
|
4
|
+
:title="$t('Duplicate Element')"
|
|
5
|
+
v-b-tooltip.hover.viewport.d50="{ customClass: 'no-pointer-events' }"
|
|
6
|
+
aria-label="Duplicate Element"
|
|
7
|
+
data-test="duplicate-button"
|
|
8
|
+
role="menuitem"
|
|
9
|
+
@click="duplicateElement"
|
|
10
|
+
>
|
|
11
|
+
<img
|
|
12
|
+
:src="duplicateIcon"
|
|
13
|
+
aria-hidden="true"
|
|
14
|
+
>
|
|
15
|
+
</crown-button>
|
|
16
|
+
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
import CrownButton from '@/components/crown/crownButtons/crownButton';
|
|
21
|
+
import duplicateIcon from '@/assets/copy-regular.svg';
|
|
22
|
+
import validCopyElements from '@/components/crown/crownButtons/validCopyElements';
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
components: { CrownButton },
|
|
26
|
+
props: ['node'],
|
|
27
|
+
data() {
|
|
28
|
+
return {
|
|
29
|
+
copyCount: 0,
|
|
30
|
+
duplicateIcon,
|
|
31
|
+
validCopyElements,
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
methods: {
|
|
35
|
+
duplicateElement() {
|
|
36
|
+
this.$emit('duplicate-element', this.node, ++this.copyCount);
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
</script>
|
|
@@ -50,6 +50,11 @@
|
|
|
50
50
|
v-on="$listeners"
|
|
51
51
|
/>
|
|
52
52
|
|
|
53
|
+
<duplicate-button
|
|
54
|
+
:node="node"
|
|
55
|
+
v-on="$listeners"
|
|
56
|
+
/>
|
|
57
|
+
|
|
53
58
|
<delete-button
|
|
54
59
|
:graph="graph"
|
|
55
60
|
:shape="shape"
|
|
@@ -79,6 +84,7 @@ import GenericFlowButton from '@/components/crown/crownButtons/genericFlowButton
|
|
|
79
84
|
import AssociationFlowButton from '@/components/crown/crownButtons/associationFlowButton';
|
|
80
85
|
import DataAssociationFlowButton from '@/components/crown/crownButtons/dataAssociationFlowButton';
|
|
81
86
|
import CopyButton from '@/components/crown/crownButtons/copyButton.vue';
|
|
87
|
+
import DuplicateButton from '@/components/crown/crownButtons/duplicateButton.vue';
|
|
82
88
|
import CrownDropdowns from '@/components/crown/crownButtons/crownDropdowns';
|
|
83
89
|
import DefaultFlow from '@/components/crown/crownButtons/defaultFlowButton.vue';
|
|
84
90
|
import poolLaneCrownConfig from '@/mixins/poolLaneCrownConfig';
|
|
@@ -95,6 +101,7 @@ export default {
|
|
|
95
101
|
GenericFlowButton,
|
|
96
102
|
AssociationFlowButton,
|
|
97
103
|
CopyButton,
|
|
104
|
+
DuplicateButton,
|
|
98
105
|
DefaultFlow,
|
|
99
106
|
DataAssociationFlowButton,
|
|
100
107
|
},
|
|
@@ -42,11 +42,18 @@ export default {
|
|
|
42
42
|
nodeToReplace: null,
|
|
43
43
|
buttons: [
|
|
44
44
|
{
|
|
45
|
-
label: 'Copy
|
|
46
|
-
icon: '
|
|
45
|
+
label: 'Copy Seletion',
|
|
46
|
+
icon: 'clipboard',
|
|
47
47
|
testId: 'copy-button',
|
|
48
48
|
role: 'menuitem',
|
|
49
|
-
action: this.
|
|
49
|
+
action: this.copySelection,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: 'Duplicate Selection',
|
|
53
|
+
icon: 'copy',
|
|
54
|
+
testId: 'duplicate-button',
|
|
55
|
+
role: 'menuitem',
|
|
56
|
+
action: this.duplicateSelection,
|
|
50
57
|
},
|
|
51
58
|
{
|
|
52
59
|
label: 'Delete Element',
|
|
@@ -70,9 +77,11 @@ export default {
|
|
|
70
77
|
highlightedShapes: () => store.getters.highlightedShapes,
|
|
71
78
|
},
|
|
72
79
|
methods: {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
copySelection() {
|
|
81
|
+
this.$emit('copy-selection');
|
|
82
|
+
},
|
|
83
|
+
duplicateSelection() {
|
|
84
|
+
this.$emit('duplicate-selection');
|
|
76
85
|
},
|
|
77
86
|
deleteElement() {
|
|
78
87
|
this.$emit('remove-nodes');
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
methods: {
|
|
3
|
+
copyPasteHandler(event, options) {
|
|
4
|
+
const isCopy = event.key === 'c';
|
|
5
|
+
const isPaste = event.key === 'v';
|
|
6
|
+
|
|
7
|
+
if (isCopy && options.mod) {
|
|
8
|
+
this.copy(event);
|
|
9
|
+
}
|
|
10
|
+
if (isPaste && options.mod) {
|
|
11
|
+
this.paste(event);
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
copy(event) {
|
|
15
|
+
event.preventDefault();
|
|
16
|
+
window.ProcessMaker.$modeler.copyElement();
|
|
17
|
+
},
|
|
18
|
+
paste(event) {
|
|
19
|
+
event.preventDefault();
|
|
20
|
+
window.ProcessMaker.$modeler.pasteElements();
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import ZoomInOut from './zoomInOut';
|
|
2
|
+
import CopyPaste from './copyPaste.js';
|
|
2
3
|
import store from '@/store';
|
|
3
4
|
import moveShapeByKeypress from './moveWithArrowKeys';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
|
-
mixins: [ZoomInOut],
|
|
7
|
+
mixins: [ZoomInOut, CopyPaste],
|
|
7
8
|
mounted() {
|
|
8
9
|
document.addEventListener('keydown', this.keydownListener);
|
|
9
10
|
document.addEventListener('keyup', this.keyupListener);
|
|
@@ -12,6 +13,7 @@ export default {
|
|
|
12
13
|
handleHotkeys(event, options) {
|
|
13
14
|
// Pass event to all handlers
|
|
14
15
|
this.zoomInOutHandler(event, options);
|
|
16
|
+
this.copyPasteHandler(event, options);
|
|
15
17
|
},
|
|
16
18
|
keyupListener(event) {
|
|
17
19
|
if (event.code === 'Space') {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
@toggle-panels-compressed="panelsCompressed = !panelsCompressed"
|
|
12
12
|
@toggle-mini-map-open="miniMapOpen = $event"
|
|
13
13
|
@saveBpmn="saveBpmn"
|
|
14
|
+
@close="close"
|
|
14
15
|
@save-state="pushToUndoStack"
|
|
15
16
|
@clearSelection="clearSelection"
|
|
16
17
|
/>
|
|
@@ -102,6 +103,10 @@
|
|
|
102
103
|
@replace-node="replaceNode"
|
|
103
104
|
@replace-generic-flow="replaceGenericFlow"
|
|
104
105
|
@copy-element="copyElement"
|
|
106
|
+
@copy-selection="copyElement"
|
|
107
|
+
@paste-element="pasteElements"
|
|
108
|
+
@duplicate-element="duplicateElement"
|
|
109
|
+
@duplicate-selection="duplicateSelection"
|
|
105
110
|
@default-flow="toggleDefaultFlow"
|
|
106
111
|
@shape-resize="shapeResize"
|
|
107
112
|
/>
|
|
@@ -111,6 +116,7 @@
|
|
|
111
116
|
:graph="graph"
|
|
112
117
|
:paperManager="paperManager"
|
|
113
118
|
:useModelGeometry="false"
|
|
119
|
+
@duplicate-selection="duplicateSelection"
|
|
114
120
|
@remove-nodes="removeNodes"
|
|
115
121
|
:processNode="processNode"
|
|
116
122
|
@save-state="pushToUndoStack"
|
|
@@ -187,6 +193,7 @@ export default {
|
|
|
187
193
|
mixins: [hotkeys],
|
|
188
194
|
data() {
|
|
189
195
|
return {
|
|
196
|
+
internalClipboard: [],
|
|
190
197
|
tooltipTarget: null,
|
|
191
198
|
|
|
192
199
|
/* Custom parsers for handling certain bpmn node types */
|
|
@@ -284,6 +291,7 @@ export default {
|
|
|
284
291
|
currentXML() {
|
|
285
292
|
return undoRedoStore.getters.currentState;
|
|
286
293
|
},
|
|
294
|
+
copiedElements: () => store.getters.copiedElements,
|
|
287
295
|
/* connectors expect a highlightedNode property */
|
|
288
296
|
highlightedNode: () => store.getters.highlightedNodes[0],
|
|
289
297
|
highlightedNodes: () => store.getters.highlightedNodes,
|
|
@@ -307,13 +315,115 @@ export default {
|
|
|
307
315
|
}
|
|
308
316
|
source.set('default', flow);
|
|
309
317
|
},
|
|
310
|
-
|
|
318
|
+
duplicateElement(node, copyCount) {
|
|
311
319
|
const clonedNode = node.clone(this.nodeRegistry, this.moddle, this.$t);
|
|
312
320
|
const yOffset = (node.diagram.bounds.height + 30) * copyCount;
|
|
313
321
|
|
|
314
322
|
clonedNode.diagram.bounds.y += yOffset;
|
|
315
323
|
this.addNode(clonedNode);
|
|
316
324
|
},
|
|
325
|
+
copyElement() {
|
|
326
|
+
// Checking if User selected a single flow and tries to copy it, to deny it.
|
|
327
|
+
const flows = [
|
|
328
|
+
sequenceFlowId,
|
|
329
|
+
dataOutputAssociationFlowId,
|
|
330
|
+
dataInputAssociationFlowId,
|
|
331
|
+
genericFlowId,
|
|
332
|
+
];
|
|
333
|
+
if (this.highlightedNodes.length === 1 && flows.includes(this.highlightedNodes[0].type)) return;
|
|
334
|
+
store.commit('setCopiedElements', this.cloneSelection());
|
|
335
|
+
this.$bvToast.toast(this.$t('Object(s) have been copied'), { noCloseButton:true, variant: 'success', solid: true, toaster: 'b-toaster-top-center' });
|
|
336
|
+
},
|
|
337
|
+
async pasteElements() {
|
|
338
|
+
if (this.copiedElements) {
|
|
339
|
+
await this.addClonedNodes(this.copiedElements);
|
|
340
|
+
this.$refs.selector.selectElements(this.findViewElementsFromNodes(this.copiedElements));
|
|
341
|
+
store.commit('setCopiedElements', this.cloneSelection());
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
cloneSelection() {
|
|
345
|
+
let clonedNodes = [], clonedFlows = [], originalFlows = [];
|
|
346
|
+
const nodes = this.highlightedNodes;
|
|
347
|
+
const selector = this.$refs.selector.$el;
|
|
348
|
+
const { height: sheight } = selector.getBoundingClientRect();
|
|
349
|
+
if (typeof selector.getBoundingClientRect === 'function') {
|
|
350
|
+
// get selector height
|
|
351
|
+
nodes.forEach(node => {
|
|
352
|
+
// Add flows described in the definitions property
|
|
353
|
+
if (node.definition.incoming || node.definition.outgoing) {
|
|
354
|
+
// Since both incoming and outgoing reference the same flow, any of them is copied
|
|
355
|
+
let flowsToCopy = [...(node.definition.incoming || node.definition.outgoing)];
|
|
356
|
+
// Check if flow is already in array before pushing
|
|
357
|
+
flowsToCopy.forEach(flow => {
|
|
358
|
+
if (!originalFlows.some(el => el.id === flow.id)) {
|
|
359
|
+
originalFlows.push(flow);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Check node type to clone
|
|
365
|
+
if ([
|
|
366
|
+
sequenceFlowId,
|
|
367
|
+
laneId,
|
|
368
|
+
associationId,
|
|
369
|
+
messageFlowId,
|
|
370
|
+
dataOutputAssociationFlowId,
|
|
371
|
+
dataInputAssociationFlowId,
|
|
372
|
+
genericFlowId,
|
|
373
|
+
].includes(node.type)) {
|
|
374
|
+
// Add offset for all waypoints on cloned flow
|
|
375
|
+
const clonedFlow = node.cloneFlow(this.nodeRegistry, this.moddle, this.$t);
|
|
376
|
+
clonedFlow.setIds(this.nodeIdGenerator);
|
|
377
|
+
clonedFlows.push(clonedFlow);
|
|
378
|
+
clonedNodes.push(clonedFlow);
|
|
379
|
+
} else {
|
|
380
|
+
// Clone node and calculate offset
|
|
381
|
+
const clonedNode = node.clone(this.nodeRegistry, this.moddle, this.$t);
|
|
382
|
+
const yOffset = sheight;
|
|
383
|
+
clonedNode.diagram.bounds.y += yOffset;
|
|
384
|
+
// Set cloned node id
|
|
385
|
+
clonedNode.setIds(this.nodeIdGenerator);
|
|
386
|
+
clonedNodes.push(clonedNode);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
// Connect flows
|
|
391
|
+
clonedFlows.forEach(flow => {
|
|
392
|
+
// Look up the original flow
|
|
393
|
+
const flowClonedFrom = { definition: originalFlows.find(el => el.id === flow.definition.cloneOf) };
|
|
394
|
+
// Get the id's of the sourceRef and targetRef of original flow
|
|
395
|
+
const src = flowClonedFrom.definition.sourceRef;
|
|
396
|
+
const target = flowClonedFrom.definition.targetRef;
|
|
397
|
+
const srcClone = clonedNodes.find(node => node.definition.cloneOf === src.id);
|
|
398
|
+
const targetClone = clonedNodes.find(node => node.definition.cloneOf === target.id);
|
|
399
|
+
// Reference the elements to the flow that connects them
|
|
400
|
+
flow.definition.sourceRef = srcClone.definition;
|
|
401
|
+
flow.definition.targetRef = targetClone.definition;
|
|
402
|
+
// Reference the flow to the elements that are connected by it
|
|
403
|
+
srcClone.definition.outgoing ? srcClone.definition.outgoing.push(flow.definition) : srcClone.definition.outgoing = [flow.definition];
|
|
404
|
+
targetClone.definition.incoming ? targetClone.definition.incoming.push(flow.definition) : targetClone.definition.incoming = [flow.definition];
|
|
405
|
+
// Translate flow waypoints to where they should be
|
|
406
|
+
flow.diagram.waypoint.forEach(point => {
|
|
407
|
+
point.y += sheight;
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
return clonedNodes;
|
|
411
|
+
},
|
|
412
|
+
async duplicateSelection() {
|
|
413
|
+
const clonedNodes = this.cloneSelection();
|
|
414
|
+
await this.addClonedNodes(clonedNodes);
|
|
415
|
+
this.$refs.selector.selectElements(this.findViewElementsFromNodes(clonedNodes));
|
|
416
|
+
},
|
|
417
|
+
findViewElementsFromNodes(nodes) {
|
|
418
|
+
return nodes.map(node => {
|
|
419
|
+
const component = this.$refs.nodeComponent.find(cmp => cmp.node === node);
|
|
420
|
+
const shape = component.shape;
|
|
421
|
+
return this.paper.findViewByModel(shape);
|
|
422
|
+
});
|
|
423
|
+
},
|
|
424
|
+
async close() {
|
|
425
|
+
this.$emit('close');
|
|
426
|
+
},
|
|
317
427
|
async saveBpmn() {
|
|
318
428
|
const svg = document.querySelector('.mini-paper svg');
|
|
319
429
|
const css = 'text { font-family: sans-serif; }';
|
|
@@ -847,6 +957,22 @@ export default {
|
|
|
847
957
|
});
|
|
848
958
|
});
|
|
849
959
|
},
|
|
960
|
+
async addClonedNodes(nodes) {
|
|
961
|
+
nodes.forEach(node => {
|
|
962
|
+
if (!node.pool) {
|
|
963
|
+
node.pool = this.poolTarget;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
const targetProcess = node.getTargetProcess(this.processes, this.processNode);
|
|
967
|
+
addNodeToProcess(node, targetProcess);
|
|
968
|
+
|
|
969
|
+
this.planeElements.push(node.diagram);
|
|
970
|
+
store.commit('addNode', node);
|
|
971
|
+
this.poolTarget = null;
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
await this.pushToUndoStack();
|
|
975
|
+
},
|
|
850
976
|
async removeNode(node, { removeRelationships = true } = {}) {
|
|
851
977
|
if (removeRelationships) {
|
|
852
978
|
removeNodeFlows(node, this);
|
|
@@ -975,6 +1101,18 @@ export default {
|
|
|
975
1101
|
this.previouslyStackedShape = shape;
|
|
976
1102
|
this.paperManager.performAtomicAction(() => ensureShapeIsNotCovered(shape, this.graph));
|
|
977
1103
|
},
|
|
1104
|
+
showSavedNotification() {
|
|
1105
|
+
undoRedoStore.dispatch('saved');
|
|
1106
|
+
},
|
|
1107
|
+
enableVersions() {
|
|
1108
|
+
undoRedoStore.dispatch('enableVersions');
|
|
1109
|
+
},
|
|
1110
|
+
setVersionIndicator(isDraft) {
|
|
1111
|
+
undoRedoStore.dispatch('setVersionIndicator', isDraft);
|
|
1112
|
+
},
|
|
1113
|
+
setLoadingState(isLoading) {
|
|
1114
|
+
undoRedoStore.dispatch('setLoadingState', isLoading);
|
|
1115
|
+
},
|
|
978
1116
|
clearSelection(){
|
|
979
1117
|
this.$refs.selector.clearSelection();
|
|
980
1118
|
},
|
|
@@ -1137,7 +1275,13 @@ export default {
|
|
|
1137
1275
|
}, this);
|
|
1138
1276
|
|
|
1139
1277
|
this.$el.addEventListener('mousemove', event => {
|
|
1278
|
+
const { clientX, clientY } = event;
|
|
1140
1279
|
this.pointerMoveHandler(event);
|
|
1280
|
+
store.commit('setClientMousePosition', { clientX, clientY });
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
this.$el.addEventListener('mouseleave', () => {
|
|
1284
|
+
store.commit('clientLeftPaper');
|
|
1141
1285
|
});
|
|
1142
1286
|
|
|
1143
1287
|
this.paperManager.addEventHandler('cell:pointerclick', (cellView, evt, x, y) => {
|
|
@@ -29,6 +29,13 @@ import { id as poolId } from '@/components/nodes/pool/config';
|
|
|
29
29
|
import { id as laneId } from '@/components/nodes/poolLane/config';
|
|
30
30
|
import { id as genericFlowId } from '@/components/nodes/genericFlow/config';
|
|
31
31
|
import { labelWidth, poolPadding } from '../nodes/pool/poolSizes';
|
|
32
|
+
const boundaryElements = [
|
|
33
|
+
'processmaker-modeler-boundary-timer-event',
|
|
34
|
+
'processmaker-modeler-boundary-error-event',
|
|
35
|
+
'processmaker-modeler-boundary-signal-event',
|
|
36
|
+
'processmaker-modeler-boundary-conditional-event',
|
|
37
|
+
'processmaker-modeler-boundary-message-event',
|
|
38
|
+
];
|
|
32
39
|
export default {
|
|
33
40
|
name: 'Selection',
|
|
34
41
|
components: {
|
|
@@ -85,6 +92,17 @@ export default {
|
|
|
85
92
|
},
|
|
86
93
|
},
|
|
87
94
|
methods: {
|
|
95
|
+
async selectElements(elements) {
|
|
96
|
+
await this.$nextTick();
|
|
97
|
+
this.clearSelection();
|
|
98
|
+
this.selected = elements;
|
|
99
|
+
this.showLasso = true;
|
|
100
|
+
this.isSelected = true;
|
|
101
|
+
this.isSelecting = true;
|
|
102
|
+
this.start = null;
|
|
103
|
+
await this.$nextTick();
|
|
104
|
+
this.updateSelectionBox();
|
|
105
|
+
},
|
|
88
106
|
/**
|
|
89
107
|
* Select an element dinamically.
|
|
90
108
|
* Shift key will manage the condition to push to selection
|
|
@@ -321,19 +339,36 @@ export default {
|
|
|
321
339
|
* Filter the selected elements
|
|
322
340
|
*/
|
|
323
341
|
filterSelected() {
|
|
324
|
-
//
|
|
342
|
+
// Get the selected pools IDs
|
|
325
343
|
const selectedPoolsIds = this.selected
|
|
326
344
|
.filter(shape => shape.model.component)
|
|
327
345
|
.filter(shape => shape.model.component.node.type === 'processmaker-modeler-pool')
|
|
328
346
|
.map(shape => shape.model.component.node.id);
|
|
347
|
+
// remove from selection the selected children that belongs to a selected pool
|
|
329
348
|
this.selected = this.selected.filter(shape => {
|
|
330
349
|
if (shape.model.component && shape.model.component.node.pool) {
|
|
331
350
|
return shape.model.component.node.pool && !selectedPoolsIds.includes(shape.model.component.node.pool.component.node.id);
|
|
332
351
|
}
|
|
333
352
|
return true;
|
|
334
|
-
}).filter(shape => {
|
|
335
|
-
return !(shape.model.getParentCell() && shape.model.getParentCell().get('parent'));
|
|
336
353
|
});
|
|
354
|
+
// A boundary event could only be selected alone
|
|
355
|
+
const firstSelectedBoundary = this.selected.find(shape => {
|
|
356
|
+
return shape.model.component &&
|
|
357
|
+
boundaryElements.includes(shape.model.component.node.type);
|
|
358
|
+
});
|
|
359
|
+
const firstSelectedElement = this.selected[0];
|
|
360
|
+
if (firstSelectedBoundary) {
|
|
361
|
+
this.selected = this.selected.filter(shape => {
|
|
362
|
+
if (firstSelectedElement === firstSelectedBoundary) {
|
|
363
|
+
// boundary event selected alone
|
|
364
|
+
return shape.model.component &&
|
|
365
|
+
shape === firstSelectedBoundary;
|
|
366
|
+
}
|
|
367
|
+
// do not allow to select a boundary event with another element
|
|
368
|
+
return shape.model.component &&
|
|
369
|
+
!boundaryElements.includes(shape.model.component.node.type);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
337
372
|
},
|
|
338
373
|
/**
|
|
339
374
|
* Pan paper handler
|
|
@@ -377,7 +412,7 @@ export default {
|
|
|
377
412
|
return shapes && selected.length === shapes.length;
|
|
378
413
|
},
|
|
379
414
|
/**
|
|
380
|
-
* Start the drag procedure for the
|
|
415
|
+
* Start the drag procedure for the select box
|
|
381
416
|
* @param {Object} event
|
|
382
417
|
*/
|
|
383
418
|
startDrag(event) {
|
|
@@ -11,6 +11,7 @@ import cloneDeep from 'lodash/cloneDeep';
|
|
|
11
11
|
export default class Node {
|
|
12
12
|
static diagramPropertiesToCopy = ['x', 'y', 'width', 'height'];
|
|
13
13
|
static definitionPropertiesToNotCopy = ['$type', 'id'];
|
|
14
|
+
static flowDefinitionPropertiesToNotCopy = ['$type', 'id', 'sourceRef', 'targetRef'];
|
|
14
15
|
static eventDefinitionPropertiesToNotCopy = ['errorRef', 'messageRef'];
|
|
15
16
|
|
|
16
17
|
type;
|
|
@@ -89,6 +90,8 @@ export default class Node {
|
|
|
89
90
|
|
|
90
91
|
clonedNode.id = null;
|
|
91
92
|
clonedNode.pool = this.pool;
|
|
93
|
+
clonedNode.definition.cloneOf = this.id;
|
|
94
|
+
|
|
92
95
|
Node.diagramPropertiesToCopy.forEach(prop => clonedNode.diagram.bounds[prop] = this.diagram.bounds[prop]);
|
|
93
96
|
Object.keys(this.definition).filter(key => !Node.definitionPropertiesToNotCopy.includes(key)).forEach(key => {
|
|
94
97
|
const definition = this.definition.get(key);
|
|
@@ -112,6 +115,42 @@ export default class Node {
|
|
|
112
115
|
return clonedNode;
|
|
113
116
|
}
|
|
114
117
|
|
|
118
|
+
cloneFlow(nodeRegistry, moddle, $t) {
|
|
119
|
+
const definition = nodeRegistry[this.type].definition(moddle, $t);
|
|
120
|
+
const diagram = nodeRegistry[this.type].diagram(moddle);
|
|
121
|
+
const clonedFlow = new this.constructor(this.type, definition, diagram);
|
|
122
|
+
|
|
123
|
+
clonedFlow.id = null;
|
|
124
|
+
clonedFlow.pool = this.pool;
|
|
125
|
+
clonedFlow.definition.cloneOf = this.id;
|
|
126
|
+
clonedFlow.diagram.waypoint = [];
|
|
127
|
+
|
|
128
|
+
this.diagram.waypoint.forEach(point => clonedFlow.diagram.waypoint.push(point));
|
|
129
|
+
|
|
130
|
+
Object.keys(this.definition).filter(key => !Node.flowDefinitionPropertiesToNotCopy.includes(key)).forEach(key => {
|
|
131
|
+
const definition = this.definition.get(key);
|
|
132
|
+
const clonedDefinition = typeof definition === 'object' ? cloneDeep(definition) : definition;
|
|
133
|
+
if (key === 'eventDefinitions') {
|
|
134
|
+
for (var i in clonedDefinition) {
|
|
135
|
+
if (definition[i].signalRef && !clonedDefinition[i].signalRef) {
|
|
136
|
+
clonedDefinition[i].signalRef = { ...definition[i].signalRef };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
clonedFlow.definition.set(key, clonedDefinition);
|
|
141
|
+
clonedFlow.definition.sourceRef = clonedFlow.definition.targetRef = null;
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
Node.eventDefinitionPropertiesToNotCopy.forEach(
|
|
145
|
+
prop => clonedFlow.definition.eventDefinitions &&
|
|
146
|
+
clonedFlow.definition.eventDefinitions[0] &&
|
|
147
|
+
clonedFlow.definition.eventDefinitions[0].hasOwnProperty(prop) &&
|
|
148
|
+
clonedFlow.definition.eventDefinitions[0].set(prop, null)
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return clonedFlow;
|
|
152
|
+
}
|
|
153
|
+
|
|
115
154
|
getTargetProcess(processes, processNode) {
|
|
116
155
|
return this.pool
|
|
117
156
|
? processes.find(({ id }) => id === this.pool.component.node.definition.get('processRef').id)
|