DrilldownBreadcrumbs.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { domify, classes } from 'min-dom';
  2. import { find } from 'min-dash';
  3. import { escapeHTML } from 'diagram-js/lib/util/EscapeUtil';
  4. import { getBusinessObject, is } from '../../util/ModelUtil';
  5. import {
  6. getPlaneIdFromShape
  7. } from '../../util/DrilldownUtil';
  8. /**
  9. * @typedef {import('diagram-js/lib/core/Canvas').default} Canvas
  10. * @typedef {import('diagram-js/lib/core/ElementRegistry').default} ElementRegistry
  11. * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
  12. *
  13. * @typedef {import('../../model/Types').Element} Element
  14. * @typedef {import('../../model/Types').Shape} Shape
  15. */
  16. var OPEN_CLASS = 'bjs-breadcrumbs-shown';
  17. /**
  18. * Adds overlays that allow switching planes on collapsed subprocesses.
  19. *
  20. * @param {EventBus} eventBus
  21. * @param {ElementRegistry} elementRegistry
  22. * @param {Canvas} canvas
  23. */
  24. export default function DrilldownBreadcrumbs(eventBus, elementRegistry, canvas) {
  25. var breadcrumbs = domify('<ul class="bjs-breadcrumbs"></ul>');
  26. var container = canvas.getContainer();
  27. var containerClasses = classes(container);
  28. container.appendChild(breadcrumbs);
  29. var businessObjectParents = [];
  30. // update breadcrumbs if name or ID of the primary shape changes
  31. eventBus.on('element.changed', function(event) {
  32. var shape = event.element,
  33. businessObject = getBusinessObject(shape);
  34. var isPresent = find(businessObjectParents, function(element) {
  35. return element === businessObject;
  36. });
  37. if (!isPresent) {
  38. return;
  39. }
  40. updateBreadcrumbs();
  41. });
  42. /**
  43. * Updates the displayed breadcrumbs. If no element is provided, only the
  44. * labels are updated.
  45. *
  46. * @param {Element} [element]
  47. */
  48. function updateBreadcrumbs(element) {
  49. if (element) {
  50. businessObjectParents = getBusinessObjectParentChain(element);
  51. }
  52. var path = businessObjectParents.map(function(parent) {
  53. var title = escapeHTML(parent.name || parent.id);
  54. var link = domify('<li><span class="bjs-crumb"><a title="' + title + '">' + title + '</a></span></li>');
  55. var parentPlane = canvas.findRoot(getPlaneIdFromShape(parent)) || canvas.findRoot(parent.id);
  56. // when the root is a collaboration, the process does not have a corresponding
  57. // element in the elementRegisty. Instead, we search for the corresponding participant
  58. if (!parentPlane && is(parent, 'bpmn:Process')) {
  59. var participant = elementRegistry.find(function(element) {
  60. var businessObject = getBusinessObject(element);
  61. return businessObject && businessObject.get('processRef') && businessObject.get('processRef') === parent;
  62. });
  63. parentPlane = canvas.findRoot(participant.id);
  64. }
  65. link.addEventListener('click', function() {
  66. canvas.setRootElement(parentPlane);
  67. });
  68. return link;
  69. });
  70. breadcrumbs.innerHTML = '';
  71. // show breadcrumbs and expose state to .djs-container
  72. var visible = path.length > 1;
  73. containerClasses.toggle(OPEN_CLASS, visible);
  74. path.forEach(function(element) {
  75. breadcrumbs.appendChild(element);
  76. });
  77. }
  78. eventBus.on('root.set', function(event) {
  79. updateBreadcrumbs(event.element);
  80. });
  81. }
  82. DrilldownBreadcrumbs.$inject = [ 'eventBus', 'elementRegistry', 'canvas' ];
  83. // helpers //////////
  84. /**
  85. * Returns the parents for the element using the business object chain,
  86. * starting with the root element.
  87. *
  88. * @param {Shape} child
  89. *
  90. * @return {Shape}
  91. */
  92. function getBusinessObjectParentChain(child) {
  93. var businessObject = getBusinessObject(child);
  94. var parents = [];
  95. for (var element = businessObject; element; element = element.$parent) {
  96. if (is(element, 'bpmn:SubProcess') || is(element, 'bpmn:Process')) {
  97. parents.push(element);
  98. }
  99. }
  100. return parents.reverse();
  101. }