DataInputAssociationBehavior.js 3.7 KB

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