@processmaker/modeler 1.43.12 → 1.43.13
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/cypress.config.js +1 -0
- package/dist/img/pan-icon.4a4b74b7.svg +3 -0
- package/dist/modeler.common.js +2667 -1922
- package/dist/modeler.common.js.map +1 -1
- package/dist/modeler.umd.js +2671 -1926
- package/dist/modeler.umd.js.map +1 -1
- package/dist/modeler.umd.min.js +4 -4
- package/dist/modeler.umd.min.js.map +1 -1
- package/package.json +2 -2
- package/src/ModelerApp.vue +5 -1
- package/src/assets/railBottom/pan-icon.svg +3 -0
- package/src/components/crown/crownConfig/crownConfig.vue +1 -6
- package/src/components/hotkeys/main.js +41 -16
- package/src/components/hotkeys/undoRedo.js +24 -0
- package/src/components/modeler/Modeler.vue +216 -186
- package/src/components/modeler/modeler.scss +17 -5
- package/src/components/railBottom/PanControl.vue +38 -0
- package/src/components/railBottom/RailBottom.vue +8 -0
- package/src/components/railBottom/{miniPaperControl/miniPaperControl.scss → bottomLeftControl.scss} +5 -1
- package/src/components/railBottom/controls/Controls.vue +18 -6
- package/src/components/railBottom/controls/SubmenuPopper/SubmenuPopper.vue +2 -7
- package/src/components/railBottom/miniPaperControl/MiniPaperControl.vue +1 -1
- package/src/components/railBottom/undoRedoControl/UndoRedoControl.vue +4 -0
- package/src/components/rails/explorer-rail/nodeTypesLoop/nodeTypesLoop.vue +10 -3
- package/src/components/rails/explorer-rail/pmBlocksLoop/pmBlocksLoop.vue +6 -3
- package/src/components/topRail/TopRail.vue +5 -0
- package/src/mixins/clickAndDrop.js +20 -0
- package/src/mixins/linkEditing.js +393 -0
- package/src/mixins/transparentDragging.js +45 -0
- package/src/setup/initialLoad.js +2 -1
- package/src/undoRedoStore.js +11 -0
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
:class="['control-item', {'active': selectedItem && (selectedItem.type === item.type)}]"
|
|
9
9
|
:id="item.id"
|
|
10
10
|
:key="item.id"
|
|
11
|
-
@
|
|
11
|
+
@mousedown.stop="onClickControlHandler($event, item, 'down')"
|
|
12
|
+
@mouseup.stop="onClickControlHandler($event, item, 'up')"
|
|
12
13
|
:data-test="`${item.type}-main`"
|
|
13
14
|
>
|
|
14
15
|
<SubmenuPopper
|
|
15
16
|
:data="item"
|
|
16
|
-
@
|
|
17
|
+
@mouseDownSubmenu="($event, data) => clickToSubmenuHandler($event, data, 'down')"
|
|
18
|
+
@mouseUpSubmenu="($event, data) => clickToSubmenuHandler($event, data, 'up')"
|
|
17
19
|
:selectedItem="selectedSubmenuItem"
|
|
18
20
|
:popperType="popperType"
|
|
19
21
|
/>
|
|
@@ -65,22 +67,32 @@ export default ({
|
|
|
65
67
|
},
|
|
66
68
|
},
|
|
67
69
|
methods: {
|
|
68
|
-
clickToSubmenuHandler(data){
|
|
70
|
+
clickToSubmenuHandler(event, data, type){
|
|
71
|
+
if (type === 'up') {
|
|
72
|
+
this.cancelDragNewObject();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
69
76
|
window.ProcessMaker.EventBus.$off('custom-pointerclick');
|
|
70
77
|
this.wasClicked = false;
|
|
71
78
|
this.parent = this.selectedItem;
|
|
72
79
|
this.selectedSubmenuItem = data.control.type;
|
|
73
|
-
this.
|
|
80
|
+
this.startDragNewObject(event, data);
|
|
74
81
|
},
|
|
75
82
|
/**
|
|
76
83
|
* On click on the botton rail control
|
|
77
84
|
* @param {Object} event
|
|
78
85
|
* @param {Object} control
|
|
79
86
|
*/
|
|
80
|
-
onClickControlHandler(event, control) {
|
|
87
|
+
onClickControlHandler(event, control, type) {
|
|
88
|
+
if (type === 'up') {
|
|
89
|
+
this.cancelDragNewObject();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
81
93
|
this.selectedSubmenuItem = null;
|
|
82
94
|
this.popperType = this.currentType === control.type ? null : control.type;
|
|
83
|
-
this.
|
|
95
|
+
this.startDragNewObject(event, control);
|
|
84
96
|
this.currentType = this.popperType;
|
|
85
97
|
},
|
|
86
98
|
toggleExplorer() {
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
<li v-for="(item, key) in data.items"
|
|
16
16
|
:class="['control-submenu-list', {'active': selectedItem === item.type}]"
|
|
17
17
|
:key="key"
|
|
18
|
-
@
|
|
18
|
+
@mousedown.stop="$emit('mouseDownSubmenu', $event, item)"
|
|
19
|
+
@mouseup.stop="$emit('mouseUpSubmenu', $event, item)"
|
|
19
20
|
:data-test="item.type"
|
|
20
21
|
>
|
|
21
22
|
<i v-if="!containsSvg(item.icon)" :class="item.icon" class="fa-lg"/>
|
|
@@ -74,12 +75,6 @@ export default ({
|
|
|
74
75
|
wasClicked: false,
|
|
75
76
|
};
|
|
76
77
|
},
|
|
77
|
-
methods: {
|
|
78
|
-
onClickHandler(event, control) {
|
|
79
|
-
event.stopPropagation();
|
|
80
|
-
this.$emit('clickToSubmenu', { event, control });
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
78
|
});
|
|
84
79
|
|
|
85
80
|
</script>
|
|
@@ -43,6 +43,10 @@ export default ({
|
|
|
43
43
|
redoIcon: require('@/assets/railBottom/redo.svg'),
|
|
44
44
|
};
|
|
45
45
|
},
|
|
46
|
+
mounted() {
|
|
47
|
+
this.$root.$on('undo-keyboard-shortcut', this.undo);
|
|
48
|
+
this.$root.$on('redo-keyboard-shortcut', this.redo);
|
|
49
|
+
},
|
|
46
50
|
watch: {
|
|
47
51
|
canUndo(canUndo) {
|
|
48
52
|
if (!canUndo) {
|
|
@@ -70,7 +70,8 @@ export default {
|
|
|
70
70
|
:key="object.id"
|
|
71
71
|
@mouseover="showPin = true"
|
|
72
72
|
@mouseleave="showPin = false"
|
|
73
|
-
@
|
|
73
|
+
@mousedown.stop="startDragNewObject($event, object)"
|
|
74
|
+
@mouseup.stop="cancelDragNewObject()"
|
|
74
75
|
>
|
|
75
76
|
<i v-if="!containsSvg(object.icon)" :class="object.icon" class="fa-lg"/>
|
|
76
77
|
<img v-else class="node-types__item__icon" :src="object.icon" :alt="$t(object.label)">
|
|
@@ -81,6 +82,7 @@ export default {
|
|
|
81
82
|
class="pinIcon"
|
|
82
83
|
alt="Unpin Element"
|
|
83
84
|
@click="unPin(object)"
|
|
85
|
+
@mousedown.stop="cancelDragNewObject()"
|
|
84
86
|
>
|
|
85
87
|
<img
|
|
86
88
|
v-else
|
|
@@ -88,6 +90,7 @@ export default {
|
|
|
88
90
|
class="pinIcon"
|
|
89
91
|
alt="Pin Element"
|
|
90
92
|
@click="addPin(object)"
|
|
93
|
+
@mousedown.stop="cancelDragNewObject()"
|
|
91
94
|
>
|
|
92
95
|
</div>
|
|
93
96
|
</template>
|
|
@@ -103,7 +106,8 @@ export default {
|
|
|
103
106
|
:key="pinnedObject.id"
|
|
104
107
|
@mouseover="showPin = true"
|
|
105
108
|
@mouseleave="showPin = false"
|
|
106
|
-
@
|
|
109
|
+
@mousedown.stop="startDragNewObject($event, pinnedObject)"
|
|
110
|
+
@mouseup.stop="cancelDragNewObject()"
|
|
107
111
|
>
|
|
108
112
|
<i v-if="!containsSvg(pinnedObject.icon)" :class="pinnedObject.icon" class="fa-lg"/>
|
|
109
113
|
<img v-else class="node-types__item__icon" :src="pinnedObject.icon" :alt="$t(pinnedObject.label)">
|
|
@@ -113,6 +117,7 @@ export default {
|
|
|
113
117
|
class="pinIcon"
|
|
114
118
|
alt="Pin/Unpin Element"
|
|
115
119
|
@click="unPin(pinnedObject)"
|
|
120
|
+
@mousedown.stop="cancelDragNewObject()"
|
|
116
121
|
>
|
|
117
122
|
</div>
|
|
118
123
|
</template>
|
|
@@ -127,7 +132,8 @@ export default {
|
|
|
127
132
|
:key="nodeType.id"
|
|
128
133
|
@mouseover="showPin = true"
|
|
129
134
|
@mouseleave="showPin = false"
|
|
130
|
-
@
|
|
135
|
+
@mousedown.stop="startDragNewObject($event, nodeType)"
|
|
136
|
+
@mouseup.stop="cancelDragNewObject()"
|
|
131
137
|
>
|
|
132
138
|
<i v-if="!containsSvg(nodeType.icon)" :class="nodeType.icon" class="fa-lg"/>
|
|
133
139
|
<img v-else class="node-types__item__icon" :src="nodeType.icon" :alt="$t(nodeType.label)">
|
|
@@ -137,6 +143,7 @@ export default {
|
|
|
137
143
|
class="pinIcon"
|
|
138
144
|
alt="Pin/Unpin Element"
|
|
139
145
|
@click="addPin(nodeType)"
|
|
146
|
+
@mousedown.stop="cancelDragNewObject()"
|
|
140
147
|
>
|
|
141
148
|
</div>
|
|
142
149
|
</template>
|
|
@@ -69,7 +69,8 @@ export default {
|
|
|
69
69
|
:key="object.id"
|
|
70
70
|
@mouseover="showPin = true"
|
|
71
71
|
@mouseleave="showPin = false"
|
|
72
|
-
@
|
|
72
|
+
@mousedown.stop="startDragNewObject($event, object)"
|
|
73
|
+
@mouseup.stop="cancelDragNewObject()"
|
|
73
74
|
>
|
|
74
75
|
<div class="d-flex">
|
|
75
76
|
<i v-if="!object.svgIcon" class="node-types__item__icon" :class="object.customIcon"/>
|
|
@@ -103,7 +104,8 @@ export default {
|
|
|
103
104
|
:key="pinnedBlock.id"
|
|
104
105
|
@mouseover="showPin = true"
|
|
105
106
|
@mouseleave="showPin = false"
|
|
106
|
-
@
|
|
107
|
+
@mousedown.stop="startDragNewObject($event, pinnedBlock)"
|
|
108
|
+
@mouseup.stop="cancelDragNewObject()"
|
|
107
109
|
>
|
|
108
110
|
<i v-if="!containsSvg(pinnedBlock.icon)" :class="pinnedBlock.customIcon" class="fa-lg"/>
|
|
109
111
|
<img v-else class="node-types__item__icon" :src="pinnedBlock.svgIcon" :alt="$t(pinnedBlock.label)">
|
|
@@ -126,7 +128,8 @@ export default {
|
|
|
126
128
|
:key="nodeType.id"
|
|
127
129
|
@mouseover="showPin = true"
|
|
128
130
|
@mouseleave="showPin = false"
|
|
129
|
-
@
|
|
131
|
+
@mousedown.stop="startDragNewObject($event, nodeType)"
|
|
132
|
+
@mouseup.stop="cancelDragNewObject()"
|
|
130
133
|
>
|
|
131
134
|
<i v-if="!containsSvg(nodeType.icon)" :class="nodeType.customIcon" class="fa-lg"/>
|
|
132
135
|
<img v-else class="node-types__item__icon" :src="nodeType.svgIcon" :alt="$t(nodeType.label)">
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
/>
|
|
9
9
|
|
|
10
10
|
<AiGenerateButton
|
|
11
|
+
v-if="isPackageAiInstalled"
|
|
11
12
|
v-on="$listeners"
|
|
12
13
|
/>
|
|
13
14
|
|
|
@@ -27,6 +28,7 @@ import store from '@/store';
|
|
|
27
28
|
import { ValidateButton, ValidateIssue, ValidatePanel } from '@/components/topRail/validateControl';
|
|
28
29
|
import MultiplayerViewUsers from '@/components/topRail/multiplayerViewUsers/MultiplayerViewUsers';
|
|
29
30
|
import AiGenerateButton from '../aiMessages/AiGenerateButton.vue';
|
|
31
|
+
|
|
30
32
|
export default {
|
|
31
33
|
components: {
|
|
32
34
|
ValidateButton,
|
|
@@ -71,6 +73,9 @@ export default {
|
|
|
71
73
|
// Get the number of errors
|
|
72
74
|
return this.errorList.length + this.warnings.length;
|
|
73
75
|
},
|
|
76
|
+
isPackageAiInstalled() {
|
|
77
|
+
return window.ProcessMaker?.modeler?.isPackageAiInstalled;
|
|
78
|
+
},
|
|
74
79
|
},
|
|
75
80
|
watch: {
|
|
76
81
|
numberOfErrors(newValue) {
|
|
@@ -38,6 +38,7 @@ export default {
|
|
|
38
38
|
this.popperType = control.type;
|
|
39
39
|
}
|
|
40
40
|
window.ProcessMaker.EventBus.$on('custom-pointerclick', message => {
|
|
41
|
+
window.ProcessMaker.EventBus.$emit('capture-hovered-link', message);
|
|
41
42
|
window.ProcessMaker.EventBus.$off('custom-pointerclick');
|
|
42
43
|
document.removeEventListener('mousemove', this.setDraggingPosition);
|
|
43
44
|
if (this.movedElement) {
|
|
@@ -109,6 +110,25 @@ export default {
|
|
|
109
110
|
nodeTypesStore.commit('clearSelectedNode');
|
|
110
111
|
nodeTypesStore.commit('setGhostNode', null);
|
|
111
112
|
},
|
|
113
|
+
/**
|
|
114
|
+
* The user mouse-down'd inside the panel so this *might* be a
|
|
115
|
+
* click-and-drag event. Set mouseDownDrag to true and fire
|
|
116
|
+
* the onClickHandler (previously, this is what the click event did).
|
|
117
|
+
*/
|
|
118
|
+
startDragNewObject(e, control) {
|
|
119
|
+
window.ProcessMaker.mouseDownDrag = true;
|
|
120
|
+
this.onClickHandler(e, control);
|
|
121
|
+
},
|
|
122
|
+
/**
|
|
123
|
+
* The user mouse-up'd inside the panel so this is a
|
|
124
|
+
* click-move-click event, not a click-and-drag event.
|
|
125
|
+
*
|
|
126
|
+
* Also used by the Pin buttons so we don't trigger a new element
|
|
127
|
+
* when they are clicked/dragged.
|
|
128
|
+
*/
|
|
129
|
+
cancelDragNewObject() {
|
|
130
|
+
window.ProcessMaker.mouseDownDrag = false;
|
|
131
|
+
},
|
|
112
132
|
},
|
|
113
133
|
computed: {
|
|
114
134
|
selectedItem() {
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import nodeTypesStore from '@/nodeTypesStore';
|
|
2
|
+
import { COLOR_DEFAULT } from '@/components/highlightColors.js';
|
|
3
|
+
import SequenceFlow from '@/components/nodes/genericFlow/SequenceFlow';
|
|
4
|
+
|
|
5
|
+
const ALLOWED_BPMN_TYPES = [
|
|
6
|
+
'bpmn:Task',
|
|
7
|
+
'bpmn:UserTask',
|
|
8
|
+
'bpmn:GlobalTask',
|
|
9
|
+
'bpmn:CallActivity',
|
|
10
|
+
'bpmn:ScriptTask',
|
|
11
|
+
'bpmn:ServiceTask',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const ALLOWED_ALTERNATE_TYPES = [
|
|
15
|
+
'processmaker-modeler-task',
|
|
16
|
+
'processmaker-modeler-manual-task',
|
|
17
|
+
'processmaker-modeler-script-task',
|
|
18
|
+
'processmaker-modeler-call-activity',
|
|
19
|
+
'processmaker-modeler-intermediate-catch-timer-event',
|
|
20
|
+
'processmaker-modeler-intermediate-signal-catch-event',
|
|
21
|
+
'processmaker-modeler-intermediate-signal-throw-event',
|
|
22
|
+
'processmaker-modeler-intermediate-message-catch-event',
|
|
23
|
+
'processmaker-modeler-intermediate-message-throw-event',
|
|
24
|
+
'processmaker-modeler-intermediate-conditional-catch-event',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
data() {
|
|
29
|
+
return {
|
|
30
|
+
linkModel: null,
|
|
31
|
+
hoveredLinkModel: null,
|
|
32
|
+
originalHoveredLink: null,
|
|
33
|
+
originalColor: null,
|
|
34
|
+
activeElement: null,
|
|
35
|
+
timeout: null,
|
|
36
|
+
tooltipEl: null,
|
|
37
|
+
clickPosition: null,
|
|
38
|
+
currentMovingModel: null,
|
|
39
|
+
currentMovingModelCanBisect: null,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
watch: {
|
|
43
|
+
hoveredLinkModel() {
|
|
44
|
+
if (this.hoveredLinkModel) {
|
|
45
|
+
this.originalColor = this.hoveredLinkModel.attr('line/stroke');
|
|
46
|
+
this.originalHoveredLink = this.hoveredLinkModel;
|
|
47
|
+
this.hoveredLinkModel.attr('line/stroke', COLOR_DEFAULT);
|
|
48
|
+
this.addElementTooltip();
|
|
49
|
+
} else {
|
|
50
|
+
this.resetLinkColor();
|
|
51
|
+
this.removeElementTooltip();
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
computed: {
|
|
56
|
+
ghostNode() {
|
|
57
|
+
return nodeTypesStore.getters.getGhostNode;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
methods: {
|
|
61
|
+
linkEditingInit() {
|
|
62
|
+
|
|
63
|
+
// Handle hovering a new element on the page
|
|
64
|
+
this.paperManager.addEventHandler('cell:mouseover', (view) => {
|
|
65
|
+
if (view?.model?.isLink() && this.addingEligibleItem()) {
|
|
66
|
+
this.timeout = setTimeout(() => {
|
|
67
|
+
this.hoveredLinkModel = view.model;
|
|
68
|
+
}, 1000);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
this.paperManager.addEventHandler('cell:mouseout', () => {
|
|
72
|
+
clearTimeout(this.timeout);
|
|
73
|
+
this.timeout = null;
|
|
74
|
+
if (this.hoveredLinkModel) {
|
|
75
|
+
this.hoveredLinkModel = null;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Handle hovering an existing element on the page
|
|
80
|
+
this.paperManager.addEventHandler('element:pointermove', (view, evt) => {
|
|
81
|
+
if (!this.canBisectCached(view.model)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// get any links under the element we're moving
|
|
86
|
+
const viewFromPoint = this.findViewFromPoint(view, evt);
|
|
87
|
+
const model = viewFromPoint?.model;
|
|
88
|
+
|
|
89
|
+
if (model?.isLink()) {
|
|
90
|
+
if (this.hoveredLinkModel !== model && !this.timeout) {
|
|
91
|
+
this.timeout = setTimeout(() => {
|
|
92
|
+
this.hoveredLinkModel = model;
|
|
93
|
+
this.linkModel = model;
|
|
94
|
+
this.activeElement = view.model;
|
|
95
|
+
}, 1000);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
clearTimeout(this.timeout);
|
|
99
|
+
this.timeout = null;
|
|
100
|
+
if (this.hoveredLinkModel) {
|
|
101
|
+
this.hoveredLinkModel = null;
|
|
102
|
+
this.linkModel = null;
|
|
103
|
+
this.activeElement = null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Handle dropping an existing element on the page
|
|
109
|
+
this.paperManager.addEventHandler('element:pointerup', (view, evt) => {
|
|
110
|
+
if (this.linkModel && this.canBisect(view.model)) {
|
|
111
|
+
this.clickPosition = { x: evt.clientX, y: evt.clientY };
|
|
112
|
+
this.paperManager.performAtomicAction(() => {
|
|
113
|
+
this.bisectElement(view.model, this.linkModel);
|
|
114
|
+
this.hoveredLinkModel = null;
|
|
115
|
+
this.linkModel = null;
|
|
116
|
+
this.activeElement = null;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Handle dropping a new element on the page
|
|
122
|
+
this.$on('node-added', (newNode) => {
|
|
123
|
+
this.bisectNode(newNode);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// We need to save the hovered link because the mouse could move
|
|
127
|
+
// before the node is created
|
|
128
|
+
window.ProcessMaker.EventBus.$on('capture-hovered-link', (evt) => {
|
|
129
|
+
this.clickPosition = { x: evt.clientX, y: evt.clientY };
|
|
130
|
+
this.linkModel = this.hoveredLinkModel;
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
findViewFromPoint(elementView, evt) {
|
|
135
|
+
const nodesFromPoint = Array.from(
|
|
136
|
+
document.elementsFromPoint(evt.clientX, evt.clientY),
|
|
137
|
+
);
|
|
138
|
+
while (nodesFromPoint.length > 0) {
|
|
139
|
+
const el = nodesFromPoint.shift();
|
|
140
|
+
const view = this.paper.findView(el);
|
|
141
|
+
if (view && view !== elementView) {
|
|
142
|
+
return view;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
isLink(model) {
|
|
149
|
+
return model.component && model.attributes.type === 'standard.Link';
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
canBisect(controlOrModel) {
|
|
153
|
+
const bpmnTypes = this.getBpmnTypes(controlOrModel);
|
|
154
|
+
const allowedByBpmnType = bpmnTypes.some(type => ALLOWED_BPMN_TYPES.includes(type));
|
|
155
|
+
|
|
156
|
+
if (allowedByBpmnType) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Sometimes the bpmn type is not set, so check for a type in the config
|
|
161
|
+
const alternateType = this.getAlternateType(controlOrModel);
|
|
162
|
+
return ALLOWED_ALTERNATE_TYPES.includes(alternateType);
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
canBisectCached(model) {
|
|
166
|
+
let canBisect = false;
|
|
167
|
+
if (this.currentMovingModel === model) {
|
|
168
|
+
canBisect = this.currentMovingModelCanBisect;
|
|
169
|
+
} else {
|
|
170
|
+
canBisect = this.canBisect(model);
|
|
171
|
+
this.currentMovingModel = model;
|
|
172
|
+
this.currentMovingModelCanBisect = canBisect;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return canBisect;
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
getBpmnTypes(item) {
|
|
179
|
+
let nodeDefinitionType = item.component?.node?.definition?.$type;
|
|
180
|
+
let controlTypes = item.bpmnType || [];
|
|
181
|
+
if (!Array.isArray(controlTypes)) {
|
|
182
|
+
controlTypes = [controlTypes];
|
|
183
|
+
}
|
|
184
|
+
if (nodeDefinitionType) {
|
|
185
|
+
return [nodeDefinitionType];
|
|
186
|
+
}
|
|
187
|
+
return controlTypes;
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
getAlternateType(item) {
|
|
191
|
+
if (item.type) {
|
|
192
|
+
return item.type;
|
|
193
|
+
}
|
|
194
|
+
return item.component?.node?.type;
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
bisectNode(node) {
|
|
198
|
+
if (!this.linkModel) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const nodeId = node.definition.id;
|
|
203
|
+
const element = this.getElementByNodeId(nodeId);
|
|
204
|
+
|
|
205
|
+
if (!this.canBisect(element)) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const size = element.size();
|
|
210
|
+
this.paperManager.performAtomicAction(() => {
|
|
211
|
+
element.translate(-Math.round(size.width / 2), -Math.round(size.height / 2));
|
|
212
|
+
this.bisectElement(element, this.linkModel);
|
|
213
|
+
this.$refs.selector.updateSelectionBox();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
this.hoveredLinkModel = null;
|
|
217
|
+
this.linkModel = null;
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
bisectElement(element, link) {
|
|
221
|
+
const originalTargetElement = link.getTargetCell();
|
|
222
|
+
|
|
223
|
+
// Update target of the existing link in the UI
|
|
224
|
+
link.component.setTarget(element);
|
|
225
|
+
|
|
226
|
+
const linkDefinition = link.component.node.definition;
|
|
227
|
+
const elementDefinition = element.component.node.definition;
|
|
228
|
+
const originalTargetDefinition = linkDefinition.get('targetRef');
|
|
229
|
+
const originalTargetIncomingNodes = originalTargetDefinition.get('incoming');
|
|
230
|
+
|
|
231
|
+
// Remove the existing link from the original target in the bpmn definition
|
|
232
|
+
originalTargetDefinition.set('incoming', originalTargetIncomingNodes.filter(link => link !== linkDefinition));
|
|
233
|
+
|
|
234
|
+
// Update the existing link in the bpmn definition to point to our new element
|
|
235
|
+
linkDefinition.set('targetRef', elementDefinition);
|
|
236
|
+
|
|
237
|
+
// Update our new element to have the existing link as a target
|
|
238
|
+
elementDefinition.get('incoming').push(linkDefinition);
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
// Handle splitting vertices
|
|
242
|
+
let vertices = link.vertices();
|
|
243
|
+
const linkView = this.paper.findViewByModel(link);
|
|
244
|
+
const localClick = this.paper.clientToLocalPoint(this.clickPosition);
|
|
245
|
+
let nearestVertex = linkView.getVertexIndex(localClick.x, localClick.y);
|
|
246
|
+
if (vertices.length > 0) {
|
|
247
|
+
nearestVertex--;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Add vertices after the drop point to the new link
|
|
251
|
+
const newVertices = [];
|
|
252
|
+
vertices.forEach((vertex, index) => {
|
|
253
|
+
if (index > nearestVertex) {
|
|
254
|
+
newVertices.push(vertex);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Remove new vertices from the existing link
|
|
259
|
+
let vertexToRemove = nearestVertex + 1;
|
|
260
|
+
while (vertices.length > vertexToRemove) {
|
|
261
|
+
link.removeVertex(vertexToRemove);
|
|
262
|
+
vertices = link.vertices();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Reset the end waypoint for the existing link to the center of the new element in the bpmn definition
|
|
266
|
+
const linkDiagram = link.component.node.diagram;
|
|
267
|
+
const waypoints = linkDiagram.get('waypoint');
|
|
268
|
+
|
|
269
|
+
// Remove the last waypoint
|
|
270
|
+
waypoints.pop();
|
|
271
|
+
|
|
272
|
+
// Create a new end waypoint for the existing link
|
|
273
|
+
const newEndWaypoint = this.moddle.create('dc:Point', this.getCenterPosition(element));
|
|
274
|
+
|
|
275
|
+
// Add it to the existing link
|
|
276
|
+
linkDiagram.set('waypoint', [
|
|
277
|
+
...waypoints,
|
|
278
|
+
newEndWaypoint,
|
|
279
|
+
]);
|
|
280
|
+
|
|
281
|
+
// User helper to add a new link from our new element to the existing links original original target.
|
|
282
|
+
// This takes care of both the UI and the BPMN definition
|
|
283
|
+
this.newOutgoingLink(element, originalTargetElement, newVertices);
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
getCenterPosition(element) {
|
|
287
|
+
const size = element.size();
|
|
288
|
+
const position = element.position();
|
|
289
|
+
return {
|
|
290
|
+
x: position.x + size.width / 2,
|
|
291
|
+
y: position.y + size.height / 2,
|
|
292
|
+
};
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
newOutgoingLink(source, target, newVertices) {
|
|
296
|
+
const waypointsFromVertices = newVertices.map(vertex => {
|
|
297
|
+
return {
|
|
298
|
+
x: vertex.x,
|
|
299
|
+
y: vertex.y,
|
|
300
|
+
};
|
|
301
|
+
});
|
|
302
|
+
const flow = new SequenceFlow(this.nodeRegistry, this.moddle, this.paper);
|
|
303
|
+
const waypoints = [
|
|
304
|
+
this.getCenterPosition(source),
|
|
305
|
+
...waypointsFromVertices,
|
|
306
|
+
this.getCenterPosition(target),
|
|
307
|
+
];
|
|
308
|
+
|
|
309
|
+
const newFlowNode = flow.makeFlowNode(source, target, waypoints);
|
|
310
|
+
this.addNode(newFlowNode);
|
|
311
|
+
},
|
|
312
|
+
|
|
313
|
+
resetLinkColor() {
|
|
314
|
+
if (this.originalHoveredLink) {
|
|
315
|
+
this.originalHoveredLink.attr('line/stroke', this.originalColor);
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
addingEligibleItem() {
|
|
320
|
+
const addingNewElement = nodeTypesStore.getters.getSelectedNode;
|
|
321
|
+
if (addingNewElement) {
|
|
322
|
+
if (this.canBisect(addingNewElement)) {
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return false;
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
addElementTooltip() {
|
|
330
|
+
const el = document.createElement('div');
|
|
331
|
+
el.innerHTML = this.$t('Drop to add to this flow');
|
|
332
|
+
el.classList.add('element-tooltip');
|
|
333
|
+
document.body.appendChild(el);
|
|
334
|
+
document.addEventListener('mousemove', this.setTooltipPosition);
|
|
335
|
+
|
|
336
|
+
el.style.zIndex = '9999';
|
|
337
|
+
|
|
338
|
+
this.tooltipEl = el;
|
|
339
|
+
this.setTooltipPosition();
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
setTooltipPosition() {
|
|
343
|
+
let left = 0;
|
|
344
|
+
let top = 0;
|
|
345
|
+
|
|
346
|
+
if (this.activeElement) { // Moving an existing element
|
|
347
|
+
|
|
348
|
+
const elementPosition = this.activeElement.position();
|
|
349
|
+
const elementSize = this.activeElement.size();
|
|
350
|
+
const bottomCenter = {
|
|
351
|
+
x: elementPosition.x + elementSize.width / 2,
|
|
352
|
+
y: elementPosition.y + elementSize.height,
|
|
353
|
+
};
|
|
354
|
+
const realBottomCenter = this.paper.localToClientPoint(bottomCenter);
|
|
355
|
+
|
|
356
|
+
const tooltipTopCenter = {
|
|
357
|
+
x: realBottomCenter.x - this.tooltipEl.offsetWidth / 2,
|
|
358
|
+
y: realBottomCenter.y + 10,
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
left = tooltipTopCenter.x;
|
|
362
|
+
top = tooltipTopCenter.y;
|
|
363
|
+
|
|
364
|
+
} else if (this.ghostNode) { // Creating a new element
|
|
365
|
+
|
|
366
|
+
const bottomCenter = {
|
|
367
|
+
x: this.ghostNode.offsetLeft + (this.ghostNode.offsetWidth / 2),
|
|
368
|
+
y: this.ghostNode.offsetTop + this.ghostNode.offsetHeight,
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const tooltipTopCenter = {
|
|
372
|
+
x: bottomCenter.x - this.tooltipEl.offsetWidth / 2,
|
|
373
|
+
y: bottomCenter.y + 10,
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
left = tooltipTopCenter.x;
|
|
377
|
+
top = tooltipTopCenter.y;
|
|
378
|
+
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
this.tooltipEl.style.left = left + 'px';
|
|
382
|
+
this.tooltipEl.style.top = top + 'px';
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
removeElementTooltip() {
|
|
386
|
+
if (this.tooltipEl) {
|
|
387
|
+
document.removeEventListener('mousemove', this.setTooltipPosition);
|
|
388
|
+
document.body.removeChild(this.tooltipEl);
|
|
389
|
+
this.tooltipEl = null;
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { highlighters, dia } from 'jointjs';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
data() {
|
|
5
|
+
return {
|
|
6
|
+
hasTransparency: {},
|
|
7
|
+
};
|
|
8
|
+
},
|
|
9
|
+
methods: {
|
|
10
|
+
initTransparentDragging() {
|
|
11
|
+
this.paperManager.addEventHandler('cell:pointerup blank:pointerup', () => {
|
|
12
|
+
this.removeTransparency();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
this.graph.on('change:position', (model) => {
|
|
16
|
+
this.addTransparency(model);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
this.$on('node-added', (node) => {
|
|
20
|
+
const nodeId = node.definition.id;
|
|
21
|
+
const element = this.getElementByNodeId(nodeId);
|
|
22
|
+
const view = this.paper.findViewByModel(element);
|
|
23
|
+
this.removeTransparency(view);
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
addTransparency(model) {
|
|
27
|
+
if (model.id in this.hasTransparency) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const view = this.paper.findViewByModel(model);
|
|
31
|
+
highlighters.addClass.add(view, 'root', 'transparent-highlighter', { className: 'transparent-cell' });
|
|
32
|
+
this.hasTransparency[model.id] = view;
|
|
33
|
+
},
|
|
34
|
+
removeTransparency() {
|
|
35
|
+
let atLeastOneRemoved = false;
|
|
36
|
+
Object.values(this.hasTransparency).forEach((view) => {
|
|
37
|
+
dia.HighlighterView.remove(view, 'transparent-highlighter');
|
|
38
|
+
atLeastOneRemoved = true;
|
|
39
|
+
});
|
|
40
|
+
if (atLeastOneRemoved) {
|
|
41
|
+
this.paper.dumpViews();
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|