RootElementReferenceBehavior.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import inherits from 'inherits-browser';
  2. import {
  3. find,
  4. isArray,
  5. matchPattern,
  6. some
  7. } from 'min-dash';
  8. import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
  9. import {
  10. add as collectionAdd,
  11. remove as collectionRemove
  12. } from 'diagram-js/lib/util/Collections';
  13. import {
  14. getBusinessObject,
  15. is
  16. } from '../../../util/ModelUtil';
  17. import { isAny } from '../util/ModelingUtil';
  18. import { hasEventDefinition } from '../../../util/DiUtil';
  19. /**
  20. * @typedef {import('../../../Modeler').default} Modeler
  21. * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
  22. * @typedef {import('didi').Injector} Injector
  23. * @typedef {import('../../copy-paste/ModdleCopy').default} ModdleCopy
  24. * @typedef {import('../BpmnFactory').default} BpmnFactory
  25. *
  26. * @typedef {import('../../../model/Types').Element} Element
  27. * @typedef {import('../../../model/Types').Shape} Shape
  28. *
  29. * @typedef {import('diagram-js/lib/util/Types').DirectionTRBL} DirectionTRBL
  30. */
  31. var LOW_PRIORITY = 500;
  32. /**
  33. * Add referenced root elements (error, escalation, message, signal) if they don't exist.
  34. * Copy referenced root elements on copy & paste.
  35. *
  36. * @param {Modeler} bpmnjs
  37. * @param {EventBus} eventBus
  38. * @param {Injector} injector
  39. * @param {ModdleCopy} moddleCopy
  40. * @param {BpmnFactory} bpmnFactory
  41. */
  42. export default function RootElementReferenceBehavior(
  43. bpmnjs, eventBus, injector, moddleCopy, bpmnFactory
  44. ) {
  45. injector.invoke(CommandInterceptor, this);
  46. function canHaveRootElementReference(element) {
  47. return isAny(element, [ 'bpmn:ReceiveTask', 'bpmn:SendTask' ]) ||
  48. hasAnyEventDefinition(element, [
  49. 'bpmn:ErrorEventDefinition',
  50. 'bpmn:EscalationEventDefinition',
  51. 'bpmn:MessageEventDefinition',
  52. 'bpmn:SignalEventDefinition'
  53. ]);
  54. }
  55. function hasRootElement(rootElement) {
  56. var definitions = bpmnjs.getDefinitions(),
  57. rootElements = definitions.get('rootElements');
  58. return !!find(rootElements, matchPattern({ id: rootElement.id }));
  59. }
  60. function getRootElementReferencePropertyName(eventDefinition) {
  61. if (is(eventDefinition, 'bpmn:ErrorEventDefinition')) {
  62. return 'errorRef';
  63. } else if (is(eventDefinition, 'bpmn:EscalationEventDefinition')) {
  64. return 'escalationRef';
  65. } else if (is(eventDefinition, 'bpmn:MessageEventDefinition')) {
  66. return 'messageRef';
  67. } else if (is(eventDefinition, 'bpmn:SignalEventDefinition')) {
  68. return 'signalRef';
  69. }
  70. }
  71. function getRootElement(businessObject) {
  72. if (isAny(businessObject, [ 'bpmn:ReceiveTask', 'bpmn:SendTask' ])) {
  73. return businessObject.get('messageRef');
  74. }
  75. var eventDefinitions = businessObject.get('eventDefinitions'),
  76. eventDefinition = eventDefinitions[ 0 ];
  77. return eventDefinition.get(getRootElementReferencePropertyName(eventDefinition));
  78. }
  79. function setRootElement(businessObject, rootElement) {
  80. if (isAny(businessObject, [ 'bpmn:ReceiveTask', 'bpmn:SendTask' ])) {
  81. return businessObject.set('messageRef', rootElement);
  82. }
  83. var eventDefinitions = businessObject.get('eventDefinitions'),
  84. eventDefinition = eventDefinitions[ 0 ];
  85. return eventDefinition.set(getRootElementReferencePropertyName(eventDefinition), rootElement);
  86. }
  87. // create shape
  88. this.executed([
  89. 'shape.create',
  90. 'element.updateProperties',
  91. 'element.updateModdleProperties'
  92. ], function(context) {
  93. var shape = context.shape || context.element;
  94. if (!canHaveRootElementReference(shape)) {
  95. return;
  96. }
  97. var businessObject = getBusinessObject(shape),
  98. rootElement = getRootElement(businessObject),
  99. rootElements;
  100. if (rootElement && !hasRootElement(rootElement)) {
  101. rootElements = bpmnjs.getDefinitions().get('rootElements');
  102. // add root element
  103. collectionAdd(rootElements, rootElement);
  104. context.addedRootElement = rootElement;
  105. }
  106. }, true);
  107. this.reverted([
  108. 'shape.create',
  109. 'element.updateProperties',
  110. 'element.updateModdleProperties'
  111. ], function(context) {
  112. var addedRootElement = context.addedRootElement;
  113. if (!addedRootElement) {
  114. return;
  115. }
  116. var rootElements = bpmnjs.getDefinitions().get('rootElements');
  117. // remove root element
  118. collectionRemove(rootElements, addedRootElement);
  119. }, true);
  120. eventBus.on('copyPaste.copyElement', function(context) {
  121. var descriptor = context.descriptor,
  122. element = context.element;
  123. if (element.labelTarget || !canHaveRootElementReference(element)) {
  124. return;
  125. }
  126. var businessObject = getBusinessObject(element),
  127. rootElement = getRootElement(businessObject);
  128. if (rootElement) {
  129. // TODO(nikku): clone on copy
  130. descriptor.referencedRootElement = rootElement;
  131. }
  132. });
  133. eventBus.on('copyPaste.pasteElement', LOW_PRIORITY, function(context) {
  134. var descriptor = context.descriptor,
  135. businessObject = descriptor.businessObject,
  136. referencedRootElement = descriptor.referencedRootElement;
  137. if (!referencedRootElement) {
  138. return;
  139. }
  140. if (!hasRootElement(referencedRootElement)) {
  141. referencedRootElement = moddleCopy.copyElement(
  142. referencedRootElement,
  143. bpmnFactory.create(referencedRootElement.$type)
  144. );
  145. }
  146. setRootElement(businessObject, referencedRootElement);
  147. delete descriptor.referencedRootElement;
  148. });
  149. }
  150. RootElementReferenceBehavior.$inject = [
  151. 'bpmnjs',
  152. 'eventBus',
  153. 'injector',
  154. 'moddleCopy',
  155. 'bpmnFactory'
  156. ];
  157. inherits(RootElementReferenceBehavior, CommandInterceptor);
  158. // helpers //////////
  159. function hasAnyEventDefinition(element, types) {
  160. if (!isArray(types)) {
  161. types = [ types ];
  162. }
  163. return some(types, function(type) {
  164. return hasEventDefinition(element, type);
  165. });
  166. }