CopyPasteRootElementBehavior.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. 'use strict';
  2. var inherits = require('inherits');
  3. var find = require('min-dash').find,
  4. matchPattern = require('min-dash').matchPattern;
  5. var CommandInterceptor = require('diagram-js/lib/command/CommandInterceptor').default;
  6. var collectionAdd = require('diagram-js/lib/util/Collections').add,
  7. collectionRemove = require('diagram-js/lib/util/Collections').remove;
  8. var getBusinessObject = require('bpmn-js/lib/util/ModelUtil').getBusinessObject,
  9. is = require('bpmn-js/lib/util/ModelUtil').is;
  10. var LOW_PRIORITY = 500;
  11. /**
  12. * Add referenced root elements (bpmn:Error) if they don't exist.
  13. * Copy referenced root elements on copy & paste.
  14. */
  15. function CopyPasteRootElementBehavior(
  16. bpmnjs, eventBus, injector, moddleCopy, bpmnFactory
  17. ) {
  18. injector.invoke(CommandInterceptor, this);
  19. function hasRootElement(rootElement) {
  20. var definitions = bpmnjs.getDefinitions(),
  21. rootElements = definitions.get('rootElements');
  22. return !!find(rootElements, matchPattern({ id: rootElement.id }));
  23. }
  24. // create shape
  25. this.executed('shape.create', function(context) {
  26. var shape = context.shape,
  27. businessObject = getBusinessObject(shape);
  28. if (!canHaveNestedRootElementReference(businessObject)) {
  29. return;
  30. }
  31. var referencedRootElements = getRootElements(businessObject, getReferencingElement(shape)),
  32. rootElements = bpmnjs.getDefinitions().get('rootElements');
  33. context.addedRootElements = [];
  34. referencedRootElements.forEach(function(reference) {
  35. var element = reference.referencedElement;
  36. if (element && !hasRootElement(element)) {
  37. // add root element
  38. collectionAdd(rootElements, element);
  39. context.addedRootElements.push(element);
  40. }
  41. });
  42. }, true);
  43. this.reverted('shape.create', function(context) {
  44. var addedRootElements = context.addedRootElements;
  45. if (!addedRootElements) {
  46. return;
  47. }
  48. var rootElements = bpmnjs.getDefinitions().get('rootElements');
  49. // remove root elements
  50. addedRootElements.forEach(function(addedRootElement) {
  51. collectionRemove(rootElements, addedRootElement);
  52. });
  53. }, true);
  54. eventBus.on('copyPaste.copyElement', function(context) {
  55. var descriptor = context.descriptor,
  56. element = context.element,
  57. businessObject = getBusinessObject(element);
  58. if (!canHaveNestedRootElementReference(businessObject)) {
  59. return;
  60. }
  61. var rootElements = getRootElements(businessObject, getReferencingElement(element));
  62. if (rootElements) {
  63. descriptor.referencedRootElements = rootElements;
  64. }
  65. });
  66. eventBus.on('copyPaste.pasteElement', LOW_PRIORITY, function(context) {
  67. var descriptor = context.descriptor,
  68. businessObject = descriptor.businessObject;
  69. if (!canHaveNestedRootElementReference(businessObject)) {
  70. return;
  71. }
  72. var referencedRootElements = descriptor.referencedRootElements;
  73. if (referencedRootElements && referencedRootElements.length) {
  74. referencedRootElements.forEach(function(reference) {
  75. var element = reference.referencedElement,
  76. idx = reference.idx;
  77. if (!element) {
  78. return;
  79. }
  80. if (!hasRootElement(element)) {
  81. element = moddleCopy.copyElement(
  82. element,
  83. bpmnFactory.create(element.$type)
  84. );
  85. }
  86. setRootElement(businessObject, element, idx);
  87. });
  88. }
  89. delete descriptor.referencedRootElements;
  90. });
  91. }
  92. CopyPasteRootElementBehavior.$inject = [
  93. 'bpmnjs',
  94. 'eventBus',
  95. 'injector',
  96. 'moddleCopy',
  97. 'bpmnFactory'
  98. ];
  99. inherits(CopyPasteRootElementBehavior, CommandInterceptor);
  100. module.exports = CopyPasteRootElementBehavior;
  101. // helpers //////////////////////////
  102. function getReferencingElement(element) {
  103. if (is(element, 'bpmn:ServiceTask')) {
  104. return 'camunda:ErrorEventDefinition';
  105. }
  106. }
  107. function getRootElementReferencePropertyName(bo) {
  108. if (is(bo, 'camunda:ErrorEventDefinition')) {
  109. return 'errorRef';
  110. }
  111. }
  112. function canHaveNestedRootElementReference(bo) {
  113. var isExternalServiceTask = is(bo, 'bpmn:ServiceTask') && bo.type === 'external';
  114. return isExternalServiceTask;
  115. }
  116. /**
  117. * Retrieves a list of to-be copied references for the extension elements
  118. * of a given element in the following form
  119. *
  120. * [
  121. * {
  122. * idx: 0, // position of extension in the list of extension elements
  123. * referencedElement: {ModdleElement} // reference to root element
  124. * }
  125. * ]
  126. *
  127. *
  128. * @param {ModdleElement} bo
  129. * @param {String} extensionElementType
  130. *
  131. * @returns {Array}
  132. */
  133. function getRootElements(bo, extensionElementType) {
  134. var extensionElements = bo.get('extensionElements'),
  135. filteredExtensionElements = [],
  136. rootElementReference;
  137. if (extensionElements) {
  138. filteredExtensionElements = extensionElements.values.filter(function(element) {
  139. return is(element, extensionElementType);
  140. });
  141. }
  142. var rootElements = filteredExtensionElements.reduce(function(result, element) {
  143. rootElementReference = element[getRootElementReferencePropertyName(element)];
  144. if (rootElementReference) {
  145. result.push({
  146. idx: findExtensionElement(bo, element),
  147. referencedElement: rootElementReference
  148. });
  149. }
  150. return result;
  151. }, []);
  152. return rootElements;
  153. }
  154. function setRootElement(bo, rootElement, index) {
  155. var extensionElement = bo.get('extensionElements').values[index];
  156. extensionElement.set(getRootElementReferencePropertyName(extensionElement), rootElement);
  157. }
  158. function findExtensionElement(bo, extensionElement) {
  159. var extensionElements = bo.get('extensionElements');
  160. if (!extensionElements) {
  161. return -1;
  162. }
  163. return extensionElements.values.indexOf(extensionElement);
  164. }