@processmaker/modeler 1.24.3 → 1.25.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.
@@ -12,6 +12,7 @@
12
12
  @toggle-mini-map-open="miniMapOpen = $event"
13
13
  @saveBpmn="saveBpmn"
14
14
  @save-state="pushToUndoStack"
15
+ @clearSelection="clearSelection"
15
16
  />
16
17
  <b-row class="modeler h-100">
17
18
  <b-tooltip
@@ -50,6 +51,7 @@
50
51
 
51
52
  <InspectorPanel
52
53
  ref="inspector-panel"
54
+ v-show="!(highlightedNodes.length > 1)"
53
55
  :style="{ height: parentHeight }"
54
56
  :nodeRegistry="nodeRegistry"
55
57
  :moddle="moddle"
@@ -60,12 +62,14 @@
60
62
  :parent-height="parentHeight"
61
63
  :canvas-drag-position="canvasDragPosition"
62
64
  :compressed="panelsCompressed && noElementsSelected"
65
+ @shape-resize="shapeResize"
63
66
  />
64
67
 
65
68
  <component
66
69
  v-for="node in nodes"
67
70
  :is="node.type"
68
71
  :key="node._modelerId"
72
+ ref="nodeComponent"
69
73
  :graph="graph"
70
74
  :paper="paper"
71
75
  :node="node"
@@ -89,8 +93,8 @@
89
93
  @remove-node="removeNode"
90
94
  @set-cursor="cursor = $event"
91
95
  @set-pool-target="poolTarget = $event"
92
- @click="highlightNode(node, $event)"
93
96
  @unset-pools="unsetPools"
97
+ @clearSelection="clearSelection"
94
98
  @set-pools="setPools"
95
99
  @save-state="pushToUndoStack"
96
100
  @set-shape-stacking="setShapeStacking"
@@ -99,6 +103,17 @@
99
103
  @replace-generic-flow="replaceGenericFlow"
100
104
  @copy-element="copyElement"
101
105
  @default-flow="toggleDefaultFlow"
106
+ @shape-resize="shapeResize"
107
+ />
108
+ <selection
109
+ v-if="paper"
110
+ ref="selector"
111
+ :graph="graph"
112
+ :paperManager="paperManager"
113
+ :useModelGeometry="false"
114
+ @remove-nodes="removeNodes"
115
+ :processNode="processNode"
116
+ @save-state="pushToUndoStack"
102
117
  />
103
118
  </b-row>
104
119
  </span>
@@ -138,8 +153,7 @@ import ensureShapeIsNotCovered from '@/components/shapeStackUtils';
138
153
  import ToolBar from '@/components/toolbar/ToolBar';
139
154
  import Node from '@/components/nodes/node';
140
155
  import { addNodeToProcess } from '@/components/nodeManager';
141
- import moveShapeByKeypress from '@/components/modeler/moveWithArrowKeys';
142
- import setUpSelectionBox from '@/components/modeler/setUpSelectionBox';
156
+ import hotkeys from '@/components/hotkeys/main';
143
157
  import TimerEventNode from '@/components/nodes/timerEventNode';
144
158
  import focusNameInputAndHighlightLabel from '@/components/modeler/focusNameInputAndHighlightLabel';
145
159
  import XMLManager from '@/components/modeler/XMLManager';
@@ -150,6 +164,8 @@ import addLoopCharacteristics from '@/setup/addLoopCharacteristics';
150
164
 
151
165
  import ProcessmakerModelerGenericFlow from '@/components/nodes/genericFlow/genericFlow';
152
166
 
167
+ import Selection from './Selection';
168
+
153
169
  export default {
154
170
  components: {
155
171
  ToolBar,
@@ -157,6 +173,7 @@ export default {
157
173
  InspectorPanel,
158
174
  MiniPaper,
159
175
  ProcessmakerModelerGenericFlow,
176
+ Selection,
160
177
  },
161
178
  props: {
162
179
  owner: Object,
@@ -167,6 +184,7 @@ export default {
167
184
  },
168
185
  },
169
186
  },
187
+ mixins: [hotkeys],
170
188
  data() {
171
189
  return {
172
190
  tooltipTarget: null,
@@ -209,6 +227,15 @@ export default {
209
227
  activeNode: null,
210
228
  xmlManager: null,
211
229
  previouslyStackedShape: null,
230
+ keyMod: this.isAppleOS() ? 'Command' : 'Control',
231
+ canvasScale: 1,
232
+ initialScale: 1,
233
+ minimumScale: 0.2,
234
+ scaleStep: 0.1,
235
+ isDragging: false,
236
+ isSelecting: false,
237
+ isIntoTheSelection: false,
238
+ dragStart: null,
212
239
  };
213
240
  },
214
241
  watch: {
@@ -237,6 +264,10 @@ export default {
237
264
  autoValidate() {
238
265
  this.validateIfAutoValidateIsOn();
239
266
  },
267
+ canvasScale(canvasScale) {
268
+ this.paperManager.scale = canvasScale;
269
+ },
270
+
240
271
  },
241
272
  computed: {
242
273
  noElementsSelected() {
@@ -261,6 +292,14 @@ export default {
261
292
  },
262
293
  },
263
294
  methods: {
295
+ isAppleOS() {
296
+ return typeof navigator !== 'undefined' && /Mac|iPad|iPhone/.test(navigator.platform);
297
+ },
298
+ async shapeResize() {
299
+ await this.$nextTick();
300
+ await this.paperManager.awaitScheduledUpdates();
301
+ this.$refs.selector.updateSelectionBox(true);
302
+ },
264
303
  toggleDefaultFlow(flow) {
265
304
  const source = flow.definition.sourceRef;
266
305
  if (source.default && source.default.id === flow.id) {
@@ -330,7 +369,6 @@ export default {
330
369
  try {
331
370
  const xml = await this.getXmlFromDiagram();
332
371
  undoRedoStore.dispatch('pushState', xml);
333
-
334
372
  window.ProcessMaker.EventBus.$emit('modeler-change');
335
373
  } catch (invalidXml) {
336
374
  // eslint-disable-next-line no-console
@@ -403,7 +441,7 @@ export default {
403
441
  let isSameHighlightedNode = _.isEqual(node.id, this.highlightedNode.id);
404
442
 
405
443
  if (!isSameHighlightedNode) {
406
- store.commit('highlightNode', node);
444
+ store.commit('highlightNode', node);
407
445
  }
408
446
 
409
447
  return;
@@ -746,7 +784,6 @@ export default {
746
784
 
747
785
  this.highlightNode(newNode);
748
786
  await this.addNode(newNode);
749
-
750
787
  if (!nodeThatWillBeReplaced) {
751
788
  return;
752
789
  }
@@ -767,7 +804,14 @@ export default {
767
804
  diagram.bounds.x -= (diagram.bounds.width / 2);
768
805
  diagram.bounds.y -= (diagram.bounds.height / 2);
769
806
  },
770
- addNode(node) {
807
+ async selectNewNode(node) {
808
+ await this.$nextTick();
809
+ await this.paperManager.awaitScheduledUpdates();
810
+ const newNodeComponent = this.$refs.nodeComponent.find(component => component.node === node);
811
+ const view = newNodeComponent.shapeView;
812
+ await this.$refs.selector.selectElement(view);
813
+ },
814
+ async addNode(node) {
771
815
  if (!node.pool) {
772
816
  node.pool = this.poolTarget;
773
817
  }
@@ -793,6 +837,9 @@ export default {
793
837
  return;
794
838
  }
795
839
 
840
+ // Select the node after it has been added to the store (does not apply to flows)
841
+ this.selectNewNode(node);
842
+
796
843
  return new Promise(resolve => {
797
844
  setTimeout(() => {
798
845
  this.pushToUndoStack();
@@ -814,9 +861,22 @@ export default {
814
861
  this.removeNodesFromPool(node);
815
862
  store.commit('removeNode', node);
816
863
  store.commit('highlightNode', this.processNode);
864
+ this.$refs.selector.clearSelection();
817
865
  await this.$nextTick();
818
866
  this.pushToUndoStack();
819
867
  },
868
+ async removeNodes() {
869
+ this.performSingleUndoRedoTransaction(async() => {
870
+ await this.paperManager.performAtomicAction(async() => {
871
+ const waitPromises = [];
872
+ this.highlightedNodes.forEach((node) =>
873
+ waitPromises.push(this.removeNode(node, { removeRelationships: true }))
874
+ );
875
+ await Promise.all(waitPromises);
876
+ store.commit('highlightNode');
877
+ });
878
+ });
879
+ },
820
880
  replaceNode({ node, typeToReplaceWith }) {
821
881
  this.performSingleUndoRedoTransaction(async() => {
822
882
  await this.paperManager.performAtomicAction(async() => {
@@ -829,6 +889,7 @@ export default {
829
889
 
830
890
  await this.removeNode(node, { removeRelationships: false });
831
891
  this.highlightNode(newNode);
892
+ this.selectNewNode(newNode);
832
893
  });
833
894
  });
834
895
  },
@@ -898,18 +959,6 @@ export default {
898
959
 
899
960
  this.paperManager.setPaperDimensions(clientWidth, clientHeight);
900
961
  },
901
- keydownListener(event) {
902
- const focusIsOutsideDiagram = !event.target.toString().toLowerCase().includes('body');
903
- if (focusIsOutsideDiagram) {
904
- return;
905
- }
906
-
907
- moveShapeByKeypress(
908
- event.key,
909
- store.getters.highlightedShapes,
910
- this.pushToUndoStack,
911
- );
912
- },
913
962
  validateDropTarget({ clientX, clientY, control }) {
914
963
  const { allowDrop, poolTarget } = getValidationProperties(clientX, clientY, control, this.paperManager.paper, this.graph, this.collaboration, this.$refs['paper-container']);
915
964
  this.allowDrop = allowDrop;
@@ -926,6 +975,94 @@ export default {
926
975
  this.previouslyStackedShape = shape;
927
976
  this.paperManager.performAtomicAction(() => ensureShapeIsNotCovered(shape, this.graph));
928
977
  },
978
+ clearSelection(){
979
+ this.$refs.selector.clearSelection();
980
+ },
981
+ isPointInSelection(event) {
982
+ const selector = this.$refs.selector.$el;
983
+ if (typeof selector.getBoundingClientRect === 'function') {
984
+ // check if mouse was clicked inside the selector
985
+ const { x: sx, y: sy, width:swidth, height: sheight } = selector.getBoundingClientRect();
986
+ if (event.clientX >= sx && event.clientX <= sx + swidth && event.clientY >= sy && event.clientY <= sy + sheight) {
987
+ return true;
988
+ }
989
+ }
990
+ return false;
991
+ },
992
+ async pointerDowInShape(event, element) {
993
+ const { clientX: x, clientY: y } = event;
994
+ const shapeView = this.paper.findViewByModel(element);
995
+ this.isDragging = false;
996
+ this.isSelecting = false;
997
+ this.isIntoTheSelection = false;
998
+ this.dragStart = { x, y };
999
+ // Verify if is in the selection box
1000
+ if (this.isPointInSelection(event)) {
1001
+ this.isIntoTheSelection = true;
1002
+ } else {
1003
+ if (!event.shiftKey) {
1004
+ await this.$refs.selector.selectElement(shapeView);
1005
+ await this.$nextTick();
1006
+ }
1007
+ }
1008
+ this.$refs.selector.startDrag({
1009
+ clientX: event.clientX,
1010
+ clientY: event.clientY,
1011
+ });
1012
+ },
1013
+ pointerDownHandler(event) {
1014
+ const { clientX: x, clientY: y } = event;
1015
+ this.isDragging = false;
1016
+ this.isSelecting = false;
1017
+ this.isIntoTheSelection = false;
1018
+ this.dragStart = { x, y };
1019
+ // Verify if is in the selection box
1020
+ if (this.isPointInSelection(event)) {
1021
+ this.isIntoTheSelection = true;
1022
+ this.$refs.selector.startDrag({
1023
+ clientX: event.clientX,
1024
+ clientY: event.clientY,
1025
+ });
1026
+ } else {
1027
+ this.isSelecting = true;
1028
+ this.$refs.selector.startSelection(event);
1029
+ }
1030
+ },
1031
+ pointerMoveHandler(event) {
1032
+ const { clientX: x, clientY: y } = event;
1033
+ if (this.dragStart && (Math.abs(x - this.dragStart.x) > 5 || Math.abs(y - this.dragStart.y) > 5)) {
1034
+ this.isDragging = true;
1035
+ this.dragStart = null;
1036
+ } else {
1037
+ if (this.isSelecting) {
1038
+ this.$refs.selector.updateSelection(event);
1039
+ } else {
1040
+ if (this.isDragging) {
1041
+ this.$refs.selector.drag(event);
1042
+ }
1043
+ }
1044
+ }
1045
+ },
1046
+ pointerUpHandler(event, cellView) {
1047
+ if (!this.isDragging && this.dragStart) {
1048
+ // is clicked over the shape
1049
+ if (cellView) {
1050
+ this.$refs.selector.stopDrag(event);
1051
+ this.$refs.selector.selectElement(cellView, event.shiftKey);
1052
+ } else {
1053
+ this.clearSelection();
1054
+ }
1055
+ } else {
1056
+ if (this.isSelecting) {
1057
+ this.$refs.selector.endSelection(this.paperManager.paper);
1058
+ } else {
1059
+ this.$refs.selector.stopDrag(event);
1060
+ }
1061
+ }
1062
+ this.isDragging = false;
1063
+ this.dragStart = null;
1064
+ this.isSelecting = false;
1065
+ },
929
1066
  },
930
1067
  created() {
931
1068
  if (runningInCypressTest()) {
@@ -959,13 +1096,12 @@ export default {
959
1096
  this.$emit('set-xml-manager', this.xmlManager);
960
1097
  },
961
1098
  mounted() {
962
- document.addEventListener('keydown', this.keydownListener);
963
-
964
1099
  this.graph = new dia.Graph();
965
1100
  store.commit('setGraph', this.graph);
966
1101
  this.graph.set('interactiveFunc', cellView => {
1102
+ const isPoolEdge = cellView.model.get('type') === 'standard.EmbeddedImage';
967
1103
  return {
968
- elementMove: cellView.model.get('elementMove'),
1104
+ elementMove: isPoolEdge,
969
1105
  labelMove: false,
970
1106
  };
971
1107
  });
@@ -980,31 +1116,29 @@ export default {
980
1116
 
981
1117
  store.commit('setPaper', this.paperManager.paper);
982
1118
 
983
- this.paperManager.addEventHandler('blank:pointerclick', () => {
984
- store.commit('highlightNode', this.processNode);
985
- }, this);
986
-
987
1119
  this.paperManager.addEventHandler('element:pointerclick', this.blurFocusedScreenBuilderElement, this);
988
1120
 
989
1121
  this.paperManager.addEventHandler('blank:pointerdown', (event, x, y) => {
1122
+ if (this.isGrabbing) return;
990
1123
  const scale = this.paperManager.scale;
991
1124
  this.canvasDragPosition = { x: x * scale.sx, y: y * scale.sy };
992
- this.isGrabbing = true;
1125
+ this.isOverShape = false;
1126
+ this.pointerDownHandler(event);
1127
+ }, this);
1128
+ this.paperManager.addEventHandler('blank:pointerup', (event) => {
1129
+ this.canvasDragPosition = null;
1130
+ this.activeNode = null;
1131
+ this.pointerUpHandler(event);
993
1132
  }, this);
994
- this.paperManager.addEventHandler('cell:pointerup blank:pointerup', () => {
1133
+ this.paperManager.addEventHandler('cell:pointerup', (cellView, event) => {
995
1134
  this.canvasDragPosition = null;
996
- this.isGrabbing = false;
997
1135
  this.activeNode = null;
1136
+ this.pointerUpHandler(event, cellView);
998
1137
  }, this);
999
1138
 
1000
1139
  this.$el.addEventListener('mousemove', event => {
1001
- if (this.canvasDragPosition) {
1002
- this.paperManager.translate(
1003
- event.offsetX - this.canvasDragPosition.x,
1004
- event.offsetY - this.canvasDragPosition.y,
1005
- );
1006
- }
1007
- }, this);
1140
+ this.pointerMoveHandler(event);
1141
+ });
1008
1142
 
1009
1143
  this.paperManager.addEventHandler('cell:pointerclick', (cellView, evt, x, y) => {
1010
1144
  const clickHandler = cellView.model.get('onClick');
@@ -1021,23 +1155,16 @@ export default {
1021
1155
  shape.component.$emit('click', event);
1022
1156
  });
1023
1157
 
1024
- this.paperManager.addEventHandler('cell:pointerdown', ({ model: shape }) => {
1158
+ this.paperManager.addEventHandler('cell:pointerdown', ({ model: shape }, event) => {
1025
1159
  if (!this.isBpmnNode(shape)) {
1026
1160
  return;
1027
1161
  }
1028
-
1029
1162
  this.setShapeStacking(shape);
1030
1163
  this.activeNode = shape.component.node;
1164
+ this.isOverShape = true;
1165
+ this.pointerDowInShape(event, shape);
1031
1166
  });
1032
1167
 
1033
- let cursor;
1034
- const setCursor = () => {
1035
- cursor = this.cursor;
1036
- this.cursor = 'crosshair';
1037
- };
1038
- const resetCursor = () => this.cursor = cursor;
1039
- setUpSelectionBox(setCursor, resetCursor, this.paperManager, this.graph);
1040
-
1041
1168
  /* Register custom nodes */
1042
1169
  window.ProcessMaker.EventBus.$emit('modeler-start', {
1043
1170
  loadXML: xml => {