@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.
Files changed (31) hide show
  1. package/cypress.config.js +1 -0
  2. package/dist/img/pan-icon.4a4b74b7.svg +3 -0
  3. package/dist/modeler.common.js +2667 -1922
  4. package/dist/modeler.common.js.map +1 -1
  5. package/dist/modeler.umd.js +2671 -1926
  6. package/dist/modeler.umd.js.map +1 -1
  7. package/dist/modeler.umd.min.js +4 -4
  8. package/dist/modeler.umd.min.js.map +1 -1
  9. package/package.json +2 -2
  10. package/src/ModelerApp.vue +5 -1
  11. package/src/assets/railBottom/pan-icon.svg +3 -0
  12. package/src/components/crown/crownConfig/crownConfig.vue +1 -6
  13. package/src/components/hotkeys/main.js +41 -16
  14. package/src/components/hotkeys/undoRedo.js +24 -0
  15. package/src/components/modeler/Modeler.vue +216 -186
  16. package/src/components/modeler/modeler.scss +17 -5
  17. package/src/components/railBottom/PanControl.vue +38 -0
  18. package/src/components/railBottom/RailBottom.vue +8 -0
  19. package/src/components/railBottom/{miniPaperControl/miniPaperControl.scss → bottomLeftControl.scss} +5 -1
  20. package/src/components/railBottom/controls/Controls.vue +18 -6
  21. package/src/components/railBottom/controls/SubmenuPopper/SubmenuPopper.vue +2 -7
  22. package/src/components/railBottom/miniPaperControl/MiniPaperControl.vue +1 -1
  23. package/src/components/railBottom/undoRedoControl/UndoRedoControl.vue +4 -0
  24. package/src/components/rails/explorer-rail/nodeTypesLoop/nodeTypesLoop.vue +10 -3
  25. package/src/components/rails/explorer-rail/pmBlocksLoop/pmBlocksLoop.vue +6 -3
  26. package/src/components/topRail/TopRail.vue +5 -0
  27. package/src/mixins/clickAndDrop.js +20 -0
  28. package/src/mixins/linkEditing.js +393 -0
  29. package/src/mixins/transparentDragging.js +45 -0
  30. package/src/setup/initialLoad.js +2 -1
  31. 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
- @click.stop="onClickControlHandler($event, item)"
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
- @clickToSubmenu="clickToSubmenuHandler"
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.onClickHandler(data.event, data.control);
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.onClickHandler(event, control);
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
- @click="onClickHandler($event, item)"
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,4 +43,4 @@ export default ({
43
43
 
44
44
  </script>
45
45
 
46
- <style lang="scss" scoped src="./miniPaperControl.scss"></style>
46
+ <style lang="scss" scoped src="../bottomLeftControl.scss"></style>
@@ -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
- @click.self="onClickHandler($event, object)"
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
- @click.stop="onClickHandler($event, pinnedObject)"
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
- @click.stop="onClickHandler($event, nodeType)"
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
- @click.stop="onClickHandler($event, object)"
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
- @click.stop="onClickHandler($event, pinnedBlock)"
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
- @click.stop="onClickHandler($event, nodeType)"
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
+ };