bpmn-js 9.0.0-subprocesses.3 → 9.0.2

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 (44) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/assets/bpmn-js.css +44 -7
  3. package/dist/assets/diagram-js.css +1 -1
  4. package/dist/bpmn-modeler.development.js +2424 -1130
  5. package/dist/bpmn-modeler.production.min.js +8 -8
  6. package/dist/bpmn-navigated-viewer.development.js +990 -317
  7. package/dist/bpmn-navigated-viewer.production.min.js +6 -6
  8. package/dist/bpmn-viewer.development.js +989 -316
  9. package/dist/bpmn-viewer.production.min.js +6 -6
  10. package/lib/BaseViewer.js +1 -1
  11. package/lib/draw/BpmnRenderer.js +8 -7
  12. package/lib/features/auto-resize/BpmnAutoResizeProvider.js +6 -0
  13. package/lib/features/copy-paste/BpmnCopyPaste.js +1 -0
  14. package/lib/features/di-ordering/BpmnDiOrdering.js +15 -11
  15. package/lib/features/drilldown/DrilldownBreadcrumbs.js +122 -0
  16. package/lib/features/drilldown/DrilldownCentering.js +87 -10
  17. package/lib/features/drilldown/DrilldownOverlayBehavior.js +181 -0
  18. package/lib/features/drilldown/SubprocessCompatibility.js +15 -7
  19. package/lib/features/drilldown/index.js +7 -4
  20. package/lib/features/label-editing/LabelEditingProvider.js +1 -1
  21. package/lib/features/label-editing/cmd/UpdateLabelHandler.js +29 -2
  22. package/lib/features/modeling/BpmnFactory.js +5 -1
  23. package/lib/features/modeling/BpmnUpdater.js +43 -1
  24. package/lib/features/modeling/ElementFactory.js +4 -0
  25. package/lib/features/modeling/behavior/CreateParticipantBehavior.js +59 -84
  26. package/lib/features/modeling/behavior/DropOnFlowBehavior.js +2 -2
  27. package/lib/features/modeling/behavior/GroupBehavior.js +6 -18
  28. package/lib/features/modeling/behavior/RemoveEmbeddedLabelBoundsBehavior.js +34 -0
  29. package/lib/features/modeling/behavior/SubProcessPlaneBehavior.js +557 -0
  30. package/lib/features/modeling/behavior/ToggleCollapseConnectionBehaviour.js +74 -0
  31. package/lib/features/modeling/behavior/UnclaimIdBehavior.js +3 -1
  32. package/lib/features/modeling/behavior/index.js +27 -18
  33. package/lib/features/modeling/cmd/SetColorHandler.js +23 -6
  34. package/lib/features/modeling/cmd/UpdateCanvasRootHandler.js +4 -2
  35. package/lib/features/modeling/util/ModelingUtil.js +2 -20
  36. package/lib/features/ordering/BpmnOrderingProvider.js +3 -3
  37. package/lib/features/palette/PaletteProvider.js +1 -1
  38. package/lib/features/popup-menu/ReplaceMenuProvider.js +1 -1
  39. package/lib/import/BpmnImporter.js +15 -9
  40. package/lib/import/Importer.js +130 -10
  41. package/lib/util/DrilldownUtil.js +66 -0
  42. package/lib/util/ModelUtil.js +19 -0
  43. package/package.json +2 -2
  44. package/lib/features/drilldown/DrilldownOverlays.js +0 -110
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * bpmn-js - bpmn-navigated-viewer v9.0.0-subprocesses.3
2
+ * bpmn-js - bpmn-navigated-viewer v9.0.2
3
3
  *
4
4
  * Copyright (c) 2014-present, camunda Services GmbH
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Source Code: https://github.com/bpmn-io/bpmn-js
10
10
  *
11
- * Date: 2021-11-19
11
+ * Date: 2022-02-23
12
12
  */
13
13
  (function (global, factory) {
14
14
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -207,6 +207,23 @@
207
207
  function some(collection, matcher) {
208
208
  return !!find(collection, matcher);
209
209
  }
210
+ /**
211
+ * Transform a collection into another collection
212
+ * by piping each member through the given fn.
213
+ *
214
+ * @param {Object|Array} collection
215
+ * @param {Function} fn
216
+ *
217
+ * @return {Array} transformed collection
218
+ */
219
+
220
+ function map$1(collection, fn) {
221
+ var result = [];
222
+ forEach(collection, function (val, key) {
223
+ result.push(fn(val, key));
224
+ });
225
+ return result;
226
+ }
210
227
  /**
211
228
  * Create an object pattern matcher.
212
229
  *
@@ -214,7 +231,7 @@
214
231
  *
215
232
  * const matcher = matchPattern({ id: 1 });
216
233
  *
217
- * var element = find(elements, matcher);
234
+ * let element = find(elements, matcher);
218
235
  *
219
236
  * @param {Object} pattern
220
237
  *
@@ -244,8 +261,11 @@
244
261
  }
245
262
 
246
263
  /**
247
- * Debounce fn, calling it only once if
248
- * the given time elapsed between calls.
264
+ * Debounce fn, calling it only once if the given time
265
+ * elapsed between calls.
266
+ *
267
+ * Lodash-style the function exposes methods to `#clear`
268
+ * and `#flush` to control internal behavior.
249
269
  *
250
270
  * @param {Function} fn
251
271
  * @param {Number} timeout
@@ -258,23 +278,39 @@
258
278
  var lastThis;
259
279
  var lastNow;
260
280
 
261
- function fire() {
281
+ function fire(force) {
262
282
  var now = Date.now();
263
- var scheduledDiff = lastNow + timeout - now;
283
+ var scheduledDiff = force ? 0 : lastNow + timeout - now;
264
284
 
265
285
  if (scheduledDiff > 0) {
266
286
  return schedule(scheduledDiff);
267
287
  }
268
288
 
269
289
  fn.apply(lastThis, lastArgs);
270
- timer = lastNow = lastArgs = lastThis = undefined;
290
+ clear();
271
291
  }
272
292
 
273
293
  function schedule(timeout) {
274
294
  timer = setTimeout(fire, timeout);
275
295
  }
276
296
 
277
- return function () {
297
+ function clear() {
298
+ if (timer) {
299
+ clearTimeout(timer);
300
+ }
301
+
302
+ timer = lastNow = lastArgs = lastThis = undefined;
303
+ }
304
+
305
+ function flush() {
306
+ if (timer) {
307
+ fire(true);
308
+ }
309
+
310
+ clear();
311
+ }
312
+
313
+ function callback() {
278
314
  lastNow = Date.now();
279
315
 
280
316
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
@@ -287,7 +323,11 @@
287
323
  if (!timer) {
288
324
  schedule(timeout);
289
325
  }
290
- };
326
+ }
327
+
328
+ callback.flush = flush;
329
+ callback.cancel = clear;
330
+ return callback;
291
331
  }
292
332
  /**
293
333
  * Bind function against target <this>.
@@ -476,7 +516,6 @@
476
516
  return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
477
517
  }
478
518
 
479
-
480
519
  /**
481
520
  * Return the business object for a given element.
482
521
  *
@@ -2530,16 +2569,16 @@
2530
2569
  return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
2531
2570
  }
2532
2571
 
2572
+ function renderer(type) {
2573
+ return handlers[type];
2574
+ }
2575
+
2533
2576
  function as(type) {
2534
2577
  return function(parentGfx, element) {
2535
- return handlers[type](parentGfx, element);
2578
+ return renderer(type)(parentGfx, element);
2536
2579
  };
2537
2580
  }
2538
2581
 
2539
- function renderer(type) {
2540
- return handlers[type];
2541
- }
2542
-
2543
2582
  function renderEventContent(element, parentGfx) {
2544
2583
 
2545
2584
  var event = getSemantic(element);
@@ -4020,6 +4059,7 @@
4020
4059
  // extension API, use at your own risk
4021
4060
  this._drawPath = drawPath;
4022
4061
 
4062
+ this._renderer = renderer;
4023
4063
  }
4024
4064
 
4025
4065
 
@@ -4041,7 +4081,7 @@
4041
4081
 
4042
4082
  BpmnRenderer.prototype.drawShape = function(parentGfx, element) {
4043
4083
  var type = element.type;
4044
- var h = this.handlers[type];
4084
+ var h = this._renderer(type);
4045
4085
 
4046
4086
  /* jshint -W040 */
4047
4087
  return h(parentGfx, element);
@@ -4049,7 +4089,7 @@
4049
4089
 
4050
4090
  BpmnRenderer.prototype.drawConnection = function(parentGfx, element) {
4051
4091
  var type = element.type;
4052
- var h = this.handlers[type];
4092
+ var h = this._renderer(type);
4053
4093
 
4054
4094
  /* jshint -W040 */
4055
4095
  return h(parentGfx, element);
@@ -5259,6 +5299,13 @@
5259
5299
  return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />';
5260
5300
  }
5261
5301
 
5302
+ /**
5303
+ * @param {ModdleElement} semantic
5304
+ * @param {ModdleElement} di
5305
+ * @param {Object} [attrs=null]
5306
+ *
5307
+ * @return {Object}
5308
+ */
5262
5309
  function elementData(semantic, di, attrs) {
5263
5310
  return assign({
5264
5311
  id: semantic.id,
@@ -5338,15 +5385,14 @@
5338
5385
  // invisible root element (process, subprocess or collaboration)
5339
5386
  if (is$1(di, 'bpmndi:BPMNPlane')) {
5340
5387
 
5341
- // add a virtual element (not being drawn)
5342
- element = this._elementFactory.createRoot(elementData(semantic, di));
5388
+ var attrs = is$1(semantic, 'bpmn:SubProcess')
5389
+ ? { id: semantic.id + '_plane' }
5390
+ : {};
5343
5391
 
5344
- // for subprocesses, the id is already defined on the collapsed shape
5345
- if (is$1(semantic, 'bpmn:SubProcess')) {
5346
- element.id = element.id + '_plane';
5347
- }
5392
+ // add a virtual element (not being drawn)
5393
+ element = this._elementFactory.createRoot(elementData(semantic, di, attrs));
5348
5394
 
5349
- this._canvas.createPlane(semantic.id, element);
5395
+ this._canvas.addRootElement(element);
5350
5396
  }
5351
5397
 
5352
5398
  // SHAPE
@@ -5382,7 +5428,7 @@
5382
5428
 
5383
5429
  // check whether data store is inside our outside of its semantic parent
5384
5430
  if (!isPointInsideBBox(parentElement, getMid(bounds))) {
5385
- parentElement = this._canvas.findPlane(parentElement).rootElement;
5431
+ parentElement = this._canvas.findRoot(parentElement);
5386
5432
  }
5387
5433
  }
5388
5434
 
@@ -5410,7 +5456,7 @@
5410
5456
  // are rendered correctly across different "hacks" people
5411
5457
  // love to model such as cross participant / sub process
5412
5458
  // associations
5413
- parentElement = this._canvas.findPlane(parentElement).rootElement;
5459
+ parentElement = this._canvas.findRoot(parentElement);
5414
5460
  }
5415
5461
 
5416
5462
  // insert sequence flows behind other flow nodes (cf. #727)
@@ -5661,7 +5707,7 @@
5661
5707
  return isPrimaryButton(event) || isAuxiliaryButton(event);
5662
5708
  }
5663
5709
 
5664
- var LOW_PRIORITY$3 = 500;
5710
+ var LOW_PRIORITY$4 = 500;
5665
5711
 
5666
5712
 
5667
5713
  /**
@@ -5856,7 +5902,7 @@
5856
5902
  eventBus.on([
5857
5903
  'shape.changed',
5858
5904
  'connection.changed'
5859
- ], LOW_PRIORITY$3, function(event) {
5905
+ ], LOW_PRIORITY$4, function(event) {
5860
5906
 
5861
5907
  var element = event.element,
5862
5908
  gfx = event.gfx;
@@ -5864,7 +5910,7 @@
5864
5910
  eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
5865
5911
  });
5866
5912
 
5867
- eventBus.on('interactionEvents.createHit', LOW_PRIORITY$3, function(event) {
5913
+ eventBus.on('interactionEvents.createHit', LOW_PRIORITY$4, function(event) {
5868
5914
  var element = event.element,
5869
5915
  gfx = event.gfx;
5870
5916
 
@@ -6212,7 +6258,7 @@
6212
6258
  return !!(element && element.isFrame);
6213
6259
  }
6214
6260
 
6215
- var LOW_PRIORITY$2 = 500;
6261
+ var LOW_PRIORITY$3 = 500;
6216
6262
 
6217
6263
 
6218
6264
  /**
@@ -6250,7 +6296,7 @@
6250
6296
 
6251
6297
  // A low priortity is necessary, because outlines of labels have to be updated
6252
6298
  // after the label bounds have been updated in the renderer.
6253
- eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$2, function(event) {
6299
+ eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$3, function(event) {
6254
6300
  var element = event.element,
6255
6301
  gfx = event.gfx;
6256
6302
 
@@ -6347,7 +6393,7 @@
6347
6393
  self.deselect(element);
6348
6394
  });
6349
6395
 
6350
- eventBus.on([ 'diagram.clear', 'plane.set' ], function(e) {
6396
+ eventBus.on([ 'diagram.clear', 'root.set' ], function(e) {
6351
6397
  self.select(null);
6352
6398
  });
6353
6399
  }
@@ -6400,10 +6446,12 @@
6400
6446
 
6401
6447
  var canvas = this._canvas;
6402
6448
 
6449
+ var rootElement = canvas.getRootElement();
6450
+
6403
6451
  elements = elements.filter(function(element) {
6404
- var plane = canvas.findPlane(element);
6452
+ var elementRoot = canvas.findRoot(element);
6405
6453
 
6406
- return plane === canvas.getActivePlane();
6454
+ return rootElement === elementRoot;
6407
6455
  });
6408
6456
 
6409
6457
  // selection may be cleared by passing an empty array or null
@@ -6644,7 +6692,7 @@
6644
6692
  // document wide unique overlay ids
6645
6693
  var ids = new IdGenerator('ov');
6646
6694
 
6647
- var LOW_PRIORITY$1 = 500;
6695
+ var LOW_PRIORITY$2 = 500;
6648
6696
 
6649
6697
 
6650
6698
  /**
@@ -6874,8 +6922,7 @@
6874
6922
  *
6875
6923
  * @see Overlays#get for filter options.
6876
6924
  *
6877
- * @param {string} [id]
6878
- * @param {Object} [filter]
6925
+ * @param {string|object} [filter]
6879
6926
  */
6880
6927
  Overlays.prototype.remove = function(filter) {
6881
6928
 
@@ -6991,6 +7038,7 @@
6991
7038
  }
6992
7039
 
6993
7040
  setPosition(htmlContainer, left || 0, top || 0);
7041
+ this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
6994
7042
  };
6995
7043
 
6996
7044
 
@@ -7074,12 +7122,10 @@
7074
7122
  classes(htmlContainer).add('djs-overlay-' + overlay.type);
7075
7123
  }
7076
7124
 
7077
- var plane = this._canvas.findPlane(element);
7078
- var activePlane = this._canvas.getActivePlane();
7079
- overlay.plane = plane;
7080
- if (plane !== activePlane) {
7081
- setVisible(htmlContainer, false);
7082
- }
7125
+ var elementRoot = this._canvas.findRoot(element);
7126
+ var activeRoot = this._canvas.getRootElement();
7127
+
7128
+ setVisible(htmlContainer, elementRoot === activeRoot);
7083
7129
 
7084
7130
  overlay.htmlContainer = htmlContainer;
7085
7131
 
@@ -7095,14 +7141,14 @@
7095
7141
 
7096
7142
  Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
7097
7143
  var show = overlay.show,
7098
- plane = overlay.plane,
7144
+ rootElement = this._canvas.findRoot(overlay.element),
7099
7145
  minZoom = show && show.minZoom,
7100
7146
  maxZoom = show && show.maxZoom,
7101
7147
  htmlContainer = overlay.htmlContainer,
7102
- activePlane = this._canvas.getActivePlane(),
7148
+ activeRootElement = this._canvas.getRootElement(),
7103
7149
  visible = true;
7104
7150
 
7105
- if (plane !== activePlane) {
7151
+ if (rootElement !== activeRootElement) {
7106
7152
  visible = false;
7107
7153
  } else if (show) {
7108
7154
  if (
@@ -7213,7 +7259,7 @@
7213
7259
 
7214
7260
  // move integration
7215
7261
 
7216
- eventBus.on('element.changed', LOW_PRIORITY$1, function(e) {
7262
+ eventBus.on('element.changed', LOW_PRIORITY$2, function(e) {
7217
7263
  var element = e.element;
7218
7264
 
7219
7265
  var container = self._getOverlayContainer(element, true);
@@ -7238,10 +7284,8 @@
7238
7284
  });
7239
7285
 
7240
7286
 
7241
- eventBus.on('plane.set', function(e) {
7242
- forEach(self._overlays, function(el) {
7243
- setVisible(el.htmlContainer, el.plane === e.plane);
7244
- });
7287
+ eventBus.on('root.set', function() {
7288
+ self._updateOverlaysVisibilty(self._canvas.viewbox());
7245
7289
  });
7246
7290
 
7247
7291
  // clear overlays with diagram
@@ -7354,6 +7398,181 @@
7354
7398
  changeSupport: [ 'type', ChangeSupport ]
7355
7399
  };
7356
7400
 
7401
+ var DEFAULT_PRIORITY$2 = 1000;
7402
+
7403
+ /**
7404
+ * A utility that can be used to plug-in into the command execution for
7405
+ * extension and/or validation.
7406
+ *
7407
+ * @param {EventBus} eventBus
7408
+ *
7409
+ * @example
7410
+ *
7411
+ * import inherits from 'inherits';
7412
+ *
7413
+ * import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
7414
+ *
7415
+ * function CommandLogger(eventBus) {
7416
+ * CommandInterceptor.call(this, eventBus);
7417
+ *
7418
+ * this.preExecute(function(event) {
7419
+ * console.log('command pre-execute', event);
7420
+ * });
7421
+ * }
7422
+ *
7423
+ * inherits(CommandLogger, CommandInterceptor);
7424
+ *
7425
+ */
7426
+ function CommandInterceptor(eventBus) {
7427
+ this._eventBus = eventBus;
7428
+ }
7429
+
7430
+ CommandInterceptor.$inject = [ 'eventBus' ];
7431
+
7432
+ function unwrapEvent(fn, that) {
7433
+ return function(event) {
7434
+ return fn.call(that || null, event.context, event.command, event);
7435
+ };
7436
+ }
7437
+
7438
+ /**
7439
+ * Register an interceptor for a command execution
7440
+ *
7441
+ * @param {string|Array<string>} [events] list of commands to register on
7442
+ * @param {string} [hook] command hook, i.e. preExecute, executed to listen on
7443
+ * @param {number} [priority] the priority on which to hook into the execution
7444
+ * @param {Function} handlerFn interceptor to be invoked with (event)
7445
+ * @param {boolean} unwrap if true, unwrap the event and pass (context, command, event) to the
7446
+ * listener instead
7447
+ * @param {Object} [that] Pass context (`this`) to the handler function
7448
+ */
7449
+ CommandInterceptor.prototype.on = function(events, hook, priority, handlerFn, unwrap, that) {
7450
+
7451
+ if (isFunction(hook) || isNumber(hook)) {
7452
+ that = unwrap;
7453
+ unwrap = handlerFn;
7454
+ handlerFn = priority;
7455
+ priority = hook;
7456
+ hook = null;
7457
+ }
7458
+
7459
+ if (isFunction(priority)) {
7460
+ that = unwrap;
7461
+ unwrap = handlerFn;
7462
+ handlerFn = priority;
7463
+ priority = DEFAULT_PRIORITY$2;
7464
+ }
7465
+
7466
+ if (isObject(unwrap)) {
7467
+ that = unwrap;
7468
+ unwrap = false;
7469
+ }
7470
+
7471
+ if (!isFunction(handlerFn)) {
7472
+ throw new Error('handlerFn must be a function');
7473
+ }
7474
+
7475
+ if (!isArray$1(events)) {
7476
+ events = [ events ];
7477
+ }
7478
+
7479
+ var eventBus = this._eventBus;
7480
+
7481
+ forEach(events, function(event) {
7482
+
7483
+ // concat commandStack(.event)?(.hook)?
7484
+ var fullEvent = [ 'commandStack', event, hook ].filter(function(e) { return e; }).join('.');
7485
+
7486
+ eventBus.on(fullEvent, priority, unwrap ? unwrapEvent(handlerFn, that) : handlerFn, that);
7487
+ });
7488
+ };
7489
+
7490
+
7491
+ var hooks = [
7492
+ 'canExecute',
7493
+ 'preExecute',
7494
+ 'preExecuted',
7495
+ 'execute',
7496
+ 'executed',
7497
+ 'postExecute',
7498
+ 'postExecuted',
7499
+ 'revert',
7500
+ 'reverted'
7501
+ ];
7502
+
7503
+ /*
7504
+ * Install hook shortcuts
7505
+ *
7506
+ * This will generate the CommandInterceptor#(preExecute|...|reverted) methods
7507
+ * which will in term forward to CommandInterceptor#on.
7508
+ */
7509
+ forEach(hooks, function(hook) {
7510
+
7511
+ /**
7512
+ * {canExecute|preExecute|preExecuted|execute|executed|postExecute|postExecuted|revert|reverted}
7513
+ *
7514
+ * A named hook for plugging into the command execution
7515
+ *
7516
+ * @param {string|Array<string>} [events] list of commands to register on
7517
+ * @param {number} [priority] the priority on which to hook into the execution
7518
+ * @param {Function} handlerFn interceptor to be invoked with (event)
7519
+ * @param {boolean} [unwrap=false] if true, unwrap the event and pass (context, command, event) to the
7520
+ * listener instead
7521
+ * @param {Object} [that] Pass context (`this`) to the handler function
7522
+ */
7523
+ CommandInterceptor.prototype[hook] = function(events, priority, handlerFn, unwrap, that) {
7524
+
7525
+ if (isFunction(events) || isNumber(events)) {
7526
+ that = unwrap;
7527
+ unwrap = handlerFn;
7528
+ handlerFn = priority;
7529
+ priority = events;
7530
+ events = null;
7531
+ }
7532
+
7533
+ this.on(events, hook, priority, handlerFn, unwrap, that);
7534
+ };
7535
+ });
7536
+
7537
+ /**
7538
+ * A modeling behavior that ensures we set the correct root element
7539
+ * as we undo and redo commands.
7540
+ *
7541
+ * @param {Canvas} canvas
7542
+ * @param {didi.Injector} injector
7543
+ */
7544
+ function RootElementsBehavior(canvas, injector) {
7545
+
7546
+ injector.invoke(CommandInterceptor, this);
7547
+
7548
+ this.executed(function(event) {
7549
+ var context = event.context;
7550
+
7551
+ if (context.rootElement) {
7552
+ canvas.setRootElement(context.rootElement);
7553
+ } else {
7554
+ context.rootElement = canvas.getRootElement();
7555
+ }
7556
+ });
7557
+
7558
+ this.revert(function(event) {
7559
+ var context = event.context;
7560
+
7561
+ if (context.rootElement) {
7562
+ canvas.setRootElement(context.rootElement);
7563
+ }
7564
+ });
7565
+ }
7566
+
7567
+ inherits$1(RootElementsBehavior, CommandInterceptor);
7568
+
7569
+ RootElementsBehavior.$inject = [ 'canvas', 'injector'];
7570
+
7571
+ var RootElementsModule = {
7572
+ __init__: [ 'rootElementsBehavior' ],
7573
+ rootElementsBehavior: [ 'type', RootElementsBehavior ]
7574
+ };
7575
+
7357
7576
  var css_escape = {exports: {}};
7358
7577
 
7359
7578
  /*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
@@ -7476,39 +7695,94 @@
7476
7695
  });
7477
7696
  }
7478
7697
 
7479
- var ARROW_DOWN_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M4.81801948,3.50735931 L10.4996894,9.1896894 L10.5,4 L12,4 L12,12 L4,12 L4,10.5 L9.6896894,10.4996894 L3.75735931,4.56801948 C3.46446609,4.27512627 3.46446609,3.80025253 3.75735931,3.50735931 C4.05025253,3.21446609 4.52512627,3.21446609 4.81801948,3.50735931 Z"/></svg>';
7698
+ var planeSuffix = '_plane';
7699
+
7700
+ /**
7701
+ * Get plane ID for a primary shape.
7702
+ *
7703
+ * @param {djs.model.Base|ModdleElement} element
7704
+ *
7705
+ * @returns {String}
7706
+ */
7707
+ function getPlaneIdFromShape(element) {
7708
+ var id = element.id;
7709
+
7710
+ if (is$1(element, 'bpmn:SubProcess')) {
7711
+ return addPlaneSuffix(id);
7712
+ }
7713
+
7714
+ return id;
7715
+ }
7716
+
7717
+ function addPlaneSuffix(id) {
7718
+ return id + planeSuffix;
7719
+ }
7480
7720
 
7481
7721
  var OPEN_CLASS = 'bjs-breadcrumbs-shown';
7482
7722
 
7723
+
7483
7724
  /**
7484
- * Adds Overlays that allow switching planes on collapsed subprocesses.
7725
+ * Adds overlays that allow switching planes on collapsed subprocesses.
7485
7726
  *
7486
7727
  * @param {eventBus} eventBus
7487
7728
  * @param {elementRegistry} elementRegistry
7488
7729
  * @param {overlays} overlays
7489
7730
  * @param {canvas} canvas
7490
7731
  */
7491
- function DrilldownOverlays(eventBus, elementRegistry, overlays, canvas) {
7732
+ function DrilldownBreadcrumbs(eventBus, elementRegistry, overlays, canvas) {
7492
7733
  var breadcrumbs = domify('<ul class="bjs-breadcrumbs"></ul>');
7493
7734
  var container = canvas.getContainer();
7494
7735
  var containerClasses = classes(container);
7495
7736
  container.appendChild(breadcrumbs);
7496
7737
 
7497
- function updateBreadcrumbs(plane) {
7498
- var subProcess = elementRegistry.get(plane.name);
7499
- var parents = getParentChain(subProcess);
7738
+ var boParents = [];
7739
+
7740
+ // update breadcrumbs if name or ID of the primary shape changes
7741
+ eventBus.on('element.changed', function(e) {
7742
+ var shape = e.element,
7743
+ bo = getBusinessObject(shape);
7744
+
7745
+ var isPresent = find(boParents, function(el) {
7746
+ return el === bo;
7747
+ });
7500
7748
 
7501
- var path = parents.map(function(el) {
7502
- var title = escapeHTML(el.name || el.id);
7749
+ if (!isPresent) {
7750
+ return;
7751
+ }
7752
+
7753
+ updateBreadcrumbs();
7754
+ });
7755
+
7756
+ /**
7757
+ * Updates the displayed breadcrumbs. If no element is provided, only the
7758
+ * labels are updated.
7759
+ *
7760
+ * @param {djs.model.Base} [element]
7761
+ */
7762
+ function updateBreadcrumbs(element) {
7763
+ if (element) {
7764
+ boParents = getBoParentChain(element);
7765
+ }
7766
+
7767
+ var path = boParents.map(function(parent) {
7768
+ var title = escapeHTML(parent.name || parent.id);
7503
7769
  var link = domify('<li><span class="bjs-crumb"><a title="' + title + '">' + title + '</a></span></li>');
7504
7770
 
7771
+ var parentPlane = canvas.findRoot(getPlaneIdFromShape(parent)) || canvas.findRoot(parent.id);
7772
+
7773
+ // when the root is a collaboration, the process does not have a corresponding
7774
+ // element in the elementRegisty. Instead, we search for the corresponding participant
7775
+ if (!parentPlane && is$1(parent, 'bpmn:Process')) {
7776
+ var participant = elementRegistry.find(function(element) {
7777
+ var bo = getBusinessObject(element);
7778
+ return bo && bo.processRef && bo.processRef === parent;
7779
+ });
7780
+
7781
+ parentPlane = canvas.findRoot(participant.id);
7782
+ }
7783
+
7505
7784
  link.addEventListener('click', function() {
7506
- if (canvas.getPlane(el.id)) {
7507
- canvas.setActivePlane(el.id);
7508
- } else {
7509
- var plane = canvas.findPlane(el.id);
7510
- canvas.setActivePlane(plane);
7511
- }
7785
+ canvas.setRootElement(parentPlane);
7512
7786
  });
7513
7787
 
7514
7788
  return link;
@@ -7525,50 +7799,26 @@
7525
7799
  });
7526
7800
  }
7527
7801
 
7528
- eventBus.on('plane.set', function(event) {
7529
- var plane = event.plane;
7530
-
7531
- updateBreadcrumbs(plane);
7802
+ eventBus.on('root.set', function(event) {
7803
+ updateBreadcrumbs(event.element);
7532
7804
  });
7533
7805
 
7534
- var createOverlay = function(element) {
7535
- var html = domify('<button class="bjs-drilldown">' + ARROW_DOWN_SVG + '</button>');
7536
-
7537
- html.addEventListener('click', function() {
7538
- canvas.setActivePlane(element.id);
7539
- });
7540
-
7541
- overlays.add(element, {
7542
- position: {
7543
- bottom: -7,
7544
- right: -8
7545
- },
7546
- html: html
7547
- });
7548
- };
7549
-
7550
- var addOverlays = function(elements) {
7551
- elements.forEach(function(element) {
7552
- if (is$1(element, 'bpmn:SubProcess')
7553
- && element.collapsed
7554
- && canvas.getPlane(element.id)) {
7555
- createOverlay(element);
7556
- }
7557
- });
7558
- };
7559
-
7560
- eventBus.on('import.done', function() {
7561
- addOverlays(elementRegistry.filter(function(el) {
7562
- return is$1(el, 'bpmn:SubProcess');
7563
- }));
7564
- });
7565
7806
  }
7566
7807
 
7567
- DrilldownOverlays.$inject = [ 'eventBus', 'elementRegistry', 'overlays', 'canvas' ];
7808
+ DrilldownBreadcrumbs.$inject = [ 'eventBus', 'elementRegistry', 'overlays', 'canvas' ];
7568
7809
 
7569
7810
 
7570
- // helpers
7571
- var getParentChain = function(child) {
7811
+ // helpers //////////
7812
+
7813
+ /**
7814
+ * Returns the parents for the element using the business object chain,
7815
+ * starting with the root element.
7816
+ *
7817
+ * @param {djs.model.Shape} child
7818
+ *
7819
+ * @returns {Array<djs.model.Shape>} parents
7820
+ */
7821
+ function getBoParentChain(child) {
7572
7822
  var bo = getBusinessObject(child);
7573
7823
 
7574
7824
  var parents = [];
@@ -7580,29 +7830,40 @@
7580
7830
  }
7581
7831
 
7582
7832
  return parents.reverse();
7583
- };
7833
+ }
7584
7834
 
7585
7835
  /**
7586
- * Move collapsed subprocesses into view when drilling down. Zoom and scroll
7587
- * are saved in a session.
7836
+ * Move collapsed subprocesses into view when drilling down.
7837
+ *
7838
+ * Zoom and scroll are saved in a session.
7588
7839
  *
7589
7840
  * @param {eventBus} eventBus
7590
7841
  * @param {canvas} canvas
7591
7842
  */
7592
7843
  function DrilldownCentering(eventBus, canvas) {
7593
- var currentPlane = 'base';
7594
- var positionMap = {};
7595
7844
 
7596
- eventBus.on('plane.set', function(event) {
7845
+ var currentRoot = null;
7846
+ var positionMap = new Map();
7847
+
7848
+ eventBus.on('root.set', function(event) {
7849
+ var newRoot = event.element;
7597
7850
  var currentViewbox = canvas.viewbox();
7598
- positionMap[currentPlane] = {
7851
+ var storedViewbox = positionMap.get(newRoot);
7852
+
7853
+ positionMap.set(currentRoot, {
7599
7854
  x: currentViewbox.x,
7600
7855
  y: currentViewbox.y,
7601
7856
  zoom: currentViewbox.scale
7602
- };
7857
+ });
7603
7858
 
7604
- var planeId = event.plane.name;
7605
- var storedViewbox = positionMap[planeId] || { x: 0, y: 0, zoom: 1 };
7859
+ currentRoot = newRoot;
7860
+
7861
+ // current root was replaced with a collaboration, we don't update the viewbox
7862
+ if (is$1(newRoot, 'bpmn:Collaboration') && !storedViewbox) {
7863
+ return;
7864
+ }
7865
+
7866
+ storedViewbox = storedViewbox || { x: 0, y: 0, zoom: 1 };
7606
7867
 
7607
7868
  var dx = (currentViewbox.x - storedViewbox.x) * currentViewbox.scale,
7608
7869
  dy = (currentViewbox.y - storedViewbox.y) * currentViewbox.scale;
@@ -7617,13 +7878,77 @@
7617
7878
  if (storedViewbox.zoom !== currentViewbox.scale) {
7618
7879
  canvas.zoom(storedViewbox.zoom, { x: 0, y: 0 });
7619
7880
  }
7881
+ });
7620
7882
 
7621
- currentPlane = planeId;
7883
+ eventBus.on('diagram.clear', function() {
7884
+ positionMap.clear();
7885
+ currentRoot = null;
7622
7886
  });
7887
+
7623
7888
  }
7624
7889
 
7625
7890
  DrilldownCentering.$inject = [ 'eventBus', 'canvas' ];
7626
7891
 
7892
+
7893
+ /**
7894
+ * ES5 Map implementation. Works.
7895
+ */
7896
+ function Map() {
7897
+
7898
+ this._entries = [];
7899
+
7900
+ this.set = function(key, value) {
7901
+
7902
+ var found = false;
7903
+
7904
+ for (var k in this._entries) {
7905
+ if (this._entries[k][0] === key) {
7906
+ this._entries[k][1] = value;
7907
+
7908
+ found = true;
7909
+
7910
+ break;
7911
+ }
7912
+ }
7913
+
7914
+ if (!found) {
7915
+ this._entries.push([ key, value ]);
7916
+ }
7917
+ };
7918
+
7919
+ this.get = function(key) {
7920
+
7921
+ for (var k in this._entries) {
7922
+ if (this._entries[k][0] === key) {
7923
+ return this._entries[k][1];
7924
+ }
7925
+ }
7926
+
7927
+ return null;
7928
+ };
7929
+
7930
+ this.clear = function() {
7931
+ this._entries.length = 0;
7932
+ };
7933
+
7934
+ this.remove = function(key) {
7935
+
7936
+ var idx = -1;
7937
+
7938
+ for (var k in this._entries) {
7939
+ if (this._entries[k][0] === key) {
7940
+ idx = k;
7941
+
7942
+ break;
7943
+ }
7944
+ }
7945
+
7946
+ if (idx !== -1) {
7947
+ this._entries.splice(idx, 1);
7948
+ }
7949
+ };
7950
+ }
7951
+
7627
7952
  var DEFAULT_POSITION = {
7628
7953
  x: 180,
7629
7954
  y: 160
@@ -7690,6 +8015,11 @@
7690
8015
 
7691
8016
  plane.get('planeElement').forEach(function(diElement) {
7692
8017
  var bo = diElement.bpmnElement;
8018
+
8019
+ if (!bo) {
8020
+ return;
8021
+ }
8022
+
7693
8023
  var parent = bo.$parent;
7694
8024
 
7695
8025
  if (is$1(bo, 'bpmn:SubProcess') && !diElement.isExpanded) {
@@ -7705,12 +8035,21 @@
7705
8035
 
7706
8036
  var newDiagrams = [];
7707
8037
 
8038
+ // create new planes for all collapsed subprocesses, even when they are empty
8039
+ collapsedElements.forEach(function(element) {
8040
+ if (!self._processToDiagramMap[element.id]) {
8041
+ var diagram = self.createDiagram(element);
8042
+ self._processToDiagramMap[element.id] = diagram;
8043
+ newDiagrams.push(diagram);
8044
+ }
8045
+ });
8046
+
7708
8047
  elementsToMove.forEach(function(element) {
7709
8048
  var diElement = element.diElement;
7710
8049
  var parent = element.parent;
7711
8050
 
7712
8051
  // parent is expanded, get nearest collapsed parent
7713
- while (parent && !collapsedElements.includes(parent)) {
8052
+ while (parent && collapsedElements.indexOf(parent) === -1) {
7714
8053
  parent = parent.$parent;
7715
8054
  }
7716
8055
 
@@ -7720,12 +8059,6 @@
7720
8059
  }
7721
8060
 
7722
8061
  var diagram = self._processToDiagramMap[parent.id];
7723
- if (!diagram) {
7724
- diagram = self.createDiagram(parent);
7725
- self._processToDiagramMap[parent.id] = diagram;
7726
- newDiagrams.push(diagram);
7727
- }
7728
-
7729
8062
  self.moveToDiPlane(diElement, diagram.plane);
7730
8063
  });
7731
8064
 
@@ -7792,33 +8125,209 @@
7792
8125
  }
7793
8126
  }
7794
8127
 
7795
- function getPlaneBounds(plane) {
7796
- var planeTrbl = {
7797
- top: Infinity,
7798
- right: -Infinity,
7799
- bottom: -Infinity,
7800
- left: Infinity
7801
- };
8128
+ function getPlaneBounds(plane) {
8129
+ var planeTrbl = {
8130
+ top: Infinity,
8131
+ right: -Infinity,
8132
+ bottom: -Infinity,
8133
+ left: Infinity
8134
+ };
8135
+
8136
+ plane.planeElement.forEach(function(element) {
8137
+ if (!element.bounds) {
8138
+ return;
8139
+ }
8140
+
8141
+ var trbl = asTRBL(element.bounds);
8142
+
8143
+ planeTrbl.top = Math.min(trbl.top, planeTrbl.top);
8144
+ planeTrbl.left = Math.min(trbl.left, planeTrbl.left);
8145
+ });
8146
+
8147
+ return asBounds(planeTrbl);
8148
+ }
8149
+
8150
+ var LOW_PRIORITY$1 = 250;
8151
+ var ARROW_DOWN_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M4.81801948,3.50735931 L10.4996894,9.1896894 L10.5,4 L12,4 L12,12 L4,12 L4,10.5 L9.6896894,10.4996894 L3.75735931,4.56801948 C3.46446609,4.27512627 3.46446609,3.80025253 3.75735931,3.50735931 C4.05025253,3.21446609 4.52512627,3.21446609 4.81801948,3.50735931 Z"/></svg>';
8152
+
8153
+ var EMPTY_MARKER = 'bjs-drilldown-empty';
8154
+
8155
+ function DrilldownOverlayBehavior(
8156
+ canvas, eventBus, elementRegistry, overlays
8157
+ ) {
8158
+ CommandInterceptor.call(this, eventBus);
8159
+
8160
+ this._canvas = canvas;
8161
+ this._eventBus = eventBus;
8162
+ this._elementRegistry = elementRegistry;
8163
+ this._overlays = overlays;
8164
+
8165
+ var self = this;
8166
+
8167
+ this.executed('shape.toggleCollapse', LOW_PRIORITY$1, function(context) {
8168
+ var shape = context.shape;
8169
+
8170
+ // Add overlay to the collapsed shape
8171
+ if (self.canDrillDown(shape)) {
8172
+ self.addOverlay(shape);
8173
+ } else {
8174
+ self.removeOverlay(shape);
8175
+ }
8176
+ }, true);
8177
+
8178
+
8179
+ this.reverted('shape.toggleCollapse', LOW_PRIORITY$1, function(context) {
8180
+ var shape = context.shape;
8181
+
8182
+ // Add overlay to the collapsed shape
8183
+ if (self.canDrillDown(shape)) {
8184
+ self.addOverlay(shape);
8185
+ } else {
8186
+ self.removeOverlay(shape);
8187
+ }
8188
+ }, true);
8189
+
8190
+
8191
+ this.executed(['shape.create', 'shape.move', 'shape.delete'], LOW_PRIORITY$1,
8192
+ function(context) {
8193
+ var oldParent = context.oldParent,
8194
+ newParent = context.newParent || context.parent,
8195
+ shape = context.shape;
8196
+
8197
+ // Add overlay to the collapsed shape
8198
+ if (self.canDrillDown(shape)) {
8199
+ self.addOverlay(shape);
8200
+ }
8201
+
8202
+ self.updateDrilldownOverlay(oldParent);
8203
+ self.updateDrilldownOverlay(newParent);
8204
+ self.updateDrilldownOverlay(shape);
8205
+ }, true);
8206
+
8207
+
8208
+ this.reverted(['shape.create', 'shape.move', 'shape.delete'], LOW_PRIORITY$1,
8209
+ function(context) {
8210
+ var oldParent = context.oldParent,
8211
+ newParent = context.newParent || context.parent,
8212
+ shape = context.shape;
8213
+
8214
+ // Add overlay to the collapsed shape
8215
+ if (self.canDrillDown(shape)) {
8216
+ self.addOverlay(shape);
8217
+ }
8218
+
8219
+ self.updateDrilldownOverlay(oldParent);
8220
+ self.updateDrilldownOverlay(newParent);
8221
+ self.updateDrilldownOverlay(shape);
8222
+ }, true);
8223
+
8224
+
8225
+ eventBus.on('import.done', function() {
8226
+ elementRegistry.filter(function(e) {
8227
+ return self.canDrillDown(e);
8228
+ }).map(function(el) {
8229
+ self.addOverlay(el);
8230
+ });
8231
+ });
8232
+
8233
+ }
8234
+
8235
+ inherits$1(DrilldownOverlayBehavior, CommandInterceptor);
8236
+
8237
+ DrilldownOverlayBehavior.prototype.updateDrilldownOverlay = function(shape) {
8238
+ var canvas = this._canvas;
8239
+
8240
+ if (!shape) {
8241
+ return;
8242
+ }
8243
+
8244
+ var root = canvas.findRoot(shape);
8245
+ if (root) {
8246
+ this.updateOverlayVisibility(root);
8247
+ }
8248
+ };
8249
+
8250
+
8251
+ DrilldownOverlayBehavior.prototype.canDrillDown = function(element) {
8252
+ var canvas = this._canvas;
8253
+ return is$1(element, 'bpmn:SubProcess') && canvas.findRoot(getPlaneIdFromShape(element));
8254
+ };
8255
+
8256
+ /**
8257
+ * Updates visibility of the drilldown overlay. If the plane has no elements,
8258
+ * the drilldown will be only shown when the element is selected.
8259
+ *
8260
+ * @param {djs.model.Shape|djs.model.Root} element collapsed shape or root element
8261
+ */
8262
+ DrilldownOverlayBehavior.prototype.updateOverlayVisibility = function(element) {
8263
+ var overlays = this._overlays;
8264
+
8265
+ var bo = element.businessObject;
8266
+
8267
+ var overlay = overlays.get({ element: bo.id, type: 'drilldown' })[0];
8268
+
8269
+ if (!overlay) {
8270
+ return;
8271
+ }
8272
+
8273
+ var hasContent = bo && bo.flowElements && bo.flowElements.length;
8274
+ classes(overlay.html).toggle(EMPTY_MARKER, !hasContent);
8275
+ };
8276
+
8277
+ /**
8278
+ * Attaches a drilldown button to the given element. We assume that the plane has
8279
+ * the same id as the element.
8280
+ *
8281
+ * @param {djs.model.Shape} element collapsed shape
8282
+ */
8283
+ DrilldownOverlayBehavior.prototype.addOverlay = function(element) {
8284
+ var canvas = this._canvas;
8285
+ var overlays = this._overlays;
8286
+
8287
+ var existingOverlays = overlays.get({ element: element, type: 'drilldown' });
8288
+ if (existingOverlays.length) {
8289
+ this.removeOverlay(element);
8290
+ }
8291
+
8292
+ var button = domify('<button class="bjs-drilldown">' + ARROW_DOWN_SVG + '</button>');
7802
8293
 
7803
- plane.planeElement.forEach(function(element) {
7804
- if (!element.bounds) {
7805
- return;
7806
- }
8294
+ button.addEventListener('click', function() {
8295
+ canvas.setRootElement(canvas.findRoot(getPlaneIdFromShape(element)));
8296
+ });
7807
8297
 
7808
- var trbl = asTRBL(element.bounds);
8298
+ overlays.add(element, 'drilldown', {
8299
+ position: {
8300
+ bottom: -7,
8301
+ right: -8
8302
+ },
8303
+ html: button
8304
+ });
7809
8305
 
7810
- planeTrbl.top = Math.min(trbl.top, planeTrbl.top);
7811
- planeTrbl.left = Math.min(trbl.left, planeTrbl.left);
8306
+ this.updateOverlayVisibility(element);
8307
+ };
8308
+
8309
+ DrilldownOverlayBehavior.prototype.removeOverlay = function(element) {
8310
+ var overlays = this._overlays;
8311
+
8312
+ overlays.remove({
8313
+ element: element,
8314
+ type: 'drilldown'
7812
8315
  });
8316
+ };
7813
8317
 
7814
- return asBounds(planeTrbl);
7815
- }
8318
+ DrilldownOverlayBehavior.$inject = [
8319
+ 'canvas',
8320
+ 'eventBus',
8321
+ 'elementRegistry',
8322
+ 'overlays'
8323
+ ];
7816
8324
 
7817
8325
  var DrilldownModdule = {
7818
- __depends__: [ OverlaysModule, ChangeSupportModule ],
7819
- __init__: [ 'drilldownOverlays', 'drilldownCentering', 'subprocessCompatibility'],
7820
- drilldownOverlays: [ 'type', DrilldownOverlays ],
8326
+ __depends__: [ OverlaysModule, ChangeSupportModule, RootElementsModule ],
8327
+ __init__: [ 'drilldownBreadcrumbs', 'drilldownOverlayBehavior', 'drilldownCentering', 'subprocessCompatibility'],
8328
+ drilldownBreadcrumbs: [ 'type', DrilldownBreadcrumbs ],
7821
8329
  drilldownCentering: [ 'type', DrilldownCentering ],
8330
+ drilldownOverlayBehavior: [ 'type', DrilldownOverlayBehavior ],
7822
8331
  subprocessCompatibility: [ 'type', SubprocessCompatibility ]
7823
8332
  };
7824
8333
 
@@ -8459,7 +8968,6 @@
8459
8968
  }
8460
8969
 
8461
8970
  var BASE_LAYER = 'base';
8462
- var HIDDEN_MARKER = 'djs-element-hidden';
8463
8971
 
8464
8972
  // render plane contents behind utility layers
8465
8973
  var PLANE_LAYER_INDEX = 0;
@@ -8490,6 +8998,12 @@
8490
8998
  this._elementRegistry = elementRegistry;
8491
8999
  this._graphicsFactory = graphicsFactory;
8492
9000
 
9001
+ this._rootsIdx = 0;
9002
+
9003
+ this._layers = {};
9004
+ this._planes = [];
9005
+ this._rootElement = null;
9006
+
8493
9007
  this._init(config || {});
8494
9008
  }
8495
9009
 
@@ -8527,9 +9041,6 @@
8527
9041
 
8528
9042
  var viewport = this._viewport = createGroup(svg, 'viewport');
8529
9043
 
8530
- this._layers = {};
8531
- this._planes = {};
8532
-
8533
9044
  // debounce canvas.viewbox.changed events
8534
9045
  // for smoother diagram interaction
8535
9046
  if (config.deferUpdate !== false) {
@@ -8564,7 +9075,7 @@
8564
9075
  'shape.removed',
8565
9076
  'connection.removed',
8566
9077
  'elements.changed',
8567
- 'plane.set'
9078
+ 'root.set'
8568
9079
  ], function() {
8569
9080
  delete this._cachedViewbox;
8570
9081
  }, this);
@@ -8589,7 +9100,7 @@
8589
9100
  delete this._container;
8590
9101
  delete this._layers;
8591
9102
  delete this._planes;
8592
- delete this._activePlane;
9103
+ delete this._rootElement;
8593
9104
  delete this._viewport;
8594
9105
  };
8595
9106
 
@@ -8604,15 +9115,15 @@
8604
9115
  var type = getType(element);
8605
9116
 
8606
9117
  if (type === 'root') {
8607
- self.setRootElementForPlane(null, self.findPlane(element), true);
9118
+ self.removeRootElement(element);
8608
9119
  } else {
8609
9120
  self._removeElement(element, type);
8610
9121
  }
8611
9122
  });
8612
9123
 
8613
9124
  // remove all planes
8614
- this._activePlane = null;
8615
- this._planes = {};
9125
+ this._planes = [];
9126
+ this._rootElement = null;
8616
9127
 
8617
9128
  // force recomputation of view box
8618
9129
  delete this._cachedViewbox;
@@ -8693,140 +9204,75 @@
8693
9204
 
8694
9205
  };
8695
9206
 
8696
- /**
8697
- * Returns a plane that is used to draw elements on it.
8698
- *
8699
- * @param {string} name
8700
- *
8701
- * @return {Object} plane descriptor with { layer, rootElement, name }
8702
- */
8703
- Canvas.prototype.getPlane = function(name) {
8704
- if (!name) {
8705
- throw new Error('must specify a name');
8706
- }
8707
-
8708
- return this._planes[name];
8709
- };
8710
-
8711
- /**
8712
- * Creates a plane that is used to draw elements on it. If no
8713
- * root element is provided, an implicit root will be used.
8714
- *
8715
- * @param {string} name
8716
- * @param {Object|djs.model.Root} [rootElement] optional root element
8717
- *
8718
- * @return {Object} plane descriptor with { layer, rootElement, name }
8719
- */
8720
- Canvas.prototype.createPlane = function(name, rootElement) {
8721
- if (!name) {
8722
- throw new Error('must specify a name');
8723
- }
8724
-
8725
- if (this._planes[name]) {
8726
- throw new Error('plane ' + name + ' already exists');
8727
- }
8728
-
8729
- if (!rootElement) {
8730
- rootElement = {
8731
- id: '__implicitroot' + name,
8732
- children: [],
8733
- isImplicit: true
8734
- };
8735
- }
8736
-
8737
- var svgLayer = this.getLayer(name, PLANE_LAYER_INDEX);
8738
- classes$1(svgLayer).add(HIDDEN_MARKER);
8739
-
8740
- var plane = this._planes[name] = {
8741
- layer: svgLayer,
8742
- name: name,
8743
- rootElement: null
8744
- };
8745
-
8746
- this.setRootElementForPlane(rootElement, plane);
8747
-
8748
- return plane;
8749
- };
8750
-
8751
- /**
8752
- * Sets the active plane and hides the previously active plane.
8753
- *
8754
- * @param {string|Object} plane
8755
- *
8756
- * @return {Object} plane descriptor with { layer, rootElement, name }
8757
- */
8758
- Canvas.prototype.setActivePlane = function(plane) {
8759
- if (!plane) {
8760
- throw new Error('must specify a plane');
8761
- }
8762
-
8763
- if (typeof plane === 'string') {
8764
- plane = this.getPlane(plane);
8765
- }
8766
9207
 
8767
- // hide previous Plane
8768
- if (this._activePlane) {
8769
- classes$1(this._activePlane.layer).add(HIDDEN_MARKER);
8770
- }
9208
+ Canvas.prototype._removeLayer = function(name) {
8771
9209
 
8772
- this._activePlane = plane;
9210
+ var layer = this._layers[name];
8773
9211
 
8774
- // show current Plane
8775
- classes$1(plane.layer).remove(HIDDEN_MARKER);
9212
+ if (layer) {
9213
+ delete this._layers[name];
8776
9214
 
8777
- if (plane.rootElement) {
8778
- this._elementRegistry.updateGraphics(plane.rootElement, this._svg, true);
9215
+ remove$2(layer.group);
8779
9216
  }
8780
-
8781
- this._eventBus.fire('plane.set', { plane: plane });
8782
-
8783
- return plane;
8784
9217
  };
8785
9218
 
8786
9219
  /**
8787
- * Returns the currently active layer
9220
+ * Returns the currently active layer. Can be null.
8788
9221
  *
8789
- * @returns {SVGElement}
9222
+ * @returns {SVGElement|null}
8790
9223
  */
8791
-
8792
9224
  Canvas.prototype.getActiveLayer = function() {
8793
- return this.getActivePlane().layer;
8794
- };
9225
+ var plane = this._findPlaneForRoot(this.getRootElement());
8795
9226
 
8796
- /**
8797
- * Returns the currently active plane.
8798
- *
8799
- * @return {Object} plane descriptor with { layer, rootElement, name }
8800
- */
8801
- Canvas.prototype.getActivePlane = function() {
8802
- var plane = this._activePlane;
8803
9227
  if (!plane) {
8804
- plane = this.createPlane(BASE_LAYER);
8805
- this.setActivePlane(BASE_LAYER);
9228
+ return null;
8806
9229
  }
8807
9230
 
8808
- return plane;
9231
+ return plane.layer;
8809
9232
  };
8810
9233
 
9234
+
8811
9235
  /**
8812
9236
  * Returns the plane which contains the given element.
8813
9237
  *
8814
9238
  * @param {string|djs.model.Base} element
8815
9239
  *
8816
- * @return {Object} plane descriptor with { layer, rootElement, name }
9240
+ * @return {djs.model.Base} root for element
8817
9241
  */
8818
- Canvas.prototype.findPlane = function(element) {
9242
+ Canvas.prototype.findRoot = function(element) {
8819
9243
  if (typeof element === 'string') {
8820
9244
  element = this._elementRegistry.get(element);
8821
9245
  }
8822
9246
 
8823
- var root = findRoot(element);
9247
+ if (!element) {
9248
+ return;
9249
+ }
9250
+
9251
+ var plane = this._findPlaneForRoot(
9252
+ findRoot(element)
9253
+ ) || {};
9254
+
9255
+ return plane.rootElement;
9256
+ };
9257
+
9258
+ /**
9259
+ * Return a list of all root elements on the diagram.
9260
+ *
9261
+ * @return {djs.model.Root[]}
9262
+ */
9263
+ Canvas.prototype.getRootElements = function() {
9264
+ return this._planes.map(function(plane) {
9265
+ return plane.rootElement;
9266
+ });
9267
+ };
8824
9268
 
9269
+ Canvas.prototype._findPlaneForRoot = function(rootElement) {
8825
9270
  return find(this._planes, function(plane) {
8826
- return plane.rootElement === root;
9271
+ return plane.rootElement === rootElement;
8827
9272
  });
8828
9273
  };
8829
9274
 
9275
+
8830
9276
  /**
8831
9277
  * Returns the html element that encloses the
8832
9278
  * drawing canvas.
@@ -8947,95 +9393,205 @@
8947
9393
  }
8948
9394
  };
8949
9395
 
9396
+ /**
9397
+ * Returns the current root element.
9398
+ *
9399
+ * Supports two different modes for handling root elements:
9400
+ *
9401
+ * 1. if no root element has been added before, an implicit root will be added
9402
+ * and returned. This is used in applications that don't require explicit
9403
+ * root elements.
9404
+ *
9405
+ * 2. when root elements have been added before calling `getRootElement`,
9406
+ * root elements can be null. This is used for applications that want to manage
9407
+ * root elements themselves.
9408
+ *
9409
+ * @returns {Object|djs.model.Root|null} rootElement.
9410
+ */
8950
9411
  Canvas.prototype.getRootElement = function() {
8951
- var plane = this.getActivePlane();
9412
+ var rootElement = this._rootElement;
8952
9413
 
8953
- return plane.rootElement;
9414
+ // can return null if root elements are present but none was set yet
9415
+ if (rootElement || this._planes.length) {
9416
+ return rootElement;
9417
+ }
9418
+
9419
+ return this.setRootElement(this.addRootElement(null));
8954
9420
  };
8955
9421
 
9422
+ /**
9423
+ * Adds a given root element and returns it.
9424
+ *
9425
+ * @param {Object|djs.model.Root} rootElement
9426
+ *
9427
+ * @return {Object|djs.model.Root} rootElement
9428
+ */
8956
9429
 
9430
+ Canvas.prototype.addRootElement = function(rootElement) {
9431
+ var idx = this._rootsIdx++;
8957
9432
 
8958
- // root element handling //////////////////////
9433
+ if (!rootElement) {
9434
+ rootElement = {
9435
+ id: '__implicitroot_' + idx,
9436
+ children: [],
9437
+ isImplicit: true
9438
+ };
9439
+ }
9440
+
9441
+ var layerName = rootElement.layer = 'root-' + idx;
9442
+
9443
+ this._ensureValid('root', rootElement);
9444
+
9445
+ var layer = this.getLayer(layerName, PLANE_LAYER_INDEX);
9446
+
9447
+ attr$1(layer, 'display', 'none');
9448
+
9449
+ this._addRoot(rootElement, layer);
9450
+
9451
+ this._planes.push({
9452
+ rootElement: rootElement,
9453
+ layer: layer
9454
+ });
9455
+
9456
+ return rootElement;
9457
+ };
8959
9458
 
8960
9459
  /**
8961
- * Sets a given element as the new root element for the canvas
8962
- * and returns the new root element.
9460
+ * Removes a given rootElement and returns it.
8963
9461
  *
8964
- * @param {Object|djs.model.Root} element
8965
- * @param {boolean} [override] whether to override the current root element, if any
9462
+ * @param {djs.model.Root|String} rootElement
8966
9463
  *
8967
- * @return {Object|djs.model.Root} new root element
9464
+ * @return {Object|djs.model.Root} rootElement
8968
9465
  */
8969
- Canvas.prototype.setRootElement = function(element, override) {
8970
- var activePlane = this._activePlane;
9466
+ Canvas.prototype.removeRootElement = function(rootElement) {
8971
9467
 
8972
- if (activePlane) {
8973
- return this.setRootElementForPlane(element, activePlane, override);
8974
- } else {
8975
- var basePlane = this.createPlane(BASE_LAYER, element);
9468
+ if (typeof rootElement === 'string') {
9469
+ rootElement = this._elementRegistry.get(rootElement);
9470
+ }
9471
+
9472
+ var plane = this._findPlaneForRoot(rootElement);
9473
+
9474
+ if (!plane) {
9475
+ return;
9476
+ }
9477
+
9478
+ // hook up life-cycle events
9479
+ this._removeRoot(rootElement);
9480
+
9481
+ // clean up layer
9482
+ this._removeLayer(rootElement.layer);
8976
9483
 
8977
- this.setActivePlane(basePlane);
9484
+ // clean up plane
9485
+ this._planes = this._planes.filter(function(plane) {
9486
+ return plane.rootElement !== rootElement;
9487
+ });
8978
9488
 
8979
- return basePlane.rootElement;
9489
+ // clean up active root
9490
+ if (this._rootElement === rootElement) {
9491
+ this._rootElement = null;
8980
9492
  }
9493
+
9494
+ return rootElement;
8981
9495
  };
8982
9496
 
8983
9497
 
9498
+ // root element handling //////////////////////
9499
+
8984
9500
  /**
8985
9501
  * Sets a given element as the new root element for the canvas
8986
9502
  * and returns the new root element.
8987
9503
  *
8988
- * @param {Object|djs.model.Root} element
8989
- * @param {Object|djs.model.Root} plane
8990
- * @param {boolean} [override] whether to override the current root element, if any
9504
+ * @param {Object|djs.model.Root} rootElement
8991
9505
  *
8992
9506
  * @return {Object|djs.model.Root} new root element
8993
9507
  */
8994
- Canvas.prototype.setRootElementForPlane = function(element, plane, override) {
9508
+ Canvas.prototype.setRootElement = function(rootElement, override) {
8995
9509
 
8996
- if (typeof plane === 'string') {
8997
- plane = this.getPlane(plane);
9510
+ if (isDefined(override)) {
9511
+ throw new Error('override not supported');
8998
9512
  }
8999
9513
 
9000
- if (element) {
9001
- this._ensureValid('root', element);
9514
+ if (rootElement === this._rootElement) {
9515
+ return;
9002
9516
  }
9003
9517
 
9004
- var currentRoot = plane.rootElement,
9005
- elementRegistry = this._elementRegistry,
9006
- eventBus = this._eventBus;
9518
+ var plane;
9007
9519
 
9008
- if (currentRoot) {
9009
- if (!override) {
9010
- throw new Error('rootElement already set, need to specify override');
9011
- }
9520
+ if (!rootElement) {
9521
+ throw new Error('rootElement required');
9522
+ }
9012
9523
 
9013
- // simulate element remove event sequence
9014
- eventBus.fire('root.remove', { element: currentRoot });
9015
- eventBus.fire('root.removed', { element: currentRoot });
9524
+ plane = this._findPlaneForRoot(rootElement);
9016
9525
 
9017
- elementRegistry.remove(currentRoot);
9526
+ // give set add semantics for backwards compatibility
9527
+ if (!plane) {
9528
+ rootElement = this.addRootElement(rootElement);
9018
9529
  }
9019
9530
 
9020
- if (element) {
9021
- var gfx = plane.layer;
9531
+ this._setRoot(rootElement);
9532
+
9533
+ return rootElement;
9534
+ };
9022
9535
 
9023
- // resemble element add event sequence
9024
- eventBus.fire('root.add', { element: element });
9025
9536
 
9026
- elementRegistry.add(element, gfx);
9537
+ Canvas.prototype._removeRoot = function(element) {
9538
+ var elementRegistry = this._elementRegistry,
9539
+ eventBus = this._eventBus;
9540
+
9541
+ // simulate element remove event sequence
9542
+ eventBus.fire('root.remove', { element: element });
9543
+ eventBus.fire('root.removed', { element: element });
9544
+
9545
+ elementRegistry.remove(element);
9546
+ };
9547
+
9548
+
9549
+ Canvas.prototype._addRoot = function(element, gfx) {
9550
+ var elementRegistry = this._elementRegistry,
9551
+ eventBus = this._eventBus;
9552
+
9553
+ // resemble element add event sequence
9554
+ eventBus.fire('root.add', { element: element });
9555
+
9556
+ elementRegistry.add(element, gfx);
9557
+
9558
+ eventBus.fire('root.added', { element: element, gfx: gfx });
9559
+ };
9560
+
9561
+
9562
+ Canvas.prototype._setRoot = function(rootElement, layer) {
9027
9563
 
9028
- eventBus.fire('root.added', { element: element, gfx: gfx });
9564
+ var currentRoot = this._rootElement;
9029
9565
 
9030
- // associate SVG with root element when active
9031
- if (plane === this._activePlane) {
9032
- this._elementRegistry.updateGraphics(element, this._svg, true);
9566
+ var currentLayer;
9567
+
9568
+ if (currentRoot) {
9569
+
9570
+ // un-associate previous root element <svg>
9571
+ this._elementRegistry.updateGraphics(currentRoot, null, true);
9572
+
9573
+ // hide previous layer
9574
+ currentLayer = this._findPlaneForRoot(currentRoot).layer;
9575
+
9576
+ attr$1(currentLayer, 'display', 'none');
9577
+ }
9578
+
9579
+ if (rootElement) {
9580
+
9581
+ if (!layer) {
9582
+ layer = this._findPlaneForRoot(rootElement).layer;
9033
9583
  }
9584
+
9585
+ // associate element with <svg>
9586
+ this._elementRegistry.updateGraphics(rootElement, this._svg, true);
9587
+
9588
+ // show root layer
9589
+ attr$1(layer, 'display', null);
9034
9590
  }
9035
9591
 
9036
- plane.rootElement = element;
9592
+ this._rootElement = rootElement;
9037
9593
 
9038
- return element;
9594
+ this._eventBus.fire('root.set', { element: rootElement });
9039
9595
  };
9040
9596
 
9041
9597
  // add functionality //////////////////////
@@ -9046,7 +9602,7 @@
9046
9602
  }
9047
9603
 
9048
9604
  if (this._elementRegistry.get(element.id)) {
9049
- throw new Error('element with id ' + element.id + ' already exists');
9605
+ throw new Error('element <' + element.id + '> already exists');
9050
9606
  }
9051
9607
 
9052
9608
  var requiredAttrs = REQUIRED_MODEL_ATTRS[type];
@@ -9336,6 +9892,7 @@
9336
9892
  innerBox,
9337
9893
  outerBox = this.getSize(),
9338
9894
  matrix,
9895
+ activeLayer,
9339
9896
  transform,
9340
9897
  scale,
9341
9898
  x, y;
@@ -9343,10 +9900,11 @@
9343
9900
  if (!box) {
9344
9901
 
9345
9902
  // compute the inner box based on the
9346
- // diagrams active plane. This allows us to exclude
9903
+ // diagrams active layer. This allows us to exclude
9347
9904
  // external components, such as overlays
9348
9905
 
9349
- innerBox = (this._activePlane && this._activePlane.layer.getBBox()) || {};
9906
+ activeLayer = this._rootElement ? this.getActiveLayer() : null;
9907
+ innerBox = activeLayer && activeLayer.getBBox() || {};
9350
9908
 
9351
9909
  transform = transform$1(viewport);
9352
9910
  matrix = transform ? transform.matrix : createMatrix();
@@ -9429,10 +9987,11 @@
9429
9987
  element = this._elementRegistry.get(element);
9430
9988
  }
9431
9989
 
9432
- // switch to correct Plane
9433
- var targetPlane = this.findPlane(element);
9434
- if (targetPlane !== this._activePlane) {
9435
- this.setActivePlane(targetPlane);
9990
+ // set to correct rootElement
9991
+ var rootElement = this.findRoot(element);
9992
+
9993
+ if (rootElement !== this.getRootElement()) {
9994
+ this.setRootElement(rootElement);
9436
9995
  }
9437
9996
 
9438
9997
  if (!padding) {
@@ -9795,7 +10354,9 @@
9795
10354
  container.gfx = gfx;
9796
10355
  }
9797
10356
 
9798
- attr$1(gfx, ELEMENT_ID, id);
10357
+ if (gfx) {
10358
+ attr$1(gfx, ELEMENT_ID, id);
10359
+ }
9799
10360
 
9800
10361
  return gfx;
9801
10362
  };
@@ -19572,18 +20133,29 @@
19572
20133
 
19573
20134
  var walker = new BpmnTreeWalker(visitor, translate);
19574
20135
 
20136
+
20137
+ bpmnDiagram = bpmnDiagram || (definitions.diagrams && definitions.diagrams[0]);
20138
+
20139
+ var diagramsToImport = getDiagramsToImport(definitions, bpmnDiagram);
20140
+
20141
+ if (!diagramsToImport) {
20142
+ throw new Error(translate('no diagram to display'));
20143
+ }
20144
+
19575
20145
  // traverse BPMN 2.0 document model,
19576
20146
  // starting at definitions
19577
- if (!bpmnDiagram && definitions.diagrams) {
19578
- for (var i = 0; i < definitions.diagrams.length; i++) {
19579
- walker.handleDefinitions(definitions, definitions.diagrams[i]);
19580
- }
19581
- } else {
19582
- walker.handleDefinitions(definitions, bpmnDiagram);
19583
- }
20147
+ forEach(diagramsToImport, function(diagram) {
20148
+ walker.handleDefinitions(definitions, diagram);
20149
+ });
19584
20150
 
19585
- var mainDiagram = bpmnDiagram || definitions.diagrams[0];
19586
- canvas.setActivePlane(mainDiagram.plane.bpmnElement.id);
20151
+ var rootId = bpmnDiagram.plane.bpmnElement.id;
20152
+
20153
+ // we do need to account for different ways we create root elements
20154
+ // each nested imported <root> do have the `_plane` suffix, while
20155
+ // the root <root> is found under the business object ID
20156
+ canvas.setRootElement(
20157
+ canvas.findRoot(rootId + '_plane') || canvas.findRoot(rootId)
20158
+ );
19587
20159
  }
19588
20160
 
19589
20161
  return new Promise(function(resolve, reject) {
@@ -19611,6 +20183,107 @@
19611
20183
  });
19612
20184
  }
19613
20185
 
20186
+ /**
20187
+ * Returns all diagrams in the same hirarchy as the requested diagram.
20188
+ * Includes all parent and sub process diagrams.
20189
+ *
20190
+ * @param {Array} definitions
20191
+ * @param {Object} bpmnDiagram
20192
+ *
20193
+ * @returns {Array<Object>}
20194
+ */
20195
+ function getDiagramsToImport(definitions, bpmnDiagram) {
20196
+ if (!bpmnDiagram) {
20197
+ return;
20198
+ }
20199
+
20200
+ var bpmnElement = bpmnDiagram.plane.bpmnElement,
20201
+ rootElement = bpmnElement;
20202
+
20203
+ if (!is$1(bpmnElement, 'bpmn:Process') && !is$1(bpmnElement, 'bpmn:Collaboration')) {
20204
+ rootElement = findRootProcess(bpmnElement);
20205
+ }
20206
+
20207
+ // in case the process is part of a collaboration, the plane references the
20208
+ // collaboration, not the process
20209
+ var collaboration;
20210
+
20211
+ if (is$1(rootElement, 'bpmn:Collaboration')) {
20212
+ collaboration = rootElement;
20213
+ } else {
20214
+ collaboration = find(definitions.rootElements, function(element) {
20215
+ if (!is$1(element, 'bpmn:Collaboration')) {
20216
+ return;
20217
+ }
20218
+
20219
+ return find(element.participants, function(participant) {
20220
+ return participant.processRef === rootElement;
20221
+ });
20222
+ });
20223
+ }
20224
+
20225
+ var rootElements = [ rootElement ];
20226
+
20227
+ // all collaboration processes can contain sub-diagrams
20228
+ if (collaboration) {
20229
+ rootElements = map$1(collaboration.participants, function(participant) {
20230
+ return participant.processRef;
20231
+ });
20232
+
20233
+ rootElements.push(collaboration);
20234
+ }
20235
+
20236
+ var allChildren = selfAndAllFlowElements(rootElements);
20237
+
20238
+ // if we have multiple diagrams referencing the same element, we
20239
+ // use the first in the file
20240
+ var diagramsToImport = [ bpmnDiagram ];
20241
+ var handledElements = [ bpmnElement ];
20242
+
20243
+ forEach(definitions.diagrams, function(diagram) {
20244
+ var businessObject = diagram.plane.bpmnElement;
20245
+
20246
+ if (
20247
+ allChildren.indexOf(businessObject) !== -1 &&
20248
+ handledElements.indexOf(businessObject) === -1
20249
+ ) {
20250
+ diagramsToImport.push(diagram);
20251
+ handledElements.push(businessObject);
20252
+ }
20253
+ });
20254
+
20255
+
20256
+ return diagramsToImport;
20257
+ }
20258
+
20259
+ function selfAndAllFlowElements(elements) {
20260
+ var result = [];
20261
+
20262
+ forEach(elements, function(element) {
20263
+ if (!element) {
20264
+ return;
20265
+ }
20266
+
20267
+ result.push(element);
20268
+
20269
+ result = result.concat(selfAndAllFlowElements(element.flowElements));
20270
+ });
20271
+
20272
+ return result;
20273
+ }
20274
+
20275
+ function findRootProcess(element) {
20276
+ var parent = element;
20277
+
20278
+ while (parent) {
20279
+ if (is$1(parent, 'bpmn:Process')) {
20280
+ return parent;
20281
+ }
20282
+
20283
+ parent = parent.$parent;
20284
+ }
20285
+ }
20286
+
19614
20287
  /**
19615
20288
  * This file must not be changed or exchanged.
19616
20289
  *
@@ -20101,7 +20774,7 @@
20101
20774
  try {
20102
20775
  var canvas = self.get('canvas');
20103
20776
 
20104
- var contentNode = canvas.getDefaultLayer(),
20777
+ var contentNode = canvas.getActiveLayer(),
20105
20778
  defsNode = query('defs', canvas._svg);
20106
20779
 
20107
20780
  var contents = innerSVG(contentNode),
@@ -20633,7 +21306,7 @@
20633
21306
  }
20634
21307
 
20635
21308
  var allowedModifiers = this._getAllowedModifiers(event.target);
20636
- return !allowedModifiers.includes(event.key);
21309
+ return allowedModifiers.indexOf(event.key) === -1;
20637
21310
  };
20638
21311
 
20639
21312
  Keyboard.prototype._getAllowedModifiers = function(element) {