bpmn-js 17.6.2 → 17.6.3

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.
@@ -1,592 +1,592 @@
1
- import {
2
- assign,
3
- forEach,
4
- isArray,
5
- every
6
- } from 'min-dash';
7
-
8
- import {
9
- is
10
- } from '../../util/ModelUtil';
11
-
12
- import {
13
- isExpanded,
14
- isHorizontal,
15
- isEventSubProcess
16
- } from '../../util/DiUtil';
17
-
18
- import {
19
- isAny
20
- } from '../modeling/util/ModelingUtil';
21
-
22
- import {
23
- getChildLanes
24
- } from '../modeling/util/LaneUtil';
25
-
26
- import {
27
- hasPrimaryModifier
28
- } from 'diagram-js/lib/util/Mouse';
29
-
30
- /**
31
- * @typedef {import('didi').Injector} Injector
32
- * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
33
- * @typedef {import('diagram-js/lib/features/context-pad/ContextPad').default} ContextPad
34
- * @typedef {import('../modeling/Modeling').default} Modeling
35
- * @typedef {import('../modeling/ElementFactory').default} ElementFactory
36
- * @typedef {import('diagram-js/lib/features/connect/Connect').default} Connect
37
- * @typedef {import('diagram-js/lib/features/create/Create').default} Create
38
- * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenu').default} PopupMenu
39
- * @typedef {import('diagram-js/lib/features/canvas/Canvas').default} Canvas
40
- * @typedef {import('diagram-js/lib/features/rules/Rules').default} Rules
41
- * @typedef {import('diagram-js/lib/i18n/translate/translate').default} Translate
42
- *
43
- * @typedef {import('../../model/Types').Element} Element
44
- * @typedef {import('../../model/Types').ModdleElement} ModdleElement
45
- *
46
- * @typedef {import('diagram-js/lib/features/context-pad/ContextPadProvider').default<Element>} BaseContextPadProvider
47
- * @typedef {import('diagram-js/lib/features/context-pad/ContextPadProvider').ContextPadEntries} ContextPadEntries
48
- * @typedef {import('diagram-js/lib/features/context-pad/ContextPadProvider').ContextPadEntry} ContextPadEntry
49
- *
50
- * @typedef { { autoPlace?: boolean; } } ContextPadConfig
51
- */
52
-
53
- /**
54
- * BPMN-specific context pad provider.
55
- *
56
- * @implements {BaseContextPadProvider}
57
- *
58
- * @param {ContextPadConfig} config
59
- * @param {Injector} injector
60
- * @param {EventBus} eventBus
61
- * @param {ContextPad} contextPad
62
- * @param {Modeling} modeling
63
- * @param {ElementFactory} elementFactory
64
- * @param {Connect} connect
65
- * @param {Create} create
66
- * @param {PopupMenu} popupMenu
67
- * @param {Canvas} canvas
68
- * @param {Rules} rules
69
- * @param {Translate} translate
70
- */
71
- export default function ContextPadProvider(
72
- config, injector, eventBus,
73
- contextPad, modeling, elementFactory,
74
- connect, create, popupMenu,
75
- canvas, rules, translate, appendPreview) {
76
-
77
- config = config || {};
78
-
79
- contextPad.registerProvider(this);
80
-
81
- this._contextPad = contextPad;
82
-
83
- this._modeling = modeling;
84
-
85
- this._elementFactory = elementFactory;
86
- this._connect = connect;
87
- this._create = create;
88
- this._popupMenu = popupMenu;
89
- this._canvas = canvas;
90
- this._rules = rules;
91
- this._translate = translate;
92
- this._eventBus = eventBus;
93
- this._appendPreview = appendPreview;
94
-
95
- if (config.autoPlace !== false) {
96
- this._autoPlace = injector.get('autoPlace', false);
97
- }
98
-
99
- eventBus.on('create.end', 250, function(event) {
100
- var context = event.context,
101
- shape = context.shape;
102
-
103
- if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {
104
- return;
105
- }
106
-
107
- var entries = contextPad.getEntries(shape);
108
-
109
- if (entries.replace) {
110
- entries.replace.action.click(event, shape);
111
- }
112
- });
113
-
114
- eventBus.on('contextPad.close', function() {
115
- appendPreview.cleanUp();
116
- });
117
- }
118
-
119
- ContextPadProvider.$inject = [
120
- 'config.contextPad',
121
- 'injector',
122
- 'eventBus',
123
- 'contextPad',
124
- 'modeling',
125
- 'elementFactory',
126
- 'connect',
127
- 'create',
128
- 'popupMenu',
129
- 'canvas',
130
- 'rules',
131
- 'translate',
132
- 'appendPreview'
133
- ];
134
-
135
- /**
136
- * @param {Element[]} elements
137
- *
138
- * @return {ContextPadEntries}
139
- */
140
- ContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) {
141
- var modeling = this._modeling;
142
-
143
- var actions = {};
144
-
145
- if (this._isDeleteAllowed(elements)) {
146
- assign(actions, {
147
- 'delete': {
148
- group: 'edit',
149
- className: 'bpmn-icon-trash',
150
- title: this._translate('Delete'),
151
- action: {
152
- click: function(event, elements) {
153
- modeling.removeElements(elements.slice());
154
- }
155
- }
156
- }
157
- });
158
- }
159
-
160
- return actions;
161
- };
162
-
163
- /**
164
- * @param {Element[]} elements
165
- *
166
- * @return {boolean}
167
- */
168
- ContextPadProvider.prototype._isDeleteAllowed = function(elements) {
169
-
170
- var baseAllowed = this._rules.allowed('elements.delete', {
171
- elements: elements
172
- });
173
-
174
- if (isArray(baseAllowed)) {
175
- return every(baseAllowed, function(element) {
176
- return includes(baseAllowed, element);
177
- });
178
- }
179
-
180
- return baseAllowed;
181
- };
182
-
183
- /**
184
- * @param {Element} element
185
- *
186
- * @return {ContextPadEntries}
187
- */
188
- ContextPadProvider.prototype.getContextPadEntries = function(element) {
189
- var contextPad = this._contextPad,
190
- modeling = this._modeling,
191
- elementFactory = this._elementFactory,
192
- connect = this._connect,
193
- create = this._create,
194
- popupMenu = this._popupMenu,
195
- rules = this._rules,
196
- autoPlace = this._autoPlace,
197
- translate = this._translate,
198
- appendPreview = this._appendPreview;
199
-
200
- var actions = {};
201
-
202
- if (element.type === 'label') {
203
- return actions;
204
- }
205
-
206
- var businessObject = element.businessObject;
207
-
208
- function startConnect(event, element) {
209
- connect.start(event, element);
210
- }
211
-
212
- function removeElement(e, element) {
213
- modeling.removeElements([ element ]);
214
- }
215
-
216
- function getReplaceMenuPosition(element) {
217
-
218
- var Y_OFFSET = 5;
219
-
220
- var pad = contextPad.getPad(element).html;
221
-
222
- var padRect = pad.getBoundingClientRect();
223
-
224
- var pos = {
225
- x: padRect.left,
226
- y: padRect.bottom + Y_OFFSET
227
- };
228
-
229
- return pos;
230
- }
231
-
232
- /**
233
- * Create an append action.
234
- *
235
- * @param {string} type
236
- * @param {string} className
237
- * @param {string} title
238
- * @param {Object} [options]
239
- *
240
- * @return {ContextPadEntry}
241
- */
242
- function appendAction(type, className, title, options) {
243
-
244
- function appendStart(event, element) {
245
-
246
- var shape = elementFactory.createShape(assign({ type: type }, options));
247
-
248
- create.start(event, shape, {
249
- source: element
250
- });
251
- }
252
-
253
- var append = autoPlace ? function(_, element) {
254
- var shape = elementFactory.createShape(assign({ type: type }, options));
255
-
256
- autoPlace.append(element, shape);
257
- } : appendStart;
258
-
259
- var previewAppend = autoPlace ? function(_, element) {
260
-
261
- // mouseover
262
- appendPreview.create(element, type, options);
263
-
264
- return () => {
265
-
266
- // mouseout
267
- appendPreview.cleanUp();
268
- };
269
- } : null;
270
-
271
- return {
272
- group: 'model',
273
- className: className,
274
- title: title,
275
- action: {
276
- dragstart: appendStart,
277
- click: append,
278
- hover: previewAppend
279
- }
280
- };
281
- }
282
-
283
- function splitLaneHandler(count) {
284
-
285
- return function(_, element) {
286
-
287
- // actual split
288
- modeling.splitLane(element, count);
289
-
290
- // refresh context pad after split to
291
- // get rid of split icons
292
- contextPad.open(element, true);
293
- };
294
- }
295
-
296
-
297
- if (isAny(businessObject, [ 'bpmn:Lane', 'bpmn:Participant' ]) && isExpanded(element)) {
298
-
299
- var childLanes = getChildLanes(element);
300
-
301
- assign(actions, {
302
- 'lane-insert-above': {
303
- group: 'lane-insert-above',
304
- className: 'bpmn-icon-lane-insert-above',
305
- title: translate('Add lane above'),
306
- action: {
307
- click: function(event, element) {
308
- modeling.addLane(element, 'top');
309
- }
310
- }
311
- }
312
- });
313
-
314
- if (childLanes.length < 2) {
315
-
316
- if (isHorizontal(element) ? element.height >= 120 : element.width >= 120) {
317
- assign(actions, {
318
- 'lane-divide-two': {
319
- group: 'lane-divide',
320
- className: 'bpmn-icon-lane-divide-two',
321
- title: translate('Divide into two lanes'),
322
- action: {
323
- click: splitLaneHandler(2)
324
- }
325
- }
326
- });
327
- }
328
-
329
- if (isHorizontal(element) ? element.height >= 180 : element.width >= 180) {
330
- assign(actions, {
331
- 'lane-divide-three': {
332
- group: 'lane-divide',
333
- className: 'bpmn-icon-lane-divide-three',
334
- title: translate('Divide into three lanes'),
335
- action: {
336
- click: splitLaneHandler(3)
337
- }
338
- }
339
- });
340
- }
341
- }
342
-
343
- assign(actions, {
344
- 'lane-insert-below': {
345
- group: 'lane-insert-below',
346
- className: 'bpmn-icon-lane-insert-below',
347
- title: translate('Add lane below'),
348
- action: {
349
- click: function(event, element) {
350
- modeling.addLane(element, 'bottom');
351
- }
352
- }
353
- }
354
- });
355
-
356
- }
357
-
358
- if (is(businessObject, 'bpmn:FlowNode')) {
359
-
360
- if (is(businessObject, 'bpmn:EventBasedGateway')) {
361
-
362
- assign(actions, {
363
- 'append.receive-task': appendAction(
364
- 'bpmn:ReceiveTask',
365
- 'bpmn-icon-receive-task',
366
- translate('Append receive task')
367
- ),
368
- 'append.message-intermediate-event': appendAction(
369
- 'bpmn:IntermediateCatchEvent',
370
- 'bpmn-icon-intermediate-event-catch-message',
371
- translate('Append message intermediate catch event'),
372
- { eventDefinitionType: 'bpmn:MessageEventDefinition' }
373
- ),
374
- 'append.timer-intermediate-event': appendAction(
375
- 'bpmn:IntermediateCatchEvent',
376
- 'bpmn-icon-intermediate-event-catch-timer',
377
- translate('Append timer intermediate catch event'),
378
- { eventDefinitionType: 'bpmn:TimerEventDefinition' }
379
- ),
380
- 'append.condition-intermediate-event': appendAction(
381
- 'bpmn:IntermediateCatchEvent',
382
- 'bpmn-icon-intermediate-event-catch-condition',
383
- translate('Append conditional intermediate catch event'),
384
- { eventDefinitionType: 'bpmn:ConditionalEventDefinition' }
385
- ),
386
- 'append.signal-intermediate-event': appendAction(
387
- 'bpmn:IntermediateCatchEvent',
388
- 'bpmn-icon-intermediate-event-catch-signal',
389
- translate('Append signal intermediate catch event'),
390
- { eventDefinitionType: 'bpmn:SignalEventDefinition' }
391
- )
392
- });
393
- } else
394
-
395
- if (isEventType(businessObject, 'bpmn:BoundaryEvent', 'bpmn:CompensateEventDefinition')) {
396
-
397
- assign(actions, {
398
- 'append.compensation-activity':
399
- appendAction(
400
- 'bpmn:Task',
401
- 'bpmn-icon-task',
402
- translate('Append compensation activity'),
403
- {
404
- isForCompensation: true
405
- }
406
- )
407
- });
408
- } else
409
-
410
- if (!is(businessObject, 'bpmn:EndEvent') &&
411
- !businessObject.isForCompensation &&
412
- !isEventType(businessObject, 'bpmn:IntermediateThrowEvent', 'bpmn:LinkEventDefinition') &&
413
- !isEventSubProcess(businessObject)) {
414
-
415
- assign(actions, {
416
- 'append.end-event': appendAction(
417
- 'bpmn:EndEvent',
418
- 'bpmn-icon-end-event-none',
419
- translate('Append end event')
420
- ),
421
- 'append.gateway': appendAction(
422
- 'bpmn:ExclusiveGateway',
423
- 'bpmn-icon-gateway-none',
424
- translate('Append gateway')
425
- ),
426
- 'append.append-task': appendAction(
427
- 'bpmn:Task',
428
- 'bpmn-icon-task',
429
- translate('Append task')
430
- ),
431
- 'append.intermediate-event': appendAction(
432
- 'bpmn:IntermediateThrowEvent',
433
- 'bpmn-icon-intermediate-event-none',
434
- translate('Append intermediate/boundary event')
435
- )
436
- });
437
- }
438
- }
439
-
440
- if (!popupMenu.isEmpty(element, 'bpmn-replace')) {
441
-
442
- // Replace menu entry
443
- assign(actions, {
444
- 'replace': {
445
- group: 'edit',
446
- className: 'bpmn-icon-screw-wrench',
447
- title: translate('Change element'),
448
- action: {
449
- click: function(event, element) {
450
-
451
- var position = assign(getReplaceMenuPosition(element), {
452
- cursor: { x: event.x, y: event.y }
453
- });
454
-
455
- popupMenu.open(element, 'bpmn-replace', position, {
456
- title: translate('Change element'),
457
- width: 300,
458
- search: true
459
- });
460
- }
461
- }
462
- }
463
- });
464
- }
465
-
466
- if (is(businessObject, 'bpmn:SequenceFlow')) {
467
- assign(actions, {
468
- 'append.text-annotation': appendAction(
469
- 'bpmn:TextAnnotation',
470
- 'bpmn-icon-text-annotation',
471
- translate('Add text annotation')
472
- )
473
- });
474
- }
475
-
476
- if (
477
- isAny(businessObject, [
478
- 'bpmn:FlowNode',
479
- 'bpmn:InteractionNode',
480
- 'bpmn:DataObjectReference',
481
- 'bpmn:DataStoreReference',
482
- ])
483
- ) {
484
- assign(actions, {
485
- 'append.text-annotation': appendAction(
486
- 'bpmn:TextAnnotation',
487
- 'bpmn-icon-text-annotation',
488
- translate('Add text annotation')
489
- ),
490
- 'connect': {
491
- group: 'connect',
492
- className: 'bpmn-icon-connection-multi',
493
- title: translate('Connect to other element'),
494
- action: {
495
- click: startConnect,
496
- dragstart: startConnect,
497
- },
498
- },
499
- });
500
- }
501
-
502
- if (is(businessObject, 'bpmn:TextAnnotation')) {
503
- assign(actions, {
504
- 'connect': {
505
- group: 'connect',
506
- className: 'bpmn-icon-connection-multi',
507
- title: translate('Connect using association'),
508
- action: {
509
- click: startConnect,
510
- dragstart: startConnect,
511
- },
512
- },
513
- });
514
- }
515
-
516
- if (isAny(businessObject, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
517
- assign(actions, {
518
- 'connect': {
519
- group: 'connect',
520
- className: 'bpmn-icon-connection-multi',
521
- title: translate('Connect using data input association'),
522
- action: {
523
- click: startConnect,
524
- dragstart: startConnect
525
- }
526
- }
527
- });
528
- }
529
-
530
- if (is(businessObject, 'bpmn:Group')) {
531
- assign(actions, {
532
- 'append.text-annotation': appendAction(
533
- 'bpmn:TextAnnotation',
534
- 'bpmn-icon-text-annotation',
535
- translate('Add text annotation')
536
- )
537
- });
538
- }
539
-
540
- // delete element entry, only show if allowed by rules
541
- var deleteAllowed = rules.allowed('elements.delete', { elements: [ element ] });
542
-
543
- if (isArray(deleteAllowed)) {
544
-
545
- // was the element returned as a deletion candidate?
546
- deleteAllowed = deleteAllowed[0] === element;
547
- }
548
-
549
- if (deleteAllowed) {
550
- assign(actions, {
551
- 'delete': {
552
- group: 'edit',
553
- className: 'bpmn-icon-trash',
554
- title: translate('Delete'),
555
- action: {
556
- click: removeElement
557
- }
558
- }
559
- });
560
- }
561
-
562
- return actions;
563
- };
564
-
565
-
566
- // helpers /////////
567
-
568
- /**
569
- * @param {ModdleElement} businessObject
570
- * @param {string} type
571
- * @param {string} eventDefinitionType
572
- *
573
- * @return {boolean}
574
- */
575
- function isEventType(businessObject, type, eventDefinitionType) {
576
-
577
- var isType = businessObject.$instanceOf(type);
578
- var isDefinition = false;
579
-
580
- var definitions = businessObject.eventDefinitions || [];
581
- forEach(definitions, function(def) {
582
- if (def.$type === eventDefinitionType) {
583
- isDefinition = true;
584
- }
585
- });
586
-
587
- return isType && isDefinition;
588
- }
589
-
590
- function includes(array, item) {
591
- return array.indexOf(item) !== -1;
1
+ import {
2
+ assign,
3
+ forEach,
4
+ isArray,
5
+ every
6
+ } from 'min-dash';
7
+
8
+ import {
9
+ is
10
+ } from '../../util/ModelUtil';
11
+
12
+ import {
13
+ isExpanded,
14
+ isHorizontal,
15
+ isEventSubProcess
16
+ } from '../../util/DiUtil';
17
+
18
+ import {
19
+ isAny
20
+ } from '../modeling/util/ModelingUtil';
21
+
22
+ import {
23
+ getChildLanes
24
+ } from '../modeling/util/LaneUtil';
25
+
26
+ import {
27
+ hasPrimaryModifier
28
+ } from 'diagram-js/lib/util/Mouse';
29
+
30
+ /**
31
+ * @typedef {import('didi').Injector} Injector
32
+ * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
33
+ * @typedef {import('diagram-js/lib/features/context-pad/ContextPad').default} ContextPad
34
+ * @typedef {import('../modeling/Modeling').default} Modeling
35
+ * @typedef {import('../modeling/ElementFactory').default} ElementFactory
36
+ * @typedef {import('diagram-js/lib/features/connect/Connect').default} Connect
37
+ * @typedef {import('diagram-js/lib/features/create/Create').default} Create
38
+ * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenu').default} PopupMenu
39
+ * @typedef {import('diagram-js/lib/features/canvas/Canvas').default} Canvas
40
+ * @typedef {import('diagram-js/lib/features/rules/Rules').default} Rules
41
+ * @typedef {import('diagram-js/lib/i18n/translate/translate').default} Translate
42
+ *
43
+ * @typedef {import('../../model/Types').Element} Element
44
+ * @typedef {import('../../model/Types').ModdleElement} ModdleElement
45
+ *
46
+ * @typedef {import('diagram-js/lib/features/context-pad/ContextPadProvider').default<Element>} BaseContextPadProvider
47
+ * @typedef {import('diagram-js/lib/features/context-pad/ContextPadProvider').ContextPadEntries} ContextPadEntries
48
+ * @typedef {import('diagram-js/lib/features/context-pad/ContextPadProvider').ContextPadEntry} ContextPadEntry
49
+ *
50
+ * @typedef { { autoPlace?: boolean; } } ContextPadConfig
51
+ */
52
+
53
+ /**
54
+ * BPMN-specific context pad provider.
55
+ *
56
+ * @implements {BaseContextPadProvider}
57
+ *
58
+ * @param {ContextPadConfig} config
59
+ * @param {Injector} injector
60
+ * @param {EventBus} eventBus
61
+ * @param {ContextPad} contextPad
62
+ * @param {Modeling} modeling
63
+ * @param {ElementFactory} elementFactory
64
+ * @param {Connect} connect
65
+ * @param {Create} create
66
+ * @param {PopupMenu} popupMenu
67
+ * @param {Canvas} canvas
68
+ * @param {Rules} rules
69
+ * @param {Translate} translate
70
+ */
71
+ export default function ContextPadProvider(
72
+ config, injector, eventBus,
73
+ contextPad, modeling, elementFactory,
74
+ connect, create, popupMenu,
75
+ canvas, rules, translate, appendPreview) {
76
+
77
+ config = config || {};
78
+
79
+ contextPad.registerProvider(this);
80
+
81
+ this._contextPad = contextPad;
82
+
83
+ this._modeling = modeling;
84
+
85
+ this._elementFactory = elementFactory;
86
+ this._connect = connect;
87
+ this._create = create;
88
+ this._popupMenu = popupMenu;
89
+ this._canvas = canvas;
90
+ this._rules = rules;
91
+ this._translate = translate;
92
+ this._eventBus = eventBus;
93
+ this._appendPreview = appendPreview;
94
+
95
+ if (config.autoPlace !== false) {
96
+ this._autoPlace = injector.get('autoPlace', false);
97
+ }
98
+
99
+ eventBus.on('create.end', 250, function(event) {
100
+ var context = event.context,
101
+ shape = context.shape;
102
+
103
+ if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {
104
+ return;
105
+ }
106
+
107
+ var entries = contextPad.getEntries(shape);
108
+
109
+ if (entries.replace) {
110
+ entries.replace.action.click(event, shape);
111
+ }
112
+ });
113
+
114
+ eventBus.on('contextPad.close', function() {
115
+ appendPreview.cleanUp();
116
+ });
117
+ }
118
+
119
+ ContextPadProvider.$inject = [
120
+ 'config.contextPad',
121
+ 'injector',
122
+ 'eventBus',
123
+ 'contextPad',
124
+ 'modeling',
125
+ 'elementFactory',
126
+ 'connect',
127
+ 'create',
128
+ 'popupMenu',
129
+ 'canvas',
130
+ 'rules',
131
+ 'translate',
132
+ 'appendPreview'
133
+ ];
134
+
135
+ /**
136
+ * @param {Element[]} elements
137
+ *
138
+ * @return {ContextPadEntries}
139
+ */
140
+ ContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) {
141
+ var modeling = this._modeling;
142
+
143
+ var actions = {};
144
+
145
+ if (this._isDeleteAllowed(elements)) {
146
+ assign(actions, {
147
+ 'delete': {
148
+ group: 'edit',
149
+ className: 'bpmn-icon-trash',
150
+ title: this._translate('Delete'),
151
+ action: {
152
+ click: function(event, elements) {
153
+ modeling.removeElements(elements.slice());
154
+ }
155
+ }
156
+ }
157
+ });
158
+ }
159
+
160
+ return actions;
161
+ };
162
+
163
+ /**
164
+ * @param {Element[]} elements
165
+ *
166
+ * @return {boolean}
167
+ */
168
+ ContextPadProvider.prototype._isDeleteAllowed = function(elements) {
169
+
170
+ var baseAllowed = this._rules.allowed('elements.delete', {
171
+ elements: elements
172
+ });
173
+
174
+ if (isArray(baseAllowed)) {
175
+ return every(baseAllowed, function(element) {
176
+ return includes(baseAllowed, element);
177
+ });
178
+ }
179
+
180
+ return baseAllowed;
181
+ };
182
+
183
+ /**
184
+ * @param {Element} element
185
+ *
186
+ * @return {ContextPadEntries}
187
+ */
188
+ ContextPadProvider.prototype.getContextPadEntries = function(element) {
189
+ var contextPad = this._contextPad,
190
+ modeling = this._modeling,
191
+ elementFactory = this._elementFactory,
192
+ connect = this._connect,
193
+ create = this._create,
194
+ popupMenu = this._popupMenu,
195
+ rules = this._rules,
196
+ autoPlace = this._autoPlace,
197
+ translate = this._translate,
198
+ appendPreview = this._appendPreview;
199
+
200
+ var actions = {};
201
+
202
+ if (element.type === 'label') {
203
+ return actions;
204
+ }
205
+
206
+ var businessObject = element.businessObject;
207
+
208
+ function startConnect(event, element) {
209
+ connect.start(event, element);
210
+ }
211
+
212
+ function removeElement(e, element) {
213
+ modeling.removeElements([ element ]);
214
+ }
215
+
216
+ function getReplaceMenuPosition(element) {
217
+
218
+ var Y_OFFSET = 5;
219
+
220
+ var pad = contextPad.getPad(element).html;
221
+
222
+ var padRect = pad.getBoundingClientRect();
223
+
224
+ var pos = {
225
+ x: padRect.left,
226
+ y: padRect.bottom + Y_OFFSET
227
+ };
228
+
229
+ return pos;
230
+ }
231
+
232
+ /**
233
+ * Create an append action.
234
+ *
235
+ * @param {string} type
236
+ * @param {string} className
237
+ * @param {string} title
238
+ * @param {Object} [options]
239
+ *
240
+ * @return {ContextPadEntry}
241
+ */
242
+ function appendAction(type, className, title, options) {
243
+
244
+ function appendStart(event, element) {
245
+
246
+ var shape = elementFactory.createShape(assign({ type: type }, options));
247
+
248
+ create.start(event, shape, {
249
+ source: element
250
+ });
251
+ }
252
+
253
+ var append = autoPlace ? function(_, element) {
254
+ var shape = elementFactory.createShape(assign({ type: type }, options));
255
+
256
+ autoPlace.append(element, shape);
257
+ } : appendStart;
258
+
259
+ var previewAppend = autoPlace ? function(_, element) {
260
+
261
+ // mouseover
262
+ appendPreview.create(element, type, options);
263
+
264
+ return () => {
265
+
266
+ // mouseout
267
+ appendPreview.cleanUp();
268
+ };
269
+ } : null;
270
+
271
+ return {
272
+ group: 'model',
273
+ className: className,
274
+ title: title,
275
+ action: {
276
+ dragstart: appendStart,
277
+ click: append,
278
+ hover: previewAppend
279
+ }
280
+ };
281
+ }
282
+
283
+ function splitLaneHandler(count) {
284
+
285
+ return function(_, element) {
286
+
287
+ // actual split
288
+ modeling.splitLane(element, count);
289
+
290
+ // refresh context pad after split to
291
+ // get rid of split icons
292
+ contextPad.open(element, true);
293
+ };
294
+ }
295
+
296
+
297
+ if (isAny(businessObject, [ 'bpmn:Lane', 'bpmn:Participant' ]) && isExpanded(element)) {
298
+
299
+ var childLanes = getChildLanes(element);
300
+
301
+ assign(actions, {
302
+ 'lane-insert-above': {
303
+ group: 'lane-insert-above',
304
+ className: 'bpmn-icon-lane-insert-above',
305
+ title: translate('Add lane above'),
306
+ action: {
307
+ click: function(event, element) {
308
+ modeling.addLane(element, 'top');
309
+ }
310
+ }
311
+ }
312
+ });
313
+
314
+ if (childLanes.length < 2) {
315
+
316
+ if (isHorizontal(element) ? element.height >= 120 : element.width >= 120) {
317
+ assign(actions, {
318
+ 'lane-divide-two': {
319
+ group: 'lane-divide',
320
+ className: 'bpmn-icon-lane-divide-two',
321
+ title: translate('Divide into two lanes'),
322
+ action: {
323
+ click: splitLaneHandler(2)
324
+ }
325
+ }
326
+ });
327
+ }
328
+
329
+ if (isHorizontal(element) ? element.height >= 180 : element.width >= 180) {
330
+ assign(actions, {
331
+ 'lane-divide-three': {
332
+ group: 'lane-divide',
333
+ className: 'bpmn-icon-lane-divide-three',
334
+ title: translate('Divide into three lanes'),
335
+ action: {
336
+ click: splitLaneHandler(3)
337
+ }
338
+ }
339
+ });
340
+ }
341
+ }
342
+
343
+ assign(actions, {
344
+ 'lane-insert-below': {
345
+ group: 'lane-insert-below',
346
+ className: 'bpmn-icon-lane-insert-below',
347
+ title: translate('Add lane below'),
348
+ action: {
349
+ click: function(event, element) {
350
+ modeling.addLane(element, 'bottom');
351
+ }
352
+ }
353
+ }
354
+ });
355
+
356
+ }
357
+
358
+ if (is(businessObject, 'bpmn:FlowNode')) {
359
+
360
+ if (is(businessObject, 'bpmn:EventBasedGateway')) {
361
+
362
+ assign(actions, {
363
+ 'append.receive-task': appendAction(
364
+ 'bpmn:ReceiveTask',
365
+ 'bpmn-icon-receive-task',
366
+ translate('Append receive task')
367
+ ),
368
+ 'append.message-intermediate-event': appendAction(
369
+ 'bpmn:IntermediateCatchEvent',
370
+ 'bpmn-icon-intermediate-event-catch-message',
371
+ translate('Append message intermediate catch event'),
372
+ { eventDefinitionType: 'bpmn:MessageEventDefinition' }
373
+ ),
374
+ 'append.timer-intermediate-event': appendAction(
375
+ 'bpmn:IntermediateCatchEvent',
376
+ 'bpmn-icon-intermediate-event-catch-timer',
377
+ translate('Append timer intermediate catch event'),
378
+ { eventDefinitionType: 'bpmn:TimerEventDefinition' }
379
+ ),
380
+ 'append.condition-intermediate-event': appendAction(
381
+ 'bpmn:IntermediateCatchEvent',
382
+ 'bpmn-icon-intermediate-event-catch-condition',
383
+ translate('Append conditional intermediate catch event'),
384
+ { eventDefinitionType: 'bpmn:ConditionalEventDefinition' }
385
+ ),
386
+ 'append.signal-intermediate-event': appendAction(
387
+ 'bpmn:IntermediateCatchEvent',
388
+ 'bpmn-icon-intermediate-event-catch-signal',
389
+ translate('Append signal intermediate catch event'),
390
+ { eventDefinitionType: 'bpmn:SignalEventDefinition' }
391
+ )
392
+ });
393
+ } else
394
+
395
+ if (isEventType(businessObject, 'bpmn:BoundaryEvent', 'bpmn:CompensateEventDefinition')) {
396
+
397
+ assign(actions, {
398
+ 'append.compensation-activity':
399
+ appendAction(
400
+ 'bpmn:Task',
401
+ 'bpmn-icon-task',
402
+ translate('Append compensation activity'),
403
+ {
404
+ isForCompensation: true
405
+ }
406
+ )
407
+ });
408
+ } else
409
+
410
+ if (!is(businessObject, 'bpmn:EndEvent') &&
411
+ !businessObject.isForCompensation &&
412
+ !isEventType(businessObject, 'bpmn:IntermediateThrowEvent', 'bpmn:LinkEventDefinition') &&
413
+ !isEventSubProcess(businessObject)) {
414
+
415
+ assign(actions, {
416
+ 'append.end-event': appendAction(
417
+ 'bpmn:EndEvent',
418
+ 'bpmn-icon-end-event-none',
419
+ translate('Append end event')
420
+ ),
421
+ 'append.gateway': appendAction(
422
+ 'bpmn:ExclusiveGateway',
423
+ 'bpmn-icon-gateway-none',
424
+ translate('Append gateway')
425
+ ),
426
+ 'append.append-task': appendAction(
427
+ 'bpmn:Task',
428
+ 'bpmn-icon-task',
429
+ translate('Append task')
430
+ ),
431
+ 'append.intermediate-event': appendAction(
432
+ 'bpmn:IntermediateThrowEvent',
433
+ 'bpmn-icon-intermediate-event-none',
434
+ translate('Append intermediate/boundary event')
435
+ )
436
+ });
437
+ }
438
+ }
439
+
440
+ if (!popupMenu.isEmpty(element, 'bpmn-replace')) {
441
+
442
+ // Replace menu entry
443
+ assign(actions, {
444
+ 'replace': {
445
+ group: 'edit',
446
+ className: 'bpmn-icon-screw-wrench',
447
+ title: translate('Change element'),
448
+ action: {
449
+ click: function(event, element) {
450
+
451
+ var position = assign(getReplaceMenuPosition(element), {
452
+ cursor: { x: event.x, y: event.y }
453
+ });
454
+
455
+ popupMenu.open(element, 'bpmn-replace', position, {
456
+ title: translate('Change element'),
457
+ width: 300,
458
+ search: true
459
+ });
460
+ }
461
+ }
462
+ }
463
+ });
464
+ }
465
+
466
+ if (is(businessObject, 'bpmn:SequenceFlow')) {
467
+ assign(actions, {
468
+ 'append.text-annotation': appendAction(
469
+ 'bpmn:TextAnnotation',
470
+ 'bpmn-icon-text-annotation',
471
+ translate('Add text annotation')
472
+ )
473
+ });
474
+ }
475
+
476
+ if (
477
+ isAny(businessObject, [
478
+ 'bpmn:FlowNode',
479
+ 'bpmn:InteractionNode',
480
+ 'bpmn:DataObjectReference',
481
+ 'bpmn:DataStoreReference',
482
+ ])
483
+ ) {
484
+ assign(actions, {
485
+ 'append.text-annotation': appendAction(
486
+ 'bpmn:TextAnnotation',
487
+ 'bpmn-icon-text-annotation',
488
+ translate('Add text annotation')
489
+ ),
490
+ 'connect': {
491
+ group: 'connect',
492
+ className: 'bpmn-icon-connection-multi',
493
+ title: translate('Connect to other element'),
494
+ action: {
495
+ click: startConnect,
496
+ dragstart: startConnect,
497
+ },
498
+ },
499
+ });
500
+ }
501
+
502
+ if (is(businessObject, 'bpmn:TextAnnotation')) {
503
+ assign(actions, {
504
+ 'connect': {
505
+ group: 'connect',
506
+ className: 'bpmn-icon-connection-multi',
507
+ title: translate('Connect using association'),
508
+ action: {
509
+ click: startConnect,
510
+ dragstart: startConnect,
511
+ },
512
+ },
513
+ });
514
+ }
515
+
516
+ if (isAny(businessObject, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
517
+ assign(actions, {
518
+ 'connect': {
519
+ group: 'connect',
520
+ className: 'bpmn-icon-connection-multi',
521
+ title: translate('Connect using data input association'),
522
+ action: {
523
+ click: startConnect,
524
+ dragstart: startConnect
525
+ }
526
+ }
527
+ });
528
+ }
529
+
530
+ if (is(businessObject, 'bpmn:Group')) {
531
+ assign(actions, {
532
+ 'append.text-annotation': appendAction(
533
+ 'bpmn:TextAnnotation',
534
+ 'bpmn-icon-text-annotation',
535
+ translate('Add text annotation')
536
+ )
537
+ });
538
+ }
539
+
540
+ // delete element entry, only show if allowed by rules
541
+ var deleteAllowed = rules.allowed('elements.delete', { elements: [ element ] });
542
+
543
+ if (isArray(deleteAllowed)) {
544
+
545
+ // was the element returned as a deletion candidate?
546
+ deleteAllowed = deleteAllowed[0] === element;
547
+ }
548
+
549
+ if (deleteAllowed) {
550
+ assign(actions, {
551
+ 'delete': {
552
+ group: 'edit',
553
+ className: 'bpmn-icon-trash',
554
+ title: translate('Delete'),
555
+ action: {
556
+ click: removeElement
557
+ }
558
+ }
559
+ });
560
+ }
561
+
562
+ return actions;
563
+ };
564
+
565
+
566
+ // helpers /////////
567
+
568
+ /**
569
+ * @param {ModdleElement} businessObject
570
+ * @param {string} type
571
+ * @param {string} eventDefinitionType
572
+ *
573
+ * @return {boolean}
574
+ */
575
+ function isEventType(businessObject, type, eventDefinitionType) {
576
+
577
+ var isType = businessObject.$instanceOf(type);
578
+ var isDefinition = false;
579
+
580
+ var definitions = businessObject.eventDefinitions || [];
581
+ forEach(definitions, function(def) {
582
+ if (def.$type === eventDefinitionType) {
583
+ isDefinition = true;
584
+ }
585
+ });
586
+
587
+ return isType && isDefinition;
588
+ }
589
+
590
+ function includes(array, item) {
591
+ return array.indexOf(item) !== -1;
592
592
  }