Parcourir la source

保存流程节点相关数据/bpmn.js源码替换:logo隐藏

lph il y a 1 an
Parent
commit
9fe995762d
100 fichiers modifiés avec 13752 ajouts et 10 suppressions
  1. 20 0
      ruoyi-ui/src/api/bpmprocess/process.js
  2. 14 10
      ruoyi-ui/src/assets/styles/bpmn-properties-theme.scss
  3. 817 0
      ruoyi-ui/src/components/updateModule/bpmn-js/CHANGELOG.md
  4. 23 0
      ruoyi-ui/src/components/updateModule/bpmn-js/LICENSE
  5. 110 0
      ruoyi-ui/src/components/updateModule/bpmn-js/README.md
  6. 3 0
      ruoyi-ui/src/components/updateModule/bpmn-js/index.js
  7. 74 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/BaseModeler.js
  8. 787 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/BaseViewer.js
  9. 220 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/Modeler.js
  10. 31 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/NavigatedViewer.js
  11. 75 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/Viewer.js
  12. 9 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/core/index.js
  13. 157 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/BpmnRenderUtil.js
  14. 1928 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/BpmnRenderer.js
  15. 471 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/PathMap.js
  16. 116 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/TextRenderer.js
  17. 11 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/index.js
  18. 87 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/AlignElementsContextPadProvider.js
  19. 15 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/AlignElementsIcons.js
  20. 72 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/AlignElementsMenuProvider.js
  21. 39 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/BpmnAlignElements.js
  22. 23 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/index.js
  23. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-bottom-tool.svg
  24. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-horizontal-center-tool.svg
  25. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-left-tool.svg
  26. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-right-tool.svg
  27. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-tool.svg
  28. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-top-tool.svg
  29. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-vertical-center-tool.svg
  30. 18 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-place/BpmnAutoPlace.js
  31. 148 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-place/BpmnAutoPlaceUtil.js
  32. 9 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-place/index.js
  33. 38 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-resize/BpmnAutoResize.js
  34. 57 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-resize/BpmnAutoResizeProvider.js
  35. 12 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-resize/index.js
  36. 526 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/context-pad/ContextPadProvider.js
  37. 21 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/context-pad/index.js
  38. 185 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/copy-paste/BpmnCopyPaste.js
  39. 304 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/copy-paste/ModdleCopy.js
  40. 13 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/copy-paste/index.js
  41. 40 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/di-ordering/BpmnDiOrdering.js
  42. 8 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/di-ordering/index.js
  43. 55 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/BpmnDistributeElements.js
  44. 10 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/DistributeElementsIcons.js
  45. 69 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/DistributeElementsMenuProvider.js
  46. 19 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/index.js
  47. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/resources/distribute-horizontally-tool.svg
  48. 5 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/resources/distribute-vertically-tool.svg
  49. 122 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/DrilldownBreadcrumbs.js
  50. 118 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/DrilldownCentering.js
  51. 181 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/DrilldownOverlayBehavior.js
  52. 218 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/SubprocessCompatibility.js
  53. 17 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/index.js
  54. 177 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/editor-actions/BpmnEditorActions.js
  55. 10 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/editor-actions/index.js
  56. 25 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/BpmnGridSnapping.js
  57. 59 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/behavior/GridSnappingAutoPlaceBehavior.js
  58. 144 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/behavior/GridSnappingLayoutConnectionBehavior.js
  59. 36 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/behavior/GridSnappingParticipantBehavior.js
  60. 14 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/behavior/index.js
  61. 13 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/index.js
  62. 118 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/interaction-events/BpmnInteractionEvents.js
  63. 6 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/interaction-events/index.js
  64. 158 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/keyboard/BpmnKeyboardBindings.js
  65. 11 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/keyboard/index.js
  66. 138 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/LabelEditingPreview.js
  67. 426 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/LabelEditingProvider.js
  68. 67 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/LabelUtil.js
  69. 165 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/cmd/UpdateLabelHandler.js
  70. 21 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/index.js
  71. 127 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/BpmnFactory.js
  72. 399 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/BpmnLayouter.js
  73. 762 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/BpmnUpdater.js
  74. 292 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/ElementFactory.js
  75. 202 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/Modeling.js
  76. 274 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/AdaptiveLabelPositioningBehavior.js
  77. 42 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/AppendBehavior.js
  78. 35 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/AssociationBehavior.js
  79. 98 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/AttachEventBehavior.js
  80. 68 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/BoundaryEventBehavior.js
  81. 28 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/CreateBehavior.js
  82. 38 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/CreateDataObjectBehavior.js
  83. 230 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/CreateParticipantBehavior.js
  84. 158 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DataInputAssociationBehavior.js
  85. 212 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DataStoreBehavior.js
  86. 112 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DeleteLaneBehavior.js
  87. 94 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DetachEventBehavior.js
  88. 211 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DropOnFlowBehavior.js
  89. 85 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/EventBasedGatewayBehavior.js
  90. 117 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/FixHoverBehavior.js
  91. 311 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/GroupBehavior.js
  92. 81 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/ImportDockingFix.js
  93. 45 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/IsHorizontalFix.js
  94. 403 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/LabelBehavior.js
  95. 117 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/LayoutConnectionBehavior.js
  96. 89 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/MessageFlowBehavior.js
  97. 35 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/ModelingFeedback.js
  98. 82 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/RemoveElementBehavior.js
  99. 34 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/RemoveEmbeddedLabelBoundsBehavior.js
  100. 48 0
      ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/RemoveParticipantBehavior.js

+ 20 - 0
ruoyi-ui/src/api/bpmprocess/process.js

@@ -80,3 +80,23 @@ export function enableProcess(data) {
   })
 }
 
+
+// 新增流程配置
+export function addConfiguration(data) {
+  return request({
+    url: '/system/configuration',
+    method: 'post',
+    data: data,
+    baseURL: process.env.VUE_APP_BASE_API4,
+  })
+}
+
+// 修改流程配置
+export function updateConfiguration(data) {
+  return request({
+    url: '/system/configuration',
+    method: 'put',
+    data: data,
+    baseURL: process.env.VUE_APP_BASE_API4,
+  })
+}

+ 14 - 10
ruoyi-ui/src/assets/styles/bpmn-properties-theme.scss

@@ -1,5 +1,5 @@
 .bpp-properties-panel {
-  background-color: rgba(27, 31, 35, .05);
+  background-color: rgba(27, 31, 35, 0.05);
   // border-color: rgba(0, 0, 0, 0.09);
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
 }
@@ -13,7 +13,7 @@
   color: #fff;
 }
 
-.bpp-properties-header>.label {
+.bpp-properties-header > .label {
   color: #0e88eb;
   font-size: 16px;
 }
@@ -22,28 +22,28 @@
   font-size: 12px;
 }
 
-ul.bpp-properties-tabs-links>li.bpp-active a {
+ul.bpp-properties-tabs-links > li.bpp-active a {
   border-top: 2px solid #0e88eb;
   color: #0e88eb;
 }
 
-ul.bpp-properties-tabs-links>li>a {
+ul.bpp-properties-tabs-links > li > a {
   border: 1px solid #0e88eb;
   border-radius: 2px 2px 0 0;
 }
 
-.bpp-properties-group:hover>.group-toggle {
+.bpp-properties-group:hover > .group-toggle {
   background-color: #0e88eb;
 }
 
-.bpp-properties-group>.group-label {
+.bpp-properties-group > .group-label {
   font-size: 16px;
   color: #0e88eb;
   border-bottom: 2px solid #0e88eb;
   font-style: normal;
 }
 
-.bpp-properties-panel [type=text],
+.bpp-properties-panel [type="text"],
 .bpp-properties-panel [contenteditable],
 .bpp-properties-panel textarea,
 .bpp-properties-panel select {
@@ -95,10 +95,14 @@ ul.bpp-properties-tabs-links>li>a {
   border-color: #0e88eb;
 }
 
-.bpp-properties-group+.bpp-properties-group {
+.bpp-properties-group + .bpp-properties-group {
   border-top: 1px dotted #0e88eb;
 }
 
-.bpp-checkbox input{
+.bpp-checkbox input {
   margin-right: 2px;
-}
+}
+
+.bjs-powered-by {
+  display: none;
+}

+ 817 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/CHANGELOG.md

@@ -0,0 +1,817 @@
+# Changelog
+
+All notable changes to [bpmn-js](https://github.com/bpmn-io/bpmn-js) are documented here. We use [semantic versioning](http://semver.org/) for releases.
+
+
+## Unreleased
+
+___Note:__ Yet to be released changes appear here._
+
+## 9.4.1
+
+* `FIX`: ignore elements which cannot be colored ([#1734](https://github.com/bpmn-io/bpmn-js/pull/1734))
+
+## 9.4.0
+
+* `FEAT`: allow clipboard to be serialized ([#1707](https://github.com/bpmn-io/bpmn-js/pull/1707))
+* `FEAT`: allow cloning of elements ([#1707](https://github.com/bpmn-io/bpmn-js/pull/1707))
+* `FEAT`: copy groups in a safe manner ([#1707](https://github.com/bpmn-io/bpmn-js/pull/1707))
+* `FIX`: make clipboard contents immutable ([#1707](https://github.com/bpmn-io/bpmn-js/pull/1707))
+* `FIX`: do not alter inputs passed to `ElementFactory#create` ([#1711](https://github.com/bpmn-io/bpmn-js/pull/1711))
+* `FIX`: prevent bogus meta-data to be attached on paste ([#1707](https://github.com/bpmn-io/bpmn-js/pull/1707))
+* `FIX`: only claim existing IDs ([#1707](https://github.com/bpmn-io/bpmn-js/pull/1707))
+* `FIX`: prevent double paste on label creation ([#1707](https://github.com/bpmn-io/bpmn-js/pull/1707))
+* `FIX`: move labels when collapsing sub-process ([#1695](https://github.com/bpmn-io/bpmn-js/issues/1695))
+* `FIX`: assign default size when expanding element ([#1687](https://github.com/bpmn-io/bpmn-js/issues/1687))
+* `FIX`: render sequence flows always on top ([#1716](https://github.com/bpmn-io/bpmn-js/issues/1716))
+* `DEPS`: update to `diagram-js@8.9.0`
+* `DEPS`: update to `bpmn-moddle@7.1.3`
+
+## 9.3.2
+
+* `FIX`: prevent unnecessary scrollbar ([#1692](https://github.com/bpmn-io/bpmn-js/issues/1692))
+* `FIX`: check for replacement using actual target ([#1699](https://github.com/bpmn-io/bpmn-js/pull/1699))
+* `DEPS`: update to `diagram-js@8.7.1`
+
+## 9.3.1
+
+* `FIX`: properly size icons for distribute/align menu ([#1694](https://github.com/bpmn-io/bpmn-js/pull/1694))
+
+## 9.3.0
+
+* `FEAT`: add aligment and distribution menu ([#1680](https://github.com/bpmn-io/bpmn-js/issues/1680), [#1691](https://github.com/bpmn-io/bpmn-js/issues/1691))
+* `DEPS`: update to `diagram-js@8.7.0`
+
+## 9.2.2
+
+* `FIX`: correctly toggle loop characteristics ([#1673](https://github.com/bpmn-io/bpmn-js/issues/1673))
+
+## 9.2.1
+
+* `FIX`: cancel direct editing before shape deletion ([#1677](https://github.com/bpmn-io/bpmn-js/issues/1677))
+
+## 9.2.0
+
+* `FEAT`: rework select and hover interaction on the diagram ([#1616](https://github.com/bpmn-io/bpmn-js/issues/1616), [#640](https://github.com/bpmn-io/diagram-js/pull/640), [#643](https://github.com/bpmn-io/diagram-js/pull/643))
+* `FEAT`: rework diagram interaction handles ([#640](https://github.com/bpmn-io/diagram-js/pull/640))
+* `FEAT`: clearly distinguish select and hover states ([#1616](https://github.com/bpmn-io/bpmn-js/issues/1616))
+* `FEAT`: allow text annotation on sequence flows ([#1652](https://github.com/bpmn-io/bpmn-js/pull/1652))
+* `FEAT`: add multi-element context pad ([#1525](https://github.com/bpmn-io/bpmn-js/pull/1525))
+* `FEAT`: change default color to off black ([#1656](https://github.com/bpmn-io/bpmn-js/pull/1656))
+* `FEAT`: select connection after connect ([#644](https://github.com/bpmn-io/diagram-js/pull/644))
+* `FIX`: copy elements with `string` extension properties ([#1518](https://github.com/bpmn-io/bpmn-js/issues/1518))
+* `FIX`: cancel direct editing before shape deletion ([#1664](https://github.com/bpmn-io/bpmn-js/issues/1664))
+* `FIX`: remove connection on source connection deletion ([#1663](https://github.com/bpmn-io/bpmn-js/issues/1663))
+* `FIX`: set correct label color when batch coloring elements ([#1653](https://github.com/bpmn-io/bpmn-js/issues/1653))
+* `FIX`: always reconnect labels and associations ([#1659](https://github.com/bpmn-io/bpmn-js/pull/1659))
+* `FIX`: correct connection drop highlighting
+* `DEPS`: replace `inherits` with `inherits-browser`
+* `DEPS`: bump to `diagram-js@8.5.0`
+
+## 9.1.0
+
+* `FEAT`: allow to select participant and subprocess via click on body ([#1646](https://github.com/bpmn-io/bpmn-js/pull/1646))
+* `FIX`: comply with strict style-src CSP ([#1625](https://github.com/bpmn-io/bpmn-js/issues/1625))
+* `FIX`: complete direct editing when selection changes ([#1648](https://github.com/bpmn-io/bpmn-js/pull/1648))
+* `DEPS`: update to `diagram-js@8.3.0`
+* `DEPS`: update to `min-dom@3.2.0`
+
+## 9.0.4
+
+* `FIX`: remove `label` property on empty label ([#1637](https://github.com/bpmn-io/bpmn-js/issues/1637))
+* `FIX`: create drilldown overlays on `viewer.open` ([`574a67438`](https://github.com/bpmn-io/bpmn-js/commit/574a674381d6449b509396b6d17c4ca94674ea1c))
+* `FIX`: render data association inside collapsed sub-processes ([#1619](https://github.com/bpmn-io/bpmn-js/issues/1619))
+* `FIX`: preserve multi-instance properties when toggling between parallel and sequential ([#1581](https://github.com/bpmn-io/bpmn-js/issues/1581))
+* `FIX`: correct hanging sequence flow label after collapsing sub-process ([#1617](https://github.com/bpmn-io/bpmn-js/issues/1617))
+* `FIX`: correct start event not added to newly created sub-process ([#1631](https://github.com/bpmn-io/bpmn-js/issues/1631))
+
+## 9.0.3
+
+* `FIX`: submit direct editing result on drilldown ([#1609](https://github.com/bpmn-io/bpmn-js/issues/1609))
+* `DEPS`: bump to `diagram-js@8.2.0` ([2bac149](https://github.com/bpmn-io/bpmn-js/commit/2bac1495058601fec203c134b41efe5600e5fc97))
+
+## 9.0.2
+
+* `FIX`: support modeling of groups in collapsed subporcesses ([#1606](https://github.com/bpmn-io/bpmn-js/issues/1606))
+* `FIX`: override default padding of breadcrumb element ([#1608](https://github.com/bpmn-io/bpmn-js/pull/1608))
+
+## 9.0.1
+
+* `FIX`: use ES5 everywhere ([#1605](https://github.com/bpmn-io/bpmn-js/pull/1605))
+* `FIX`: support DIs without associated business object ([#1605](https://github.com/bpmn-io/bpmn-js/pull/1605))
+* `DEPS`: bump to `diagram-js@8.1.2` ([bdf9cf3](https://github.com/bpmn-io/bpmn-js/commit/bdf9cf3e752254a4c8172031d8a493955a9fca9c))
+
+## 9.0.0
+
+* `FEAT`: support drilldown and modeling of collapsed subprocesses ([#1443](https://github.com/bpmn-io/bpmn-js/issues/1443))
+* `FEAT`: update embedded label bounds when shape is moved ([#1586](https://github.com/bpmn-io/bpmn-js/pull/1586))
+* `FIX`: create di for embedded labels ([#1579](https://github.com/bpmn-io/bpmn-js/pull/1579))
+* `CHORE`: expose `BpmnRenderer` extension points ([#1585](https://github.com/bpmn-io/bpmn-js/pull/1585))
+* `DEPS`: bump to `diagram-js@8.1.1`
+
+### Breaking Changes
+
+* Reworked the link of elements to bpmn DIs. You must access the `di` directly from the diagram element instead of the `businessObject` [#1472](https://github.com/bpmn-io/bpmn-js/issues/1472).
+* Reworked `viewer.open` behavior for single planes ([#1576](https://github.com/bpmn-io/bpmn-js/pull/1576)).
+* Reworked import and `BpmnFactory` APIs [#1472](https://github.com/bpmn-io/bpmn-js/issues/1472).
+* Added `bpmn-js.css`, which is required to display drilldown overlays correctly.
+
+## 8.10.0
+
+* `CHORE`: provide `ModelUtil#isAny` utility ([#1604](https://github.com/bpmn-io/bpmn-js/pull/1604))
+* `CHORE`: provide `ModelUtil#getDi` utility ([#1604](https://github.com/bpmn-io/bpmn-js/pull/1604))
+
+## 8.9.1
+
+* `FIX`: re-use process for redo of first participant ([#1439](https://github.com/bpmn-io/bpmn-js/issues/1439))
+* `FIX`: ensure IDs are claimed when used ([#1555](https://github.com/bpmn-io/bpmn-js/issues/1555))
+* `FIX`: prevent morphing data stores outside participants ([#1508](https://github.com/bpmn-io/bpmn-js/issues/1508))
+
+## 8.9.0
+
+* `FEAT`: select newly created sub-process ([`6214772b`](https://github.com/bpmn-io/bpmn-js/commit/6214772b8519cb82f61c4867b16c112bc6344922))
+* `FEAT`: select newly created group for immediate resizing ([`56eb34cc`](https://github.com/bpmn-io/bpmn-js/commit/56eb34cc826ca0dc8ee788575a504d5fda301292))
+* `FEAT`: simplify color scheme
+* `FIX`: set label color on `bpmndi:BPMNLabel#color` ([#1543](https://github.com/bpmn-io/bpmn-js/pull/1543))
+* `FIX`: don't create illegal `bpmndi:BPMNEdge#waypoints` property ([#1544](https://github.com/bpmn-io/bpmn-js/issues/1544))
+* `FIX`: correct direct editing on touch devices
+* `DEPS`: update to `diagram-js@7.8.2`
+
+## 8.8.3
+
+* `FIX`: correct resize handles hidden behind element ([#1520](https://github.com/bpmn-io/bpmn-js/issues/1520))
+* `FIX`: handle close to source or target drop on flow ([#1541](https://github.com/bpmn-io/bpmn-js/issues/1541))
+* `CHORE`: bump to `diagram-js@7.6.3`
+
+## 8.8.2
+
+* `FIX`: properly re-use ID of a copied element if available ([#1503](https://github.com/bpmn-io/bpmn-js/pull/1509))
+
+## 8.8.1
+
+* `FIX`: re-use ID of a copied element if available ([#1503](https://github.com/bpmn-io/bpmn-js/pull/1503))
+* `CHORE`: unbuild circular dependency with `ResizeUtil` ([#1500](https://github.com/bpmn-io/bpmn-js/pull/1500))
+
+## 8.8.0
+
+* `FEAT`: give `keyboard` fine-grained control over which events to handle ([#1493](https://github.com/bpmn-io/bpmn-js/issues/1493))
+* `FIX`: correct keyboard shortcuts not working in direct editing mode ([#1493](https://github.com/bpmn-io/bpmn-js/issues/1493))
+* `DEPS`: update to `diagram-js@7.15`
+
+## 8.7.3
+
+* `FIX`: convert file to `ES6` module ([#1478](https://github.com/bpmn-io/bpmn-js/pull/1478))
+
+## 8.7.2
+
+* `CHORE`: improve error recovery in ordering provider
+* `DEPS`: update build dependencies
+
+## 8.7.1
+
+* `FIX`: allow connecting `bpmn:MessageFlow` to `bpmn:CallActivity` ([#1467](https://github.com/bpmn-io/bpmn-js/issues/1467))
+* `DEPS`: update to `bpmn-moddle@7.1.2`
+
+## 8.7.0
+
+* `FEAT`: support BPMN in Color ([#1453](https://github.com/bpmn-io/bpmn-js/pull/1453))
+* `DEPS`: update to `bpmn-moddle@7.1.1`
+
+## 8.6.2
+
+* `DEPS`: update diagram-js-direct-editing to v1.6.3
+
+## 8.6.1
+
+* `FIX`: serialize `bpmn:DataStoreReference` correctly in case if first participant is an empty pool ([#1456](https://github.com/bpmn-io/bpmn-js/issues/1456))
+
+## 8.6.0
+
+* `FEAT`: support Promise in `inject` test helper ([#1450](https://github.com/bpmn-io/bpmn-js/pull/1450))
+* `DEPS`: update to `hosted-git@2.8.9` ([#1447](https://github.com/bpmn-io/bpmn-js/pull/1447))
+
+## 8.5.0
+
+* `FEAT`: reconnect message flows when participant is collapsed ([#1432](https://github.com/bpmn-io/bpmn-js/pull/1432))
+* `FEAT`: replace elements on create ([#1340](https://github.com/bpmn-io/bpmn-js/issues/1340))
+* `FEAT`: show message name on message flow ([#777](https://github.com/bpmn-io/bpmn-js/issues/777))
+* `FEAT`: ensure auto-placed elements are visible
+* `FIX`: fix reversed connection preview ([#1431](https://github.com/bpmn-io/bpmn-js/issues/1431))
+* `FIX`: copy root element references on replace ([#1430](https://github.com/bpmn-io/bpmn-js/issues/1431))
+* `DEPS`: update to `diagram-js@7.3.0`
+
+## 8.4.0
+
+* `FIX`: disallow inserting multiple elements on a sequence flow ([#1440](https://github.com/bpmn-io/bpmn-js/issues/1440))
+
+## 8.3.1
+
+* `FIX`: correctly serialize `xml` attributes on `Any` elements
+* `DEPS`: update bump to `bpmn-moddle@7.0.5`
+
+## 8.3.0
+
+* `FEAT`: enable connection tool for text annotations ([#1428](https://github.com/bpmn-io/bpmn-js/pull/1428))
+
+## 8.2.2
+
+* `FIX`: always emit `saveXML.done`
+* `FIX`: correct path intersections not being detected in certain cases
+* `CHORE`: bump to `diagram-js@7.2.3`
+
+## 8.2.1
+
+* `FIX`: prevent bendpoint hover error ([#1387](https://github.com/bpmn-io/bpmn-js/issues/1387))
+
+## 8.2.0
+
+* `FIX`: correct label colors on connect / hover ([#1380](https://github.com/bpmn-io/bpmn-js/issues/1380))
+* `FIX`: correct new parent indicator when leaving lane ([#1413](https://github.com/bpmn-io/bpmn-js/issues/1413))
+* `CHORE`: update to `diagram-js@7.2.0`
+
+## 8.1.0
+
+* `TEST`: simplify markup created by built-in test helpers
+
+## 8.0.1
+
+* `FIX`: activate, not toggle global connect tool on palette click
+* `FIX`: only allow cancel boundary events on transactions
+* `CHORE`: add `npm start` script for demo purposes
+
+## 8.0.0
+
+* `FEAT`: improve replace label for collapsed pools ([`8faee2bd`](https://github.com/bpmn-io/bpmn-js/commit/8faee2bde9a74b75b4b6bb9b003507652e75c9c5))
+* `FEAT`: allow participant multiplicity marker to be toggled ([#533](https://github.com/bpmn-io/bpmn-js/issues/533))
+* `FEAT`: support soft breaks / discretionary hyphens in labels ([#1383](https://github.com/bpmn-io/bpmn-js/issues/1383))
+* `FEAT`: improve tool activation via keyboard shortcuts or editor actions
+* `FEAT`: allow components to react to auxiliary mouse button interactions
+* `FEAT`: move canvas on auxiliary button mouse down
+* `CHORE`: bump to `diagram-js@7`
+
+### Breaking Changes
+
+* Auxiliary mouse button events will now be passed as `element.*` mouse events to components. You must filter your event listeners to prevent reactions to these events ([`1063f7c1`](https://github.com/bpmn-io/diagram-js/commit/1063f7c18474096d3d7c9e400ce82a1bf762a157)).
+
+## 7.5.0
+
+* `FEAT`: update translatable strings ([#1364](https://github.com/bpmn-io/bpmn-js/pull/1364))
+* `FEAT`: add collection marker to DataObjectReference ([#381](https://github.com/bpmn-io/bpmn-js/issues/381))
+* `FEAT`: provide generic command for updating moddle properties ([#1376](https://github.com/bpmn-io/bpmn-js/pull/1376))
+* `FEAT`: add switch between DataStoreReference and DataObjectReference in replace menu ([#1372](https://github.com/bpmn-io/bpmn-js/issues/1372))
+* `FIX`: align collection and parallel instance markers style ([#1371](https://github.com/bpmn-io/bpmn-js/issues/1371))
+
+## 7.4.2
+
+* `FIX`: correctly emit out `element.event` after drop-on-flow ([#1366](https://github.com/bpmn-io/bpmn-js/issues/1366))
+
+## 7.4.1
+
+* `FIX`: correct keyboard zoom in key on international keyboard shortcuts ([#1362](https://github.com/bpmn-io/bpmn-js/issues/1362))
+
+## 7.4.0
+
+* `CHORE`: bump to `diagram-js@6.8.0`
+* `CHORE`: migrate to `travis-ci.com`
+
+## 7.3.1
+
+* `CHORE`: bump to `diagram-js@6.7.1`
+
+## 7.3.0
+
+* `FEAT`: disallow typed start events inside non-event based sub processes ([#831](https://github.com/bpmn-io/bpmn-js/issues/831))
+* `CHORE`: bump to `diagram-js@6.7.0`
+
+## 7.2.1
+
+* `FIX`: disallow boundary events as message flow targets ([#1300](https://github.com/bpmn-io/bpmn-js/issues/1300))
+
+## 7.2.0
+
+_Republish of `v7.1.0`._
+
+## 7.1.0
+
+* `FEAT`: allow annotating groups ([#1327](https://github.com/bpmn-io/bpmn-js/issues/1327))
+
+## 7.0.1
+
+* `FIX`: roundtrip default `xml` namespace ([#1319](https://github.com/bpmn-io/bpmn-js/issues/1319))
+* `CHORE`: bump to `bpmn-moddle@7.0.3`
+
+## 7.0.0
+
+* `FEAT`: make import and export APIs awaitable ([#812](https://github.com/bpmn-io/bpmn-js/issues/812))
+* `FEAT`: update watermark ([#1281](https://github.com/bpmn-io/bpmn-js/pull/1281))
+* `CHORE`: deprecated `import.parse.complete` context payload ([`157aec6e`](https://github.com/bpmn-io/bpmn-js/commit/157aec6e))
+* `CHORE`: clarify license terms ([`bc98a637`](https://github.com/bpmn-io/bpmn-js/commit/bc98a63712f6ac5c66d39f59bf93e296e59ad1e0))
+* `CHORE`: bump to `bpmn-moddle@7.0.1`
+
+### Breaking Changes
+
+* The toolkit now requires the ES6 `Promise` to be present. To support IE11 you must polyfill it.
+
+## 6.5.1
+
+* `FIX`: correct namespaces being removed on diagram export ([#1310](https://github.com/bpmn-io/bpmn-js/issues/1310))
+* `CHORE`: bump to `bpmn-moddle@6.0.6`
+
+## 6.5.0
+
+* `FEAT`: prefer straight layout for sub-process connections ([#1309](https://github.com/bpmn-io/bpmn-js/pull/1309))
+* `FEAT`: move common auto-place feature to diagram-js, add BPMN-specific auto-place feature ([#1284](https://github.com/bpmn-io/bpmn-js/pull/1284))
+* `CHORE`: make bpmn-font a development dependency ([`63045bdf`](https://github.com/bpmn-io/bpmn-js/commit/63045bdfa87b9f1989a2a7a509facbeb4616acda))
+* `CHORE`: bump to `diagram-js@6.6.1`
+
+## 6.4.2
+
+* `CHORE`: bump to `bpmn-moddle@6.0.5`
+
+## 6.4.1
+
+* `FIX`: parse `>` in attribute names and body tag
+* `CHORE`: bump to `bpmn-moddle@6.0.4`
+
+## 6.4.0
+
+* `FEAT`: serialize link events with an empty name ([#1296](https://github.com/bpmn-io/bpmn-js/issues/1296))
+
+## 6.3.5
+
+* `FIX`: correct accidental resizing of label target ([#1294](https://github.com/bpmn-io/bpmn-js/issues/1294))
+
+## 6.3.4
+
+* `FIX`: export BPMNDI in correct order ([#985](https://github.com/bpmn-io/bpmn-js/issues/985))
+
+## 6.3.3
+
+* `FIX`: resize empty text annotations
+* `CHORE`: bump `min-dom` version
+* `CHORE`: bump to `diagram-js@6.4.1`
+
+## 6.3.2
+
+* `FIX`: correctly move flows when adding lane ([#1287](https://github.com/bpmn-io/bpmn-js/pull/1287))
+* `FIX`: restore semantic IDs for non flow nodes ([#1285](https://github.com/bpmn-io/bpmn-js/issues/1285))
+
+## 6.3.1
+
+* `FIX`: prevent editor crash in some strict execution environments ([#1283](https://github.com/bpmn-io/bpmn-js/pull/1283))
+
+## 6.3.0
+
+* `FEAT`: generate more generic IDs for new elements ([`035bb0c1`](https://github.com/bpmn-io/bpmn-js/commit/035bb0c1fd01adbaab8a340cb1075aa57736540d))
+* `FEAT`: copy referenced root elements (message, signal, ...) ([`dc5a566e`](https://github.com/bpmn-io/bpmn-js/commit/dc5a566e107bc156505a40de3331b3832afc4b8d))
+* `FEAT`: ensure minimum size when resizing elements with space tool ([`7ee304f4`](https://github.com/bpmn-io/bpmn-js/commit/7ee304f424d1c9db46633523165d25ca1fabba1b))
+* `FIX`: correct interaction events inside `bpmn:Group` elements ([#1278](https://github.com/bpmn-io/bpmn-js/issues/1278))
+* `FIX`: correct copy and paste of collapsed sub-processes ([#1270](https://github.com/bpmn-io/bpmn-js/issues/1270))
+* `FIX`: correct various space tool related issues ([#1019](https://github.com/bpmn-io/bpmn-js/issues/1019), [#878](https://github.com/bpmn-io/bpmn-js/issues/878))
+* `CHORE`: rework space tool
+* `CHORE`: update to `diagram-js@6.4.0`
+
+## 6.2.1
+
+* `FIX`: correct serialization of `DataAssociation#assignment`
+* `CHORE`: update to `bpmn-moddle@6.0.2`
+
+## 6.2.0
+
+* `FIX`: keep non-duplicate outgoing connection when dropping on flows ([#1263](https://github.com/bpmn-io/bpmn-js/issues/1263))
+* `FIX`: properly reconnect message flows when collapsing participant
+* `CHORE`: update to `diagram-js@6.3.0`
+* `CHORE`: update to `bpmn-moddle@6.0.1`
+
+## 6.1.2
+
+* `FIX`: translate _Append ReceiveTask_
+* `FIX`: allow associations where data associations are allowed, too ([`4a675b37`](https://github.com/bpmn-io/bpmn-js/commit/4a675b378027532db413186ea292daeac087285b))
+* `FIX`: correct origin snapping on multi-element create ([`27fec8bd`](https://github.com/bpmn-io/bpmn-js/commit/27fec8bdf1c6236e7ca09b5721b74b1b45b45d39))
+* `CHORE`: update to `diagram-js@6.2.2`
+
+## 6.1.1
+
+_Republish of `v6.1.0`._
+
+## 6.1.0
+
+* `FEAT`: copy signals, escalations and errors ([#1245](https://github.com/bpmn-io/bpmn-js/pull/1245))
+* `FEAT`: provide base viewer / modeler distributions ([`bb94b206`](https://github.com/bpmn-io/bpmn-js/commit/bb94b206a7c9ab3b80e283d6513600a9591c437d))
+* `FEAT`: add horizontal and vertical resize handles
+* `FEAT`: improve connection cropping (bump to `path-intersection@2`)
+* `FIX`: correctly mark elements as changed on `{shape|connection}.create` undo
+* `FIX`: do not open replace menu after multi create ([#1255](https://github.com/bpmn-io/bpmn-js/pull/1255))
+* `CHORE`: update to `diagram-js@6.2.0`
+
+## 6.0.7
+
+* `FIX`: disable waypoints-cropping after pasting connections ([`9f8a724e`](https://github.com/bpmn-io/bpmn-js/commit/9f8a724e9a3ff66bfce14e06ab38066189111a95))
+
+## 6.0.6
+
+* `FIX`: create nested lanes in the correct parent again ([#1256](https://github.com/bpmn-io/bpmn-js/issues/1256), [#1253](https://github.com/bpmn-io/bpmn-js/issues/1253), [#1254](https://github.com/bpmn-io/bpmn-js/issues/1254))
+
+## 6.0.5
+
+* `FIX`: only update `Lane#flownNodeRefs` once during paste ([`4455c3fc`](https://github.com/bpmn-io/bpmn-js/commit/4455c3fc35290e51220566fb6539a1efc4d3612f))
+* `FIX`: do not adjust labels on paste ([`b2b607f5`](https://github.com/bpmn-io/bpmn-js/commit/b2b607f5582d3409c789d831a0896aaa55949899))
+* `FIX`: do not snap connection waypoints on paste ([`d769e6dd`](https://github.com/bpmn-io/bpmn-js/commit/d769e6ddb0cb2dc8befb2e7b31682925089ba8f1))
+
+## 6.0.4
+
+* `FIX`: correctly fix hover on cleanup ([#1247](https://github.com/bpmn-io/bpmn-js/pull/1247))
+
+## 6.0.3
+
+* `FIX`: render colored BPMN groups ([#1246](https://github.com/bpmn-io/bpmn-js/pull/1246))
+* `CHORE`: bump to `diagram-js@6.0.2`
+
+## 6.0.2
+
+* `CHORE`: bump `diagram-js-direct-editing` dependency
+
+## 6.0.1
+
+* `CHORE`: bump to `diagram-js@6.0.1`
+
+## 6.0.0
+
+* `FEAT`: rework (re-)connecting of shapes ([#427](https://github.com/bpmn-io/bpmn-js/pull/1230))
+
+### Breaking Changes
+
+Connecting and re-connecting shapes got reworked via [#427](https://github.com/bpmn-io/bpmn-js/pull/1230):
+
+* The rules `connection.reconnectStart` and `connection.reconnectEnd` got replaced with `connection.reconnect` rule
+* `BpmnLayouter#layoutConnection` waypoints can be specified via hint
+
+## 5.1.2
+
+* `FIX`: account for label pasting in label behavior ([#1227](https://github.com/bpmn-io/bpmn-js/issues/1227))
+
+## 5.1.1
+
+* `FIX`: re-select only existing elements when dragging is finished ([#1225](https://github.com/bpmn-io/bpmn-js/issues/1225))
+* `FIX`: correctly hide nested children of a collapsed shape
+* `CHORE`: bump to [`diagram-js@5.1.1`](https://github.com/bpmn-io/diagram-js/blob/develop/CHANGELOG.md#511)
+
+## 5.1.0
+
+* `FEAT`: adjust label position post creation ([`41c6af18`](https://github.com/bpmn-io/bpmn-js/commit/41c6af183014626a0f84e0bda0f8e39018f9151e))
+* `FEAT`: copy and paste boundary events ([`2e27d743`](https://github.com/bpmn-io/bpmn-js/commit/2e27d7430642439e30806941d0df43018ca729eb))
+* `FIX`: ordering after moving boundary events between hosts ([#1207](https://github.com/bpmn-io/bpmn-js/issues/1207))
+* `FIX`: do not remove sequence flow condition on type change ([`b2900786`](https://github.com/bpmn-io/bpmn-js/commit/b290078600ae4e45e7c72bd37919732e3f8fcbea))
+* `FIX`: do not remove default sequence flow on type change ([`37bcd070`](https://github.com/bpmn-io/bpmn-js/commit/37bcd070e8406a43a7316893c6b68debeaae5e26))
+* `FIX`: do not duplicate flow node references ([`168a1493`](https://github.com/bpmn-io/bpmn-js/commit/168a1493b26c3059d2440a70f7aa5991745b51e5))
+* `FIX`: ignore labels that are being created in adaptive label positioning ([`44cceb5d`](https://github.com/bpmn-io/bpmn-js/commit/44cceb5da287a0ad01d9389f475284c88eda7f7b))
+
+## 5.0.5
+
+* `FIX`: snap connections to task mid ([`86c61b0`](https://github.com/bpmn-io/bpmn-js/commit/86c61b0c0d6dcf776adda94b6d72b621644c2abe))
+* `FIX`: snap connections to sub process mid ([`83e9f05`](https://github.com/bpmn-io/bpmn-js/commit/83e9f05efab6fbe57100e11d0443291a561bdfe4))
+* `FIX`: complete direct editing when auto place starts ([`dcf440b`](https://github.com/bpmn-io/bpmn-js/commit/dcf440b07684339bdb52ba97cd1c83f9eb234044))
+* `FIX`: do not clear diagram if no diagram to clear ([#1181](https://github.com/bpmn-io/bpmn-js/issues/1181))
+* `FIX`: copy boundary events attachments ([#1190](https://github.com/bpmn-io/bpmn-js/issues/1190))
+* `FIX`: do not copy generic properties ([`a74d83`](https://github.com/bpmn-io/bpmn-js/commit/a74d838dc78aceddf88e07231cf85a4cf9e0dd95))
+
+## 5.0.4
+
+* `FIX`: correct sequence flow layout after drop on flow ([#1178](https://github.com/bpmn-io/bpmn-js/issues/1178))
+
+## 5.0.3
+
+_Republish of `v5.0.2`._
+
+## 5.0.2
+
+* `FIX`: allow reconnecting to loops ([#1121](https://github.com/bpmn-io/bpmn-js/issues/1121))
+* `CHORE`: bump to `diagram-js@5.0.1`
+
+## 5.0.1
+
+* `FIX`: import boundary event associations ([#1170](https://github.com/bpmn-io/bpmn-js/issues/1170))
+
+## 5.0.0
+
+* `FEAT`: add two-step copy and paste ([#1137](https://github.com/bpmn-io/bpmn-js/pull/1137))
+* `FEAT` add `elements.create` rule for creating multiple elements ([#1137](https://github.com/bpmn-io/bpmn-js/pull/1137))
+* `FEAT`: make containers draggable via their borders / labels only ([#1097](https://github.com/bpmn-io/bpmn-js/pull/1097), [#957](https://github.com/bpmn-io/bpmn-js/issues/957))
+* `FEAT`: allow copied elements to be filtered ([#888](https://github.com/bpmn-io/bpmn-js/issues/888))
+* `FIX`: prevent accidental dragging of participants and sub-processes ([#1097](https://github.com/bpmn-io/bpmn-js/pull/1097), [#957](https://github.com/bpmn-io/bpmn-js/issues/957))
+* `FIX`: keep labels during pool extraction ([#921](https://github.com/bpmn-io/bpmn-js/issues/921))
+* `FIX`: duplicate `bpmn:CategoryValue` when copying groups ([#1055](https://github.com/bpmn-io/bpmn-js/issues/1055))
+* `FIX`: translate group creation entry in palette ([#1146](https://github.com/bpmn-io/bpmn-js/issues/1146))
+* `CHORE`: use `element.copyProperty` event to copy category value when copying group ([`12bedca5`](https://github.com/bpmn-io/bpmn-js/pull/1137/commits/12bedca5ba2a05791591e53f554dc2310f6c1a6f))
+* `CHORE`: bump to `diagram-js@5`
+
+### Breaking Changes
+
+Copy and paste as well as create is completely reworked:
+
+* `CopyPaste`: remove `ModelCloneHelper` in favor of `ModdleCopy` service, remove `property.clone` event, add `moddleCopy.canCopyProperties`, `moddleCopy.canCopyProperty` and `moddleCopy.canSetCopiedProperty` event
+* `BpmnRules`: removed `elements.paste` rule in favor of `elements.create` rule
+* `BpmnRules`: removed `element.paste` rule
+* `ElementFactory`: use `attrs.di` property instead of `attrs.colors` for fill and stroke when creating element through `ElementFactory#createBpmnElement`
+* To prevent additional behavior on create after paste you should check for the `createElementsBehavior` hint, cf. [`bf180321`](https://github.com/bpmn-io/bpmn-js/commit/bf180321a3a40428c3f87b639b87cc3fc578066e#diff-2f0de25761fb7459e88071f83fd845c5R22)
+
+## 4.0.4
+
+* `FIX`: creating `bpmn:Participant` on single `bpmn:Group` throwing error ([#1133](https://github.com/bpmn-io/bpmn-js/issues/1133))
+* `CHORE`: bump to `diagram-js@4.0.3`
+
+## 4.0.3
+
+* `FIX`: prevent dropping on labels and `bpmn:Group` elements ([#1131](https://github.com/bpmn-io/bpmn-js/pull/1131))
+
+## 4.0.2
+
+* `FIX`: correct element positioning update ([#1129](https://github.com/bpmn-io/bpmn-js/issues/1129))
+* `CHORE`: bump to `diagram-js@4.0.2`
+
+## 4.0.1
+
+* `FIX`: prevent adding lane from crashing IE ([#746](https://github.com/bpmn-io/bpmn-js/issues/746))
+* `FIX`: correct inverse space tool visuals ([#1105](https://github.com/bpmn-io/bpmn-js/issues/1105))
+* `CHORE`: update `diagram-js-direct-editing` to prevent install warning
+* `CHORE`: update to `diagram-js@4.0.1`
+
+## 4.0.0
+
+* `FEAT`: add top, right, bottom, left snapping with container elements ([#1108](https://github.com/bpmn-io/bpmn-js/pull/1108))
+* `FEAT`: add grid snapping ([#987](https://github.com/bpmn-io/bpmn-js/pull/987))
+* `FEAT`: allow modeling of groups ([#343](https://github.com/bpmn-io/bpmn-js/issues/343))
+* `FEAT`: improve modeling rules behind event-based gateways ([#1006](https://github.com/bpmn-io/bpmn-js/pull/1006))
+* `FEAT`: adjust default collapsed pool to standard height ([`5affe2570`](https://github.com/bpmn-io/bpmn-js/commit/5affe25705082937beace6b4a568f176a0527baf))
+* `FEAT`: add connection previews ([#743](https://github.com/bpmn-io/bpmn-js/issues/743))
+* `FEAT`: create expanded sub-process with start event included ([#1039](https://github.com/bpmn-io/bpmn-js/pull/1039))
+* `FEAT`: improve automatic label adjustment for boundary events ([#1064](https://github.com/bpmn-io/bpmn-js/pull/1064))
+* `FEAT`: improve creation of initial participant ([#1046](https://github.com/bpmn-io/bpmn-js/pull/1046))
+* `FEAT`: improve boundary to host loop layout ([#1070](https://github.com/bpmn-io/bpmn-js/pull/1070))
+* `FEAT`: make connection segment move the primary connection drag behavior
+* `FEAT`: allow label and group movement everywhere ([#1080](https://github.com/bpmn-io/bpmn-js/pull/1080))
+* `FEAT`: improve message flow to participant connection in the presence of lanes ([#950](https://github.com/bpmn-io/bpmn-js/issues/950))
+* `FEAT`: allow detaching of boundary and attaching of intermediate events ([#1045](https://github.com/bpmn-io/bpmn-js/issues/1045))
+* `FEAT`: simplify requested palette and context pad translations ([#1027](https://github.com/bpmn-io/bpmn-js/pull/1027))
+* `FEAT`: simplify participant dragging in the presence of nested lanes ([`fdb299dc`](https://github.com/bpmn-io/bpmn-js/commit/fdb299dc888a7dcdb3f7674b6ed2a857864df457))
+* `FEAT`: correctly render all kinds of multiple events ([#1091](https://github.com/bpmn-io/bpmn-js/pull/1091))
+* `CHORE`: validate BPMN 2.0 XML ids as QNames ([`92c03679a`](https://github.com/bpmn-io/bpmn-js/commit/92c03679a4fd3c92a1c5ce3c97f7d366e2a5753a))
+* `FIX`: correctly handle flow reconnection + type replacement ([#896](https://github.com/bpmn-io/bpmn-js/issues/896), [#1008](https://github.com/bpmn-io/bpmn-js/issues/1008))
+
+### Breaking Changes
+
+* `CHORE`: bump to [`diagram-js@4.0.0`](https://github.com/bpmn-io/diagram-js/blob/master/CHANGELOG.md#400)
+
+## 3.5.0
+
+* `FEAT`: restore `Viewer#importDefinitions` and make it public API ([#1112](https://github.com/bpmn-io/bpmn-js/pull/1112))
+
+## 3.4.3
+
+* `FIX`: prevent HTML injection in search ([diagram-js#362](https://github.com/bpmn-io/diagram-js/pull/362))
+
+## 2.5.4
+
+* `FIX`: prevent HTML injection in search ([diagram-js#362](https://github.com/bpmn-io/diagram-js/pull/362))
+* `CHORE`: bump to `diagram-js@2.6.2`
+
+## 3.4.2
+
+* `FIX`: do not evaluate pasted text as HTML ([#1073](https://github.com/bpmn-io/bpmn-js/issues/1073))
+
+## 2.5.3
+
+* `FIX`: do not evaluate pasted text as HTML ([#1073](https://github.com/bpmn-io/bpmn-js/issues/1073))
+
+## 3.4.1
+
+_Republish of `v3.4.0` without `.git` folder._
+
+## 3.4.0
+
+* `FIX`: properly render colored connection markers ([#981](https://github.com/bpmn-io/bpmn-js/issues/981))
+* `FEAT`: add ability to open different DI diagrams ([#87](https://github.com/bpmn-io/bpmn-js/issues/87))
+* `FIX`: correctly layout straight boundary to target connections ([#891](https://github.com/bpmn-io/bpmn-js/issues/891))
+* `FEAT`: resize participant to standard size on collapse ([#975](https://github.com/bpmn-io/bpmn-js/pull/975))
+* `FEAT`: consistently layout connection on reconnect start and end ([#971](https://github.com/bpmn-io/bpmn-js/pull/971))
+* `FEAT`: layout connection on element removal ([#989](https://github.com/bpmn-io/bpmn-js/issues/989))
+* `FIX`: properly crop sequence flow ends on undo/redo ([#940](https://github.com/bpmn-io/bpmn-js/issues/940))
+* `CHORE`: bump to [`diagram-js@3.3.0`](https://github.com/bpmn-io/diagram-js/blob/master/CHANGELOG.md#330)
+
+## 3.3.1
+
+* `FIX`: ignore unchanged direct editing completion
+* `CHORE`: update to `diagram-js-direct-editing@1.4.2`
+
+## 3.3.0
+
+* `FEAT`: display `DataInput` / `DataOutput` labels ([`89719de3b`](https://github.com/bpmn-io/bpmn-js/commit/89719de3be50d9270227fd04216f7f19f0d018a2))
+* `FEAT`: support basic `DataInput` / `DataOutput` move ([#962](https://github.com/bpmn-io/bpmn-js/pull/962))
+* `FIX`: properly handle `DataInput` / `DataOutput` move ([#961](https://github.com/bpmn-io/bpmn-js/issues/961))
+
+## 3.2.3
+
+* `FIX`: update to `diagram-js-direct-editing@1.4.1` to trim trailing/leading whitespace in task names ([#763](https://github.com/bpmn-io/bpmn-js/issues/763))
+
+## 3.2.2
+
+* `FIX`: gracefully handle missing waypoints ([`45486f2`](https://github.com/bpmn-io/bpmn-js/commit/45486f2afe7f42fcac31be9ca477a7c94babe7d8))
+
+## 3.2.1
+
+* `FIX`: bump to `diagram-js@3.1.3` / `tiny-svg@2.2.1` to work around MS Edge bug ([`ed798a15`](https://github.com/bpmn-io/bpmn-js/commit/ed798a152539a613dbc9de9d61231ebbfb50987a))
+
+## 3.2.0
+
+* `FEAT`: set isHorizontal=true for new and updated participant/lane DIs ([#934](https://github.com/bpmn-io/bpmn-js/issues/934))
+
+## 3.1.1
+
+* `CHORE`: update to `diagram-js@3.1.1`
+
+## 3.1.0
+
+* `CHORE`: update to `diagram-js@3.1`
+
+## 3.0.4
+
+* `FIX`: render labels always on top ([#920](https://github.com/bpmn-io/bpmn-js/pull/920))
+
+## 3.0.3
+
+* `FIX`: do not join incoming/outgoing flows other than sequence flows on element deletion ([#917](https://github.com/bpmn-io/bpmn-js/issues/917))
+
+## 3.0.2
+
+* `FIX`: correct IE 11 delete keybinding ([#904](https://github.com/bpmn-io/bpmn-js/issues/904))
+
+## 3.0.1
+
+* `FIX`: restore copy-paste behavior
+
+## 3.0.0
+
+* `FEAT`: improve context pad tooltip titles for `EventBasedGateway` ([`350a5ab`](https://github.com/bpmn-io/bpmn-js/commit/350a5ab75ed675991599faff9615e4bbe184d491))
+* `FEAT`: display group names ([#844](https://github.com/bpmn-io/bpmn-js/issues/844))
+* `FEAT`: add ability to move selection with keyboard arrows ([#376](https://github.com/bpmn-io/bpmn-js/issues/376))
+* `FEAT`: support `SHIFT` modifier to move elements / canvas with keyboard arrows at accelerated speed
+* `FEAT`: require `Ctrl/Cmd` to be pressed as a modifier key to move the canvas via keyboard errors
+* `FEAT`: auto-expand elements when children resize ([#786](https://github.com/bpmn-io/bpmn-js/issues/786))
+* `CHORE`: bind editor actions and keyboard shortcuts for explicitly added features only ([#887](https://github.com/bpmn-io/bpmn-js/pull/887))
+* `CHORE`: update to [`diagram-js@3.0.0`](https://github.com/bpmn-io/diagram-js/blob/master/CHANGELOG.md#300)
+* `FIX`: disallow attaching of `BoundaryEvent` to a `ReceiveTask` following an `EventBasedGateway` ([#874](https://github.com/bpmn-io/bpmn-js/issues/874))
+* `FIX`: fix date in license ([#882](https://github.com/bpmn-io/bpmn-js/pull/882))
+
+### Breaking Changes
+
+* `BpmnGlobalConnect` provider got removed. Use `connection.start` rule to customize whether connection should allowed to be started ([#565](https://github.com/bpmn-io/bpmn-js/issues/565), [#870](https://github.com/bpmn-io/bpmn-js/issues/870))
+* `EditorActions` / `Keyboard` do not pull in features implicitly anymore. If you roll your own editor, include features you would like to ship with manually to provide the respective actions / keyboard bindings ([`645265ad`](https://github.com/bpmn-io/bpmn-js/commit/645265ad7e4a47e80657c671068a027752d7504f))
+* Moving the canvas with keyboard arrows now requires the `Ctrl/Cmd` modifiers to be pressed.
+
+## 2.5.2
+
+* `FIX`: correct horizontal embedded label padding
+
+## 2.5.1
+
+* `FIX`: prevent error to be thrown on lane move ([#855](https://github.com/bpmn-io/bpmn-js/issues/855))
+
+## 2.5.0
+
+* `FEAT`: snap message flows to `bpmn:Event` center during connect ([#850](https://github.com/bpmn-io/bpmn-js/issues/850))
+* `CHORE`: bump to `diagram-js@2.6.0`
+* `FIX`: allow label movement over message flow ([#849](https://github.com/bpmn-io/bpmn-js/issues/849))
+
+## 2.4.1
+
+* `FIX`: make viewer IE 9 compatible
+* `FIX`: prevent duplicate connections after drop on flow ([#774](https://github.com/bpmn-io/bpmn-js/issues/774))
+* `FIX`: fix rules not preventing redundant loop ([#836](https://github.com/bpmn-io/bpmn-js/issues/836))
+
+## 2.4.0
+
+* `FEAT`: improve layouting of boundary event to host loops ([#467](https://github.com/bpmn-io/bpmn-js/issues/467))
+* `FEAT`: allow circular activity to activity loops ([#824](https://github.com/bpmn-io/bpmn-js/issues/824))
+* `FEAT`: create label on appropriate free position ([#825](https://github.com/bpmn-io/bpmn-js/issues/825))
+* `CHORE`: bump to `diagram-js@2.5.0`
+* `FIX`: repair label position not being adapted on host move
+
+## 2.3.1
+
+* `FIX`: revert to `Arial` as the default rendering font ([#819](https://github.com/bpmn-io/bpmn-js/issues/819))
+* `FIX`: keep event definitions when switching from interrupting to non-interrupting boundary event ([#799](https://github.com/bpmn-io/bpmn-js/issues/799))
+
+## 2.3.0
+
+* `CHORE`: update to `diagram-js@2.4.0`
+
+## 2.2.1
+
+* `FIX`: correct updating of multiple data stores ([`300e7010`](https://github.com/bpmn-io/bpmn-js/commit/300e7010c4e1862394d147988dc4c4bcc09b07bc))
+
+## 2.2.0
+
+* `FEAT`: emit export events ([#813](https://github.com/bpmn-io/bpmn-js/issues/813))
+* `FEAT`: unset businessObject name if empty ([`6c081d85`](https://github.com/bpmn-io/bpmn-js/commit/6c081d854fa8a4e87eb7cdd1744be37c78652667))
+* `FEAT`: resize text annotation on text change ([`100f3fb2`](https://github.com/bpmn-io/bpmn-js/commit/100f3fb2ee6373cd4b7ad0b76e520a1afb70887e))
+* `FIX`: apply data store behavior in collaboration only ([`5cc28d5d`](https://github.com/bpmn-io/bpmn-js/commit/5cc28d5d5571287a798b189aed75095f1fd0189e))
+* `FIX`: create/update labels when updating element name via `Modeling#updateProperties` ([`4a0f6da8`](https://github.com/bpmn-io/bpmn-js/commit/4a0f6da814c45268e8a324e73a53479bd2435bbe))
+
+## 2.1.0
+
+* `FEAT`: support specifying `lineHeight` for text rendering ([#256](https://github.com/bpmn-io/diagram-js/pull/256))
+* `FEAT`: `bpmn:LaneSet` elements get an ID assigned on creation
+* `FEAT`: external labels can be deleted, clearing the elements name ([#791](https://github.com/bpmn-io/bpmn-js/pull/791))
+* `FEAT`: add ability to override default element colors ([#713](https://github.com/bpmn-io/bpmn-js/issues/713))
+* `FEAT`: add ability to override font family and size of rendered labels ([`4bb270f1`](https://github.com/bpmn-io/bpmn-js/commit/4bb270f19279db40f9cc3c179e09ee3a9a114e7c))
+
+## 2.0.1
+
+_Republish of `v2.0.0` due to registry error._
+
+## 2.0.0
+
+* `FEAT`: allow data store to be modeled between participants ([#483](https://github.com/bpmn-io/bpmn-js/issues/483))
+* `CHORE`: update to [`diagram-js@2.0.0`](https://github.com/bpmn-io/diagram-js/blob/master/CHANGELOG.md#200)
+* `FIX`: correctly handle missing `bpmndi:Label` bounds during model updating ([#794](https://github.com/bpmn-io/bpmn-js/issues/794))
+
+### Breaking Changes
+
+* The `PopupMenu` API got rewritten, cf. [`b1852e1d`](https://github.com/bpmn-io/diagram-js/pull/254/commits/b1852e1d71f67bd36ae1eb02748d2d0cbf124625)
+
+## 1.3.3
+
+* `CHORE`: update to [`bpmn-moddle@5.1.5`](https://github.com/bpmn-io/bpmn-moddle/blob/master/CHANGELOG.md#515)
+
+## 1.3.2
+
+* `FIX`: correctly serialize extension attributes on `bpmn:Expression`
+
+## 1.3.1
+
+* `FIX`: correctly auto-place from boundary events attached to host edges ([#788](https://github.com/bpmn-io/bpmn-js/issues/788))
+
+## 1.3.0
+
+* `FEAT`: expose additional `BpmnTreeWalker` APIs for advanced import use-cases
+* `CHORE`: bump diagram-js and object-refs version
+
+## 1.2.1
+
+* `FIX`: correct side-effects config to not include `*.css` files
+
+## 1.2.0
+
+* `FEAT`: add initial snapping when creating associations
+* `CHORE`: update to `diagram-js@1.3.0`
+* `FIX`: allow message flows between collapsed pools
+* `FIX`: complete direct editing on popup menu use
+* `FIX`: focus label editing box on element creation
+
+## 1.1.1
+
+* `FIX`: escape `data-element-id` in CSS selectors
+
+## 1.1.0
+
+* `FEAT`: show gateway icon on context pad without marker ([`15dfab6b`](https://github.com/bpmn-io/bpmn-js/commit/15dfab6b5b12dd184acf070f2ab3ad205d1b245c))
+
+## 1.0.4
+
+* `FIX`: properly wire `$parent` on copy + paste
+* `FIX`: improve boundary event rendering to correct SVG to image conversion
+
+## 1.0.3
+
+* `FIX`: re-expose `TestHelper#bootstrapBpmnJS` util
+
+## 1.0.2
+
+* `FIX`: correct library default export
+
+## 1.0.1
+
+_Republished 1.0.0 with CHANGELOG entries._
+
+## 1.0.0
+
+* `CHORE`: convert code base to ES modules
+* `CHORE`: update utility toolbelt
+
+### Breaking Changes
+
+* You must now configure a module transpiler such as Babel or Webpack to handle ES module imports and exports.
+
+## 0.31.0
+
+* `FEAT`: encode entities in body properties during XML export
+* `CHORE`: bump to [`bpmn-moddle@4.0.0`](https://github.com/bpmn-io/bpmn-moddle/releases/tag/v4.0.0)
+* `CHORE`: bump utility version
+
+## 0.30.0
+
+* `CHORE`: bump to [`diagram-js@0.31.0`](https://github.com/bpmn-io/diagram-js/releases/tag/v0.31.0)
+
+## ...
+
+Check `git log` for earlier history.

+ 23 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/LICENSE

@@ -0,0 +1,23 @@
+Copyright (c) 2014-present Camunda Services GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in the
+Software without restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The source code responsible for displaying the bpmn.io project watermark that
+links back to https://bpmn.io as part of rendered diagrams MUST NOT be
+removed or changed. When this software is being used in a website or application,
+the watermark must stay fully visible and not visually overlapped by other elements.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.

+ 110 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/README.md

@@ -0,0 +1,110 @@
+# bpmn-js - BPMN 2.0 for the web
+
+[![Build Status](https://github.com/bpmn-io/bpmn-js/workflows/CI/badge.svg)](https://github.com/bpmn-io/bpmn-js/actions?query=workflow%3ACI)
+
+View and edit BPMN 2.0 diagrams in the browser.
+
+[![bpmn-js screencast](./resources/screencast.gif "bpmn-js in action")](http://demo.bpmn.io/s/start)
+
+
+## Installation
+
+Use the library [pre-packaged](https://github.com/bpmn-io/bpmn-js-examples/tree/master/pre-packaged)
+or include it [via npm](https://github.com/bpmn-io/bpmn-js-examples/tree/master/bundling)
+into your node-style web-application.
+
+## Usage
+
+To get started, create a [bpmn-js](https://github.com/bpmn-io/bpmn-js) instance
+and render [BPMN 2.0 diagrams](https://www.omg.org/spec/BPMN/2.0.2/) in the browser:
+
+```javascript
+const xml = '...'; // my BPMN 2.0 xml
+const viewer = new BpmnJS({
+  container: 'body'
+});
+
+try {
+  const { warnings } = await viewer.importXML(xml);
+
+  console.log('rendered');
+} catch (err) {
+  console.log('error rendering', err);
+}
+```
+
+Checkout our [examples](https://github.com/bpmn-io/bpmn-js-examples) for many
+more supported usage scenarios.
+
+
+### Dynamic Attach/Detach
+
+You may attach or detach the viewer dynamically to any element on the page, too:
+
+```javascript
+const viewer = new BpmnJS();
+
+// attach it to some element
+viewer.attachTo('#container');
+
+// detach the panel
+viewer.detach();
+```
+
+
+## Resources
+
+* [Demo](http://demo.bpmn.io)
+* [Issues](https://github.com/bpmn-io/bpmn-js/issues)
+* [Examples](https://github.com/bpmn-io/bpmn-js-examples)
+* [Forum](https://forum.bpmn.io)
+* [Changelog](./CHANGELOG.md)
+
+
+## Build and Run
+
+Prepare the project by installing all dependencies:
+
+```sh
+npm install
+```
+
+Then, depending on your use-case you may run any of the following commands:
+
+```sh
+# build the library and run all tests
+npm run all
+
+# spin up a single local modeler instance
+npm start
+
+# run the full development setup
+npm run dev
+```
+
+You may need to perform [additional project setup](./docs/project/SETUP.md) when
+building the latest development snapshot.
+
+
+## Related
+
+bpmn-js builds on top of a few powerful tools:
+
+* [bpmn-moddle](https://github.com/bpmn-io/bpmn-moddle): Read / write support for BPMN 2.0 XML in the browsers
+* [diagram-js](https://github.com/bpmn-io/diagram-js): Diagram rendering and editing toolkit
+
+
+## Contributing
+
+Please checkout our [contributing guidelines](./.github/CONTRIBUTING.md) if you plan to
+file an issue or pull request.
+
+
+## Code of Conduct
+
+By participating to this project, please uphold to our [Code of Conduct](https://github.com/bpmn-io/.github/blob/master/.github/CODE_OF_CONDUCT.md).
+
+
+## License
+
+Use under the terms of the [bpmn.io license](http://bpmn.io/license).

+ 3 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/index.js

@@ -0,0 +1,3 @@
+export {
+  default
+} from './lib/Viewer';

+ 74 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/BaseModeler.js

@@ -0,0 +1,74 @@
+import inherits from 'inherits-browser';
+
+import Ids from 'ids';
+
+import BaseViewer from './BaseViewer';
+
+
+/**
+ * A base modeler for BPMN 2.0 diagrams.
+ *
+ * Have a look at {@link Modeler} for a bundle that includes actual features.
+ *
+ * @param {Object} [options] configuration options to pass to the viewer
+ * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
+ * @param {string|number} [options.width] the width of the viewer
+ * @param {string|number} [options.height] the height of the viewer
+ * @param {Object} [options.moddleExtensions] extension packages to provide
+ * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
+ * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
+ */
+export default function BaseModeler(options) {
+  BaseViewer.call(this, options);
+
+  // hook ID collection into the modeler
+  this.on('import.parse.complete', function(event) {
+    if (!event.error) {
+      this._collectIds(event.definitions, event.elementsById);
+    }
+  }, this);
+
+  this.on('diagram.destroy', function() {
+    this.get('moddle').ids.clear();
+  }, this);
+}
+
+inherits(BaseModeler, BaseViewer);
+
+
+/**
+ * Create a moddle instance, attaching ids to it.
+ *
+ * @param {Object} options
+ */
+BaseModeler.prototype._createModdle = function(options) {
+  var moddle = BaseViewer.prototype._createModdle.call(this, options);
+
+  // attach ids to moddle to be able to track
+  // and validated ids in the BPMN 2.0 XML document
+  // tree
+  moddle.ids = new Ids([ 32, 36, 1 ]);
+
+  return moddle;
+};
+
+/**
+ * Collect ids processed during parsing of the
+ * definitions object.
+ *
+ * @param {ModdleElement} definitions
+ * @param {Context} context
+ */
+BaseModeler.prototype._collectIds = function(definitions, elementsById) {
+
+  var moddle = definitions.$model,
+      ids = moddle.ids,
+      id;
+
+  // remove references from previous import
+  ids.clear();
+
+  for (id in elementsById) {
+    ids.claim(id, elementsById[id]);
+  }
+};

+ 787 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/BaseViewer.js

@@ -0,0 +1,787 @@
+/**
+ * The code in the <project-logo></project-logo> area
+ * must not be changed.
+ *
+ * @see http://bpmn.io/license for more information.
+ */
+import {
+  assign,
+  find,
+  isNumber,
+  omit
+} from 'min-dash';
+
+import {
+  domify,
+  assignStyle,
+  query as domQuery,
+  remove as domRemove
+} from 'min-dom';
+
+import {
+  innerSVG
+} from 'tiny-svg';
+
+import Diagram from 'diagram-js';
+import BpmnModdle from 'bpmn-moddle';
+
+import inherits from 'inherits-browser';
+
+import {
+  importBpmnDiagram
+} from './import/Importer';
+
+import {
+  wrapForCompatibility
+} from './util/CompatibilityUtil';
+
+/**
+ * A base viewer for BPMN 2.0 diagrams.
+ *
+ * Have a look at {@link Viewer}, {@link NavigatedViewer} or {@link Modeler} for
+ * bundles that include actual features.
+ *
+ * @param {Object} [options] configuration options to pass to the viewer
+ * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
+ * @param {string|number} [options.width] the width of the viewer
+ * @param {string|number} [options.height] the height of the viewer
+ * @param {Object} [options.moddleExtensions] extension packages to provide
+ * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
+ * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
+ */
+export default function BaseViewer(options) {
+
+  options = assign({}, DEFAULT_OPTIONS, options);
+
+  this._moddle = this._createModdle(options);
+
+  this._container = this._createContainer(options);
+
+  /* <project-logo> */
+
+  addProjectLogo(this._container);
+
+  /* </project-logo> */
+
+  this._init(this._container, this._moddle, options);
+}
+
+inherits(BaseViewer, Diagram);
+
+/**
+* The importXML result.
+*
+* @typedef {Object} ImportXMLResult
+*
+* @property {Array<string>} warnings
+*/
+
+/**
+* The importXML error.
+*
+* @typedef {Error} ImportXMLError
+*
+* @property {Array<string>} warnings
+*/
+
+/**
+ * Parse and render a BPMN 2.0 diagram.
+ *
+ * Once finished the viewer reports back the result to the
+ * provided callback function with (err, warnings).
+ *
+ * ## Life-Cycle Events
+ *
+ * During import the viewer will fire life-cycle events:
+ *
+ *   * import.parse.start (about to read model from xml)
+ *   * import.parse.complete (model read; may have worked or not)
+ *   * import.render.start (graphical import start)
+ *   * import.render.complete (graphical import finished)
+ *   * import.done (everything done)
+ *
+ * You can use these events to hook into the life-cycle.
+ *
+ * @param {string} xml the BPMN 2.0 xml
+ * @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
+ *
+ * Returns {Promise<ImportXMLResult, ImportXMLError>}
+ */
+BaseViewer.prototype.importXML = wrapForCompatibility(function importXML(xml, bpmnDiagram) {
+
+  var self = this;
+
+  function ParseCompleteEvent(data) {
+
+    var event = self.get('eventBus').createEvent(data);
+
+    // TODO(nikku): remove with future bpmn-js version
+    Object.defineProperty(event, 'context', {
+      enumerable: true,
+      get: function () {
+
+        console.warn(new Error(
+          'import.parse.complete <context> is deprecated ' +
+          'and will be removed in future library versions'
+        ));
+
+        return {
+          warnings: data.warnings,
+          references: data.references,
+          elementsById: data.elementsById
+        };
+      }
+    });
+
+    return event;
+  }
+
+  return new Promise(function (resolve, reject) {
+
+    // hook in pre-parse listeners +
+    // allow xml manipulation
+    xml = self._emit('import.parse.start', { xml: xml }) || xml;
+
+    self._moddle.fromXML(xml, 'bpmn:Definitions').then(function (result) {
+      var definitions = result.rootElement;
+      var references = result.references;
+      var parseWarnings = result.warnings;
+      var elementsById = result.elementsById;
+
+      // hook in post parse listeners +
+      // allow definitions manipulation
+      definitions = self._emit('import.parse.complete', ParseCompleteEvent({
+        error: null,
+        definitions: definitions,
+        elementsById: elementsById,
+        references: references,
+        warnings: parseWarnings
+      })) || definitions;
+
+      self.importDefinitions(definitions, bpmnDiagram).then(function (result) {
+        var allWarnings = [].concat(parseWarnings, result.warnings || []);
+
+        self._emit('import.done', { error: null, warnings: allWarnings });
+
+        return resolve({ warnings: allWarnings });
+      }).catch(function (err) {
+        var allWarnings = [].concat(parseWarnings, err.warnings || []);
+
+        self._emit('import.done', { error: err, warnings: allWarnings });
+
+        return reject(addWarningsToError(err, allWarnings));
+      });
+    }).catch(function (err) {
+
+      self._emit('import.parse.complete', {
+        error: err
+      });
+
+      err = checkValidationError(err);
+
+      self._emit('import.done', { error: err, warnings: err.warnings });
+
+      return reject(err);
+    });
+  });
+});
+
+/**
+* The importDefinitions result.
+*
+* @typedef {Object} ImportDefinitionsResult
+*
+* @property {Array<string>} warnings
+*/
+
+/**
+* The importDefinitions error.
+*
+* @typedef {Error} ImportDefinitionsError
+*
+* @property {Array<string>} warnings
+*/
+
+/**
+ * Import parsed definitions and render a BPMN 2.0 diagram.
+ *
+ * Once finished the viewer reports back the result to the
+ * provided callback function with (err, warnings).
+ *
+ * ## Life-Cycle Events
+ *
+ * During import the viewer will fire life-cycle events:
+ *
+ *   * import.render.start (graphical import start)
+ *   * import.render.complete (graphical import finished)
+ *
+ * You can use these events to hook into the life-cycle.
+ *
+ * @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
+ * @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
+ *
+ * Returns {Promise<ImportDefinitionsResult, ImportDefinitionsError>}
+ */
+BaseViewer.prototype.importDefinitions = wrapForCompatibility(function importDefinitions(definitions, bpmnDiagram) {
+
+  var self = this;
+
+  return new Promise(function (resolve, reject) {
+
+    self._setDefinitions(definitions);
+
+    self.open(bpmnDiagram).then(function (result) {
+
+      var warnings = result.warnings;
+
+      return resolve({ warnings: warnings });
+    }).catch(function (err) {
+
+      return reject(err);
+    });
+  });
+});
+
+/**
+ * The open result.
+ *
+ * @typedef {Object} OpenResult
+ *
+ * @property {Array<string>} warnings
+ */
+
+/**
+* The open error.
+*
+* @typedef {Error} OpenError
+*
+* @property {Array<string>} warnings
+*/
+
+/**
+ * Open diagram of previously imported XML.
+ *
+ * Once finished the viewer reports back the result to the
+ * provided callback function with (err, warnings).
+ *
+ * ## Life-Cycle Events
+ *
+ * During switch the viewer will fire life-cycle events:
+ *
+ *   * import.render.start (graphical import start)
+ *   * import.render.complete (graphical import finished)
+ *
+ * You can use these events to hook into the life-cycle.
+ *
+ * @param {string|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
+ *
+ * Returns {Promise<OpenResult, OpenError>}
+ */
+BaseViewer.prototype.open = wrapForCompatibility(function open(bpmnDiagramOrId) {
+
+  var definitions = this._definitions;
+  var bpmnDiagram = bpmnDiagramOrId;
+
+  var self = this;
+
+  return new Promise(function (resolve, reject) {
+    if (!definitions) {
+      var err1 = new Error('no XML imported');
+
+      return reject(addWarningsToError(err1, []));
+    }
+
+    if (typeof bpmnDiagramOrId === 'string') {
+      bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
+
+      if (!bpmnDiagram) {
+        var err2 = new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found');
+
+        return reject(addWarningsToError(err2, []));
+      }
+    }
+
+    // clear existing rendered diagram
+    // catch synchronous exceptions during #clear()
+    try {
+      self.clear();
+    } catch (error) {
+
+      return reject(addWarningsToError(error, []));
+    }
+
+    // perform graphical import
+    importBpmnDiagram(self, definitions, bpmnDiagram).then(function (result) {
+
+      var warnings = result.warnings;
+
+      return resolve({ warnings: warnings });
+    }).catch(function (err) {
+
+      return reject(err);
+    });
+  });
+});
+
+/**
+ * The saveXML result.
+ *
+ * @typedef {Object} SaveXMLResult
+ *
+ * @property {string} xml
+ */
+
+/**
+ * Export the currently displayed BPMN 2.0 diagram as
+ * a BPMN 2.0 XML document.
+ *
+ * ## Life-Cycle Events
+ *
+ * During XML saving the viewer will fire life-cycle events:
+ *
+ *   * saveXML.start (before serialization)
+ *   * saveXML.serialized (after xml generation)
+ *   * saveXML.done (everything done)
+ *
+ * You can use these events to hook into the life-cycle.
+ *
+ * @param {Object} [options] export options
+ * @param {boolean} [options.format=false] output formatted XML
+ * @param {boolean} [options.preamble=true] output preamble
+ *
+ * Returns {Promise<SaveXMLResult, Error>}
+ */
+BaseViewer.prototype.saveXML = wrapForCompatibility(function saveXML(options) {
+
+  options = options || {};
+
+  var self = this;
+
+  var definitions = this._definitions;
+
+  return new Promise(function (resolve) {
+
+    if (!definitions) {
+      return resolve({
+        error: new Error('no definitions loaded')
+      });
+    }
+
+    // allow to fiddle around with definitions
+    definitions = self._emit('saveXML.start', {
+      definitions: definitions
+    }) || definitions;
+
+    self._moddle.toXML(definitions, options).then(function (result) {
+
+      var xml = result.xml;
+
+      xml = self._emit('saveXML.serialized', {
+        xml: xml
+      }) || xml;
+
+      return resolve({
+        xml: xml
+      });
+    });
+  }).catch(function (error) {
+    return { error: error };
+  }).then(function (result) {
+
+    self._emit('saveXML.done', result);
+
+    var error = result.error;
+
+    if (error) {
+      return Promise.reject(error);
+    }
+
+    return result;
+  });
+});
+
+/**
+ * The saveSVG result.
+ *
+ * @typedef {Object} SaveSVGResult
+ *
+ * @property {string} svg
+ */
+
+/**
+ * Export the currently displayed BPMN 2.0 diagram as
+ * an SVG image.
+ *
+ * ## Life-Cycle Events
+ *
+ * During SVG saving the viewer will fire life-cycle events:
+ *
+ *   * saveSVG.start (before serialization)
+ *   * saveSVG.done (everything done)
+ *
+ * You can use these events to hook into the life-cycle.
+ *
+ * @param {Object} [options]
+ *
+ * Returns {Promise<SaveSVGResult, Error>}
+ */
+BaseViewer.prototype.saveSVG = wrapForCompatibility(function saveSVG(options) {
+
+  options = options || {};
+
+  var self = this;
+
+  return new Promise(function (resolve, reject) {
+
+    self._emit('saveSVG.start');
+
+    var svg, err;
+
+    try {
+      var canvas = self.get('canvas');
+
+      var contentNode = canvas.getActiveLayer(),
+        defsNode = domQuery('defs', canvas._svg);
+
+      var contents = innerSVG(contentNode),
+        defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
+
+      var bbox = contentNode.getBBox();
+
+      svg =
+        '<?xml version="1.0" encoding="utf-8"?>\n' +
+        '<!-- created with bpmn-js / http://bpmn.io -->\n' +
+        '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
+        '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
+        'width="' + bbox.width + '" height="' + bbox.height + '" ' +
+        'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
+        defs + contents +
+        '</svg>';
+    } catch (e) {
+      err = e;
+    }
+
+    self._emit('saveSVG.done', {
+      error: err,
+      svg: svg
+    });
+
+    if (!err) {
+      return resolve({ svg: svg });
+    }
+
+    return reject(err);
+  });
+});
+
+/**
+ * Get a named diagram service.
+ *
+ * @example
+ *
+ * var elementRegistry = viewer.get('elementRegistry');
+ * var startEventShape = elementRegistry.get('StartEvent_1');
+ *
+ * @param {string} name
+ *
+ * @return {Object} diagram service instance
+ *
+ * @method BaseViewer#get
+ */
+
+/**
+ * Invoke a function in the context of this viewer.
+ *
+ * @example
+ *
+ * viewer.invoke(function(elementRegistry) {
+ *   var startEventShape = elementRegistry.get('StartEvent_1');
+ * });
+ *
+ * @param {Function} fn to be invoked
+ *
+ * @return {Object} the functions return value
+ *
+ * @method BaseViewer#invoke
+ */
+
+
+BaseViewer.prototype._setDefinitions = function (definitions) {
+  this._definitions = definitions;
+};
+
+BaseViewer.prototype.getModules = function () {
+  return this._modules;
+};
+
+/**
+ * Remove all drawn elements from the viewer.
+ *
+ * After calling this method the viewer can still
+ * be reused for opening another diagram.
+ *
+ * @method BaseViewer#clear
+ */
+BaseViewer.prototype.clear = function () {
+  if (!this.getDefinitions()) {
+
+    // no diagram to clear
+    return;
+  }
+
+  // remove drawn elements
+  Diagram.prototype.clear.call(this);
+};
+
+/**
+ * Destroy the viewer instance and remove all its
+ * remainders from the document tree.
+ */
+BaseViewer.prototype.destroy = function () {
+
+  // diagram destroy
+  Diagram.prototype.destroy.call(this);
+
+  // dom detach
+  domRemove(this._container);
+};
+
+/**
+ * Register an event listener
+ *
+ * Remove a previously added listener via {@link #off(event, callback)}.
+ *
+ * @param {string} event
+ * @param {number} [priority]
+ * @param {Function} callback
+ * @param {Object} [that]
+ */
+BaseViewer.prototype.on = function (event, priority, callback, target) {
+  return this.get('eventBus').on(event, priority, callback, target);
+};
+
+/**
+ * De-register an event listener
+ *
+ * @param {string} event
+ * @param {Function} callback
+ */
+BaseViewer.prototype.off = function (event, callback) {
+  this.get('eventBus').off(event, callback);
+};
+
+BaseViewer.prototype.attachTo = function (parentNode) {
+
+  if (!parentNode) {
+    throw new Error('parentNode required');
+  }
+
+  // ensure we detach from the
+  // previous, old parent
+  this.detach();
+
+  // unwrap jQuery if provided
+  if (parentNode.get && parentNode.constructor.prototype.jquery) {
+    parentNode = parentNode.get(0);
+  }
+
+  if (typeof parentNode === 'string') {
+    parentNode = domQuery(parentNode);
+  }
+
+  parentNode.appendChild(this._container);
+
+  this._emit('attach', {});
+
+  this.get('canvas').resized();
+};
+
+BaseViewer.prototype.getDefinitions = function () {
+  return this._definitions;
+};
+
+BaseViewer.prototype.detach = function () {
+
+  var container = this._container,
+    parentNode = container.parentNode;
+
+  if (!parentNode) {
+    return;
+  }
+
+  this._emit('detach', {});
+
+  parentNode.removeChild(container);
+};
+
+BaseViewer.prototype._init = function (container, moddle, options) {
+
+  var baseModules = options.modules || this.getModules(),
+    additionalModules = options.additionalModules || [],
+    staticModules = [
+      {
+        bpmnjs: ['value', this],
+        moddle: ['value', moddle]
+      }
+    ];
+
+  var diagramModules = [].concat(staticModules, baseModules, additionalModules);
+
+  var diagramOptions = assign(omit(options, ['additionalModules']), {
+    canvas: assign({}, options.canvas, { container: container }),
+    modules: diagramModules
+  });
+
+  // invoke diagram constructor
+  Diagram.call(this, diagramOptions);
+
+  if (options && options.container) {
+    this.attachTo(options.container);
+  }
+};
+
+/**
+ * Emit an event on the underlying {@link EventBus}
+ *
+ * @param  {string} type
+ * @param  {Object} event
+ *
+ * @return {Object} event processing result (if any)
+ */
+BaseViewer.prototype._emit = function (type, event) {
+  return this.get('eventBus').fire(type, event);
+};
+
+BaseViewer.prototype._createContainer = function (options) {
+
+  var container = domify('<div class="bjs-container"></div>');
+
+  assignStyle(container, {
+    width: ensureUnit(options.width),
+    height: ensureUnit(options.height),
+    position: options.position
+  });
+
+  return container;
+};
+
+BaseViewer.prototype._createModdle = function (options) {
+  var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
+
+  return new BpmnModdle(moddleOptions);
+};
+
+BaseViewer.prototype._modules = [];
+
+// helpers ///////////////
+
+function addWarningsToError(err, warningsAry) {
+  err.warnings = warningsAry;
+  return err;
+}
+
+function checkValidationError(err) {
+
+  // check if we can help the user by indicating wrong BPMN 2.0 xml
+  // (in case he or the exporting tool did not get that right)
+
+  var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
+  var match = pattern.exec(err.message);
+
+  if (match) {
+    err.message =
+      'unparsable content <' + match[1] + '> detected; ' +
+      'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
+  }
+
+  return err;
+}
+
+var DEFAULT_OPTIONS = {
+  width: '100%',
+  height: '100%',
+  position: 'relative'
+};
+
+
+/**
+ * Ensure the passed argument is a proper unit (defaulting to px)
+ */
+function ensureUnit(val) {
+  return val + (isNumber(val) ? 'px' : '');
+}
+
+
+/**
+ * Find BPMNDiagram in definitions by ID
+ *
+ * @param {ModdleElement<Definitions>} definitions
+ * @param {string} diagramId
+ *
+ * @return {ModdleElement<BPMNDiagram>|null}
+ */
+function findBPMNDiagram(definitions, diagramId) {
+  if (!diagramId) {
+    return null;
+  }
+
+  return find(definitions.diagrams, function (element) {
+    return element.id === diagramId;
+  }) || null;
+}
+
+
+/* <project-logo> */
+
+import {
+  open as openPoweredBy,
+  BPMNIO_IMG,
+  LOGO_STYLES,
+  LINK_STYLES
+} from './util/PoweredByUtil';
+
+import {
+  event as domEvent
+} from 'min-dom';
+
+/**
+ * Adds the project logo to the diagram container as
+ * required by the bpmn.io license.
+ *
+ * @see http://bpmn.io/license
+ *
+ * @param {Element} container
+ */
+function addProjectLogo(container) {
+  var img = BPMNIO_IMG;
+
+  var linkMarkup =
+    '<a href="http://bpmn.io" ' +
+    'target="_blank" ' +
+    'class="bjs-powered-by" ' +
+    'title="Powered by bpmn.io" ' +
+    '>' +
+    img +
+    '</a>';
+
+  var linkElement = domify(linkMarkup);
+
+  assignStyle(domQuery('svg', linkElement), LOGO_STYLES);
+  assignStyle(linkElement, LINK_STYLES, {
+    position: 'absolute',
+    bottom: '15px',
+    right: '15px',
+    display: 'none',
+    zIndex: '100'
+  });
+
+  container.appendChild(linkElement);
+
+  domEvent.bind(linkElement, 'click', function (event) {
+    openPoweredBy();
+
+    event.preventDefault();
+  });
+}
+
+/* </project-logo> */

+ 220 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/Modeler.js

@@ -0,0 +1,220 @@
+import inherits from 'inherits-browser';
+
+import BaseModeler from './BaseModeler';
+
+import Viewer from './Viewer';
+import NavigatedViewer from './NavigatedViewer';
+
+import KeyboardMoveModule from 'diagram-js/lib/navigation/keyboard-move';
+import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
+import TouchModule from 'diagram-js/lib/navigation/touch';
+import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
+
+import AlignElementsModule from './features/align-elements';
+import AutoPlaceModule from './features/auto-place';
+import AutoResizeModule from './features/auto-resize';
+import AutoScrollModule from 'diagram-js/lib/features/auto-scroll';
+import BendpointsModule from 'diagram-js/lib/features/bendpoints';
+import ConnectModule from 'diagram-js/lib/features/connect';
+import ConnectionPreviewModule from 'diagram-js/lib/features/connection-preview';
+import ContextPadModule from './features/context-pad';
+import CopyPasteModule from './features/copy-paste';
+import CreateModule from 'diagram-js/lib/features/create';
+import DistributeElementsModule from './features/distribute-elements';
+import EditorActionsModule from './features/editor-actions';
+import GridSnappingModule from './features/grid-snapping';
+import InteractionEventsModule from './features/interaction-events';
+import KeyboardModule from './features/keyboard';
+import KeyboardMoveSelectionModule from 'diagram-js/lib/features/keyboard-move-selection';
+import LabelEditingModule from './features/label-editing';
+import ModelingModule from './features/modeling';
+import MoveModule from 'diagram-js/lib/features/move';
+import PaletteModule from './features/palette';
+import ReplacePreviewModule from './features/replace-preview';
+import ResizeModule from 'diagram-js/lib/features/resize';
+import SnappingModule from './features/snapping';
+import SearchModule from './features/search';
+
+import {
+  wrapForCompatibility
+} from './util/CompatibilityUtil';
+
+var initialDiagram =
+  '<?xml version="1.0" encoding="UTF-8"?>' +
+  '<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
+                    'xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" ' +
+                    'xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" ' +
+                    'xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" ' +
+                    'targetNamespace="http://bpmn.io/schema/bpmn" ' +
+                    'id="Definitions_1">' +
+    '<bpmn:process id="Process_1" isExecutable="false">' +
+      '<bpmn:startEvent id="StartEvent_1"/>' +
+    '</bpmn:process>' +
+    '<bpmndi:BPMNDiagram id="BPMNDiagram_1">' +
+      '<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">' +
+        '<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">' +
+          '<dc:Bounds height="36.0" width="36.0" x="173.0" y="102.0"/>' +
+        '</bpmndi:BPMNShape>' +
+      '</bpmndi:BPMNPlane>' +
+    '</bpmndi:BPMNDiagram>' +
+  '</bpmn:definitions>';
+
+
+/**
+ * A modeler for BPMN 2.0 diagrams.
+ *
+ *
+ * ## Extending the Modeler
+ *
+ * In order to extend the viewer pass extension modules to bootstrap via the
+ * `additionalModules` option. An extension module is an object that exposes
+ * named services.
+ *
+ * The following example depicts the integration of a simple
+ * logging component that integrates with interaction events:
+ *
+ *
+ * ```javascript
+ *
+ * // logging component
+ * function InteractionLogger(eventBus) {
+ *   eventBus.on('element.hover', function(event) {
+ *     console.log()
+ *   })
+ * }
+ *
+ * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
+ *
+ * // extension module
+ * var extensionModule = {
+ *   __init__: [ 'interactionLogger' ],
+ *   interactionLogger: [ 'type', InteractionLogger ]
+ * };
+ *
+ * // extend the viewer
+ * var bpmnModeler = new Modeler({ additionalModules: [ extensionModule ] });
+ * bpmnModeler.importXML(...);
+ * ```
+ *
+ *
+ * ## Customizing / Replacing Components
+ *
+ * You can replace individual diagram components by redefining them in override modules.
+ * This works for all components, including those defined in the core.
+ *
+ * Pass in override modules via the `options.additionalModules` flag like this:
+ *
+ * ```javascript
+ * function CustomContextPadProvider(contextPad) {
+ *
+ *   contextPad.registerProvider(this);
+ *
+ *   this.getContextPadEntries = function(element) {
+ *     // no entries, effectively disable the context pad
+ *     return {};
+ *   };
+ * }
+ *
+ * CustomContextPadProvider.$inject = [ 'contextPad' ];
+ *
+ * var overrideModule = {
+ *   contextPadProvider: [ 'type', CustomContextPadProvider ]
+ * };
+ *
+ * var bpmnModeler = new Modeler({ additionalModules: [ overrideModule ]});
+ * ```
+ *
+ * @param {Object} [options] configuration options to pass to the viewer
+ * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
+ * @param {string|number} [options.width] the width of the viewer
+ * @param {string|number} [options.height] the height of the viewer
+ * @param {Object} [options.moddleExtensions] extension packages to provide
+ * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
+ * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
+ */
+export default function Modeler(options) {
+  BaseModeler.call(this, options);
+}
+
+inherits(Modeler, BaseModeler);
+
+
+Modeler.Viewer = Viewer;
+Modeler.NavigatedViewer = NavigatedViewer;
+
+/**
+* The createDiagram result.
+*
+* @typedef {Object} CreateDiagramResult
+*
+* @property {Array<string>} warnings
+*/
+
+/**
+* The createDiagram error.
+*
+* @typedef {Error} CreateDiagramError
+*
+* @property {Array<string>} warnings
+*/
+
+/**
+ * Create a new diagram to start modeling.
+ *
+ * Returns {Promise<CreateDiagramResult, CreateDiagramError>}
+ */
+Modeler.prototype.createDiagram = wrapForCompatibility(function createDiagram() {
+  return this.importXML(initialDiagram);
+});
+
+
+Modeler.prototype._interactionModules = [
+
+  // non-modeling components
+  KeyboardMoveModule,
+  MoveCanvasModule,
+  TouchModule,
+  ZoomScrollModule
+];
+
+Modeler.prototype._modelingModules = [
+
+  // modeling components
+  AlignElementsModule,
+  AutoPlaceModule,
+  AutoScrollModule,
+  AutoResizeModule,
+  BendpointsModule,
+  ConnectModule,
+  ConnectionPreviewModule,
+  ContextPadModule,
+  CopyPasteModule,
+  CreateModule,
+  DistributeElementsModule,
+  EditorActionsModule,
+  GridSnappingModule,
+  InteractionEventsModule,
+  KeyboardModule,
+  KeyboardMoveSelectionModule,
+  LabelEditingModule,
+  ModelingModule,
+  MoveModule,
+  PaletteModule,
+  ReplacePreviewModule,
+  ResizeModule,
+  SnappingModule,
+  SearchModule
+];
+
+
+// modules the modeler is composed of
+//
+// - viewer modules
+// - interaction modules
+// - modeling modules
+
+Modeler.prototype._modules = [].concat(
+  Viewer.prototype._modules,
+  Modeler.prototype._interactionModules,
+  Modeler.prototype._modelingModules
+);

+ 31 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/NavigatedViewer.js

@@ -0,0 +1,31 @@
+import inherits from 'inherits-browser';
+
+import Viewer from './Viewer';
+
+import KeyboardMoveModule from 'diagram-js/lib/navigation/keyboard-move';
+import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
+import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
+
+
+/**
+ * A viewer that includes mouse navigation facilities
+ *
+ * @param {Object} options
+ */
+export default function NavigatedViewer(options) {
+  Viewer.call(this, options);
+}
+
+inherits(NavigatedViewer, Viewer);
+
+
+NavigatedViewer.prototype._navigationModules = [
+  KeyboardMoveModule,
+  MoveCanvasModule,
+  ZoomScrollModule
+];
+
+NavigatedViewer.prototype._modules = [].concat(
+  Viewer.prototype._modules,
+  NavigatedViewer.prototype._navigationModules
+);

+ 75 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/Viewer.js

@@ -0,0 +1,75 @@
+import inherits from 'inherits-browser';
+
+import CoreModule from './core';
+import TranslateModule from 'diagram-js/lib/i18n/translate';
+import SelectionModule from 'diagram-js/lib/features/selection';
+import OverlaysModule from 'diagram-js/lib/features/overlays';
+import DrilldownModdule from './features/drilldown';
+
+import BaseViewer from './BaseViewer';
+
+
+/**
+ * A viewer for BPMN 2.0 diagrams.
+ *
+ * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
+ * additional features.
+ *
+ *
+ * ## Extending the Viewer
+ *
+ * In order to extend the viewer pass extension modules to bootstrap via the
+ * `additionalModules` option. An extension module is an object that exposes
+ * named services.
+ *
+ * The following example depicts the integration of a simple
+ * logging component that integrates with interaction events:
+ *
+ *
+ * ```javascript
+ *
+ * // logging component
+ * function InteractionLogger(eventBus) {
+ *   eventBus.on('element.hover', function(event) {
+ *     console.log()
+ *   })
+ * }
+ *
+ * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
+ *
+ * // extension module
+ * var extensionModule = {
+ *   __init__: [ 'interactionLogger' ],
+ *   interactionLogger: [ 'type', InteractionLogger ]
+ * };
+ *
+ * // extend the viewer
+ * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] });
+ * bpmnViewer.importXML(...);
+ * ```
+ *
+ * @param {Object} [options] configuration options to pass to the viewer
+ * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
+ * @param {string|number} [options.width] the width of the viewer
+ * @param {string|number} [options.height] the height of the viewer
+ * @param {Object} [options.moddleExtensions] extension packages to provide
+ * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
+ * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
+ */
+export default function Viewer(options) {
+  BaseViewer.call(this, options);
+}
+
+inherits(Viewer, BaseViewer);
+
+// modules the viewer is composed of
+Viewer.prototype._modules = [
+  CoreModule,
+  TranslateModule,
+  SelectionModule,
+  OverlaysModule,
+  DrilldownModdule
+];
+
+// default moddle extensions the viewer is composed of
+Viewer.prototype._moddleExtensions = {};

+ 9 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/core/index.js

@@ -0,0 +1,9 @@
+import DrawModule from '../draw';
+import ImportModule from '../import';
+
+export default {
+  __depends__: [
+    DrawModule,
+    ImportModule
+  ]
+};

+ 157 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/BpmnRenderUtil.js

@@ -0,0 +1,157 @@
+import {
+  every,
+  some
+} from 'min-dash';
+
+import {
+  getDi
+} from '../util/ModelUtil';
+
+import {
+  componentsToPath
+} from 'diagram-js/lib/util/RenderUtil';
+
+// re-export getDi for compatibility
+export { getDi };
+
+export var black = 'hsl(225, 10%, 15%)';
+
+// element utils //////////////////////
+
+/**
+ * Checks if eventDefinition of the given element matches with semantic type.
+ *
+ * @return {boolean} true if element is of the given semantic type
+ */
+export function isTypedEvent(event, eventDefinitionType, filter) {
+
+  function matches(definition, filter) {
+    return every(filter, function(val, key) {
+
+      // we want a == conversion here, to be able to catch
+      // undefined == false and friends
+      /* jshint -W116 */
+      return definition[key] == val;
+    });
+  }
+
+  return some(event.eventDefinitions, function(definition) {
+    return definition.$type === eventDefinitionType && matches(event, filter);
+  });
+}
+
+export function isThrowEvent(event) {
+  return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent');
+}
+
+export function isCollection(element) {
+  var dataObject = element.dataObjectRef;
+
+  return element.isCollection || (dataObject && dataObject.isCollection);
+}
+
+export function getSemantic(element) {
+  return element.businessObject;
+}
+
+
+// color access //////////////////////
+
+export function getFillColor(element, defaultColor) {
+  var di = getDi(element);
+
+  return di.get('color:background-color') || di.get('bioc:fill') || defaultColor || 'white';
+}
+
+export function getStrokeColor(element, defaultColor) {
+  var di = getDi(element);
+
+  return di.get('color:border-color') || di.get('bioc:stroke') || defaultColor || black;
+}
+
+export function getLabelColor(element, defaultColor, defaultStrokeColor) {
+  var di = getDi(element),
+      label = di.get('label');
+
+  return label && label.get('color:color') || defaultColor ||
+    getStrokeColor(element, defaultStrokeColor);
+}
+
+// cropping path customizations //////////////////////
+
+export function getCirclePath(shape) {
+
+  var cx = shape.x + shape.width / 2,
+      cy = shape.y + shape.height / 2,
+      radius = shape.width / 2;
+
+  var circlePath = [
+    [ 'M', cx, cy ],
+    [ 'm', 0, -radius ],
+    [ 'a', radius, radius, 0, 1, 1, 0, 2 * radius ],
+    [ 'a', radius, radius, 0, 1, 1, 0, -2 * radius ],
+    [ 'z' ]
+  ];
+
+  return componentsToPath(circlePath);
+}
+
+export function getRoundRectPath(shape, borderRadius) {
+
+  var x = shape.x,
+      y = shape.y,
+      width = shape.width,
+      height = shape.height;
+
+  var roundRectPath = [
+    [ 'M', x + borderRadius, y ],
+    [ 'l', width - borderRadius * 2, 0 ],
+    [ 'a', borderRadius, borderRadius, 0, 0, 1, borderRadius, borderRadius ],
+    [ 'l', 0, height - borderRadius * 2 ],
+    [ 'a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, borderRadius ],
+    [ 'l', borderRadius * 2 - width, 0 ],
+    [ 'a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, -borderRadius ],
+    [ 'l', 0, borderRadius * 2 - height ],
+    [ 'a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -borderRadius ],
+    [ 'z' ]
+  ];
+
+  return componentsToPath(roundRectPath);
+}
+
+export function getDiamondPath(shape) {
+
+  var width = shape.width,
+      height = shape.height,
+      x = shape.x,
+      y = shape.y,
+      halfWidth = width / 2,
+      halfHeight = height / 2;
+
+  var diamondPath = [
+    [ 'M', x + halfWidth, y ],
+    [ 'l', halfWidth, halfHeight ],
+    [ 'l', -halfWidth, halfHeight ],
+    [ 'l', -halfWidth, -halfHeight ],
+    [ 'z' ]
+  ];
+
+  return componentsToPath(diamondPath);
+}
+
+export function getRectPath(shape) {
+  var x = shape.x,
+      y = shape.y,
+      width = shape.width,
+      height = shape.height;
+
+  var rectPath = [
+    [ 'M', x, y ],
+    [ 'l', width, 0 ],
+    [ 'l', 0, height ],
+    [ 'l', -width, 0 ],
+    [ 'z' ]
+  ];
+
+  return componentsToPath(rectPath);
+}

+ 1928 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/BpmnRenderer.js

@@ -0,0 +1,1928 @@
+import inherits from 'inherits-browser';
+
+import {
+  isObject,
+  assign,
+  forEach
+} from 'min-dash';
+
+import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer';
+
+import {
+  isExpanded,
+  isEventSubProcess
+} from '../util/DiUtil';
+
+import {
+  getLabel
+} from '../features/label-editing/LabelUtil';
+
+import { is } from '../util/ModelUtil';
+
+import {
+  createLine
+} from 'diagram-js/lib/util/RenderUtil';
+
+import {
+  isTypedEvent,
+  isThrowEvent,
+  isCollection,
+  getDi,
+  getSemantic,
+  getCirclePath,
+  getRoundRectPath,
+  getDiamondPath,
+  getRectPath,
+  getFillColor,
+  getStrokeColor,
+  getLabelColor
+} from './BpmnRenderUtil';
+
+import {
+  query as domQuery
+} from 'min-dom';
+
+import {
+  append as svgAppend,
+  attr as svgAttr,
+  create as svgCreate,
+  classes as svgClasses
+} from 'tiny-svg';
+
+import {
+  rotate,
+  transform,
+  translate
+} from 'diagram-js/lib/util/SvgTransformUtil';
+
+import Ids from 'ids';
+
+import { black } from './BpmnRenderUtil';
+
+var RENDERER_IDS = new Ids();
+
+var TASK_BORDER_RADIUS = 10;
+var INNER_OUTER_DIST = 3;
+
+var DEFAULT_FILL_OPACITY = .95,
+    HIGH_FILL_OPACITY = .35;
+
+var ELEMENT_LABEL_DISTANCE = 10;
+
+export default function BpmnRenderer(
+    config, eventBus, styles, pathMap,
+    canvas, textRenderer, priority) {
+
+  BaseRenderer.call(this, eventBus, priority);
+
+  var defaultFillColor = config && config.defaultFillColor,
+      defaultStrokeColor = config && config.defaultStrokeColor,
+      defaultLabelColor = config && config.defaultLabelColor;
+
+  var rendererId = RENDERER_IDS.next();
+
+  var markers = {};
+
+  var computeStyle = styles.computeStyle;
+
+  function addMarker(id, options) {
+    var attrs = assign({
+      fill: black,
+      strokeWidth: 1,
+      strokeLinecap: 'round',
+      strokeDasharray: 'none'
+    }, options.attrs);
+
+    var ref = options.ref || { x: 0, y: 0 };
+
+    var scale = options.scale || 1;
+
+    // fix for safari / chrome / firefox bug not correctly
+    // resetting stroke dash array
+    if (attrs.strokeDasharray === 'none') {
+      attrs.strokeDasharray = [ 10000, 1 ];
+    }
+
+    var marker = svgCreate('marker');
+
+    svgAttr(options.element, attrs);
+
+    svgAppend(marker, options.element);
+
+    svgAttr(marker, {
+      id: id,
+      viewBox: '0 0 20 20',
+      refX: ref.x,
+      refY: ref.y,
+      markerWidth: 20 * scale,
+      markerHeight: 20 * scale,
+      orient: 'auto'
+    });
+
+    var defs = domQuery('defs', canvas._svg);
+
+    if (!defs) {
+      defs = svgCreate('defs');
+
+      svgAppend(canvas._svg, defs);
+    }
+
+    svgAppend(defs, marker);
+
+    markers[id] = marker;
+  }
+
+  function colorEscape(str) {
+
+    // only allow characters and numbers
+    return str.replace(/[^0-9a-zA-z]+/g, '_');
+  }
+
+  function marker(type, fill, stroke) {
+    var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
+
+    if (!markers[id]) {
+      createMarker(id, type, fill, stroke);
+    }
+
+    return 'url(#' + id + ')';
+  }
+
+  function createMarker(id, type, fill, stroke) {
+
+    if (type === 'sequenceflow-end') {
+      var sequenceflowEnd = svgCreate('path');
+      svgAttr(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
+
+      addMarker(id, {
+        element: sequenceflowEnd,
+        ref: { x: 11, y: 10 },
+        scale: 0.5,
+        attrs: {
+          fill: stroke,
+          stroke: stroke
+        }
+      });
+    }
+
+    if (type === 'messageflow-start') {
+      var messageflowStart = svgCreate('circle');
+      svgAttr(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
+
+      addMarker(id, {
+        element: messageflowStart,
+        attrs: {
+          fill: fill,
+          stroke: stroke
+        },
+        ref: { x: 6, y: 6 }
+      });
+    }
+
+    if (type === 'messageflow-end') {
+      var messageflowEnd = svgCreate('path');
+      svgAttr(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
+
+      addMarker(id, {
+        element: messageflowEnd,
+        attrs: {
+          fill: fill,
+          stroke: stroke,
+          strokeLinecap: 'butt'
+        },
+        ref: { x: 8.5, y: 5 }
+      });
+    }
+
+    if (type === 'association-start') {
+      var associationStart = svgCreate('path');
+      svgAttr(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
+
+      addMarker(id, {
+        element: associationStart,
+        attrs: {
+          fill: 'none',
+          stroke: stroke,
+          strokeWidth: 1.5
+        },
+        ref: { x: 1, y: 10 },
+        scale: 0.5
+      });
+    }
+
+    if (type === 'association-end') {
+      var associationEnd = svgCreate('path');
+      svgAttr(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
+
+      addMarker(id, {
+        element: associationEnd,
+        attrs: {
+          fill: 'none',
+          stroke: stroke,
+          strokeWidth: 1.5
+        },
+        ref: { x: 12, y: 10 },
+        scale: 0.5
+      });
+    }
+
+    if (type === 'conditional-flow-marker') {
+      var conditionalflowMarker = svgCreate('path');
+      svgAttr(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
+
+      addMarker(id, {
+        element: conditionalflowMarker,
+        attrs: {
+          fill: fill,
+          stroke: stroke
+        },
+        ref: { x: -1, y: 10 },
+        scale: 0.5
+      });
+    }
+
+    if (type === 'conditional-default-flow-marker') {
+      var conditionaldefaultflowMarker = svgCreate('path');
+      svgAttr(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
+
+      addMarker(id, {
+        element: conditionaldefaultflowMarker,
+        attrs: {
+          stroke: stroke
+        },
+        ref: { x: 0, y: 10 },
+        scale: 0.5
+      });
+    }
+  }
+
+  function drawCircle(parentGfx, width, height, offset, attrs) {
+
+    if (isObject(offset)) {
+      attrs = offset;
+      offset = 0;
+    }
+
+    offset = offset || 0;
+
+    attrs = computeStyle(attrs, {
+      stroke: black,
+      strokeWidth: 2,
+      fill: 'white'
+    });
+
+    if (attrs.fill === 'none') {
+      delete attrs.fillOpacity;
+    }
+
+    var cx = width / 2,
+        cy = height / 2;
+
+    var circle = svgCreate('circle');
+    svgAttr(circle, {
+      cx: cx,
+      cy: cy,
+      r: Math.round((width + height) / 4 - offset)
+    });
+    svgAttr(circle, attrs);
+
+    svgAppend(parentGfx, circle);
+
+    return circle;
+  }
+
+  function drawRect(parentGfx, width, height, r, offset, attrs) {
+
+    if (isObject(offset)) {
+      attrs = offset;
+      offset = 0;
+    }
+
+    offset = offset || 0;
+
+    attrs = computeStyle(attrs, {
+      stroke: black,
+      strokeWidth: 2,
+      fill: 'white'
+    });
+
+    var rect = svgCreate('rect');
+    svgAttr(rect, {
+      x: offset,
+      y: offset,
+      width: width - offset * 2,
+      height: height - offset * 2,
+      rx: r,
+      ry: r
+    });
+    svgAttr(rect, attrs);
+
+    svgAppend(parentGfx, rect);
+
+    return rect;
+  }
+
+  function drawDiamond(parentGfx, width, height, attrs) {
+
+    var x_2 = width / 2;
+    var y_2 = height / 2;
+
+    var points = [ { x: x_2, y: 0 }, { x: width, y: y_2 }, { x: x_2, y: height }, { x: 0, y: y_2 } ];
+
+    var pointsString = points.map(function(point) {
+      return point.x + ',' + point.y;
+    }).join(' ');
+
+    attrs = computeStyle(attrs, {
+      stroke: black,
+      strokeWidth: 2,
+      fill: 'white'
+    });
+
+    var polygon = svgCreate('polygon');
+    svgAttr(polygon, {
+      points: pointsString
+    });
+    svgAttr(polygon, attrs);
+
+    svgAppend(parentGfx, polygon);
+
+    return polygon;
+  }
+
+  function drawLine(parentGfx, waypoints, attrs) {
+    attrs = computeStyle(attrs, [ 'no-fill' ], {
+      stroke: black,
+      strokeWidth: 2,
+      fill: 'none'
+    });
+
+    var line = createLine(waypoints, attrs);
+
+    svgAppend(parentGfx, line);
+
+    return line;
+  }
+
+  function drawPath(parentGfx, d, attrs) {
+
+    attrs = computeStyle(attrs, [ 'no-fill' ], {
+      strokeWidth: 2,
+      stroke: black
+    });
+
+    var path = svgCreate('path');
+    svgAttr(path, { d: d });
+    svgAttr(path, attrs);
+
+    svgAppend(parentGfx, path);
+
+    return path;
+  }
+
+  function drawMarker(type, parentGfx, path, attrs) {
+    return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
+  }
+
+  function renderer(type) {
+    return handlers[type];
+  }
+
+  function as(type) {
+    return function(parentGfx, element) {
+      return renderer(type)(parentGfx, element);
+    };
+  }
+
+  function renderEventContent(element, parentGfx) {
+
+    var event = getSemantic(element);
+    var isThrowing = isThrowEvent(event);
+
+    if (event.eventDefinitions && event.eventDefinitions.length > 1) {
+      if (event.parallelMultiple) {
+        return renderer('bpmn:ParallelMultipleEventDefinition')(parentGfx, element, isThrowing);
+      }
+      else {
+        return renderer('bpmn:MultipleEventDefinition')(parentGfx, element, isThrowing);
+      }
+    }
+
+    if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) {
+      return renderer('bpmn:MessageEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) {
+      return renderer('bpmn:TimerEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) {
+      return renderer('bpmn:ConditionalEventDefinition')(parentGfx, element);
+    }
+
+    if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) {
+      return renderer('bpmn:SignalEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) {
+      return renderer('bpmn:EscalationEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) {
+      return renderer('bpmn:LinkEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) {
+      return renderer('bpmn:ErrorEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) {
+      return renderer('bpmn:CancelEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) {
+      return renderer('bpmn:CompensateEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) {
+      return renderer('bpmn:TerminateEventDefinition')(parentGfx, element, isThrowing);
+    }
+
+    return null;
+  }
+
+  function renderLabel(parentGfx, label, options) {
+
+    options = assign({
+      size: {
+        width: 100
+      }
+    }, options);
+
+    var text = textRenderer.createText(label || '', options);
+
+    svgClasses(text).add('djs-label');
+
+    svgAppend(parentGfx, text);
+
+    return text;
+  }
+
+  function renderEmbeddedLabel(parentGfx, element, align) {
+    var semantic = getSemantic(element);
+
+    return renderLabel(parentGfx, semantic.name, {
+      box: element,
+      align: align,
+      padding: 5,
+      style: {
+        fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
+      }
+    });
+  }
+
+  function renderExternalLabel(parentGfx, element) {
+
+    var box = {
+      width: 90,
+      height: 30,
+      x: element.width / 2 + element.x,
+      y: element.height / 2 + element.y
+    };
+
+    return renderLabel(parentGfx, getLabel(element), {
+      box: box,
+      fitBox: true,
+      style: assign(
+        {},
+        textRenderer.getExternalStyle(),
+        {
+          fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
+        }
+      )
+    });
+  }
+
+  function renderLaneLabel(parentGfx, text, element) {
+    var textBox = renderLabel(parentGfx, text, {
+      box: {
+        height: 30,
+        width: element.height
+      },
+      align: 'center-middle',
+      style: {
+        fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
+      }
+    });
+
+    var top = -1 * element.height;
+
+    transform(textBox, 0, -top, 270);
+  }
+
+  function createPathFromConnection(connection) {
+    var waypoints = connection.waypoints;
+
+    var pathData = 'm  ' + waypoints[0].x + ',' + waypoints[0].y;
+    for (var i = 1; i < waypoints.length; i++) {
+      pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' ';
+    }
+    return pathData;
+  }
+
+  var handlers = this.handlers = {
+    'bpmn:Event': function(parentGfx, element, attrs) {
+
+      if (!('fillOpacity' in attrs)) {
+        attrs.fillOpacity = DEFAULT_FILL_OPACITY;
+      }
+
+      return drawCircle(parentGfx, element.width, element.height, attrs);
+    },
+    'bpmn:StartEvent': function(parentGfx, element) {
+      var attrs = {
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      };
+
+      var semantic = getSemantic(element);
+
+      if (!semantic.isInterrupting) {
+        attrs = {
+          strokeDasharray: '6',
+          strokeLinecap: 'round',
+          fill: getFillColor(element, defaultFillColor),
+          stroke: getStrokeColor(element, defaultStrokeColor)
+        };
+      }
+
+      var circle = renderer('bpmn:Event')(parentGfx, element, attrs);
+
+      renderEventContent(element, parentGfx);
+
+      return circle;
+    },
+    'bpmn:MessageEventDefinition': function(parentGfx, element, isThrowing) {
+      var pathData = pathMap.getScaledPath('EVENT_MESSAGE', {
+        xScaleFactor: 0.9,
+        yScaleFactor: 0.9,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0.235,
+          my: 0.315
+        }
+      });
+
+      var fill = isThrowing ? getStrokeColor(element, defaultStrokeColor) : getFillColor(element, defaultFillColor);
+      var stroke = isThrowing ? getFillColor(element, defaultFillColor) : getStrokeColor(element, defaultStrokeColor);
+
+      var messagePath = drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: fill,
+        stroke: stroke
+      });
+
+      return messagePath;
+    },
+    'bpmn:TimerEventDefinition': function(parentGfx, element) {
+      var circle = drawCircle(parentGfx, element.width, element.height, 0.2 * element.height, {
+        strokeWidth: 2,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', {
+        xScaleFactor: 0.75,
+        yScaleFactor: 0.75,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0.5,
+          my: 0.5
+        }
+      });
+
+      drawPath(parentGfx, pathData, {
+        strokeWidth: 2,
+        strokeLinecap: 'square',
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      for (var i = 0;i < 12; i++) {
+
+        var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', {
+          xScaleFactor: 0.75,
+          yScaleFactor: 0.75,
+          containerWidth: element.width,
+          containerHeight: element.height,
+          position: {
+            mx: 0.5,
+            my: 0.5
+          }
+        });
+
+        var width = element.width / 2;
+        var height = element.height / 2;
+
+        drawPath(parentGfx, linePathData, {
+          strokeWidth: 1,
+          strokeLinecap: 'square',
+          transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')',
+          stroke: getStrokeColor(element, defaultStrokeColor)
+        });
+      }
+
+      return circle;
+    },
+    'bpmn:EscalationEventDefinition': function(parentGfx, event, isThrowing) {
+      var pathData = pathMap.getScaledPath('EVENT_ESCALATION', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.5,
+          my: 0.2
+        }
+      });
+
+      var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
+
+      return drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: fill,
+        stroke: getStrokeColor(event, defaultStrokeColor)
+      });
+    },
+    'bpmn:ConditionalEventDefinition': function(parentGfx, event) {
+      var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.5,
+          my: 0.222
+        }
+      });
+
+      return drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        stroke: getStrokeColor(event, defaultStrokeColor)
+      });
+    },
+    'bpmn:LinkEventDefinition': function(parentGfx, event, isThrowing) {
+      var pathData = pathMap.getScaledPath('EVENT_LINK', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.57,
+          my: 0.263
+        }
+      });
+
+      var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
+
+      return drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: fill,
+        stroke: getStrokeColor(event, defaultStrokeColor)
+      });
+    },
+    'bpmn:ErrorEventDefinition': function(parentGfx, event, isThrowing) {
+      var pathData = pathMap.getScaledPath('EVENT_ERROR', {
+        xScaleFactor: 1.1,
+        yScaleFactor: 1.1,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.2,
+          my: 0.722
+        }
+      });
+
+      var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
+
+      return drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: fill,
+        stroke: getStrokeColor(event, defaultStrokeColor)
+      });
+    },
+    'bpmn:CancelEventDefinition': function(parentGfx, event, isThrowing) {
+      var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', {
+        xScaleFactor: 1.0,
+        yScaleFactor: 1.0,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.638,
+          my: -0.055
+        }
+      });
+
+      var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
+
+      var path = drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: fill,
+        stroke: getStrokeColor(event, defaultStrokeColor)
+      });
+
+      rotate(path, 45);
+
+      return path;
+    },
+    'bpmn:CompensateEventDefinition': function(parentGfx, event, isThrowing) {
+      var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.22,
+          my: 0.5
+        }
+      });
+
+      var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
+
+      return drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: fill,
+        stroke: getStrokeColor(event, defaultStrokeColor)
+      });
+    },
+    'bpmn:SignalEventDefinition': function(parentGfx, event, isThrowing) {
+      var pathData = pathMap.getScaledPath('EVENT_SIGNAL', {
+        xScaleFactor: 0.9,
+        yScaleFactor: 0.9,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.5,
+          my: 0.2
+        }
+      });
+
+      var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
+
+      return drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: fill,
+        stroke: getStrokeColor(event, defaultStrokeColor)
+      });
+    },
+    'bpmn:MultipleEventDefinition': function(parentGfx, event, isThrowing) {
+      var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', {
+        xScaleFactor: 1.1,
+        yScaleFactor: 1.1,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.222,
+          my: 0.36
+        }
+      });
+
+      var fill = isThrowing ? getStrokeColor(event, defaultStrokeColor) : 'none';
+
+      return drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: fill
+      });
+    },
+    'bpmn:ParallelMultipleEventDefinition': function(parentGfx, event) {
+      var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', {
+        xScaleFactor: 1.2,
+        yScaleFactor: 1.2,
+        containerWidth: event.width,
+        containerHeight: event.height,
+        position: {
+          mx: 0.458,
+          my: 0.194
+        }
+      });
+
+      return drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: getStrokeColor(event, defaultStrokeColor),
+        stroke: getStrokeColor(event, defaultStrokeColor)
+      });
+    },
+    'bpmn:EndEvent': function(parentGfx, element) {
+      var circle = renderer('bpmn:Event')(parentGfx, element, {
+        strokeWidth: 4,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      renderEventContent(element, parentGfx, true);
+
+      return circle;
+    },
+    'bpmn:TerminateEventDefinition': function(parentGfx, element) {
+      var circle = drawCircle(parentGfx, element.width, element.height, 8, {
+        strokeWidth: 4,
+        fill: getStrokeColor(element, defaultStrokeColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return circle;
+    },
+    'bpmn:IntermediateEvent': function(parentGfx, element) {
+      var outer = renderer('bpmn:Event')(parentGfx, element, {
+        strokeWidth: 1,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      /* inner */
+      drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, {
+        strokeWidth: 1,
+        fill: getFillColor(element, 'none'),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      renderEventContent(element, parentGfx);
+
+      return outer;
+    },
+    'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'),
+    'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'),
+
+    'bpmn:Activity': function(parentGfx, element, attrs) {
+
+      attrs = attrs || {};
+
+      if (!('fillOpacity' in attrs)) {
+        attrs.fillOpacity = DEFAULT_FILL_OPACITY;
+      }
+
+      return drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, attrs);
+    },
+
+    'bpmn:Task': function(parentGfx, element) {
+      var attrs = {
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      };
+
+      var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
+
+      renderEmbeddedLabel(parentGfx, element, 'center-middle');
+      attachTaskMarkers(parentGfx, element);
+
+      return rect;
+    },
+    'bpmn:ServiceTask': function(parentGfx, element) {
+      var task = renderer('bpmn:Task')(parentGfx, element);
+
+      var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
+        abspos: {
+          x: 12,
+          y: 18
+        }
+      });
+
+      /* service bg */ drawPath(parentGfx, pathDataBG, {
+        strokeWidth: 1,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', {
+        abspos: {
+          x: 17.2,
+          y: 18
+        }
+      });
+
+      /* service fill */ drawPath(parentGfx, fillPathData, {
+        strokeWidth: 0,
+        fill: getFillColor(element, defaultFillColor)
+      });
+
+      var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
+        abspos: {
+          x: 17,
+          y: 22
+        }
+      });
+
+      /* service */ drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return task;
+    },
+    'bpmn:UserTask': function(parentGfx, element) {
+      var task = renderer('bpmn:Task')(parentGfx, element);
+
+      var x = 15;
+      var y = 12;
+
+      var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', {
+        abspos: {
+          x: x,
+          y: y
+        }
+      });
+
+      /* user path */ drawPath(parentGfx, pathData, {
+        strokeWidth: 0.5,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', {
+        abspos: {
+          x: x,
+          y: y
+        }
+      });
+
+      /* user2 path */ drawPath(parentGfx, pathData2, {
+        strokeWidth: 0.5,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', {
+        abspos: {
+          x: x,
+          y: y
+        }
+      });
+
+      /* user3 path */ drawPath(parentGfx, pathData3, {
+        strokeWidth: 0.5,
+        fill: getStrokeColor(element, defaultStrokeColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return task;
+    },
+    'bpmn:ManualTask': function(parentGfx, element) {
+      var task = renderer('bpmn:Task')(parentGfx, element);
+
+      var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', {
+        abspos: {
+          x: 17,
+          y: 15
+        }
+      });
+
+      /* manual path */ drawPath(parentGfx, pathData, {
+        strokeWidth: 0.5, // 0.25,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return task;
+    },
+    'bpmn:SendTask': function(parentGfx, element) {
+      var task = renderer('bpmn:Task')(parentGfx, element);
+
+      var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: 21,
+        containerHeight: 14,
+        position: {
+          mx: 0.285,
+          my: 0.357
+        }
+      });
+
+      /* send path */ drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: getStrokeColor(element, defaultStrokeColor),
+        stroke: getFillColor(element, defaultFillColor)
+      });
+
+      return task;
+    },
+    'bpmn:ReceiveTask' : function(parentGfx, element) {
+      var semantic = getSemantic(element);
+
+      var task = renderer('bpmn:Task')(parentGfx, element);
+      var pathData;
+
+      if (semantic.instantiate) {
+        drawCircle(parentGfx, 28, 28, 20 * 0.22, { strokeWidth: 1 });
+
+        pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', {
+          abspos: {
+            x: 7.77,
+            y: 9.52
+          }
+        });
+      } else {
+
+        pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
+          xScaleFactor: 0.9,
+          yScaleFactor: 0.9,
+          containerWidth: 21,
+          containerHeight: 14,
+          position: {
+            mx: 0.3,
+            my: 0.4
+          }
+        });
+      }
+
+      /* receive path */ drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return task;
+    },
+    'bpmn:ScriptTask': function(parentGfx, element) {
+      var task = renderer('bpmn:Task')(parentGfx, element);
+
+      var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', {
+        abspos: {
+          x: 15,
+          y: 20
+        }
+      });
+
+      /* script path */ drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return task;
+    },
+    'bpmn:BusinessRuleTask': function(parentGfx, element) {
+      var task = renderer('bpmn:Task')(parentGfx, element);
+
+      var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', {
+        abspos: {
+          x: 8,
+          y: 8
+        }
+      });
+
+      var businessHeaderPath = drawPath(parentGfx, headerPathData);
+      svgAttr(businessHeaderPath, {
+        strokeWidth: 1,
+        fill: getFillColor(element, '#aaaaaa'),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', {
+        abspos: {
+          x: 8,
+          y: 8
+        }
+      });
+
+      var businessPath = drawPath(parentGfx, headerData);
+      svgAttr(businessPath, {
+        strokeWidth: 1,
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return task;
+    },
+    'bpmn:SubProcess': function(parentGfx, element, attrs) {
+      attrs = assign({
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      }, attrs);
+
+      var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
+
+      var expanded = isExpanded(element);
+
+      if (isEventSubProcess(element)) {
+        svgAttr(rect, {
+          strokeDasharray: '1,2'
+        });
+      }
+
+      renderEmbeddedLabel(parentGfx, element, expanded ? 'center-top' : 'center-middle');
+
+      if (expanded) {
+        attachTaskMarkers(parentGfx, element);
+      } else {
+        attachTaskMarkers(parentGfx, element, [ 'SubProcessMarker' ]);
+      }
+
+      return rect;
+    },
+    'bpmn:AdHocSubProcess': function(parentGfx, element) {
+      return renderer('bpmn:SubProcess')(parentGfx, element);
+    },
+    'bpmn:Transaction': function(parentGfx, element) {
+      var outer = renderer('bpmn:SubProcess')(parentGfx, element);
+
+      var innerAttrs = styles.style([ 'no-fill', 'no-events' ], {
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      /* inner path */ drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs);
+
+      return outer;
+    },
+    'bpmn:CallActivity': function(parentGfx, element) {
+      return renderer('bpmn:SubProcess')(parentGfx, element, {
+        strokeWidth: 5
+      });
+    },
+    'bpmn:Participant': function(parentGfx, element) {
+
+      var attrs = {
+        fillOpacity: DEFAULT_FILL_OPACITY,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      };
+
+      var lane = renderer('bpmn:Lane')(parentGfx, element, attrs);
+
+      var expandedPool = isExpanded(element);
+
+      if (expandedPool) {
+        drawLine(parentGfx, [
+          { x: 30, y: 0 },
+          { x: 30, y: element.height }
+        ], {
+          stroke: getStrokeColor(element, defaultStrokeColor)
+        });
+        var text = getSemantic(element).name;
+        renderLaneLabel(parentGfx, text, element);
+      } else {
+
+        // Collapsed pool draw text inline
+        var text2 = getSemantic(element).name;
+        renderLabel(parentGfx, text2, {
+          box: element, align: 'center-middle',
+          style: {
+            fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
+          }
+        });
+      }
+
+      var participantMultiplicity = !!(getSemantic(element).participantMultiplicity);
+
+      if (participantMultiplicity) {
+        renderer('ParticipantMultiplicityMarker')(parentGfx, element);
+      }
+
+      return lane;
+    },
+    'bpmn:Lane': function(parentGfx, element, attrs) {
+      var rect = drawRect(parentGfx, element.width, element.height, 0, assign({
+        fill: getFillColor(element, defaultFillColor),
+        fillOpacity: HIGH_FILL_OPACITY,
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      }, attrs));
+
+      var semantic = getSemantic(element);
+
+      if (semantic.$type === 'bpmn:Lane') {
+        var text = semantic.name;
+        renderLaneLabel(parentGfx, text, element);
+      }
+
+      return rect;
+    },
+    'bpmn:InclusiveGateway': function(parentGfx, element) {
+      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
+
+      /* circle path */
+      drawCircle(parentGfx, element.width, element.height, element.height * 0.24, {
+        strokeWidth: 2.5,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return diamond;
+    },
+    'bpmn:ExclusiveGateway': function(parentGfx, element) {
+      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
+
+      var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
+        xScaleFactor: 0.4,
+        yScaleFactor: 0.4,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0.32,
+          my: 0.3
+        }
+      });
+
+      if ((getDi(element).isMarkerVisible)) {
+        drawPath(parentGfx, pathData, {
+          strokeWidth: 1,
+          fill: getStrokeColor(element, defaultStrokeColor),
+          stroke: getStrokeColor(element, defaultStrokeColor)
+        });
+      }
+
+      return diamond;
+    },
+    'bpmn:ComplexGateway': function(parentGfx, element) {
+      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
+
+      var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
+        xScaleFactor: 0.5,
+        yScaleFactor:0.5,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0.46,
+          my: 0.26
+        }
+      });
+
+      /* complex path */ drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: getStrokeColor(element, defaultStrokeColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return diamond;
+    },
+    'bpmn:ParallelGateway': function(parentGfx, element) {
+      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
+
+      var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
+        xScaleFactor: 0.6,
+        yScaleFactor:0.6,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0.46,
+          my: 0.2
+        }
+      });
+
+      /* parallel path */ drawPath(parentGfx, pathData, {
+        strokeWidth: 1,
+        fill: getStrokeColor(element, defaultStrokeColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return diamond;
+    },
+    'bpmn:EventBasedGateway': function(parentGfx, element) {
+
+      var semantic = getSemantic(element);
+
+      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
+
+      /* outer circle path */ drawCircle(parentGfx, element.width, element.height, element.height * 0.20, {
+        strokeWidth: 1,
+        fill: 'none',
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      var type = semantic.eventGatewayType;
+      var instantiate = !!semantic.instantiate;
+
+      function drawEvent() {
+
+        var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
+          xScaleFactor: 0.18,
+          yScaleFactor: 0.18,
+          containerWidth: element.width,
+          containerHeight: element.height,
+          position: {
+            mx: 0.36,
+            my: 0.44
+          }
+        });
+
+        var attrs = {
+          strokeWidth: 2,
+          fill: getFillColor(element, 'none'),
+          stroke: getStrokeColor(element, defaultStrokeColor)
+        };
+
+        /* event path */ drawPath(parentGfx, pathData, attrs);
+      }
+
+      if (type === 'Parallel') {
+
+        var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
+          xScaleFactor: 0.4,
+          yScaleFactor:0.4,
+          containerWidth: element.width,
+          containerHeight: element.height,
+          position: {
+            mx: 0.474,
+            my: 0.296
+          }
+        });
+
+        var parallelPath = drawPath(parentGfx, pathData);
+        svgAttr(parallelPath, {
+          strokeWidth: 1,
+          fill: 'none'
+        });
+      } else if (type === 'Exclusive') {
+
+        if (!instantiate) {
+          var innerCircle = drawCircle(parentGfx, element.width, element.height, element.height * 0.26);
+          svgAttr(innerCircle, {
+            strokeWidth: 1,
+            fill: 'none',
+            stroke: getStrokeColor(element, defaultStrokeColor)
+          });
+        }
+
+        drawEvent();
+      }
+
+
+      return diamond;
+    },
+    'bpmn:Gateway': function(parentGfx, element) {
+      var attrs = {
+        fill: getFillColor(element, defaultFillColor),
+        fillOpacity: DEFAULT_FILL_OPACITY,
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      };
+
+      return drawDiamond(parentGfx, element.width, element.height, attrs);
+    },
+    'bpmn:SequenceFlow': function(parentGfx, element) {
+      var pathData = createPathFromConnection(element);
+
+      var fill = getFillColor(element, defaultFillColor),
+          stroke = getStrokeColor(element, defaultStrokeColor);
+
+      var attrs = {
+        strokeLinejoin: 'round',
+        markerEnd: marker('sequenceflow-end', fill, stroke),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      };
+
+      var path = drawPath(parentGfx, pathData, attrs);
+
+      var sequenceFlow = getSemantic(element);
+
+      var source;
+
+      if (element.source) {
+        source = element.source.businessObject;
+
+        // conditional flow marker
+        if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Activity')) {
+          svgAttr(path, {
+            markerStart: marker('conditional-flow-marker', fill, stroke)
+          });
+        }
+
+        // default marker
+        if (source.default && (source.$instanceOf('bpmn:Gateway') || source.$instanceOf('bpmn:Activity')) &&
+            source.default === sequenceFlow) {
+          svgAttr(path, {
+            markerStart: marker('conditional-default-flow-marker', fill, stroke)
+          });
+        }
+      }
+
+      return path;
+    },
+    'bpmn:Association': function(parentGfx, element, attrs) {
+
+      var semantic = getSemantic(element);
+
+      var fill = getFillColor(element, defaultFillColor),
+          stroke = getStrokeColor(element, defaultStrokeColor);
+
+      attrs = assign({
+        strokeDasharray: '0.5, 5',
+        strokeLinecap: 'round',
+        strokeLinejoin: 'round',
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      }, attrs || {});
+
+      if (semantic.associationDirection === 'One' ||
+          semantic.associationDirection === 'Both') {
+        attrs.markerEnd = marker('association-end', fill, stroke);
+      }
+
+      if (semantic.associationDirection === 'Both') {
+        attrs.markerStart = marker('association-start', fill, stroke);
+      }
+
+      return drawLine(parentGfx, element.waypoints, attrs);
+    },
+    'bpmn:DataInputAssociation': function(parentGfx, element) {
+      var fill = getFillColor(element, defaultFillColor),
+          stroke = getStrokeColor(element, defaultStrokeColor);
+
+      return renderer('bpmn:Association')(parentGfx, element, {
+        markerEnd: marker('association-end', fill, stroke)
+      });
+    },
+    'bpmn:DataOutputAssociation': function(parentGfx, element) {
+      var fill = getFillColor(element, defaultFillColor),
+          stroke = getStrokeColor(element, defaultStrokeColor);
+
+      return renderer('bpmn:Association')(parentGfx, element, {
+        markerEnd: marker('association-end', fill, stroke)
+      });
+    },
+    'bpmn:MessageFlow': function(parentGfx, element) {
+
+      var semantic = getSemantic(element),
+          di = getDi(element);
+
+      var fill = getFillColor(element, defaultFillColor),
+          stroke = getStrokeColor(element, defaultStrokeColor);
+
+      var pathData = createPathFromConnection(element);
+
+      var attrs = {
+        markerEnd: marker('messageflow-end', fill, stroke),
+        markerStart: marker('messageflow-start', fill, stroke),
+        strokeDasharray: '10, 12',
+        strokeLinecap: 'round',
+        strokeLinejoin: 'round',
+        strokeWidth: '1.5px',
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      };
+
+      var path = drawPath(parentGfx, pathData, attrs);
+
+      if (semantic.messageRef) {
+        var midPoint = path.getPointAtLength(path.getTotalLength() / 2);
+
+        var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', {
+          abspos: {
+            x: midPoint.x,
+            y: midPoint.y
+          }
+        });
+
+        var messageAttrs = { strokeWidth: 1 };
+
+        if (di.messageVisibleKind === 'initiating') {
+          messageAttrs.fill = 'white';
+          messageAttrs.stroke = black;
+        } else {
+          messageAttrs.fill = '#888';
+          messageAttrs.stroke = 'white';
+        }
+
+        var message = drawPath(parentGfx, markerPathData, messageAttrs);
+
+        var labelText = semantic.messageRef.name;
+        var label = renderLabel(parentGfx, labelText, {
+          align: 'center-top',
+          fitBox: true,
+          style: {
+            fill: getStrokeColor(element, defaultLabelColor, defaultStrokeColor)
+          }
+        });
+
+        var messageBounds = message.getBBox(),
+            labelBounds = label.getBBox();
+
+        var translateX = midPoint.x - labelBounds.width / 2,
+            translateY = midPoint.y + messageBounds.height / 2 + ELEMENT_LABEL_DISTANCE;
+
+        transform(label, translateX, translateY, 0);
+
+      }
+
+      return path;
+    },
+    'bpmn:DataObject': function(parentGfx, element) {
+      var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0.474,
+          my: 0.296
+        }
+      });
+
+      var elementObject = drawPath(parentGfx, pathData, {
+        fill: getFillColor(element, defaultFillColor),
+        fillOpacity: DEFAULT_FILL_OPACITY,
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      var semantic = getSemantic(element);
+
+      if (isCollection(semantic)) {
+        renderDataItemCollection(parentGfx, element);
+      }
+
+      return elementObject;
+    },
+    'bpmn:DataObjectReference': as('bpmn:DataObject'),
+    'bpmn:DataInput': function(parentGfx, element) {
+
+      var arrowPathData = pathMap.getRawPath('DATA_ARROW');
+
+      // page
+      var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
+
+      /* input arrow path */ drawPath(parentGfx, arrowPathData, { strokeWidth: 1 });
+
+      return elementObject;
+    },
+    'bpmn:DataOutput': function(parentGfx, element) {
+      var arrowPathData = pathMap.getRawPath('DATA_ARROW');
+
+      // page
+      var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
+
+      /* output arrow path */ drawPath(parentGfx, arrowPathData, {
+        strokeWidth: 1,
+        fill: black
+      });
+
+      return elementObject;
+    },
+    'bpmn:DataStoreReference': function(parentGfx, element) {
+      var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0,
+          my: 0.133
+        }
+      });
+
+      var elementStore = drawPath(parentGfx, DATA_STORE_PATH, {
+        strokeWidth: 2,
+        fill: getFillColor(element, defaultFillColor),
+        fillOpacity: DEFAULT_FILL_OPACITY,
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      return elementStore;
+    },
+    'bpmn:BoundaryEvent': function(parentGfx, element) {
+
+      var semantic = getSemantic(element),
+          cancel = semantic.cancelActivity;
+
+      var attrs = {
+        strokeWidth: 1,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      };
+
+      if (!cancel) {
+        attrs.strokeDasharray = '6';
+        attrs.strokeLinecap = 'round';
+      }
+
+      // apply fillOpacity
+      var outerAttrs = assign({}, attrs, {
+        fillOpacity: 1
+      });
+
+      // apply no-fill
+      var innerAttrs = assign({}, attrs, {
+        fill: 'none'
+      });
+
+      var outer = renderer('bpmn:Event')(parentGfx, element, outerAttrs);
+
+      /* inner path */ drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, innerAttrs);
+
+      renderEventContent(element, parentGfx);
+
+      return outer;
+    },
+    'bpmn:Group': function(parentGfx, element) {
+
+      var group = drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, {
+        stroke: getStrokeColor(element, defaultStrokeColor),
+        strokeWidth: 1,
+        strokeDasharray: '8,3,1,3',
+        fill: 'none',
+        pointerEvents: 'none'
+      });
+
+      return group;
+    },
+    'label': function(parentGfx, element) {
+      return renderExternalLabel(parentGfx, element);
+    },
+    'bpmn:TextAnnotation': function(parentGfx, element) {
+      var style = {
+        'fill': 'none',
+        'stroke': 'none'
+      };
+
+      var textElement = drawRect(parentGfx, element.width, element.height, 0, 0, style);
+
+      var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0.0,
+          my: 0.0
+        }
+      });
+
+      drawPath(parentGfx, textPathData, {
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      var text = getSemantic(element).text || '';
+      renderLabel(parentGfx, text, {
+        box: element,
+        align: 'left-top',
+        padding: 5,
+        style: {
+          fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
+        }
+      });
+
+      return textElement;
+    },
+    'ParticipantMultiplicityMarker': function(parentGfx, element) {
+      var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: ((element.width / 2) / element.width),
+          my: (element.height - 15) / element.height
+        }
+      });
+
+      drawMarker('participant-multiplicity', parentGfx, markerPath, {
+        strokeWidth: 2,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+    },
+    'SubProcessMarker': function(parentGfx, element) {
+      var markerRect = drawRect(parentGfx, 14, 14, 0, {
+        strokeWidth: 1,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+
+      // Process marker is placed in the middle of the box
+      // therefore fixed values can be used here
+      translate(markerRect, element.width / 2 - 7.5, element.height - 20);
+
+      var markerPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', {
+        xScaleFactor: 1.5,
+        yScaleFactor: 1.5,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: (element.width / 2 - 7.5) / element.width,
+          my: (element.height - 20) / element.height
+        }
+      });
+
+      drawMarker('sub-process', parentGfx, markerPath, {
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+    },
+    'ParallelMarker': function(parentGfx, element, position) {
+      var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: ((element.width / 2 + position.parallel) / element.width),
+          my: (element.height - 20) / element.height
+        }
+      });
+
+      drawMarker('parallel', parentGfx, markerPath, {
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+    },
+    'SequentialMarker': function(parentGfx, element, position) {
+      var markerPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: ((element.width / 2 + position.seq) / element.width),
+          my: (element.height - 19) / element.height
+        }
+      });
+
+      drawMarker('sequential', parentGfx, markerPath, {
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+    },
+    'CompensationMarker': function(parentGfx, element, position) {
+      var markerMath = pathMap.getScaledPath('MARKER_COMPENSATION', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: ((element.width / 2 + position.compensation) / element.width),
+          my: (element.height - 13) / element.height
+        }
+      });
+
+      drawMarker('compensation', parentGfx, markerMath, {
+        strokeWidth: 1,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+    },
+    'LoopMarker': function(parentGfx, element, position) {
+      var markerPath = pathMap.getScaledPath('MARKER_LOOP', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: ((element.width / 2 + position.loop) / element.width),
+          my: (element.height - 7) / element.height
+        }
+      });
+
+      drawMarker('loop', parentGfx, markerPath, {
+        strokeWidth: 1,
+        fill: getFillColor(element, defaultFillColor),
+        stroke: getStrokeColor(element, defaultStrokeColor),
+        strokeLinecap: 'round',
+        strokeMiterlimit: 0.5
+      });
+    },
+    'AdhocMarker': function(parentGfx, element, position) {
+      var markerPath = pathMap.getScaledPath('MARKER_ADHOC', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: ((element.width / 2 + position.adhoc) / element.width),
+          my: (element.height - 15) / element.height
+        }
+      });
+
+      drawMarker('adhoc', parentGfx, markerPath, {
+        strokeWidth: 1,
+        fill: getStrokeColor(element, defaultStrokeColor),
+        stroke: getStrokeColor(element, defaultStrokeColor)
+      });
+    }
+  };
+
+  function attachTaskMarkers(parentGfx, element, taskMarkers) {
+    var obj = getSemantic(element);
+
+    var subprocess = taskMarkers && taskMarkers.indexOf('SubProcessMarker') !== -1;
+    var position;
+
+    if (subprocess) {
+      position = {
+        seq: -21,
+        parallel: -22,
+        compensation: -42,
+        loop: -18,
+        adhoc: 10
+      };
+    } else {
+      position = {
+        seq: -3,
+        parallel: -6,
+        compensation: -27,
+        loop: 0,
+        adhoc: 10
+      };
+    }
+
+    forEach(taskMarkers, function(marker) {
+      renderer(marker)(parentGfx, element, position);
+    });
+
+    if (obj.isForCompensation) {
+      renderer('CompensationMarker')(parentGfx, element, position);
+    }
+
+    if (obj.$type === 'bpmn:AdHocSubProcess') {
+      renderer('AdhocMarker')(parentGfx, element, position);
+    }
+
+    var loopCharacteristics = obj.loopCharacteristics,
+        isSequential = loopCharacteristics && loopCharacteristics.isSequential;
+
+    if (loopCharacteristics) {
+
+      if (isSequential === undefined) {
+        renderer('LoopMarker')(parentGfx, element, position);
+      }
+
+      if (isSequential === false) {
+        renderer('ParallelMarker')(parentGfx, element, position);
+      }
+
+      if (isSequential === true) {
+        renderer('SequentialMarker')(parentGfx, element, position);
+      }
+    }
+  }
+
+  function renderDataItemCollection(parentGfx, element) {
+
+    var yPosition = (element.height - 18) / element.height;
+
+    var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', {
+      xScaleFactor: 1,
+      yScaleFactor: 1,
+      containerWidth: element.width,
+      containerHeight: element.height,
+      position: {
+        mx: 0.33,
+        my: yPosition
+      }
+    });
+
+    /* collection path */ drawPath(parentGfx, pathData, {
+      strokeWidth: 2
+    });
+  }
+
+
+  // extension API, use at your own risk
+  this._drawPath = drawPath;
+
+  this._renderer = renderer;
+}
+
+
+inherits(BpmnRenderer, BaseRenderer);
+
+BpmnRenderer.$inject = [
+  'config.bpmnRenderer',
+  'eventBus',
+  'styles',
+  'pathMap',
+  'canvas',
+  'textRenderer'
+];
+
+
+BpmnRenderer.prototype.canRender = function(element) {
+  return is(element, 'bpmn:BaseElement');
+};
+
+BpmnRenderer.prototype.drawShape = function(parentGfx, element) {
+  var type = element.type;
+  var h = this._renderer(type);
+
+  /* jshint -W040 */
+  return h(parentGfx, element);
+};
+
+BpmnRenderer.prototype.drawConnection = function(parentGfx, element) {
+  var type = element.type;
+  var h = this._renderer(type);
+
+  /* jshint -W040 */
+  return h(parentGfx, element);
+};
+
+BpmnRenderer.prototype.getShapePath = function(element) {
+
+  if (is(element, 'bpmn:Event')) {
+    return getCirclePath(element);
+  }
+
+  if (is(element, 'bpmn:Activity')) {
+    return getRoundRectPath(element, TASK_BORDER_RADIUS);
+  }
+
+  if (is(element, 'bpmn:Gateway')) {
+    return getDiamondPath(element);
+  }
+
+  return getRectPath(element);
+};

+ 471 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/PathMap.js

@@ -0,0 +1,471 @@
+/**
+ * Map containing SVG paths needed by BpmnRenderer.
+ */
+
+export default function PathMap() {
+
+  /**
+   * Contains a map of path elements
+   *
+   * <h1>Path definition</h1>
+   * A parameterized path is defined like this:
+   * <pre>
+   * 'GATEWAY_PARALLEL': {
+   *   d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
+          '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
+   *   height: 17.5,
+   *   width:  17.5,
+   *   heightElements: [2.5, 7.5],
+   *   widthElements: [2.5, 7.5]
+   * }
+   * </pre>
+   * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
+   * is based on the ratio between the specified height and width in this object and the
+   * height and width that is set as scale target (Note x,y coordinates will be scaled with
+   * individual ratios).</p>
+   * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
+   * The scaling is based on the computed ratios.
+   * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
+   * the computed ratio coefficient.
+   * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
+   *   <ul>
+   *    <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
+   *    <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
+   *   </ul>
+   *   The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
+   * </p>
+   */
+  this.pathMap = {
+    'EVENT_MESSAGE': {
+      d: 'm {mx},{my} l 0,{e.y1} l {e.x1},0 l 0,-{e.y1} z l {e.x0},{e.y0} l {e.x0},-{e.y0}',
+      height: 36,
+      width:  36,
+      heightElements: [ 6, 14 ],
+      widthElements: [ 10.5, 21 ]
+    },
+    'EVENT_SIGNAL': {
+      d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z',
+      height: 36,
+      width: 36,
+      heightElements: [ 18 ],
+      widthElements: [ 10, 20 ]
+    },
+    'EVENT_ESCALATION': {
+      d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x0},-{e.y1} l -{e.x0},{e.y1} Z',
+      height: 36,
+      width: 36,
+      heightElements: [ 20, 7 ],
+      widthElements: [ 8 ]
+    },
+    'EVENT_CONDITIONAL': {
+      d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' +
+         'M {e.x2},{e.y3} l {e.x0},0 ' +
+         'M {e.x2},{e.y4} l {e.x0},0 ' +
+         'M {e.x2},{e.y5} l {e.x0},0 ' +
+         'M {e.x2},{e.y6} l {e.x0},0 ' +
+         'M {e.x2},{e.y7} l {e.x0},0 ' +
+         'M {e.x2},{e.y8} l {e.x0},0 ',
+      height: 36,
+      width:  36,
+      heightElements: [ 8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5 ],
+      widthElements:  [ 10.5, 14.5, 12.5 ]
+    },
+    'EVENT_LINK': {
+      d: 'm {mx},{my} 0,{e.y0} -{e.x1},0 0,{e.y1} {e.x1},0 0,{e.y0} {e.x0},-{e.y2} -{e.x0},-{e.y2} z',
+      height: 36,
+      width: 36,
+      heightElements: [ 4.4375, 6.75, 7.8125 ],
+      widthElements: [ 9.84375, 13.5 ]
+    },
+    'EVENT_ERROR': {
+      d: 'm {mx},{my} {e.x0},-{e.y0} {e.x1},-{e.y1} {e.x2},{e.y2} {e.x3},-{e.y3} -{e.x4},{e.y4} -{e.x5},-{e.y5} z',
+      height: 36,
+      width: 36,
+      heightElements: [ 0.023, 8.737, 8.151, 16.564, 10.591, 8.714 ],
+      widthElements: [ 0.085, 6.672, 6.97, 4.273, 5.337, 6.636 ]
+    },
+    'EVENT_CANCEL_45': {
+      d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
+        '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
+      height: 36,
+      width: 36,
+      heightElements: [ 4.75, 8.5 ],
+      widthElements: [ 4.75, 8.5 ]
+    },
+    'EVENT_COMPENSATION': {
+      d: 'm {mx},{my} {e.x0},-{e.y0} 0,{e.y1} z m {e.x1},-{e.y2} {e.x2},-{e.y3} 0,{e.y1} -{e.x2},-{e.y3} z',
+      height: 36,
+      width: 36,
+      heightElements: [ 6.5, 13, 0.4, 6.1 ],
+      widthElements: [ 9, 9.3, 8.7 ]
+    },
+    'EVENT_TIMER_WH': {
+      d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ',
+      height: 36,
+      width:  36,
+      heightElements: [ 10, 2 ],
+      widthElements: [ 3, 7 ]
+    },
+    'EVENT_TIMER_LINE': {
+      d:  'M {mx},{my} ' +
+          'm {e.x0},{e.y0} l -{e.x1},{e.y1} ',
+      height: 36,
+      width:  36,
+      heightElements: [ 10, 3 ],
+      widthElements: [ 0, 0 ]
+    },
+    'EVENT_MULTIPLE': {
+      d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z',
+      height: 36,
+      width:  36,
+      heightElements: [ 6.28099, 12.56199 ],
+      widthElements: [ 3.1405, 9.42149, 12.56198 ]
+    },
+    'EVENT_PARALLEL_MULTIPLE': {
+      d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
+        '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
+      height: 36,
+      width:  36,
+      heightElements: [ 2.56228, 7.68683 ],
+      widthElements: [ 2.56228, 7.68683 ]
+    },
+    'GATEWAY_EXCLUSIVE': {
+      d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
+                    '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
+                    '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
+      height: 17.5,
+      width:  17.5,
+      heightElements: [ 8.5, 6.5312, -6.5312, -8.5 ],
+      widthElements:  [ 6.5, -6.5, 3, -3, 5, -5 ]
+    },
+    'GATEWAY_PARALLEL': {
+      d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
+        '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
+      height: 30,
+      width:  30,
+      heightElements: [ 5, 12.5 ],
+      widthElements: [ 5, 12.5 ]
+    },
+    'GATEWAY_EVENT_BASED': {
+      d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
+      height: 11,
+      width:  11,
+      heightElements: [ -6, 6, 12, -12 ],
+      widthElements: [ 9, -3, -12 ]
+    },
+    'GATEWAY_COMPLEX': {
+      d:'m {mx},{my} 0,{e.y0} -{e.x0},-{e.y1} -{e.x1},{e.y2} {e.x0},{e.y1} -{e.x2},0 0,{e.y3} ' +
+        '{e.x2},0  -{e.x0},{e.y1} l {e.x1},{e.y2} {e.x0},-{e.y1} 0,{e.y0} {e.x3},0 0,-{e.y0} {e.x0},{e.y1} ' +
+        '{e.x1},-{e.y2} -{e.x0},-{e.y1} {e.x2},0 0,-{e.y3} -{e.x2},0 {e.x0},-{e.y1} -{e.x1},-{e.y2} ' +
+        '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
+      height: 17.125,
+      width:  17.125,
+      heightElements: [ 4.875, 3.4375, 2.125, 3 ],
+      widthElements: [ 3.4375, 2.125, 4.875, 3 ]
+    },
+    'DATA_OBJECT_PATH': {
+      d:'m 0,0 {e.x1},0 {e.x0},{e.y0} 0,{e.y1} -{e.x2},0 0,-{e.y2} {e.x1},0 0,{e.y0} {e.x0},0',
+      height: 61,
+      width:  51,
+      heightElements: [ 10, 50, 60 ],
+      widthElements: [ 10, 40, 50, 60 ]
+    },
+    'DATA_OBJECT_COLLECTION_PATH': {
+      d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
+      height: 10,
+      width: 10,
+      heightElements: [],
+      widthElements: []
+    },
+    'DATA_ARROW': {
+      d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z',
+      height: 61,
+      width:  51,
+      heightElements: [],
+      widthElements: []
+    },
+    'DATA_STORE': {
+      d:'m  {mx},{my} ' +
+        'l  0,{e.y2} ' +
+        'c  {e.x0},{e.y1} {e.x1},{e.y1}  {e.x2},0 ' +
+        'l  0,-{e.y2} ' +
+        'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' +
+        'c  {e.x0},{e.y1} {e.x1},{e.y1}  {e.x2},0 ' +
+        'm  -{e.x2},{e.y0}' +
+        'c  {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0' +
+        'm  -{e.x2},{e.y0}' +
+        'c  {e.x0},{e.y1} {e.x1},{e.y1}  {e.x2},0',
+      height: 61,
+      width:  61,
+      heightElements: [ 7, 10, 45 ],
+      widthElements:  [ 2, 58, 60 ]
+    },
+    'TEXT_ANNOTATION': {
+      d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
+      height: 30,
+      width: 10,
+      heightElements: [ 30 ],
+      widthElements: [ 10 ]
+    },
+    'MARKER_SUB_PROCESS': {
+      d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0',
+      height: 10,
+      width: 10,
+      heightElements: [],
+      widthElements: []
+    },
+    'MARKER_PARALLEL': {
+      d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
+      height: 10,
+      width: 10,
+      heightElements: [],
+      widthElements: []
+    },
+    'MARKER_SEQUENTIAL': {
+      d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0',
+      height: 10,
+      width: 10,
+      heightElements: [],
+      widthElements: []
+    },
+    'MARKER_COMPENSATION': {
+      d: 'm {mx},{my} 7,-5 0,10 z m 7.1,-0.3 6.9,-4.7 0,10 -6.9,-4.7 z',
+      height: 10,
+      width: 21,
+      heightElements: [],
+      widthElements: []
+    },
+    'MARKER_LOOP': {
+      d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' +
+        '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' +
+        '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' +
+        'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902',
+      height: 13.9,
+      width: 13.7,
+      heightElements: [],
+      widthElements: []
+    },
+    'MARKER_ADHOC': {
+      d: 'm {mx},{my} m 0.84461,2.64411 c 1.05533,-1.23780996 2.64337,-2.07882 4.29653,-1.97997996 2.05163,0.0805 ' +
+        '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' +
+        '1.2775,-0.64078 1.7542,-1.17511 0,0.56023 0,1.12046 0,1.6807 -0.98706,0.96237996 -2.29792,1.62393996 ' +
+        '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' +
+        '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z',
+      height: 4,
+      width: 15,
+      heightElements: [],
+      widthElements: []
+    },
+    'TASK_TYPE_SEND': {
+      d: 'm {mx},{my} l 0,{e.y1} l {e.x1},0 l 0,-{e.y1} z l {e.x0},{e.y0} l {e.x0},-{e.y0}',
+      height: 14,
+      width:  21,
+      heightElements: [ 6, 14 ],
+      widthElements: [ 10.5, 21 ]
+    },
+    'TASK_TYPE_SCRIPT': {
+      d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' +
+        'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' +
+        'm -7,-12 l 5,0 ' +
+        'm -4.5,3 l 4.5,0 ' +
+        'm -3,3 l 5,0' +
+        'm -4,3 l 5,0',
+      height: 15,
+      width:  12.6,
+      heightElements: [ 6, 14 ],
+      widthElements: [ 10.5, 21 ]
+    },
+    'TASK_TYPE_USER_1': {
+      d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' +
+        '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' +
+        '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' +
+        'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' +
+        'm -8,6 l 0,5.5 m 11,0 l 0,-5'
+    },
+    'TASK_TYPE_USER_2': {
+      d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' +
+        '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 '
+    },
+    'TASK_TYPE_USER_3': {
+      d: 'm {mx},{my} m -6.9,-3.80 c 0,0 2.25099998,-2.358 4.27399998,-1.177 2.024,1.181 4.221,1.537 ' +
+        '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' +
+        '-4.20799998,3.36699999 -4.20699998,4.34799999 z'
+    },
+    'TASK_TYPE_MANUAL': {
+      d: 'm {mx},{my} c 0.234,-0.01 5.604,0.008 8.029,0.004 0.808,0 1.271,-0.172 1.417,-0.752 0.227,-0.898 ' +
+        '-0.334,-1.314 -1.338,-1.316 -2.467,-0.01 -7.886,-0.004 -8.108,-0.004 -0.014,-0.079 0.016,-0.533 0,-0.61 ' +
+        '0.195,-0.042 8.507,0.006 9.616,0.002 0.877,-0.007 1.35,-0.438 1.353,-1.208 0.003,-0.768 -0.479,-1.09 ' +
+        '-1.35,-1.091 -2.968,-0.002 -9.619,-0.013 -9.619,-0.013 v -0.591 c 0,0 5.052,-0.016 7.225,-0.016 ' +
+        '0.888,-0.002 1.354,-0.416 1.351,-1.193 -0.006,-0.761 -0.492,-1.196 -1.361,-1.196 -3.473,-0.005 ' +
+        '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' +
+        '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' +
+        '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' +
+        '-1.516,1.253 -1.882,2.19 -0.37000002,0.95 -0.17,2.01 -0.166,2.979 0.004,0.718 -0.27300002,1.345 ' +
+        '-0.055,2.063 0.629,2.087 2.425,3.312 4.859,3.318 4.6179995,0.014 9.2379995,-0.139 13.8569995,-0.158 ' +
+        '0.755,-0.004 1.171,-0.301 1.182,-1.033 0.012,-0.754 -0.423,-0.969 -1.183,-0.973 -1.778,-0.01 ' +
+        '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z'
+    },
+    'TASK_TYPE_INSTANTIATING_SEND': {
+      d: 'm {mx},{my} l 0,8.4 l 12.6,0 l 0,-8.4 z l 6.3,3.6 l 6.3,-3.6'
+    },
+    'TASK_TYPE_SERVICE': {
+      d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' +
+        '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' +
+        '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' +
+        'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' +
+        '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' +
+        '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' +
+        'h -2.241173 l 0.0042,1.63124 c -0.353763,0.0736 -0.705369,0.17977 -1.049785,0.32371 -0.344415,0.14437 ' +
+        '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' +
+        'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' +
+        'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' +
+        '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' +
+        'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' +
+        'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
+        '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
+        '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
+    },
+    'TASK_TYPE_SERVICE_FILL': {
+      d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
+        '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
+        '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
+    },
+    'TASK_TYPE_BUSINESS_RULE_HEADER': {
+      d: 'm {mx},{my} 0,4 20,0 0,-4 z'
+    },
+    'TASK_TYPE_BUSINESS_RULE_MAIN': {
+      d: 'm {mx},{my} 0,12 20,0 0,-12 z' +
+        'm 0,8 l 20,0 ' +
+        'm -13,-4 l 0,8'
+    },
+    'MESSAGE_FLOW_MARKER': {
+      d: 'm {mx},{my} m -10.5 ,-7 l 0,14 l 21,0 l 0,-14 z l 10.5,6 l 10.5,-6'
+    }
+  };
+
+  this.getRawPath = function getRawPath(pathId) {
+    return this.pathMap[pathId].d;
+  };
+
+  /**
+   * Scales the path to the given height and width.
+   * <h1>Use case</h1>
+   * <p>Use case is to scale the content of elements (event, gateways) based
+   * on the element bounding box's size.
+   * </p>
+   * <h1>Why not transform</h1>
+   * <p>Scaling a path with transform() will also scale the stroke and IE does not support
+   * the option 'non-scaling-stroke' to prevent this.
+   * Also there are use cases where only some parts of a path should be
+   * scaled.</p>
+   *
+   * @param {string} pathId The ID of the path.
+   * @param {Object} param <p>
+   *   Example param object scales the path to 60% size of the container (data.width, data.height).
+   *   <pre>
+   *   {
+   *     xScaleFactor: 0.6,
+   *     yScaleFactor:0.6,
+   *     containerWidth: data.width,
+   *     containerHeight: data.height,
+   *     position: {
+   *       mx: 0.46,
+   *       my: 0.2,
+   *     }
+   *   }
+   *   </pre>
+   *   <ul>
+   *    <li>targetpathwidth = xScaleFactor * containerWidth</li>
+   *    <li>targetpathheight = yScaleFactor * containerHeight</li>
+   *    <li>Position is used to set the starting coordinate of the path. M is computed:
+    *    <ul>
+    *      <li>position.x * containerWidth</li>
+    *      <li>position.y * containerHeight</li>
+    *    </ul>
+    *    Center of the container <pre> position: {
+   *       mx: 0.5,
+   *       my: 0.5,
+   *     }</pre>
+   *     Upper left corner of the container
+   *     <pre> position: {
+   *       mx: 0.0,
+   *       my: 0.0,
+   *     }</pre>
+   *    </li>
+   *   </ul>
+   * </p>
+   *
+   */
+  this.getScaledPath = function getScaledPath(pathId, param) {
+    var rawPath = this.pathMap[pathId];
+
+    // positioning
+    // compute the start point of the path
+    var mx, my;
+
+    if (param.abspos) {
+      mx = param.abspos.x;
+      my = param.abspos.y;
+    } else {
+      mx = param.containerWidth * param.position.mx;
+      my = param.containerHeight * param.position.my;
+    }
+
+    var coordinates = {}; // map for the scaled coordinates
+    if (param.position) {
+
+      // path
+      var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor;
+      var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor;
+
+
+      // Apply height ratio
+      for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
+        coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
+      }
+
+      // Apply width ratio
+      for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
+        coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
+      }
+    }
+
+    // Apply value to raw path
+    var path = format(
+      rawPath.d, {
+        mx: mx,
+        my: my,
+        e: coordinates
+      }
+    );
+    return path;
+  };
+}
+
+// helpers //////////////////////
+
+// copied and adjusted from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
+var tokenRegex = /\{([^{}]+)\}/g,
+    objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties
+
+function replacer(all, key, obj) {
+  var res = obj;
+  key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
+    name = name || quotedName;
+    if (res) {
+      if (name in res) {
+        res = res[name];
+      }
+      typeof res == 'function' && isFunc && (res = res());
+    }
+  });
+  res = (res == null || res == obj ? all : res) + '';
+
+  return res;
+}
+
+function format(str, obj) {
+  return String(str).replace(tokenRegex, function(all, key) {
+    return replacer(all, key, obj);
+  });
+}

+ 116 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/TextRenderer.js

@@ -0,0 +1,116 @@
+import { assign } from 'min-dash';
+
+import TextUtil from 'diagram-js/lib/util/Text';
+
+var DEFAULT_FONT_SIZE = 12;
+var LINE_HEIGHT_RATIO = 1.2;
+
+var MIN_TEXT_ANNOTATION_HEIGHT = 30;
+
+
+export default function TextRenderer(config) {
+
+  var defaultStyle = assign({
+    fontFamily: 'Arial, sans-serif',
+    fontSize: DEFAULT_FONT_SIZE,
+    fontWeight: 'normal',
+    lineHeight: LINE_HEIGHT_RATIO
+  }, config && config.defaultStyle || {});
+
+  var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
+
+  var externalStyle = assign({}, defaultStyle, {
+    fontSize: fontSize
+  }, config && config.externalStyle || {});
+
+  var textUtil = new TextUtil({
+    style: defaultStyle
+  });
+
+  /**
+   * Get the new bounds of an externally rendered,
+   * layouted label.
+   *
+   * @param  {Bounds} bounds
+   * @param  {string} text
+   *
+   * @return {Bounds}
+   */
+  this.getExternalLabelBounds = function(bounds, text) {
+
+    var layoutedDimensions = textUtil.getDimensions(text, {
+      box: {
+        width: 90,
+        height: 30,
+        x: bounds.width / 2 + bounds.x,
+        y: bounds.height / 2 + bounds.y
+      },
+      style: externalStyle
+    });
+
+    // resize label shape to fit label text
+    return {
+      x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
+      y: Math.round(bounds.y),
+      width: Math.ceil(layoutedDimensions.width),
+      height: Math.ceil(layoutedDimensions.height)
+    };
+
+  };
+
+  /**
+   * Get the new bounds of text annotation.
+   *
+   * @param  {Bounds} bounds
+   * @param  {string} text
+   *
+   * @return {Bounds}
+   */
+  this.getTextAnnotationBounds = function(bounds, text) {
+
+    var layoutedDimensions = textUtil.getDimensions(text, {
+      box: bounds,
+      style: defaultStyle,
+      align: 'left-top',
+      padding: 5
+    });
+
+    return {
+      x: bounds.x,
+      y: bounds.y,
+      width: bounds.width,
+      height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
+    };
+  };
+
+  /**
+   * Create a layouted text element.
+   *
+   * @param {string} text
+   * @param {Object} [options]
+   *
+   * @return {SVGElement} rendered text
+   */
+  this.createText = function(text, options) {
+    return textUtil.createText(text, options || {});
+  };
+
+  /**
+   * Get default text style.
+   */
+  this.getDefaultStyle = function() {
+    return defaultStyle;
+  };
+
+  /**
+   * Get the external text style.
+   */
+  this.getExternalStyle = function() {
+    return externalStyle;
+  };
+
+}
+
+TextRenderer.$inject = [
+  'config.textRenderer'
+];

+ 11 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/draw/index.js

@@ -0,0 +1,11 @@
+import BpmnRenderer from './BpmnRenderer';
+import TextRenderer from './TextRenderer';
+
+import PathMap from './PathMap';
+
+export default {
+  __init__: [ 'bpmnRenderer' ],
+  bpmnRenderer: [ 'type', BpmnRenderer ],
+  textRenderer: [ 'type', TextRenderer ],
+  pathMap: [ 'type', PathMap ]
+};

+ 87 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/AlignElementsContextPadProvider.js

@@ -0,0 +1,87 @@
+import {
+  assign
+} from 'min-dash';
+
+import ICONS from './AlignElementsIcons';
+
+var LOW_PRIORITY = 900;
+
+/**
+ * A provider for align elements context pad button
+ */
+export default function AlignElementsContextPadProvider(contextPad, popupMenu, translate, canvas) {
+
+  contextPad.registerProvider(LOW_PRIORITY, this);
+
+  this._contextPad = contextPad;
+  this._popupMenu = popupMenu;
+  this._translate = translate;
+  this._canvas = canvas;
+}
+
+AlignElementsContextPadProvider.$inject = [
+  'contextPad',
+  'popupMenu',
+  'translate',
+  'canvas'
+];
+
+AlignElementsContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) {
+  var actions = {};
+
+  if (this._isAllowed(elements)) {
+    assign(actions, this._getEntries(elements));
+  }
+
+  return actions;
+};
+
+AlignElementsContextPadProvider.prototype._isAllowed = function(elements) {
+  return !this._popupMenu.isEmpty(elements, 'align-elements');
+};
+
+AlignElementsContextPadProvider.prototype._getEntries = function(elements) {
+  var self = this;
+
+  return {
+    'align-elements': {
+      group: 'align-elements',
+      title: self._translate('Align elements'),
+      imageUrl: ICONS['align'],
+      action: {
+        click: function(event, elements) {
+          var position = self._getMenuPosition(elements);
+
+          assign(position, {
+            cursor: {
+              x: event.x,
+              y: event.y
+            }
+          });
+
+          self._popupMenu.open(elements, 'align-elements', position);
+        }
+      }
+    }
+  };
+};
+
+AlignElementsContextPadProvider.prototype._getMenuPosition = function(elements) {
+  var Y_OFFSET = 5;
+
+  var diagramContainer = this._canvas.getContainer(),
+      pad = this._contextPad.getPad(elements).html;
+
+  var diagramRect = diagramContainer.getBoundingClientRect(),
+      padRect = pad.getBoundingClientRect();
+
+  var top = padRect.top - diagramRect.top;
+  var left = padRect.left - diagramRect.left;
+
+  var pos = {
+    x: left,
+    y: top + padRect.height + Y_OFFSET
+  };
+
+  return pos;
+};

+ 15 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/AlignElementsIcons.js

@@ -0,0 +1,15 @@
+/**
+ * To change the icons, modify the SVGs in `./resources`, execute `npx svgo -f resources --datauri enc -o dist`,
+ * and then replace respective icons with the optimized data URIs in `./dist`.
+ */
+var icons = {
+  align:  'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%202000%202000%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M200%20150v1700%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22700%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%221150%22%20width%3D%22700%22%20height%3D%22700%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
+  bottom: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%201650h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22350%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22850%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
+  center: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M900%20150v1500%22%2F%3E%3Crect%20x%3D%22250%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22500%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
+  left:   'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M100%20150v1500%22%2F%3E%3Crect%20x%3D%22100%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22100%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
+  right:  'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M1650%20150v1500%22%2F%3E%3Crect%20x%3D%22350%22%20y%3D%22150%22%20width%3D%221300%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22850%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
+  top:    'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%20150h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22150%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22150%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
+  middle: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22stroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linecap%3Around%22%20d%3D%22M150%20900h1500%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22250%22%20width%3D%22600%22%20height%3D%221300%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22500%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E'
+};
+
+export default icons;

+ 72 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/AlignElementsMenuProvider.js

@@ -0,0 +1,72 @@
+import ICONS from './AlignElementsIcons';
+
+import {
+  assign,
+  forEach,
+} from 'min-dash';
+
+var ALIGNMENT_OPTIONS = [
+  'left',
+  'center',
+  'right',
+  'top',
+  'middle',
+  'bottom'
+];
+
+/**
+ * A provider for align elements popup menu.
+ */
+export default function AlignElementsMenuProvider(popupMenu, alignElements, translate, rules) {
+
+  this._alignElements = alignElements;
+  this._translate = translate;
+  this._popupMenu = popupMenu;
+  this._rules = rules;
+
+  popupMenu.registerProvider('align-elements', this);
+}
+
+AlignElementsMenuProvider.$inject = [
+  'popupMenu',
+  'alignElements',
+  'translate',
+  'rules'
+];
+
+AlignElementsMenuProvider.prototype.getPopupMenuEntries = function(elements) {
+  var entries = {};
+
+  if (this._isAllowed(elements)) {
+    assign(entries, this._getEntries(elements));
+  }
+
+  return entries;
+};
+
+AlignElementsMenuProvider.prototype._isAllowed = function(elements) {
+  return this._rules.allowed('elements.align', { elements: elements });
+};
+
+AlignElementsMenuProvider.prototype._getEntries = function(elements) {
+  var alignElements = this._alignElements,
+      translate = this._translate,
+      popupMenu = this._popupMenu;
+
+  var entries = {};
+
+  forEach(ALIGNMENT_OPTIONS, function(alignment) {
+    entries[ 'align-elements-' + alignment ] = {
+      group: 'align',
+      title: translate('Align elements ' + alignment),
+      className: 'bjs-align-elements-menu-entry',
+      imageUrl: ICONS[alignment],
+      action: function(event, entry) {
+        alignElements.trigger(elements, alignment);
+        popupMenu.close();
+      }
+    };
+  });
+
+  return entries;
+};

+ 39 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/BpmnAlignElements.js

@@ -0,0 +1,39 @@
+import inherits from 'inherits-browser';
+
+import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';
+import { getParents } from 'diagram-js/lib/util/Elements';
+
+import {
+  filter
+} from 'min-dash';
+
+/**
+ * Rule provider for alignment of BPMN elements.
+ */
+export default function BpmnAlignElements(eventBus) {
+  RuleProvider.call(this, eventBus);
+}
+
+BpmnAlignElements.$inject = [ 'eventBus' ];
+
+inherits(BpmnAlignElements, RuleProvider);
+
+BpmnAlignElements.prototype.init = function() {
+  this.addRule('elements.align', function(context) {
+    var elements = context.elements;
+
+    // filter out elements which cannot be aligned
+    var filteredElements = filter(elements, function(element) {
+      return !(element.waypoints || element.host || element.labelTarget);
+    });
+
+    // filter out elements which are children of any of the selected elements
+    filteredElements = getParents(filteredElements);
+
+    if (filteredElements.length < 2) {
+      return false;
+    }
+
+    return filteredElements;
+  });
+};

+ 23 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/index.js

@@ -0,0 +1,23 @@
+import AlignElementsModule from 'diagram-js/lib/features/align-elements';
+import ContextPadModule from 'diagram-js/lib/features/context-pad';
+import PopupMenuModule from 'diagram-js/lib/features/popup-menu';
+
+import AlignElementsContextPadProvider from './AlignElementsContextPadProvider';
+import AlignElementsMenuProvider from './AlignElementsMenuProvider';
+import BpmnAlignElements from './BpmnAlignElements';
+
+export default {
+  __depends__: [
+    AlignElementsModule,
+    ContextPadModule,
+    PopupMenuModule
+  ],
+  __init__: [
+    'alignElementsContextPadProvider',
+    'alignElementsMenuProvider',
+    'bpmnAlignElements'
+  ],
+  alignElementsContextPadProvider: [ 'type', AlignElementsContextPadProvider ],
+  alignElementsMenuProvider: [ 'type', AlignElementsMenuProvider ],
+  bpmnAlignElements: [ 'type', BpmnAlignElements ]
+};

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-bottom-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
+  <line x1="150" y1="1650" x2="1650" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
+  <rect x="150" y="350" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="1050" y="850" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-horizontal-center-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
+  <line x1="900" y1="150" x2="900" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
+  <rect x="250" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="500" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-left-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
+  <line x1="100" y1="150" x2="100" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
+  <rect x="100" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="100" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-right-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
+  <line x1="1650" y1="150" x2="1650" y2="1650" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
+  <rect x="350" y="150" width="1300" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="850" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000">
+  <line x1="200" y1="150" x2="200" y2="1850" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
+  <rect x="500" y="150" width="1300" height="700" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="500" y="1150" width="700" height="700" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-top-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
+  <line x1="150" y1="150" x2="1650" y2="150" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
+  <rect x="150" y="150" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="1050" y="150" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/align-elements/resources/align-vertical-center-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
+  <line x1="150" y1="900" x2="1650" y2="900" style="stroke:currentColor;stroke-width:100;stroke-linecap:round;"/>
+  <rect x="150" y="250" width="600" height="1300" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="1050" y="500" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 18 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-place/BpmnAutoPlace.js

@@ -0,0 +1,18 @@
+import { getNewShapePosition } from './BpmnAutoPlaceUtil';
+
+
+/**
+ * BPMN auto-place behavior.
+ *
+ * @param {EventBus} eventBus
+ */
+export default function AutoPlace(eventBus) {
+  eventBus.on('autoPlace', function(context) {
+    var shape = context.shape,
+        source = context.source;
+
+    return getNewShapePosition(source, shape);
+  });
+}
+
+AutoPlace.$inject = [ 'eventBus' ];

+ 148 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-place/BpmnAutoPlaceUtil.js

@@ -0,0 +1,148 @@
+import { is } from '../../util/ModelUtil';
+import { isAny } from '../modeling/util/ModelingUtil';
+
+import {
+  getMid,
+  asTRBL,
+  getOrientation
+} from 'diagram-js/lib/layout/LayoutUtil';
+
+import {
+  findFreePosition,
+  generateGetNextPosition,
+  getConnectedDistance
+} from 'diagram-js/lib/features/auto-place/AutoPlaceUtil';
+
+
+/**
+ * Find the new position for the target element to
+ * connect to source.
+ *
+ * @param  {djs.model.Shape} source
+ * @param  {djs.model.Shape} element
+ *
+ * @return {Point}
+ */
+export function getNewShapePosition(source, element) {
+
+  if (is(element, 'bpmn:TextAnnotation')) {
+    return getTextAnnotationPosition(source, element);
+  }
+
+  if (isAny(element, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
+    return getDataElementPosition(source, element);
+  }
+
+  if (is(element, 'bpmn:FlowNode')) {
+    return getFlowNodePosition(source, element);
+  }
+}
+
+/**
+ * Always try to place element right of source;
+ * compute actual distance from previous nodes in flow.
+ */
+export function getFlowNodePosition(source, element) {
+
+  var sourceTrbl = asTRBL(source);
+  var sourceMid = getMid(source);
+
+  var horizontalDistance = getConnectedDistance(source, {
+    filter: function(connection) {
+      return is(connection, 'bpmn:SequenceFlow');
+    }
+  });
+
+  var margin = 30,
+      minDistance = 80,
+      orientation = 'left';
+
+  if (is(source, 'bpmn:BoundaryEvent')) {
+    orientation = getOrientation(source, source.host, -25);
+
+    if (orientation.indexOf('top') !== -1) {
+      margin *= -1;
+    }
+  }
+
+  var position = {
+    x: sourceTrbl.right + horizontalDistance + element.width / 2,
+    y: sourceMid.y + getVerticalDistance(orientation, minDistance)
+  };
+
+  var nextPositionDirection = {
+    y: {
+      margin: margin,
+      minDistance: minDistance
+    }
+  };
+
+  return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
+}
+
+
+function getVerticalDistance(orientation, minDistance) {
+  if (orientation.indexOf('top') != -1) {
+    return -1 * minDistance;
+  } else if (orientation.indexOf('bottom') != -1) {
+    return minDistance;
+  } else {
+    return 0;
+  }
+}
+
+
+/**
+ * Always try to place text annotations top right of source.
+ */
+export function getTextAnnotationPosition(source, element) {
+
+  var sourceTrbl = asTRBL(source);
+
+  var position = {
+    x: sourceTrbl.right + element.width / 2,
+    y: sourceTrbl.top - 50 - element.height / 2
+  };
+
+  if (isConnection(source)) {
+    position = getMid(source);
+    position.x += 100;
+    position.y -= 50;
+  }
+
+  var nextPositionDirection = {
+    y: {
+      margin: -30,
+      minDistance: 20
+    }
+  };
+
+  return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
+}
+
+
+/**
+ * Always put element bottom right of source.
+ */
+export function getDataElementPosition(source, element) {
+
+  var sourceTrbl = asTRBL(source);
+
+  var position = {
+    x: sourceTrbl.right - 10 + element.width / 2,
+    y: sourceTrbl.bottom + 40 + element.width / 2
+  };
+
+  var nextPositionDirection = {
+    x: {
+      margin: 30,
+      minDistance: 30
+    }
+  };
+
+  return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
+}
+
+function isConnection(element) {
+  return !!element.waypoints;
+}

+ 9 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-place/index.js

@@ -0,0 +1,9 @@
+import AutoPlaceModule from 'diagram-js/lib/features/auto-place';
+
+import BpmnAutoPlace from './BpmnAutoPlace';
+
+export default {
+  __depends__: [ AutoPlaceModule ],
+  __init__: [ 'bpmnAutoPlace' ],
+  bpmnAutoPlace: [ 'type', BpmnAutoPlace ]
+};

+ 38 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-resize/BpmnAutoResize.js

@@ -0,0 +1,38 @@
+import AutoResize from 'diagram-js/lib/features/auto-resize/AutoResize';
+
+import inherits from 'inherits-browser';
+
+import { is } from '../../util/ModelUtil';
+
+
+/**
+ * Sub class of the AutoResize module which implements a BPMN
+ * specific resize function.
+ */
+export default function BpmnAutoResize(injector) {
+
+  injector.invoke(AutoResize, this);
+}
+
+BpmnAutoResize.$inject = [
+  'injector'
+];
+
+inherits(BpmnAutoResize, AutoResize);
+
+
+/**
+ * Resize shapes and lanes.
+ *
+ * @param {djs.model.Shape} target
+ * @param {Bounds} newBounds
+ * @param {Object} hints
+ */
+BpmnAutoResize.prototype.resize = function(target, newBounds, hints) {
+
+  if (is(target, 'bpmn:Participant')) {
+    this._modeling.resizeLane(target, newBounds, null, hints);
+  } else {
+    this._modeling.resizeShape(target, newBounds, null, hints);
+  }
+};

+ 57 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-resize/BpmnAutoResizeProvider.js

@@ -0,0 +1,57 @@
+import { is } from '../../util/ModelUtil';
+
+import inherits from 'inherits-browser';
+
+import { forEach } from 'min-dash';
+
+import AutoResizeProvider from 'diagram-js/lib/features/auto-resize/AutoResizeProvider';
+
+
+/**
+ * This module is a provider for automatically resizing parent BPMN elements
+ */
+export default function BpmnAutoResizeProvider(eventBus, modeling) {
+  AutoResizeProvider.call(this, eventBus);
+
+  this._modeling = modeling;
+}
+
+inherits(BpmnAutoResizeProvider, AutoResizeProvider);
+
+BpmnAutoResizeProvider.$inject = [
+  'eventBus',
+  'modeling'
+];
+
+
+/**
+ * Check if the given target can be expanded
+ *
+ * @param  {djs.model.Shape} target
+ *
+ * @return {boolean}
+ */
+BpmnAutoResizeProvider.prototype.canResize = function(elements, target) {
+
+  // do not resize plane elements:
+  // root elements, collapsed sub-processes
+  if (is(target.di, 'bpmndi:BPMNPlane')) {
+    return false;
+  }
+
+  if (!is(target, 'bpmn:Participant') && !is(target, 'bpmn:Lane') && !(is(target, 'bpmn:SubProcess'))) {
+    return false;
+  }
+
+  var canResize = true;
+
+  forEach(elements, function(element) {
+
+    if (is(element, 'bpmn:Lane') || element.labelTarget) {
+      canResize = false;
+      return;
+    }
+  });
+
+  return canResize;
+};

+ 12 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/auto-resize/index.js

@@ -0,0 +1,12 @@
+import BpmnAutoResize from './BpmnAutoResize';
+import BpmnAutoResizeProvider from './BpmnAutoResizeProvider';
+
+
+export default {
+  __init__: [
+    'bpmnAutoResize',
+    'bpmnAutoResizeProvider'
+  ],
+  bpmnAutoResize: [ 'type', BpmnAutoResize ],
+  bpmnAutoResizeProvider: [ 'type', BpmnAutoResizeProvider ]
+};

+ 526 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/context-pad/ContextPadProvider.js

@@ -0,0 +1,526 @@
+import {
+  assign,
+  forEach,
+  isArray,
+  every
+} from 'min-dash';
+
+import {
+  is
+} from '../../util/ModelUtil';
+
+import {
+  isExpanded,
+  isEventSubProcess
+} from '../../util/DiUtil';
+
+import {
+  isAny
+} from '../modeling/util/ModelingUtil';
+
+import {
+  getChildLanes
+} from '../modeling/util/LaneUtil';
+
+import {
+  hasPrimaryModifier
+} from 'diagram-js/lib/util/Mouse';
+
+
+/**
+ * A provider for BPMN 2.0 elements context pad
+ */
+export default function ContextPadProvider(
+    config, injector, eventBus,
+    contextPad, modeling, elementFactory,
+    connect, create, popupMenu,
+    canvas, rules, translate) {
+
+  config = config || {};
+
+  contextPad.registerProvider(this);
+
+  this._contextPad = contextPad;
+
+  this._modeling = modeling;
+
+  this._elementFactory = elementFactory;
+  this._connect = connect;
+  this._create = create;
+  this._popupMenu = popupMenu;
+  this._canvas = canvas;
+  this._rules = rules;
+  this._translate = translate;
+
+  if (config.autoPlace !== false) {
+    this._autoPlace = injector.get('autoPlace', false);
+  }
+
+  eventBus.on('create.end', 250, function(event) {
+    var context = event.context,
+        shape = context.shape;
+
+    if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {
+      return;
+    }
+
+    var entries = contextPad.getEntries(shape);
+
+    if (entries.replace) {
+      entries.replace.action.click(event, shape);
+    }
+  });
+}
+
+ContextPadProvider.$inject = [
+  'config.contextPad',
+  'injector',
+  'eventBus',
+  'contextPad',
+  'modeling',
+  'elementFactory',
+  'connect',
+  'create',
+  'popupMenu',
+  'canvas',
+  'rules',
+  'translate'
+];
+
+ContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) {
+  var modeling = this._modeling;
+
+  var actions = {};
+
+  if (this._isDeleteAllowed(elements)) {
+    assign(actions, {
+      'delete': {
+        group: 'edit',
+        className: 'bpmn-icon-trash',
+        title: this._translate('Remove'),
+        action: {
+          click: function(event, elements) {
+            modeling.removeElements(elements.slice());
+          }
+        }
+      }
+    });
+  }
+
+  return actions;
+};
+
+/**
+ * @param {djs.model.Base[]} elements
+ * @return {boolean}
+ */
+ContextPadProvider.prototype._isDeleteAllowed = function(elements) {
+
+  var baseAllowed = this._rules.allowed('elements.delete', {
+    elements: elements
+  });
+
+  if (isArray(baseAllowed)) {
+    return every(baseAllowed, function(element) {
+      return includes(baseAllowed, element);
+    });
+  }
+
+  return baseAllowed;
+};
+
+ContextPadProvider.prototype.getContextPadEntries = function(element) {
+  var contextPad = this._contextPad,
+      modeling = this._modeling,
+
+      elementFactory = this._elementFactory,
+      connect = this._connect,
+      create = this._create,
+      popupMenu = this._popupMenu,
+      canvas = this._canvas,
+      rules = this._rules,
+      autoPlace = this._autoPlace,
+      translate = this._translate;
+
+  var actions = {};
+
+  if (element.type === 'label') {
+    return actions;
+  }
+
+  var businessObject = element.businessObject;
+
+  function startConnect(event, element) {
+    connect.start(event, element);
+  }
+
+  function removeElement(e, element) {
+    modeling.removeElements([ element ]);
+  }
+
+  function getReplaceMenuPosition(element) {
+
+    var Y_OFFSET = 5;
+
+    var diagramContainer = canvas.getContainer(),
+        pad = contextPad.getPad(element).html;
+
+    var diagramRect = diagramContainer.getBoundingClientRect(),
+        padRect = pad.getBoundingClientRect();
+
+    var top = padRect.top - diagramRect.top;
+    var left = padRect.left - diagramRect.left;
+
+    var pos = {
+      x: left,
+      y: top + padRect.height + Y_OFFSET
+    };
+
+    return pos;
+  }
+
+
+  /**
+   * Create an append action
+   *
+   * @param {string} type
+   * @param {string} className
+   * @param {string} [title]
+   * @param {Object} [options]
+   *
+   * @return {Object} descriptor
+   */
+  function appendAction(type, className, title, options) {
+
+    if (typeof title !== 'string') {
+      options = title;
+      title = translate('Append {type}', { type: type.replace(/^bpmn:/, '') });
+    }
+
+    function appendStart(event, element) {
+
+      var shape = elementFactory.createShape(assign({ type: type }, options));
+      create.start(event, shape, {
+        source: element
+      });
+    }
+
+
+    var append = autoPlace ? function(event, element) {
+      var shape = elementFactory.createShape(assign({ type: type }, options));
+
+      autoPlace.append(element, shape);
+    } : appendStart;
+
+
+    return {
+      group: 'model',
+      className: className,
+      title: title,
+      action: {
+        dragstart: appendStart,
+        click: append
+      }
+    };
+  }
+
+  function splitLaneHandler(count) {
+
+    return function(event, element) {
+
+      // actual split
+      modeling.splitLane(element, count);
+
+      // refresh context pad after split to
+      // get rid of split icons
+      contextPad.open(element, true);
+    };
+  }
+
+
+  if (isAny(businessObject, [ 'bpmn:Lane', 'bpmn:Participant' ]) && isExpanded(element)) {
+
+    var childLanes = getChildLanes(element);
+
+    assign(actions, {
+      'lane-insert-above': {
+        group: 'lane-insert-above',
+        className: 'bpmn-icon-lane-insert-above',
+        title: translate('Add Lane above'),
+        action: {
+          click: function(event, element) {
+            modeling.addLane(element, 'top');
+          }
+        }
+      }
+    });
+
+    if (childLanes.length < 2) {
+
+      if (element.height >= 120) {
+        assign(actions, {
+          'lane-divide-two': {
+            group: 'lane-divide',
+            className: 'bpmn-icon-lane-divide-two',
+            title: translate('Divide into two Lanes'),
+            action: {
+              click: splitLaneHandler(2)
+            }
+          }
+        });
+      }
+
+      if (element.height >= 180) {
+        assign(actions, {
+          'lane-divide-three': {
+            group: 'lane-divide',
+            className: 'bpmn-icon-lane-divide-three',
+            title: translate('Divide into three Lanes'),
+            action: {
+              click: splitLaneHandler(3)
+            }
+          }
+        });
+      }
+    }
+
+    assign(actions, {
+      'lane-insert-below': {
+        group: 'lane-insert-below',
+        className: 'bpmn-icon-lane-insert-below',
+        title: translate('Add Lane below'),
+        action: {
+          click: function(event, element) {
+            modeling.addLane(element, 'bottom');
+          }
+        }
+      }
+    });
+
+  }
+
+  if (is(businessObject, 'bpmn:FlowNode')) {
+
+    if (is(businessObject, 'bpmn:EventBasedGateway')) {
+
+      assign(actions, {
+        'append.receive-task': appendAction(
+          'bpmn:ReceiveTask',
+          'bpmn-icon-receive-task',
+          translate('Append ReceiveTask')
+        ),
+        'append.message-intermediate-event': appendAction(
+          'bpmn:IntermediateCatchEvent',
+          'bpmn-icon-intermediate-event-catch-message',
+          translate('Append MessageIntermediateCatchEvent'),
+          { eventDefinitionType: 'bpmn:MessageEventDefinition' }
+        ),
+        'append.timer-intermediate-event': appendAction(
+          'bpmn:IntermediateCatchEvent',
+          'bpmn-icon-intermediate-event-catch-timer',
+          translate('Append TimerIntermediateCatchEvent'),
+          { eventDefinitionType: 'bpmn:TimerEventDefinition' }
+        ),
+        'append.condition-intermediate-event': appendAction(
+          'bpmn:IntermediateCatchEvent',
+          'bpmn-icon-intermediate-event-catch-condition',
+          translate('Append ConditionIntermediateCatchEvent'),
+          { eventDefinitionType: 'bpmn:ConditionalEventDefinition' }
+        ),
+        'append.signal-intermediate-event': appendAction(
+          'bpmn:IntermediateCatchEvent',
+          'bpmn-icon-intermediate-event-catch-signal',
+          translate('Append SignalIntermediateCatchEvent'),
+          { eventDefinitionType: 'bpmn:SignalEventDefinition' }
+        )
+      });
+    } else
+
+    if (isEventType(businessObject, 'bpmn:BoundaryEvent', 'bpmn:CompensateEventDefinition')) {
+
+      assign(actions, {
+        'append.compensation-activity':
+            appendAction(
+              'bpmn:Task',
+              'bpmn-icon-task',
+              translate('Append compensation activity'),
+              {
+                isForCompensation: true
+              }
+            )
+      });
+    } else
+
+    if (!is(businessObject, 'bpmn:EndEvent') &&
+        !businessObject.isForCompensation &&
+        !isEventType(businessObject, 'bpmn:IntermediateThrowEvent', 'bpmn:LinkEventDefinition') &&
+        !isEventSubProcess(businessObject)) {
+
+      assign(actions, {
+        'append.end-event': appendAction(
+          'bpmn:EndEvent',
+          'bpmn-icon-end-event-none',
+          translate('Append EndEvent')
+        ),
+        'append.gateway': appendAction(
+          'bpmn:ExclusiveGateway',
+          'bpmn-icon-gateway-none',
+          translate('Append Gateway')
+        ),
+        'append.append-task': appendAction(
+          'bpmn:Task',
+          'bpmn-icon-task',
+          translate('Append Task')
+        ),
+        'append.intermediate-event': appendAction(
+          'bpmn:IntermediateThrowEvent',
+          'bpmn-icon-intermediate-event-none',
+          translate('Append Intermediate/Boundary Event')
+        )
+      });
+    }
+  }
+
+  if (!popupMenu.isEmpty(element, 'bpmn-replace')) {
+
+    // Replace menu entry
+    assign(actions, {
+      'replace': {
+        group: 'edit',
+        className: 'bpmn-icon-screw-wrench',
+        title: translate('Change type'),
+        action: {
+          click: function(event, element) {
+
+            var position = assign(getReplaceMenuPosition(element), {
+              cursor: { x: event.x, y: event.y }
+            });
+
+            popupMenu.open(element, 'bpmn-replace', position);
+          }
+        }
+      }
+    });
+  }
+
+  if (is(businessObject, 'bpmn:SequenceFlow')) {
+    assign(actions, {
+      'append.text-annotation': appendAction(
+        'bpmn:TextAnnotation',
+        'bpmn-icon-text-annotation'
+      )
+    });
+  }
+
+  if (
+    isAny(businessObject, [
+      'bpmn:FlowNode',
+      'bpmn:InteractionNode',
+      'bpmn:DataObjectReference',
+      'bpmn:DataStoreReference',
+    ])
+  ) {
+    assign(actions, {
+      'append.text-annotation': appendAction(
+        'bpmn:TextAnnotation',
+        'bpmn-icon-text-annotation'
+      ),
+
+      'connect': {
+        group: 'connect',
+        className: 'bpmn-icon-connection-multi',
+        title: translate(
+          'Connect using ' +
+            (businessObject.isForCompensation
+              ? ''
+              : 'Sequence/MessageFlow or ') +
+            'Association'
+        ),
+        action: {
+          click: startConnect,
+          dragstart: startConnect,
+        },
+      },
+    });
+  }
+
+  if (is(businessObject, 'bpmn:TextAnnotation')) {
+    assign(actions, {
+      'connect': {
+        group: 'connect',
+        className: 'bpmn-icon-connection-multi',
+        title: translate('Connect using Association'),
+        action: {
+          click: startConnect,
+          dragstart: startConnect,
+        },
+      },
+    });
+  }
+
+  if (isAny(businessObject, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
+    assign(actions, {
+      'connect': {
+        group: 'connect',
+        className: 'bpmn-icon-connection-multi',
+        title: translate('Connect using DataInputAssociation'),
+        action: {
+          click: startConnect,
+          dragstart: startConnect
+        }
+      }
+    });
+  }
+
+  if (is(businessObject, 'bpmn:Group')) {
+    assign(actions, {
+      'append.text-annotation': appendAction('bpmn:TextAnnotation', 'bpmn-icon-text-annotation')
+    });
+  }
+
+  // delete element entry, only show if allowed by rules
+  var deleteAllowed = rules.allowed('elements.delete', { elements: [ element ] });
+
+  if (isArray(deleteAllowed)) {
+
+    // was the element returned as a deletion candidate?
+    deleteAllowed = deleteAllowed[0] === element;
+  }
+
+  if (deleteAllowed) {
+    assign(actions, {
+      'delete': {
+        group: 'edit',
+        className: 'bpmn-icon-trash',
+        title: translate('Remove'),
+        action: {
+          click: removeElement
+        }
+      }
+    });
+  }
+
+  return actions;
+};
+
+
+// helpers /////////
+
+function isEventType(eventBo, type, definition) {
+
+  var isType = eventBo.$instanceOf(type);
+  var isDefinition = false;
+
+  var definitions = eventBo.eventDefinitions || [];
+  forEach(definitions, function(def) {
+    if (def.$type === definition) {
+      isDefinition = true;
+    }
+  });
+
+  return isType && isDefinition;
+}
+
+function includes(array, item) {
+  return array.indexOf(item) !== -1;
+}

+ 21 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/context-pad/index.js

@@ -0,0 +1,21 @@
+import DirectEditingModule from 'diagram-js-direct-editing';
+import ContextPadModule from 'diagram-js/lib/features/context-pad';
+import SelectionModule from 'diagram-js/lib/features/selection';
+import ConnectModule from 'diagram-js/lib/features/connect';
+import CreateModule from 'diagram-js/lib/features/create';
+import PopupMenuModule from '../popup-menu';
+
+import ContextPadProvider from './ContextPadProvider';
+
+export default {
+  __depends__: [
+    DirectEditingModule,
+    ContextPadModule,
+    SelectionModule,
+    ConnectModule,
+    CreateModule,
+    PopupMenuModule
+  ],
+  __init__: [ 'contextPadProvider' ],
+  contextPadProvider: [ 'type', ContextPadProvider ]
+};

+ 185 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/copy-paste/BpmnCopyPaste.js

@@ -0,0 +1,185 @@
+import {
+  getBusinessObject,
+  getDi,
+  is
+} from '../../util/ModelUtil';
+
+import {
+  forEach,
+  isArray,
+  isUndefined,
+  omit,
+  reduce
+} from 'min-dash';
+
+function copyProperties(source, target, properties) {
+  if (!isArray(properties)) {
+    properties = [ properties ];
+  }
+
+  forEach(properties, function(property) {
+    if (!isUndefined(source[property])) {
+      target[property] = source[property];
+    }
+  });
+}
+
+var LOW_PRIORITY = 750;
+
+
+export default function BpmnCopyPaste(bpmnFactory, eventBus, moddleCopy) {
+
+  function copy(bo, clone) {
+    var targetBo = bpmnFactory.create(bo.$type);
+
+    return moddleCopy.copyElement(bo, targetBo, null, clone);
+  }
+
+  eventBus.on('copyPaste.copyElement', LOW_PRIORITY, function(context) {
+    var descriptor = context.descriptor,
+        element = context.element,
+        businessObject = getBusinessObject(element);
+
+    // do not copy business object + di for labels;
+    // will be pulled from the referenced label target
+    if (isLabel(element)) {
+      return descriptor;
+    }
+
+    var businessObjectCopy = descriptor.businessObject = copy(businessObject, true);
+    var diCopy = descriptor.di = copy(getDi(element), true);
+    diCopy.bpmnElement = businessObjectCopy;
+
+    copyProperties(businessObjectCopy, descriptor, 'name');
+    copyProperties(diCopy, descriptor, 'isExpanded');
+
+    // default sequence flow
+    if (businessObject.default) {
+      descriptor.default = businessObject.default.id;
+    }
+  });
+
+  var referencesKey = '-bpmn-js-refs';
+
+  function getReferences(cache) {
+    return (cache[referencesKey] = cache[referencesKey] || {});
+  }
+
+  function setReferences(cache, references) {
+    cache[referencesKey] = references;
+  }
+
+  function resolveReferences(descriptor, cache, references) {
+    var businessObject = getBusinessObject(descriptor);
+
+    // default sequence flows
+    if (descriptor.default) {
+
+      // relationship cannot be resolved immediately
+      references[ descriptor.default ] = {
+        element: businessObject,
+        property: 'default'
+      };
+    }
+
+    // boundary events
+    if (descriptor.host) {
+
+      // relationship can be resolved immediately
+      getBusinessObject(descriptor).attachedToRef = getBusinessObject(cache[ descriptor.host ]);
+    }
+
+    return omit(references, reduce(references, function(array, reference, key) {
+      var element = reference.element,
+          property = reference.property;
+
+      if (key === descriptor.id) {
+        element[ property ] = businessObject;
+
+        array.push(descriptor.id);
+      }
+
+      return array;
+    }, []));
+  }
+
+  eventBus.on('copyPaste.pasteElement', function(context) {
+    var cache = context.cache,
+        descriptor = context.descriptor,
+        businessObject = descriptor.businessObject,
+        di = descriptor.di;
+
+    // wire existing di + businessObject for external label
+    if (isLabel(descriptor)) {
+      descriptor.businessObject = getBusinessObject(cache[ descriptor.labelTarget ]);
+      descriptor.di = getDi(cache[ descriptor.labelTarget ]);
+
+      return;
+    }
+
+    businessObject = descriptor.businessObject = copy(businessObject);
+
+    di = descriptor.di = copy(di);
+    di.bpmnElement = businessObject;
+
+    copyProperties(descriptor, businessObject, [
+      'isExpanded',
+      'name'
+    ]);
+
+    descriptor.type = businessObject.$type;
+  });
+
+  // copy + paste processRef with participant
+
+  eventBus.on('copyPaste.copyElement', LOW_PRIORITY, function(context) {
+    var descriptor = context.descriptor,
+        element = context.element;
+
+    if (!is(element, 'bpmn:Participant')) {
+      return;
+    }
+
+    var participantBo = getBusinessObject(element);
+
+    if (participantBo.processRef) {
+      descriptor.processRef = copy(participantBo.processRef, true);
+    }
+  });
+
+  eventBus.on('copyPaste.pasteElement', function(context) {
+    var descriptor = context.descriptor,
+        processRef = descriptor.processRef;
+
+    if (processRef) {
+      descriptor.processRef = copy(processRef);
+    }
+  });
+
+  // resolve references
+
+  eventBus.on('copyPaste.pasteElement', LOW_PRIORITY, function(context) {
+    var cache = context.cache,
+        descriptor = context.descriptor;
+
+    // resolve references e.g. default sequence flow
+    setReferences(
+      cache,
+      resolveReferences(descriptor, cache, getReferences(cache))
+    );
+  });
+
+}
+
+
+BpmnCopyPaste.$inject = [
+  'bpmnFactory',
+  'eventBus',
+  'moddleCopy'
+];
+
+// helpers //////////
+
+function isLabel(element) {
+  return !!element.labelTarget;
+}

+ 304 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/copy-paste/ModdleCopy.js

@@ -0,0 +1,304 @@
+import {
+  find,
+  forEach,
+  isArray,
+  isDefined,
+  isObject,
+  matchPattern,
+  reduce,
+  has,
+  sortBy
+} from 'min-dash';
+
+var DISALLOWED_PROPERTIES = [
+  'artifacts',
+  'dataInputAssociations',
+  'dataOutputAssociations',
+  'default',
+  'flowElements',
+  'lanes',
+  'incoming',
+  'outgoing',
+  'categoryValue'
+];
+
+/**
+ * @typedef {Function} <moddleCopy.canCopyProperties> listener
+ *
+ * @param {Object} context
+ * @param {Array<string>} context.propertyNames
+ * @param {ModdleElement} context.sourceElement
+ * @param {ModdleElement} context.targetElement
+ *
+ * @returns {Array<string>|boolean} - Return properties to be copied or false to disallow
+ * copying.
+ */
+
+/**
+ * @typedef {Function} <moddleCopy.canCopyProperty> listener
+ *
+ * @param {Object} context
+ * @param {ModdleElement} context.parent
+ * @param {*} context.property
+ * @param {string} context.propertyName
+ *
+ * @returns {*|boolean} - Return copied property or false to disallow
+ * copying.
+ */
+
+/**
+ * @typedef {Function} <moddleCopy.canSetCopiedProperty> listener
+ *
+ * @param {Object} context
+ * @param {ModdleElement} context.parent
+ * @param {*} context.property
+ * @param {string} context.propertyName
+ *
+ * @returns {boolean} - Return false to disallow
+ * setting copied property.
+ */
+
+/**
+ * Utility for copying model properties from source element to target element.
+ *
+ * @param {EventBus} eventBus
+ * @param {BpmnFactory} bpmnFactory
+ * @param {BpmnModdle} moddle
+ */
+export default function ModdleCopy(eventBus, bpmnFactory, moddle) {
+  this._bpmnFactory = bpmnFactory;
+  this._eventBus = eventBus;
+  this._moddle = moddle;
+
+  // copy extension elements last
+  eventBus.on('moddleCopy.canCopyProperties', function(context) {
+    var propertyNames = context.propertyNames;
+
+    if (!propertyNames || !propertyNames.length) {
+      return;
+    }
+
+    return sortBy(propertyNames, function(propertyName) {
+      return propertyName === 'extensionElements';
+    });
+  });
+
+  // default check whether property can be copied
+  eventBus.on('moddleCopy.canCopyProperty', function(context) {
+    var parent = context.parent,
+        parentDescriptor = isObject(parent) && parent.$descriptor,
+        propertyName = context.propertyName;
+
+    if (propertyName && DISALLOWED_PROPERTIES.indexOf(propertyName) !== -1) {
+
+      // disallow copying property
+      return false;
+    }
+
+    if (propertyName &&
+      parentDescriptor &&
+      !find(parentDescriptor.properties, matchPattern({ name: propertyName }))) {
+
+      // disallow copying property
+      return false;
+    }
+  });
+
+  // do NOT allow to copy empty extension elements
+  eventBus.on('moddleCopy.canSetCopiedProperty', function(context) {
+    var property = context.property;
+
+    if (is(property, 'bpmn:ExtensionElements') && (!property.values || !property.values.length)) {
+
+      // disallow setting copied property
+      return false;
+    }
+  });
+}
+
+ModdleCopy.$inject = [
+  'eventBus',
+  'bpmnFactory',
+  'moddle'
+];
+
+/**
+ * Copy model properties of source element to target element.
+ *
+ * @param {ModdleElement} sourceElement
+ * @param {ModdleElement} targetElement
+ * @param {Array<string>} [propertyNames]
+ * @param {boolean} clone
+ *
+ * @param {ModdleElement}
+ */
+ModdleCopy.prototype.copyElement = function(sourceElement, targetElement, propertyNames, clone) {
+  var self = this;
+
+  if (propertyNames && !isArray(propertyNames)) {
+    propertyNames = [ propertyNames ];
+  }
+
+  propertyNames = propertyNames || getPropertyNames(sourceElement.$descriptor);
+
+  var canCopyProperties = this._eventBus.fire('moddleCopy.canCopyProperties', {
+    propertyNames: propertyNames,
+    sourceElement: sourceElement,
+    targetElement: targetElement,
+    clone: clone
+  });
+
+  if (canCopyProperties === false) {
+    return targetElement;
+  }
+
+  if (isArray(canCopyProperties)) {
+    propertyNames = canCopyProperties;
+  }
+
+  // copy properties
+  forEach(propertyNames, function(propertyName) {
+    var sourceProperty;
+
+    if (has(sourceElement, propertyName)) {
+      sourceProperty = sourceElement.get(propertyName);
+    }
+
+    var copiedProperty = self.copyProperty(sourceProperty, targetElement, propertyName, clone);
+
+    if (!isDefined(copiedProperty)) {
+      return;
+    }
+
+    var canSetProperty = self._eventBus.fire('moddleCopy.canSetCopiedProperty', {
+      parent: targetElement,
+      property: copiedProperty,
+      propertyName: propertyName
+    });
+
+    if (canSetProperty === false) {
+      return;
+    }
+
+    // TODO(nikku): unclaim old IDs if ID property is copied over
+    // this._moddle.getPropertyDescriptor(parent, propertyName)
+    targetElement.set(propertyName, copiedProperty);
+  });
+
+  return targetElement;
+};
+
+/**
+ * Copy model property.
+ *
+ * @param {*} property
+ * @param {ModdleElement} parent
+ * @param {string} propertyName
+ * @param {boolean} clone
+ *
+ * @returns {*}
+ */
+ModdleCopy.prototype.copyProperty = function(property, parent, propertyName, clone) {
+  var self = this;
+
+  // allow others to copy property
+  var copiedProperty = this._eventBus.fire('moddleCopy.canCopyProperty', {
+    parent: parent,
+    property: property,
+    propertyName: propertyName,
+    clone: clone
+  });
+
+  // return if copying is NOT allowed
+  if (copiedProperty === false) {
+    return;
+  }
+
+  if (copiedProperty) {
+    if (isObject(copiedProperty) && copiedProperty.$type && !copiedProperty.$parent) {
+      copiedProperty.$parent = parent;
+    }
+
+    return copiedProperty;
+  }
+
+  var propertyDescriptor = this._moddle.getPropertyDescriptor(parent, propertyName);
+
+  // do NOT copy references
+  if (propertyDescriptor.isReference) {
+    return;
+  }
+
+  // copy id
+  if (propertyDescriptor.isId) {
+    return property && this._copyId(property, parent, clone);
+  }
+
+  // copy arrays
+  if (isArray(property)) {
+    return reduce(property, function(childProperties, childProperty) {
+
+      // recursion
+      copiedProperty = self.copyProperty(childProperty, parent, propertyName, clone);
+
+      // copying might NOT be allowed
+      if (copiedProperty) {
+        return childProperties.concat(copiedProperty);
+      }
+
+      return childProperties;
+    }, []);
+  }
+
+  // copy model elements
+  if (isObject(property) && property.$type) {
+    if (this._moddle.getElementDescriptor(property).isGeneric) {
+      return;
+    }
+
+    copiedProperty = self._bpmnFactory.create(property.$type);
+
+    copiedProperty.$parent = parent;
+
+    // recursion
+    copiedProperty = self.copyElement(property, copiedProperty, null, clone);
+
+    return copiedProperty;
+  }
+
+  // copy primitive properties
+  return property;
+};
+
+ModdleCopy.prototype._copyId = function(id, element, clone) {
+
+  if (clone) {
+    return id;
+  }
+
+  // disallow if already taken
+  if (this._moddle.ids.assigned(id)) {
+    return;
+  } else {
+
+    this._moddle.ids.claim(id, element);
+    return id;
+  }
+};
+
+// helpers //////////
+
+export function getPropertyNames(descriptor, keepDefaultProperties) {
+  return reduce(descriptor.properties, function(properties, property) {
+
+    if (keepDefaultProperties && property.default) {
+      return properties;
+    }
+
+    return properties.concat(property.name);
+  }, []);
+}
+
+function is(element, type) {
+  return element && (typeof element.$instanceOf === 'function') && element.$instanceOf(type);
+}

+ 13 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/copy-paste/index.js

@@ -0,0 +1,13 @@
+import CopyPasteModule from 'diagram-js/lib/features/copy-paste';
+
+import BpmnCopyPaste from './BpmnCopyPaste';
+import ModdleCopy from './ModdleCopy';
+
+export default {
+  __depends__: [
+    CopyPasteModule
+  ],
+  __init__: [ 'bpmnCopyPaste', 'moddleCopy' ],
+  bpmnCopyPaste: [ 'type', BpmnCopyPaste ],
+  moddleCopy: [ 'type', ModdleCopy ]
+};

+ 40 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/di-ordering/BpmnDiOrdering.js

@@ -0,0 +1,40 @@
+import { getDi } from '../../util/ModelUtil';
+
+import {
+  filter,
+  forEach,
+  map
+} from 'min-dash';
+
+import { selfAndAllChildren } from 'diagram-js/lib/util/Elements';
+
+
+var HIGH_PRIORITY = 2000;
+
+export default function BpmnDiOrdering(eventBus, canvas) {
+
+  eventBus.on('saveXML.start', HIGH_PRIORITY, orderDi);
+
+  function orderDi() {
+    var rootElements = canvas.getRootElements();
+
+    forEach(rootElements, function(root) {
+      var rootDi = getDi(root),
+          elements,
+          diElements;
+
+      elements = selfAndAllChildren([ root ], false);
+
+      // only bpmndi:Shape and bpmndi:Edge can be direct children of bpmndi:Plane
+      elements = filter(elements, function(element) {
+        return element !== root && !element.labelTarget;
+      });
+
+      diElements = map(elements, getDi);
+
+      rootDi.set('planeElement', diElements);
+    });
+  }
+}
+
+BpmnDiOrdering.$inject = [ 'eventBus', 'canvas' ];

+ 8 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/di-ordering/index.js

@@ -0,0 +1,8 @@
+import BpmnDiOrdering from '../di-ordering/BpmnDiOrdering';
+
+export default {
+  __init__: [
+    'bpmnDiOrdering'
+  ],
+  bpmnDiOrdering: [ 'type', BpmnDiOrdering ]
+};

+ 55 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/BpmnDistributeElements.js

@@ -0,0 +1,55 @@
+import inherits from 'inherits-browser';
+
+import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';
+import { getParents } from 'diagram-js/lib/util/Elements';
+
+import {
+  filter
+} from 'min-dash';
+
+import {
+  isAny
+} from '../modeling/util/ModelingUtil';
+
+
+/**
+ * Registers element exclude filters for elements that
+ * currently do not support distribution.
+ */
+export default function BpmnDistributeElements(distributeElements, eventBus, rules) {
+  RuleProvider.call(this, eventBus);
+}
+
+BpmnDistributeElements.$inject = [ 'distributeElements', 'eventBus', 'rules' ];
+
+inherits(BpmnDistributeElements, RuleProvider);
+
+BpmnDistributeElements.prototype.init = function() {
+  this.addRule('elements.distribute', function(context) {
+    var elements = context.elements;
+
+    elements = filter(elements, function(element) {
+      var cannotDistribute = isAny(element, [
+        'bpmn:Association',
+        'bpmn:BoundaryEvent',
+        'bpmn:DataInputAssociation',
+        'bpmn:DataOutputAssociation',
+        'bpmn:Lane',
+        'bpmn:MessageFlow',
+        'bpmn:SequenceFlow',
+        'bpmn:TextAnnotation'
+      ]);
+
+      return !(element.labelTarget || cannotDistribute);
+    });
+
+    // filter out elements which are children of any of the selected elements
+    elements = getParents(elements);
+
+    if (elements.length < 3) {
+      return false;
+    }
+
+    return elements;
+  });
+};

+ 10 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/DistributeElementsIcons.js

@@ -0,0 +1,10 @@
+/**
+ * To change the icons, modify the SVGs in `./resources`, execute `npx svgo -f resources --datauri enc -o dist`,
+ * and then replace respective icons with the optimized data URIs in `./dist`.
+ */
+var icons = {
+  horizontal: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linejoin%3Around%22%20d%3D%22M450%20400V150h900v250%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22450%22%20width%3D%22600%22%20height%3D%221200%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%221050%22%20y%3D%22450%22%20width%3D%22600%22%20height%3D%22800%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
+  vertical: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201800%201800%22%3E%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bstroke-linejoin%3Around%22%20d%3D%22M400%201350H150V450h250%22%2F%3E%3Crect%20x%3D%22450%22%20y%3D%22150%22%20width%3D%221200%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3Anone%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%22%2F%3E%3Crect%20x%3D%22450%22%20y%3D%221050%22%20width%3D%22800%22%20height%3D%22600%22%20rx%3D%221%22%20style%3D%22fill%3AcurrentColor%3Bstroke%3AcurrentColor%3Bstroke-width%3A100%3Bopacity%3A.5%22%2F%3E%3C%2Fsvg%3E',
+};
+
+export default icons;

+ 69 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/DistributeElementsMenuProvider.js

@@ -0,0 +1,69 @@
+import ICONS from './DistributeElementsIcons';
+
+import { assign } from 'min-dash';
+
+var LOW_PRIORITY = 900;
+
+/**
+ * A provider for distribute elements popup menu.
+ */
+export default function DistributeElementsMenuProvider(
+    popupMenu, distributeElements, translate, rules) {
+  this._distributeElements = distributeElements;
+  this._translate = translate;
+  this._popupMenu = popupMenu;
+  this._rules = rules;
+
+  popupMenu.registerProvider('align-elements', LOW_PRIORITY, this);
+}
+
+DistributeElementsMenuProvider.$inject = [
+  'popupMenu',
+  'distributeElements',
+  'translate',
+  'rules'
+];
+
+DistributeElementsMenuProvider.prototype.getPopupMenuEntries = function(elements) {
+  var entries = {};
+
+  if (this._isAllowed(elements)) {
+    assign(entries, this._getEntries(elements));
+  }
+
+  return entries;
+};
+
+DistributeElementsMenuProvider.prototype._isAllowed = function(elements) {
+  return this._rules.allowed('elements.distribute', { elements: elements });
+};
+
+DistributeElementsMenuProvider.prototype._getEntries = function(elements) {
+  var distributeElements = this._distributeElements,
+      translate = this._translate,
+      popupMenu = this._popupMenu;
+
+  var entries = {
+    'distribute-elements-horizontal': {
+      group: 'distribute',
+      title: translate('Distribute elements horizontally'),
+      className: 'bjs-align-elements-menu-entry',
+      imageUrl: ICONS['horizontal'],
+      action: function(event, entry) {
+        distributeElements.trigger(elements, 'horizontal');
+        popupMenu.close();
+      }
+    },
+    'distribute-elements-vertical': {
+      group: 'distribute',
+      title: translate('Distribute elements vertically'),
+      imageUrl: ICONS['vertical'],
+      action: function(event, entry) {
+        distributeElements.trigger(elements, 'vertical');
+        popupMenu.close();
+      }
+    },
+  };
+
+  return entries;
+};

+ 19 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/index.js

@@ -0,0 +1,19 @@
+import DistributeElementsModule from 'diagram-js/lib/features/distribute-elements';
+import PopupMenuModule from 'diagram-js/lib/features/popup-menu';
+
+import BpmnDistributeElements from './BpmnDistributeElements';
+import DistributeElementsMenuProvider from './DistributeElementsMenuProvider';
+
+
+export default {
+  __depends__: [
+    PopupMenuModule,
+    DistributeElementsModule
+  ],
+  __init__: [
+    'bpmnDistributeElements',
+    'distributeElementsMenuProvider'
+  ],
+  bpmnDistributeElements: [ 'type', BpmnDistributeElements ],
+  distributeElementsMenuProvider: [ 'type', DistributeElementsMenuProvider ]
+};

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/resources/distribute-horizontally-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
+  <polyline points="450 400 450 150 1350 150 1350 400" style="fill:none;stroke:currentColor;stroke-width:100;stroke-linejoin:round;"/>
+  <rect x="150" y="450" width="600" height="1200" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="1050" y="450" width="600" height="800" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 5 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/distribute-elements/resources/distribute-vertically-tool.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800">
+  <polyline points="400 1350 150 1350 150 450 400 450" style="fill:none;stroke:currentColor;stroke-width:100;stroke-linejoin:round;"/>
+  <rect x="450" y="150" width="1200" height="600" rx="1" style="fill:none;stroke:currentColor;stroke-width:100;"></rect>
+  <rect x="450" y="1050" width="800" height="600" rx="1" style="fill:currentColor;stroke:currentColor;stroke-width:100;opacity:.5;"></rect>
+</svg>

+ 122 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/DrilldownBreadcrumbs.js

@@ -0,0 +1,122 @@
+import { domify, classes } from 'min-dom';
+import { find } from 'min-dash';
+
+import { escapeHTML } from 'diagram-js/lib/util/EscapeUtil';
+import { getBusinessObject, is } from '../../util/ModelUtil';
+import {
+  getPlaneIdFromShape
+} from '../../util/DrilldownUtil';
+
+var OPEN_CLASS = 'bjs-breadcrumbs-shown';
+
+
+/**
+ * Adds overlays that allow switching planes on collapsed subprocesses.
+ *
+ * @param {eventBus} eventBus
+ * @param {elementRegistry} elementRegistry
+ * @param {overlays} overlays
+ * @param {canvas} canvas
+ */
+export default function DrilldownBreadcrumbs(eventBus, elementRegistry, overlays, canvas) {
+  var breadcrumbs = domify('<ul class="bjs-breadcrumbs"></ul>');
+  var container = canvas.getContainer();
+  var containerClasses = classes(container);
+  container.appendChild(breadcrumbs);
+
+  var boParents = [];
+
+  // update breadcrumbs if name or ID of the primary shape changes
+  eventBus.on('element.changed', function(e) {
+    var shape = e.element,
+        bo = getBusinessObject(shape);
+
+    var isPresent = find(boParents, function(el) {
+      return el === bo;
+    });
+
+    if (!isPresent) {
+      return;
+    }
+
+    updateBreadcrumbs();
+  });
+
+  /**
+   * Updates the displayed breadcrumbs. If no element is provided, only the
+   * labels are updated.
+   *
+   * @param {djs.model.Base} [element]
+   */
+  function updateBreadcrumbs(element) {
+    if (element) {
+      boParents = getBoParentChain(element);
+    }
+
+    var path = boParents.map(function(parent) {
+      var title = escapeHTML(parent.name || parent.id);
+      var link = domify('<li><span class="bjs-crumb"><a title="' + title + '">' + title + '</a></span></li>');
+
+      var parentPlane = canvas.findRoot(getPlaneIdFromShape(parent)) || canvas.findRoot(parent.id);
+
+      // when the root is a collaboration, the process does not have a corresponding
+      // element in the elementRegisty. Instead, we search for the corresponding participant
+      if (!parentPlane && is(parent, 'bpmn:Process')) {
+        var participant = elementRegistry.find(function(element) {
+          var bo = getBusinessObject(element);
+          return bo && bo.processRef && bo.processRef === parent;
+        });
+
+        parentPlane = canvas.findRoot(participant.id);
+      }
+
+      link.addEventListener('click', function() {
+        canvas.setRootElement(parentPlane);
+      });
+
+      return link;
+    });
+
+    breadcrumbs.innerHTML = '';
+
+    // show breadcrumbs and expose state to .djs-container
+    var visible = path.length > 1;
+    containerClasses.toggle(OPEN_CLASS, visible);
+
+    path.forEach(function(el) {
+      breadcrumbs.appendChild(el);
+    });
+  }
+
+  eventBus.on('root.set', function(event) {
+    updateBreadcrumbs(event.element);
+  });
+
+}
+
+DrilldownBreadcrumbs.$inject = [ 'eventBus', 'elementRegistry', 'overlays', 'canvas' ];
+
+
+// helpers //////////
+
+/**
+ * Returns the parents for the element using the business object chain,
+ * starting with the root element.
+ *
+ * @param {djs.model.Shape} child
+ *
+ * @returns {Array<djs.model.Shape>} parents
+ */
+function getBoParentChain(child) {
+  var bo = getBusinessObject(child);
+
+  var parents = [];
+
+  for (var element = bo; element; element = element.$parent) {
+    if (is(element, 'bpmn:SubProcess') || is(element, 'bpmn:Process')) {
+      parents.push(element);
+    }
+  }
+
+  return parents.reverse();
+}

+ 118 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/DrilldownCentering.js

@@ -0,0 +1,118 @@
+import { is } from '../../util/ModelUtil';
+
+/**
+ * Move collapsed subprocesses into view when drilling down.
+ *
+ * Zoom and scroll are saved in a session.
+ *
+ * @param {eventBus} eventBus
+ * @param {canvas} canvas
+ */
+export default function DrilldownCentering(eventBus, canvas) {
+
+  var currentRoot = null;
+  var positionMap = new Map();
+
+  eventBus.on('root.set', function(event) {
+    var newRoot = event.element;
+    var currentViewbox = canvas.viewbox();
+    var storedViewbox = positionMap.get(newRoot);
+
+    positionMap.set(currentRoot, {
+      x: currentViewbox.x,
+      y: currentViewbox.y,
+      zoom: currentViewbox.scale
+    });
+
+    currentRoot = newRoot;
+
+    // current root was replaced with a collaboration, we don't update the viewbox
+    if (is(newRoot, 'bpmn:Collaboration') && !storedViewbox) {
+      return;
+    }
+
+    storedViewbox = storedViewbox || { x: 0, y: 0, zoom: 1 };
+
+    var dx = (currentViewbox.x - storedViewbox.x) * currentViewbox.scale,
+        dy = (currentViewbox.y - storedViewbox.y) * currentViewbox.scale;
+
+    if (dx !== 0 || dy !== 0) {
+      canvas.scroll({
+        dx: dx,
+        dy: dy
+      });
+    }
+
+    if (storedViewbox.zoom !== currentViewbox.scale) {
+      canvas.zoom(storedViewbox.zoom, { x: 0, y: 0 });
+    }
+  });
+
+  eventBus.on('diagram.clear', function() {
+    positionMap.clear();
+    currentRoot = null;
+  });
+
+}
+
+DrilldownCentering.$inject = [ 'eventBus', 'canvas' ];
+
+
+/**
+ * ES5 Map implementation. Works.
+ */
+function Map() {
+
+  this._entries = [];
+
+  this.set = function(key, value) {
+
+    var found = false;
+
+    for (var k in this._entries) {
+      if (this._entries[k][0] === key) {
+        this._entries[k][1] = value;
+
+        found = true;
+
+        break;
+      }
+    }
+
+    if (!found) {
+      this._entries.push([ key, value ]);
+    }
+  };
+
+  this.get = function(key) {
+
+    for (var k in this._entries) {
+      if (this._entries[k][0] === key) {
+        return this._entries[k][1];
+      }
+    }
+
+    return null;
+  };
+
+  this.clear = function() {
+    this._entries.length = 0;
+  };
+
+  this.remove = function(key) {
+
+    var idx = -1;
+
+    for (var k in this._entries) {
+      if (this._entries[k][0] === key) {
+        idx = k;
+
+        break;
+      }
+    }
+
+    if (idx !== -1) {
+      this._entries.splice(idx, 1);
+    }
+  };
+}

+ 181 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/DrilldownOverlayBehavior.js

@@ -0,0 +1,181 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+import { is } from '../../util/ModelUtil';
+import { classes, domify } from 'min-dom';
+import { getPlaneIdFromShape } from '../../util/DrilldownUtil';
+
+var LOW_PRIORITY = 250;
+var ARROW_DOWN_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M4.81801948,3.50735931 L10.4996894,9.1896894 L10.5,4 L12,4 L12,12 L4,12 L4,10.5 L9.6896894,10.4996894 L3.75735931,4.56801948 C3.46446609,4.27512627 3.46446609,3.80025253 3.75735931,3.50735931 C4.05025253,3.21446609 4.52512627,3.21446609 4.81801948,3.50735931 Z"/></svg>';
+
+var EMPTY_MARKER = 'bjs-drilldown-empty';
+
+export default function DrilldownOverlayBehavior(
+    canvas, eventBus, elementRegistry, overlays
+) {
+  CommandInterceptor.call(this, eventBus);
+
+  this._canvas = canvas;
+  this._eventBus = eventBus;
+  this._elementRegistry = elementRegistry;
+  this._overlays = overlays;
+
+  var self = this;
+
+  this.executed('shape.toggleCollapse', LOW_PRIORITY, function(context) {
+    var shape = context.shape;
+
+    // Add overlay to the collapsed shape
+    if (self.canDrillDown(shape)) {
+      self.addOverlay(shape);
+    } else {
+      self.removeOverlay(shape);
+    }
+  }, true);
+
+
+  this.reverted('shape.toggleCollapse', LOW_PRIORITY, function(context) {
+    var shape = context.shape;
+
+    // Add overlay to the collapsed shape
+    if (self.canDrillDown(shape)) {
+      self.addOverlay(shape);
+    } else {
+      self.removeOverlay(shape);
+    }
+  }, true);
+
+
+  this.executed([ 'shape.create', 'shape.move', 'shape.delete' ], LOW_PRIORITY,
+    function(context) {
+      var oldParent = context.oldParent,
+          newParent = context.newParent || context.parent,
+          shape = context.shape;
+
+      // Add overlay to the collapsed shape
+      if (self.canDrillDown(shape)) {
+        self.addOverlay(shape);
+      }
+
+      self.updateDrilldownOverlay(oldParent);
+      self.updateDrilldownOverlay(newParent);
+      self.updateDrilldownOverlay(shape);
+    }, true);
+
+
+  this.reverted([ 'shape.create', 'shape.move', 'shape.delete' ], LOW_PRIORITY,
+    function(context) {
+      var oldParent = context.oldParent,
+          newParent = context.newParent || context.parent,
+          shape = context.shape;
+
+      // Add overlay to the collapsed shape
+      if (self.canDrillDown(shape)) {
+        self.addOverlay(shape);
+      }
+
+      self.updateDrilldownOverlay(oldParent);
+      self.updateDrilldownOverlay(newParent);
+      self.updateDrilldownOverlay(shape);
+    }, true);
+
+
+  eventBus.on('import.render.complete', function() {
+    elementRegistry.filter(function(e) {
+      return self.canDrillDown(e);
+    }).map(function(el) {
+      self.addOverlay(el);
+    });
+  });
+
+}
+
+inherits(DrilldownOverlayBehavior, CommandInterceptor);
+
+DrilldownOverlayBehavior.prototype.updateDrilldownOverlay = function(shape) {
+  var canvas = this._canvas;
+
+  if (!shape) {
+    return;
+  }
+
+  var root = canvas.findRoot(shape);
+  if (root) {
+    this.updateOverlayVisibility(root);
+  }
+};
+
+
+DrilldownOverlayBehavior.prototype.canDrillDown = function(element) {
+  var canvas = this._canvas;
+  return is(element, 'bpmn:SubProcess') && canvas.findRoot(getPlaneIdFromShape(element));
+};
+
+/**
+ * Updates visibility of the drilldown overlay. If the plane has no elements,
+ * the drilldown will be only shown when the element is selected.
+ *
+ * @param {djs.model.Shape|djs.model.Root} element collapsed shape or root element
+ */
+DrilldownOverlayBehavior.prototype.updateOverlayVisibility = function(element) {
+  var overlays = this._overlays;
+
+  var bo = element.businessObject;
+
+  var overlay = overlays.get({ element: bo.id, type: 'drilldown' })[0];
+
+  if (!overlay) {
+    return;
+  }
+
+  var hasContent = bo && bo.flowElements && bo.flowElements.length;
+  classes(overlay.html).toggle(EMPTY_MARKER, !hasContent);
+};
+
+/**
+ * Attaches a drilldown button to the given element. We assume that the plane has
+ * the same id as the element.
+ *
+ * @param {djs.model.Shape} element collapsed shape
+ */
+DrilldownOverlayBehavior.prototype.addOverlay = function(element) {
+  var canvas = this._canvas;
+  var overlays = this._overlays;
+
+  var existingOverlays = overlays.get({ element: element, type: 'drilldown' });
+  if (existingOverlays.length) {
+    this.removeOverlay(element);
+  }
+
+  var button = domify('<button class="bjs-drilldown">' + ARROW_DOWN_SVG + '</button>');
+
+  button.addEventListener('click', function() {
+    canvas.setRootElement(canvas.findRoot(getPlaneIdFromShape(element)));
+  });
+
+  overlays.add(element, 'drilldown', {
+    position: {
+      bottom: -7,
+      right: -8
+    },
+    html: button
+  });
+
+  this.updateOverlayVisibility(element);
+};
+
+DrilldownOverlayBehavior.prototype.removeOverlay = function(element) {
+  var overlays = this._overlays;
+
+  overlays.remove({
+    element: element,
+    type: 'drilldown'
+  });
+};
+
+DrilldownOverlayBehavior.$inject = [
+  'canvas',
+  'eventBus',
+  'elementRegistry',
+  'overlays'
+];

+ 218 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/SubprocessCompatibility.js

@@ -0,0 +1,218 @@
+
+import { asBounds, asTRBL } from 'diagram-js/lib/layout/LayoutUtil';
+import { is, isAny } from '../../util/ModelUtil';
+
+var DEFAULT_POSITION = {
+  x: 180,
+  y: 160
+};
+
+/**
+ * Hook into `import.render.start` and create new planes for diagrams with
+ * collapsed subprocesses and all dis on the same plane.
+ *
+ * @param {eventBus} eventBus
+ * @param {moddle} moddle
+ */
+export default function SubprocessCompatibility(eventBus, moddle) {
+  this._eventBus = eventBus;
+  this._moddle = moddle;
+
+  var self = this;
+
+  eventBus.on('import.render.start', 1500, function(e, context) {
+    self.handleImport(context.definitions);
+  });
+}
+
+SubprocessCompatibility.prototype.handleImport = function(definitions) {
+  if (!definitions.diagrams) {
+    return;
+  }
+
+  var self = this;
+  this._definitions = definitions;
+  this._processToDiagramMap = {};
+
+  definitions.diagrams.forEach(function(diagram) {
+    if (!diagram.plane || !diagram.plane.bpmnElement) {
+      return;
+    }
+
+    self._processToDiagramMap[diagram.plane.bpmnElement.id] = diagram;
+  });
+
+  var newDiagrams = [];
+  definitions.diagrams.forEach(function(diagram) {
+    var createdDiagrams = self.createNewDiagrams(diagram.plane);
+    Array.prototype.push.apply(newDiagrams, createdDiagrams);
+  });
+
+  newDiagrams.forEach(function(diagram) {
+    self.movePlaneElementsToOrigin(diagram.plane);
+  });
+};
+
+
+/**
+ * Moves all DI elements from collapsed subprocesses to a new plane.
+ *
+ * @param {Object} plane
+ * @return {Array} new diagrams created for the collapsed subprocesses
+ */
+SubprocessCompatibility.prototype.createNewDiagrams = function(plane) {
+  var self = this;
+
+  var collapsedElements = [];
+  var elementsToMove = [];
+
+  plane.get('planeElement').forEach(function(diElement) {
+    var bo = diElement.bpmnElement;
+
+    if (!bo) {
+      return;
+    }
+
+    var parent = bo.$parent;
+
+    if (is(bo, 'bpmn:SubProcess') && !diElement.isExpanded) {
+      collapsedElements.push(bo);
+    }
+
+    if (shouldMoveToPlane(bo, plane)) {
+
+      // don't change the array while we iterate over it
+      elementsToMove.push({ diElement: diElement, parent: parent });
+    }
+  });
+
+  var newDiagrams = [];
+
+  // create new planes for all collapsed subprocesses, even when they are empty
+  collapsedElements.forEach(function(element) {
+    if (!self._processToDiagramMap[element.id]) {
+      var diagram = self.createDiagram(element);
+      self._processToDiagramMap[element.id] = diagram;
+      newDiagrams.push(diagram);
+    }
+  });
+
+  elementsToMove.forEach(function(element) {
+    var diElement = element.diElement;
+    var parent = element.parent;
+
+    // parent is expanded, get nearest collapsed parent
+    while (parent && collapsedElements.indexOf(parent) === -1) {
+      parent = parent.$parent;
+    }
+
+    // false positive, all parents are expanded
+    if (!parent) {
+      return;
+    }
+
+    var diagram = self._processToDiagramMap[parent.id];
+    self.moveToDiPlane(diElement, diagram.plane);
+  });
+
+  return newDiagrams;
+};
+
+SubprocessCompatibility.prototype.movePlaneElementsToOrigin = function(plane) {
+  var elements = plane.get('planeElement');
+
+  // get bounding box of all elements
+  var planeBounds = getPlaneBounds(plane);
+
+  var offset = {
+    x: planeBounds.x - DEFAULT_POSITION.x,
+    y: planeBounds.y - DEFAULT_POSITION.y
+  };
+
+  elements.forEach(function(diElement) {
+    if (diElement.waypoint) {
+      diElement.waypoint.forEach(function(waypoint) {
+        waypoint.x = waypoint.x - offset.x;
+        waypoint.y = waypoint.y - offset.y;
+      });
+    } else if (diElement.bounds) {
+      diElement.bounds.x = diElement.bounds.x - offset.x;
+      diElement.bounds.y = diElement.bounds.y - offset.y;
+    }
+  });
+};
+
+
+SubprocessCompatibility.prototype.moveToDiPlane = function(diElement, newPlane) {
+  var containingDiagram = findRootDiagram(diElement);
+
+  // remove DI from old Plane and add it to the new one
+  var parentPlaneElement = containingDiagram.plane.get('planeElement');
+  parentPlaneElement.splice(parentPlaneElement.indexOf(diElement), 1);
+  newPlane.get('planeElement').push(diElement);
+};
+
+
+SubprocessCompatibility.prototype.createDiagram = function(bo) {
+  var plane = this._moddle.create('bpmndi:BPMNPlane', { bpmnElement: bo });
+  var diagram = this._moddle.create('bpmndi:BPMNDiagram', {
+    plane: plane
+  });
+  plane.$parent = diagram;
+  plane.bpmnElement = bo;
+  diagram.$parent = this._definitions;
+  this._definitions.diagrams.push(diagram);
+  return diagram;
+};
+
+SubprocessCompatibility.$inject = [ 'eventBus', 'moddle' ];
+
+
+// helpers //////////////////////////
+
+function findRootDiagram(element) {
+  if (is(element, 'bpmndi:BPMNDiagram')) {
+    return element;
+  } else {
+    return findRootDiagram(element.$parent);
+  }
+}
+
+function getPlaneBounds(plane) {
+  var planeTrbl = {
+    top: Infinity,
+    right: -Infinity,
+    bottom: -Infinity,
+    left: Infinity
+  };
+
+  plane.planeElement.forEach(function(element) {
+    if (!element.bounds) {
+      return;
+    }
+
+    var trbl = asTRBL(element.bounds);
+
+    planeTrbl.top = Math.min(trbl.top, planeTrbl.top);
+    planeTrbl.left = Math.min(trbl.left, planeTrbl.left);
+  });
+
+  return asBounds(planeTrbl);
+}
+
+function shouldMoveToPlane(bo, plane) {
+  var parent = bo.$parent;
+
+  // don't move elements that are already on the plane
+  if (!is(parent, 'bpmn:SubProcess') || parent === plane.bpmnElement) {
+    return false;
+  }
+
+  // dataAssociations are children of the subprocess but rendered on process level
+  // cf. https://github.com/bpmn-io/bpmn-js/issues/1619
+  if (isAny(bo, [ 'bpmn:DataInputAssociation', 'bpmn:DataOutputAssociation' ])) {
+    return false;
+  }
+
+  return true;
+}

+ 17 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/drilldown/index.js

@@ -0,0 +1,17 @@
+import OverlaysModule from 'diagram-js/lib/features/overlays';
+import ChangeSupportModule from 'diagram-js/lib/features/change-support';
+import RootElementsModule from 'diagram-js/lib/features/root-elements';
+
+import DrilldownBreadcrumbs from './DrilldownBreadcrumbs';
+import DrilldownCentering from './DrilldownCentering';
+import SubprocessCompatibility from './SubprocessCompatibility';
+import DrilldownOverlayBehavior from './DrilldownOverlayBehavior';
+
+export default {
+  __depends__: [ OverlaysModule, ChangeSupportModule, RootElementsModule ],
+  __init__: [ 'drilldownBreadcrumbs', 'drilldownOverlayBehavior', 'drilldownCentering', 'subprocessCompatibility' ],
+  drilldownBreadcrumbs: [ 'type', DrilldownBreadcrumbs ],
+  drilldownCentering: [ 'type', DrilldownCentering ],
+  drilldownOverlayBehavior: [ 'type', DrilldownOverlayBehavior ],
+  subprocessCompatibility: [ 'type', SubprocessCompatibility ]
+};

+ 177 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/editor-actions/BpmnEditorActions.js

@@ -0,0 +1,177 @@
+import inherits from 'inherits-browser';
+
+import EditorActions from 'diagram-js/lib/features/editor-actions/EditorActions';
+
+import { filter } from 'min-dash';
+
+import { is } from '../../util/ModelUtil';
+
+import {
+  getBBox
+} from 'diagram-js/lib/util/Elements';
+
+
+/**
+ * Registers and executes BPMN specific editor actions.
+ *
+ * @param {Injector} injector
+ */
+export default function BpmnEditorActions(injector) {
+  injector.invoke(EditorActions, this);
+}
+
+inherits(BpmnEditorActions, EditorActions);
+
+BpmnEditorActions.$inject = [
+  'injector'
+];
+
+/**
+ * Register default actions.
+ *
+ * @param {Injector} injector
+ */
+BpmnEditorActions.prototype._registerDefaultActions = function(injector) {
+
+  // (0) invoke super method
+
+  EditorActions.prototype._registerDefaultActions.call(this, injector);
+
+  // (1) retrieve optional components to integrate with
+
+  var canvas = injector.get('canvas', false);
+  var elementRegistry = injector.get('elementRegistry', false);
+  var selection = injector.get('selection', false);
+  var spaceTool = injector.get('spaceTool', false);
+  var lassoTool = injector.get('lassoTool', false);
+  var handTool = injector.get('handTool', false);
+  var globalConnect = injector.get('globalConnect', false);
+  var distributeElements = injector.get('distributeElements', false);
+  var alignElements = injector.get('alignElements', false);
+  var directEditing = injector.get('directEditing', false);
+  var searchPad = injector.get('searchPad', false);
+  var modeling = injector.get('modeling', false);
+
+  // (2) check components and register actions
+
+  if (canvas && elementRegistry && selection) {
+    this._registerAction('selectElements', function() {
+
+      // select all elements except for the invisible
+      // root element
+      var rootElement = canvas.getRootElement();
+
+      var elements = elementRegistry.filter(function(element) {
+        return element !== rootElement;
+      });
+
+      selection.select(elements);
+
+      return elements;
+    });
+  }
+
+  if (spaceTool) {
+    this._registerAction('spaceTool', function() {
+      spaceTool.toggle();
+    });
+  }
+
+  if (lassoTool) {
+    this._registerAction('lassoTool', function() {
+      lassoTool.toggle();
+    });
+  }
+
+  if (handTool) {
+    this._registerAction('handTool', function() {
+      handTool.toggle();
+    });
+  }
+
+  if (globalConnect) {
+    this._registerAction('globalConnectTool', function() {
+      globalConnect.toggle();
+    });
+  }
+
+  if (selection && distributeElements) {
+    this._registerAction('distributeElements', function(opts) {
+      var currentSelection = selection.get(),
+          type = opts.type;
+
+      if (currentSelection.length) {
+        distributeElements.trigger(currentSelection, type);
+      }
+    });
+  }
+
+  if (selection && alignElements) {
+    this._registerAction('alignElements', function(opts) {
+      var currentSelection = selection.get(),
+          aligneableElements = [],
+          type = opts.type;
+
+      if (currentSelection.length) {
+        aligneableElements = filter(currentSelection, function(element) {
+          return !is(element, 'bpmn:Lane');
+        });
+
+        alignElements.trigger(aligneableElements, type);
+      }
+    });
+  }
+
+  if (selection && modeling) {
+    this._registerAction('setColor', function(opts) {
+      var currentSelection = selection.get();
+
+      if (currentSelection.length) {
+        modeling.setColor(currentSelection, opts);
+      }
+    });
+  }
+
+  if (selection && directEditing) {
+    this._registerAction('directEditing', function() {
+      var currentSelection = selection.get();
+
+      if (currentSelection.length) {
+        directEditing.activate(currentSelection[0]);
+      }
+    });
+  }
+
+  if (searchPad) {
+    this._registerAction('find', function() {
+      searchPad.toggle();
+    });
+  }
+
+  if (canvas && modeling) {
+    this._registerAction('moveToOrigin', function() {
+      var rootElement = canvas.getRootElement(),
+          boundingBox,
+          elements;
+
+      if (is(rootElement, 'bpmn:Collaboration')) {
+        elements = elementRegistry.filter(function(element) {
+          return is(element.parent, 'bpmn:Collaboration');
+        });
+      } else {
+        elements = elementRegistry.filter(function(element) {
+          return element !== rootElement && !is(element.parent, 'bpmn:SubProcess');
+        });
+      }
+
+      boundingBox = getBBox(elements);
+
+      modeling.moveElements(
+        elements,
+        { x: -boundingBox.x, y: -boundingBox.y },
+        rootElement
+      );
+    });
+  }
+
+};

+ 10 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/editor-actions/index.js

@@ -0,0 +1,10 @@
+import EditorActionsModule from 'diagram-js/lib/features/editor-actions';
+
+import BpmnEditorActions from './BpmnEditorActions';
+
+export default {
+  __depends__: [
+    EditorActionsModule
+  ],
+  editorActions: [ 'type', BpmnEditorActions ]
+};

+ 25 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/BpmnGridSnapping.js

@@ -0,0 +1,25 @@
+import { isAny } from '../modeling/util/ModelingUtil';
+
+export default function BpmnGridSnapping(eventBus) {
+  eventBus.on([
+    'create.init',
+    'shape.move.init'
+  ], function(event) {
+    var context = event.context,
+        shape = event.shape;
+
+    if (isAny(shape, [
+      'bpmn:Participant',
+      'bpmn:SubProcess',
+      'bpmn:TextAnnotation'
+    ])) {
+      if (!context.gridSnappingContext) {
+        context.gridSnappingContext = {};
+      }
+
+      context.gridSnappingContext.snapLocation = 'top-left';
+    }
+  });
+}
+
+BpmnGridSnapping.$inject = [ 'eventBus' ];

+ 59 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/behavior/GridSnappingAutoPlaceBehavior.js

@@ -0,0 +1,59 @@
+import { getNewShapePosition } from '../../auto-place/BpmnAutoPlaceUtil';
+
+import { getMid } from 'diagram-js/lib/layout/LayoutUtil';
+import { is } from '../../../util/ModelUtil';
+
+var HIGH_PRIORITY = 2000;
+
+
+export default function GridSnappingAutoPlaceBehavior(eventBus, gridSnapping) {
+  eventBus.on('autoPlace', HIGH_PRIORITY, function(context) {
+    var source = context.source,
+        sourceMid = getMid(source),
+        shape = context.shape;
+
+    var position = getNewShapePosition(source, shape);
+
+    [ 'x', 'y' ].forEach(function(axis) {
+      var options = {};
+
+      // do not snap if x/y equal
+      if (position[ axis ] === sourceMid[ axis ]) {
+        return;
+      }
+
+      if (position[ axis ] > sourceMid[ axis ]) {
+        options.min = position[ axis ];
+      } else {
+        options.max = position[ axis ];
+      }
+
+      if (is(shape, 'bpmn:TextAnnotation')) {
+
+        if (isHorizontal(axis)) {
+          options.offset = -shape.width / 2;
+        } else {
+          options.offset = -shape.height / 2;
+        }
+
+      }
+
+      position[ axis ] = gridSnapping.snapValue(position[ axis ], options);
+
+    });
+
+    // must be returned to be considered by auto place
+    return position;
+  });
+}
+
+GridSnappingAutoPlaceBehavior.$inject = [
+  'eventBus',
+  'gridSnapping'
+];
+
+// helpers //////////
+
+function isHorizontal(axis) {
+  return axis === 'x';
+}

+ 144 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/behavior/GridSnappingLayoutConnectionBehavior.js

@@ -0,0 +1,144 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { pointsAligned } from 'diagram-js/lib/util/Geometry';
+
+import {
+  assign
+} from 'min-dash';
+
+var HIGH_PRIORITY = 3000;
+
+
+/**
+ * Snaps connections with Manhattan layout.
+ */
+export default function GridSnappingLayoutConnectionBehavior(eventBus, gridSnapping, modeling) {
+  CommandInterceptor.call(this, eventBus);
+
+  this._gridSnapping = gridSnapping;
+
+  var self = this;
+
+  this.postExecuted([
+    'connection.create',
+    'connection.layout'
+  ], HIGH_PRIORITY, function(event) {
+    var context = event.context,
+        connection = context.connection,
+        hints = context.hints || {},
+        waypoints = connection.waypoints;
+
+    if (hints.connectionStart || hints.connectionEnd || hints.createElementsBehavior === false) {
+      return;
+    }
+
+    if (!hasMiddleSegments(waypoints)) {
+      return;
+    }
+
+    modeling.updateWaypoints(connection, self.snapMiddleSegments(waypoints));
+  });
+}
+
+GridSnappingLayoutConnectionBehavior.$inject = [
+  'eventBus',
+  'gridSnapping',
+  'modeling'
+];
+
+inherits(GridSnappingLayoutConnectionBehavior, CommandInterceptor);
+
+/**
+ * Snap middle segments of a given connection.
+ *
+ * @param {Array<Point>} waypoints
+ *
+ * @returns {Array<Point>}
+ */
+GridSnappingLayoutConnectionBehavior.prototype.snapMiddleSegments = function(waypoints) {
+  var gridSnapping = this._gridSnapping,
+      snapped;
+
+  waypoints = waypoints.slice();
+
+  for (var i = 1; i < waypoints.length - 2; i++) {
+
+    snapped = snapSegment(gridSnapping, waypoints[i], waypoints[i + 1]);
+
+    waypoints[i] = snapped[0];
+    waypoints[i + 1] = snapped[1];
+  }
+
+  return waypoints;
+};
+
+
+// helpers //////////
+
+/**
+ * Check whether a connection has a middle segments.
+ *
+ * @param {Array} waypoints
+ *
+ * @returns {boolean}
+ */
+function hasMiddleSegments(waypoints) {
+  return waypoints.length > 3;
+}
+
+/**
+ * Check whether an alignment is horizontal.
+ *
+ * @param {string} aligned
+ *
+ * @returns {boolean}
+ */
+function horizontallyAligned(aligned) {
+  return aligned === 'h';
+}
+
+/**
+ * Check whether an alignment is vertical.
+ *
+ * @param {string} aligned
+ *
+ * @returns {boolean}
+ */
+function verticallyAligned(aligned) {
+  return aligned === 'v';
+}
+
+/**
+ * Get middle segments from a given connection.
+ *
+ * @param {Array} waypoints
+ *
+ * @returns {Array}
+ */
+function snapSegment(gridSnapping, segmentStart, segmentEnd) {
+
+  var aligned = pointsAligned(segmentStart, segmentEnd);
+
+  var snapped = {};
+
+  if (horizontallyAligned(aligned)) {
+
+    // snap horizontally
+    snapped.y = gridSnapping.snapValue(segmentStart.y);
+  }
+
+  if (verticallyAligned(aligned)) {
+
+    // snap vertically
+    snapped.x = gridSnapping.snapValue(segmentStart.x);
+  }
+
+  if ('x' in snapped || 'y' in snapped) {
+    segmentStart = assign({}, segmentStart, snapped);
+    segmentEnd = assign({}, segmentEnd, snapped);
+  }
+
+  return [ segmentStart, segmentEnd ];
+}

+ 36 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/behavior/GridSnappingParticipantBehavior.js

@@ -0,0 +1,36 @@
+import { is } from '../../../util/ModelUtil';
+
+var HIGHER_PRIORITY = 1750;
+
+
+export default function GridSnappingParticipantBehavior(canvas, eventBus, gridSnapping) {
+  eventBus.on([
+    'create.start',
+    'shape.move.start'
+  ], HIGHER_PRIORITY, function(event) {
+    var context = event.context,
+        shape = context.shape,
+        rootElement = canvas.getRootElement();
+
+    if (!is(shape, 'bpmn:Participant') ||
+      !is(rootElement, 'bpmn:Process') ||
+      !rootElement.children.length) {
+      return;
+    }
+
+    var createConstraints = context.createConstraints;
+
+    if (!createConstraints) {
+      return;
+    }
+
+    shape.width = gridSnapping.snapValue(shape.width, { min: shape.width });
+    shape.height = gridSnapping.snapValue(shape.height, { min: shape.height });
+  });
+}
+
+GridSnappingParticipantBehavior.$inject = [
+  'canvas',
+  'eventBus',
+  'gridSnapping'
+];

+ 14 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/behavior/index.js

@@ -0,0 +1,14 @@
+import GridSnappingAutoPlaceBehavior from './GridSnappingAutoPlaceBehavior';
+import GridSnappingParticipantBehavior from './GridSnappingParticipantBehavior';
+import GridSnappingLayoutConnectionBehavior from './GridSnappingLayoutConnectionBehavior';
+
+export default {
+  __init__: [
+    'gridSnappingAutoPlaceBehavior',
+    'gridSnappingParticipantBehavior',
+    'gridSnappingLayoutConnectionBehavior',
+  ],
+  gridSnappingAutoPlaceBehavior: [ 'type', GridSnappingAutoPlaceBehavior ],
+  gridSnappingParticipantBehavior: [ 'type', GridSnappingParticipantBehavior ],
+  gridSnappingLayoutConnectionBehavior: [ 'type', GridSnappingLayoutConnectionBehavior ]
+};

+ 13 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/grid-snapping/index.js

@@ -0,0 +1,13 @@
+import BpmnGridSnapping from './BpmnGridSnapping';
+import GridSnappingModule from 'diagram-js/lib/features/grid-snapping';
+
+import GridSnappingBehaviorModule from './behavior';
+
+export default {
+  __depends__: [
+    GridSnappingModule,
+    GridSnappingBehaviorModule
+  ],
+  __init__: [ 'bpmnGridSnapping' ],
+  bpmnGridSnapping: [ 'type', BpmnGridSnapping ]
+};

+ 118 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/interaction-events/BpmnInteractionEvents.js

@@ -0,0 +1,118 @@
+import { is } from '../../util/ModelUtil';
+
+import { isExpanded } from '../../util/DiUtil';
+
+var LABEL_WIDTH = 30,
+    LABEL_HEIGHT = 30;
+
+
+/**
+ * BPMN-specific hit zones and interaction fixes.
+ *
+ * @param {EventBus} eventBus
+ * @param {InteractionEvents} interactionEvents
+ */
+export default function BpmnInteractionEvents(eventBus, interactionEvents) {
+
+  this._interactionEvents = interactionEvents;
+
+  var self = this;
+
+  eventBus.on([
+    'interactionEvents.createHit',
+    'interactionEvents.updateHit'
+  ], function(context) {
+    var element = context.element,
+        gfx = context.gfx;
+
+    if (is(element, 'bpmn:Lane')) {
+      return self.createParticipantHit(element, gfx);
+    } else
+
+    if (is(element, 'bpmn:Participant')) {
+      if (isExpanded(element)) {
+        return self.createParticipantHit(element, gfx);
+      } else {
+        return self.createDefaultHit(element, gfx);
+      }
+    } else
+
+    if (is(element, 'bpmn:SubProcess')) {
+      if (isExpanded(element)) {
+        return self.createSubProcessHit(element, gfx);
+      } else {
+        return self.createDefaultHit(element, gfx);
+      }
+    }
+  });
+
+}
+
+BpmnInteractionEvents.$inject = [
+  'eventBus',
+  'interactionEvents'
+];
+
+
+BpmnInteractionEvents.prototype.createDefaultHit = function(element, gfx) {
+  this._interactionEvents.removeHits(gfx);
+
+  this._interactionEvents.createDefaultHit(element, gfx);
+
+  // indicate that we created a hit
+  return true;
+};
+
+BpmnInteractionEvents.prototype.createParticipantHit = function(element, gfx) {
+
+  // remove existing hits
+  this._interactionEvents.removeHits(gfx);
+
+  // add body hit
+  this._interactionEvents.createBoxHit(gfx, 'no-move', {
+    width: element.width,
+    height: element.height
+  });
+
+  // add outline hit
+  this._interactionEvents.createBoxHit(gfx, 'click-stroke', {
+    width: element.width,
+    height: element.height
+  });
+
+  // add label hit
+  this._interactionEvents.createBoxHit(gfx, 'all', {
+    width: LABEL_WIDTH,
+    height: element.height
+  });
+
+  // indicate that we created a hit
+  return true;
+};
+
+BpmnInteractionEvents.prototype.createSubProcessHit = function(element, gfx) {
+
+  // remove existing hits
+  this._interactionEvents.removeHits(gfx);
+
+  // add body hit
+  this._interactionEvents.createBoxHit(gfx, 'no-move', {
+    width: element.width,
+    height: element.height
+  });
+
+  // add outline hit
+  this._interactionEvents.createBoxHit(gfx, 'click-stroke', {
+    width: element.width,
+    height: element.height
+  });
+
+  // add label hit
+  this._interactionEvents.createBoxHit(gfx, 'all', {
+    width: element.width,
+    height: LABEL_HEIGHT
+  });
+
+  // indicate that we created a hit
+  return true;
+};

+ 6 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/interaction-events/index.js

@@ -0,0 +1,6 @@
+import BpmnInteractionEvents from './BpmnInteractionEvents';
+
+export default {
+  __init__: [ 'bpmnInteractionEvents' ],
+  bpmnInteractionEvents: [ 'type', BpmnInteractionEvents ]
+};

+ 158 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/keyboard/BpmnKeyboardBindings.js

@@ -0,0 +1,158 @@
+import inherits from 'inherits-browser';
+
+import KeyboardBindings from 'diagram-js/lib/features/keyboard/KeyboardBindings';
+
+
+/**
+ * BPMN 2.0 specific keyboard bindings.
+ *
+ * @param {Injector} injector
+ */
+export default function BpmnKeyboardBindings(injector) {
+  injector.invoke(KeyboardBindings, this);
+}
+
+inherits(BpmnKeyboardBindings, KeyboardBindings);
+
+BpmnKeyboardBindings.$inject = [
+  'injector'
+];
+
+
+/**
+ * Register available keyboard bindings.
+ *
+ * @param {Keyboard} keyboard
+ * @param {EditorActions} editorActions
+ */
+BpmnKeyboardBindings.prototype.registerBindings = function(keyboard, editorActions) {
+
+  // inherit default bindings
+  KeyboardBindings.prototype.registerBindings.call(this, keyboard, editorActions);
+
+  /**
+   * Add keyboard binding if respective editor action
+   * is registered.
+   *
+   * @param {string} action name
+   * @param {Function} fn that implements the key binding
+   */
+  function addListener(action, fn) {
+
+    if (editorActions.isRegistered(action)) {
+      keyboard.addListener(fn);
+    }
+  }
+
+  // select all elements
+  // CTRL + A
+  addListener('selectElements', function(context) {
+
+    var event = context.keyEvent;
+
+    if (keyboard.isKey([ 'a', 'A' ], event) && keyboard.isCmd(event)) {
+      editorActions.trigger('selectElements');
+
+      return true;
+    }
+  });
+
+  // search labels
+  // CTRL + F
+  addListener('find', function(context) {
+
+    var event = context.keyEvent;
+
+    if (keyboard.isKey([ 'f', 'F' ], event) && keyboard.isCmd(event)) {
+      editorActions.trigger('find');
+
+      return true;
+    }
+  });
+
+  // activate space tool
+  // S
+  addListener('spaceTool', function(context) {
+
+    var event = context.keyEvent;
+
+    if (keyboard.hasModifier(event)) {
+      return;
+    }
+
+    if (keyboard.isKey([ 's', 'S' ], event)) {
+      editorActions.trigger('spaceTool');
+
+      return true;
+    }
+  });
+
+  // activate lasso tool
+  // L
+  addListener('lassoTool', function(context) {
+
+    var event = context.keyEvent;
+
+    if (keyboard.hasModifier(event)) {
+      return;
+    }
+
+    if (keyboard.isKey([ 'l', 'L' ], event)) {
+      editorActions.trigger('lassoTool');
+
+      return true;
+    }
+  });
+
+  // activate hand tool
+  // H
+  addListener('handTool', function(context) {
+
+    var event = context.keyEvent;
+
+    if (keyboard.hasModifier(event)) {
+      return;
+    }
+
+    if (keyboard.isKey([ 'h', 'H' ], event)) {
+      editorActions.trigger('handTool');
+
+      return true;
+    }
+  });
+
+  // activate global connect tool
+  // C
+  addListener('globalConnectTool', function(context) {
+
+    var event = context.keyEvent;
+
+    if (keyboard.hasModifier(event)) {
+      return;
+    }
+
+    if (keyboard.isKey([ 'c', 'C' ], event)) {
+      editorActions.trigger('globalConnectTool');
+
+      return true;
+    }
+  });
+
+  // activate direct editing
+  // E
+  addListener('directEditing', function(context) {
+
+    var event = context.keyEvent;
+
+    if (keyboard.hasModifier(event)) {
+      return;
+    }
+
+    if (keyboard.isKey([ 'e', 'E' ], event)) {
+      editorActions.trigger('directEditing');
+
+      return true;
+    }
+  });
+
+};

+ 11 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/keyboard/index.js

@@ -0,0 +1,11 @@
+import KeyboardModule from 'diagram-js/lib/features/keyboard';
+
+import BpmnKeyboardBindings from './BpmnKeyboardBindings';
+
+export default {
+  __depends__: [
+    KeyboardModule
+  ],
+  __init__: [ 'keyboardBindings' ],
+  keyboardBindings: [ 'type', BpmnKeyboardBindings ]
+};

+ 138 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/LabelEditingPreview.js

@@ -0,0 +1,138 @@
+import {
+  append as svgAppend,
+  attr as svgAttr,
+  create as svgCreate,
+  remove as svgRemove
+} from 'tiny-svg';
+
+import {
+  getDi,
+  is
+} from '../../util/ModelUtil';
+
+import {
+  translate
+} from 'diagram-js/lib/util/SvgTransformUtil';
+
+var MARKER_HIDDEN = 'djs-element-hidden',
+    MARKER_LABEL_HIDDEN = 'djs-label-hidden';
+
+
+export default function LabelEditingPreview(
+    eventBus, canvas, elementRegistry,
+    pathMap) {
+
+  var self = this;
+
+  var defaultLayer = canvas.getDefaultLayer();
+
+  var element, absoluteElementBBox, gfx;
+
+  eventBus.on('directEditing.activate', function(context) {
+    var activeProvider = context.active;
+
+    element = activeProvider.element.label || activeProvider.element;
+
+    // text annotation
+    if (is(element, 'bpmn:TextAnnotation')) {
+      absoluteElementBBox = canvas.getAbsoluteBBox(element);
+
+      gfx = svgCreate('g');
+
+      var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: element.height,
+        position: {
+          mx: 0.0,
+          my: 0.0
+        }
+      });
+
+      var path = self.path = svgCreate('path');
+
+      svgAttr(path, {
+        d: textPathData,
+        strokeWidth: 2,
+        stroke: getStrokeColor(element)
+      });
+
+      svgAppend(gfx, path);
+
+      svgAppend(defaultLayer, gfx);
+
+      translate(gfx, element.x, element.y);
+    }
+
+    if (is(element, 'bpmn:TextAnnotation') ||
+        element.labelTarget) {
+      canvas.addMarker(element, MARKER_HIDDEN);
+    } else if (is(element, 'bpmn:Task') ||
+               is(element, 'bpmn:CallActivity') ||
+               is(element, 'bpmn:SubProcess') ||
+               is(element, 'bpmn:Participant')) {
+      canvas.addMarker(element, MARKER_LABEL_HIDDEN);
+    }
+  });
+
+  eventBus.on('directEditing.resize', function(context) {
+
+    // text annotation
+    if (is(element, 'bpmn:TextAnnotation')) {
+      var height = context.height,
+          dy = context.dy;
+
+      var newElementHeight = Math.max(element.height / absoluteElementBBox.height * (height + dy), 0);
+
+      var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
+        xScaleFactor: 1,
+        yScaleFactor: 1,
+        containerWidth: element.width,
+        containerHeight: newElementHeight,
+        position: {
+          mx: 0.0,
+          my: 0.0
+        }
+      });
+
+      svgAttr(self.path, {
+        d: textPathData
+      });
+    }
+  });
+
+  eventBus.on([ 'directEditing.complete', 'directEditing.cancel' ], function(context) {
+    var activeProvider = context.active;
+
+    if (activeProvider) {
+      canvas.removeMarker(activeProvider.element.label || activeProvider.element, MARKER_HIDDEN);
+      canvas.removeMarker(element, MARKER_LABEL_HIDDEN);
+    }
+
+    element = undefined;
+    absoluteElementBBox = undefined;
+
+    if (gfx) {
+      svgRemove(gfx);
+
+      gfx = undefined;
+    }
+  });
+}
+
+LabelEditingPreview.$inject = [
+  'eventBus',
+  'canvas',
+  'elementRegistry',
+  'pathMap'
+];
+
+
+// helpers ///////////////////
+
+function getStrokeColor(element, defaultColor) {
+  var di = getDi(element);
+
+  return di.get('stroke') || defaultColor || 'black';
+}

+ 426 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/LabelEditingProvider.js

@@ -0,0 +1,426 @@
+import {
+  assign
+} from 'min-dash';
+
+import {
+  getLabel
+} from './LabelUtil';
+
+import {
+  is
+} from '../../util/ModelUtil';
+
+import { isAny } from '../modeling/util/ModelingUtil';
+import { isExpanded } from '../../util/DiUtil';
+
+import {
+  getExternalLabelMid,
+  isLabelExternal,
+  hasExternalLabel,
+  isLabel
+} from '../../util/LabelUtil';
+
+var HIGH_PRIORITY = 2000;
+
+
+export default function LabelEditingProvider(
+    eventBus, bpmnFactory, canvas, directEditing,
+    modeling, resizeHandles, textRenderer) {
+
+  this._bpmnFactory = bpmnFactory;
+  this._canvas = canvas;
+  this._modeling = modeling;
+  this._textRenderer = textRenderer;
+
+  directEditing.registerProvider(this);
+
+  // listen to dblclick on non-root elements
+  eventBus.on('element.dblclick', function(event) {
+    activateDirectEdit(event.element, true);
+  });
+
+  // complete on followup canvas operation
+  eventBus.on([
+    'autoPlace.start',
+    'canvas.viewbox.changing',
+    'drag.init',
+    'element.mousedown',
+    'popupMenu.open',
+    'root.set',
+    'selection.changed'
+  ], function(event) {
+
+    if (directEditing.isActive()) {
+      directEditing.complete();
+    }
+  });
+
+  eventBus.on([
+    'shape.remove',
+    'connection.remove'
+  ], HIGH_PRIORITY, function(event) {
+
+    if (directEditing.isActive(event.element)) {
+      directEditing.cancel();
+    }
+  });
+
+  // cancel on command stack changes
+  eventBus.on([ 'commandStack.changed' ], function(e) {
+    if (directEditing.isActive()) {
+      directEditing.cancel();
+    }
+  });
+
+
+  eventBus.on('directEditing.activate', function(event) {
+    resizeHandles.removeResizers();
+  });
+
+  eventBus.on('create.end', 500, function(event) {
+
+    var context = event.context,
+        element = context.shape,
+        canExecute = event.context.canExecute,
+        isTouch = event.isTouch;
+
+    // TODO(nikku): we need to find a way to support the
+    // direct editing on mobile devices; right now this will
+    // break for desworkflowediting on mobile devices
+    // as it breaks the user interaction workflow
+
+    // TODO(nre): we should temporarily focus the edited element
+    // here and release the focused viewport after the direct edit
+    // operation is finished
+    if (isTouch) {
+      return;
+    }
+
+    if (!canExecute) {
+      return;
+    }
+
+    if (context.hints && context.hints.createElementsBehavior === false) {
+      return;
+    }
+
+    activateDirectEdit(element);
+  });
+
+  eventBus.on('autoPlace.end', 500, function(event) {
+    activateDirectEdit(event.shape);
+  });
+
+
+  function activateDirectEdit(element, force) {
+    if (force ||
+        isAny(element, [ 'bpmn:Task', 'bpmn:TextAnnotation' ]) ||
+        isCollapsedSubProcess(element)) {
+
+      directEditing.activate(element);
+    }
+  }
+
+}
+
+LabelEditingProvider.$inject = [
+  'eventBus',
+  'bpmnFactory',
+  'canvas',
+  'directEditing',
+  'modeling',
+  'resizeHandles',
+  'textRenderer'
+];
+
+
+/**
+ * Activate direct editing for activities and text annotations.
+ *
+ * @param  {djs.model.Base} element
+ *
+ * @return {Object} an object with properties bounds (position and size), text and options
+ */
+LabelEditingProvider.prototype.activate = function(element) {
+
+  // text
+  var text = getLabel(element);
+
+  if (text === undefined) {
+    return;
+  }
+
+  var context = {
+    text: text
+  };
+
+  // bounds
+  var bounds = this.getEditingBBox(element);
+
+  assign(context, bounds);
+
+  var options = {};
+
+  // tasks
+  if (
+    isAny(element, [
+      'bpmn:Task',
+      'bpmn:Participant',
+      'bpmn:Lane',
+      'bpmn:CallActivity'
+    ]) ||
+    isCollapsedSubProcess(element)
+  ) {
+    assign(options, {
+      centerVertically: true
+    });
+  }
+
+  // external labels
+  if (isLabelExternal(element)) {
+    assign(options, {
+      autoResize: true
+    });
+  }
+
+  // text annotations
+  if (is(element, 'bpmn:TextAnnotation')) {
+    assign(options, {
+      resizable: true,
+      autoResize: true
+    });
+  }
+
+  assign(context, {
+    options: options
+  });
+
+  return context;
+};
+
+
+/**
+ * Get the editing bounding box based on the element's size and position
+ *
+ * @param  {djs.model.Base} element
+ *
+ * @return {Object} an object containing information about position
+ *                  and size (fixed or minimum and/or maximum)
+ */
+LabelEditingProvider.prototype.getEditingBBox = function(element) {
+  var canvas = this._canvas;
+
+  var target = element.label || element;
+
+  var bbox = canvas.getAbsoluteBBox(target);
+
+  var mid = {
+    x: bbox.x + bbox.width / 2,
+    y: bbox.y + bbox.height / 2
+  };
+
+  // default position
+  var bounds = { x: bbox.x, y: bbox.y };
+
+  var zoom = canvas.zoom();
+
+  var defaultStyle = this._textRenderer.getDefaultStyle(),
+      externalStyle = this._textRenderer.getExternalStyle();
+
+  // take zoom into account
+  var externalFontSize = externalStyle.fontSize * zoom,
+      externalLineHeight = externalStyle.lineHeight,
+      defaultFontSize = defaultStyle.fontSize * zoom,
+      defaultLineHeight = defaultStyle.lineHeight;
+
+  var style = {
+    fontFamily: this._textRenderer.getDefaultStyle().fontFamily,
+    fontWeight: this._textRenderer.getDefaultStyle().fontWeight
+  };
+
+  // adjust for expanded pools AND lanes
+  if (is(element, 'bpmn:Lane') || isExpandedPool(element)) {
+
+    assign(bounds, {
+      width: bbox.height,
+      height: 30 * zoom,
+      x: bbox.x - bbox.height / 2 + (15 * zoom),
+      y: mid.y - (30 * zoom) / 2
+    });
+
+    assign(style, {
+      fontSize: defaultFontSize + 'px',
+      lineHeight: defaultLineHeight,
+      paddingTop: (7 * zoom) + 'px',
+      paddingBottom: (7 * zoom) + 'px',
+      paddingLeft: (5 * zoom) + 'px',
+      paddingRight: (5 * zoom) + 'px',
+      transform: 'rotate(-90deg)'
+    });
+  }
+
+
+  // internal labels for tasks and collapsed call activities,
+  // sub processes and participants
+  if (isAny(element, [ 'bpmn:Task', 'bpmn:CallActivity' ]) ||
+      isCollapsedPool(element) ||
+      isCollapsedSubProcess(element)) {
+
+    assign(bounds, {
+      width: bbox.width,
+      height: bbox.height
+    });
+
+    assign(style, {
+      fontSize: defaultFontSize + 'px',
+      lineHeight: defaultLineHeight,
+      paddingTop: (7 * zoom) + 'px',
+      paddingBottom: (7 * zoom) + 'px',
+      paddingLeft: (5 * zoom) + 'px',
+      paddingRight: (5 * zoom) + 'px'
+    });
+  }
+
+
+  // internal labels for expanded sub processes
+  if (isExpandedSubProcess(element)) {
+    assign(bounds, {
+      width: bbox.width,
+      x: bbox.x
+    });
+
+    assign(style, {
+      fontSize: defaultFontSize + 'px',
+      lineHeight: defaultLineHeight,
+      paddingTop: (7 * zoom) + 'px',
+      paddingBottom: (7 * zoom) + 'px',
+      paddingLeft: (5 * zoom) + 'px',
+      paddingRight: (5 * zoom) + 'px'
+    });
+  }
+
+  var width = 90 * zoom,
+      paddingTop = 7 * zoom,
+      paddingBottom = 4 * zoom;
+
+  // external labels for events, data elements, gateways, groups and connections
+  if (target.labelTarget) {
+    assign(bounds, {
+      width: width,
+      height: bbox.height + paddingTop + paddingBottom,
+      x: mid.x - width / 2,
+      y: bbox.y - paddingTop
+    });
+
+    assign(style, {
+      fontSize: externalFontSize + 'px',
+      lineHeight: externalLineHeight,
+      paddingTop: paddingTop + 'px',
+      paddingBottom: paddingBottom + 'px'
+    });
+  }
+
+  // external label not yet created
+  if (isLabelExternal(target)
+      && !hasExternalLabel(target)
+      && !isLabel(target)) {
+
+    var externalLabelMid = getExternalLabelMid(element);
+
+    var absoluteBBox = canvas.getAbsoluteBBox({
+      x: externalLabelMid.x,
+      y: externalLabelMid.y,
+      width: 0,
+      height: 0
+    });
+
+    var height = externalFontSize + paddingTop + paddingBottom;
+
+    assign(bounds, {
+      width: width,
+      height: height,
+      x: absoluteBBox.x - width / 2,
+      y: absoluteBBox.y - height / 2
+    });
+
+    assign(style, {
+      fontSize: externalFontSize + 'px',
+      lineHeight: externalLineHeight,
+      paddingTop: paddingTop + 'px',
+      paddingBottom: paddingBottom + 'px'
+    });
+  }
+
+  // text annotations
+  if (is(element, 'bpmn:TextAnnotation')) {
+    assign(bounds, {
+      width: bbox.width,
+      height: bbox.height,
+      minWidth: 30 * zoom,
+      minHeight: 10 * zoom
+    });
+
+    assign(style, {
+      textAlign: 'left',
+      paddingTop: (5 * zoom) + 'px',
+      paddingBottom: (7 * zoom) + 'px',
+      paddingLeft: (7 * zoom) + 'px',
+      paddingRight: (5 * zoom) + 'px',
+      fontSize: defaultFontSize + 'px',
+      lineHeight: defaultLineHeight
+    });
+  }
+
+  return { bounds: bounds, style: style };
+};
+
+
+LabelEditingProvider.prototype.update = function(
+    element, newLabel,
+    activeContextText, bounds) {
+
+  var newBounds,
+      bbox;
+
+  if (is(element, 'bpmn:TextAnnotation')) {
+
+    bbox = this._canvas.getAbsoluteBBox(element);
+
+    newBounds = {
+      x: element.x,
+      y: element.y,
+      width: element.width / bbox.width * bounds.width,
+      height: element.height / bbox.height * bounds.height
+    };
+  }
+
+  if (isEmptyText(newLabel)) {
+    newLabel = null;
+  }
+
+  this._modeling.updateLabel(element, newLabel, newBounds);
+};
+
+
+
+// helpers //////////////////////
+
+function isCollapsedSubProcess(element) {
+  return is(element, 'bpmn:SubProcess') && !isExpanded(element);
+}
+
+function isExpandedSubProcess(element) {
+  return is(element, 'bpmn:SubProcess') && isExpanded(element);
+}
+
+function isCollapsedPool(element) {
+  return is(element, 'bpmn:Participant') && !isExpanded(element);
+}
+
+function isExpandedPool(element) {
+  return is(element, 'bpmn:Participant') && isExpanded(element);
+}
+
+function isEmptyText(label) {
+  return !label || !label.trim();
+}

+ 67 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/LabelUtil.js

@@ -0,0 +1,67 @@
+import { is } from '../../util/ModelUtil';
+
+function getLabelAttr(semantic) {
+  if (
+    is(semantic, 'bpmn:FlowElement') ||
+    is(semantic, 'bpmn:Participant') ||
+    is(semantic, 'bpmn:Lane') ||
+    is(semantic, 'bpmn:SequenceFlow') ||
+    is(semantic, 'bpmn:MessageFlow') ||
+    is(semantic, 'bpmn:DataInput') ||
+    is(semantic, 'bpmn:DataOutput')
+  ) {
+    return 'name';
+  }
+
+  if (is(semantic, 'bpmn:TextAnnotation')) {
+    return 'text';
+  }
+
+  if (is(semantic, 'bpmn:Group')) {
+    return 'categoryValueRef';
+  }
+}
+
+function getCategoryValue(semantic) {
+  var categoryValueRef = semantic['categoryValueRef'];
+
+  if (!categoryValueRef) {
+    return '';
+  }
+
+
+  return categoryValueRef.value || '';
+}
+
+export function getLabel(element) {
+  var semantic = element.businessObject,
+      attr = getLabelAttr(semantic);
+
+  if (attr) {
+
+    if (attr === 'categoryValueRef') {
+
+      return getCategoryValue(semantic);
+    }
+
+    return semantic[attr] || '';
+  }
+}
+
+
+export function setLabel(element, text, isExternal) {
+  var semantic = element.businessObject,
+      attr = getLabelAttr(semantic);
+
+  if (attr) {
+
+    if (attr === 'categoryValueRef') {
+      semantic['categoryValueRef'].value = text;
+    } else {
+      semantic[attr] = text;
+    }
+
+  }
+
+  return element;
+}

+ 165 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/cmd/UpdateLabelHandler.js

@@ -0,0 +1,165 @@
+import {
+  setLabel,
+  getLabel
+} from '../LabelUtil';
+
+import {
+  getExternalLabelMid,
+  isLabelExternal,
+  hasExternalLabel,
+  isLabel
+} from '../../../util/LabelUtil';
+
+import {
+  getDi,
+  is
+} from '../../../util/ModelUtil';
+
+var NULL_DIMENSIONS = {
+  width: 0,
+  height: 0
+};
+
+
+/**
+ * A handler that updates the text of a BPMN element.
+ */
+export default function UpdateLabelHandler(modeling, textRenderer, bpmnFactory) {
+
+  /**
+   * Creates an empty `diLabel` attribute for embedded labels.
+   *
+   * @param {djs.model.Base} element
+   * @param {string} text
+   */
+  function ensureInternalLabelDi(element, text) {
+    if (isLabelExternal(element)) {
+      return;
+    }
+
+    var di = getDi(element);
+
+    if (text && !di.label) {
+      di.label = bpmnFactory.create('bpmndi:BPMNLabel');
+    }
+
+    if (!text && di.label) {
+      delete di.label;
+    }
+  }
+
+
+  /**
+   * Set the label and return the changed elements.
+   *
+   * Element parameter can be label itself or connection (i.e. sequence flow).
+   *
+   * @param {djs.model.Base} element
+   * @param {string} text
+   */
+  function setText(element, text) {
+
+    // external label if present
+    var label = element.label || element;
+
+    var labelTarget = element.labelTarget || element;
+
+    setLabel(label, text, labelTarget !== label);
+
+    ensureInternalLabelDi(element, text);
+
+    return [ label, labelTarget ];
+  }
+
+  function preExecute(ctx) {
+    var element = ctx.element,
+        businessObject = element.businessObject,
+        newLabel = ctx.newLabel;
+
+    if (!isLabel(element)
+        && isLabelExternal(element)
+        && !hasExternalLabel(element)
+        && !isEmptyText(newLabel)) {
+
+      // create label
+      var paddingTop = 7;
+
+      var labelCenter = getExternalLabelMid(element);
+
+      labelCenter = {
+        x: labelCenter.x,
+        y: labelCenter.y + paddingTop
+      };
+
+      modeling.createLabel(element, labelCenter, {
+        id: businessObject.id + '_label',
+        businessObject: businessObject,
+        di: element.di
+      });
+    }
+  }
+
+  function execute(ctx) {
+    ctx.oldLabel = getLabel(ctx.element);
+    return setText(ctx.element, ctx.newLabel);
+  }
+
+  function revert(ctx) {
+    return setText(ctx.element, ctx.oldLabel);
+  }
+
+  function postExecute(ctx) {
+    var element = ctx.element,
+        label = element.label || element,
+        newLabel = ctx.newLabel,
+        newBounds = ctx.newBounds,
+        hints = ctx.hints || {};
+
+    // ignore internal labels for elements except text annotations
+    if (!isLabel(label) && !is(label, 'bpmn:TextAnnotation')) {
+      return;
+    }
+
+    if (isLabel(label) && isEmptyText(newLabel)) {
+
+      if (hints.removeShape !== false) {
+        modeling.removeShape(label, { unsetLabel: false });
+      }
+
+      return;
+    }
+
+    var text = getLabel(label);
+
+    // resize element based on label _or_ pre-defined bounds
+    if (typeof newBounds === 'undefined') {
+      newBounds = textRenderer.getExternalLabelBounds(label, text);
+    }
+
+    // setting newBounds to false or _null_ will
+    // disable the postExecute resize operation
+    if (newBounds) {
+      modeling.resizeShape(label, newBounds, NULL_DIMENSIONS);
+    }
+  }
+
+  // API
+
+  this.preExecute = preExecute;
+  this.execute = execute;
+  this.revert = revert;
+  this.postExecute = postExecute;
+}
+
+UpdateLabelHandler.$inject = [
+  'modeling',
+  'textRenderer',
+  'bpmnFactory'
+];
+
+
+// helpers ///////////////////////
+
+function isEmptyText(label) {
+  return !label || !label.trim();
+}

+ 21 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/label-editing/index.js

@@ -0,0 +1,21 @@
+import ChangeSupportModule from 'diagram-js/lib/features/change-support';
+import ResizeModule from 'diagram-js/lib/features/resize';
+import DirectEditingModule from 'diagram-js-direct-editing';
+
+import LabelEditingProvider from './LabelEditingProvider';
+import LabelEditingPreview from './LabelEditingPreview';
+
+
+export default {
+  __depends__: [
+    ChangeSupportModule,
+    ResizeModule,
+    DirectEditingModule
+  ],
+  __init__: [
+    'labelEditingProvider',
+    'labelEditingPreview'
+  ],
+  labelEditingProvider: [ 'type', LabelEditingProvider ],
+  labelEditingPreview: [ 'type', LabelEditingPreview ]
+};

+ 127 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/BpmnFactory.js

@@ -0,0 +1,127 @@
+import {
+  map,
+  assign,
+  pick
+} from 'min-dash';
+
+import {
+  isAny
+} from './util/ModelingUtil';
+
+import {
+  is
+} from '../../util/ModelUtil';
+
+
+export default function BpmnFactory(moddle) {
+  this._model = moddle;
+}
+
+BpmnFactory.$inject = [ 'moddle' ];
+
+
+BpmnFactory.prototype._needsId = function(element) {
+  return isAny(element, [
+    'bpmn:RootElement',
+    'bpmn:FlowElement',
+    'bpmn:MessageFlow',
+    'bpmn:DataAssociation',
+    'bpmn:Artifact',
+    'bpmn:Participant',
+    'bpmn:Lane',
+    'bpmn:LaneSet',
+    'bpmn:Process',
+    'bpmn:Collaboration',
+    'bpmndi:BPMNShape',
+    'bpmndi:BPMNEdge',
+    'bpmndi:BPMNDiagram',
+    'bpmndi:BPMNPlane',
+    'bpmn:Property',
+    'bpmn:CategoryValue'
+  ]);
+};
+
+BpmnFactory.prototype._ensureId = function(element) {
+  if (element.id) {
+    this._model.ids.claim(element.id, element);
+    return;
+  }
+
+  // generate semantic ids for elements
+  // bpmn:SequenceFlow -> SequenceFlow_ID
+  var prefix;
+
+  if (is(element, 'bpmn:Activity')) {
+    prefix = 'Activity';
+  } else if (is(element, 'bpmn:Event')) {
+    prefix = 'Event';
+  } else if (is(element, 'bpmn:Gateway')) {
+    prefix = 'Gateway';
+  } else if (isAny(element, [ 'bpmn:SequenceFlow', 'bpmn:MessageFlow' ])) {
+    prefix = 'Flow';
+  } else {
+    prefix = (element.$type || '').replace(/^[^:]*:/g, '');
+  }
+
+  prefix += '_';
+
+  if (!element.id && this._needsId(element)) {
+    element.id = this._model.ids.nextPrefixed(prefix, element);
+  }
+};
+
+
+BpmnFactory.prototype.create = function(type, attrs) {
+  var element = this._model.create(type, attrs || {});
+
+  this._ensureId(element);
+
+  return element;
+};
+
+
+BpmnFactory.prototype.createDiLabel = function() {
+  return this.create('bpmndi:BPMNLabel', {
+    bounds: this.createDiBounds()
+  });
+};
+
+
+BpmnFactory.prototype.createDiShape = function(semantic, attrs) {
+  return this.create('bpmndi:BPMNShape', assign({
+    bpmnElement: semantic,
+    bounds: this.createDiBounds()
+  }, attrs));
+};
+
+
+BpmnFactory.prototype.createDiBounds = function(bounds) {
+  return this.create('dc:Bounds', bounds);
+};
+
+
+BpmnFactory.prototype.createDiWaypoints = function(waypoints) {
+  var self = this;
+
+  return map(waypoints, function(pos) {
+    return self.createDiWaypoint(pos);
+  });
+};
+
+BpmnFactory.prototype.createDiWaypoint = function(point) {
+  return this.create('dc:Point', pick(point, [ 'x', 'y' ]));
+};
+
+
+BpmnFactory.prototype.createDiEdge = function(semantic, attrs) {
+  return this.create('bpmndi:BPMNEdge', assign({
+    bpmnElement: semantic,
+    waypoint: this.createDiWaypoints([])
+  }, attrs));
+};
+
+BpmnFactory.prototype.createDiPlane = function(semantic, attrs) {
+  return this.create('bpmndi:BPMNPlane', assign({
+    bpmnElement: semantic
+  }, attrs));
+};

+ 399 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/BpmnLayouter.js

@@ -0,0 +1,399 @@
+import inherits from 'inherits-browser';
+
+import {
+  assign
+} from 'min-dash';
+
+import BaseLayouter from 'diagram-js/lib/layout/BaseLayouter';
+
+import {
+  repairConnection,
+  withoutRedundantPoints
+} from 'diagram-js/lib/layout/ManhattanLayout';
+
+import {
+  getMid,
+  getOrientation
+} from 'diagram-js/lib/layout/LayoutUtil';
+
+import {
+  isExpanded
+} from '../../util/DiUtil';
+
+import { is } from '../../util/ModelUtil';
+
+var ATTACH_ORIENTATION_PADDING = -10,
+    BOUNDARY_TO_HOST_THRESHOLD = 40;
+
+var oppositeOrientationMapping = {
+  'top': 'bottom',
+  'top-right': 'bottom-left',
+  'top-left': 'bottom-right',
+  'right': 'left',
+  'bottom': 'top',
+  'bottom-right': 'top-left',
+  'bottom-left': 'top-right',
+  'left': 'right'
+};
+
+var orientationDirectionMapping = {
+  top: 't',
+  right: 'r',
+  bottom: 'b',
+  left: 'l'
+};
+
+
+export default function BpmnLayouter() {}
+
+inherits(BpmnLayouter, BaseLayouter);
+
+
+BpmnLayouter.prototype.layoutConnection = function(connection, hints) {
+  if (!hints) {
+    hints = {};
+  }
+
+  var source = hints.source || connection.source,
+      target = hints.target || connection.target,
+      waypoints = hints.waypoints || connection.waypoints,
+      connectionStart = hints.connectionStart,
+      connectionEnd = hints.connectionEnd;
+
+  var manhattanOptions,
+      updatedWaypoints;
+
+  if (!connectionStart) {
+    connectionStart = getConnectionDocking(waypoints && waypoints[ 0 ], source);
+  }
+
+  if (!connectionEnd) {
+    connectionEnd = getConnectionDocking(waypoints && waypoints[ waypoints.length - 1 ], target);
+  }
+
+  // TODO(nikku): support vertical modeling
+  // and invert preferredLayouts accordingly
+
+  if (is(connection, 'bpmn:Association') ||
+      is(connection, 'bpmn:DataAssociation')) {
+
+    if (waypoints && !isCompensationAssociation(source, target)) {
+      return [].concat([ connectionStart ], waypoints.slice(1, -1), [ connectionEnd ]);
+    }
+  }
+
+  if (is(connection, 'bpmn:MessageFlow')) {
+    manhattanOptions = getMessageFlowManhattanOptions(source, target);
+  } else if (is(connection, 'bpmn:SequenceFlow') || isCompensationAssociation(source, target)) {
+
+    // layout all connection between flow elements h:h, except for
+    // (1) outgoing of boundary events -> layout based on attach orientation and target orientation
+    // (2) incoming/outgoing of gateways -> v:h for outgoing, h:v for incoming
+    // (3) loops
+    if (source === target) {
+      manhattanOptions = {
+        preferredLayouts: getLoopPreferredLayout(source, connection)
+      };
+    } else if (is(source, 'bpmn:BoundaryEvent')) {
+      manhattanOptions = {
+        preferredLayouts: getBoundaryEventPreferredLayouts(source, target, connectionEnd)
+      };
+    } else if (isExpandedSubProcess(source) || isExpandedSubProcess(target)) {
+      manhattanOptions = getSubProcessManhattanOptions(source);
+    } else if (is(source, 'bpmn:Gateway')) {
+      manhattanOptions = {
+        preferredLayouts: [ 'v:h' ]
+      };
+    } else if (is(target, 'bpmn:Gateway')) {
+      manhattanOptions = {
+        preferredLayouts: [ 'h:v' ]
+      };
+    } else {
+      manhattanOptions = {
+        preferredLayouts: [ 'h:h' ]
+      };
+    }
+  }
+
+  if (manhattanOptions) {
+    manhattanOptions = assign(manhattanOptions, hints);
+
+    updatedWaypoints = withoutRedundantPoints(repairConnection(
+      source,
+      target,
+      connectionStart,
+      connectionEnd,
+      waypoints,
+      manhattanOptions
+    ));
+  }
+
+  return updatedWaypoints || [ connectionStart, connectionEnd ];
+};
+
+
+// helpers //////////
+
+function getAttachOrientation(attachedElement) {
+  var hostElement = attachedElement.host;
+
+  return getOrientation(getMid(attachedElement), hostElement, ATTACH_ORIENTATION_PADDING);
+}
+
+function getMessageFlowManhattanOptions(source, target) {
+  return {
+    preferredLayouts: [ 'straight', 'v:v' ],
+    preserveDocking: getMessageFlowPreserveDocking(source, target)
+  };
+}
+
+function getMessageFlowPreserveDocking(source, target) {
+
+  // (1) docking element connected to participant has precedence
+  if (is(target, 'bpmn:Participant')) {
+    return 'source';
+  }
+
+  if (is(source, 'bpmn:Participant')) {
+    return 'target';
+  }
+
+  // (2) docking element connected to expanded sub-process has precedence
+  if (isExpandedSubProcess(target)) {
+    return 'source';
+  }
+
+  if (isExpandedSubProcess(source)) {
+    return 'target';
+  }
+
+  // (3) docking event has precedence
+  if (is(target, 'bpmn:Event')) {
+    return 'target';
+  }
+
+  if (is(source, 'bpmn:Event')) {
+    return 'source';
+  }
+
+  return null;
+}
+
+function getSubProcessManhattanOptions(source) {
+  return {
+    preferredLayouts: [ 'straight', 'h:h' ],
+    preserveDocking: getSubProcessPreserveDocking(source)
+  };
+}
+
+function getSubProcessPreserveDocking(source) {
+  return isExpandedSubProcess(source) ? 'target' : 'source';
+}
+
+function getConnectionDocking(point, shape) {
+  return point ? (point.original || point) : getMid(shape);
+}
+
+function isCompensationAssociation(source, target) {
+  return is(target, 'bpmn:Activity') &&
+    is(source, 'bpmn:BoundaryEvent') &&
+    target.businessObject.isForCompensation;
+}
+
+function isExpandedSubProcess(element) {
+  return is(element, 'bpmn:SubProcess') && isExpanded(element);
+}
+
+function isSame(a, b) {
+  return a === b;
+}
+
+function isAnyOrientation(orientation, orientations) {
+  return orientations.indexOf(orientation) !== -1;
+}
+
+function getHorizontalOrientation(orientation) {
+  var matches = /right|left/.exec(orientation);
+
+  return matches && matches[0];
+}
+
+function getVerticalOrientation(orientation) {
+  var matches = /top|bottom/.exec(orientation);
+
+  return matches && matches[0];
+}
+
+function isOppositeOrientation(a, b) {
+  return oppositeOrientationMapping[a] === b;
+}
+
+function isOppositeHorizontalOrientation(a, b) {
+  var horizontalOrientation = getHorizontalOrientation(a);
+
+  var oppositeHorizontalOrientation = oppositeOrientationMapping[horizontalOrientation];
+
+  return b.indexOf(oppositeHorizontalOrientation) !== -1;
+}
+
+function isOppositeVerticalOrientation(a, b) {
+  var verticalOrientation = getVerticalOrientation(a);
+
+  var oppositeVerticalOrientation = oppositeOrientationMapping[verticalOrientation];
+
+  return b.indexOf(oppositeVerticalOrientation) !== -1;
+}
+
+function isHorizontalOrientation(orientation) {
+  return orientation === 'right' || orientation === 'left';
+}
+
+function getLoopPreferredLayout(source, connection) {
+  var waypoints = connection.waypoints;
+
+  var orientation = waypoints && waypoints.length && getOrientation(waypoints[0], source);
+
+  if (orientation === 'top') {
+    return [ 't:r' ];
+  } else if (orientation === 'right') {
+    return [ 'r:b' ];
+  } else if (orientation === 'left') {
+    return [ 'l:t' ];
+  }
+
+  return [ 'b:l' ];
+}
+
+function getBoundaryEventPreferredLayouts(source, target, end) {
+  var sourceMid = getMid(source),
+      targetMid = getMid(target),
+      attachOrientation = getAttachOrientation(source),
+      sourceLayout,
+      targetLayout;
+
+  var isLoop = isSame(source.host, target);
+
+  var attachedToSide = isAnyOrientation(attachOrientation, [ 'top', 'right', 'bottom', 'left' ]);
+
+  var targetOrientation = getOrientation(targetMid, sourceMid, {
+    x: source.width / 2 + target.width / 2,
+    y: source.height / 2 + target.height / 2
+  });
+
+  if (isLoop) {
+    return getBoundaryEventLoopLayout(attachOrientation, attachedToSide, source, target, end);
+  }
+
+  // source layout
+  sourceLayout = getBoundaryEventSourceLayout(attachOrientation, targetOrientation, attachedToSide);
+
+  // target layout
+  targetLayout = getBoundaryEventTargetLayout(attachOrientation, targetOrientation, attachedToSide);
+
+  return [ sourceLayout + ':' + targetLayout ];
+}
+
+function getBoundaryEventLoopLayout(attachOrientation, attachedToSide, source, target, end) {
+  var orientation = attachedToSide ? attachOrientation : getVerticalOrientation(attachOrientation),
+      sourceLayout = orientationDirectionMapping[ orientation ],
+      targetLayout;
+
+  if (attachedToSide) {
+    if (isHorizontalOrientation(attachOrientation)) {
+      targetLayout = shouldConnectToSameSide('y', source, target, end) ? 'h' : 'b';
+    } else {
+      targetLayout = shouldConnectToSameSide('x', source, target, end) ? 'v' : 'l';
+    }
+  } else {
+    targetLayout = 'v';
+  }
+
+  return [ sourceLayout + ':' + targetLayout ];
+}
+
+function shouldConnectToSameSide(axis, source, target, end) {
+  var threshold = BOUNDARY_TO_HOST_THRESHOLD;
+
+  return !(
+    areCloseOnAxis(axis, end, target, threshold) ||
+    areCloseOnAxis(axis, end, {
+      x: target.x + target.width,
+      y: target.y + target.height
+    }, threshold) ||
+    areCloseOnAxis(axis, end, getMid(source), threshold)
+  );
+}
+
+function areCloseOnAxis(axis, a, b, threshold) {
+  return Math.abs(a[ axis ] - b[ axis ]) < threshold;
+}
+
+function getBoundaryEventSourceLayout(attachOrientation, targetOrientation, attachedToSide) {
+
+  // attached to either top, right, bottom or left side
+  if (attachedToSide) {
+    return orientationDirectionMapping[ attachOrientation ];
+  }
+
+  // attached to either top-right, top-left, bottom-right or bottom-left corner
+
+  // same vertical or opposite horizontal orientation
+  if (isSame(
+    getVerticalOrientation(attachOrientation), getVerticalOrientation(targetOrientation)
+  ) || isOppositeOrientation(
+    getHorizontalOrientation(attachOrientation), getHorizontalOrientation(targetOrientation)
+  )) {
+    return orientationDirectionMapping[ getVerticalOrientation(attachOrientation) ];
+  }
+
+  // fallback
+  return orientationDirectionMapping[ getHorizontalOrientation(attachOrientation) ];
+}
+
+function getBoundaryEventTargetLayout(attachOrientation, targetOrientation, attachedToSide) {
+
+  // attached to either top, right, bottom or left side
+  if (attachedToSide) {
+    if (isHorizontalOrientation(attachOrientation)) {
+
+      // orientation is right or left
+
+      // opposite horizontal orientation or same orientation
+      if (
+        isOppositeHorizontalOrientation(attachOrientation, targetOrientation) ||
+        isSame(attachOrientation, targetOrientation)
+      ) {
+        return 'h';
+      }
+
+      // fallback
+      return 'v';
+    } else {
+
+      // orientation is top or bottom
+
+      // opposite vertical orientation or same orientation
+      if (
+        isOppositeVerticalOrientation(attachOrientation, targetOrientation) ||
+        isSame(attachOrientation, targetOrientation)
+      ) {
+        return 'v';
+      }
+
+      // fallback
+      return 'h';
+    }
+  }
+
+  // attached to either top-right, top-left, bottom-right or bottom-left corner
+
+  // orientation is right, left
+  // or same vertical orientation but also right or left
+  if (isHorizontalOrientation(targetOrientation) ||
+    (isSame(getVerticalOrientation(attachOrientation), getVerticalOrientation(targetOrientation)) &&
+      getHorizontalOrientation(targetOrientation))) {
+    return 'h';
+  } else {
+    return 'v';
+  }
+}

+ 762 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/BpmnUpdater.js

@@ -0,0 +1,762 @@
+import {
+  assign,
+  forEach
+} from 'min-dash';
+
+import inherits from 'inherits-browser';
+
+import {
+  remove as collectionRemove,
+  add as collectionAdd
+} from 'diagram-js/lib/util/Collections';
+
+import {
+  Label
+} from 'diagram-js/lib/model';
+
+import {
+  getBusinessObject,
+  getDi,
+  is
+} from '../../util/ModelUtil';
+
+import {
+  isAny
+} from './util/ModelingUtil';
+
+import {
+  delta
+} from 'diagram-js/lib/util/PositionUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+/**
+ * A handler responsible for updating the underlying BPMN 2.0 XML + DI
+ * once changes on the diagram happen
+ */
+export default function BpmnUpdater(
+    eventBus, bpmnFactory, connectionDocking,
+    translate) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  this._bpmnFactory = bpmnFactory;
+  this._translate = translate;
+
+  var self = this;
+
+
+
+  // connection cropping //////////////////////
+
+  // crop connection ends during create/update
+  function cropConnection(e) {
+    var context = e.context,
+        hints = context.hints || {},
+        connection;
+
+    if (!context.cropped && hints.createElementsBehavior !== false) {
+      connection = context.connection;
+      connection.waypoints = connectionDocking.getCroppedWaypoints(connection);
+      context.cropped = true;
+    }
+  }
+
+  this.executed([
+    'connection.layout',
+    'connection.create'
+  ], cropConnection);
+
+  this.reverted([ 'connection.layout' ], function(e) {
+    delete e.context.cropped;
+  });
+
+
+
+  // BPMN + DI update //////////////////////
+
+
+  // update parent
+  function updateParent(e) {
+    var context = e.context;
+
+    self.updateParent(context.shape || context.connection, context.oldParent);
+  }
+
+  function reverseUpdateParent(e) {
+    var context = e.context;
+
+    var element = context.shape || context.connection,
+
+        // oldParent is the (old) new parent, because we are undoing
+        oldParent = context.parent || context.newParent;
+
+    self.updateParent(element, oldParent);
+  }
+
+  this.executed([
+    'shape.move',
+    'shape.create',
+    'shape.delete',
+    'connection.create',
+    'connection.move',
+    'connection.delete'
+  ], ifBpmn(updateParent));
+
+  this.reverted([
+    'shape.move',
+    'shape.create',
+    'shape.delete',
+    'connection.create',
+    'connection.move',
+    'connection.delete'
+  ], ifBpmn(reverseUpdateParent));
+
+  /*
+   * ## Updating Parent
+   *
+   * When morphing a Process into a Collaboration or vice-versa,
+   * make sure that both the *semantic* and *di* parent of each element
+   * is updated.
+   *
+   */
+  function updateRoot(event) {
+    var context = event.context,
+        oldRoot = context.oldRoot,
+        children = oldRoot.children;
+
+    forEach(children, function(child) {
+      if (is(child, 'bpmn:BaseElement')) {
+        self.updateParent(child);
+      }
+    });
+  }
+
+  this.executed([ 'canvas.updateRoot' ], updateRoot);
+  this.reverted([ 'canvas.updateRoot' ], updateRoot);
+
+
+  // update bounds
+  function updateBounds(e) {
+    var shape = e.context.shape;
+
+    if (!is(shape, 'bpmn:BaseElement')) {
+      return;
+    }
+
+    self.updateBounds(shape);
+  }
+
+  this.executed([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
+
+    // exclude labels because they're handled separately during shape.changed
+    if (event.context.shape.type === 'label') {
+      return;
+    }
+
+    updateBounds(event);
+  }));
+
+  this.reverted([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
+
+    // exclude labels because they're handled separately during shape.changed
+    if (event.context.shape.type === 'label') {
+      return;
+    }
+
+    updateBounds(event);
+  }));
+
+  // Handle labels separately. This is necessary, because the label bounds have to be updated
+  // every time its shape changes, not only on move, create and resize.
+  eventBus.on('shape.changed', function(event) {
+    if (event.element.type === 'label') {
+      updateBounds({ context: { shape: event.element } });
+    }
+  });
+
+  // attach / detach connection
+  function updateConnection(e) {
+    self.updateConnection(e.context);
+  }
+
+  this.executed([
+    'connection.create',
+    'connection.move',
+    'connection.delete',
+    'connection.reconnect'
+  ], ifBpmn(updateConnection));
+
+  this.reverted([
+    'connection.create',
+    'connection.move',
+    'connection.delete',
+    'connection.reconnect'
+  ], ifBpmn(updateConnection));
+
+
+  // update waypoints
+  function updateConnectionWaypoints(e) {
+    self.updateConnectionWaypoints(e.context.connection);
+  }
+
+  this.executed([
+    'connection.layout',
+    'connection.move',
+    'connection.updateWaypoints',
+  ], ifBpmn(updateConnectionWaypoints));
+
+  this.reverted([
+    'connection.layout',
+    'connection.move',
+    'connection.updateWaypoints',
+  ], ifBpmn(updateConnectionWaypoints));
+
+  // update conditional/default flows
+  this.executed('connection.reconnect', ifBpmn(function(event) {
+    var context = event.context,
+        connection = context.connection,
+        oldSource = context.oldSource,
+        newSource = context.newSource,
+        connectionBo = getBusinessObject(connection),
+        oldSourceBo = getBusinessObject(oldSource),
+        newSourceBo = getBusinessObject(newSource);
+
+    // remove condition from connection on reconnect to new source
+    // if new source can NOT have condional sequence flow
+    if (connectionBo.conditionExpression && !isAny(newSourceBo, [
+      'bpmn:Activity',
+      'bpmn:ExclusiveGateway',
+      'bpmn:InclusiveGateway'
+    ])) {
+      context.oldConditionExpression = connectionBo.conditionExpression;
+
+      delete connectionBo.conditionExpression;
+    }
+
+    // remove default from old source flow on reconnect to new source
+    // if source changed
+    if (oldSource !== newSource && oldSourceBo.default === connectionBo) {
+      context.oldDefault = oldSourceBo.default;
+
+      delete oldSourceBo.default;
+    }
+  }));
+
+  this.reverted('connection.reconnect', ifBpmn(function(event) {
+    var context = event.context,
+        connection = context.connection,
+        oldSource = context.oldSource,
+        newSource = context.newSource,
+        connectionBo = getBusinessObject(connection),
+        oldSourceBo = getBusinessObject(oldSource),
+        newSourceBo = getBusinessObject(newSource);
+
+    // add condition to connection on revert reconnect to new source
+    if (context.oldConditionExpression) {
+      connectionBo.conditionExpression = context.oldConditionExpression;
+    }
+
+    // add default to old source on revert reconnect to new source
+    if (context.oldDefault) {
+      oldSourceBo.default = context.oldDefault;
+
+      delete newSourceBo.default;
+    }
+  }));
+
+  // update attachments
+  function updateAttachment(e) {
+    self.updateAttachment(e.context);
+  }
+
+  this.executed([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
+  this.reverted([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
+}
+
+inherits(BpmnUpdater, CommandInterceptor);
+
+BpmnUpdater.$inject = [
+  'eventBus',
+  'bpmnFactory',
+  'connectionDocking',
+  'translate'
+];
+
+
+// implementation //////////////////////
+
+BpmnUpdater.prototype.updateAttachment = function(context) {
+
+  var shape = context.shape,
+      businessObject = shape.businessObject,
+      host = shape.host;
+
+  businessObject.attachedToRef = host && host.businessObject;
+};
+
+BpmnUpdater.prototype.updateParent = function(element, oldParent) {
+
+  // do not update BPMN 2.0 label parent
+  if (element instanceof Label) {
+    return;
+  }
+
+  // data stores in collaborations are handled separately by DataStoreBehavior
+  if (is(element, 'bpmn:DataStoreReference') &&
+      element.parent &&
+      is(element.parent, 'bpmn:Collaboration')) {
+    return;
+  }
+
+  var parentShape = element.parent;
+
+  var businessObject = element.businessObject,
+      di = getDi(element),
+      parentBusinessObject = parentShape && parentShape.businessObject,
+      parentDi = getDi(parentShape);
+
+  if (is(element, 'bpmn:FlowNode')) {
+    this.updateFlowNodeRefs(businessObject, parentBusinessObject, oldParent && oldParent.businessObject);
+  }
+
+  if (is(element, 'bpmn:DataOutputAssociation')) {
+    if (element.source) {
+      parentBusinessObject = element.source.businessObject;
+    } else {
+      parentBusinessObject = null;
+    }
+  }
+
+  if (is(element, 'bpmn:DataInputAssociation')) {
+    if (element.target) {
+      parentBusinessObject = element.target.businessObject;
+    } else {
+      parentBusinessObject = null;
+    }
+  }
+
+  this.updateSemanticParent(businessObject, parentBusinessObject);
+
+  if (is(element, 'bpmn:DataObjectReference') && businessObject.dataObjectRef) {
+    this.updateSemanticParent(businessObject.dataObjectRef, parentBusinessObject);
+  }
+
+  this.updateDiParent(di, parentDi);
+};
+
+
+BpmnUpdater.prototype.updateBounds = function(shape) {
+
+  var di = getDi(shape),
+      embeddedLabelBounds = getEmbeddedLabelBounds(shape);
+
+  // update embedded label bounds if possible
+  if (embeddedLabelBounds) {
+    var embeddedLabelBoundsDelta = delta(embeddedLabelBounds, di.get('bounds'));
+
+    assign(embeddedLabelBounds, {
+      x: shape.x + embeddedLabelBoundsDelta.x,
+      y: shape.y + embeddedLabelBoundsDelta.y
+    });
+  }
+
+  var target = (shape instanceof Label) ? this._getLabel(di) : di;
+
+  var bounds = target.bounds;
+
+  if (!bounds) {
+    bounds = this._bpmnFactory.createDiBounds();
+    target.set('bounds', bounds);
+  }
+
+  assign(bounds, {
+    x: shape.x,
+    y: shape.y,
+    width: shape.width,
+    height: shape.height
+  });
+};
+
+BpmnUpdater.prototype.updateFlowNodeRefs = function(businessObject, newContainment, oldContainment) {
+
+  if (oldContainment === newContainment) {
+    return;
+  }
+
+  var oldRefs, newRefs;
+
+  if (is (oldContainment, 'bpmn:Lane')) {
+    oldRefs = oldContainment.get('flowNodeRef');
+    collectionRemove(oldRefs, businessObject);
+  }
+
+  if (is(newContainment, 'bpmn:Lane')) {
+    newRefs = newContainment.get('flowNodeRef');
+    collectionAdd(newRefs, businessObject);
+  }
+};
+
+
+// update existing sourceElement and targetElement di information
+BpmnUpdater.prototype.updateDiConnection = function(connection, newSource, newTarget) {
+  var connectionDi = getDi(connection),
+      newSourceDi = getDi(newSource),
+      newTargetDi = getDi(newTarget);
+
+  if (connectionDi.sourceElement && connectionDi.sourceElement.bpmnElement !== getBusinessObject(newSource)) {
+    connectionDi.sourceElement = newSource && newSourceDi;
+  }
+
+  if (connectionDi.targetElement && connectionDi.targetElement.bpmnElement !== getBusinessObject(newTarget)) {
+    connectionDi.targetElement = newTarget && newTargetDi;
+  }
+
+};
+
+
+BpmnUpdater.prototype.updateDiParent = function(di, parentDi) {
+
+  if (parentDi && !is(parentDi, 'bpmndi:BPMNPlane')) {
+    parentDi = parentDi.$parent;
+  }
+
+  if (di.$parent === parentDi) {
+    return;
+  }
+
+  var planeElements = (parentDi || di.$parent).get('planeElement');
+
+  if (parentDi) {
+    planeElements.push(di);
+    di.$parent = parentDi;
+  } else {
+    collectionRemove(planeElements, di);
+    di.$parent = null;
+  }
+};
+
+function getDefinitions(element) {
+  while (element && !is(element, 'bpmn:Definitions')) {
+    element = element.$parent;
+  }
+
+  return element;
+}
+
+BpmnUpdater.prototype.getLaneSet = function(container) {
+
+  var laneSet, laneSets;
+
+  // bpmn:Lane
+  if (is(container, 'bpmn:Lane')) {
+    laneSet = container.childLaneSet;
+
+    if (!laneSet) {
+      laneSet = this._bpmnFactory.create('bpmn:LaneSet');
+      container.childLaneSet = laneSet;
+      laneSet.$parent = container;
+    }
+
+    return laneSet;
+  }
+
+  // bpmn:Participant
+  if (is(container, 'bpmn:Participant')) {
+    container = container.processRef;
+  }
+
+  // bpmn:FlowElementsContainer
+  laneSets = container.get('laneSets');
+  laneSet = laneSets[0];
+
+  if (!laneSet) {
+    laneSet = this._bpmnFactory.create('bpmn:LaneSet');
+    laneSet.$parent = container;
+    laneSets.push(laneSet);
+  }
+
+  return laneSet;
+};
+
+BpmnUpdater.prototype.updateSemanticParent = function(businessObject, newParent, visualParent) {
+
+  var containment,
+      translate = this._translate;
+
+  if (businessObject.$parent === newParent) {
+    return;
+  }
+
+  if (is(businessObject, 'bpmn:DataInput') || is(businessObject, 'bpmn:DataOutput')) {
+
+    if (is(newParent, 'bpmn:Participant') && 'processRef' in newParent) {
+      newParent = newParent.processRef;
+    }
+
+    // already in correct ioSpecification
+    if ('ioSpecification' in newParent && newParent.ioSpecification === businessObject.$parent) {
+      return;
+    }
+  }
+
+  if (is(businessObject, 'bpmn:Lane')) {
+
+    if (newParent) {
+      newParent = this.getLaneSet(newParent);
+    }
+
+    containment = 'lanes';
+  } else
+
+  if (is(businessObject, 'bpmn:FlowElement')) {
+
+    if (newParent) {
+
+      if (is(newParent, 'bpmn:Participant')) {
+        newParent = newParent.processRef;
+      } else
+
+      if (is(newParent, 'bpmn:Lane')) {
+        do {
+
+          // unwrap Lane -> LaneSet -> (Lane | FlowElementsContainer)
+          newParent = newParent.$parent.$parent;
+        } while (is(newParent, 'bpmn:Lane'));
+
+      }
+    }
+
+    containment = 'flowElements';
+
+  } else
+
+  if (is(businessObject, 'bpmn:Artifact')) {
+
+    while (newParent &&
+           !is(newParent, 'bpmn:Process') &&
+           !is(newParent, 'bpmn:SubProcess') &&
+           !is(newParent, 'bpmn:Collaboration')) {
+
+      if (is(newParent, 'bpmn:Participant')) {
+        newParent = newParent.processRef;
+        break;
+      } else {
+        newParent = newParent.$parent;
+      }
+    }
+
+    containment = 'artifacts';
+  } else
+
+  if (is(businessObject, 'bpmn:MessageFlow')) {
+    containment = 'messageFlows';
+
+  } else
+
+  if (is(businessObject, 'bpmn:Participant')) {
+    containment = 'participants';
+
+    // make sure the participants process is properly attached / detached
+    // from the XML document
+
+    var process = businessObject.processRef,
+        definitions;
+
+    if (process) {
+      definitions = getDefinitions(businessObject.$parent || newParent);
+
+      if (businessObject.$parent) {
+        collectionRemove(definitions.get('rootElements'), process);
+        process.$parent = null;
+      }
+
+      if (newParent) {
+        collectionAdd(definitions.get('rootElements'), process);
+        process.$parent = definitions;
+      }
+    }
+  } else
+
+  if (is(businessObject, 'bpmn:DataOutputAssociation')) {
+    containment = 'dataOutputAssociations';
+  } else
+
+  if (is(businessObject, 'bpmn:DataInputAssociation')) {
+    containment = 'dataInputAssociations';
+  }
+
+  if (!containment) {
+    throw new Error(translate(
+      'no parent for {element} in {parent}',
+      {
+        element: businessObject.id,
+        parent: newParent.id
+      }
+    ));
+  }
+
+  var children;
+
+  if (businessObject.$parent) {
+
+    // remove from old parent
+    children = businessObject.$parent.get(containment);
+    collectionRemove(children, businessObject);
+  }
+
+  if (!newParent) {
+    businessObject.$parent = null;
+  } else {
+
+    // add to new parent
+    children = newParent.get(containment);
+    children.push(businessObject);
+    businessObject.$parent = newParent;
+  }
+
+  if (visualParent) {
+    var diChildren = visualParent.get(containment);
+
+    collectionRemove(children, businessObject);
+
+    if (newParent) {
+
+      if (!diChildren) {
+        diChildren = [];
+        newParent.set(containment, diChildren);
+      }
+
+      diChildren.push(businessObject);
+    }
+  }
+};
+
+
+BpmnUpdater.prototype.updateConnectionWaypoints = function(connection) {
+  var di = getDi(connection);
+
+  di.set('waypoint', this._bpmnFactory.createDiWaypoints(connection.waypoints));
+};
+
+
+BpmnUpdater.prototype.updateConnection = function(context) {
+  var connection = context.connection,
+      businessObject = getBusinessObject(connection),
+      newSource = connection.source,
+      newSourceBo = getBusinessObject(newSource),
+      newTarget = connection.target,
+      newTargetBo = getBusinessObject(connection.target),
+      visualParent;
+
+  if (!is(businessObject, 'bpmn:DataAssociation')) {
+
+    var inverseSet = is(businessObject, 'bpmn:SequenceFlow');
+
+    if (businessObject.sourceRef !== newSourceBo) {
+      if (inverseSet) {
+        collectionRemove(businessObject.sourceRef && businessObject.sourceRef.get('outgoing'), businessObject);
+
+        if (newSourceBo && newSourceBo.get('outgoing')) {
+          newSourceBo.get('outgoing').push(businessObject);
+        }
+      }
+
+      businessObject.sourceRef = newSourceBo;
+    }
+
+    if (businessObject.targetRef !== newTargetBo) {
+      if (inverseSet) {
+        collectionRemove(businessObject.targetRef && businessObject.targetRef.get('incoming'), businessObject);
+
+        if (newTargetBo && newTargetBo.get('incoming')) {
+          newTargetBo.get('incoming').push(businessObject);
+        }
+      }
+
+      businessObject.targetRef = newTargetBo;
+    }
+  } else
+
+  if (is(businessObject, 'bpmn:DataInputAssociation')) {
+
+    // handle obnoxious isMsome sourceRef
+    businessObject.get('sourceRef')[0] = newSourceBo;
+
+    visualParent = context.parent || context.newParent || newTargetBo;
+
+    this.updateSemanticParent(businessObject, newTargetBo, visualParent);
+  } else
+
+  if (is(businessObject, 'bpmn:DataOutputAssociation')) {
+    visualParent = context.parent || context.newParent || newSourceBo;
+
+    this.updateSemanticParent(businessObject, newSourceBo, visualParent);
+
+    // targetRef = new target
+    businessObject.targetRef = newTargetBo;
+  }
+
+  this.updateConnectionWaypoints(connection);
+
+  this.updateDiConnection(connection, newSource, newTarget);
+};
+
+
+// helpers //////////////////////
+
+BpmnUpdater.prototype._getLabel = function(di) {
+  if (!di.label) {
+    di.label = this._bpmnFactory.createDiLabel();
+  }
+
+  return di.label;
+};
+
+
+/**
+ * Make sure the event listener is only called
+ * if the touched element is a BPMN element.
+ *
+ * @param  {Function} fn
+ * @return {Function} guarded function
+ */
+function ifBpmn(fn) {
+
+  return function(event) {
+
+    var context = event.context,
+        element = context.shape || context.connection;
+
+    if (is(element, 'bpmn:BaseElement')) {
+      fn(event);
+    }
+  };
+}
+
+/**
+ * Return dc:Bounds of bpmndi:BPMNLabel if exists.
+ *
+ * @param {djs.model.shape} shape
+ *
+ * @returns {Object|undefined}
+ */
+function getEmbeddedLabelBounds(shape) {
+  if (!is(shape, 'bpmn:Activity')) {
+    return;
+  }
+
+  var di = getDi(shape);
+
+  if (!di) {
+    return;
+  }
+
+  var label = di.get('label');
+
+  if (!label) {
+    return;
+  }
+
+  return label.get('bounds');
+}

+ 292 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/ElementFactory.js

@@ -0,0 +1,292 @@
+import {
+  assign,
+  forEach,
+  isObject,
+  omit
+} from 'min-dash';
+
+import inherits from 'inherits-browser';
+
+import {
+  getBusinessObject,
+  getDi,
+  is
+} from '../../util/ModelUtil';
+
+import {
+  isAny
+} from '../modeling/util/ModelingUtil';
+
+import {
+  isExpanded
+} from '../../util/DiUtil';
+
+import BaseElementFactory from 'diagram-js/lib/core/ElementFactory';
+
+import {
+  DEFAULT_LABEL_SIZE
+} from '../../util/LabelUtil';
+
+import {
+  ensureCompatDiRef
+} from '../../util/CompatibilityUtil';
+
+
+/**
+ * A bpmn-aware factory for diagram-js shapes
+ */
+export default function ElementFactory(bpmnFactory, moddle, translate) {
+  BaseElementFactory.call(this);
+
+  this._bpmnFactory = bpmnFactory;
+  this._moddle = moddle;
+  this._translate = translate;
+}
+
+inherits(ElementFactory, BaseElementFactory);
+
+ElementFactory.$inject = [
+  'bpmnFactory',
+  'moddle',
+  'translate'
+];
+
+ElementFactory.prototype.baseCreate = BaseElementFactory.prototype.create;
+
+ElementFactory.prototype.create = function(elementType, attrs) {
+
+  // no special magic for labels,
+  // we assume their businessObjects have already been created
+  // and wired via attrs
+  if (elementType === 'label') {
+    var di = attrs.di || this._bpmnFactory.createDiLabel();
+    return this.baseCreate(elementType, assign({ type: 'label', di: di }, DEFAULT_LABEL_SIZE, attrs));
+  }
+
+  return this.createBpmnElement(elementType, attrs);
+};
+
+ElementFactory.prototype.createBpmnElement = function(elementType, attrs) {
+  var size,
+      translate = this._translate;
+
+  attrs = assign({}, attrs || {});
+
+  var businessObject = attrs.businessObject,
+      di = attrs.di;
+
+  if (!businessObject) {
+    if (!attrs.type) {
+      throw new Error(translate('no shape type specified'));
+    }
+
+    businessObject = this._bpmnFactory.create(attrs.type);
+
+    ensureCompatDiRef(businessObject);
+  }
+
+  if (!isModdleDi(di)) {
+    var diAttrs = assign(
+      {},
+      di || {},
+      { id: businessObject.id + '_di' }
+    );
+
+    if (elementType === 'root') {
+      di = this._bpmnFactory.createDiPlane(businessObject, diAttrs);
+    } else
+    if (elementType === 'connection') {
+      di = this._bpmnFactory.createDiEdge(businessObject, diAttrs);
+    } else {
+      di = this._bpmnFactory.createDiShape(businessObject, diAttrs);
+    }
+  }
+
+  if (is(businessObject, 'bpmn:Group')) {
+    attrs = assign({
+      isFrame: true
+    }, attrs);
+  }
+
+  attrs = applyAttributes(businessObject, attrs, [
+    'processRef',
+    'isInterrupting',
+    'associationDirection',
+    'isForCompensation'
+  ]);
+
+  if (attrs.isExpanded) {
+    attrs = applyAttribute(di, attrs, 'isExpanded');
+  }
+
+  if (is(businessObject, 'bpmn:SubProcess')) {
+    attrs.collapsed = !isExpanded(businessObject, di);
+  }
+
+  if (is(businessObject, 'bpmn:ExclusiveGateway')) {
+    di.isMarkerVisible = true;
+  }
+
+  var eventDefinitions,
+      newEventDefinition;
+
+  if (attrs.eventDefinitionType) {
+    eventDefinitions = businessObject.get('eventDefinitions') || [];
+    newEventDefinition = this._bpmnFactory.create(attrs.eventDefinitionType, attrs.eventDefinitionAttrs);
+
+    if (attrs.eventDefinitionType === 'bpmn:ConditionalEventDefinition') {
+      newEventDefinition.condition = this._bpmnFactory.create('bpmn:FormalExpression');
+    }
+
+    eventDefinitions.push(newEventDefinition);
+
+    newEventDefinition.$parent = businessObject;
+    businessObject.eventDefinitions = eventDefinitions;
+
+    delete attrs.eventDefinitionType;
+  }
+
+  size = this.getDefaultSize(businessObject, di);
+
+  attrs = assign({
+    id: businessObject.id
+  }, size, attrs, {
+    businessObject: businessObject,
+    di: di
+  });
+
+  return this.baseCreate(elementType, attrs);
+};
+
+
+ElementFactory.prototype.getDefaultSize = function(element, di) {
+
+  var bo = getBusinessObject(element);
+  di = di || getDi(element);
+
+  if (is(bo, 'bpmn:SubProcess')) {
+    if (isExpanded(bo, di)) {
+      return { width: 350, height: 200 };
+    } else {
+      return { width: 100, height: 80 };
+    }
+  }
+
+  if (is(bo, 'bpmn:Task')) {
+    return { width: 100, height: 80 };
+  }
+
+  if (is(bo, 'bpmn:Gateway')) {
+    return { width: 50, height: 50 };
+  }
+
+  if (is(bo, 'bpmn:Event')) {
+    return { width: 36, height: 36 };
+  }
+
+  if (is(bo, 'bpmn:Participant')) {
+    if (isExpanded(bo, di)) {
+      return { width: 600, height: 250 };
+    } else {
+      return { width: 400, height: 60 };
+    }
+  }
+
+  if (is(bo, 'bpmn:Lane')) {
+    return { width: 400, height: 100 };
+  }
+
+  if (is(bo, 'bpmn:DataObjectReference')) {
+    return { width: 36, height: 50 };
+  }
+
+  if (is(bo, 'bpmn:DataStoreReference')) {
+    return { width: 50, height: 50 };
+  }
+
+  if (is(bo, 'bpmn:TextAnnotation')) {
+    return { width: 100, height: 30 };
+  }
+
+  if (is(bo, 'bpmn:Group')) {
+    return { width: 300, height: 300 };
+  }
+
+  return { width: 100, height: 80 };
+};
+
+
+/**
+ * Create participant.
+ *
+ * @param {boolean|Object} [attrs] attrs
+ *
+ * @returns {djs.model.Shape}
+ */
+ElementFactory.prototype.createParticipantShape = function(attrs) {
+
+  if (!isObject(attrs)) {
+    attrs = { isExpanded: attrs };
+  }
+
+  attrs = assign({ type: 'bpmn:Participant' }, attrs || {});
+
+  // participants are expanded by default
+  if (attrs.isExpanded !== false) {
+    attrs.processRef = this._bpmnFactory.create('bpmn:Process');
+  }
+
+  return this.createShape(attrs);
+};
+
+
+// helpers //////////////////////
+
+/**
+ * Apply attributes from a map to the given element,
+ * remove attribute from the map on application.
+ *
+ * @param {Base} element
+ * @param {Object} attrs (in/out map of attributes)
+ * @param {Array<string>} attributeNames name of attributes to apply
+ *
+ * @return {Object} changed attrs
+ */
+function applyAttributes(element, attrs, attributeNames) {
+
+  forEach(attributeNames, function(property) {
+    attrs = applyAttribute(element, attrs, property);
+  });
+
+  return attrs;
+}
+
+/**
+ * Apply named property to element and drain it from the attrs
+ * collection.
+ *
+ * @param {Base} element
+ * @param {Object} attrs (in/out map of attributes)
+ * @param {string} attributeName to apply
+ *
+ * @return {Object} changed attrs
+ */
+function applyAttribute(element, attrs, attributeName) {
+  if (attrs[attributeName] === undefined) {
+    return attrs;
+  }
+
+  element[attributeName] = attrs[attributeName];
+
+  return omit(attrs, [ attributeName ]);
+}
+
+
+function isModdleDi(element) {
+  return isAny(element, [
+    'bpmndi:BPMNShape',
+    'bpmndi:BPMNEdge',
+    'bpmndi:BPMNDiagram',
+    'bpmndi:BPMNPlane',
+  ]);
+}

+ 202 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/Modeling.js

@@ -0,0 +1,202 @@
+import inherits from 'inherits-browser';
+
+import BaseModeling from 'diagram-js/lib/features/modeling/Modeling';
+
+import UpdateModdlePropertiesHandler from './cmd/UpdateModdlePropertiesHandler';
+import UpdatePropertiesHandler from './cmd/UpdatePropertiesHandler';
+import UpdateCanvasRootHandler from './cmd/UpdateCanvasRootHandler';
+import AddLaneHandler from './cmd/AddLaneHandler';
+import SplitLaneHandler from './cmd/SplitLaneHandler';
+import ResizeLaneHandler from './cmd/ResizeLaneHandler';
+import UpdateFlowNodeRefsHandler from './cmd/UpdateFlowNodeRefsHandler';
+import IdClaimHandler from './cmd/IdClaimHandler';
+import SetColorHandler from './cmd/SetColorHandler';
+
+import UpdateLabelHandler from '../label-editing/cmd/UpdateLabelHandler';
+
+
+/**
+ * BPMN 2.0 modeling features activator
+ *
+ * @param {EventBus} eventBus
+ * @param {ElementFactory} elementFactory
+ * @param {CommandStack} commandStack
+ * @param {BpmnRules} bpmnRules
+ */
+export default function Modeling(
+    eventBus, elementFactory, commandStack,
+    bpmnRules) {
+
+  BaseModeling.call(this, eventBus, elementFactory, commandStack);
+
+  this._bpmnRules = bpmnRules;
+}
+
+inherits(Modeling, BaseModeling);
+
+Modeling.$inject = [
+  'eventBus',
+  'elementFactory',
+  'commandStack',
+  'bpmnRules'
+];
+
+
+Modeling.prototype.getHandlers = function() {
+  var handlers = BaseModeling.prototype.getHandlers.call(this);
+
+  handlers['element.updateModdleProperties'] = UpdateModdlePropertiesHandler;
+  handlers['element.updateProperties'] = UpdatePropertiesHandler;
+  handlers['canvas.updateRoot'] = UpdateCanvasRootHandler;
+  handlers['lane.add'] = AddLaneHandler;
+  handlers['lane.resize'] = ResizeLaneHandler;
+  handlers['lane.split'] = SplitLaneHandler;
+  handlers['lane.updateRefs'] = UpdateFlowNodeRefsHandler;
+  handlers['id.updateClaim'] = IdClaimHandler;
+  handlers['element.setColor'] = SetColorHandler;
+  handlers['element.updateLabel'] = UpdateLabelHandler;
+
+  return handlers;
+};
+
+
+Modeling.prototype.updateLabel = function(element, newLabel, newBounds, hints) {
+  this._commandStack.execute('element.updateLabel', {
+    element: element,
+    newLabel: newLabel,
+    newBounds: newBounds,
+    hints: hints || {}
+  });
+};
+
+
+Modeling.prototype.connect = function(source, target, attrs, hints) {
+
+  var bpmnRules = this._bpmnRules;
+
+  if (!attrs) {
+    attrs = bpmnRules.canConnect(source, target);
+  }
+
+  if (!attrs) {
+    return;
+  }
+
+  return this.createConnection(source, target, attrs, source.parent, hints);
+};
+
+
+Modeling.prototype.updateModdleProperties = function(element, moddleElement, properties) {
+  this._commandStack.execute('element.updateModdleProperties', {
+    element: element,
+    moddleElement: moddleElement,
+    properties: properties
+  });
+};
+
+Modeling.prototype.updateProperties = function(element, properties) {
+  this._commandStack.execute('element.updateProperties', {
+    element: element,
+    properties: properties
+  });
+};
+
+Modeling.prototype.resizeLane = function(laneShape, newBounds, balanced) {
+  this._commandStack.execute('lane.resize', {
+    shape: laneShape,
+    newBounds: newBounds,
+    balanced: balanced
+  });
+};
+
+Modeling.prototype.addLane = function(targetLaneShape, location) {
+  var context = {
+    shape: targetLaneShape,
+    location: location
+  };
+
+  this._commandStack.execute('lane.add', context);
+
+  return context.newLane;
+};
+
+Modeling.prototype.splitLane = function(targetLane, count) {
+  this._commandStack.execute('lane.split', {
+    shape: targetLane,
+    count: count
+  });
+};
+
+/**
+ * Transform the current diagram into a collaboration.
+ *
+ * @return {djs.model.Root} the new root element
+ */
+Modeling.prototype.makeCollaboration = function() {
+
+  var collaborationElement = this._create('root', {
+    type: 'bpmn:Collaboration'
+  });
+
+  var context = {
+    newRoot: collaborationElement
+  };
+
+  this._commandStack.execute('canvas.updateRoot', context);
+
+  return collaborationElement;
+};
+
+Modeling.prototype.updateLaneRefs = function(flowNodeShapes, laneShapes) {
+
+  this._commandStack.execute('lane.updateRefs', {
+    flowNodeShapes: flowNodeShapes,
+    laneShapes: laneShapes
+  });
+};
+
+/**
+ * Transform the current diagram into a process.
+ *
+ * @return {djs.model.Root} the new root element
+ */
+Modeling.prototype.makeProcess = function() {
+
+  var processElement = this._create('root', {
+    type: 'bpmn:Process'
+  });
+
+  var context = {
+    newRoot: processElement
+  };
+
+  this._commandStack.execute('canvas.updateRoot', context);
+};
+
+
+Modeling.prototype.claimId = function(id, moddleElement) {
+  this._commandStack.execute('id.updateClaim', {
+    id: id,
+    element: moddleElement,
+    claiming: true
+  });
+};
+
+
+Modeling.prototype.unclaimId = function(id, moddleElement) {
+  this._commandStack.execute('id.updateClaim', {
+    id: id,
+    element: moddleElement
+  });
+};
+
+Modeling.prototype.setColor = function(elements, colors) {
+  if (!elements.length) {
+    elements = [ elements ];
+  }
+
+  this._commandStack.execute('element.setColor', {
+    elements: elements,
+    colors: colors
+  });
+};

+ 274 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/AdaptiveLabelPositioningBehavior.js

@@ -0,0 +1,274 @@
+import inherits from 'inherits-browser';
+
+import {
+  getOrientation,
+  getMid,
+  asTRBL
+} from 'diagram-js/lib/layout/LayoutUtil';
+
+import {
+  substract
+} from 'diagram-js/lib/util/Math';
+
+import {
+  hasExternalLabel
+} from '../../../util/LabelUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+var ALIGNMENTS = [
+  'top',
+  'bottom',
+  'left',
+  'right'
+];
+
+var ELEMENT_LABEL_DISTANCE = 10;
+
+/**
+ * A component that makes sure that external labels are added
+ * together with respective elements and properly updated (DI wise)
+ * during move.
+ *
+ * @param {EventBus} eventBus
+ * @param {Modeling} modeling
+ */
+export default function AdaptiveLabelPositioningBehavior(eventBus, modeling) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  this.postExecuted([
+    'connection.create',
+    'connection.layout',
+    'connection.updateWaypoints'
+  ], function(event) {
+    var context = event.context,
+        connection = context.connection,
+        source = connection.source,
+        target = connection.target,
+        hints = context.hints || {};
+
+    if (hints.createElementsBehavior !== false) {
+      checkLabelAdjustment(source);
+      checkLabelAdjustment(target);
+    }
+  });
+
+
+  this.postExecuted([
+    'label.create'
+  ], function(event) {
+    var context = event.context,
+        shape = context.shape,
+        hints = context.hints || {};
+
+    if (hints.createElementsBehavior !== false) {
+      checkLabelAdjustment(shape.labelTarget);
+    }
+  });
+
+
+  this.postExecuted([
+    'elements.create'
+  ], function(event) {
+    var context = event.context,
+        elements = context.elements,
+        hints = context.hints || {};
+
+    if (hints.createElementsBehavior !== false) {
+      elements.forEach(function(element) {
+        checkLabelAdjustment(element);
+      });
+    }
+  });
+
+  function checkLabelAdjustment(element) {
+
+    // skip non-existing labels
+    if (!hasExternalLabel(element)) {
+      return;
+    }
+
+    var optimalPosition = getOptimalPosition(element);
+
+    // no optimal position found
+    if (!optimalPosition) {
+      return;
+    }
+
+    adjustLabelPosition(element, optimalPosition);
+  }
+
+  function adjustLabelPosition(element, orientation) {
+
+    var elementMid = getMid(element),
+        label = element.label,
+        labelMid = getMid(label);
+
+    // ignore labels that are being created
+    if (!label.parent) {
+      return;
+    }
+
+    var elementTrbl = asTRBL(element);
+
+    var newLabelMid;
+
+    switch (orientation) {
+    case 'top':
+      newLabelMid = {
+        x: elementMid.x,
+        y: elementTrbl.top - ELEMENT_LABEL_DISTANCE - label.height / 2
+      };
+
+      break;
+
+    case 'left':
+
+      newLabelMid = {
+        x: elementTrbl.left - ELEMENT_LABEL_DISTANCE - label.width / 2,
+        y: elementMid.y
+      };
+
+      break;
+
+    case 'bottom':
+
+      newLabelMid = {
+        x: elementMid.x,
+        y: elementTrbl.bottom + ELEMENT_LABEL_DISTANCE + label.height / 2
+      };
+
+      break;
+
+    case 'right':
+
+      newLabelMid = {
+        x: elementTrbl.right + ELEMENT_LABEL_DISTANCE + label.width / 2,
+        y: elementMid.y
+      };
+
+      break;
+    }
+
+    var delta = substract(newLabelMid, labelMid);
+
+    modeling.moveShape(label, delta);
+  }
+
+}
+
+inherits(AdaptiveLabelPositioningBehavior, CommandInterceptor);
+
+AdaptiveLabelPositioningBehavior.$inject = [
+  'eventBus',
+  'modeling'
+];
+
+
+// helpers //////////////////////
+
+/**
+ * Return alignments which are taken by a boundary's host element
+ *
+ * @param {Shape} element
+ *
+ * @return {Array<string>}
+ */
+function getTakenHostAlignments(element) {
+
+  var hostElement = element.host,
+      elementMid = getMid(element),
+      hostOrientation = getOrientation(elementMid, hostElement);
+
+  var freeAlignments;
+
+  // check whether there is a multi-orientation, e.g. 'top-left'
+  if (hostOrientation.indexOf('-') >= 0) {
+    freeAlignments = hostOrientation.split('-');
+  } else {
+    freeAlignments = [ hostOrientation ];
+  }
+
+  var takenAlignments = ALIGNMENTS.filter(function(alignment) {
+
+    return freeAlignments.indexOf(alignment) === -1;
+  });
+
+  return takenAlignments;
+
+}
+
+/**
+ * Return alignments which are taken by related connections
+ *
+ * @param {Shape} element
+ *
+ * @return {Array<string>}
+ */
+function getTakenConnectionAlignments(element) {
+
+  var elementMid = getMid(element);
+
+  var takenAlignments = [].concat(
+    element.incoming.map(function(c) {
+      return c.waypoints[c.waypoints.length - 2 ];
+    }),
+    element.outgoing.map(function(c) {
+      return c.waypoints[1];
+    })
+  ).map(function(point) {
+    return getApproximateOrientation(elementMid, point);
+  });
+
+  return takenAlignments;
+}
+
+/**
+ * Return the optimal label position around an element
+ * or _undefined_, if none was found.
+ *
+ * @param  {Shape} element
+ *
+ * @return {string} positioning identifier
+ */
+function getOptimalPosition(element) {
+
+  var labelMid = getMid(element.label);
+
+  var elementMid = getMid(element);
+
+  var labelOrientation = getApproximateOrientation(elementMid, labelMid);
+
+  if (!isAligned(labelOrientation)) {
+    return;
+  }
+
+  var takenAlignments = getTakenConnectionAlignments(element);
+
+  if (element.host) {
+    var takenHostAlignments = getTakenHostAlignments(element);
+
+    takenAlignments = takenAlignments.concat(takenHostAlignments);
+  }
+
+  var freeAlignments = ALIGNMENTS.filter(function(alignment) {
+
+    return takenAlignments.indexOf(alignment) === -1;
+  });
+
+  // NOTHING TO DO; label already aligned a.O.K.
+  if (freeAlignments.indexOf(labelOrientation) !== -1) {
+    return;
+  }
+
+  return freeAlignments[0];
+}
+
+function getApproximateOrientation(p0, p1) {
+  return getOrientation(p1, p0, 5);
+}
+
+function isAligned(orientation) {
+  return ALIGNMENTS.indexOf(orientation) !== -1;
+}

+ 42 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/AppendBehavior.js

@@ -0,0 +1,42 @@
+import inherits from 'inherits-browser';
+
+import { is } from '../../../util/ModelUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+
+export default function AppendBehavior(eventBus, elementFactory, bpmnRules) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  // assign correct shape position unless already set
+
+  this.preExecute('shape.append', function(context) {
+
+    var source = context.source,
+        shape = context.shape;
+
+    if (!context.position) {
+
+      if (is(shape, 'bpmn:TextAnnotation')) {
+        context.position = {
+          x: source.x + source.width / 2 + 75,
+          y: source.y - (50) - shape.height / 2
+        };
+      } else {
+        context.position = {
+          x: source.x + source.width + 80 + shape.width / 2,
+          y: source.y + source.height / 2
+        };
+      }
+    }
+  }, true);
+}
+
+inherits(AppendBehavior, CommandInterceptor);
+
+AppendBehavior.$inject = [
+  'eventBus',
+  'elementFactory',
+  'bpmnRules'
+];

+ 35 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/AssociationBehavior.js

@@ -0,0 +1,35 @@
+import inherits from 'inherits-browser';
+
+import { is } from '../../../util/ModelUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import {
+  filter,
+  forEach
+} from 'min-dash';
+
+
+export default function AssociationBehavior(injector, modeling) {
+  injector.invoke(CommandInterceptor, this);
+
+  this.postExecute('shape.move', function(context) {
+    var newParent = context.newParent,
+        shape = context.shape;
+
+    var associations = filter(shape.incoming.concat(shape.outgoing), function(connection) {
+      return is(connection, 'bpmn:Association');
+    });
+
+    forEach(associations, function(association) {
+      modeling.moveConnection(association, { x: 0, y: 0 }, newParent);
+    });
+  }, true);
+}
+
+inherits(AssociationBehavior, CommandInterceptor);
+
+AssociationBehavior.$inject = [
+  'injector',
+  'modeling'
+];

+ 98 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/AttachEventBehavior.js

@@ -0,0 +1,98 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { getBusinessObject } from '../../../util/ModelUtil';
+
+import { isAny } from '../util/ModelingUtil';
+
+import { isLabel } from '../../../util/LabelUtil';
+
+var LOW_PRIORITY = 500;
+
+
+/**
+ * Replace intermediate event with boundary event when creating or moving results in attached event.
+ */
+export default function AttachEventBehavior(bpmnReplace, injector) {
+  injector.invoke(CommandInterceptor, this);
+
+  this._bpmnReplace = bpmnReplace;
+
+  var self = this;
+
+  this.postExecuted('elements.create', LOW_PRIORITY, function(context) {
+    var elements = context.elements;
+
+    elements = elements.filter(function(shape) {
+      var host = shape.host;
+
+      return shouldReplace(shape, host);
+    });
+
+    if (elements.length !== 1) {
+      return;
+    }
+
+    elements.map(function(element) {
+      return elements.indexOf(element);
+    }).forEach(function(index) {
+      var host = elements[ index ];
+
+      context.elements[ index ] = self.replaceShape(elements[ index ], host);
+    });
+  }, true);
+
+
+  this.preExecute('elements.move', LOW_PRIORITY, function(context) {
+    var shapes = context.shapes,
+        host = context.newHost;
+
+    if (shapes.length !== 1) {
+      return;
+    }
+
+    var shape = shapes[0];
+
+    if (shouldReplace(shape, host)) {
+      context.shapes = [ self.replaceShape(shape, host) ];
+    }
+  }, true);
+}
+
+AttachEventBehavior.$inject = [
+  'bpmnReplace',
+  'injector'
+];
+
+inherits(AttachEventBehavior, CommandInterceptor);
+
+AttachEventBehavior.prototype.replaceShape = function(shape, host) {
+  var eventDefinition = getEventDefinition(shape);
+
+  var boundaryEvent = {
+    type: 'bpmn:BoundaryEvent',
+    host: host
+  };
+
+  if (eventDefinition) {
+    boundaryEvent.eventDefinitionType = eventDefinition.$type;
+  }
+
+  return this._bpmnReplace.replaceElement(shape, boundaryEvent, { layoutConnection: false });
+};
+
+
+// helpers //////////
+
+function getEventDefinition(element) {
+  var businessObject = getBusinessObject(element),
+      eventDefinitions = businessObject.eventDefinitions;
+
+  return eventDefinitions && eventDefinitions[0];
+}
+
+function shouldReplace(shape, host) {
+  return !isLabel(shape) &&
+    isAny(shape, [ 'bpmn:IntermediateThrowEvent', 'bpmn:IntermediateCatchEvent' ]) && !!host;
+}

+ 68 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/BoundaryEventBehavior.js

@@ -0,0 +1,68 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { is } from '../../../util/ModelUtil';
+
+import {
+  filter,
+  forEach
+} from 'min-dash';
+
+
+/**
+ * BPMN specific boundary event behavior
+ */
+export default function BoundaryEventBehavior(eventBus, modeling) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  function getBoundaryEvents(element) {
+    return filter(element.attachers, function(attacher) {
+      return is(attacher, 'bpmn:BoundaryEvent');
+    });
+  }
+
+  // remove after connecting to event-based gateway
+  this.postExecute('connection.create', function(event) {
+    var source = event.context.source,
+        target = event.context.target,
+        boundaryEvents = getBoundaryEvents(target);
+
+    if (
+      is(source, 'bpmn:EventBasedGateway') &&
+      is(target, 'bpmn:ReceiveTask') &&
+      boundaryEvents.length > 0
+    ) {
+      modeling.removeElements(boundaryEvents);
+    }
+
+  });
+
+  // remove after replacing connected gateway with event-based gateway
+  this.postExecute('connection.reconnect', function(event) {
+    var oldSource = event.context.oldSource,
+        newSource = event.context.newSource;
+
+    if (is(oldSource, 'bpmn:Gateway') &&
+        is(newSource, 'bpmn:EventBasedGateway')) {
+      forEach(newSource.outgoing, function(connection) {
+        var target = connection.target,
+            attachedboundaryEvents = getBoundaryEvents(target);
+
+        if (is(target, 'bpmn:ReceiveTask') &&
+            attachedboundaryEvents.length > 0) {
+          modeling.removeElements(attachedboundaryEvents);
+        }
+      });
+    }
+  });
+
+}
+
+BoundaryEventBehavior.$inject = [
+  'eventBus',
+  'modeling'
+];
+
+inherits(BoundaryEventBehavior, CommandInterceptor);

+ 28 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/CreateBehavior.js

@@ -0,0 +1,28 @@
+import inherits from 'inherits-browser';
+
+import { is } from '../../../util/ModelUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { getParent } from '../util/ModelingUtil';
+
+
+export default function CreateBehavior(injector) {
+  injector.invoke(CommandInterceptor, this);
+
+  this.preExecute('shape.create', 1500, function(event) {
+    var context = event.context,
+        parent = context.parent,
+        shape = context.shape;
+
+    if (is(parent, 'bpmn:Lane') && !is(shape, 'bpmn:Lane')) {
+      context.parent = getParent(parent, 'bpmn:Participant');
+    }
+  });
+
+}
+
+
+CreateBehavior.$inject = [ 'injector' ];
+
+inherits(CreateBehavior, CommandInterceptor);

+ 38 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/CreateDataObjectBehavior.js

@@ -0,0 +1,38 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { is } from '../../../util/ModelUtil';
+
+
+/**
+ * BPMN specific create data object behavior
+ */
+export default function CreateDataObjectBehavior(eventBus, bpmnFactory, moddle) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  this.preExecute('shape.create', function(event) {
+
+    var context = event.context,
+        shape = context.shape;
+
+    if (is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
+
+      // create a DataObject every time a DataObjectReference is created
+      var dataObject = bpmnFactory.create('bpmn:DataObject');
+
+      // set the reference to the DataObject
+      shape.businessObject.dataObjectRef = dataObject;
+    }
+  });
+
+}
+
+CreateDataObjectBehavior.$inject = [
+  'eventBus',
+  'bpmnFactory',
+  'moddle'
+];
+
+inherits(CreateDataObjectBehavior, CommandInterceptor);

+ 230 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/CreateParticipantBehavior.js

@@ -0,0 +1,230 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { getBusinessObject, is } from '../../../util/ModelUtil';
+
+import { isLabel } from '../../../util/LabelUtil';
+
+import { getBBox } from 'diagram-js/lib/util/Elements';
+
+import {
+  assign,
+  find
+} from 'min-dash';
+
+import { asTRBL } from 'diagram-js/lib/layout/LayoutUtil';
+
+var HORIZONTAL_PARTICIPANT_PADDING = 20,
+    VERTICAL_PARTICIPANT_PADDING = 20;
+
+export var PARTICIPANT_BORDER_WIDTH = 30;
+
+var HIGH_PRIORITY = 2000;
+
+
+/**
+ * BPMN-specific behavior for creating participants.
+ */
+export default function CreateParticipantBehavior(canvas, eventBus, modeling) {
+  CommandInterceptor.call(this, eventBus);
+
+  // fit participant
+  eventBus.on([
+    'create.start',
+    'shape.move.start'
+  ], HIGH_PRIORITY, function(event) {
+    var context = event.context,
+        shape = context.shape,
+        rootElement = canvas.getRootElement();
+
+    if (!is(shape, 'bpmn:Participant') ||
+      !is(rootElement, 'bpmn:Process') ||
+      !rootElement.children.length) {
+      return;
+    }
+
+    // ignore connections, groups and labels
+    var children = rootElement.children.filter(function(element) {
+      return !is(element, 'bpmn:Group') &&
+        !isLabel(element) &&
+        !isConnection(element);
+    });
+
+    // ensure for available children to calculate bounds
+    if (!children.length) {
+      return;
+    }
+
+    var childrenBBox = getBBox(children);
+
+    var participantBounds = getParticipantBounds(shape, childrenBBox);
+
+    // assign width and height
+    assign(shape, participantBounds);
+
+    // assign create constraints
+    context.createConstraints = getParticipantCreateConstraints(shape, childrenBBox);
+  });
+
+  // force hovering process when creating first participant
+  eventBus.on('create.start', HIGH_PRIORITY, function(event) {
+    var context = event.context,
+        shape = context.shape,
+        rootElement = canvas.getRootElement(),
+        rootElementGfx = canvas.getGraphics(rootElement);
+
+    function ensureHoveringProcess(event) {
+      event.element = rootElement;
+      event.gfx = rootElementGfx;
+    }
+
+    if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) {
+      eventBus.on('element.hover', HIGH_PRIORITY, ensureHoveringProcess);
+
+      eventBus.once('create.cleanup', function() {
+        eventBus.off('element.hover', ensureHoveringProcess);
+      });
+    }
+  });
+
+  // turn process into collaboration when creating first participant
+  function getOrCreateCollaboration() {
+    var rootElement = canvas.getRootElement();
+
+    if (is(rootElement, 'bpmn:Collaboration')) {
+      return rootElement;
+    }
+
+    return modeling.makeCollaboration();
+  }
+
+  // when creating mutliple elements through `elements.create` parent must be set to collaboration
+  // and passed to `shape.create` as hint
+  this.preExecute('elements.create', HIGH_PRIORITY, function(context) {
+    var elements = context.elements,
+        parent = context.parent,
+        participant = findParticipant(elements),
+        hints;
+
+    if (participant && is(parent, 'bpmn:Process')) {
+      context.parent = getOrCreateCollaboration();
+
+      hints = context.hints = context.hints || {};
+
+      hints.participant = participant;
+      hints.process = parent;
+      hints.processRef = getBusinessObject(participant).get('processRef');
+    }
+  }, true);
+
+  // when creating single shape through `shape.create` parent must be set to collaboration
+  // unless it was already set through `elements.create`
+  this.preExecute('shape.create', function(context) {
+    var parent = context.parent,
+        shape = context.shape;
+
+    if (is(shape, 'bpmn:Participant') && is(parent, 'bpmn:Process')) {
+      context.parent = getOrCreateCollaboration();
+
+      context.process = parent;
+      context.processRef = getBusinessObject(shape).get('processRef');
+    }
+  }, true);
+
+  // #execute necessary because #preExecute not called on CommandStack#redo
+  this.execute('shape.create', function(context) {
+    var hints = context.hints || {},
+        process = context.process || hints.process,
+        shape = context.shape,
+        participant = hints.participant;
+
+    // both shape.create and elements.create must be handled
+    if (process && (!participant || shape === participant)) {
+
+      // monkey-patch process ref
+      getBusinessObject(shape).set('processRef', getBusinessObject(process));
+    }
+  }, true);
+
+  this.revert('shape.create', function(context) {
+    var hints = context.hints || {},
+        process = context.process || hints.process,
+        processRef = context.processRef || hints.processRef,
+        shape = context.shape,
+        participant = hints.participant;
+
+    // both shape.create and elements.create must be handled
+    if (process && (!participant || shape === participant)) {
+
+      // monkey-patch process ref
+      getBusinessObject(shape).set('processRef', processRef);
+    }
+  }, true);
+
+  this.postExecute('shape.create', function(context) {
+    var hints = context.hints || {},
+        process = context.process || context.hints.process,
+        shape = context.shape,
+        participant = hints.participant;
+
+    if (process) {
+      var children = process.children.slice();
+
+      // both shape.create and elements.create must be handled
+      if (!participant) {
+        modeling.moveElements(children, { x: 0, y: 0 }, shape);
+      } else if (shape === participant) {
+        modeling.moveElements(children, { x: 0, y: 0 }, participant);
+      }
+    }
+  }, true);
+}
+
+CreateParticipantBehavior.$inject = [
+  'canvas',
+  'eventBus',
+  'modeling'
+];
+
+inherits(CreateParticipantBehavior, CommandInterceptor);
+
+// helpers //////////
+
+function getParticipantBounds(shape, childrenBBox) {
+  childrenBBox = {
+    width: childrenBBox.width + HORIZONTAL_PARTICIPANT_PADDING * 2 + PARTICIPANT_BORDER_WIDTH,
+    height: childrenBBox.height + VERTICAL_PARTICIPANT_PADDING * 2
+  };
+
+  var width = Math.max(shape.width, childrenBBox.width),
+      height = Math.max(shape.height, childrenBBox.height);
+
+  return {
+    x: -width / 2,
+    y: -height / 2,
+    width: width,
+    height: height
+  };
+}
+
+function getParticipantCreateConstraints(shape, childrenBBox) {
+  childrenBBox = asTRBL(childrenBBox);
+
+  return {
+    bottom: childrenBBox.top + shape.height / 2 - VERTICAL_PARTICIPANT_PADDING,
+    left: childrenBBox.right - shape.width / 2 + HORIZONTAL_PARTICIPANT_PADDING,
+    top: childrenBBox.bottom - shape.height / 2 + VERTICAL_PARTICIPANT_PADDING,
+    right: childrenBBox.left + shape.width / 2 - HORIZONTAL_PARTICIPANT_PADDING - PARTICIPANT_BORDER_WIDTH
+  };
+}
+
+function isConnection(element) {
+  return !!element.waypoints;
+}
+
+function findParticipant(elements) {
+  return find(elements, function(element) {
+    return is(element, 'bpmn:Participant');
+  });
+}

+ 158 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DataInputAssociationBehavior.js

@@ -0,0 +1,158 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import {
+  add as collectionAdd,
+  remove as collectionRemove
+} from 'diagram-js/lib/util/Collections';
+
+import {
+  find
+} from 'min-dash';
+
+import {
+  is
+} from '../../../util/ModelUtil';
+
+var TARGET_REF_PLACEHOLDER_NAME = '__targetRef_placeholder';
+
+
+/**
+ * This behavior makes sure we always set a fake
+ * DataInputAssociation#targetRef as demanded by the BPMN 2.0
+ * XSD schema.
+ *
+ * The reference is set to a bpmn:Property{ name: '__targetRef_placeholder' }
+ * which is created on the fly and cleaned up afterwards if not needed
+ * anymore.
+ *
+ * @param {EventBus} eventBus
+ * @param {BpmnFactory} bpmnFactory
+ */
+export default function DataInputAssociationBehavior(eventBus, bpmnFactory) {
+
+  CommandInterceptor.call(this, eventBus);
+
+
+  this.executed([
+    'connection.create',
+    'connection.delete',
+    'connection.move',
+    'connection.reconnect'
+  ], ifDataInputAssociation(fixTargetRef));
+
+  this.reverted([
+    'connection.create',
+    'connection.delete',
+    'connection.move',
+    'connection.reconnect'
+  ], ifDataInputAssociation(fixTargetRef));
+
+
+  function usesTargetRef(element, targetRef, removedConnection) {
+
+    var inputAssociations = element.get('dataInputAssociations');
+
+    return find(inputAssociations, function(association) {
+      return association !== removedConnection &&
+             association.targetRef === targetRef;
+    });
+  }
+
+  function getTargetRef(element, create) {
+
+    var properties = element.get('properties');
+
+    var targetRefProp = find(properties, function(p) {
+      return p.name === TARGET_REF_PLACEHOLDER_NAME;
+    });
+
+    if (!targetRefProp && create) {
+      targetRefProp = bpmnFactory.create('bpmn:Property', {
+        name: TARGET_REF_PLACEHOLDER_NAME
+      });
+
+      collectionAdd(properties, targetRefProp);
+    }
+
+    return targetRefProp;
+  }
+
+  function cleanupTargetRef(element, connection) {
+
+    var targetRefProp = getTargetRef(element);
+
+    if (!targetRefProp) {
+      return;
+    }
+
+    if (!usesTargetRef(element, targetRefProp, connection)) {
+      collectionRemove(element.get('properties'), targetRefProp);
+    }
+  }
+
+  /**
+   * Make sure targetRef is set to a valid property or
+   * `null` if the connection is detached.
+   *
+   * @param {Event} event
+   */
+  function fixTargetRef(event) {
+
+    var context = event.context,
+        connection = context.connection,
+        connectionBo = connection.businessObject,
+        target = connection.target,
+        targetBo = target && target.businessObject,
+        newTarget = context.newTarget,
+        newTargetBo = newTarget && newTarget.businessObject,
+        oldTarget = context.oldTarget || context.target,
+        oldTargetBo = oldTarget && oldTarget.businessObject;
+
+    var dataAssociation = connection.businessObject,
+        targetRefProp;
+
+    if (oldTargetBo && oldTargetBo !== targetBo) {
+      cleanupTargetRef(oldTargetBo, connectionBo);
+    }
+
+    if (newTargetBo && newTargetBo !== targetBo) {
+      cleanupTargetRef(newTargetBo, connectionBo);
+    }
+
+    if (targetBo) {
+      targetRefProp = getTargetRef(targetBo, true);
+      dataAssociation.targetRef = targetRefProp;
+    } else {
+      dataAssociation.targetRef = null;
+    }
+  }
+}
+
+DataInputAssociationBehavior.$inject = [
+  'eventBus',
+  'bpmnFactory'
+];
+
+inherits(DataInputAssociationBehavior, CommandInterceptor);
+
+
+/**
+ * Only call the given function when the event
+ * touches a bpmn:DataInputAssociation.
+ *
+ * @param {Function} fn
+ * @return {Function}
+ */
+function ifDataInputAssociation(fn) {
+
+  return function(event) {
+    var context = event.context,
+        connection = context.connection;
+
+    if (is(connection, 'bpmn:DataInputAssociation')) {
+      return fn(event);
+    }
+  };
+}

+ 212 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DataStoreBehavior.js

@@ -0,0 +1,212 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import {
+  getBusinessObject,
+  getDi,
+  is
+} from '../../../util/ModelUtil';
+
+import { isAny } from '../util/ModelingUtil';
+
+import UpdateSemanticParentHandler from '../cmd/UpdateSemanticParentHandler';
+
+
+/**
+ * BPMN specific data store behavior
+ */
+export default function DataStoreBehavior(
+    canvas, commandStack, elementRegistry,
+    eventBus) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  commandStack.registerHandler('dataStore.updateContainment', UpdateSemanticParentHandler);
+
+  function getFirstParticipantWithProcessRef() {
+    return elementRegistry.filter(function(element) {
+      return is(element, 'bpmn:Participant') && getBusinessObject(element).processRef;
+    })[0];
+  }
+
+  function getDataStores(element) {
+    return element.children.filter(function(child) {
+      return is(child, 'bpmn:DataStoreReference') && !child.labelTarget;
+    });
+  }
+
+  function updateDataStoreParent(dataStore, newDataStoreParent) {
+    var dataStoreBo = dataStore.businessObject || dataStore;
+
+    newDataStoreParent = newDataStoreParent || getFirstParticipantWithProcessRef();
+
+    if (newDataStoreParent) {
+      var newDataStoreParentBo = newDataStoreParent.businessObject || newDataStoreParent;
+
+      commandStack.execute('dataStore.updateContainment', {
+        dataStoreBo: dataStoreBo,
+        dataStoreDi: getDi(dataStore),
+        newSemanticParent: newDataStoreParentBo.processRef || newDataStoreParentBo,
+        newDiParent: getDi(newDataStoreParent)
+      });
+    }
+  }
+
+
+  // disable auto-resize for data stores
+  this.preExecute('shape.create', function(event) {
+
+    var context = event.context,
+        shape = context.shape;
+
+    if (is(shape, 'bpmn:DataStoreReference') &&
+        shape.type !== 'label') {
+
+      if (!context.hints) {
+        context.hints = {};
+      }
+
+      // prevent auto resizing
+      context.hints.autoResize = false;
+    }
+  });
+
+
+  // disable auto-resize for data stores
+  this.preExecute('elements.move', function(event) {
+    var context = event.context,
+        shapes = context.shapes;
+
+    var dataStoreReferences = shapes.filter(function(shape) {
+      return is(shape, 'bpmn:DataStoreReference');
+    });
+
+    if (dataStoreReferences.length) {
+      if (!context.hints) {
+        context.hints = {};
+      }
+
+      // prevent auto resizing for data store references
+      context.hints.autoResize = shapes.filter(function(shape) {
+        return !is(shape, 'bpmn:DataStoreReference');
+      });
+    }
+  });
+
+
+  // update parent on data store created
+  this.postExecute('shape.create', function(event) {
+    var context = event.context,
+        shape = context.shape,
+        parent = shape.parent;
+
+
+    if (is(shape, 'bpmn:DataStoreReference') &&
+        shape.type !== 'label' &&
+        is(parent, 'bpmn:Collaboration')) {
+
+      updateDataStoreParent(shape);
+    }
+  });
+
+
+  // update parent on data store moved
+  this.postExecute('shape.move', function(event) {
+    var context = event.context,
+        shape = context.shape,
+        oldParent = context.oldParent,
+        parent = shape.parent;
+
+    if (is(oldParent, 'bpmn:Collaboration')) {
+
+      // do nothing if not necessary
+      return;
+    }
+
+    if (is(shape, 'bpmn:DataStoreReference') &&
+        shape.type !== 'label' &&
+        is(parent, 'bpmn:Collaboration')) {
+
+      var participant = is(oldParent, 'bpmn:Participant') ?
+        oldParent :
+        getAncestor(oldParent, 'bpmn:Participant');
+
+      updateDataStoreParent(shape, participant);
+    }
+  });
+
+
+  // update data store parents on participant or subprocess deleted
+  this.postExecute('shape.delete', function(event) {
+    var context = event.context,
+        shape = context.shape,
+        rootElement = canvas.getRootElement();
+
+    if (isAny(shape, [ 'bpmn:Participant', 'bpmn:SubProcess' ])
+        && is(rootElement, 'bpmn:Collaboration')) {
+      getDataStores(rootElement)
+        .filter(function(dataStore) {
+          return isDescendant(dataStore, shape);
+        })
+        .forEach(function(dataStore) {
+          updateDataStoreParent(dataStore);
+        });
+    }
+  });
+
+  // update data store parents on collaboration -> process
+  this.postExecute('canvas.updateRoot', function(event) {
+    var context = event.context,
+        oldRoot = context.oldRoot,
+        newRoot = context.newRoot;
+
+    var dataStores = getDataStores(oldRoot);
+
+    dataStores.forEach(function(dataStore) {
+
+      if (is(newRoot, 'bpmn:Process')) {
+        updateDataStoreParent(dataStore, newRoot);
+      }
+
+    });
+  });
+}
+
+DataStoreBehavior.$inject = [
+  'canvas',
+  'commandStack',
+  'elementRegistry',
+  'eventBus',
+];
+
+inherits(DataStoreBehavior, CommandInterceptor);
+
+
+// helpers //////////
+
+function isDescendant(descendant, ancestor) {
+  var descendantBo = descendant.businessObject || descendant,
+      ancestorBo = ancestor.businessObject || ancestor;
+
+  while (descendantBo.$parent) {
+    if (descendantBo.$parent === ancestorBo.processRef || ancestorBo) {
+      return true;
+    }
+
+    descendantBo = descendantBo.$parent;
+  }
+
+  return false;
+}
+
+function getAncestor(element, type) {
+
+  while (element.parent) {
+    if (is(element.parent, type)) {
+      return element.parent;
+    }
+
+    element = element.parent;
+  }
+}

+ 112 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DeleteLaneBehavior.js

@@ -0,0 +1,112 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { is } from '../../../util/ModelUtil';
+
+import {
+  getChildLanes
+} from '../util/LaneUtil';
+
+import {
+  eachElement
+} from 'diagram-js/lib/util/Elements';
+
+
+var LOW_PRIORITY = 500;
+
+
+/**
+ * BPMN specific delete lane behavior
+ */
+export default function DeleteLaneBehavior(eventBus, modeling, spaceTool) {
+
+  CommandInterceptor.call(this, eventBus);
+
+
+  function compensateLaneDelete(shape, oldParent) {
+
+    var siblings = getChildLanes(oldParent);
+
+    var topAffected = [];
+    var bottomAffected = [];
+
+    eachElement(siblings, function(element) {
+
+      if (element.y > shape.y) {
+        bottomAffected.push(element);
+      } else {
+        topAffected.push(element);
+      }
+
+      return element.children;
+    });
+
+    if (!siblings.length) {
+      return;
+    }
+
+    var offset;
+
+    if (bottomAffected.length && topAffected.length) {
+      offset = shape.height / 2;
+    } else {
+      offset = shape.height;
+    }
+
+    var topAdjustments,
+        bottomAdjustments;
+
+    if (topAffected.length) {
+      topAdjustments = spaceTool.calculateAdjustments(
+        topAffected, 'y', offset, shape.y - 10);
+
+      spaceTool.makeSpace(
+        topAdjustments.movingShapes,
+        topAdjustments.resizingShapes,
+        { x: 0, y: offset }, 's');
+    }
+
+    if (bottomAffected.length) {
+      bottomAdjustments = spaceTool.calculateAdjustments(
+        bottomAffected, 'y', -offset, shape.y + shape.height + 10);
+
+      spaceTool.makeSpace(
+        bottomAdjustments.movingShapes,
+        bottomAdjustments.resizingShapes,
+        { x: 0, y: -offset }, 'n');
+    }
+  }
+
+
+  /**
+   * Adjust sizes of other lanes after lane deletion
+   */
+  this.postExecuted('shape.delete', LOW_PRIORITY, function(event) {
+
+    var context = event.context,
+        hints = context.hints,
+        shape = context.shape,
+        oldParent = context.oldParent;
+
+    // only compensate lane deletes
+    if (!is(shape, 'bpmn:Lane')) {
+      return;
+    }
+
+    // compensate root deletes only
+    if (hints && hints.nested) {
+      return;
+    }
+
+    compensateLaneDelete(shape, oldParent);
+  });
+}
+
+DeleteLaneBehavior.$inject = [
+  'eventBus',
+  'modeling',
+  'spaceTool'
+];
+
+inherits(DeleteLaneBehavior, CommandInterceptor);

+ 94 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DetachEventBehavior.js

@@ -0,0 +1,94 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import {
+  getBusinessObject,
+  is
+} from '../../../util/ModelUtil';
+
+import { isLabel } from '../../../util/LabelUtil';
+
+var LOW_PRIORITY = 500;
+
+
+/**
+ * Replace boundary event with intermediate event when creating or moving results in detached event.
+ */
+export default function DetachEventBehavior(bpmnReplace, injector) {
+  injector.invoke(CommandInterceptor, this);
+
+  this._bpmnReplace = bpmnReplace;
+
+  var self = this;
+
+  this.postExecuted('elements.create', LOW_PRIORITY, function(context) {
+    var elements = context.elements;
+
+    elements.filter(function(shape) {
+      var host = shape.host;
+
+      return shouldReplace(shape, host);
+    }).map(function(shape) {
+      return elements.indexOf(shape);
+    }).forEach(function(index) {
+      context.elements[ index ] = self.replaceShape(elements[ index ]);
+    });
+  }, true);
+
+  this.preExecute('elements.move', LOW_PRIORITY, function(context) {
+    var shapes = context.shapes,
+        newHost = context.newHost;
+
+    shapes.forEach(function(shape, index) {
+      var host = shape.host;
+
+      if (shouldReplace(shape, includes(shapes, host) ? host : newHost)) {
+        shapes[ index ] = self.replaceShape(shape);
+      }
+    });
+  }, true);
+}
+
+DetachEventBehavior.$inject = [
+  'bpmnReplace',
+  'injector'
+];
+
+inherits(DetachEventBehavior, CommandInterceptor);
+
+DetachEventBehavior.prototype.replaceShape = function(shape) {
+  var eventDefinition = getEventDefinition(shape),
+      intermediateEvent;
+
+  if (eventDefinition) {
+    intermediateEvent = {
+      type: 'bpmn:IntermediateCatchEvent',
+      eventDefinitionType: eventDefinition.$type
+    };
+  } else {
+    intermediateEvent = {
+      type: 'bpmn:IntermediateThrowEvent'
+    };
+  }
+
+  return this._bpmnReplace.replaceElement(shape, intermediateEvent, { layoutConnection: false });
+};
+
+
+// helpers //////////
+
+function getEventDefinition(element) {
+  var businessObject = getBusinessObject(element),
+      eventDefinitions = businessObject.eventDefinitions;
+
+  return eventDefinitions && eventDefinitions[0];
+}
+
+function shouldReplace(shape, host) {
+  return !isLabel(shape) && is(shape, 'bpmn:BoundaryEvent') && !host;
+}
+
+function includes(array, item) {
+  return array.indexOf(item) !== -1;
+}

+ 211 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/DropOnFlowBehavior.js

@@ -0,0 +1,211 @@
+import inherits from 'inherits-browser';
+
+import {
+  assign,
+  filter,
+  find,
+  isNumber
+} from 'min-dash';
+
+import { getMid } from 'diagram-js/lib/layout/LayoutUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import {
+  getApproxIntersection
+} from 'diagram-js/lib/util/LineIntersection';
+
+
+export default function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  /**
+   * Reconnect start / end of a connection after
+   * dropping an element on a flow.
+   */
+
+  function insertShape(shape, targetFlow, positionOrBounds) {
+    var waypoints = targetFlow.waypoints,
+        waypointsBefore,
+        waypointsAfter,
+        dockingPoint,
+        source,
+        target,
+        incomingConnection,
+        outgoingConnection,
+        oldOutgoing = shape.outgoing.slice(),
+        oldIncoming = shape.incoming.slice();
+
+    var mid;
+
+    if (isNumber(positionOrBounds.width)) {
+      mid = getMid(positionOrBounds);
+    } else {
+      mid = positionOrBounds;
+    }
+
+    var intersection = getApproxIntersection(waypoints, mid);
+
+    if (intersection) {
+      waypointsBefore = waypoints.slice(0, intersection.index);
+      waypointsAfter = waypoints.slice(intersection.index + (intersection.bendpoint ? 1 : 0));
+
+      // due to inaccuracy intersection might have been found
+      if (!waypointsBefore.length || !waypointsAfter.length) {
+        return;
+      }
+
+      dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : mid;
+
+      // if last waypointBefore is inside shape's bounds, ignore docking point
+      if (waypointsBefore.length === 1 || !isPointInsideBBox(shape, waypointsBefore[waypointsBefore.length - 1])) {
+        waypointsBefore.push(copy(dockingPoint));
+      }
+
+      // if first waypointAfter is inside shape's bounds, ignore docking point
+      if (waypointsAfter.length === 1 || !isPointInsideBBox(shape, waypointsAfter[0])) {
+        waypointsAfter.unshift(copy(dockingPoint));
+      }
+    }
+
+    source = targetFlow.source;
+    target = targetFlow.target;
+
+    if (bpmnRules.canConnect(source, shape, targetFlow)) {
+
+      // reconnect source -> inserted shape
+      modeling.reconnectEnd(targetFlow, shape, waypointsBefore || mid);
+
+      incomingConnection = targetFlow;
+    }
+
+    if (bpmnRules.canConnect(shape, target, targetFlow)) {
+
+      if (!incomingConnection) {
+
+        // reconnect inserted shape -> end
+        modeling.reconnectStart(targetFlow, shape, waypointsAfter || mid);
+
+        outgoingConnection = targetFlow;
+      } else {
+        outgoingConnection = modeling.connect(
+          shape, target, { type: targetFlow.type, waypoints: waypointsAfter }
+        );
+      }
+    }
+
+    var duplicateConnections = [].concat(
+
+      incomingConnection && filter(oldIncoming, function(connection) {
+        return connection.source === incomingConnection.source;
+      }) || [],
+
+      outgoingConnection && filter(oldOutgoing, function(connection) {
+        return connection.target === outgoingConnection.target;
+      }) || []
+    );
+
+    if (duplicateConnections.length) {
+      modeling.removeElements(duplicateConnections);
+    }
+  }
+
+  this.preExecute('elements.move', function(context) {
+
+    var newParent = context.newParent,
+        shapes = context.shapes,
+        delta = context.delta,
+        shape = shapes[0];
+
+    if (!shape || !newParent) {
+      return;
+    }
+
+    // if the new parent is a connection,
+    // change it to the new parent's parent
+    if (newParent && newParent.waypoints) {
+      context.newParent = newParent = newParent.parent;
+    }
+
+    var shapeMid = getMid(shape);
+    var newShapeMid = {
+      x: shapeMid.x + delta.x,
+      y: shapeMid.y + delta.y
+    };
+
+    // find a connection which intersects with the
+    // element's mid point
+    var connection = find(newParent.children, function(element) {
+      var canInsert = bpmnRules.canInsert(shapes, element);
+
+      return canInsert && getApproxIntersection(element.waypoints, newShapeMid);
+    });
+
+    if (connection) {
+      context.targetFlow = connection;
+      context.position = newShapeMid;
+    }
+
+  }, true);
+
+  this.postExecuted('elements.move', function(context) {
+
+    var shapes = context.shapes,
+        targetFlow = context.targetFlow,
+        position = context.position;
+
+    if (targetFlow) {
+      insertShape(shapes[0], targetFlow, position);
+    }
+
+  }, true);
+
+  this.preExecute('shape.create', function(context) {
+
+    var parent = context.parent,
+        shape = context.shape;
+
+    if (bpmnRules.canInsert(shape, parent)) {
+      context.targetFlow = parent;
+      context.parent = parent.parent;
+    }
+  }, true);
+
+  this.postExecuted('shape.create', function(context) {
+
+    var shape = context.shape,
+        targetFlow = context.targetFlow,
+        positionOrBounds = context.position;
+
+    if (targetFlow) {
+      insertShape(shape, targetFlow, positionOrBounds);
+    }
+  }, true);
+}
+
+inherits(DropOnFlowBehavior, CommandInterceptor);
+
+DropOnFlowBehavior.$inject = [
+  'eventBus',
+  'bpmnRules',
+  'modeling'
+];
+
+
+// helpers /////////////////////
+
+function isPointInsideBBox(bbox, point) {
+  var x = point.x,
+      y = point.y;
+
+  return x >= bbox.x &&
+    x <= bbox.x + bbox.width &&
+    y >= bbox.y &&
+    y <= bbox.y + bbox.height;
+}
+
+function copy(obj) {
+  return assign({}, obj);
+}
+

+ 85 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/EventBasedGatewayBehavior.js

@@ -0,0 +1,85 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { is } from '../../../util/ModelUtil';
+
+export default function EventBasedGatewayBehavior(eventBus, modeling) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  /**
+   * Remove existing sequence flows of event-based target before connecting
+   * from event-based gateway.
+   */
+  this.preExecuted('connection.create', function(event) {
+
+    var context = event.context,
+        source = context.source,
+        target = context.target,
+        existingIncomingConnections = target.incoming.slice();
+
+    if (context.hints && context.hints.createElementsBehavior === false) {
+      return;
+    }
+
+    if (
+      is(source, 'bpmn:EventBasedGateway') &&
+      target.incoming.length
+    ) {
+
+      existingIncomingConnections.filter(isSequenceFlow)
+        .forEach(function(sequenceFlow) {
+          modeling.removeConnection(sequenceFlow);
+        });
+    }
+  });
+
+  /**
+   *  After replacing shape with event-based gateway, remove incoming sequence
+   *  flows of event-based targets which do not belong to event-based gateway
+   *  source.
+   */
+  this.preExecuted('shape.replace', function(event) {
+
+    var newShape = event.context.newShape,
+        newShapeTargets,
+        newShapeTargetsIncomingSequenceFlows;
+
+    if (!is(newShape, 'bpmn:EventBasedGateway')) {
+      return;
+    }
+
+    newShapeTargets = newShape.outgoing.filter(isSequenceFlow)
+      .map(function(sequenceFlow) {
+        return sequenceFlow.target;
+      });
+
+    newShapeTargetsIncomingSequenceFlows = newShapeTargets.reduce(function(sequenceFlows, target) {
+      var incomingSequenceFlows = target.incoming.filter(isSequenceFlow);
+
+      return sequenceFlows.concat(incomingSequenceFlows);
+    }, []);
+
+    newShapeTargetsIncomingSequenceFlows.forEach(function(sequenceFlow) {
+      if (sequenceFlow.source !== newShape) {
+        modeling.removeConnection(sequenceFlow);
+      }
+    });
+  });
+}
+
+EventBasedGatewayBehavior.$inject = [
+  'eventBus',
+  'modeling'
+];
+
+inherits(EventBasedGatewayBehavior, CommandInterceptor);
+
+
+
+// helpers //////////////////////
+
+function isSequenceFlow(connection) {
+  return is(connection, 'bpmn:SequenceFlow');
+}

+ 117 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/FixHoverBehavior.js

@@ -0,0 +1,117 @@
+import { getLanesRoot } from '../util/LaneUtil';
+
+import { is } from '../../../util/ModelUtil';
+
+import { isAny } from '../util/ModelingUtil';
+
+var HIGH_PRIORITY = 1500;
+var HIGHEST_PRIORITY = 2000;
+
+
+/**
+ * Correct hover targets in certain situations to improve diagram interaction.
+ *
+ * @param {ElementRegistry} elementRegistry
+ * @param {EventBus} eventBus
+ * @param {Canvas} canvas
+ */
+export default function FixHoverBehavior(elementRegistry, eventBus, canvas) {
+
+  eventBus.on([
+    'create.hover',
+    'create.move',
+    'create.out',
+    'create.end',
+    'shape.move.hover',
+    'shape.move.move',
+    'shape.move.out',
+    'shape.move.end'
+  ], HIGH_PRIORITY, function(event) {
+    var context = event.context,
+        shape = context.shape || event.shape,
+        hover = event.hover;
+
+    // ensure elements are not dropped onto a bpmn:Lane but onto
+    // the underlying bpmn:Participant
+    if (is(hover, 'bpmn:Lane') && !isAny(shape, [ 'bpmn:Lane', 'bpmn:Participant' ])) {
+      event.hover = getLanesRoot(hover);
+      event.hoverGfx = elementRegistry.getGraphics(event.hover);
+    }
+
+    var rootElement = canvas.getRootElement();
+
+    // ensure bpmn:Group and label elements are dropped
+    // always onto the root
+    if (hover !== rootElement && (shape.labelTarget || is(shape, 'bpmn:Group'))) {
+      event.hover = rootElement;
+      event.hoverGfx = elementRegistry.getGraphics(event.hover);
+    }
+  });
+
+  eventBus.on([
+    'connect.hover',
+    'connect.out',
+    'connect.end',
+    'connect.cleanup',
+    'global-connect.hover',
+    'global-connect.out',
+    'global-connect.end',
+    'global-connect.cleanup'
+  ], HIGH_PRIORITY, function(event) {
+    var hover = event.hover;
+
+    // ensure connections start/end on bpmn:Participant,
+    // not the underlying bpmn:Lane
+    if (is(hover, 'bpmn:Lane')) {
+      event.hover = getLanesRoot(hover) || hover;
+      event.hoverGfx = elementRegistry.getGraphics(event.hover);
+    }
+  });
+
+
+  eventBus.on([
+    'bendpoint.move.hover'
+  ], HIGH_PRIORITY, function(event) {
+    var context = event.context,
+        hover = event.hover,
+        type = context.type;
+
+    // ensure reconnect start/end on bpmn:Participant,
+    // not the underlying bpmn:Lane
+    if (is(hover, 'bpmn:Lane') && /reconnect/.test(type)) {
+      event.hover = getLanesRoot(hover) || hover;
+      event.hoverGfx = elementRegistry.getGraphics(event.hover);
+    }
+  });
+
+
+  eventBus.on([
+    'connect.start'
+  ], HIGH_PRIORITY, function(event) {
+    var context = event.context,
+        start = context.start;
+
+    // ensure connect start on bpmn:Participant,
+    // not the underlying bpmn:Lane
+    if (is(start, 'bpmn:Lane')) {
+      context.start = getLanesRoot(start) || start;
+    }
+  });
+
+
+  // allow movement of participants from lanes
+  eventBus.on('shape.move.start', HIGHEST_PRIORITY, function(event) {
+    var shape = event.shape;
+
+    if (is(shape, 'bpmn:Lane')) {
+      event.shape = getLanesRoot(shape) || shape;
+    }
+  });
+
+}
+
+FixHoverBehavior.$inject = [
+  'elementRegistry',
+  'eventBus',
+  'canvas'
+];

+ 311 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/GroupBehavior.js

@@ -0,0 +1,311 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import {
+  getBusinessObject,
+  is
+} from '../../../util/ModelUtil';
+
+import {
+  createCategory,
+  createCategoryValue,
+  linkCategoryValue,
+  unlinkCategory,
+  unlinkCategoryValue
+} from './util/CategoryUtil';
+
+
+var LOWER_PRIORITY = 770;
+
+
+/**
+ * BPMN specific Group behavior
+ */
+export default function GroupBehavior(
+    bpmnFactory,
+    bpmnjs,
+    elementRegistry,
+    eventBus,
+    injector,
+    moddleCopy
+) {
+  injector.invoke(CommandInterceptor, this);
+
+  /**
+   * Returns all group element in the current registry
+   *
+   * @return {Array<djs.model.shape>} a list of group shapes
+   */
+  function getGroupElements() {
+    return elementRegistry.filter(function(e) {
+      return is(e, 'bpmn:Group');
+    });
+  }
+
+  /**
+   * Returns true if given category is referenced in one of the given elements
+   *
+   * @param { djs.model.Element[] } elements
+   * @param { ModdleElement } category
+   *
+   * @return { boolean }
+   */
+  function isReferencedCategory(elements, category) {
+    return elements.some(function(element) {
+      var businessObject = getBusinessObject(element);
+
+      var _category = businessObject.categoryValueRef && businessObject.categoryValueRef.$parent;
+
+      return _category === category;
+    });
+  }
+
+  /**
+   * Returns true if given categoryValue is referenced in one of the given elements
+   *
+   * @param { djs.model.Element[] } elements
+   * @param { ModdleElement } categoryValue
+   *
+   * @return { boolean }
+   */
+  function isReferencedCategoryValue(elements, categoryValue) {
+    return elements.some(function(element) {
+      var businessObject = getBusinessObject(element);
+
+      return businessObject.categoryValueRef === categoryValue;
+    });
+  }
+
+  /**
+   * Remove category value unless it is still referenced
+   *
+   * @param {ModdleElement} categoryValue
+   * @param {ModdleElement} category
+   * @param {ModdleElement} businessObject
+   */
+  function removeCategoryValue(categoryValue, category, businessObject) {
+
+    var groups = getGroupElements().filter(function(element) {
+      return element.businessObject !== businessObject;
+    });
+
+    if (category && !isReferencedCategory(groups, category)) {
+      unlinkCategory(category);
+    }
+
+    if (categoryValue && !isReferencedCategoryValue(groups, categoryValue)) {
+      unlinkCategoryValue(categoryValue);
+    }
+  }
+
+  /**
+   * Add category value
+   *
+   * @param {ModdleElement} categoryValue
+   * @param {ModdleElement} category
+   */
+  function addCategoryValue(categoryValue, category) {
+    return linkCategoryValue(categoryValue, category, bpmnjs.getDefinitions());
+  }
+
+  function setCategoryValue(element, context) {
+    var businessObject = getBusinessObject(element),
+        categoryValue = businessObject.categoryValueRef;
+
+    if (!categoryValue) {
+      categoryValue =
+      businessObject.categoryValueRef =
+      context.categoryValue = (
+        context.categoryValue || createCategoryValue(bpmnFactory)
+      );
+    }
+
+    var category = categoryValue.$parent;
+
+    if (!category) {
+      category =
+      categoryValue.$parent =
+      context.category = (
+        context.category || createCategory(bpmnFactory)
+      );
+    }
+
+    addCategoryValue(categoryValue, category, bpmnjs.getDefinitions());
+  }
+
+  function unsetCategoryValue(element, context) {
+    var category = context.category,
+        categoryValue = context.categoryValue,
+        businessObject = getBusinessObject(element);
+
+    if (categoryValue) {
+      businessObject.categoryValueRef = null;
+
+      removeCategoryValue(categoryValue, category, businessObject);
+    } else {
+      removeCategoryValue(null, businessObject.categoryValueRef.$parent, businessObject);
+    }
+  }
+
+
+  // ensure category + value exist before label editing
+
+  this.execute('label.create', function(event) {
+    var context = event.context,
+        labelTarget = context.labelTarget;
+
+    if (!is(labelTarget, 'bpmn:Group')) {
+      return;
+    }
+
+    setCategoryValue(labelTarget, context);
+  });
+
+  this.revert('label.create', function(event) {
+    var context = event.context,
+        labelTarget = context.labelTarget;
+
+    if (!is(labelTarget, 'bpmn:Group')) {
+      return;
+    }
+
+    unsetCategoryValue(labelTarget, context);
+  });
+
+
+  // remove referenced category + value when group was deleted
+
+  this.execute('shape.delete', function(event) {
+
+    var context = event.context,
+        shape = context.shape,
+        businessObject = getBusinessObject(shape);
+
+    if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
+      return;
+    }
+
+    var categoryValue = context.categoryValue = businessObject.categoryValueRef,
+        category;
+
+    if (categoryValue) {
+      category = context.category = categoryValue.$parent;
+
+      removeCategoryValue(categoryValue, category, businessObject);
+
+      businessObject.categoryValueRef = null;
+    }
+  });
+
+  this.reverted('shape.delete', function(event) {
+
+    var context = event.context,
+        shape = context.shape;
+
+    if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
+      return;
+    }
+
+    var category = context.category,
+        categoryValue = context.categoryValue,
+        businessObject = getBusinessObject(shape);
+
+    if (categoryValue) {
+      businessObject.categoryValueRef = categoryValue;
+
+      addCategoryValue(categoryValue, category);
+    }
+  });
+
+
+  // create new category + value when group was created
+
+  this.execute('shape.create', function(event) {
+    var context = event.context,
+        shape = context.shape;
+
+    if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
+      return;
+    }
+
+    if (getBusinessObject(shape).categoryValueRef) {
+      setCategoryValue(shape, context);
+    }
+  });
+
+  this.reverted('shape.create', function(event) {
+
+    var context = event.context,
+        shape = context.shape;
+
+    if (!is(shape, 'bpmn:Group') || shape.labelTarget) {
+      return;
+    }
+
+    if (getBusinessObject(shape).categoryValueRef) {
+      unsetCategoryValue(shape, context);
+    }
+  });
+
+
+  // copy + paste categoryValueRef with group
+
+  function copy(bo, clone) {
+    var targetBo = bpmnFactory.create(bo.$type);
+
+    return moddleCopy.copyElement(bo, targetBo, null, clone);
+  }
+
+  eventBus.on('copyPaste.copyElement', LOWER_PRIORITY, function(context) {
+    var descriptor = context.descriptor,
+        element = context.element;
+
+    if (!is(element, 'bpmn:Group') || element.labelTarget) {
+      return;
+    }
+
+    var groupBo = getBusinessObject(element);
+
+    if (groupBo.categoryValueRef) {
+
+      var categoryValue = groupBo.categoryValueRef;
+
+      descriptor.categoryValue = copy(categoryValue, true);
+
+      if (categoryValue.$parent) {
+        descriptor.category = copy(categoryValue.$parent, true);
+      }
+    }
+  });
+
+  eventBus.on('copyPaste.pasteElement', LOWER_PRIORITY, function(context) {
+    var descriptor = context.descriptor,
+        businessObject = descriptor.businessObject,
+        categoryValue = descriptor.categoryValue,
+        category = descriptor.category;
+
+    if (categoryValue) {
+      categoryValue = businessObject.categoryValueRef = copy(categoryValue);
+    }
+
+    if (category) {
+      categoryValue.$parent = copy(category);
+    }
+
+    delete descriptor.category;
+    delete descriptor.categoryValue;
+  });
+
+}
+
+GroupBehavior.$inject = [
+  'bpmnFactory',
+  'bpmnjs',
+  'elementRegistry',
+  'eventBus',
+  'injector',
+  'moddleCopy'
+];
+
+inherits(GroupBehavior, CommandInterceptor);

+ 81 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/ImportDockingFix.js

@@ -0,0 +1,81 @@
+import {
+  getMid
+} from 'diagram-js/lib/layout/LayoutUtil';
+
+import lineIntersect from './util/LineIntersect';
+
+
+/**
+ * Fix broken dockings after DI imports.
+ *
+ * @param {EventBus} eventBus
+ */
+export default function ImportDockingFix(eventBus) {
+
+  function adjustDocking(startPoint, nextPoint, elementMid) {
+
+    var elementTop = {
+      x: elementMid.x,
+      y: elementMid.y - 50
+    };
+
+    var elementLeft = {
+      x: elementMid.x - 50,
+      y: elementMid.y
+    };
+
+    var verticalIntersect = lineIntersect(startPoint, nextPoint, elementMid, elementTop),
+        horizontalIntersect = lineIntersect(startPoint, nextPoint, elementMid, elementLeft);
+
+    // original is horizontal or vertical center cross intersection
+    var centerIntersect;
+
+    if (verticalIntersect && horizontalIntersect) {
+      if (getDistance(verticalIntersect, elementMid) > getDistance(horizontalIntersect, elementMid)) {
+        centerIntersect = horizontalIntersect;
+      } else {
+        centerIntersect = verticalIntersect;
+      }
+    } else {
+      centerIntersect = verticalIntersect || horizontalIntersect;
+    }
+
+    startPoint.original = centerIntersect;
+  }
+
+  function fixDockings(connection) {
+    var waypoints = connection.waypoints;
+
+    adjustDocking(
+      waypoints[0],
+      waypoints[1],
+      getMid(connection.source)
+    );
+
+    adjustDocking(
+      waypoints[waypoints.length - 1],
+      waypoints[waypoints.length - 2],
+      getMid(connection.target)
+    );
+  }
+
+  eventBus.on('bpmnElement.added', function(e) {
+
+    var element = e.element;
+
+    if (element.waypoints) {
+      fixDockings(element);
+    }
+  });
+}
+
+ImportDockingFix.$inject = [
+  'eventBus'
+];
+
+
+// helpers //////////////////////
+
+function getDistance(p1, p2) {
+  return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
+}

+ 45 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/IsHorizontalFix.js

@@ -0,0 +1,45 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import {
+  getBusinessObject,
+  getDi
+} from '../../../util/ModelUtil';
+
+import {
+  isAny
+} from '../util/ModelingUtil';
+
+/**
+ * A component that makes sure that each created or updated
+ * Pool and Lane is assigned an isHorizontal property set to true.
+ *
+ * @param {EventBus} eventBus
+ */
+export default function IsHorizontalFix(eventBus) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  var elementTypesToUpdate = [
+    'bpmn:Participant',
+    'bpmn:Lane'
+  ];
+
+  this.executed([ 'shape.move', 'shape.create', 'shape.resize' ], function(event) {
+    var shape = event.context.shape,
+        bo = getBusinessObject(shape),
+        di = getDi(shape);
+
+    if (isAny(bo, elementTypesToUpdate) && !di.get('isHorizontal')) {
+
+      // set attribute directly to avoid modeling#updateProperty side effects
+      di.set('isHorizontal', true);
+    }
+  });
+
+}
+
+IsHorizontalFix.$inject = [ 'eventBus' ];
+
+inherits(IsHorizontalFix, CommandInterceptor);

+ 403 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/LabelBehavior.js

@@ -0,0 +1,403 @@
+import {
+  assign
+} from 'min-dash';
+
+import inherits from 'inherits-browser';
+
+import {
+  is,
+  getBusinessObject,
+  getDi
+} from '../../../util/ModelUtil';
+
+import {
+  isLabelExternal,
+  getExternalLabelMid,
+  hasExternalLabel,
+  isLabel
+} from '../../../util/LabelUtil';
+
+import {
+  getLabel
+} from '../../label-editing/LabelUtil';
+
+import {
+  getLabelAdjustment
+} from './util/LabelLayoutUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import {
+  getNewAttachPoint
+} from 'diagram-js/lib/util/AttachUtil';
+
+import {
+  getMid,
+  roundPoint
+} from 'diagram-js/lib/layout/LayoutUtil';
+
+import {
+  delta
+} from 'diagram-js/lib/util/PositionUtil';
+
+import {
+  sortBy
+} from 'min-dash';
+
+import {
+  getDistancePointLine,
+  perpendicularFoot
+} from './util/GeometricUtil';
+
+var DEFAULT_LABEL_DIMENSIONS = {
+  width: 90,
+  height: 20
+};
+
+var NAME_PROPERTY = 'name';
+var TEXT_PROPERTY = 'text';
+
+/**
+ * A component that makes sure that external labels are added
+ * together with respective elements and properly updated (DI wise)
+ * during move.
+ *
+ * @param {EventBus} eventBus
+ * @param {Modeling} modeling
+ * @param {BpmnFactory} bpmnFactory
+ * @param {TextRenderer} textRenderer
+ */
+export default function LabelBehavior(
+    eventBus, modeling, bpmnFactory,
+    textRenderer) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  // update label if name property was updated
+  this.postExecute('element.updateProperties', function(e) {
+    var context = e.context,
+        element = context.element,
+        properties = context.properties;
+
+    if (NAME_PROPERTY in properties) {
+      modeling.updateLabel(element, properties[NAME_PROPERTY]);
+    }
+
+    if (TEXT_PROPERTY in properties
+        && is(element, 'bpmn:TextAnnotation')) {
+
+      var newBounds = textRenderer.getTextAnnotationBounds(
+        {
+          x: element.x,
+          y: element.y,
+          width: element.width,
+          height: element.height
+        },
+        properties[TEXT_PROPERTY] || ''
+      );
+
+      modeling.updateLabel(element, properties.text, newBounds);
+    }
+  });
+
+  // create label shape after shape/connection was created
+  this.postExecute([ 'shape.create', 'connection.create' ], function(e) {
+    var context = e.context,
+        hints = context.hints || {};
+
+    if (hints.createElementsBehavior === false) {
+      return;
+    }
+
+    var element = context.shape || context.connection,
+        businessObject = element.businessObject;
+
+    if (isLabel(element) || !isLabelExternal(element)) {
+      return;
+    }
+
+    // only create label if attribute available
+    if (!getLabel(element)) {
+      return;
+    }
+
+    var labelCenter = getExternalLabelMid(element);
+
+    // we don't care about x and y
+    var labelDimensions = textRenderer.getExternalLabelBounds(
+      DEFAULT_LABEL_DIMENSIONS,
+      getLabel(element)
+    );
+
+    modeling.createLabel(element, labelCenter, {
+      id: businessObject.id + '_label',
+      businessObject: businessObject,
+      width: labelDimensions.width,
+      height: labelDimensions.height
+    });
+  });
+
+  // update label after label shape was deleted
+  this.postExecute('shape.delete', function(event) {
+    var context = event.context,
+        labelTarget = context.labelTarget,
+        hints = context.hints || {};
+
+    // check if label
+    if (labelTarget && hints.unsetLabel !== false) {
+      modeling.updateLabel(labelTarget, null, null, { removeShape: false });
+    }
+  });
+
+  // update di information on label creation
+  this.postExecute([ 'label.create' ], function(event) {
+
+    var context = event.context,
+        element = context.shape,
+        labelTarget = context.labelTarget,
+        di;
+
+    // we want to trigger on real labels only
+    if (!labelTarget) {
+      return;
+    }
+
+    // we want to trigger on BPMN elements only
+    if (!is(labelTarget, 'bpmn:BaseElement')) {
+      return;
+    }
+
+    di = getDi(labelTarget);
+
+    if (!di.label) {
+      di.label = bpmnFactory.create('bpmndi:BPMNLabel', {
+        bounds: bpmnFactory.create('dc:Bounds')
+      });
+
+      element.di = di;
+    }
+
+    assign(di.label.bounds, {
+      x: element.x,
+      y: element.y,
+      width: element.width,
+      height: element.height
+    });
+  });
+
+  function getVisibleLabelAdjustment(event) {
+
+    var context = event.context,
+        connection = context.connection,
+        label = connection.label,
+        hints = assign({}, context.hints),
+        newWaypoints = context.newWaypoints || connection.waypoints,
+        oldWaypoints = context.oldWaypoints;
+
+
+    if (typeof hints.startChanged === 'undefined') {
+      hints.startChanged = !!hints.connectionStart;
+    }
+
+    if (typeof hints.endChanged === 'undefined') {
+      hints.endChanged = !!hints.connectionEnd;
+    }
+
+    return getLabelAdjustment(label, newWaypoints, oldWaypoints, hints);
+  }
+
+  this.postExecute([
+    'connection.layout',
+    'connection.updateWaypoints'
+  ], function(event) {
+    var context = event.context,
+        hints = context.hints || {};
+
+    if (hints.labelBehavior === false) {
+      return;
+    }
+
+    var connection = context.connection,
+        label = connection.label,
+        labelAdjustment;
+
+    // handle missing label as well as the case
+    // that the label parent does not exist (yet),
+    // because it is being pasted / created via multi element create
+    //
+    // Cf. https://github.com/bpmn-io/bpmn-js/pull/1227
+    if (!label || !label.parent) {
+      return;
+    }
+
+    labelAdjustment = getVisibleLabelAdjustment(event);
+
+    modeling.moveShape(label, labelAdjustment);
+  });
+
+
+  // keep label position on shape replace
+  this.postExecute([ 'shape.replace' ], function(event) {
+    var context = event.context,
+        newShape = context.newShape,
+        oldShape = context.oldShape;
+
+    var businessObject = getBusinessObject(newShape);
+
+    if (businessObject
+      && isLabelExternal(businessObject)
+      && oldShape.label
+      && newShape.label) {
+      newShape.label.x = oldShape.label.x;
+      newShape.label.y = oldShape.label.y;
+    }
+  });
+
+
+  // move external label after resizing
+  this.postExecute('shape.resize', function(event) {
+
+    var context = event.context,
+        shape = context.shape,
+        newBounds = context.newBounds,
+        oldBounds = context.oldBounds;
+
+    if (hasExternalLabel(shape)) {
+
+      var label = shape.label,
+          labelMid = getMid(label),
+          edges = asEdges(oldBounds);
+
+      // get nearest border point to label as reference point
+      var referencePoint = getReferencePoint(labelMid, edges);
+
+      var delta = getReferencePointDelta(referencePoint, oldBounds, newBounds);
+
+      modeling.moveShape(label, delta);
+
+    }
+
+  });
+
+}
+
+inherits(LabelBehavior, CommandInterceptor);
+
+LabelBehavior.$inject = [
+  'eventBus',
+  'modeling',
+  'bpmnFactory',
+  'textRenderer'
+];
+
+// helpers //////////////////////
+
+/**
+ * Calculates a reference point delta relative to a new position
+ * of a certain element's bounds
+ *
+ * @param {Point} point
+ * @param {Bounds} oldBounds
+ * @param {Bounds} newBounds
+ *
+ * @return {Delta} delta
+ */
+export function getReferencePointDelta(referencePoint, oldBounds, newBounds) {
+
+  var newReferencePoint = getNewAttachPoint(referencePoint, oldBounds, newBounds);
+
+  return roundPoint(delta(newReferencePoint, referencePoint));
+}
+
+/**
+ * Generates the nearest point (reference point) for a given point
+ * onto given set of lines
+ *
+ * @param {Array<Point, Point>} lines
+ * @param {Point} point
+ *
+ * @param {Point}
+ */
+export function getReferencePoint(point, lines) {
+
+  if (!lines.length) {
+    return;
+  }
+
+  var nearestLine = getNearestLine(point, lines);
+
+  return perpendicularFoot(point, nearestLine);
+}
+
+/**
+ * Convert the given bounds to a lines array containing all edges
+ *
+ * @param {Bounds|Point} bounds
+ *
+ * @return Array<Point>
+ */
+export function asEdges(bounds) {
+  return [
+    [ // top
+      {
+        x: bounds.x,
+        y: bounds.y
+      },
+      {
+        x: bounds.x + (bounds.width || 0),
+        y: bounds.y
+      }
+    ],
+    [ // right
+      {
+        x: bounds.x + (bounds.width || 0),
+        y: bounds.y
+      },
+      {
+        x: bounds.x + (bounds.width || 0),
+        y: bounds.y + (bounds.height || 0)
+      }
+    ],
+    [ // bottom
+      {
+        x: bounds.x,
+        y: bounds.y + (bounds.height || 0)
+      },
+      {
+        x: bounds.x + (bounds.width || 0),
+        y: bounds.y + (bounds.height || 0)
+      }
+    ],
+    [ // left
+      {
+        x: bounds.x,
+        y: bounds.y
+      },
+      {
+        x: bounds.x,
+        y: bounds.y + (bounds.height || 0)
+      }
+    ]
+  ];
+}
+
+/**
+ * Returns the nearest line for a given point by distance
+ * @param {Point} point
+ * @param Array<Point> lines
+ *
+ * @return Array<Point>
+ */
+function getNearestLine(point, lines) {
+
+  var distances = lines.map(function(l) {
+    return {
+      line: l,
+      distance: getDistancePointLine(point, l)
+    };
+  });
+
+  var sorted = sortBy(distances, 'distance');
+
+  return sorted[0].line;
+}

+ 117 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/LayoutConnectionBehavior.js

@@ -0,0 +1,117 @@
+import {
+  assign
+} from 'min-dash';
+
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { getConnectionAdjustment as getConnectionAnchorPoint } from './util/ConnectionLayoutUtil';
+
+/**
+ * A component that makes sure that Associations connected to Connections
+ * are updated together with the Connection.
+ *
+ * @param {EventBus} eventBus
+ * @param {Modeling} modeling
+ */
+export default function LayoutConnectionBehavior(
+    eventBus, modeling) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  function getnewAnchorPoint(event, point) {
+
+    var context = event.context,
+        connection = context.connection,
+        hints = assign({}, context.hints),
+        newWaypoints = context.newWaypoints || connection.waypoints,
+        oldWaypoints = context.oldWaypoints;
+
+
+    if (typeof hints.startChanged === 'undefined') {
+      hints.startChanged = !!hints.connectionStart;
+    }
+
+    if (typeof hints.endChanged === 'undefined') {
+      hints.endChanged = !!hints.connectionEnd;
+    }
+
+    return getConnectionAnchorPoint(point, newWaypoints, oldWaypoints, hints);
+  }
+
+  this.postExecute([
+    'connection.layout',
+    'connection.updateWaypoints'
+  ], function(event) {
+    var context = event.context;
+
+    var connection = context.connection,
+        outgoing = connection.outgoing,
+        incoming = connection.incoming;
+
+    incoming.forEach(function(connection) {
+      var endPoint = connection.waypoints[connection.waypoints.length - 1];
+      var newEndpoint = getnewAnchorPoint(event, endPoint);
+
+      var newWaypoints = [].concat(connection.waypoints.slice(0, -1), [ newEndpoint ]);
+
+      modeling.updateWaypoints(connection, newWaypoints);
+    });
+
+    outgoing.forEach(function(connection) {
+      var startpoint = connection.waypoints[0];
+      var newStartpoint = getnewAnchorPoint(event, startpoint);
+
+      var newWaypoints = [].concat([ newStartpoint ], connection.waypoints.slice(1));
+
+      modeling.updateWaypoints(connection, newWaypoints);
+    });
+
+  });
+
+
+  this.postExecute([
+    'connection.move'
+  ], function(event) {
+    var context = event.context;
+
+    var connection = context.connection,
+        outgoing = connection.outgoing,
+        incoming = connection.incoming,
+        delta = context.delta;
+
+    incoming.forEach(function(connection) {
+      var endPoint = connection.waypoints[connection.waypoints.length - 1];
+      var newEndpoint = {
+        x: endPoint.x + delta.x,
+        y: endPoint.y + delta.y
+      };
+
+      var newWaypoints = [].concat(connection.waypoints.slice(0, -1), [ newEndpoint ]);
+
+      modeling.updateWaypoints(connection, newWaypoints);
+    });
+
+    outgoing.forEach(function(connection) {
+      var startpoint = connection.waypoints[0];
+      var newStartpoint = {
+        x: startpoint.x + delta.x,
+        y: startpoint.y + delta.y
+      };
+
+      var newWaypoints = [].concat([ newStartpoint ], connection.waypoints.slice(1));
+
+      modeling.updateWaypoints(connection, newWaypoints);
+    });
+
+  });
+
+}
+
+inherits(LayoutConnectionBehavior, CommandInterceptor);
+
+LayoutConnectionBehavior.$inject = [
+  'eventBus',
+  'modeling'
+];

+ 89 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/MessageFlowBehavior.js

@@ -0,0 +1,89 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { is } from '../../../util/ModelUtil';
+
+import { isExpanded } from '../../../util/DiUtil';
+
+import { selfAndAllChildren } from 'diagram-js/lib/util/Elements';
+
+import {
+  getResizedSourceAnchor,
+  getResizedTargetAnchor
+} from 'diagram-js/lib/features/modeling/cmd/helper/AnchorsHelper';
+
+/**
+ * BPMN-specific message flow behavior.
+ */
+export default function MessageFlowBehavior(eventBus, modeling) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  this.postExecute('shape.replace', function(context) {
+    var oldShape = context.oldShape,
+        newShape = context.newShape;
+
+    if (!isParticipantCollapse(oldShape, newShape)) {
+      return;
+    }
+
+    var messageFlows = getMessageFlows(oldShape);
+
+    messageFlows.incoming.forEach(function(incoming) {
+      var anchor = getResizedTargetAnchor(incoming, newShape, oldShape);
+
+      modeling.reconnectEnd(incoming, newShape, anchor);
+    });
+
+    messageFlows.outgoing.forEach(function(outgoing) {
+      var anchor = getResizedSourceAnchor(outgoing, newShape, oldShape);
+
+      modeling.reconnectStart(outgoing, newShape, anchor);
+    });
+  }, true);
+
+}
+
+MessageFlowBehavior.$inject = [ 'eventBus', 'modeling' ];
+
+inherits(MessageFlowBehavior, CommandInterceptor);
+
+// helpers //////////
+
+function isParticipantCollapse(oldShape, newShape) {
+  return is(oldShape, 'bpmn:Participant')
+    && isExpanded(oldShape)
+    && is(newShape, 'bpmn:Participant')
+    && !isExpanded(newShape);
+}
+
+function getMessageFlows(parent) {
+  var elements = selfAndAllChildren([ parent ], false);
+
+  var incoming = [],
+      outgoing = [];
+
+  elements.forEach(function(element) {
+    if (element === parent) {
+      return;
+    }
+
+    element.incoming.forEach(function(connection) {
+      if (is(connection, 'bpmn:MessageFlow')) {
+        incoming.push(connection);
+      }
+    });
+
+    element.outgoing.forEach(function(connection) {
+      if (is(connection, 'bpmn:MessageFlow')) {
+        outgoing.push(connection);
+      }
+    });
+  }, []);
+
+  return {
+    incoming: incoming,
+    outgoing: outgoing
+  };
+}

+ 35 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/ModelingFeedback.js

@@ -0,0 +1,35 @@
+import { is } from '../../../util/ModelUtil';
+
+var COLLAB_ERR_MSG = 'flow elements must be children of pools/participants';
+
+export default function ModelingFeedback(eventBus, tooltips, translate) {
+
+  function showError(position, message, timeout) {
+    tooltips.add({
+      position: {
+        x: position.x + 5,
+        y: position.y + 5
+      },
+      type: 'error',
+      timeout: timeout || 2000,
+      html: '<div>' + message + '</div>'
+    });
+  }
+
+  eventBus.on([ 'shape.move.rejected', 'create.rejected' ], function(event) {
+    var context = event.context,
+        shape = context.shape,
+        target = context.target;
+
+    if (is(target, 'bpmn:Collaboration') && is(shape, 'bpmn:FlowNode')) {
+      showError(event, translate(COLLAB_ERR_MSG));
+    }
+  });
+
+}
+
+ModelingFeedback.$inject = [
+  'eventBus',
+  'tooltips',
+  'translate'
+];

+ 82 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/RemoveElementBehavior.js

@@ -0,0 +1,82 @@
+import inherits from 'inherits-browser';
+
+import { is } from '../../../util/ModelUtil';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import lineIntersect from './util/LineIntersect';
+
+
+export default function RemoveElementBehavior(eventBus, bpmnRules, modeling) {
+
+  CommandInterceptor.call(this, eventBus);
+
+  /**
+   * Combine sequence flows when deleting an element
+   * if there is one incoming and one outgoing
+   * sequence flow
+   */
+  this.preExecute('shape.delete', function(e) {
+
+    var shape = e.context.shape;
+
+    // only handle [a] -> [shape] -> [b] patterns
+    if (shape.incoming.length !== 1 || shape.outgoing.length !== 1) {
+      return;
+    }
+
+    var inConnection = shape.incoming[0],
+        outConnection = shape.outgoing[0];
+
+    // only handle sequence flows
+    if (!is(inConnection, 'bpmn:SequenceFlow') || !is(outConnection, 'bpmn:SequenceFlow')) {
+      return;
+    }
+
+    if (bpmnRules.canConnect(inConnection.source, outConnection.target, inConnection)) {
+
+      // compute new, combined waypoints
+      var newWaypoints = getNewWaypoints(inConnection.waypoints, outConnection.waypoints);
+
+      modeling.reconnectEnd(inConnection, outConnection.target, newWaypoints);
+    }
+  });
+
+}
+
+inherits(RemoveElementBehavior, CommandInterceptor);
+
+RemoveElementBehavior.$inject = [
+  'eventBus',
+  'bpmnRules',
+  'modeling'
+];
+
+
+// helpers //////////////////////
+
+function getDocking(point) {
+  return point.original || point;
+}
+
+
+function getNewWaypoints(inWaypoints, outWaypoints) {
+
+  var intersection = lineIntersect(
+    getDocking(inWaypoints[inWaypoints.length - 2]),
+    getDocking(inWaypoints[inWaypoints.length - 1]),
+    getDocking(outWaypoints[1]),
+    getDocking(outWaypoints[0]));
+
+  if (intersection) {
+    return [].concat(
+      inWaypoints.slice(0, inWaypoints.length - 1),
+      [ intersection ],
+      outWaypoints.slice(1));
+  } else {
+    return [
+      getDocking(inWaypoints[0]),
+      getDocking(outWaypoints[outWaypoints.length - 1])
+    ];
+  }
+}

+ 34 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/RemoveEmbeddedLabelBoundsBehavior.js

@@ -0,0 +1,34 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { getDi } from '../../../util/ModelUtil';
+
+/**
+ * BPMN specific behavior ensuring that bpmndi:Label's dc:Bounds are removed
+ * when shape is resized.
+ */
+export default function RemoveEmbeddedLabelBoundsBehavior(eventBus, modeling) {
+  CommandInterceptor.call(this, eventBus);
+
+  this.preExecute('shape.resize', function(context) {
+    var shape = context.shape;
+
+    var di = getDi(shape),
+        label = di && di.get('label'),
+        bounds = label && label.get('bounds');
+
+    if (bounds) {
+      modeling.updateModdleProperties(shape, label, {
+        bounds: undefined
+      });
+    }
+  }, true);
+}
+
+inherits(RemoveEmbeddedLabelBoundsBehavior, CommandInterceptor);
+
+RemoveEmbeddedLabelBoundsBehavior.$inject = [
+  'eventBus',
+  'modeling'
+];

+ 48 - 0
ruoyi-ui/src/components/updateModule/bpmn-js/lib/features/modeling/behavior/RemoveParticipantBehavior.js

@@ -0,0 +1,48 @@
+import inherits from 'inherits-browser';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { is } from '../../../util/ModelUtil';
+
+
+/**
+ * BPMN specific remove behavior
+ */
+export default function RemoveParticipantBehavior(eventBus, modeling) {
+
+  CommandInterceptor.call(this, eventBus);
+
+
+  /**
+   * morph collaboration diagram into process diagram
+   * after the last participant has been removed
+   */
+
+  this.preExecute('shape.delete', function(context) {
+
+    var shape = context.shape,
+        parent = shape.parent;
+
+    // activate the behavior if the shape to be removed
+    // is a participant
+    if (is(shape, 'bpmn:Participant')) {
+      context.collaborationRoot = parent;
+    }
+  }, true);
+
+  this.postExecute('shape.delete', function(context) {
+
+    var collaborationRoot = context.collaborationRoot;
+
+    if (collaborationRoot && !collaborationRoot.businessObject.participants.length) {
+
+      // replace empty collaboration with process diagram
+      modeling.makeProcess();
+    }
+  }, true);
+
+}
+
+RemoveParticipantBehavior.$inject = [ 'eventBus', 'modeling' ];
+
+inherits(RemoveParticipantBehavior, CommandInterceptor);

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff