UpdateFlowNodeRefsHandler.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import {
  2. collectLanes,
  3. getLanesRoot
  4. } from '../util/LaneUtil';
  5. import {
  6. is
  7. } from '../../../util/ModelUtil';
  8. import {
  9. add as collectionAdd,
  10. remove as collectionRemove
  11. } from 'diagram-js/lib/util/Collections';
  12. import {
  13. asTRBL
  14. } from 'diagram-js/lib/layout/LayoutUtil';
  15. /**
  16. * @typedef {import('diagram-js/lib/command/CommandHandler').default} CommandHandler
  17. *
  18. * @typedef {import('diagram-js/lib/core/ElementRegistry').default} ElementRegistry
  19. *
  20. * @typedef {import('../../../model/Types').Shape} Shape
  21. */
  22. var FLOW_NODE_REFS_ATTR = 'flowNodeRef',
  23. LANES_ATTR = 'lanes';
  24. /**
  25. * A handler that updates lane refs on changed elements.
  26. *
  27. * @implements {CommandHandler}
  28. *
  29. * @param {ElementRegistry} elementRegistry
  30. */
  31. export default function UpdateFlowNodeRefsHandler(elementRegistry) {
  32. this._elementRegistry = elementRegistry;
  33. }
  34. UpdateFlowNodeRefsHandler.$inject = [
  35. 'elementRegistry'
  36. ];
  37. /**
  38. * @param {Shape} flowNodeShapes
  39. * @param {Shape} laneShapes
  40. *
  41. * @return { {
  42. * flowNode: Shape;
  43. * add: Shape[];
  44. * remove: Shape[];
  45. * }[] }
  46. */
  47. UpdateFlowNodeRefsHandler.prototype._computeUpdates = function(flowNodeShapes, laneShapes) {
  48. var handledNodes = [];
  49. var updates = [];
  50. var participantCache = {};
  51. var allFlowNodeShapes = [];
  52. function isInLaneShape(element, laneShape) {
  53. var laneTrbl = asTRBL(laneShape);
  54. var elementMid = {
  55. x: element.x + element.width / 2,
  56. y: element.y + element.height / 2
  57. };
  58. return elementMid.x > laneTrbl.left &&
  59. elementMid.x < laneTrbl.right &&
  60. elementMid.y > laneTrbl.top &&
  61. elementMid.y < laneTrbl.bottom;
  62. }
  63. function addFlowNodeShape(flowNodeShape) {
  64. if (handledNodes.indexOf(flowNodeShape) === -1) {
  65. allFlowNodeShapes.push(flowNodeShape);
  66. handledNodes.push(flowNodeShape);
  67. }
  68. }
  69. function getAllLaneShapes(flowNodeShape) {
  70. var root = getLanesRoot(flowNodeShape);
  71. if (!participantCache[root.id]) {
  72. participantCache[root.id] = collectLanes(root);
  73. }
  74. return participantCache[root.id];
  75. }
  76. function getNewLanes(flowNodeShape) {
  77. if (!flowNodeShape.parent) {
  78. return [];
  79. }
  80. var allLaneShapes = getAllLaneShapes(flowNodeShape);
  81. return allLaneShapes.filter(function(l) {
  82. return isInLaneShape(flowNodeShape, l);
  83. }).map(function(shape) {
  84. return shape.businessObject;
  85. });
  86. }
  87. laneShapes.forEach(function(laneShape) {
  88. var root = getLanesRoot(laneShape);
  89. if (!root || handledNodes.indexOf(root) !== -1) {
  90. return;
  91. }
  92. var children = root.children.filter(function(c) {
  93. return is(c, 'bpmn:FlowNode');
  94. });
  95. children.forEach(addFlowNodeShape);
  96. handledNodes.push(root);
  97. });
  98. flowNodeShapes.forEach(addFlowNodeShape);
  99. allFlowNodeShapes.forEach(function(flowNodeShape) {
  100. var flowNode = flowNodeShape.businessObject;
  101. var lanes = flowNode.get(LANES_ATTR),
  102. remove = lanes.slice(),
  103. add = getNewLanes(flowNodeShape);
  104. updates.push({ flowNode: flowNode, remove: remove, add: add });
  105. });
  106. laneShapes.forEach(function(laneShape) {
  107. var lane = laneShape.businessObject;
  108. // lane got removed XX-)
  109. if (!laneShape.parent) {
  110. lane.get(FLOW_NODE_REFS_ATTR).forEach(function(flowNode) {
  111. updates.push({ flowNode: flowNode, remove: [ lane ], add: [] });
  112. });
  113. }
  114. });
  115. return updates;
  116. };
  117. UpdateFlowNodeRefsHandler.prototype.execute = function(context) {
  118. var updates = context.updates;
  119. if (!updates) {
  120. updates = context.updates = this._computeUpdates(context.flowNodeShapes, context.laneShapes);
  121. }
  122. updates.forEach(function(update) {
  123. var flowNode = update.flowNode,
  124. lanes = flowNode.get(LANES_ATTR);
  125. // unwire old
  126. update.remove.forEach(function(oldLane) {
  127. collectionRemove(lanes, oldLane);
  128. collectionRemove(oldLane.get(FLOW_NODE_REFS_ATTR), flowNode);
  129. });
  130. // wire new
  131. update.add.forEach(function(newLane) {
  132. collectionAdd(lanes, newLane);
  133. collectionAdd(newLane.get(FLOW_NODE_REFS_ATTR), flowNode);
  134. });
  135. });
  136. // TODO(nikku): return changed elements
  137. // return [ ... ];
  138. return [];
  139. };
  140. UpdateFlowNodeRefsHandler.prototype.revert = function(context) {
  141. var updates = context.updates;
  142. updates.forEach(function(update) {
  143. var flowNode = update.flowNode,
  144. lanes = flowNode.get(LANES_ATTR);
  145. // unwire new
  146. update.add.forEach(function(newLane) {
  147. collectionRemove(lanes, newLane);
  148. collectionRemove(newLane.get(FLOW_NODE_REFS_ATTR), flowNode);
  149. });
  150. // wire old
  151. update.remove.forEach(function(oldLane) {
  152. collectionAdd(lanes, oldLane);
  153. collectionAdd(oldLane.get(FLOW_NODE_REFS_ATTR), flowNode);
  154. });
  155. });
  156. // TODO(nikku): return changed elements
  157. // return [ ... ];
  158. return [];
  159. };