bpmn-js 9.0.0-subprocesses.3 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/assets/bpmn-js.css +38 -4
  3. package/dist/assets/diagram-js.css +1 -1
  4. package/dist/bpmn-modeler.development.js +2411 -1110
  5. package/dist/bpmn-modeler.production.min.js +8 -8
  6. package/dist/bpmn-navigated-viewer.development.js +983 -315
  7. package/dist/bpmn-navigated-viewer.production.min.js +6 -6
  8. package/dist/bpmn-viewer.development.js +983 -315
  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 +9 -6
  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/RemoveEmbeddedLabelBoundsBehavior.js +34 -0
  28. package/lib/features/modeling/behavior/SubProcessPlaneBehavior.js +557 -0
  29. package/lib/features/modeling/behavior/ToggleCollapseConnectionBehaviour.js +74 -0
  30. package/lib/features/modeling/behavior/UnclaimIdBehavior.js +3 -1
  31. package/lib/features/modeling/behavior/index.js +27 -18
  32. package/lib/features/modeling/cmd/SetColorHandler.js +23 -6
  33. package/lib/features/modeling/cmd/UpdateCanvasRootHandler.js +4 -2
  34. package/lib/features/modeling/util/ModelingUtil.js +2 -20
  35. package/lib/features/ordering/BpmnOrderingProvider.js +3 -3
  36. package/lib/features/palette/PaletteProvider.js +1 -1
  37. package/lib/features/popup-menu/ReplaceMenuProvider.js +1 -1
  38. package/lib/import/BpmnImporter.js +15 -9
  39. package/lib/import/Importer.js +130 -10
  40. package/lib/util/DrilldownUtil.js +66 -0
  41. package/lib/util/ModelUtil.js +19 -0
  42. package/package.json +2 -2
  43. 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.0
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-18
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);
7500
7744
 
7501
- var path = parents.map(function(el) {
7502
- var title = escapeHTML(el.name || el.id);
7745
+ var isPresent = find(boParents, function(el) {
7746
+ return el === bo;
7747
+ });
7748
+
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
@@ -7705,6 +8030,15 @@
7705
8030
 
7706
8031
  var newDiagrams = [];
7707
8032
 
8033
+ // create new planes for all collapsed subprocesses, even when they are empty
8034
+ collapsedElements.forEach(function(element) {
8035
+ if (!self._processToDiagramMap[element.id]) {
8036
+ var diagram = self.createDiagram(element);
8037
+ self._processToDiagramMap[element.id] = diagram;
8038
+ newDiagrams.push(diagram);
8039
+ }
8040
+ });
8041
+
7708
8042
  elementsToMove.forEach(function(element) {
7709
8043
  var diElement = element.diElement;
7710
8044
  var parent = element.parent;
@@ -7720,12 +8054,6 @@
7720
8054
  }
7721
8055
 
7722
8056
  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
8057
  self.moveToDiPlane(diElement, diagram.plane);
7730
8058
  });
7731
8059
 
@@ -7792,33 +8120,209 @@
7792
8120
  }
7793
8121
  }
7794
8122
 
7795
- function getPlaneBounds(plane) {
7796
- var planeTrbl = {
7797
- top: Infinity,
7798
- right: -Infinity,
7799
- bottom: -Infinity,
7800
- left: Infinity
7801
- };
8123
+ function getPlaneBounds(plane) {
8124
+ var planeTrbl = {
8125
+ top: Infinity,
8126
+ right: -Infinity,
8127
+ bottom: -Infinity,
8128
+ left: Infinity
8129
+ };
8130
+
8131
+ plane.planeElement.forEach(function(element) {
8132
+ if (!element.bounds) {
8133
+ return;
8134
+ }
8135
+
8136
+ var trbl = asTRBL(element.bounds);
8137
+
8138
+ planeTrbl.top = Math.min(trbl.top, planeTrbl.top);
8139
+ planeTrbl.left = Math.min(trbl.left, planeTrbl.left);
8140
+ });
8141
+
8142
+ return asBounds(planeTrbl);
8143
+ }
8144
+
8145
+ var LOW_PRIORITY$1 = 250;
8146
+ 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>';
8147
+
8148
+ var EMPTY_MARKER = 'bjs-drilldown-empty';
8149
+
8150
+ function DrilldownOverlayBehavior(
8151
+ canvas, eventBus, elementRegistry, overlays
8152
+ ) {
8153
+ CommandInterceptor.call(this, eventBus);
8154
+
8155
+ this._canvas = canvas;
8156
+ this._eventBus = eventBus;
8157
+ this._elementRegistry = elementRegistry;
8158
+ this._overlays = overlays;
8159
+
8160
+ var self = this;
8161
+
8162
+ this.executed('shape.toggleCollapse', LOW_PRIORITY$1, function(context) {
8163
+ var shape = context.shape;
8164
+
8165
+ // Add overlay to the collapsed shape
8166
+ if (self.canDrillDown(shape)) {
8167
+ self.addOverlay(shape);
8168
+ } else {
8169
+ self.removeOverlay(shape);
8170
+ }
8171
+ }, true);
8172
+
8173
+
8174
+ this.reverted('shape.toggleCollapse', LOW_PRIORITY$1, function(context) {
8175
+ var shape = context.shape;
8176
+
8177
+ // Add overlay to the collapsed shape
8178
+ if (self.canDrillDown(shape)) {
8179
+ self.addOverlay(shape);
8180
+ } else {
8181
+ self.removeOverlay(shape);
8182
+ }
8183
+ }, true);
8184
+
8185
+
8186
+ this.executed(['shape.create', 'shape.move', 'shape.delete'], LOW_PRIORITY$1,
8187
+ function(context) {
8188
+ var oldParent = context.oldParent,
8189
+ newParent = context.newParent || context.parent,
8190
+ shape = context.shape;
8191
+
8192
+ // Add overlay to the collapsed shape
8193
+ if (self.canDrillDown(shape)) {
8194
+ self.addOverlay(shape);
8195
+ }
8196
+
8197
+ self.updateDrilldownOverlay(oldParent);
8198
+ self.updateDrilldownOverlay(newParent);
8199
+ self.updateDrilldownOverlay(shape);
8200
+ }, true);
8201
+
8202
+
8203
+ this.reverted(['shape.create', 'shape.move', 'shape.delete'], LOW_PRIORITY$1,
8204
+ function(context) {
8205
+ var oldParent = context.oldParent,
8206
+ newParent = context.newParent || context.parent,
8207
+ shape = context.shape;
8208
+
8209
+ // Add overlay to the collapsed shape
8210
+ if (self.canDrillDown(shape)) {
8211
+ self.addOverlay(shape);
8212
+ }
8213
+
8214
+ self.updateDrilldownOverlay(oldParent);
8215
+ self.updateDrilldownOverlay(newParent);
8216
+ self.updateDrilldownOverlay(shape);
8217
+ }, true);
8218
+
8219
+
8220
+ eventBus.on('import.done', function() {
8221
+ elementRegistry.filter(function(e) {
8222
+ return self.canDrillDown(e);
8223
+ }).map(function(el) {
8224
+ self.addOverlay(el);
8225
+ });
8226
+ });
8227
+
8228
+ }
8229
+
8230
+ inherits$1(DrilldownOverlayBehavior, CommandInterceptor);
8231
+
8232
+ DrilldownOverlayBehavior.prototype.updateDrilldownOverlay = function(shape) {
8233
+ var canvas = this._canvas;
8234
+
8235
+ if (!shape) {
8236
+ return;
8237
+ }
8238
+
8239
+ var root = canvas.findRoot(shape);
8240
+ if (root) {
8241
+ this.updateOverlayVisibility(root);
8242
+ }
8243
+ };
8244
+
8245
+
8246
+ DrilldownOverlayBehavior.prototype.canDrillDown = function(element) {
8247
+ var canvas = this._canvas;
8248
+ return is$1(element, 'bpmn:SubProcess') && canvas.findRoot(getPlaneIdFromShape(element));
8249
+ };
8250
+
8251
+ /**
8252
+ * Updates visibility of the drilldown overlay. If the plane has no elements,
8253
+ * the drilldown will be only shown when the element is selected.
8254
+ *
8255
+ * @param {djs.model.Shape|djs.model.Root} element collapsed shape or root element
8256
+ */
8257
+ DrilldownOverlayBehavior.prototype.updateOverlayVisibility = function(element) {
8258
+ var overlays = this._overlays;
8259
+
8260
+ var bo = element.businessObject;
8261
+
8262
+ var overlay = overlays.get({ element: bo.id, type: 'drilldown' })[0];
8263
+
8264
+ if (!overlay) {
8265
+ return;
8266
+ }
8267
+
8268
+ var hasContent = bo && bo.flowElements && bo.flowElements.length;
8269
+ classes(overlay.html).toggle(EMPTY_MARKER, !hasContent);
8270
+ };
8271
+
8272
+ /**
8273
+ * Attaches a drilldown button to the given element. We assume that the plane has
8274
+ * the same id as the element.
8275
+ *
8276
+ * @param {djs.model.Shape} element collapsed shape
8277
+ */
8278
+ DrilldownOverlayBehavior.prototype.addOverlay = function(element) {
8279
+ var canvas = this._canvas;
8280
+ var overlays = this._overlays;
8281
+
8282
+ var existingOverlays = overlays.get({ element: element, type: 'drilldown' });
8283
+ if (existingOverlays.length) {
8284
+ this.removeOverlay(element);
8285
+ }
8286
+
8287
+ var button = domify('<button class="bjs-drilldown">' + ARROW_DOWN_SVG + '</button>');
7802
8288
 
7803
- plane.planeElement.forEach(function(element) {
7804
- if (!element.bounds) {
7805
- return;
7806
- }
8289
+ button.addEventListener('click', function() {
8290
+ canvas.setRootElement(canvas.findRoot(getPlaneIdFromShape(element)));
8291
+ });
7807
8292
 
7808
- var trbl = asTRBL(element.bounds);
8293
+ overlays.add(element, 'drilldown', {
8294
+ position: {
8295
+ bottom: -7,
8296
+ right: -8
8297
+ },
8298
+ html: button
8299
+ });
7809
8300
 
7810
- planeTrbl.top = Math.min(trbl.top, planeTrbl.top);
7811
- planeTrbl.left = Math.min(trbl.left, planeTrbl.left);
8301
+ this.updateOverlayVisibility(element);
8302
+ };
8303
+
8304
+ DrilldownOverlayBehavior.prototype.removeOverlay = function(element) {
8305
+ var overlays = this._overlays;
8306
+
8307
+ overlays.remove({
8308
+ element: element,
8309
+ type: 'drilldown'
7812
8310
  });
8311
+ };
7813
8312
 
7814
- return asBounds(planeTrbl);
7815
- }
8313
+ DrilldownOverlayBehavior.$inject = [
8314
+ 'canvas',
8315
+ 'eventBus',
8316
+ 'elementRegistry',
8317
+ 'overlays'
8318
+ ];
7816
8319
 
7817
8320
  var DrilldownModdule = {
7818
- __depends__: [ OverlaysModule, ChangeSupportModule ],
7819
- __init__: [ 'drilldownOverlays', 'drilldownCentering', 'subprocessCompatibility'],
7820
- drilldownOverlays: [ 'type', DrilldownOverlays ],
8321
+ __depends__: [ OverlaysModule, ChangeSupportModule, RootElementsModule ],
8322
+ __init__: [ 'drilldownBreadcrumbs', 'drilldownOverlayBehavior', 'drilldownCentering', 'subprocessCompatibility'],
8323
+ drilldownBreadcrumbs: [ 'type', DrilldownBreadcrumbs ],
7821
8324
  drilldownCentering: [ 'type', DrilldownCentering ],
8325
+ drilldownOverlayBehavior: [ 'type', DrilldownOverlayBehavior ],
7822
8326
  subprocessCompatibility: [ 'type', SubprocessCompatibility ]
7823
8327
  };
7824
8328
 
@@ -8459,7 +8963,6 @@
8459
8963
  }
8460
8964
 
8461
8965
  var BASE_LAYER = 'base';
8462
- var HIDDEN_MARKER = 'djs-element-hidden';
8463
8966
 
8464
8967
  // render plane contents behind utility layers
8465
8968
  var PLANE_LAYER_INDEX = 0;
@@ -8490,6 +8993,12 @@
8490
8993
  this._elementRegistry = elementRegistry;
8491
8994
  this._graphicsFactory = graphicsFactory;
8492
8995
 
8996
+ this._rootsIdx = 0;
8997
+
8998
+ this._layers = {};
8999
+ this._planes = [];
9000
+ this._rootElement = null;
9001
+
8493
9002
  this._init(config || {});
8494
9003
  }
8495
9004
 
@@ -8527,9 +9036,6 @@
8527
9036
 
8528
9037
  var viewport = this._viewport = createGroup(svg, 'viewport');
8529
9038
 
8530
- this._layers = {};
8531
- this._planes = {};
8532
-
8533
9039
  // debounce canvas.viewbox.changed events
8534
9040
  // for smoother diagram interaction
8535
9041
  if (config.deferUpdate !== false) {
@@ -8564,7 +9070,7 @@
8564
9070
  'shape.removed',
8565
9071
  'connection.removed',
8566
9072
  'elements.changed',
8567
- 'plane.set'
9073
+ 'root.set'
8568
9074
  ], function() {
8569
9075
  delete this._cachedViewbox;
8570
9076
  }, this);
@@ -8589,7 +9095,7 @@
8589
9095
  delete this._container;
8590
9096
  delete this._layers;
8591
9097
  delete this._planes;
8592
- delete this._activePlane;
9098
+ delete this._rootElement;
8593
9099
  delete this._viewport;
8594
9100
  };
8595
9101
 
@@ -8604,15 +9110,15 @@
8604
9110
  var type = getType(element);
8605
9111
 
8606
9112
  if (type === 'root') {
8607
- self.setRootElementForPlane(null, self.findPlane(element), true);
9113
+ self.removeRootElement(element);
8608
9114
  } else {
8609
9115
  self._removeElement(element, type);
8610
9116
  }
8611
9117
  });
8612
9118
 
8613
9119
  // remove all planes
8614
- this._activePlane = null;
8615
- this._planes = {};
9120
+ this._planes = [];
9121
+ this._rootElement = null;
8616
9122
 
8617
9123
  // force recomputation of view box
8618
9124
  delete this._cachedViewbox;
@@ -8693,140 +9199,75 @@
8693
9199
 
8694
9200
  };
8695
9201
 
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
9202
 
8767
- // hide previous Plane
8768
- if (this._activePlane) {
8769
- classes$1(this._activePlane.layer).add(HIDDEN_MARKER);
8770
- }
9203
+ Canvas.prototype._removeLayer = function(name) {
8771
9204
 
8772
- this._activePlane = plane;
9205
+ var layer = this._layers[name];
8773
9206
 
8774
- // show current Plane
8775
- classes$1(plane.layer).remove(HIDDEN_MARKER);
9207
+ if (layer) {
9208
+ delete this._layers[name];
8776
9209
 
8777
- if (plane.rootElement) {
8778
- this._elementRegistry.updateGraphics(plane.rootElement, this._svg, true);
9210
+ remove$2(layer.group);
8779
9211
  }
8780
-
8781
- this._eventBus.fire('plane.set', { plane: plane });
8782
-
8783
- return plane;
8784
9212
  };
8785
9213
 
8786
9214
  /**
8787
- * Returns the currently active layer
9215
+ * Returns the currently active layer. Can be null.
8788
9216
  *
8789
- * @returns {SVGElement}
9217
+ * @returns {SVGElement|null}
8790
9218
  */
8791
-
8792
9219
  Canvas.prototype.getActiveLayer = function() {
8793
- return this.getActivePlane().layer;
8794
- };
9220
+ var plane = this._findPlaneForRoot(this.getRootElement());
8795
9221
 
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
9222
  if (!plane) {
8804
- plane = this.createPlane(BASE_LAYER);
8805
- this.setActivePlane(BASE_LAYER);
9223
+ return null;
8806
9224
  }
8807
9225
 
8808
- return plane;
9226
+ return plane.layer;
8809
9227
  };
8810
9228
 
9229
+
8811
9230
  /**
8812
9231
  * Returns the plane which contains the given element.
8813
9232
  *
8814
9233
  * @param {string|djs.model.Base} element
8815
9234
  *
8816
- * @return {Object} plane descriptor with { layer, rootElement, name }
9235
+ * @return {djs.model.Base} root for element
8817
9236
  */
8818
- Canvas.prototype.findPlane = function(element) {
9237
+ Canvas.prototype.findRoot = function(element) {
8819
9238
  if (typeof element === 'string') {
8820
9239
  element = this._elementRegistry.get(element);
8821
9240
  }
8822
9241
 
8823
- var root = findRoot(element);
9242
+ if (!element) {
9243
+ return;
9244
+ }
9245
+
9246
+ var plane = this._findPlaneForRoot(
9247
+ findRoot(element)
9248
+ ) || {};
9249
+
9250
+ return plane.rootElement;
9251
+ };
9252
+
9253
+ /**
9254
+ * Return a list of all root elements on the diagram.
9255
+ *
9256
+ * @return {djs.model.Root[]}
9257
+ */
9258
+ Canvas.prototype.getRootElements = function() {
9259
+ return this._planes.map(function(plane) {
9260
+ return plane.rootElement;
9261
+ });
9262
+ };
8824
9263
 
9264
+ Canvas.prototype._findPlaneForRoot = function(rootElement) {
8825
9265
  return find(this._planes, function(plane) {
8826
- return plane.rootElement === root;
9266
+ return plane.rootElement === rootElement;
8827
9267
  });
8828
9268
  };
8829
9269
 
9270
+
8830
9271
  /**
8831
9272
  * Returns the html element that encloses the
8832
9273
  * drawing canvas.
@@ -8947,95 +9388,205 @@
8947
9388
  }
8948
9389
  };
8949
9390
 
9391
+ /**
9392
+ * Returns the current root element.
9393
+ *
9394
+ * Supports two different modes for handling root elements:
9395
+ *
9396
+ * 1. if no root element has been added before, an implicit root will be added
9397
+ * and returned. This is used in applications that don't require explicit
9398
+ * root elements.
9399
+ *
9400
+ * 2. when root elements have been added before calling `getRootElement`,
9401
+ * root elements can be null. This is used for applications that want to manage
9402
+ * root elements themselves.
9403
+ *
9404
+ * @returns {Object|djs.model.Root|null} rootElement.
9405
+ */
8950
9406
  Canvas.prototype.getRootElement = function() {
8951
- var plane = this.getActivePlane();
9407
+ var rootElement = this._rootElement;
8952
9408
 
8953
- return plane.rootElement;
9409
+ // can return null if root elements are present but none was set yet
9410
+ if (rootElement || this._planes.length) {
9411
+ return rootElement;
9412
+ }
9413
+
9414
+ return this.setRootElement(this.addRootElement(null));
8954
9415
  };
8955
9416
 
9417
+ /**
9418
+ * Adds a given root element and returns it.
9419
+ *
9420
+ * @param {Object|djs.model.Root} rootElement
9421
+ *
9422
+ * @return {Object|djs.model.Root} rootElement
9423
+ */
8956
9424
 
9425
+ Canvas.prototype.addRootElement = function(rootElement) {
9426
+ var idx = this._rootsIdx++;
8957
9427
 
8958
- // root element handling //////////////////////
9428
+ if (!rootElement) {
9429
+ rootElement = {
9430
+ id: '__implicitroot_' + idx,
9431
+ children: [],
9432
+ isImplicit: true
9433
+ };
9434
+ }
9435
+
9436
+ var layerName = rootElement.layer = 'root-' + idx;
9437
+
9438
+ this._ensureValid('root', rootElement);
9439
+
9440
+ var layer = this.getLayer(layerName, PLANE_LAYER_INDEX);
9441
+
9442
+ attr$1(layer, 'display', 'none');
9443
+
9444
+ this._addRoot(rootElement, layer);
9445
+
9446
+ this._planes.push({
9447
+ rootElement: rootElement,
9448
+ layer: layer
9449
+ });
9450
+
9451
+ return rootElement;
9452
+ };
8959
9453
 
8960
9454
  /**
8961
- * Sets a given element as the new root element for the canvas
8962
- * and returns the new root element.
9455
+ * Removes a given rootElement and returns it.
8963
9456
  *
8964
- * @param {Object|djs.model.Root} element
8965
- * @param {boolean} [override] whether to override the current root element, if any
9457
+ * @param {djs.model.Root|String} rootElement
8966
9458
  *
8967
- * @return {Object|djs.model.Root} new root element
9459
+ * @return {Object|djs.model.Root} rootElement
8968
9460
  */
8969
- Canvas.prototype.setRootElement = function(element, override) {
8970
- var activePlane = this._activePlane;
9461
+ Canvas.prototype.removeRootElement = function(rootElement) {
8971
9462
 
8972
- if (activePlane) {
8973
- return this.setRootElementForPlane(element, activePlane, override);
8974
- } else {
8975
- var basePlane = this.createPlane(BASE_LAYER, element);
9463
+ if (typeof rootElement === 'string') {
9464
+ rootElement = this._elementRegistry.get(rootElement);
9465
+ }
9466
+
9467
+ var plane = this._findPlaneForRoot(rootElement);
9468
+
9469
+ if (!plane) {
9470
+ return;
9471
+ }
9472
+
9473
+ // hook up life-cycle events
9474
+ this._removeRoot(rootElement);
9475
+
9476
+ // clean up layer
9477
+ this._removeLayer(rootElement.layer);
8976
9478
 
8977
- this.setActivePlane(basePlane);
9479
+ // clean up plane
9480
+ this._planes = this._planes.filter(function(plane) {
9481
+ return plane.rootElement !== rootElement;
9482
+ });
8978
9483
 
8979
- return basePlane.rootElement;
9484
+ // clean up active root
9485
+ if (this._rootElement === rootElement) {
9486
+ this._rootElement = null;
8980
9487
  }
9488
+
9489
+ return rootElement;
8981
9490
  };
8982
9491
 
8983
9492
 
9493
+ // root element handling //////////////////////
9494
+
8984
9495
  /**
8985
9496
  * Sets a given element as the new root element for the canvas
8986
9497
  * and returns the new root element.
8987
9498
  *
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
9499
+ * @param {Object|djs.model.Root} rootElement
8991
9500
  *
8992
9501
  * @return {Object|djs.model.Root} new root element
8993
9502
  */
8994
- Canvas.prototype.setRootElementForPlane = function(element, plane, override) {
9503
+ Canvas.prototype.setRootElement = function(rootElement, override) {
8995
9504
 
8996
- if (typeof plane === 'string') {
8997
- plane = this.getPlane(plane);
9505
+ if (isDefined(override)) {
9506
+ throw new Error('override not supported');
8998
9507
  }
8999
9508
 
9000
- if (element) {
9001
- this._ensureValid('root', element);
9509
+ if (rootElement === this._rootElement) {
9510
+ return;
9002
9511
  }
9003
9512
 
9004
- var currentRoot = plane.rootElement,
9005
- elementRegistry = this._elementRegistry,
9006
- eventBus = this._eventBus;
9513
+ var plane;
9007
9514
 
9008
- if (currentRoot) {
9009
- if (!override) {
9010
- throw new Error('rootElement already set, need to specify override');
9011
- }
9515
+ if (!rootElement) {
9516
+ throw new Error('rootElement required');
9517
+ }
9012
9518
 
9013
- // simulate element remove event sequence
9014
- eventBus.fire('root.remove', { element: currentRoot });
9015
- eventBus.fire('root.removed', { element: currentRoot });
9519
+ plane = this._findPlaneForRoot(rootElement);
9016
9520
 
9017
- elementRegistry.remove(currentRoot);
9521
+ // give set add semantics for backwards compatibility
9522
+ if (!plane) {
9523
+ rootElement = this.addRootElement(rootElement);
9018
9524
  }
9019
9525
 
9020
- if (element) {
9021
- var gfx = plane.layer;
9526
+ this._setRoot(rootElement);
9527
+
9528
+ return rootElement;
9529
+ };
9022
9530
 
9023
- // resemble element add event sequence
9024
- eventBus.fire('root.add', { element: element });
9025
9531
 
9026
- elementRegistry.add(element, gfx);
9532
+ Canvas.prototype._removeRoot = function(element) {
9533
+ var elementRegistry = this._elementRegistry,
9534
+ eventBus = this._eventBus;
9535
+
9536
+ // simulate element remove event sequence
9537
+ eventBus.fire('root.remove', { element: element });
9538
+ eventBus.fire('root.removed', { element: element });
9539
+
9540
+ elementRegistry.remove(element);
9541
+ };
9542
+
9543
+
9544
+ Canvas.prototype._addRoot = function(element, gfx) {
9545
+ var elementRegistry = this._elementRegistry,
9546
+ eventBus = this._eventBus;
9547
+
9548
+ // resemble element add event sequence
9549
+ eventBus.fire('root.add', { element: element });
9550
+
9551
+ elementRegistry.add(element, gfx);
9552
+
9553
+ eventBus.fire('root.added', { element: element, gfx: gfx });
9554
+ };
9555
+
9556
+
9557
+ Canvas.prototype._setRoot = function(rootElement, layer) {
9027
9558
 
9028
- eventBus.fire('root.added', { element: element, gfx: gfx });
9559
+ var currentRoot = this._rootElement;
9029
9560
 
9030
- // associate SVG with root element when active
9031
- if (plane === this._activePlane) {
9032
- this._elementRegistry.updateGraphics(element, this._svg, true);
9561
+ var currentLayer;
9562
+
9563
+ if (currentRoot) {
9564
+
9565
+ // un-associate previous root element <svg>
9566
+ this._elementRegistry.updateGraphics(currentRoot, null, true);
9567
+
9568
+ // hide previous layer
9569
+ currentLayer = this._findPlaneForRoot(currentRoot).layer;
9570
+
9571
+ attr$1(currentLayer, 'display', 'none');
9572
+ }
9573
+
9574
+ if (rootElement) {
9575
+
9576
+ if (!layer) {
9577
+ layer = this._findPlaneForRoot(rootElement).layer;
9033
9578
  }
9579
+
9580
+ // associate element with <svg>
9581
+ this._elementRegistry.updateGraphics(rootElement, this._svg, true);
9582
+
9583
+ // show root layer
9584
+ attr$1(layer, 'display', null);
9034
9585
  }
9035
9586
 
9036
- plane.rootElement = element;
9587
+ this._rootElement = rootElement;
9037
9588
 
9038
- return element;
9589
+ this._eventBus.fire('root.set', { element: rootElement });
9039
9590
  };
9040
9591
 
9041
9592
  // add functionality //////////////////////
@@ -9046,7 +9597,7 @@
9046
9597
  }
9047
9598
 
9048
9599
  if (this._elementRegistry.get(element.id)) {
9049
- throw new Error('element with id ' + element.id + ' already exists');
9600
+ throw new Error('element <' + element.id + '> already exists');
9050
9601
  }
9051
9602
 
9052
9603
  var requiredAttrs = REQUIRED_MODEL_ATTRS[type];
@@ -9336,6 +9887,7 @@
9336
9887
  innerBox,
9337
9888
  outerBox = this.getSize(),
9338
9889
  matrix,
9890
+ activeLayer,
9339
9891
  transform,
9340
9892
  scale,
9341
9893
  x, y;
@@ -9343,10 +9895,11 @@
9343
9895
  if (!box) {
9344
9896
 
9345
9897
  // compute the inner box based on the
9346
- // diagrams active plane. This allows us to exclude
9898
+ // diagrams active layer. This allows us to exclude
9347
9899
  // external components, such as overlays
9348
9900
 
9349
- innerBox = (this._activePlane && this._activePlane.layer.getBBox()) || {};
9901
+ activeLayer = this._rootElement ? this.getActiveLayer() : null;
9902
+ innerBox = activeLayer && activeLayer.getBBox() || {};
9350
9903
 
9351
9904
  transform = transform$1(viewport);
9352
9905
  matrix = transform ? transform.matrix : createMatrix();
@@ -9429,10 +9982,11 @@
9429
9982
  element = this._elementRegistry.get(element);
9430
9983
  }
9431
9984
 
9432
- // switch to correct Plane
9433
- var targetPlane = this.findPlane(element);
9434
- if (targetPlane !== this._activePlane) {
9435
- this.setActivePlane(targetPlane);
9985
+ // set to correct rootElement
9986
+ var rootElement = this.findRoot(element);
9987
+
9988
+ if (rootElement !== this.getRootElement()) {
9989
+ this.setRootElement(rootElement);
9436
9990
  }
9437
9991
 
9438
9992
  if (!padding) {
@@ -9795,7 +10349,9 @@
9795
10349
  container.gfx = gfx;
9796
10350
  }
9797
10351
 
9798
- attr$1(gfx, ELEMENT_ID, id);
10352
+ if (gfx) {
10353
+ attr$1(gfx, ELEMENT_ID, id);
10354
+ }
9799
10355
 
9800
10356
  return gfx;
9801
10357
  };
@@ -19572,18 +20128,29 @@
19572
20128
 
19573
20129
  var walker = new BpmnTreeWalker(visitor, translate);
19574
20130
 
20131
+
20132
+ bpmnDiagram = bpmnDiagram || (definitions.diagrams && definitions.diagrams[0]);
20133
+
20134
+ var diagramsToImport = getDiagramsToImport(definitions, bpmnDiagram);
20135
+
20136
+ if (!diagramsToImport) {
20137
+ throw new Error(translate('no diagram to display'));
20138
+ }
20139
+
19575
20140
  // traverse BPMN 2.0 document model,
19576
20141
  // 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
- }
20142
+ forEach(diagramsToImport, function(diagram) {
20143
+ walker.handleDefinitions(definitions, diagram);
20144
+ });
19584
20145
 
19585
- var mainDiagram = bpmnDiagram || definitions.diagrams[0];
19586
- canvas.setActivePlane(mainDiagram.plane.bpmnElement.id);
20146
+ var rootId = bpmnDiagram.plane.bpmnElement.id;
20147
+
20148
+ // we do need to account for different ways we create root elements
20149
+ // each nested imported <root> do have the `_plane` suffix, while
20150
+ // the root <root> is found under the business object ID
20151
+ canvas.setRootElement(
20152
+ canvas.findRoot(rootId + '_plane') || canvas.findRoot(rootId)
20153
+ );
19587
20154
  }
19588
20155
 
19589
20156
  return new Promise(function(resolve, reject) {
@@ -19611,6 +20178,107 @@
19611
20178
  });
19612
20179
  }
19613
20180
 
20181
+ /**
20182
+ * Returns all diagrams in the same hirarchy as the requested diagram.
20183
+ * Includes all parent and sub process diagrams.
20184
+ *
20185
+ * @param {Array} definitions
20186
+ * @param {Object} bpmnDiagram
20187
+ *
20188
+ * @returns {Array<Object>}
20189
+ */
20190
+ function getDiagramsToImport(definitions, bpmnDiagram) {
20191
+ if (!bpmnDiagram) {
20192
+ return;
20193
+ }
20194
+
20195
+ var bpmnElement = bpmnDiagram.plane.bpmnElement,
20196
+ rootElement = bpmnElement;
20197
+
20198
+ if (!is$1(bpmnElement, 'bpmn:Process') && !is$1(bpmnElement, 'bpmn:Collaboration')) {
20199
+ rootElement = findRootProcess(bpmnElement);
20200
+ }
20201
+
20202
+ // in case the process is part of a collaboration, the plane references the
20203
+ // collaboration, not the process
20204
+ var collaboration;
20205
+
20206
+ if (is$1(rootElement, 'bpmn:Collaboration')) {
20207
+ collaboration = rootElement;
20208
+ } else {
20209
+ collaboration = find(definitions.rootElements, function(element) {
20210
+ if (!is$1(element, 'bpmn:Collaboration')) {
20211
+ return;
20212
+ }
20213
+
20214
+ return find(element.participants, function(participant) {
20215
+ return participant.processRef === rootElement;
20216
+ });
20217
+ });
20218
+ }
20219
+
20220
+ var rootElements = [ rootElement ];
20221
+
20222
+ // all collaboration processes can contain sub-diagrams
20223
+ if (collaboration) {
20224
+ rootElements = map$1(collaboration.participants, function(participant) {
20225
+ return participant.processRef;
20226
+ });
20227
+
20228
+ rootElements.push(collaboration);
20229
+ }
20230
+
20231
+ var allChildren = selfAndAllFlowElements(rootElements);
20232
+
20233
+ // if we have multiple diagrams referencing the same element, we
20234
+ // use the first in the file
20235
+ var diagramsToImport = [ bpmnDiagram ];
20236
+ var handledElements = [ bpmnElement ];
20237
+
20238
+ forEach(definitions.diagrams, function(diagram) {
20239
+ var businessObject = diagram.plane.bpmnElement;
20240
+
20241
+ if (
20242
+ allChildren.indexOf(businessObject) !== -1 &&
20243
+ handledElements.indexOf(businessObject) === -1
20244
+ ) {
20245
+ diagramsToImport.push(diagram);
20246
+ handledElements.push(businessObject);
20247
+ }
20248
+ });
20249
+
20250
+
20251
+ return diagramsToImport;
20252
+ }
20253
+
20254
+ function selfAndAllFlowElements(elements) {
20255
+ var result = [];
20256
+
20257
+ forEach(elements, function(element) {
20258
+ if (!element) {
20259
+ return;
20260
+ }
20261
+
20262
+ result.push(element);
20263
+
20264
+ result = result.concat(selfAndAllFlowElements(element.flowElements));
20265
+ });
20266
+
20267
+ return result;
20268
+ }
20269
+
20270
+ function findRootProcess(element) {
20271
+ var parent = element;
20272
+
20273
+ while (parent) {
20274
+ if (is$1(parent, 'bpmn:Process')) {
20275
+ return parent;
20276
+ }
20277
+
20278
+ parent = parent.$parent;
20279
+ }
20280
+ }
20281
+
19614
20282
  /**
19615
20283
  * This file must not be changed or exchanged.
19616
20284
  *
@@ -20101,7 +20769,7 @@
20101
20769
  try {
20102
20770
  var canvas = self.get('canvas');
20103
20771
 
20104
- var contentNode = canvas.getDefaultLayer(),
20772
+ var contentNode = canvas.getActiveLayer(),
20105
20773
  defsNode = query('defs', canvas._svg);
20106
20774
 
20107
20775
  var contents = innerSVG(contentNode),