ReplaceMenuProvider.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. import {
  2. getBusinessObject,
  3. is
  4. } from '../../util/ModelUtil';
  5. import {
  6. isEventSubProcess,
  7. isExpanded
  8. } from '../../util/DiUtil';
  9. import {
  10. isDifferentType
  11. } from './util/TypeUtil';
  12. import {
  13. forEach,
  14. filter,
  15. isArray
  16. } from 'min-dash';
  17. import * as replaceOptions from '../replace/ReplaceOptions';
  18. import { canBeNonInterrupting, getInterruptingProperty } from '../modeling/behavior/util/NonInterruptingUtil';
  19. import Icons from './util/Icons';
  20. /**
  21. * @typedef {import('../modeling/BpmnFactory').default} BpmnFactory
  22. * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenu').default} PopupMenu
  23. * @typedef {import('../modeling/Modeling').default} Modeling
  24. * @typedef {import('../replace/BpmnReplace').default} BpmnReplace
  25. * @typedef {import('diagram-js/lib/features/Rules').default} Rules
  26. * @typedef {import('diagram-js/lib/i18n/translate/translate').default} Translate
  27. * @typedef {import('../copy-paste/ModdleCopy').default} ModdleCopy
  28. *
  29. * @typedef {import('../../model/Types').Element} Element
  30. * @typedef {import('../../model/Types').Moddle} Moddle
  31. *
  32. * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenuProvider').PopupMenuEntries} PopupMenuEntries
  33. * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenuProvider').PopupMenuEntry} PopupMenuEntry
  34. * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenuProvider').PopupMenuEntryAction} PopupMenuEntryAction
  35. * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenuProvider').PopupMenuHeaderEntries} PopupMenuHeaderEntries
  36. * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenuProvider').default} PopupMenuProvider
  37. * @typedef {import('diagram-js/lib/features/popup-menu/PopupMenu').PopupMenuTarget} PopupMenuTarget
  38. *
  39. * @typedef {import('./ReplaceOptions').ReplaceOption} ReplaceOption
  40. */
  41. /**
  42. * A BPMN-specific popup menu provider.
  43. *
  44. * @implements {PopupMenuProvider}
  45. *
  46. * @param {BpmnFactory} bpmnFactory
  47. * @param {PopupMenu} popupMenu
  48. * @param {Modeling} modeling
  49. * @param {Moddle} moddle
  50. * @param {BpmnReplace} bpmnReplace
  51. * @param {Rules} rules
  52. * @param {Translate} translate
  53. * @param {ModdleCopy} moddleCopy
  54. */
  55. export default function ReplaceMenuProvider(
  56. bpmnFactory, popupMenu, modeling, moddle,
  57. bpmnReplace, rules, translate, moddleCopy) {
  58. this._bpmnFactory = bpmnFactory;
  59. this._popupMenu = popupMenu;
  60. this._modeling = modeling;
  61. this._moddle = moddle;
  62. this._bpmnReplace = bpmnReplace;
  63. this._rules = rules;
  64. this._translate = translate;
  65. this._moddleCopy = moddleCopy;
  66. this._register();
  67. }
  68. ReplaceMenuProvider.$inject = [
  69. 'bpmnFactory',
  70. 'popupMenu',
  71. 'modeling',
  72. 'moddle',
  73. 'bpmnReplace',
  74. 'rules',
  75. 'translate',
  76. 'moddleCopy'
  77. ];
  78. ReplaceMenuProvider.prototype._register = function() {
  79. this._popupMenu.registerProvider('bpmn-replace', this);
  80. };
  81. /**
  82. * @param {PopupMenuTarget} target
  83. *
  84. * @return {PopupMenuEntries}
  85. */
  86. ReplaceMenuProvider.prototype.getPopupMenuEntries = function(target) {
  87. var businessObject = target.businessObject;
  88. var rules = this._rules;
  89. var filteredReplaceOptions = [];
  90. if (isArray(target) || !rules.allowed('shape.replace', { element: target })) {
  91. return {};
  92. }
  93. var differentType = isDifferentType(target);
  94. if (is(businessObject, 'bpmn:DataObjectReference')) {
  95. return this._createEntries(target, replaceOptions.DATA_OBJECT_REFERENCE);
  96. }
  97. if (is(businessObject, 'bpmn:DataStoreReference') && !is(target.parent, 'bpmn:Collaboration')) {
  98. return this._createEntries(target, replaceOptions.DATA_STORE_REFERENCE);
  99. }
  100. // start events outside sub processes
  101. if (is(businessObject, 'bpmn:StartEvent') && !is(businessObject.$parent, 'bpmn:SubProcess')) {
  102. filteredReplaceOptions = filter(replaceOptions.START_EVENT, differentType);
  103. return this._createEntries(target, filteredReplaceOptions);
  104. }
  105. // expanded/collapsed pools
  106. if (is(businessObject, 'bpmn:Participant')) {
  107. filteredReplaceOptions = filter(replaceOptions.PARTICIPANT, function(replaceOption) {
  108. return isExpanded(target) !== replaceOption.target.isExpanded;
  109. });
  110. return this._createEntries(target, filteredReplaceOptions);
  111. }
  112. // start events inside event sub processes
  113. if (is(businessObject, 'bpmn:StartEvent') && isEventSubProcess(businessObject.$parent)) {
  114. filteredReplaceOptions = filter(replaceOptions.EVENT_SUB_PROCESS_START_EVENT, function(replaceOption) {
  115. var target = replaceOption.target;
  116. var isInterrupting = target.isInterrupting !== false;
  117. var isInterruptingEqual = businessObject.isInterrupting === isInterrupting;
  118. // filters elements which types and event definition are equal but have have different interrupting types
  119. return differentType(replaceOption) || !differentType(replaceOption) && !isInterruptingEqual;
  120. });
  121. return this._createEntries(target, filteredReplaceOptions);
  122. }
  123. // start events inside sub processes
  124. if (is(businessObject, 'bpmn:StartEvent') && !isEventSubProcess(businessObject.$parent)
  125. && is(businessObject.$parent, 'bpmn:SubProcess')) {
  126. filteredReplaceOptions = filter(replaceOptions.START_EVENT_SUB_PROCESS, differentType);
  127. return this._createEntries(target, filteredReplaceOptions);
  128. }
  129. // end events
  130. if (is(businessObject, 'bpmn:EndEvent')) {
  131. filteredReplaceOptions = filter(replaceOptions.END_EVENT, function(replaceOption) {
  132. var target = replaceOption.target;
  133. // hide cancel end events outside transactions
  134. if (target.eventDefinitionType == 'bpmn:CancelEventDefinition' && !is(businessObject.$parent, 'bpmn:Transaction')) {
  135. return false;
  136. }
  137. return differentType(replaceOption);
  138. });
  139. return this._createEntries(target, filteredReplaceOptions);
  140. }
  141. // boundary events
  142. if (is(businessObject, 'bpmn:BoundaryEvent')) {
  143. filteredReplaceOptions = filter(replaceOptions.BOUNDARY_EVENT, function(replaceOption) {
  144. var target = replaceOption.target;
  145. if (target.eventDefinitionType == 'bpmn:CancelEventDefinition' &&
  146. !is(businessObject.attachedToRef, 'bpmn:Transaction')) {
  147. return false;
  148. }
  149. var cancelActivity = target.cancelActivity !== false;
  150. var isCancelActivityEqual = businessObject.cancelActivity == cancelActivity;
  151. return differentType(replaceOption) || !differentType(replaceOption) && !isCancelActivityEqual;
  152. });
  153. return this._createEntries(target, filteredReplaceOptions);
  154. }
  155. // intermediate events
  156. if (is(businessObject, 'bpmn:IntermediateCatchEvent') ||
  157. is(businessObject, 'bpmn:IntermediateThrowEvent')) {
  158. filteredReplaceOptions = filter(replaceOptions.INTERMEDIATE_EVENT, differentType);
  159. return this._createEntries(target, filteredReplaceOptions);
  160. }
  161. // gateways
  162. if (is(businessObject, 'bpmn:Gateway')) {
  163. filteredReplaceOptions = filter(replaceOptions.GATEWAY, differentType);
  164. return this._createEntries(target, filteredReplaceOptions);
  165. }
  166. // transactions
  167. if (is(businessObject, 'bpmn:Transaction')) {
  168. filteredReplaceOptions = filter(replaceOptions.TRANSACTION, differentType);
  169. return this._createEntries(target, filteredReplaceOptions);
  170. }
  171. // expanded event sub processes
  172. if (isEventSubProcess(businessObject) && isExpanded(target)) {
  173. filteredReplaceOptions = filter(replaceOptions.EVENT_SUB_PROCESS, differentType);
  174. return this._createEntries(target, filteredReplaceOptions);
  175. }
  176. // expanded sub processes
  177. if (is(businessObject, 'bpmn:SubProcess') && isExpanded(target)) {
  178. filteredReplaceOptions = filter(replaceOptions.SUBPROCESS_EXPANDED, differentType);
  179. return this._createEntries(target, filteredReplaceOptions);
  180. }
  181. // collapsed ad hoc sub processes
  182. if (is(businessObject, 'bpmn:AdHocSubProcess') && !isExpanded(target)) {
  183. filteredReplaceOptions = filter(replaceOptions.TASK, function(replaceOption) {
  184. var target = replaceOption.target;
  185. var isTargetSubProcess = target.type === 'bpmn:SubProcess';
  186. var isTargetExpanded = target.isExpanded === true;
  187. return isDifferentType(target, target) && (!isTargetSubProcess || isTargetExpanded);
  188. });
  189. return this._createEntries(target, filteredReplaceOptions);
  190. }
  191. // sequence flows
  192. if (is(businessObject, 'bpmn:SequenceFlow')) {
  193. return this._createSequenceFlowEntries(target, replaceOptions.SEQUENCE_FLOW);
  194. }
  195. // flow nodes
  196. if (is(businessObject, 'bpmn:FlowNode')) {
  197. filteredReplaceOptions = filter(replaceOptions.TASK, differentType);
  198. // collapsed sub process cannot be replaced with itself
  199. if (is(businessObject, 'bpmn:SubProcess') && !isExpanded(target)) {
  200. filteredReplaceOptions = filter(filteredReplaceOptions, function(replaceOption) {
  201. return replaceOption.label !== 'Sub-process (collapsed)';
  202. });
  203. }
  204. return this._createEntries(target, filteredReplaceOptions);
  205. }
  206. return {};
  207. };
  208. /**
  209. * @param {PopupMenuTarget} target
  210. *
  211. * @return {PopupMenuHeaderEntries}
  212. */
  213. ReplaceMenuProvider.prototype.getPopupMenuHeaderEntries = function(target) {
  214. var headerEntries = {};
  215. if (is(target, 'bpmn:Activity') && !isEventSubProcess(target)) {
  216. headerEntries = {
  217. ...headerEntries,
  218. ...this._getLoopCharacteristicsHeaderEntries(target)
  219. };
  220. }
  221. if (is(target, 'bpmn:DataObjectReference')) {
  222. headerEntries = {
  223. ...headerEntries,
  224. ...this._getCollectionHeaderEntries(target)
  225. };
  226. }
  227. if (is(target, 'bpmn:Participant')) {
  228. headerEntries = {
  229. ...headerEntries,
  230. ...this._getParticipantMultiplicityHeaderEntries(target)
  231. };
  232. }
  233. if (is(target, 'bpmn:SubProcess') &&
  234. !is(target, 'bpmn:Transaction') &&
  235. !isEventSubProcess(target)) {
  236. headerEntries = {
  237. ...headerEntries,
  238. ...this._getAdHocHeaderEntries(target)
  239. };
  240. }
  241. if (canBeNonInterrupting(target)) {
  242. headerEntries = {
  243. ...headerEntries,
  244. ...this._getNonInterruptingHeaderEntries(target)
  245. };
  246. }
  247. return headerEntries;
  248. };
  249. /**
  250. * Create popup menu entries for the given target.
  251. *
  252. * @param {PopupMenuTarget} target
  253. * @param {ReplaceOption[]} replaceOptions
  254. *
  255. * @return {PopupMenuEntries}
  256. */
  257. ReplaceMenuProvider.prototype._createEntries = function(target, replaceOptions) {
  258. var entries = {};
  259. var self = this;
  260. forEach(replaceOptions, function(replaceOption) {
  261. entries[ replaceOption.actionName ] = self._createEntry(replaceOption, target);
  262. });
  263. return entries;
  264. };
  265. /**
  266. * Creates popup menu entries for the given sequence flow.
  267. *
  268. * @param {PopupMenuTarget} target
  269. * @param {ReplaceOption[]} replaceOptions
  270. *
  271. * @return {PopupMenuEntries}
  272. */
  273. ReplaceMenuProvider.prototype._createSequenceFlowEntries = function(target, replaceOptions) {
  274. var businessObject = getBusinessObject(target);
  275. var entries = {};
  276. var modeling = this._modeling,
  277. moddle = this._moddle;
  278. var self = this;
  279. forEach(replaceOptions, function(replaceOption) {
  280. switch (replaceOption.actionName) {
  281. case 'replace-with-default-flow':
  282. if (businessObject.sourceRef.default !== businessObject &&
  283. (is(businessObject.sourceRef, 'bpmn:ExclusiveGateway') ||
  284. is(businessObject.sourceRef, 'bpmn:InclusiveGateway') ||
  285. is(businessObject.sourceRef, 'bpmn:ComplexGateway') ||
  286. is(businessObject.sourceRef, 'bpmn:Activity'))) {
  287. entries = {
  288. ...entries,
  289. [ replaceOption.actionName ]: self._createEntry(replaceOption, target, function() {
  290. modeling.updateProperties(target.source, { default: businessObject });
  291. })
  292. };
  293. }
  294. break;
  295. case 'replace-with-conditional-flow':
  296. if (!businessObject.conditionExpression && is(businessObject.sourceRef, 'bpmn:Activity')) {
  297. entries = {
  298. ...entries,
  299. [ replaceOption.actionName ]: self._createEntry(replaceOption, target, function() {
  300. var conditionExpression = moddle.create('bpmn:FormalExpression', { body: '' });
  301. modeling.updateProperties(target, { conditionExpression: conditionExpression });
  302. })
  303. };
  304. }
  305. break;
  306. default:
  307. // conditional flow -> sequence flow
  308. if (is(businessObject.sourceRef, 'bpmn:Activity') && businessObject.conditionExpression) {
  309. entries = {
  310. ...entries,
  311. [ replaceOption.actionName ]: self._createEntry(replaceOption, target, function() {
  312. modeling.updateProperties(target, { conditionExpression: undefined });
  313. })
  314. };
  315. }
  316. // default flow -> sequence flow
  317. if ((is(businessObject.sourceRef, 'bpmn:ExclusiveGateway') ||
  318. is(businessObject.sourceRef, 'bpmn:InclusiveGateway') ||
  319. is(businessObject.sourceRef, 'bpmn:ComplexGateway') ||
  320. is(businessObject.sourceRef, 'bpmn:Activity')) &&
  321. businessObject.sourceRef.default === businessObject) {
  322. entries = {
  323. ...entries,
  324. [ replaceOption.actionName ]: self._createEntry(replaceOption, target, function() {
  325. modeling.updateProperties(target.source, { default: undefined });
  326. })
  327. };
  328. }
  329. }
  330. });
  331. return entries;
  332. };
  333. /**
  334. * Create a popup menu entry for the given replace option.
  335. *
  336. * @param {ReplaceOption} replaceOption
  337. * @param {PopupMenuTarget} target
  338. * @param {PopupMenuEntryAction} [action]
  339. *
  340. * @return {PopupMenuEntry}
  341. */
  342. ReplaceMenuProvider.prototype._createEntry = function(replaceOption, target, action) {
  343. var translate = this._translate;
  344. var replaceElement = this._bpmnReplace.replaceElement;
  345. var replaceAction = function() {
  346. return replaceElement(target, replaceOption.target);
  347. };
  348. var label = replaceOption.label;
  349. if (label && typeof label === 'function') {
  350. label = label(target);
  351. }
  352. action = action || replaceAction;
  353. return {
  354. label: translate(label),
  355. className: replaceOption.className,
  356. action: action
  357. };
  358. };
  359. /**
  360. * Get popup menu header entries for the loop characteristics of the given BPMN element.
  361. *
  362. * @param {PopupMenuTarget} target
  363. *
  364. * @return {PopupMenuHeaderEntries}
  365. */
  366. ReplaceMenuProvider.prototype._getLoopCharacteristicsHeaderEntries = function(target) {
  367. var self = this;
  368. var translate = this._translate;
  369. function toggleLoopEntry(event, entry) {
  370. // remove
  371. if (entry.active) {
  372. self._modeling.updateProperties(target, { loopCharacteristics: undefined });
  373. return;
  374. }
  375. const currentLoopCharacteristics = target.businessObject.get('loopCharacteristics'),
  376. newLoopCharacteristics = self._moddle.create(entry.options.loopCharacteristics);
  377. // copy old properties
  378. if (currentLoopCharacteristics) {
  379. self._moddleCopy.copyElement(currentLoopCharacteristics, newLoopCharacteristics);
  380. }
  381. // update `isSequential` property
  382. newLoopCharacteristics.set('isSequential', entry.options.isSequential);
  383. self._modeling.updateProperties(target, { loopCharacteristics: newLoopCharacteristics });
  384. }
  385. var businessObject = getBusinessObject(target),
  386. loopCharacteristics = businessObject.loopCharacteristics;
  387. var isSequential,
  388. isLoop,
  389. isParallel;
  390. if (loopCharacteristics) {
  391. isSequential = loopCharacteristics.isSequential;
  392. isLoop = loopCharacteristics.isSequential === undefined;
  393. isParallel = loopCharacteristics.isSequential !== undefined && !loopCharacteristics.isSequential;
  394. }
  395. return {
  396. 'toggle-parallel-mi' : {
  397. className: 'bpmn-icon-parallel-mi-marker',
  398. title: translate('Parallel multi-instance'),
  399. active: isParallel,
  400. action: toggleLoopEntry,
  401. options: {
  402. loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
  403. isSequential: false
  404. }
  405. },
  406. 'toggle-sequential-mi': {
  407. className: 'bpmn-icon-sequential-mi-marker',
  408. title: translate('Sequential multi-instance'),
  409. active: isSequential,
  410. action: toggleLoopEntry,
  411. options: {
  412. loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
  413. isSequential: true
  414. }
  415. },
  416. 'toggle-loop': {
  417. className: 'bpmn-icon-loop-marker',
  418. title: translate('Loop'),
  419. active: isLoop,
  420. action: toggleLoopEntry,
  421. options: {
  422. loopCharacteristics: 'bpmn:StandardLoopCharacteristics'
  423. }
  424. }
  425. };
  426. };
  427. /**
  428. * Get popup menu header entries for the collection property of the given BPMN element.
  429. *
  430. * @param {PopupMenuTarget} target
  431. *
  432. * @return {PopupMenuHeaderEntries}
  433. */
  434. ReplaceMenuProvider.prototype._getCollectionHeaderEntries = function(target) {
  435. var self = this;
  436. var translate = this._translate;
  437. var dataObject = target.businessObject.dataObjectRef;
  438. if (!dataObject) {
  439. return {};
  440. }
  441. function toggleIsCollection(event, entry) {
  442. self._modeling.updateModdleProperties(
  443. target,
  444. dataObject,
  445. { isCollection: !entry.active });
  446. }
  447. var isCollection = dataObject.isCollection;
  448. return {
  449. 'toggle-is-collection': {
  450. className: 'bpmn-icon-parallel-mi-marker',
  451. title: translate('Collection'),
  452. active: isCollection,
  453. action: toggleIsCollection,
  454. }
  455. };
  456. };
  457. /**
  458. * Get popup menu header entries for the participant multiplicity property of the given BPMN element.
  459. *
  460. * @param {PopupMenuTarget} target
  461. *
  462. * @return {PopupMenuHeaderEntries}
  463. */
  464. ReplaceMenuProvider.prototype._getParticipantMultiplicityHeaderEntries = function(target) {
  465. var self = this;
  466. var bpmnFactory = this._bpmnFactory;
  467. var translate = this._translate;
  468. function toggleParticipantMultiplicity(event, entry) {
  469. var isActive = entry.active;
  470. var participantMultiplicity;
  471. if (!isActive) {
  472. participantMultiplicity = bpmnFactory.create('bpmn:ParticipantMultiplicity');
  473. }
  474. self._modeling.updateProperties(
  475. target,
  476. { participantMultiplicity: participantMultiplicity });
  477. }
  478. var participantMultiplicity = target.businessObject.participantMultiplicity;
  479. return {
  480. 'toggle-participant-multiplicity': {
  481. className: 'bpmn-icon-parallel-mi-marker',
  482. title: translate('Participant multiplicity'),
  483. active: !!participantMultiplicity,
  484. action: toggleParticipantMultiplicity,
  485. }
  486. };
  487. };
  488. /**
  489. * Get popup menu header entries for the ad-hoc property of the given BPMN element.
  490. *
  491. * @param {PopupMenuTarget} element
  492. *
  493. * @return {PopupMenuHeaderEntries}
  494. */
  495. ReplaceMenuProvider.prototype._getAdHocHeaderEntries = function(element) {
  496. var translate = this._translate;
  497. var businessObject = getBusinessObject(element);
  498. var isAdHoc = is(businessObject, 'bpmn:AdHocSubProcess');
  499. var replaceElement = this._bpmnReplace.replaceElement;
  500. return {
  501. 'toggle-adhoc': {
  502. className: 'bpmn-icon-ad-hoc-marker',
  503. title: translate('Ad-hoc'),
  504. active: isAdHoc,
  505. action: function(event, entry) {
  506. if (isAdHoc) {
  507. return replaceElement(element, { type: 'bpmn:SubProcess' }, {
  508. autoResize: false,
  509. layoutConnection: false
  510. });
  511. } else {
  512. return replaceElement(element, { type: 'bpmn:AdHocSubProcess' }, {
  513. autoResize: false,
  514. layoutConnection: false
  515. });
  516. }
  517. }
  518. }
  519. };
  520. };
  521. ReplaceMenuProvider.prototype._getNonInterruptingHeaderEntries = function(element) {
  522. const translate = this._translate;
  523. const businessObject = getBusinessObject(element);
  524. const self = this;
  525. const interruptingProperty = getInterruptingProperty(element);
  526. const icon = is(element, 'bpmn:BoundaryEvent') ? Icons['intermediate-event-non-interrupting'] : Icons['start-event-non-interrupting'];
  527. const isNonInterrupting = !businessObject[interruptingProperty];
  528. return {
  529. 'toggle-non-interrupting': {
  530. imageHtml: icon,
  531. title: translate('Toggle non-interrupting'),
  532. active: isNonInterrupting,
  533. action: function() {
  534. self._modeling.updateProperties(element, {
  535. [interruptingProperty]: !!isNonInterrupting
  536. });
  537. }
  538. }
  539. };
  540. };