DataInputAssociationBehavior.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import inherits from 'inherits-browser';
  2. import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
  3. import {
  4. add as collectionAdd,
  5. remove as collectionRemove
  6. } from 'diagram-js/lib/util/Collections';
  7. import {
  8. find
  9. } from 'min-dash';
  10. import {
  11. is
  12. } from '../../../util/ModelUtil';
  13. /**
  14. * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
  15. * @typedef {import('../BpmnFactory').default} BpmnFactory
  16. */
  17. var TARGET_REF_PLACEHOLDER_NAME = '__targetRef_placeholder';
  18. /**
  19. * This behavior makes sure we always set a fake
  20. * DataInputAssociation#targetRef as demanded by the BPMN 2.0
  21. * XSD schema.
  22. *
  23. * The reference is set to a bpmn:Property{ name: '__targetRef_placeholder' }
  24. * which is created on the fly and cleaned up afterwards if not needed
  25. * anymore.
  26. *
  27. * @param {EventBus} eventBus
  28. * @param {BpmnFactory} bpmnFactory
  29. */
  30. export default function DataInputAssociationBehavior(eventBus, bpmnFactory) {
  31. CommandInterceptor.call(this, eventBus);
  32. this.executed([
  33. 'connection.create',
  34. 'connection.delete',
  35. 'connection.move',
  36. 'connection.reconnect'
  37. ], ifDataInputAssociation(fixTargetRef));
  38. this.reverted([
  39. 'connection.create',
  40. 'connection.delete',
  41. 'connection.move',
  42. 'connection.reconnect'
  43. ], ifDataInputAssociation(fixTargetRef));
  44. function usesTargetRef(element, targetRef, removedConnection) {
  45. var inputAssociations = element.get('dataInputAssociations');
  46. return find(inputAssociations, function(association) {
  47. return association !== removedConnection &&
  48. association.targetRef === targetRef;
  49. });
  50. }
  51. function getTargetRef(element, create) {
  52. var properties = element.get('properties');
  53. var targetRefProp = find(properties, function(p) {
  54. return p.name === TARGET_REF_PLACEHOLDER_NAME;
  55. });
  56. if (!targetRefProp && create) {
  57. targetRefProp = bpmnFactory.create('bpmn:Property', {
  58. name: TARGET_REF_PLACEHOLDER_NAME
  59. });
  60. collectionAdd(properties, targetRefProp);
  61. }
  62. return targetRefProp;
  63. }
  64. function cleanupTargetRef(element, connection) {
  65. var targetRefProp = getTargetRef(element);
  66. if (!targetRefProp) {
  67. return;
  68. }
  69. if (!usesTargetRef(element, targetRefProp, connection)) {
  70. collectionRemove(element.get('properties'), targetRefProp);
  71. }
  72. }
  73. /**
  74. * Make sure targetRef is set to a valid property or
  75. * `null` if the connection is detached.
  76. *
  77. * @param {Event} event
  78. */
  79. function fixTargetRef(event) {
  80. var context = event.context,
  81. connection = context.connection,
  82. connectionBo = connection.businessObject,
  83. target = connection.target,
  84. targetBo = target && target.businessObject,
  85. newTarget = context.newTarget,
  86. newTargetBo = newTarget && newTarget.businessObject,
  87. oldTarget = context.oldTarget || context.target,
  88. oldTargetBo = oldTarget && oldTarget.businessObject;
  89. var dataAssociation = connection.businessObject,
  90. targetRefProp;
  91. if (oldTargetBo && oldTargetBo !== targetBo) {
  92. cleanupTargetRef(oldTargetBo, connectionBo);
  93. }
  94. if (newTargetBo && newTargetBo !== targetBo) {
  95. cleanupTargetRef(newTargetBo, connectionBo);
  96. }
  97. if (targetBo) {
  98. targetRefProp = getTargetRef(targetBo, true);
  99. dataAssociation.targetRef = targetRefProp;
  100. } else {
  101. dataAssociation.targetRef = null;
  102. }
  103. }
  104. }
  105. DataInputAssociationBehavior.$inject = [
  106. 'eventBus',
  107. 'bpmnFactory'
  108. ];
  109. inherits(DataInputAssociationBehavior, CommandInterceptor);
  110. /**
  111. * Only call the given function when the event
  112. * touches a bpmn:DataInputAssociation.
  113. *
  114. * @param {Function} fn
  115. * @return {Function}
  116. */
  117. function ifDataInputAssociation(fn) {
  118. return function(event) {
  119. var context = event.context,
  120. connection = context.connection;
  121. if (is(connection, 'bpmn:DataInputAssociation')) {
  122. return fn(event);
  123. }
  124. };
  125. }