فهرست منبع

工作流引擎

zhouhao 7 سال پیش
والد
کامیت
362601a61e
100فایلهای تغییر یافته به همراه16036 افزوده شده و 0 حذف شده
  1. 100 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/pom.xml
  2. 20 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/META-INF/context.xml
  3. 157 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/404.html
  4. 9 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/browserconfig.xml
  5. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/.gitignore
  6. 153 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/Gruntfile.js
  7. 387 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/Polyline.js
  8. 824 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/bpmn-draw.js
  9. 303 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/bpmn-icons.js
  10. 24 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/displaymodel.css
  11. 19 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/displaymodel.html
  12. 317 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/displaymodel.js
  13. 2 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/jquery.qtip.min.css
  14. 5 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/jquery.qtip.min.js
  15. 37 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/package.json
  16. 8078 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/raphael.js
  17. 19 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/flowable-header-custom.js
  18. 39 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/flowable-toolbar-custom-actions.js
  19. 504 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-assignment-controller.js
  20. 80 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-collapsed-subprocess-controller.js
  21. 59 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-condition-expression-controller.js
  22. 12 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-custom-controllers.js
  23. 288 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-decisiontable-reference-controller.js
  24. 111 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-default-controllers.js
  25. 126 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-duedate-controller.js
  26. 263 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-event-listeners-controller.js
  27. 358 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-execution-listeners-controller.js
  28. 206 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-fields-controller.js
  29. 327 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-form-properties-controller.js
  30. 261 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-form-reference-controller.js
  31. 179 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-in-parameters-controller.js
  32. 145 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-message-definitions-controller.js
  33. 41 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-message-scope-controller.js
  34. 28 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-multiinstance-controller.js
  35. 28 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-ordering-controller.js
  36. 176 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-out-parameters-controller.js
  37. 126 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-sequenceflow-order-controller.js
  38. 151 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-signal-definitions-controller.js
  39. 42 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-signal-scope-controller.js
  40. 356 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-task-listeners-controller.js
  41. 109 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties.js
  42. 15 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/assignment-display-template.html
  43. 268 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/assignment-popup.html
  44. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/assignment-write-template.html
  45. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/boolean-property-template.html
  46. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/condition-expression-display-template.html
  47. 26 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/condition-expression-popup.html
  48. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/condition-expression-write-template.html
  49. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/decisiontable-reference-display-template.html
  50. 74 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/decisiontable-reference-popup.html
  51. 2 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/decisiontable-reference-write-template.html
  52. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/default-value-display-template.html
  53. 6 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/duedate-display-template.html
  54. 120 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/duedate-popup.html
  55. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/duedate-write-template.html
  56. 5 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/errorgrid-critical.html
  57. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/event-listeners-display-template.html
  58. 119 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/event-listeners-popup.html
  59. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/event-listeners-write-template.html
  60. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/execution-listeners-display-template.html
  61. 101 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/execution-listeners-popup.html
  62. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/execution-listeners-write-template.html
  63. 17 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/feedback-popup.html
  64. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/fields-display-template.html
  65. 58 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/fields-popup.html
  66. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/fields-write-template.html
  67. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-properties-display-template.html
  68. 117 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-properties-popup.html
  69. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-properties-write-template.html
  70. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-reference-display-template.html
  71. 74 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-reference-popup.html
  72. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-reference-write-template.html
  73. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/in-parameters-display-template.html
  74. 53 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/in-parameters-popup.html
  75. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/in-parameters-write-template.html
  76. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/message-definitions-display-template.html
  77. 49 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/message-definitions-popup.html
  78. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/message-definitions-write-template.html
  79. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/message-property-write-template.html
  80. 8 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/multiinstance-property-write-template.html
  81. 7 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/ordering-property-write-template.html
  82. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/out-parameters-display-template.html
  83. 53 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/out-parameters-popup.html
  84. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/out-parameters-write-template.html
  85. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/sequenceflow-order-display-template.html
  86. 47 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/sequenceflow-order-popup.html
  87. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/sequenceflow-order-write-template.html
  88. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/signal-definitions-display-template.html
  89. 56 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/signal-definitions-popup.html
  90. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/signal-definitions-write-template.html
  91. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/signal-property-write-template.html
  92. 9 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/string-property-write-mode-template.html
  93. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/subprocess-reference-display-template.html
  94. 43 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/subprocess-reference-popup.html
  95. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/subprocess-reference-write-template.html
  96. 3 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/task-listeners-display-template.html
  97. 102 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/task-listeners-popup.html
  98. 4 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/task-listeners-write-template.html
  99. 17 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/text-popup.html
  100. 0 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/text-property-write-template.html

+ 100 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/pom.xml

@@ -29,6 +29,106 @@
             <version>${project.version}</version>
         </dependency>
 
+        <!--<dependency>-->
+            <!--<groupId>org.flowable</groupId>-->
+            <!--<artifactId>flowable-ui-modeler-conf</artifactId>-->
+            <!--<version>${flowable.version}</version>-->
+        <!--</dependency>-->
+        <!--<dependency>-->
+            <!--<groupId>org.flowable</groupId>-->
+            <!--<artifactId>flowable-ui-modeler-rest</artifactId>-->
+            <!--<version>${flowable.version}</version>-->
+            <!--<exclusions>-->
+                <!--&lt;!&ndash;<exclusion>&ndash;&gt;-->
+                    <!--&lt;!&ndash;<groupId>org.flowable</groupId>&ndash;&gt;-->
+                    <!--&lt;!&ndash;<artifactId>flowable-ui-modeler-logic</artifactId>&ndash;&gt;-->
+                <!--&lt;!&ndash;</exclusion>&ndash;&gt;-->
+                <!--<exclusion>-->
+                    <!--<groupId>org.mybatis</groupId>-->
+                    <!--<artifactId>mybatis</artifactId>-->
+                <!--</exclusion>-->
+                <!--<exclusion>-->
+                    <!--<groupId>org.mybatis</groupId>-->
+                    <!--<artifactId>mybatis-spring</artifactId>-->
+                <!--</exclusion>-->
+                <!--<exclusion>-->
+                    <!--<groupId>org.springframework.security</groupId>-->
+                    <!--<artifactId>spring-security-core</artifactId>-->
+                <!--</exclusion>-->
+                <!--<exclusion>-->
+                    <!--<groupId>org.springframework.security</groupId>-->
+                    <!--<artifactId>spring-security-config</artifactId>-->
+                <!--</exclusion>-->
+                <!--<exclusion>-->
+                    <!--<groupId>org.springframework.security</groupId>-->
+                    <!--<artifactId>spring-security-crypto</artifactId>-->
+                <!--</exclusion>-->
+                <!--<exclusion>-->
+                    <!--<groupId>org.springframework.security</groupId>-->
+                    <!--<artifactId>spring-security-web</artifactId>-->
+                <!--</exclusion>-->
+            <!--</exclusions>-->
+        <!--</dependency>-->
+
+        <!--<dependency>-->
+            <!--<groupId>org.hswebframework.web</groupId>-->
+            <!--<artifactId>hsweb-spring-boot-starter</artifactId>-->
+            <!--<version>${project.version}</version>-->
+        <!--</dependency>-->
+
+        <dependency>
+            <groupId>org.hswebframework.web</groupId>
+            <artifactId>hsweb-commons-dao-mybatis</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-bpmn-model</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-bpmn-converter</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-json-converter</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-bpmn-layout</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-form-model</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-form-json-converter</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-dmn-model</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-dmn-xml-converter</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-dmn-json-converter</artifactId>
+            <version>${flowable.version}</version>
+        </dependency>
+
+
         <dependency>
             <groupId>com.h2database</groupId>
             <artifactId>h2</artifactId>

+ 20 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/META-INF/context.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright 2005-2015 Alfresco Software, Ltd.
+	
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+
+-->
+<Context path="" privileged="true" reloadable="true" crossContext="true">
+</Context>

+ 157 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/404.html

@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>Page Not Found :(</title>
+    <style>
+      ::-moz-selection {
+        background: #b3d4fc;
+        text-shadow: none;
+      }
+
+      ::selection {
+        background: #b3d4fc;
+        text-shadow: none;
+      }
+
+      html {
+        padding: 30px 10px;
+        font-size: 20px;
+        line-height: 1.4;
+        color: #737373;
+        background: #f0f0f0;
+        -webkit-text-size-adjust: 100%;
+        -ms-text-size-adjust: 100%;
+      }
+
+      html,
+      input {
+        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+      }
+
+      body {
+        max-width: 500px;
+        _width: 500px;
+        padding: 30px 20px 50px;
+        border: 1px solid #b3b3b3;
+        border-radius: 4px;
+        margin: 0 auto;
+        box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;
+        background: #fcfcfc;
+      }
+
+      h1 {
+        margin: 0 10px;
+        font-size: 50px;
+        text-align: center;
+      }
+
+      h1 span {
+        color: #bbb;
+      }
+
+      h3 {
+        margin: 1.5em 0 0.5em;
+      }
+
+      p {
+        margin: 1em 0;
+      }
+
+      ul {
+        padding: 0 0 0 40px;
+        margin: 1em 0;
+      }
+
+      .container {
+        max-width: 380px;
+        _width: 380px;
+        margin: 0 auto;
+      }
+
+      /* google search */
+
+      #goog-fixurl ul {
+        list-style: none;
+        padding: 0;
+        margin: 0;
+      }
+
+      #goog-fixurl form {
+        margin: 0;
+      }
+
+      #goog-wm-qt,
+      #goog-wm-sb {
+        border: 1px solid #bbb;
+        font-size: 16px;
+        line-height: normal;
+        vertical-align: top;
+        color: #444;
+        border-radius: 2px;
+      }
+
+      #goog-wm-qt {
+        width: 220px;
+        height: 20px;
+        padding: 5px;
+        margin: 5px 10px 0 0;
+        box-shadow: inset 0 1px 1px #ccc;
+      }
+
+      #goog-wm-sb {
+        display: inline-block;
+        height: 32px;
+        padding: 0 10px;
+        margin: 5px 0 0;
+        white-space: nowrap;
+        cursor: pointer;
+        background-color: #f5f5f5;
+        background-image: -webkit-linear-gradient(rgba(255,255,255,0), #f1f1f1);
+        background-image: -moz-linear-gradient(rgba(255,255,255,0), #f1f1f1);
+        background-image: -ms-linear-gradient(rgba(255,255,255,0), #f1f1f1);
+        background-image: -o-linear-gradient(rgba(255,255,255,0), #f1f1f1);
+        -webkit-appearance: none;
+        -moz-appearance: none;
+        appearance: none;
+        *overflow: visible;
+        *display: inline;
+        *zoom: 1;
+      }
+
+      #goog-wm-sb:hover,
+      #goog-wm-sb:focus {
+        border-color: #aaa;
+        box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+        background-color: #f8f8f8;
+      }
+
+      #goog-wm-qt:hover,
+      #goog-wm-qt:focus {
+        border-color: #105cb6;
+        outline: 0;
+        color: #222;
+      }
+
+      input::-moz-focus-inner {
+        padding: 0;
+        border: 0;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="container">
+      <h1>Not found <span>:(</span></h1>
+      <p>Sorry, but the page you were trying to view does not exist.</p>
+      <p>It looks like this was the result of either:</p>
+      <ul>
+        <li>a mistyped address</li>
+        <li>an out-of-date link</li>
+      </ul>
+      <script>
+        var GOOG_FIXURL_LANG = (navigator.language || '').slice(0,2),GOOG_FIXURL_SITE = location.host;
+      </script>
+      <script src="//linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js"></script>
+    </div>
+  </body>
+</html>

+ 9 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/browserconfig.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<browserconfig>
+  <msapplication>
+    <tile>
+      <square150x150logo src="images/mstile-150x150.png?v=Om5N75Y123"/>
+      <TileColor>#da532c</TileColor>
+    </tile>
+  </msapplication>
+</browserconfig>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/.gitignore

@@ -0,0 +1,3 @@
+/dist
+/node_modules
+/displaymodel_temp.html

+ 153 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/Gruntfile.js

@@ -0,0 +1,153 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'use strict';
+
+module.exports = function (grunt) {
+
+    require('load-grunt-tasks')(grunt);
+    require('time-grunt')(grunt);
+
+    grunt.initConfig({
+        yeoman: {
+            app: require('./package.json').appPath || 'app',
+            dist: 'dist'
+        },
+        clean: {
+            dist: {
+                files: [
+                    {
+                        dot: true,
+                        src: [
+                            '.tmp',
+                            '<%= yeoman.dist %>/*',
+                            '!<%= yeoman.dist %>/.git*'
+                        ]
+                    }
+                ]
+            },
+            server: '.tmp'
+        },
+        useminPrepare: {
+            html: 'displaymodel.html',
+            options: {
+                dest: '<%= yeoman.dist %>/'
+            }
+        },
+        usemin: {
+            html: ['<%= yeoman.dist %>/{,*/}*.html'],
+            css: ['<%= yeoman.dist %>/display/styles/{,*/}*.css'],
+            options: {
+                dirs: ['<%= yeoman.dist %>']
+            }
+        },
+        // Put files not handled in other tasks here
+        copy: {
+          dist: {
+            files: [{
+              expand: true,
+              dot: true,
+              cwd: '.',
+              dest: '<%= yeoman.dist %>',
+              src: [
+                'fonts/*'
+              ]
+            }, {
+              expand: true,
+              cwd: '.tmp/images',
+              dest: '<%= yeoman.dist %>/images',
+              src: [
+                'generated/*'
+              ]
+            }]
+          },
+          styles: {
+            expand: true,
+            cwd: 'styles',
+            dest: '.tmp/styles/',
+            src: '{,*/}*.css'
+          },
+          index: {
+            expand: true,
+            cwd: './',
+            src: ['*.html', 'views/**/**.html'],
+            dest: '<%= yeoman.dist %>'
+          },
+          copyCss : {
+            files: [
+          {expand: true, cwd:'.tmp/concat/display/styles/', src:'*.css', dest:'<%= yeoman.dist %>/display/styles/', filter: 'isFile'}
+            ]
+          },
+          copyJs : {
+            files: [
+          {expand: true, cwd:'.tmp/concat/display/scripts', src:'*.js', dest:'<%= yeoman.dist %>/display/scripts/', filter: 'isFile'}
+            ]
+          },
+        },  
+        ngAnnotate: {
+            dist: {
+                files: [
+                    {
+                        expand: true,
+                        cwd: '.tmp/concat/display/scripts',
+                        src: '*.js',
+                        dest: '.tmp/concat/display/scripts'
+                    }
+                ]
+            }
+        },
+        uglify: {
+            dist: {
+                options: {
+                    mangle: true
+                },
+                files: {
+                    '<%= yeoman.dist %>/display/scripts/displaymodel-logic.js': [
+                        '<%= yeoman.dist %>/display/scripts/displaymodel-logic.js'
+                    ]
+                }
+            }
+        },
+        rev: {
+            dist: {
+                files: {
+                    src: [
+                        '<%= yeoman.dist %>/display/{,*/}*.js',
+                        '<%= yeoman.dist %>/display/{,*/}*.css',
+                        '<%= yeoman.dist %>/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
+                    ]
+                }
+            }
+        }
+    });
+
+    grunt.registerTask('buildApp', [
+        'clean:dist',
+        'useminPrepare',
+        'copy:styles',
+        'concat',
+        'copy:dist',
+        'ngAnnotate',
+        'copy:copyCss',
+        'copy:copyJs',
+        'copy:index',
+        'uglify',
+        'rev',
+        'usemin'
+    ]);
+
+
+    grunt.registerTask('default', [
+        'buildApp'
+    ]);
+
+};

+ 387 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/Polyline.js

@@ -0,0 +1,387 @@
+/* Copyright 2005-2015 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class to generate polyline
+ *
+ * @author Dmitry Farafonov
+ */
+ 
+var ANCHOR_TYPE= {
+	main: "main",
+	middle: "middle",
+	first: "first",
+	last: "last"
+};
+
+function Anchor(uuid, type, x, y) {
+	this.uuid = uuid; 
+	this.x = x;
+	this.y = y;
+	this.type = (type == ANCHOR_TYPE.middle) ? ANCHOR_TYPE.middle : ANCHOR_TYPE.main;
+};
+Anchor.prototype = {
+	uuid: null,
+	x: 0,
+	y: 0,
+	type: ANCHOR_TYPE.main,
+	isFirst: false,
+	isLast: false,
+	ndex: 0,
+	typeIndex: 0
+};
+
+function Polyline(uuid, points, strokeWidth, paper) {
+	/* Array on coordinates:
+	 * points: [{x: 410, y: 110}, 1
+	 *			{x: 570, y: 110}, 1 2
+	 *			{x: 620, y: 240},   2 3
+	 *			{x: 750, y: 270},     3 4
+	 *			{x: 650, y: 370}];      4
+	 */
+	this.points = points;
+	
+	/*
+	 * path for graph
+	 * [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]]
+	 */
+	this.path = [];
+	
+	this.anchors = [];
+	
+	if (strokeWidth) this.strokeWidth = strokeWidth;
+	
+	this.paper = paper;
+	
+	this.closePath = false;
+	
+	this.init();
+};
+
+Polyline.prototype = {
+	id: null,
+	points: [],
+	path: [],
+	anchors: [],
+	strokeWidth: 1,
+	radius: 1,
+	showDetails: false,
+	paper: null,
+	element: null,
+	isDefaultConditionAvailable: false,
+	closePath: false,
+	
+	init: function(points){
+		var linesCount = this.getLinesCount();
+		if (linesCount < 1)
+			return;
+			
+		this.normalizeCoordinates();
+		
+		// create anchors
+		
+		this.pushAnchor(ANCHOR_TYPE.first, this.getLine(0).x1, this.getLine(0).y1);
+		
+		for (var i = 1; i < linesCount; i++)
+		{
+			var line1 = this.getLine(i-1);
+			this.pushAnchor(ANCHOR_TYPE.main,  line1.x2, line1.y2);
+		}
+		
+		this.pushAnchor(ANCHOR_TYPE.last, this.getLine(linesCount-1).x2, this.getLine(linesCount-1).y2);
+		
+		this.rebuildPath();
+	},
+	
+	normalizeCoordinates: function(){
+		for(var i=0; i < this.points.length; i++){
+			this.points[i].x = parseFloat(this.points[i].x);
+			this.points[i].y = parseFloat(this.points[i].y);
+		}
+	},
+	
+	getLinesCount: function(){
+		return this.points.length-1;
+	},
+	_getLine: function(i){
+	    if (this.points.length > i && this.points[i]) {
+	        return {x1: this.points[i].x, y1: this.points[i].y, x2: this.points[i+1].x, y2: this.points[i+1].y};
+	    } else {
+	        return undefined;
+	    }
+	},
+	getLine: function(i){
+		var line = this._getLine(i);
+		if (line != undefined) {
+		    line.angle = this.getLineAngle(i);
+		}
+		return line;
+	},
+	getLineAngle: function(i){
+		var line = this._getLine(i);
+		return Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
+	},
+	getLineLengthX: function(i){
+		var line = this.getLine(i);
+		return (line.x2 - line.x1);
+	},
+	getLineLengthY: function(i){
+		var line = this.getLine(i);
+		return (line.y2 - line.y1);
+	},
+	getLineLength: function(i){
+		return Math.sqrt(Math.pow(this.getLineLengthX(i), 2) + Math.pow(this.getLineLengthY(i), 2));
+	},
+	
+	getAnchors: function(){
+		return this.anchors;
+	},
+	getAnchorsCount: function(type){
+		if (!type)
+			return this.anchors.length;
+		else {
+			var count = 0;
+			for(var i=0; i < this.getAnchorsCount(); i++){
+				var anchor = this.anchors[i];
+				if (anchor.getType() == type) {
+					count++;
+				}
+			}
+			return count;
+		}
+	},
+	
+	pushAnchor: function(type, x, y, index){
+		if (type == ANCHOR_TYPE.first) {
+			index = 0;
+			typeIndex = 0;
+		} else if (type == ANCHOR_TYPE.last) {
+			index = this.getAnchorsCount();
+			typeIndex = 0;
+		} else if (!index) {
+			index = this.anchors.length;
+		} else {
+			for(var i=0; i < this.getAnchorsCount(); i++){
+				var anchor = this.anchors[i];
+				if (anchor.index > index) {
+					anchor.index++;
+					anchor.typeIndex++;
+				}
+			}
+		}
+		
+		var anchor = new Anchor(this.id, ANCHOR_TYPE.main, x, y, index, typeIndex);
+		
+		this.anchors.push(anchor);
+	},
+	
+	getAnchor: function(position){
+		return this.anchors[position];
+	},
+	
+	getAnchorByType: function(type, position){
+		if (type == ANCHOR_TYPE.first)
+			return this.anchors[0];
+		if (type == ANCHOR_TYPE.last)
+			return this.anchors[this.getAnchorsCount()-1];
+		
+		for(var i=0; i < this.getAnchorsCount(); i++){
+			var anchor = this.anchors[i];
+			if (anchor.type == type) {
+				if( position == anchor.position)
+					return anchor;
+			}
+		}
+		return null;
+	},
+	
+	addNewPoint: function(position, x, y){
+		// 
+		for(var i = 0; i < this.getLinesCount(); i++){
+			var line = this.getLine(i);
+			if (x > line.x1 && x < line.x2 && y > line.y1 && y < line.y2) {
+				this.points.splice(i+1,0,{x: x, y: y});
+				break;
+			}
+		}
+		
+		this.rebuildPath();
+	},
+	
+	rebuildPath: function(){
+		var path = [];
+		
+		for(var i = 0; i < this.getAnchorsCount(); i++){
+			var anchor = this.getAnchor(i);
+			
+			var pathType = "";
+			if (i == 0)
+				pathType = "M";
+			else 
+				pathType = "L";
+			
+			// TODO: save previous points and calculate new path just if points are updated, and then save currents values as previous
+			
+			var targetX = anchor.x, targetY = anchor.y;
+			if (i>0 && i < this.getAnchorsCount()-1) {
+				// get new x,y
+				var cx = anchor.x, cy = anchor.y;
+				
+				// pivot point of prev line
+				var AO = this.getLineLength(i-1);
+				if (AO < this.radius) {
+					AO = this.radius;
+				}
+				
+				this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10));
+				
+				var ED = this.getLineLengthY(i-1) * this.radius / AO;
+				var OD = this.getLineLengthX(i-1) * this.radius / AO;
+					targetX = anchor.x - OD;
+					targetY = anchor.y - ED;
+				
+				if (AO < 2*this.radius && i>1) {
+					targetX = anchor.x - this.getLineLengthX(i-1)/2;
+					targetY = anchor.y - this.getLineLengthY(i-1)/2;;
+				}
+					
+				// pivot point of next line
+				var AO = this.getLineLength(i);
+				if (AO < this.radius) {
+					AO = this.radius;
+				}
+				var ED = this.getLineLengthY(i) * this.radius / AO;
+				var OD = this.getLineLengthX(i) * this.radius / AO;
+					var nextSrcX = anchor.x + OD;
+					var nextSrcY = anchor.y + ED;
+					
+				if (AO < 2*this.radius && i<this.getAnchorsCount()-2) {
+					nextSrcX = anchor.x + this.getLineLengthX(i)/2;
+					nextSrcY = anchor.y + this.getLineLengthY(i)/2;;
+				}
+					
+				
+				var dx0 = (cx - targetX) / 3,
+					dy0 = (cy - targetY) / 3,
+					ax = cx - dx0,
+					ay = cy - dy0,
+					
+					dx1 = (cx - nextSrcX) / 3,
+					dy1 = (cy - nextSrcY) / 3,
+					bx = cx - dx1,
+					by = cy - dy1,
+					
+					zx=nextSrcX, zy=nextSrcY;
+					
+			} else if (i==1 && this.getAnchorsCount() == 2){
+				var AO = this.getLineLength(i-1);
+				if (AO < this.radius) {
+					AO = this.radius;
+				}
+				this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10));
+			}
+
+			// anti smoothing
+			if (this.strokeWidth%2 == 1) {
+				targetX += 0.5;
+				targetY += 0.5;
+			}
+			
+			path.push([pathType, targetX, targetY]);
+			
+			if (i>0 && i < this.getAnchorsCount()-1) {
+				path.push(["C", ax, ay, bx, by, zx, zy]);
+			}
+		}
+		
+		if (this.closePath) 
+		{
+			path.push(["Z"]);
+		}
+		
+		this.path = path;
+	},
+	
+	transform: function(transformation)
+	{
+		this.element.transform(transformation);
+	},
+	attr: function(attrs)
+	{
+		// TODO: foreach and set each
+		this.element.attr(attrs);
+	}
+};
+
+function Polygone(points, strokeWidth) {
+	/* Array on coordinates:
+	 * points: [{x: 410, y: 110}, 1
+	 *			{x: 570, y: 110}, 1 2
+	 *			{x: 620, y: 240},   2 3
+	 *			{x: 750, y: 270},     3 4
+	 *			{x: 650, y: 370}];      4
+	 */
+	this.points = points;
+	
+	/*
+	 * path for graph
+	 * [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]]
+	 */
+	this.path = [];
+	
+	this.anchors = [];
+	
+	if (strokeWidth) this.strokeWidth = strokeWidth;
+	
+	this.closePath = true;
+	this.init();
+};
+
+
+/*
+ * Poligone is inherited from Poliline: draws closedPath of polyline
+ */
+
+var Foo = function () { };
+Foo.prototype = Polyline.prototype;
+
+Polygone.prototype = new Foo();
+
+Polygone.prototype.rebuildPath = function(){
+	var path = [];
+	for(var i = 0; i < this.getAnchorsCount(); i++){
+		var anchor = this.getAnchor(i);
+		
+		var pathType = "";
+		if (i == 0)
+			pathType = "M";
+		else 
+			pathType = "L";
+		
+		var targetX = anchor.x, targetY = anchor.y;
+		
+		// anti smoothing
+		if (this.strokeWidth%2 == 1) {
+			targetX += 0.5;
+			targetY += 0.5;
+		}
+		
+		path.push([pathType, targetX, targetY]);	
+	}
+	if (this.closePath)
+		path.push(["Z"]);
+	
+	this.path = path;
+};

+ 824 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/bpmn-draw.js

@@ -0,0 +1,824 @@
+/* Copyright 2005-2015 Alfresco Software, Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+function _bpmnGetColor(element, defaultColor) 
+{
+    var strokeColor;
+    if(element.current) {
+        strokeColor = CURRENT_COLOR;
+    } else if(element.completed) {
+        strokeColor = COMPLETED_COLOR;
+    } else {
+        strokeColor = defaultColor;
+    }
+    return strokeColor;
+}
+
+function _drawPool(pool)
+{
+	var rect = paper.rect(pool.x, pool.y, pool.width, pool.height);
+
+	rect.attr({"stroke-width": 1,
+		"stroke": "#000000",
+		"fill": "white"
+ 	});
+	
+	if (pool.name)
+	{
+		var poolName = paper.text(pool.x + 14, pool.y + (pool.height / 2), pool.name).attr({
+	        "text-anchor" : "middle",
+	        "font-family" : "Arial",
+	        "font-size" : "12",
+	        "fill" : "#000000"
+	  	});
+		
+		poolName.transform("r270");
+	}
+	
+	if (pool.lanes)
+	{
+		for (var i = 0; i < pool.lanes.length; i++)
+		{
+			var lane = pool.lanes[i];
+			_drawLane(lane);
+		}
+	}
+}
+
+function _drawLane(lane)
+{
+	var rect = paper.rect(lane.x, lane.y, lane.width, lane.height);
+
+	rect.attr({"stroke-width": 1,
+		"stroke": "#000000",
+		"fill": "white"
+ 	});
+	
+	if (lane.name)
+	{
+		var laneName = paper.text(lane.x + 10, lane.y + (lane.height / 2), lane.name).attr({
+	        "text-anchor" : "middle",
+	        "font-family" : "Arial",
+	        "font-size" : "12",
+	        "fill" : "#000000"
+	  	});
+		
+		laneName.transform("r270");
+	}
+}
+
+function _drawSubProcess(element)
+{
+	var rect = paper.rect(element.x, element.y, element.width, element.height, 4);
+
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+	
+	rect.attr({"stroke-width": 1,
+		"stroke": strokeColor,
+		"fill": "white"
+ 	});
+}
+
+function _drawTransaction(element)
+{
+	var rect = paper.rect(element.x, element.y, element.width, element.height, 4);
+
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+	
+	rect.attr({"stroke-width": 1,
+		"stroke": strokeColor,
+		"fill": "white"
+ 	});
+	
+	var borderRect = paper.rect(element.x + 2, element.y + 2, element.width - 4, element.height -4, 4);
+	
+	borderRect.attr({"stroke-width": 1,
+		"stroke": "black",
+		"fill": "none"
+ 	});
+}
+
+function _drawEventSubProcess(element)
+{
+	var rect = paper.rect(element.x, element.y, element.width, element.height, 4);
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+	
+	rect.attr({"stroke-width": 1,
+		"stroke": strokeColor,
+		"stroke-dasharray": ".",
+		"fill": "white"
+ 	});
+}
+
+function _drawAdhocSubProcess(element)
+{
+	var rect = paper.rect(element.x, element.y, element.width, element.height, 4);
+
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+	
+	rect.attr({"stroke-width": 1,
+		"stroke": strokeColor,
+		"fill": "white"
+ 	});
+ 	
+ 	paper.text(element.x + (element.width / 2), element.y + element.height - 8).attr({
+        "text-anchor" : "middle",
+        "font-family" : "Arial",
+        "font-size" : 20,
+        "text" : "~",
+        "fill" : "#373e48"
+  	});
+}
+
+function _drawStartEvent(element)
+{
+	var startEvent = _drawEvent(element, NORMAL_STROKE, 15);
+	startEvent.click(function() {
+		_zoom(true);
+	});
+	_addHoverLogic(element, "circle", MAIN_STROKE_COLOR);
+}
+
+function _drawEndEvent(element)
+{
+	var endEvent = _drawEvent(element, ENDEVENT_STROKE, 14);
+	endEvent.click(function() {
+		_zoom(false);
+	});
+	_addHoverLogic(element, "circle", MAIN_STROKE_COLOR);
+}
+
+function _drawEvent(element, strokeWidth, radius)
+{
+	var x = element.x + (element.width / 2);
+	var y = element.y + (element.height / 2);
+
+	var circle = paper.circle(x, y, radius);
+
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+
+    // Fill
+    var eventFillColor = _determineCustomFillColor(element, "#ffffff");
+
+    // Opacity
+    var eventOpacity = 1.0;
+    if (customActivityBackgroundOpacity) {
+        eventOpacity = customActivityBackgroundOpacity;
+    }
+    
+	if (element.interrupting === undefined || element.interrupting) {
+		circle.attr({
+		    "stroke-width": strokeWidth,
+			"stroke": strokeColor,
+			"fill": eventFillColor,
+	        "fill-opacity": eventOpacity
+	 	});
+	
+	} else {
+		circle.attr({
+		    "stroke-width": strokeWidth,
+			"stroke": strokeColor,
+			"stroke-dasharray": ".",
+			"fill": eventFillColor,
+	        "fill-opacity": eventOpacity
+	 	});
+	}
+
+	circle.id = element.id;
+	
+	_drawEventIcon(paper, element);
+	
+	return circle;
+}
+
+function _drawServiceTask(element)
+{
+	_drawTask(element);
+	if (element.taskType === "mail")
+	{
+		_drawSendTaskIcon(paper, element.x + 4, element.y + 4);
+	}
+	else if (element.taskType === "camel")
+	{
+		_drawCamelTaskIcon(paper, element.x + 4, element.y + 4);
+	}
+	else if (element.taskType === "mule")
+	{
+		_drawMuleTaskIcon(paper, element.x + 4, element.y + 4);
+	}
+    else if (element.taskType === "http")
+    {
+        _drawHttpTaskIcon(paper, element.x + 4, element.y + 4);
+    }
+	else if (element.stencilIconId)
+	{
+		paper.image("../service/stencilitem/" + element.stencilIconId + "/icon", element.x + 4, element.y + 4, 16, 16);
+	}
+	else
+	{
+		_drawServiceTaskIcon(paper, element.x + 4, element.y + 4);
+	}
+	_addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawHttpServiceTask(element)
+{
+    _drawTask(element);
+    _drawHttpTaskIcon(paper, element.x + 4, element.y + 4);
+    _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawCallActivity(element)
+{
+    var width = element.width - (CALL_ACTIVITY_STROKE / 2);
+    var height = element.height - (CALL_ACTIVITY_STROKE / 2);
+
+    var rect = paper.rect(element.x, element.y, width, height, 4);
+  
+    var strokeColor = _bpmnGetColor(element, ACTIVITY_STROKE_COLOR);
+
+    // Fill
+    var callActivityFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR);
+
+    // Opacity
+    var callActivityOpacity = 1.0;
+    if (customActivityBackgroundOpacity) {
+        callActivityOpacity = customActivityBackgroundOpacity;
+    }
+
+    rect.attr({"stroke-width": CALL_ACTIVITY_STROKE,
+        "stroke": strokeColor,
+        "fill": callActivityFillColor,
+        "fill-opacity": callActivityOpacity
+    });
+  
+    rect.id = element.id;
+  
+    if (element.name) {
+        this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11);
+    }
+    _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawScriptTask(element)
+{
+	_drawTask(element);
+	_drawScriptTaskIcon(paper, element.x + 4, element.y + 4);
+	_addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawUserTask(element)
+{
+	_drawTask(element);
+	_drawUserTaskIcon(paper, element.x + 4, element.y + 4);
+	_addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawBusinessRuleTask(element)
+{
+	_drawTask(element);
+	_drawBusinessRuleTaskIcon(paper, element.x + 4, element.y + 4);
+	_addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawManualTask(element)
+{
+	_drawTask(element);
+	_drawManualTaskIcon(paper, element.x + 4, element.y + 4);
+	_addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawSendTask(element)
+{
+    _drawTask(element);
+    _drawSendTaskIcon(paper, element.x + 4, element.y + 4);
+    _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawReceiveTask(element)
+{
+	_drawTask(element);
+	_drawReceiveTaskIcon(paper, element.x, element.y);
+	_addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR);
+}
+
+function _drawTask(element)
+{
+    var rectAttrs = {};
+    
+    // Stroke
+    var strokeColor = _bpmnGetColor(element, ACTIVITY_STROKE_COLOR);
+    rectAttrs['stroke'] = strokeColor;
+    
+    var strokeWidth;
+    if (strokeColor === ACTIVITY_STROKE_COLOR) {
+        strokeWidth = TASK_STROKE;
+    } else {
+        strokeWidth = TASK_HIGHLIGHT_STROKE;
+    }
+    
+	var width = element.width - (strokeWidth / 2);
+	var height = element.height - (strokeWidth / 2);
+
+	var rect = paper.rect(element.x, element.y, width, height, 4);
+    rectAttrs['stroke-width'] = strokeWidth;
+
+    // Fill
+	var fillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR);
+    rectAttrs['fill'] = fillColor;
+
+    // Opacity
+    if (customActivityBackgroundOpacity) {
+        rectAttrs['fill-opacity'] = customActivityBackgroundOpacity;
+    }
+
+	rect.attr(rectAttrs);
+	rect.id = element.id;
+	
+	if (element.name) {
+		this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11);
+	}
+}
+
+function _drawExclusiveGateway(element)
+{
+	_drawGateway(element);
+	var quarterWidth = element.width / 4;
+	var quarterHeight = element.height / 4;
+	
+	var iks = paper.path(
+		"M" + (element.x + quarterWidth + 3) + " " + (element.y + quarterHeight + 3) + 
+		"L" + (element.x + 3 * quarterWidth - 3) + " " + (element.y + 3 * quarterHeight - 3) + 
+		"M" + (element.x + quarterWidth + 3) + " " + (element.y + 3 * quarterHeight - 3) + 
+		"L" + (element.x + 3 * quarterWidth - 3) + " " + (element.y + quarterHeight + 3)
+	);
+	
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+
+    // Fill
+    var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR);
+
+    // Opacity
+    var gatewayOpacity = 1.0;
+    if (customActivityBackgroundOpacity) {
+        gatewayOpacity = customActivityBackgroundOpacity;
+    }
+
+
+    iks.attr({"stroke-width": 3, "stroke": strokeColor, "fill": gatewayFillColor, "fill-opacity": gatewayOpacity});
+	
+	_addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR);
+}
+
+function _drawParallelGateway(element)
+{
+	_drawGateway(element);
+	
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+	
+	var path1 = paper.path("M 6.75,16 L 25.75,16 M 16,6.75 L 16,25.75");
+
+    // Fill
+    var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR);
+
+    // Opacity
+    var gatewayOpacity = 1.0;
+    if (customActivityBackgroundOpacity) {
+        gatewayOpacity = customActivityBackgroundOpacity;
+    }
+
+	path1.attr({
+		"stroke-width": 3, 
+		"stroke": strokeColor,
+		"fill": gatewayFillColor,
+        "fill-opacity": gatewayOpacity
+	});
+	
+	path1.transform("T" + (element.x + 4) + "," + (element.y + 4));
+	
+	_addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR);
+}
+
+function _drawInclusiveGateway(element)
+{
+	_drawGateway(element);
+	
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+	
+	var circle1 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 9.75);
+
+    // Fill
+    var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR);
+
+    // Opacity
+    var gatewayOpacity = 1.0;
+    if (customActivityBackgroundOpacity) {
+        gatewayOpacity = customActivityBackgroundOpacity;
+    }
+
+	circle1.attr({
+		"stroke-width": 2.5, 
+		"stroke": strokeColor,
+		"fill": gatewayFillColor,
+        "fill-opacity": gatewayOpacity
+	});
+	
+	_addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR);
+}
+
+function _drawEventGateway(element)
+{
+	_drawGateway(element);
+	
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+	
+	var circle1 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 10.4);
+
+    // Fill
+    var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR);
+
+    // Opacity
+    var gatewayOpacity = 1.0;
+    if (customActivityBackgroundOpacity) {
+        gatewayOpacity = customActivityBackgroundOpacity;
+    }
+
+	circle1.attr({
+		"stroke-width": 0.5, 
+		"stroke": strokeColor,
+		"fill": gatewayFillColor,
+        "fill-opacity": gatewayOpacity
+    });
+	
+	var circle2 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 11.7);
+	circle2.attr({
+		"stroke-width": 0.5, 
+		"stroke": strokeColor,
+        "fill": gatewayFillColor,
+        "fill-opacity": gatewayOpacity
+	});
+	
+	var path1 = paper.path("M 20.327514,22.344972 L 11.259248,22.344216 L 8.4577203,13.719549 L 15.794545,8.389969 L 23.130481,13.720774 L 20.327514,22.344972 z");
+	path1.attr({
+		"stroke-width": 1.39999998, 
+		"stroke": strokeColor,
+        "fill": gatewayFillColor,
+        "fill-opacity": gatewayOpacity,
+		"stroke-linejoin": "bevel"
+	});
+	
+	path1.transform("T" + (element.x + 4) + "," + (element.y + 4));
+	
+	_addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR);
+}
+
+function _drawGateway(element)
+{
+    var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+    
+	var rhombus = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + 
+		"L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + 
+		"L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) +
+		"L" + (element.x + (element.width / 2)) + " " + element.y + "z"
+	);
+
+    // Fill
+    var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR);
+
+    // Opacity
+    var gatewayOpacity = 1.0;
+    if (customActivityBackgroundOpacity) {
+        gatewayOpacity = customActivityBackgroundOpacity;
+    }
+
+	rhombus.attr("stroke-width", 2);
+	rhombus.attr("stroke", strokeColor);
+	rhombus.attr("fill", gatewayFillColor);
+    rhombus.attr("fill-opacity", gatewayOpacity);
+	
+	rhombus.id = element.id;
+	
+	return rhombus;
+}
+
+function _drawBoundaryEvent(element)
+{
+	var x = element.x + (element.width / 2);
+	var y = element.y + (element.height / 2);
+
+	var circle = paper.circle(x, y, 15);
+	
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+
+ 	if (element.cancelActivity)  {
+		circle.attr({
+		    "stroke-width": 1,
+			"stroke": strokeColor,
+			"fill": "white"
+	 	});
+	 	
+	} else {
+		circle.attr({
+		    "stroke-width": 1,
+		    "stroke-dasharray": ".",
+			"stroke": strokeColor,
+			"fill": "white"
+	 	});
+	}
+	
+	var innerCircle = paper.circle(x, y, 12);
+	
+	if (element.cancelActivity)  {
+		innerCircle.attr({"stroke-width": 1,
+			"stroke": strokeColor,
+			"fill": "none"
+	 	});
+	
+	} else {
+		innerCircle.attr({
+		    "stroke-width": 1,
+		    "stroke-dasharray": ".",
+			"stroke": strokeColor,
+			"fill": "none"
+	 	});
+	}
+	
+	_drawEventIcon(paper, element);
+	_addHoverLogic(element, "circle", MAIN_STROKE_COLOR);
+	
+	circle.id = element.id;
+	innerCircle.id = element.id + "_inner";
+}
+
+function _drawIntermediateCatchEvent(element)
+{
+	var x = element.x + (element.width / 2);
+	var y = element.y + (element.height / 2);
+
+	var circle = paper.circle(x, y, 15);
+	
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+
+	circle.attr({"stroke-width": 1,
+		"stroke": strokeColor,
+		"fill": "white"
+ 	});
+	
+	var innerCircle = paper.circle(x, y, 12);
+	
+	innerCircle.attr({"stroke-width": 1,
+		"stroke": strokeColor,
+		"fill": "none"
+ 	});
+	
+	_drawEventIcon(paper, element);
+	_addHoverLogic(element, "circle", MAIN_STROKE_COLOR);
+	
+	circle.id = element.id;
+	innerCircle.id = element.id + "_inner";
+}
+
+function _drawThrowEvent(element)
+{
+	var x = element.x + (element.width / 2);
+	var y = element.y + (element.height / 2);
+
+	var circle = paper.circle(x, y, 15);
+
+	var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR);
+	
+	circle.attr({"stroke-width": 1,
+		"stroke": strokeColor,
+		"fill": "white"
+ 	});
+	
+	var innerCircle = paper.circle(x, y, 12);
+	
+	innerCircle.attr({"stroke-width": 1,
+		"stroke": strokeColor,
+		"fill": "none"
+ 	});
+	
+	_drawEventIcon(paper, element);
+	_addHoverLogic(element, "circle", MAIN_STROKE_COLOR);
+	
+	circle.id = element.id;
+	innerCircle.id = element.id + "_inner";
+}
+
+function _drawMultilineText(text, x, y, boxWidth, boxHeight, horizontalAnchor, verticalAnchor, fontSize) 
+{
+	if (!text || text == "")
+	{
+		return;
+	}
+	
+	var textBoxX, textBoxY;
+    var width = boxWidth - (2 * TEXT_PADDING);
+    
+    if (horizontalAnchor === "middle")
+    {
+    	textBoxX = x + (boxWidth / 2);
+    }
+    else if (horizontalAnchor === "start")
+    {
+    	textBoxX = x;
+    }
+    
+    textBoxY = y + (boxHeight / 2);
+    
+ 	var t = paper.text(textBoxX + TEXT_PADDING, textBoxY + TEXT_PADDING).attr({
+        "text-anchor" : horizontalAnchor,
+        "font-family" : "Arial",
+        "font-size" : fontSize,
+        "fill" : "#373e48"
+  	});
+  	
+    var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    t.attr({
+        "text" : abc
+    });
+    var letterWidth = t.getBBox().width / abc.length;
+	   
+    t.attr({
+        "text" : text
+    });
+    var removedLineBreaks = text.split("\n");
+    var x = 0, s = [];
+    for (var r = 0; r < removedLineBreaks.length; r++)
+    {
+  	    var words = removedLineBreaks[r].split(" ");
+  	    for ( var i = 0; i < words.length; i++) {
+  
+  	        var l = words[i].length;
+  	        if (x + (l * letterWidth) > width) {
+  	            s.push("\n");
+  	            x = 0;
+  	        }
+  	        x += l * letterWidth;
+  	        s.push(words[i] + " ");
+  	    }
+	  	s.push("\n");
+        x = 0;
+    }
+    t.attr({
+    	"text" : s.join("")
+    });
+    
+    if (verticalAnchor && verticalAnchor === "top")
+    {
+    	t.attr({"y": y + (t.getBBox().height / 2)});
+    }
+}
+
+function _drawTextAnnotation(element)
+{
+	var path1 = paper.path("M20,1 L1,1 L1,50 L20,50");
+	path1.attr({
+		"stroke": "#585858",
+		"fill": "none"
+ 	});
+	
+	var annotation = paper.set();
+	annotation.push(path1);
+
+	annotation.transform("T" + element.x + "," + element.y);
+	
+	if (element.text) {
+		this._drawMultilineText(element.text, element.x + 2, element.y, element.width, element.height, "start", "middle", 11);
+	}
+}
+ 
+function _drawFlow(flow){
+	
+	var polyline = new Polyline(flow.id, flow.waypoints, SEQUENCEFLOW_STROKE, paper);
+	
+	var strokeColor = _bpmnGetColor(flow, MAIN_STROKE_COLOR);
+	
+	polyline.element = paper.path(polyline.path);
+	polyline.element.attr({"stroke-width":SEQUENCEFLOW_STROKE});
+	polyline.element.attr({"stroke":strokeColor});
+	
+	polyline.element.id = flow.id;
+	
+	var lastLineIndex = polyline.getLinesCount() - 1;
+	var line = polyline.getLine(lastLineIndex);
+	
+	if (line == undefined) return;
+	
+	if (flow.type == "connection" && flow.conditions)
+	{
+		var middleX = (line.x1 + line.x2) / 2;
+		var middleY = (line.y1 + line.y2) / 2;
+		var image = paper.image("../editor/images/condition-flow.png", middleX - 8, middleY - 8, 16, 16);
+	}
+	
+	var polylineInvisible = new Polyline(flow.id, flow.waypoints, SEQUENCEFLOW_STROKE, paper);
+	
+	polylineInvisible.element = paper.path(polyline.path);
+	polylineInvisible.element.attr({
+			"opacity": 0,
+			"stroke-width": 8,
+            "stroke" : "#000000"
+	});
+	
+	_showTip(jQuery(polylineInvisible.element.node), flow);
+	
+	polylineInvisible.element.mouseover(function() {
+		paper.getById(polyline.element.id).attr({"stroke":"blue"});
+	});
+	
+	polylineInvisible.element.mouseout(function() {
+		paper.getById(polyline.element.id).attr({"stroke":"#585858"});
+	});
+	
+	_drawArrowHead(line);
+}
+
+function _drawAssociation(flow){
+	
+	var polyline = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper);
+	
+	polyline.element = paper.path(polyline.path);
+	polyline.element.attr({"stroke-width": ASSOCIATION_STROKE});
+	polyline.element.attr({"stroke-dasharray": ". "});
+	polyline.element.attr({"stroke":"#585858"});
+	
+	polyline.element.id = flow.id;
+	
+	var polylineInvisible = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper);
+	
+	polylineInvisible.element = paper.path(polyline.path);
+	polylineInvisible.element.attr({
+			"opacity": 0,
+			"stroke-width": 8,
+            "stroke" : "#000000"
+	});
+	
+	_showTip(jQuery(polylineInvisible.element.node), flow);
+	
+	polylineInvisible.element.mouseover(function() {
+		paper.getById(polyline.element.id).attr({"stroke":"blue"});
+	});
+	
+	polylineInvisible.element.mouseout(function() {
+		paper.getById(polyline.element.id).attr({"stroke":"#585858"});
+	});
+}
+
+function _drawArrowHead(line, connectionType) 
+{
+	var doubleArrowWidth = 2 * ARROW_WIDTH;
+	
+	var arrowHead = paper.path("M0 0L-" + (ARROW_WIDTH / 2 + .5) + " -" + doubleArrowWidth + "L" + (ARROW_WIDTH/2 + .5) + " -" + doubleArrowWidth + "z");
+	
+	// anti smoothing
+	if (this.strokeWidth%2 == 1)
+		line.x2 += .5, line.y2 += .5;
+	
+	arrowHead.transform("t" + line.x2 + "," + line.y2 + "");
+	arrowHead.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0);
+	
+	arrowHead.attr("fill", "#585858");
+		
+	arrowHead.attr("stroke-width", SEQUENCEFLOW_STROKE);
+	arrowHead.attr("stroke", "#585858");
+	
+	return arrowHead;
+}
+
+function _determineCustomFillColor(element, defaultColor) {
+
+    var color;
+
+    // By name
+    if (customActivityColors && customActivityColors[element.name]) {
+        color = customActivityColors[element.name];
+    }
+
+    if (color !== null && color !== undefined) {
+        return color;
+    }
+
+    // By id
+    if (customActivityColors && customActivityColors[element.id]) {
+        color = customActivityColors[element.id];
+    }
+
+    if (color !== null && color !== undefined) {
+        return color;
+    }
+
+    return defaultColor;
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 303 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/bpmn-icons.js


+ 24 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/displaymodel.css

@@ -0,0 +1,24 @@
+div[class*='ui-tooltip-kisbpm-'] {
+    background-color: #ffffff;
+    border-color: #c5c5c5;
+    color: #4a4a4a;
+    font-family: Verdana;
+    font-size: 12px;
+}
+
+div[class*='ui-tooltip-kisbpm-'] .qtip-content {
+  color: #4a4a4a;
+  background-color: #ffffff;
+  font-family: Verdana;
+  font-size: 12px;
+}
+
+.ui-tooltip-kisbpm-bpmn .qtip-titlebar {
+  color: #FFFFFF;
+  font-size: 12px;
+  background: #2B414F;
+}
+
+.ui-tooltip-kisbpm-bpmn .qtip-tip {
+  background-color: #2B414F;
+}

+ 19 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/displaymodel.html

@@ -0,0 +1,19 @@
+<html>  
+    <head>
+
+        <!-- build:css display/styles/displaymodel-style.css -->
+        <link type="text/css" rel="stylesheet" href="display/jquery.qtip.min.css" />
+        <link type="text/css" rel="stylesheet" href="display/displaymodel.css" />
+        <!-- endbuild -->
+
+        <!-- build:js display/scripts/displaymodel-logic.js -->
+        <script type="text/javascript" src="display/jquery.qtip.min.js"></script>
+        <script type="text/javascript" src="display/raphael.js"></script>
+        <script type="text/javascript" src="display/bpmn-draw.js"></script>
+        <script type="text/javascript" src="display/bpmn-icons.js"></script>
+        <script type="text/javascript" src="display/Polyline.js"></script>
+        <script type="text/javascript" src="display/displaymodel.js"></script>
+        <!-- endbuild -->
+
+    </head>
+</html>

+ 317 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/displaymodel.js

@@ -0,0 +1,317 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var NORMAL_STROKE = 1;
+var SEQUENCEFLOW_STROKE = 1.5;
+var ASSOCIATION_STROKE = 2;
+var TASK_STROKE = 1;
+var TASK_HIGHLIGHT_STROKE = 2;
+var CALL_ACTIVITY_STROKE = 2;
+var ENDEVENT_STROKE = 3;
+
+var COMPLETED_COLOR= "#2632aa";
+var TEXT_COLOR= "#373e48";
+var CURRENT_COLOR= "#017501";
+var HOVER_COLOR= "#666666";
+var ACTIVITY_STROKE_COLOR = "#bbbbbb";
+var ACTIVITY_FILL_COLOR = "#f9f9f9";
+var MAIN_STROKE_COLOR = "#585858";
+
+var TEXT_PADDING = 3;
+var ARROW_WIDTH = 4;
+var MARKER_WIDTH = 12;
+
+var TASK_FONT = {font: "11px Arial", opacity: 1, fill: Raphael.rgb(0, 0, 0)};
+
+// icons
+var ICON_SIZE = 16;
+var ICON_PADDING = 4;
+
+var INITIAL_CANVAS_WIDTH;
+var INITIAL_CANVAS_HEIGHT;
+
+var paper;
+var viewBox;
+var viewBoxWidth;
+var viewBoxHeight;
+
+var canvasWidth;
+var canvasHeight;
+
+var modelDiv = jQuery('#bpmnModel');
+var modelId = modelDiv.attr('data-model-id');
+var historyModelId = modelDiv.attr('data-history-id');
+var processDefinitionId = modelDiv.attr('data-process-definition-id');
+var modelType = modelDiv.attr('data-model-type');
+
+// Support for custom background colors for activities
+var customActivityColors = modelDiv.attr('data-activity-color-mapping');
+if (customActivityColors !== null && customActivityColors !== undefined && customActivityColors.length > 0) {
+    // Stored on the attribute as a string
+    customActivityColors = JSON.parse(customActivityColors);
+}
+
+var customActivityToolTips = modelDiv.attr('data-activity-tooltips');
+if (customActivityToolTips !== null && customActivityToolTips !== undefined && customActivityToolTips.length > 0) {
+    // Stored on the attribute as a string
+    customActivityToolTips = JSON.parse(customActivityToolTips);
+}
+
+// Support for custom opacity for activity backgrounds
+var customActivityBackgroundOpacity = modelDiv.attr('data-activity-opacity');
+
+var elementsAdded = new Array();
+var elementsRemoved = new Array();
+
+function _showTip(htmlNode, element)
+{
+
+    // Custom tooltip
+    var documentation = undefined;
+    if (customActivityToolTips) {
+        if (customActivityToolTips[element.name]) {
+            documentation = customActivityToolTips[element.name];
+        } else if (customActivityToolTips[element.id]) {
+            documentation = customActivityToolTips[element.id];
+        } else {
+            documentation = ''; // Show nothing if custom tool tips are enabled
+        }
+    }
+
+    // Default tooltip, no custom tool tip set
+    if (documentation === undefined) {
+        var documentation = "";
+        if (element.name && element.name.length > 0) {
+            documentation += "<b>Name</b>: <i>" + element.name + "</i><br/><br/>";
+        }
+
+        if (element.properties) {
+            for (var i = 0; i < element.properties.length; i++) {
+                var propName = element.properties[i].name;
+                if (element.properties[i].type && element.properties[i].type === 'list') {
+                    documentation += '<b>' + propName + '</b>:<br/>';
+                    for (var j = 0; j < element.properties[i].value.length; j++) {
+                        documentation += '<i>' + element.properties[i].value[j] + '</i><br/>';
+                    }
+                }
+                else {
+                    documentation += '<b>' + propName + '</b>: <i>' + element.properties[i].value + '</i><br/>';
+                }
+            }
+        }
+    }
+
+    var text = element.type + " ";
+    if (element.name && element.name.length > 0)
+    {
+        text += element.name;
+    }
+    else
+    {
+        text += element.id;
+    }
+
+    htmlNode.qtip({
+        content: {
+            text: documentation,
+            title: {
+                text: text
+            }
+        },
+        position: {
+            my: 'top left',
+            at: 'bottom center',
+            viewport: jQuery('#bpmnModel')
+        },
+        hide: {
+            fixed: true, delay: 500,
+            event: 'click mouseleave'
+        },
+        style: {
+            classes: 'ui-tooltip-kisbpm-bpmn'
+        }
+    });
+}
+
+function _addHoverLogic(element, type, defaultColor)
+{
+    var strokeColor = _bpmnGetColor(element, defaultColor);
+    var topBodyRect = null;
+    if (type === "rect")
+    {
+        topBodyRect = paper.rect(element.x, element.y, element.width, element.height);
+    }
+    else if (type === "circle")
+    {
+        var x = element.x + (element.width / 2);
+        var y = element.y + (element.height / 2);
+        topBodyRect = paper.circle(x, y, 15);
+    }
+    else if (type === "rhombus")
+    {
+        topBodyRect = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) +
+            "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) +
+            "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) +
+            "L" + (element.x + (element.width / 2)) + " " + element.y + "z"
+        );
+    }
+
+    var opacity = 0;
+    var fillColor = "#ffffff";
+    if (jQuery.inArray(element.id, elementsAdded) >= 0)
+    {
+        opacity = 0.2;
+        fillColor = "green";
+    }
+
+    if (jQuery.inArray(element.id, elementsRemoved) >= 0)
+    {
+        opacity = 0.2;
+        fillColor = "red";
+    }
+
+    topBodyRect.attr({
+        "opacity": opacity,
+        "stroke" : "none",
+        "fill" : fillColor
+    });
+    _showTip(jQuery(topBodyRect.node), element);
+
+    topBodyRect.mouseover(function() {
+        paper.getById(element.id).attr({"stroke":HOVER_COLOR});
+    });
+
+    topBodyRect.mouseout(function() {
+        paper.getById(element.id).attr({"stroke":strokeColor});
+    });
+}
+
+function _zoom(zoomIn)
+{
+    var tmpCanvasWidth, tmpCanvasHeight;
+    if (zoomIn)
+    {
+        tmpCanvasWidth = canvasWidth * (1.0/0.90);
+        tmpCanvasHeight = canvasHeight * (1.0/0.90);
+    }
+    else
+    {
+        tmpCanvasWidth = canvasWidth * (1.0/1.10);
+        tmpCanvasHeight = canvasHeight * (1.0/1.10);
+    }
+
+    if (tmpCanvasWidth != canvasWidth || tmpCanvasHeight != canvasHeight)
+    {
+        canvasWidth = tmpCanvasWidth;
+        canvasHeight = tmpCanvasHeight;
+        paper.setSize(canvasWidth, canvasHeight);
+    }
+}
+
+var modelUrl;
+
+if (modelType == 'runtime') {
+	if (historyModelId) {
+    	modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/process-instances/history/' + historyModelId + '/model-json';
+	} else {
+    	modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/process-instances/' + modelId + '/model-json';
+	}
+} else if (modelType == 'design') {
+	if (historyModelId) {
+    	modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/models/' + modelId + '/history/' + historyModelId + '/model-json';
+	} else {
+    	modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/models/' + modelId + '/model-json';
+	}
+} else if (modelType == 'process-definition') {
+    modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/process-definitions/' + processDefinitionId + '/model-json';
+}
+
+var request = jQuery.ajax({
+    type: 'get',
+    url: modelUrl + '?nocaching=' + new Date().getTime()
+});
+
+request.success(function(data, textStatus, jqXHR) {
+
+    if ((!data.elements || data.elements.length == 0) && (!data.pools || data.pools.length == 0)) return;
+
+    INITIAL_CANVAS_WIDTH = data.diagramWidth;
+    
+    if (modelType == 'design') {
+    	INITIAL_CANVAS_WIDTH += 20;
+    } else {
+        INITIAL_CANVAS_WIDTH += 30;
+    }
+    
+    INITIAL_CANVAS_HEIGHT = data.diagramHeight + 50;
+    canvasWidth = INITIAL_CANVAS_WIDTH;
+    canvasHeight = INITIAL_CANVAS_HEIGHT;
+    viewBoxWidth = INITIAL_CANVAS_WIDTH;
+    viewBoxHeight = INITIAL_CANVAS_HEIGHT;
+    
+    if (modelType == 'design') {
+    	var headerBarHeight = 170;
+    	var offsetY = 0;
+    	if (jQuery(window).height() > (canvasHeight + headerBarHeight))
+    	{
+        	offsetY = (jQuery(window).height() - headerBarHeight - canvasHeight) / 2;
+    	}
+
+    	if (offsetY > 50) {
+        	offsetY = 50;
+    	}
+
+    	jQuery('#bpmnModel').css('marginTop', offsetY);
+    }
+
+    jQuery('#bpmnModel').width(INITIAL_CANVAS_WIDTH);
+    jQuery('#bpmnModel').height(INITIAL_CANVAS_HEIGHT);
+    paper = Raphael(document.getElementById('bpmnModel'), canvasWidth, canvasHeight);
+    paper.setViewBox(0, 0, viewBoxWidth, viewBoxHeight, false);
+    paper.renderfix();
+
+    if (data.pools)
+    {
+        for (var i = 0; i < data.pools.length; i++)
+        {
+            var pool = data.pools[i];
+            _drawPool(pool);
+        }
+    }
+
+    var modelElements = data.elements;
+    for (var i = 0; i < modelElements.length; i++)
+    {
+        var element = modelElements[i];
+        //try {
+        var drawFunction = eval("_draw" + element.type);
+        drawFunction(element);
+        //} catch(err) {console.log(err);}
+    }
+
+    if (data.flows)
+    {
+        for (var i = 0; i < data.flows.length; i++)
+        {
+            var flow = data.flows[i];
+            if (flow.type === 'sequenceFlow') {
+                _drawFlow(flow);
+            } else if (flow.type === 'association') {
+                _drawAssociation(flow);
+            }
+        }
+    }
+});
+
+request.error(function(jqXHR, textStatus, errorThrown) {
+    alert("error");
+});

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/jquery.qtip.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 5 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/jquery.qtip.min.js


+ 37 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/package.json

@@ -0,0 +1,37 @@
+{
+  "name": "displaymodel",
+  "version": "1.0.0",
+  "dependencies": {},
+  "devDependencies": {
+    "grunt": "0.4.2",
+    "grunt-autoprefixer": "0.4.0",
+    "grunt-bower-install": "0.7.0",
+    "grunt-concurrent": "0.4.1",
+    "grunt-contrib-clean": "0.5.0",
+    "grunt-contrib-coffee": "0.7.0",
+    "grunt-contrib-compass": "0.6.0",
+    "grunt-contrib-concat": "0.3.0",
+    "grunt-contrib-connect": "0.5.0",
+    "grunt-contrib-copy": "0.4.1",
+    "grunt-contrib-cssmin": "0.7.0",
+    "grunt-contrib-htmlmin": "0.1.3",
+    "grunt-contrib-imagemin": "0.3.0",
+    "grunt-contrib-jshint": "0.7.1",
+    "grunt-contrib-uglify": "0.2.0",
+    "grunt-contrib-watch": "0.5.2",
+    "grunt-google-cdn": "0.2.0",
+    "grunt-newer": "0.5.4",
+    "grunt-ng-annotate": "0.5.0",
+    "grunt-rev": "0.1.0",
+    "grunt-svgmin": "0.2.0",
+    "grunt-usemin": "2.0.0",
+    "jshint-stylish": "0.1.3",
+    "load-grunt-tasks": "0.2.0",
+    "time-grunt": "0.2.1",
+    "grunt-text-replace": "0.3.11",
+    "grunt-contrib-rename": "0.0.3"
+  },
+  "engines": {
+    "node": ">=0.8.0"
+  }
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 8078 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/display/raphael.js


+ 19 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/flowable-header-custom.js

@@ -0,0 +1,19 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+FLOWABLE.HEADER_CONFIG.showAppTitle = false;
+FLOWABLE.HEADER_CONFIG.showHeaderMenu = false;
+FLOWABLE.HEADER_CONFIG.showMainNavigation = false;
+FLOWABLE.HEADER_CONFIG.showPageHeader = false;

+ 39 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/flowable-toolbar-custom-actions.js

@@ -0,0 +1,39 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Create custom functions for the FLOWABLE-editor
+FLOWABLE.TOOLBAR.ACTIONS.closeEditor =  function(services) {
+	services.$location.path("/processes");
+};
+
+FLOWABLE.TOOLBAR.ACTIONS.navigateToProcess = function(processId) {
+    var navigateEvent = {
+        type: FLOWABLE.eventBus.EVENT_TYPE_NAVIGATE_TO_PROCESS,
+        processId: processId
+    };
+    FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_NAVIGATE_TO_PROCESS, navigateEvent);
+},
+
+// Add custom buttons 
+FLOWABLE.TOOLBAR_CONFIG.secondaryItems.push( 
+	{
+        "type" : "button",
+        "title" : "Close",
+        "cssClass" : "glyphicon glyphicon-remove",
+        "action" : "FLOWABLE.TOOLBAR.ACTIONS.closeEditor"
+    }
+);
+
+
+
+

+ 504 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-assignment-controller.js

@@ -0,0 +1,504 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Assignment
+ */
+'use strict';
+
+angular.module('flowableModeler').controller('FlowableAssignmentCtrl', [ '$scope', '$modal', function($scope, $modal) {
+
+    // Config for the modal window
+    var opts = {
+        template:  'editor-app/configuration/properties/assignment-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    // Open the dialog
+    _internalCreateModal(opts, $modal, $scope);
+}]);
+
+angular.module('flowableModeler').controller('FlowableAssignmentPopupCtrl',
+    [ '$rootScope', '$scope', '$translate', '$http', 'UserService', 'GroupService', function($rootScope, $scope, $translate, $http, UserService, GroupService) {
+
+    // Put json representing assignment on scope
+    if ($scope.property.value !== undefined && $scope.property.value !== null
+        && $scope.property.value.assignment !== undefined
+        && $scope.property.value.assignment !== null) {
+
+        $scope.assignment = $scope.property.value.assignment;
+
+    } else {
+        $scope.assignment = {type:'idm'};
+    }
+
+    $scope.popup = {
+        assignmentObject: {
+            type:$scope.assignment.type,
+            idm: {
+                type:undefined,
+                assignee: undefined,
+                candidateUsers: [],
+                candidateGroups: []
+            },
+            static: {
+                assignee: undefined,
+                candidateUsers: [],
+                candidateGroups: []
+            }
+        }
+    };
+
+
+    $scope.assignmentOptions = [
+        {id: "initiator", title: $translate.instant('PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR')},
+        {id: "user", title: $translate.instant('PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER')},
+        {id: "users", title: $translate.instant('PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS')},
+        {id: "groups", title: $translate.instant('PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS')}
+    ];
+
+    if ($scope.assignment.idm && $scope.assignment.idm.type) {
+        for (var i = 0; i < $scope.assignmentOptions.length; i++) {
+            if ($scope.assignmentOptions[i].id == $scope.assignment.idm.type) {
+                $scope.assignmentOption = $scope.assignmentOptions[i];
+                break;
+            }
+        }
+    }
+
+    // fill the IDM area
+    if (!$scope.assignmentOption) {
+        // Default, first time opening the popup
+        $scope.assignmentOption = $scope.assignmentOptions[0];
+    } else {
+        // Values already filled
+        if ($scope.assignment.idm) { //fill the IDM tab
+            if ($scope.assignment.idm.assignee) {
+                if ($scope.assignment.idm.assignee.id) {
+                    $scope.popup.assignmentObject.idm.assignee = $scope.assignment.idm.assignee;
+                } else {
+                    $scope.popup.assignmentObject.idm.assignee = {email: $scope.assignment.idm.assignee.email};
+                }
+            }
+
+            if ($scope.assignment.idm.candidateUsers && $scope.assignment.idm.candidateUsers.length > 0) {
+                for (var i = 0; i < $scope.assignment.idm.candidateUsers.length; i++) {
+                    $scope.popup.assignmentObject.idm.candidateUsers.push($scope.assignment.idm.candidateUsers[i]);
+                }
+            }
+
+            if ($scope.assignment.idm.candidateGroups && $scope.assignment.idm.candidateGroups.length > 0) {
+                for (var i = 0; i < $scope.assignment.idm.candidateGroups.length; i++) {
+                    $scope.popup.assignmentObject.idm.candidateGroups.push($scope.assignment.idm.candidateGroups[i]);
+                }
+            }
+        }
+    }
+    
+    //fill the static area
+    if ($scope.assignment.assignee) {
+        $scope.popup.assignmentObject.static.assignee = $scope.assignment.assignee;
+    }
+
+    if ($scope.assignment.candidateUsers && $scope.assignment.candidateUsers.length > 0) {
+        for (var i = 0; i < $scope.assignment.candidateUsers.length; i++) {
+            $scope.popup.assignmentObject.static.candidateUsers.push($scope.assignment.candidateUsers[i]);
+        }
+    }
+
+    if ($scope.assignment.candidateGroups && $scope.assignment.candidateGroups.length > 0) {
+        for (var i = 0; i < $scope.assignment.candidateGroups.length; i++) {
+            $scope.popup.assignmentObject.static.candidateGroups.push($scope.assignment.candidateGroups[i]);
+        }
+    }
+
+    initStaticContextForEditing($scope);
+
+    $scope.$watch('popup.groupFilter', function () {
+        $scope.updateGroupFilter();
+    });
+
+    $scope.$watch('popup.filter', function() {
+        $scope.updateFilter();
+    });
+
+    $scope.updateFilter = function() {
+        if ($scope.popup.oldFilter == undefined || $scope.popup.oldFilter != $scope.popup.filter) {
+            if (!$scope.popup.filter) {
+                $scope.popup.oldFilter = '';
+            } else {
+                $scope.popup.oldFilter = $scope.popup.filter;
+            }
+
+            if ($scope.popup.filter !== null && $scope.popup.filter !== undefined) {
+                UserService.getFilteredUsers($scope.popup.filter).then(function (result) {
+                    var filteredUsers = [];
+                    for (var i=0; i<result.data.length; i++) {
+                        var filteredUser = result.data[i];
+
+                        var foundCandidateUser = false;
+                        if ($scope.popup.assignmentObject.idm.candidateUsers !== null && $scope.popup.assignmentObject.idm.candidateUsers !== undefined) {
+                            for (var j=0; j<$scope.popup.assignmentObject.idm.candidateUsers.length; j++) {
+                                var candidateUser = $scope.popup.assignmentObject.idm.candidateUsers[j];
+                                if (candidateUser.id === filteredUser.id) {
+                                    foundCandidateUser = true;
+                                    break;
+                                }
+                            }
+                        }
+
+                        if (!foundCandidateUser) {
+                            filteredUsers.push(filteredUser);
+                        }
+
+                    }
+
+                    $scope.popup.userResults = filteredUsers;
+                    $scope.resetSelection();
+                });
+            }
+        }
+    };
+
+    $scope.updateGroupFilter = function() {
+        if ($scope.popup.oldGroupFilter == undefined || $scope.popup.oldGroupFilter != $scope.popup.groupFilter) {
+            if (!$scope.popup.groupFilter) {
+                $scope.popup.oldGroupFilter = '';
+            } else {
+                $scope.popup.oldGroupFilter = $scope.popup.groupFilter;
+            }
+
+            GroupService.getFilteredGroups($scope.popup.groupFilter).then(function(result) {
+                $scope.popup.groupResults = result.data;
+                $scope.resetGroupSelection();
+            });
+        }
+    };
+
+    $scope.confirmUser = function(user) {
+        if (!user) {
+            // Selection is done with keyboard, use selection index
+            var users = $scope.popup.userResults;
+            if ($scope.popup.selectedIndex >= 0 && $scope.popup.selectedIndex < users.length) {
+                user = users[$scope.popup.selectedIndex];
+            }
+        }
+
+        if (user) {
+            if ("user" == $scope.assignmentOption.id) {
+                $scope.popup.assignmentObject.idm.assignee = user;
+            } else if ("users" == $scope.assignmentOption.id) {
+
+                // Only add if not yet part of candidate users
+                var found = false;
+                if ($scope.popup.assignmentObject.idm.candidateUsers) {
+                    for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateUsers.length; i++) {
+                        if ($scope.popup.assignmentObject.idm.candidateUsers[i].id === user.id) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+
+                if (!found) {
+                    $scope.addCandidateUser(user);
+                }
+            }
+        }
+    };
+
+    $scope.confirmEmail = function() {
+        if ("user" == $scope.assignmentOption.id) {
+            $scope.popup.assignmentObject.idm.assignee = {email: $scope.popup.email};
+        } else if ("users" == $scope.assignmentOption.id) {
+
+            // Only add if not yet part of candidate users
+            var found = false;
+            if ($scope.popup.assignmentObject.idm.candidateUsers) {
+                for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateUsers.length; i++) {
+
+                    if ($scope.popup.assignmentObject.idm.candidateUsers[i].id) {
+                        if ($scope.popup.assignmentObject.idm.candidateUsers[i].id === user.id) {
+                            found = true;
+                            break;
+                        }
+                    } else if ($scope.popup.assignmentObject.idm.candidateUsers[i].email) {
+                        if ($scope.popup.assignmentObject.idm.candidateUsers[i].email === $scope.popup.email) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (!found) {
+                $scope.addCandidateUser({email: $scope.popup.email});
+            }
+        }
+    };
+
+    $scope.confirmGroup = function(group) {
+        if (!group) {
+            // Selection is done with keyboard, use selection index
+            var groups = $scope.popup.groupResults;
+            if ($scope.popup.selectedGroupIndex >= 0 && $scope.popup.selectedGroupIndex < groups.length) {
+                group = groups[$scope.popup.selectedGroupIndex];
+            }
+        }
+
+        if (group) {
+            // Only add if not yet part of candidate groups
+            var found = false;
+            if ($scope.popup.assignmentObject.idm.candidateGroups) {
+                for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateGroups.length; i++) {
+                    if ($scope.popup.assignmentObject.idm.candidateGroups[i].id === group.id) {
+                        found = true;
+                        break;
+                    }
+                }
+            }
+
+            if (!found) {
+                $scope.addCandidateGroup(group);
+            }
+        }
+    };
+
+    $scope.addCandidateUser = function(user) {
+        $scope.popup.assignmentObject.idm.candidateUsers.push(user);
+    };
+    
+    $scope.removeCandidateUser = function(user) {
+        var users = $scope.popup.assignmentObject.idm.candidateUsers;
+        var indexToRemove = -1;
+        for (var i = 0; i < users.length; i++) {
+            if (user.id) {
+                if (user.id === users[i].id) {
+                    indexToRemove = i;
+                    break;
+                }
+            } else {
+                if (user.email === users[i].email) {
+                    indexToRemove = i;
+                    break;
+                }
+            }
+        }
+        if (indexToRemove >= 0) {
+            users.splice(indexToRemove, 1);
+        }
+    };
+    
+    $scope.addCandidateGroup = function(group) {
+        $scope.popup.assignmentObject.idm.candidateGroups.push(group);
+    };
+    
+    $scope.removeCandidateGroup = function(group) {
+        var groups = $scope.popup.assignmentObject.idm.candidateGroups;
+        var indexToRemove = -1;
+        for (var i = 0; i < groups.length; i++) {
+            if (group.id == groups[i].id) {
+                indexToRemove = i;
+                break;
+            }
+        }
+        if (indexToRemove >= 0) {
+            groups.splice(indexToRemove, 1);
+        }
+    };
+
+    $scope.resetSelection = function() {
+        if ($scope.popup.userResults && $scope.popup.userResults.length > 0) {
+            $scope.popup.selectedIndex = 0;
+        } else {
+            $scope.popup.selectedIndex = -1;
+        }
+    };
+
+    $scope.nextUser = function() {
+        var users = $scope.popup.userResults;
+        if (users && users.length > 0 && $scope.popup.selectedIndex < users.length -1) {
+            $scope.popup.selectedIndex += 1;
+        }
+    };
+
+    $scope.previousUser = function() {
+        var users = $scope.popup.userResults;
+        if (users && users.length > 0 && $scope.popup.selectedIndex > 0) {
+            $scope.popup.selectedIndex -= 1;
+        }
+    };
+
+    $scope.resetGroupSelection = function() {
+        if ($scope.popup.groupResults && $scope.popup.groupResults.length > 0) {
+            $scope.popup.selectedGroupIndex = 0;
+        } else {
+            $scope.popup.selectedGroupIndex = -1;
+        }
+    };
+
+    $scope.nextGroup = function() {
+        var groups = $scope.popup.groupResults;
+        if (groups && groups.length > 0 && $scope.popup.selectedGroupIndex < groups.length -1) {
+            $scope.popup.selectedGroupIndex += 1;
+        }
+    };
+
+    $scope.previousGroup = function() {
+        var groups = $scope.popup.groupResults;
+        if (groups && groups.length > 0 && $scope.popup.selectedGroupIndex > 0) {
+            $scope.popup.selectedGroupIndex -= 1;
+        }
+    };
+
+    $scope.removeAssignee = function() {
+        $scope.popup.assignmentObject.idm.assignee = undefined;
+    };
+    
+    // Click handler for + button after enum value
+    $scope.addCandidateUserValue = function(index) {
+        $scope.popup.assignmentObject.static.candidateUsers.splice(index + 1, 0, {value: ''});
+    };
+
+    // Click handler for - button after enum value
+    $scope.removeCandidateUserValue = function(index) {
+        $scope.popup.assignmentObject.static.candidateUsers.splice(index, 1);
+    };
+
+    // Click handler for + button after enum value
+    $scope.addCandidateGroupValue = function(index) {
+        $scope.popup.assignmentObject.static.candidateGroups.splice(index + 1, 0, {value: ''});
+    };
+
+    // Click handler for - button after enum value
+    $scope.removeCandidateGroupValue = function(index) {
+        $scope.popup.assignmentObject.static.candidateGroups.splice(index, 1);
+    };
+    
+    $scope.setSearchType = function() {
+        $scope.popup.assignmentObject.assignmentSourceType = 'search';
+    };
+
+    $scope.allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape);
+
+    $scope.save = function () {
+
+        handleAssignmentInput($scope.popup.assignmentObject.static);
+
+        $scope.assignment.type = $scope.popup.assignmentObject.type;
+
+        if ('idm' === $scope.popup.assignmentObject.type) { // IDM
+            $scope.popup.assignmentObject.static = undefined;
+
+            //Construct an IDM object to be saved to the process model.
+            var idm = {type: $scope.assignmentOption.id};
+            if ('user' == idm.type) {
+                if ($scope.popup.assignmentObject.idm.assignee) {
+                    idm.assignee = $scope.popup.assignmentObject.idm.assignee;
+                }
+            } else if ('users' == idm.type) {
+                if ($scope.popup.assignmentObject.idm.candidateUsers && $scope.popup.assignmentObject.idm.candidateUsers.length > 0) {
+                    idm.candidateUsers = $scope.popup.assignmentObject.idm.candidateUsers;
+                }
+            } else if ('groups' == idm.type) {
+                if ($scope.popup.assignmentObject.idm.candidateGroups && $scope.popup.assignmentObject.idm.candidateGroups.length > 0) {
+                    idm.candidateGroups = $scope.popup.assignmentObject.idm.candidateGroups;
+                }
+            }
+            $scope.assignment.idm = idm;
+            $scope.assignment.assignee = undefined;
+            $scope.assignment.candidateUsers = undefined;
+            $scope.assignment.candidateGroups = undefined;
+
+        }
+
+        if ('static' === $scope.popup.assignmentObject.type) { // IDM
+            $scope.popup.assignmentObject.idm = undefined;
+            $scope.assignment.idm = undefined;
+            $scope.assignment.assignee = $scope.popup.assignmentObject.static.assignee;
+            $scope.assignment.candidateUsers = $scope.popup.assignmentObject.static.candidateUsers;
+            $scope.assignment.candidateGroups = $scope.popup.assignmentObject.static.candidateGroups;
+        }
+
+        $scope.property.value = {};
+        $scope.property.value.assignment = $scope.assignment;
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    // Close button handler
+    $scope.close = function() {
+    	$scope.property.mode = 'read';
+    	$scope.$hide();
+    };
+
+    var handleAssignmentInput = function ($assignment) {
+    
+        function isEmptyString(value) {
+          return (value === undefined || value === null || value.trim().length === 0);
+        }
+    
+        if (isEmptyString($assignment.assignee)){
+          $assignment.assignee = undefined;
+        }
+        var toRemoveIndexes;
+        var removedItems=0;
+        var i = 0;
+        if ($assignment.candidateUsers) {
+          toRemoveIndexes = [];
+          for (i = 0; i < $assignment.candidateUsers.length; i++) {
+            if (isEmptyString($assignment.candidateUsers[i].value)) {
+              toRemoveIndexes[toRemoveIndexes.length] = i;
+            }
+          }
+    
+          if (toRemoveIndexes.length == $assignment.candidateUsers.length) {
+            $assignment.candidateUsers = undefined;
+          } else {
+             removedItems=0;
+            for (i = 0; i < toRemoveIndexes.length; i++) {
+              $assignment.candidateUsers.splice(toRemoveIndexes[i]-removedItems, 1);
+              removedItems++;
+            }
+          }
+        }
+    
+        if ($assignment.candidateGroups) {
+          toRemoveIndexes = [];
+          for (i = 0; i < $assignment.candidateGroups.length; i++) {
+            if (isEmptyString($assignment.candidateGroups[i].value)) {
+              toRemoveIndexes[toRemoveIndexes.length] = i;
+            }
+          }
+    
+          if (toRemoveIndexes.length == $assignment.candidateGroups.length) {
+            $assignment.candidateGroups = undefined;
+          } else {
+             removedItems=0;
+            for (i = 0; i < toRemoveIndexes.length; i++) {
+              $assignment.candidateGroups.splice(toRemoveIndexes[i]-removedItems, 1);
+              removedItems++;
+            }
+          }
+        }
+    };
+    
+    function initStaticContextForEditing($scope) {
+        if (!$scope.popup.assignmentObject.static.candidateUsers || $scope.popup.assignmentObject.static.candidateUsers.length==0) {
+          $scope.popup.assignmentObject.static.candidateUsers = [{value: ''}];
+        }
+        if (!$scope.popup.assignmentObject.static.candidateGroups || $scope.popup.assignmentObject.static.candidateGroups.length==0) {
+          $scope.popup.assignmentObject.static.candidateGroups = [{value: ''}];
+        }
+    }
+}]);

+ 80 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-collapsed-subprocess-controller.js

@@ -0,0 +1,80 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+angular.module('flowableModeler').controller('FlowableCollapsedSubprocessReferenceCtrl',
+    [ '$scope', '$modal', '$http', function($scope, $modal, $http) {
+	
+     // Config for the modal window
+     var opts = {
+         template:  'editor-app/configuration/properties/subprocess-reference-popup.html?version=' + Date.now(),
+         scope: $scope
+     };
+
+     // Open the dialog
+        _internalCreateModal(opts, $modal, $scope);
+}]);
+
+angular.module('flowableModeler').controller('FlowableCollapsedSubprocessReferencePopupCtrl', [ '$scope', '$http', function($scope, $http) {
+	
+    $scope.state = {'loadingSubprocesses' : true, 'error' : false};
+    
+    // Close button handler
+    $scope.close = function() {
+    	$scope.property.mode = 'read';
+        $scope.$hide();
+    };
+    
+    // Selecting/deselecting a subprocess
+    $scope.selectSubProcess = function(sub, $event) {
+   	 	$event.stopPropagation();
+   	 	if ($scope.selectedSubProcess && $scope.selectedSubProcess.id && sub.id == $scope.selectedSubProcess.id) {
+   	 		// un-select the current selection
+   	 		$scope.selectedSubProcess = null;
+   	 	} else {
+   	 		$scope.selectedSubProcess = sub;
+   	 	}
+    };
+    
+    // Saving the selected value
+    $scope.save = function() {
+   	 	if ($scope.selectedSubProcess) {
+   	 		$scope.property.value = {'id' : $scope.selectedSubProcess.id, 'name' : $scope.selectedSubProcess.name};
+   	 	} else {
+   	 		$scope.property.value = null; 
+   	 	}
+   	 	$scope.updatePropertyInModel($scope.property);
+   	 	$scope.close();
+    };
+    
+    $scope.loadProcesses = function() {
+   	 
+    	$http.get(FLOWABLE.CONFIG.contextRoot + '/app/rest/models?filter=myprocesses')
+    		.success(
+    			function(response) {
+    				$scope.state.loadingSubprocesses = false;
+    				$scope.state.subprocessError = false;
+    				$scope.subProcesses = response.data;
+    			})
+    		.error(
+    			function(data, status, headers, config) {
+    				$scope.state.loadingSubprocesses = false;
+    				$scope.state.subprocessError = true;
+    			});
+    };
+    
+    if ($scope.property && $scope.property.value && $scope.property.value.id) {
+   	 	$scope.selectedSubProcess = $scope.property.value;
+    }
+    
+    $scope.loadProcesses();  
+}]);

+ 59 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-condition-expression-controller.js

@@ -0,0 +1,59 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Condition expression
+ */
+
+angular.module('flowableModeler').controller('FlowableConditionExpressionCtrl', [ '$scope', '$modal', function($scope, $modal) {
+
+    // Config for the modal window
+    var opts = {
+        template: 'editor-app/configuration/properties/condition-expression-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    // Open the dialog
+    _internalCreateModal(opts, $modal, $scope);
+}]);
+
+angular.module('flowableModeler').controller('FlowableConditionExpressionPopupCtrl',
+    [ '$rootScope', '$scope', '$translate', 'FormBuilderService', function($rootScope, $scope, $translate, FormBuilderService) {
+    	
+    // Put json representing assignment on scope
+    if ($scope.property.value !== undefined && $scope.property.value !== null
+        && $scope.property.value.expression !== undefined
+        && $scope.property.value.expression !== null) {
+
+        $scope.expression = $scope.property.value.expression;
+
+    } else if ($scope.property.value !== undefined && $scope.property.value !== null) {
+        $scope.expression = {type: 'static', staticValue: $scope.property.value};
+        
+    } else {
+        $scope.expression = {};
+    }
+
+    $scope.save = function() {
+        $scope.property.value = {expression: $scope.expression};
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    // Close button handler
+    $scope.close = function() {
+    	$scope.property.mode = 'read';
+    	$scope.$hide();
+    };
+
+}]);

+ 12 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-custom-controllers.js

@@ -0,0 +1,12 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */

+ 288 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-decisiontable-reference-controller.js

@@ -0,0 +1,288 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+angular.module('flowableModeler').controller('FlowableDecisionTableReferenceCtrl',
+    [ '$scope', '$modal', '$http', function($scope, $modal, $http) {
+	
+     // Config for the modal window
+     var opts = {
+         template:  'editor-app/configuration/properties/decisiontable-reference-popup.html?version=' + Date.now(),
+         scope: $scope
+     };
+
+     // Open the dialog
+     _internalCreateModal(opts, $modal, $scope);
+}]);
+ 
+angular.module('flowableModeler').controller('FlowableDecisionTableReferencePopupCtrl', ['$rootScope', '$scope', '$http', '$location', 'editorManager',
+    function($rootScope, $scope, $http, $location, editorManager) {
+
+        $scope.state = {
+            'loadingDecisionTables': true,
+            'decisionTableError': false
+        };
+
+        $scope.popup = {
+            'state': 'decisionTableReference'
+        };
+
+        $scope.foldersBreadCrumbs = [];
+
+        // Make click outside dialog also call close.
+        $scope.$parent.$on('modal.hide.before', function() {
+            $scope.close();
+            $scope.$parent.$apply();
+        });
+
+        // Close button handler
+        $scope.close = function() {
+            $scope.property.newVariablesMapping = undefined;
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+        // Selecting/deselecting a decision table
+        $scope.selectDecisionTable = function(decisionTable, $event) {
+            $event.stopPropagation();
+            if ($scope.selectedDecisionTable && $scope.selectedDecisionTable.id && decisionTable.id == $scope.selectedDecisionTable.id) {
+                // un-select the current selection
+                $scope.selectedDecisionTable = null;
+            } else {
+                $scope.selectedDecisionTable = decisionTable;
+            }
+        };
+
+        $scope.isSelected = function () {
+            if ($scope.selectedDecisionTable && $scope.selectedDecisionTable.id) {
+                return true;
+            }
+            return false;
+        };
+
+        // Saving the selected value
+        $scope.save = function() {
+            if ($scope.selectedDecisionTable) {
+                $scope.property.value = {
+                    'id': $scope.selectedDecisionTable.id,
+                    'name': $scope.selectedDecisionTable.name,
+                    'key': $scope.selectedDecisionTable.key
+                };
+                
+            } else {
+                $scope.property.value = null;
+            }
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        // Open the selected value
+        $scope.open = function() {
+            if ($scope.selectedDecisionTable) {
+                $scope.property.value = {
+                    'id': $scope.selectedDecisionTable.id,
+                    'name': $scope.selectedDecisionTable.name,
+                    'key': $scope.selectedDecisionTable.key
+                };
+                $scope.updatePropertyInModel($scope.property);
+
+                var modelMetaData = editorManager.getBaseModelData();
+                var json = editorManager.getModel();
+                json = JSON.stringify(json);
+
+                var params = {
+                    modeltype: modelMetaData.model.modelType,
+                    json_xml: json,
+                    name: modelMetaData.name,
+                    key: modelMetaData.key,
+                    description: modelMetaData.description,
+                    newversion: false,
+                    lastUpdated: modelMetaData.lastUpdated
+                };
+
+                // Update
+                $http({
+                    method: 'POST',
+                    data: params,
+                    ignoreErrors: true,
+                    headers: {
+                        'Accept': 'application/json',
+                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
+                    },
+                    transformRequest: function (obj) {
+	                    var str = [];
+	                    for (var p in obj) {
+	                        str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
+	                    }
+	                    return str.join("&");
+	                },
+                    url: FLOWABLE.URL.putModel(modelMetaData.modelId)
+                })
+
+                .success(function(data, status, headers, config) {
+                        editorManager.handleEvents({
+                            type: ORYX.CONFIG.EVENT_SAVED
+                        });
+
+						$rootScope.addHistoryItem($scope.selectedShape.resourceId);
+						$location.path('decision-table-editor/' + $scope.selectedDecisionTable.id);
+                    })
+                    .error(function(data, status, headers, config) {
+
+                    });
+                
+                $scope.close();
+            }
+        };
+
+        $scope.newDecisionTable = function() {
+            $scope.property.value.variablesmapping = [];
+
+            $scope.popup.state = 'newDecisionTable';
+
+            var modelMetaData = editorManager.getBaseModelData();
+
+            $scope.model = {
+                loading: false,
+                decisionTable: {
+                    name: '',
+                    key: '',
+                    description: '',
+                    modelType: 4
+                },
+                defaultStencilSet: undefined,
+                decisionTableStencilSets: []
+            };
+        };
+
+        $scope.createDecisionTable = function() {
+
+            if (!$scope.model.decisionTable.name || $scope.model.decisionTable.name.length == 0 ||
+            	!$scope.model.decisionTable.key || $scope.model.decisionTable.key.length == 0) {
+            	
+                return;
+            }
+
+            var stencilSetId = $scope.model.decisionTable.stencilSet;
+            $scope.model.loading = true;
+
+            $http({
+                method: 'POST',
+                url: FLOWABLE.CONFIG.contextRoot + '/app/rest/models',
+                data: $scope.model.decisionTable
+            }).
+            success(function(data, status, headers, config) {
+
+                var newDecisionTableId = data.id;
+                $scope.property.value = {
+                    'id': newDecisionTableId,
+                    'name': data.name,
+                    'key': data.key
+                };
+                $scope.updatePropertyInModel($scope.property);
+
+                var modelMetaData = editorManager.getBaseModelData();
+                var json = editorManager.getModel();
+                json = JSON.stringify(json);
+
+                var params = {
+                    modeltype: modelMetaData.model.modelType,
+                    json_xml: json,
+                    name: modelMetaData.name,
+                    key: modelMetaData.key,
+                    description: modelMetaData.description,
+                    newversion: false,
+                    lastUpdated: modelMetaData.lastUpdated,
+                    stencilSet: stencilSetId
+                };
+
+                // Update
+                $http({
+                    method: 'POST',
+                    data: params,
+                    ignoreErrors: true,
+                    headers: {
+                        'Accept': 'application/json',
+                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
+                    },
+                    transformRequest: function (obj) {
+	                    var str = [];
+	                    for (var p in obj) {
+	                        str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
+	                    }
+	                    return str.join("&");
+	                },
+                    url: FLOWABLE.URL.putModel(modelMetaData.modelId)
+                })
+
+                .success(function(data, status, headers, config) {
+                        editorManager.handleEvents({
+                            type: ORYX.CONFIG.EVENT_SAVED
+                        });
+
+                        $scope.model.loading = false;
+                        $scope.$hide();
+                        
+                        $rootScope.addHistoryItem($scope.selectedShape.resourceId);
+                        $location.path('decision-table-editor/' + newDecisionTableId);
+                    })
+                    .error(function(data, status, headers, config) {
+                        $scope.model.loading = false;
+                        $scope.$hide();
+                    });
+
+            }).
+            error(function(data, status, headers, config) {
+                $scope.model.loading = false;
+                $scope.model.errorMessage = data.message;
+            });
+        };
+
+        $scope.cancel = function() {
+            $scope.close();
+        };
+
+        $scope.resetCurrent = function () {
+            for (var i = 0, found = false; i < $scope.decisionTables.length && found === false; i++) {
+                var table = $scope.decisionTables[i];
+                if (table.id === $scope.property.value.id) {
+                    $scope.selectedDecisionTable = table;
+                    found = true;
+                }
+            }
+        };
+
+        $scope.loadDecisionTables = function() {
+            var modelMetaData = editorManager.getBaseModelData();
+            $http.get(FLOWABLE.CONFIG.contextRoot + '/app/rest/decision-table-models')
+                .success(
+                    function(response) {
+                        $scope.state.loadingDecisionTables = false;
+                        $scope.state.decisionTableError = false;
+                        $scope.decisionTables = response.data;
+                        $scope.resetCurrent();
+                    })
+                .error(
+                    function(data, status, headers, config) {
+                        $scope.state.loadingDecisionTables = false;
+                        $scope.state.decisionTableError = true;
+                    });
+        };
+
+        if ($scope.property && $scope.property.value && $scope.property.value.id) {
+            $scope.selectedDecisionTable = $scope.property.value;
+            $scope.storedId = $scope.property.value.id;
+        }
+
+        $scope.loadDecisionTables();
+    }
+]);

+ 111 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-default-controllers.js

@@ -0,0 +1,111 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * String controller
+ */
+
+angular.module('flowableModeler').controller('FlowableStringPropertyCtrl', [ '$scope', function ($scope) {
+
+	$scope.shapeId = $scope.selectedShape.id;
+	$scope.valueFlushed = false;
+    /** Handler called when input field is blurred */
+    $scope.inputBlurred = function() {
+    	$scope.valueFlushed = true;
+    	if ($scope.property.value) {
+    		$scope.property.value = $scope.property.value.replace(/(<([^>]+)>)/ig,"");
+    	}
+        $scope.updatePropertyInModel($scope.property);
+    };
+
+    $scope.enterPressed = function(keyEvent) {
+        // if enter is pressed
+        if (keyEvent && keyEvent.which === 13) {
+            keyEvent.preventDefault();
+            $scope.inputBlurred(); // we want to do the same as if the user would blur the input field
+        }
+        // else; do nothing
+    };
+    
+    $scope.$on('$destroy', function controllerDestroyed() {
+    	if(!$scope.valueFlushed) {
+    		if ($scope.property.value) {
+        		$scope.property.value = $scope.property.value.replace(/(<([^>]+)>)/ig,"");
+        	}
+    		$scope.updatePropertyInModel($scope.property, $scope.shapeId);
+    	}
+    });
+
+}]);
+
+/*
+ * Boolean controller
+ */
+
+angular.module('flowableModeler').controller('FlowableBooleanPropertyCtrl', ['$scope', function ($scope) {
+
+    $scope.changeValue = function() {
+        if ($scope.property.key === 'oryx-defaultflow' && $scope.property.value) {
+            var selectedShape = $scope.selectedShape;
+            if (selectedShape) {
+                var incomingNodes = selectedShape.getIncomingShapes();
+                if (incomingNodes && incomingNodes.length > 0) {
+                    // get first node, since there can be only one for a sequence flow
+                    var rootNode = incomingNodes[0];
+                    var flows = rootNode.getOutgoingShapes();
+                    if (flows && flows.length > 1) {
+                        // in case there are more flows, check if another flow is already defined as default
+                        for (var i = 0; i < flows.length; i++) {
+                            if (flows[i].resourceId != selectedShape.resourceId) {
+                                var defaultFlowProp = flows[i].properties.get('oryx-defaultflow');
+                                if (defaultFlowProp) {
+                                    flows[i].setProperty('oryx-defaultflow', false, true);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        $scope.updatePropertyInModel($scope.property);
+    };
+
+}]);
+
+/*
+ * Text controller
+ */
+
+angular.module('flowableModeler').controller('FlowableTextPropertyCtrl', [ '$scope', '$modal', function($scope, $modal) {
+
+    var opts = {
+        template:  'editor-app/configuration/properties/text-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    // Open the dialog
+    _internalCreateModal(opts, $modal, $scope);
+}]);
+
+angular.module('flowableModeler').controller('FlowableTextPropertyPopupCtrl', ['$scope', function($scope) {
+    
+    $scope.save = function() {
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    $scope.close = function() {
+        $scope.property.mode = 'read';
+        $scope.$hide();
+    };
+}]);

+ 126 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-duedate-controller.js

@@ -0,0 +1,126 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Due date
+ */
+'use strict';
+
+angular.module('flowableModeler').controller('BpmnEditorDueDateCtrl', [ '$scope', '$modal', function($scope, $modal) {
+
+    // Config for the modal window
+    var opts = {
+        template: 'editor-app/configuration/properties/duedate-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    // Open the dialog
+    _internalCreateModal(opts, $modal, $scope);
+}]);
+
+angular.module('flowableModeler').controller('BpmnEditorDueDatePopupCtrl',
+    [ '$rootScope', '$scope', '$translate', function($rootScope, $scope, $translate) {
+
+    // Put json representing assignment on scope
+    if ($scope.property.value !== undefined && $scope.property.value !== null) {
+    
+        if ($scope.property.value.duedate !== undefined && $scope.property.value.duedate !== null) {
+            $scope.popup = {'duedate': $scope.property.value.duedate};
+        
+        } else if ($scope.property.value.duedateExpression !== undefined && $scope.property.value.duedateExpression !== null) {
+            $scope.popup = {'duedateExpression': $scope.property.value.duedateExpression};
+            
+        } else {
+            $scope.popup = {'duedateExpression': $scope.property.value};
+        }
+    
+    } else {
+        $scope.popup = {};
+    }
+    
+    $scope.taskDueDateOptions = [
+        {id: "none", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE')},
+        {id: "expression", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION')},
+        {id: "static", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC')},
+        {id: "field", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD')}
+    ];
+    
+    if (!$scope.popup.duedate && !$scope.popup.duedateExpression) {
+        // Default, first time opening the popup
+        $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[0].id;
+        
+    } else if (!$scope.popup.duedate) {
+        $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[1].id;
+        
+    } else {
+        
+        if ($scope.popup.duedate.fixed) {
+            $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[2].id;
+            
+        } else if ($scope.popup.duedate.field) {
+            $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[3].id;
+        
+        } else {
+            $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[0].id;
+        }
+    }
+    
+    $scope.dueDateOptionChanged = function() {
+        if ($scope.popup.selectedDueDateOption === 'expression') {
+            $scope.popup.duedate = undefined;
+        
+        } else if ($scope.popup.selectedDueDateOption === 'none') {
+            $scope.popup.duedate = undefined;
+            $scope.popup.duedateExpression = undefined;
+        
+        } else if ($scope.popup.selectedDueDateOption === 'static') {
+            $scope.popup.duedate = {'fixed': {}};
+            $scope.popup.duedateExpression = undefined;
+        
+        } else if ($scope.popup.selectedDueDateOption === 'field') {
+            $scope.popup.duedate = {'field': {}};
+            $scope.popup.duedateExpression = undefined;
+        }
+    };
+    
+    $scope.setAddCalculationType = function() {
+        $scope.popup.duedate.field.taskDueDateCalculationType = 'add';
+    };
+    
+    $scope.setSubtractCalculationType = function() {
+        $scope.popup.duedate.field.taskDueDateCalculationType = 'subtract';
+    };
+
+    $scope.allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape);
+
+    $scope.save = function () {
+        $scope.property.value = {};
+        if ($scope.popup.duedate) {
+            $scope.property.value.duedate = $scope.popup.duedate;
+            
+        } else if ($scope.popup.duedateExpression) {
+            $scope.property.value.duedateExpression = $scope.popup.duedateExpression;
+        
+        } else {
+            $scope.property.value = '';
+        }
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    // Close button handler
+    $scope.close = function() {
+    	$scope.property.mode = 'read';
+    	$scope.$hide();
+    };
+}]);

+ 263 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-event-listeners-controller.js

@@ -0,0 +1,263 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Execution listeners
+ */
+
+angular.module('flowableModeler').controller('FlowableEventListenersCtrl',
+    ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) {
+
+        // Config for the modal window
+        var opts = {
+            template: 'editor-app/configuration/properties/event-listeners-popup.html?version=' + Date.now(),
+            scope: $scope
+        };
+
+        // Open the dialog
+        _internalCreateModal(opts, $modal, $scope);
+    }]);
+
+//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259
+// Will be fixed in a newer version of Angular UI
+angular.module('flowableModeler').controller('FlowableEventListenersPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing form properties on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null
+            && $scope.property.value.eventListeners !== undefined
+            && $scope.property.value.eventListeners !== null) {
+
+            if ($scope.property.value.eventListeners.constructor == String) {
+                $scope.eventListeners = JSON.parse($scope.property.value.eventListeners);
+            }
+            else {
+                // Note that we clone the json object rather then setting it directly,
+                // this to cope with the fact that the user can click the cancel button and no changes should have happened
+                $scope.eventListeners = angular.copy($scope.property.value.eventListeners);
+            }
+
+        } else {
+            $scope.eventListeners = [];
+        }
+
+        $scope.translationsRetrieved = false;
+        $scope.labels = {};
+
+        var eventPromise = $translate('PROPERTY.EXECUTIONLISTENERS.EVENT');
+        var implementationPromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION');
+        var namePromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME');
+
+        $q.all([eventPromise, implementationPromise, namePromise]).then(function (results) {
+            $scope.labels.eventLabel = results[0];
+            $scope.labels.implementationLabel = results[1];
+            $scope.labels.nameLabel = results[2];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.eventListeners,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel},
+                    {field: 'implementation', displayName: $scope.labels.implementationLabel}]
+            };
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedListener = row.entity;
+
+                    if ($scope.selectedListener) {
+                        var fields = $scope.selectedListener.fields;
+                        if (fields !== undefined && fields !== null) {
+                            for (var i = 0; i < fields.length; i++) {
+                                var field = fields[i];
+                                if (field.stringValue !== undefined && field.stringValue !== '') {
+                                    field.implementation = field.stringValue;
+                                } else if (field.expression !== undefined && field.expression !== '') {
+                                    field.implementation = field.expression;
+                                } else if (field.string !== undefined && field.string !== '') {
+                                    field.implementation = field.string;
+                                }
+                            }
+                        } else {
+                            $scope.selectedListener.fields = [];
+                        }
+                        if (!$scope.selectedListener.events) {
+                            $scope.selectedListener.events = [{event: ''}];
+                        }
+                    }
+                });
+            };
+        });
+
+
+        // Click handler for + button after enum value
+        $scope.addEventValue = function (index) {
+            $scope.selectedListener.events.splice(index + 1, 0, {event: ''});
+        };
+
+        // Click handler for - button after enum value
+        $scope.removeEventValue = function (index) {
+            $scope.selectedListener.events.splice(index, 1);
+            $scope.listenerDetailsChanged();
+        };
+
+        $scope.listenerDetailsChanged = function () {
+            var listener = $scope.selectedListener;
+            if (listener.events) {
+                var eventText = '';
+                for (var i = 0; i < listener.events.length; i++) {
+                    if (i > 0) {
+                        eventText += ", ";
+                    }
+                    eventText += listener.events[i].event;
+                }
+                $scope.selectedListener.event = eventText;
+            }
+
+            if (listener.rethrowEvent) {
+                var implementationText = '';
+                if (listener.rethrowType && listener.rethrowType.length > 0) {
+                    if (listener.rethrowType === 'error' && listener.errorcode !== '') {
+                        implementationText = "Rethrow as error " + listener.errorcode;
+                    }
+                    else if (listener.rethrowType === 'message' && listener.messagename !== '') {
+                        implementationText = "Rethrow as message " + listener.messagename;
+                    }
+                    else if ((listener.rethrowType === 'signal' || listener.rethrowType === 'globalSignal') && listener.signalname !== '') {
+                        implementationText = "Rethrow as signal " + listener.signalname;
+                    }
+                }
+                $scope.selectedListener.implementation = implementationText;
+            }
+            else {
+                if ($scope.selectedListener.className !== '') {
+                    $scope.selectedListener.implementation = $scope.selectedListener.className;
+                }
+                else if ($scope.selectedListener.delegateExpression !== '') {
+                    $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression;
+                }
+                else {
+                    $scope.selectedListener.implementation = '';
+                }
+            }
+        };
+
+        // Click handler for add button
+        $scope.addNewListener = function () {
+            var newListener = {
+                event: '',
+                implementation: '',
+                className: '',
+                delegateExpression: '',
+                retrowEvent: false
+            };
+
+            $scope.eventListeners.push(newListener);
+
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newListener);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeListener = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.eventListeners.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+                $scope.eventListeners.splice(index, 1);
+
+                if ($scope.eventListeners.length == 0) {
+                    $scope.selectedListener = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.eventListeners.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.eventListeners[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.moveListenerUp = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.eventListeners.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.eventListeners[index];
+                    $scope.eventListeners.splice(index, 1);
+                    $timeout(function () {
+                        $scope.eventListeners.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.moveListenerDown = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.eventListeners.indexOf(selectedItems[0]);
+                if (index != $scope.eventListeners.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.eventListeners[index];
+                    $scope.eventListeners.splice(index, 1);
+                    $timeout(function () {
+                        $scope.eventListeners.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.eventListeners.length > 0) {
+                $scope.property.value = {};
+                $scope.property.value.eventListeners = $scope.eventListeners;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+    }]);

+ 358 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-execution-listeners-controller.js

@@ -0,0 +1,358 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Execution listeners
+ */
+
+angular.module('flowableModeler').controller('FlowableExecutionListenersCtrl',
+    ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) {
+
+        // Config for the modal window
+        var opts = {
+            template: 'editor-app/configuration/properties/execution-listeners-popup.html?version=' + Date.now(),
+            scope: $scope
+        };
+
+        // Open the dialog
+        _internalCreateModal(opts, $modal, $scope);
+    }]);
+
+angular.module('flowableModeler').controller('FlowableExecutionListenersPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing form properties on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null
+            && $scope.property.value.executionListeners !== undefined
+            && $scope.property.value.executionListeners !== null) {
+
+            if ($scope.property.value.executionListeners.constructor == String) {
+                $scope.executionListeners = JSON.parse($scope.property.value.executionListeners);
+            }
+            else {
+                // Note that we clone the json object rather then setting it directly,
+                // this to cope with the fact that the user can click the cancel button and no changes should have happened
+                $scope.executionListeners = angular.copy($scope.property.value.executionListeners);
+            }
+
+            for (var i = 0; i < $scope.executionListeners.length; i++) {
+                var executionListener = $scope.executionListeners[i];
+                if (executionListener.className !== undefined && executionListener.className !== '') {
+                    executionListener.implementation = executionListener.className;
+                }
+                else if (executionListener.expression !== undefined && executionListener.expression !== '') {
+                    executionListener.implementation = executionListener.expression;
+                }
+                else if (executionListener.delegateExpression !== undefined && executionListener.delegateExpression !== '') {
+                    executionListener.implementation = executionListener.delegateExpression;
+                }
+            }
+        } else {
+            $scope.executionListeners = [];
+        }
+
+        $scope.selectedListener = undefined;
+        $scope.selectedField = undefined;
+        $scope.fields = [];
+        $scope.translationsRetrieved = false;
+
+        $scope.labels = {};
+
+        var eventPromise = $translate('PROPERTY.EXECUTIONLISTENERS.EVENT');
+        var implementationPromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION');
+        var namePromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME');
+
+        $q.all([eventPromise, implementationPromise, namePromise]).then(function (results) {
+            $scope.labels.eventLabel = results[0];
+            $scope.labels.implementationLabel = results[1];
+            $scope.labels.nameLabel = results[2];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.executionListeners,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel},
+                    {field: 'implementation', displayName: $scope.labels.implementationLabel}]
+            };
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedListener = row.entity;
+                    $scope.selectedField = undefined;
+                    if ($scope.selectedListener) {
+                        var fields = $scope.selectedListener.fields;
+                        if (fields !== undefined && fields !== null) {
+                            for (var i = 0; i < fields.length; i++) {
+                                var field = fields[i];
+                                if (field.stringValue !== undefined && field.stringValue !== '') {
+                                    field.implementation = field.stringValue;
+                                } else if (field.expression !== undefined && field.expression !== '') {
+                                    field.implementation = field.expression;
+                                } else if (field.string !== undefined && field.string !== '') {
+                                    field.implementation = field.string;
+                                }
+                            }
+                        } else {
+                            $scope.selectedListener.fields = [];
+                        }
+
+                        $scope.fields.length = 0;
+                        for (var i = 0; i < $scope.selectedListener.fields.length; i++) {
+                            $scope.fields.push($scope.selectedListener.fields[i]);
+                        }
+                    }
+                });
+            };
+
+            // Config for field grid
+            $scope.gridFieldOptions = {
+                data: $scope.fields,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{field: 'name', displayName: $scope.labels.name},
+                    {field: 'implementation', displayName: $scope.labels.implementationLabel}]
+            };
+
+            $scope.gridFieldOptions.onRegisterApi = function (gridApi) {
+                // set gridApi on scope
+                $scope.fieldGridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedField = row.entity;
+                });
+            };
+        });
+
+        $scope.listenerDetailsChanged = function () {
+            if ($scope.selectedListener.className !== '') {
+                $scope.selectedListener.implementation = $scope.selectedListener.className;
+            } else if ($scope.selectedListener.expression !== '') {
+                $scope.selectedListener.implementation = $scope.selectedListener.expression;
+            } else if ($scope.selectedListener.delegateExpression !== '') {
+                $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression;
+            } else {
+                $scope.selectedListener.implementation = '';
+            }
+        };
+
+        // Click handler for add button
+        $scope.addNewListener = function () {
+            var newListener = {
+                event: 'start',
+                implementation: '',
+                className: '',
+                expression: '',
+                delegateExpression: ''
+            };
+            $scope.executionListeners.push(newListener);
+
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newListener);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeListener = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.executionListeners.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+
+                $scope.executionListeners.splice(index, 1);
+
+                if ($scope.executionListeners.length == 0) {
+                    $scope.selectedListener = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.executionListeners.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.executionListeners[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.moveListenerUp = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.executionListeners.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.executionListeners[index];
+                    $scope.executionListeners.splice(index, 1);
+                    $timeout(function () {
+                        $scope.executionListeners.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.moveListenerDown = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.executionListeners.indexOf(selectedItems[0]);
+                if (index != $scope.executionListeners.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.executionListeners[index];
+                    $scope.executionListeners.splice(index, 1);
+                    $timeout(function () {
+                        $scope.executionListeners.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        $scope.fieldDetailsChanged = function () {
+            if ($scope.selectedField.stringValue != '') {
+                $scope.selectedField.implementation = $scope.selectedField.stringValue;
+            } else if ($scope.selectedField.expression != '') {
+                $scope.selectedField.implementation = $scope.selectedField.expression;
+            } else if ($scope.selectedField.string != '') {
+                $scope.selectedField.implementation = $scope.selectedField.string;
+            } else {
+                $scope.selectedField.implementation = '';
+            }
+        };
+
+        // Click handler for add button
+        $scope.addNewField = function () {
+            if ($scope.selectedListener) {
+                if ($scope.selectedListener.fields == undefined) {
+                    $scope.selectedListener.fields = [];
+                }
+
+                var newField = {
+                    name: 'fieldName',
+                    implementation: '',
+                    stringValue: '',
+                    expression: '',
+                    string: ''
+                };
+                $scope.fields.push(newField);
+                $scope.selectedListener.fields.push(newField);
+
+                $timeout(function () {
+                    $scope.fieldGridApi.selection.toggleRowSelection(newField);
+                });
+            }
+        };
+
+        // Click handler for remove button
+        $scope.removeField = function () {
+            var selectedItems = $scope.fieldGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                $scope.fieldGridApi.selection.toggleRowSelection(selectedItems[0]);
+
+                $scope.fields.splice(index, 1);
+                $scope.selectedListener.fields.splice(index, 1);
+
+                if ($scope.fields.length == 0) {
+                    $scope.selectedField = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.fields.length > 0) {
+                        $scope.fieldGridApi.selection.toggleRowSelection($scope.fields[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.moveFieldUp = function () {
+            var selectedItems = $scope.fieldGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.fields[index];
+                    $scope.fields.splice(index, 1);
+                    $scope.selectedListener.fields.splice(index, 1);
+                    $timeout(function () {
+                        $scope.fields.splice(index + -1, 0, temp);
+                        $scope.selectedListener.fields.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.fieldGridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.moveFieldDown = function () {
+            var selectedItems = $scope.fieldGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.fields[index];
+                    $scope.fields.splice(index, 1);
+                    $scope.selectedListener.fields.splice(index, 1);
+                    $timeout(function () {
+                        $scope.fields.splice(index + 1, 0, temp);
+                        $scope.selectedListener.fields.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.fieldGridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.executionListeners.length > 0) {
+                $scope.property.value = {};
+                $scope.property.value.executionListeners = $scope.executionListeners;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.$hide();
+            $scope.property.mode = 'read';
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.$hide();
+            $scope.property.mode = 'read';
+        };
+
+    }]);

+ 206 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-fields-controller.js

@@ -0,0 +1,206 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Task listeners
+ */
+
+angular.module('flowableModeler').controller('FlowableFieldsCtrl',
+    ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) {
+
+        // Config for the modal window
+        var opts = {
+            template: 'editor-app/configuration/properties/fields-popup.html?version=' + Date.now(),
+            scope: $scope
+        };
+
+        // Open the dialog
+        _internalCreateModal(opts, $modal, $scope);
+    }]);
+
+angular.module('flowableModeler').controller('FlowableFieldsPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing form properties on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null
+            && $scope.property.value.fields !== undefined
+            && $scope.property.value.fields !== null) {
+
+            // Note that we clone the json object rather then setting it directly,
+            // this to cope with the fact that the user can click the cancel button and no changes should have happened
+            $scope.fields = angular.copy($scope.property.value.fields);
+
+            for (var i = 0; i < $scope.fields.length; i++) {
+                var field = $scope.fields[i];
+                if (field.stringValue !== undefined && field.stringValue !== '') {
+                    field.implementation = field.stringValue;
+                }
+                else if (field.expression !== undefined && field.expression !== '') {
+                    field.implementation = field.expression;
+                }
+                else if (field.string !== undefined && field.string !== '') {
+                    field.implementation = field.string;
+                }
+            }
+
+        } else {
+            $scope.fields = [];
+        }
+
+        $scope.translationsRetrieved = false;
+        $scope.labels = {};
+
+        var namePromise = $translate('PROPERTY.FIELDS.NAME');
+        var implementationPromise = $translate('PROPERTY.FIELDS.IMPLEMENTATION');
+
+        $q.all([namePromise, implementationPromise]).then(function (results) {
+            $scope.labels.nameLabel = results[0];
+            $scope.labels.implementationLabel = results[1];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.fields,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{field: 'name', displayName: $scope.labels.nameLabel},
+                    {field: 'implementation', displayName: $scope.labels.implementationLabel}]
+            };
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedField = row.entity;
+                });
+            };
+        });
+
+        $scope.fieldDetailsChanged = function () {
+            if ($scope.selectedField.stringValue != '') {
+                $scope.selectedField.implementation = $scope.selectedField.stringValue;
+            }
+            else if ($scope.selectedField.expression != '') {
+                $scope.selectedField.implementation = $scope.selectedField.expression;
+            }
+            else if ($scope.selectedField.string != '') {
+                $scope.selectedField.implementation = $scope.selectedField.string;
+            }
+            else {
+                $scope.selectedField.implementation = '';
+            }
+        };
+
+        // Click handler for add button
+        $scope.addNewField = function () {
+            var newField = {
+                name: 'fieldName',
+                implementation: '',
+                stringValue: '',
+                expression: '',
+                string: ''
+            };
+
+            $scope.fields.push(newField);
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newField);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeField = function () {
+
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+                $scope.fields.splice(index, 1);
+
+                if ($scope.fields.length == 0) {
+                    $scope.selectedField = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.fields.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.fields[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.moveFieldUp = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.fields[index];
+                    $scope.fields.splice(index, 1);
+                    $timeout(function () {
+                        $scope.fields.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.moveFieldDown = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.fields[index];
+                    $scope.fields.splice(index, 1);
+                    $timeout(function () {
+                        $scope.fields.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.fields.length > 0) {
+                $scope.property.value = {};
+                $scope.property.value.fields = $scope.fields;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.$hide();
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+    }]);

+ 327 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-form-properties-controller.js

@@ -0,0 +1,327 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Form Properties
+ */
+
+angular.module('flowableModeler').controller('FlowableFormPropertiesCtrl',
+    ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) {
+
+        // Config for the modal window
+        var opts = {
+            template: 'editor-app/configuration/properties/form-properties-popup.html?version=' + Date.now(),
+            scope: $scope
+        };
+
+        // Open the dialog
+        _internalCreateModal(opts, $modal, $scope);
+    }]);
+
+angular.module('flowableModeler').controller('FlowableFormPropertiesPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing form properties on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null
+            && $scope.property.value.formProperties !== undefined
+            && $scope.property.value.formProperties !== null) {
+            // Note that we clone the json object rather then setting it directly,
+            // this to cope with the fact that the user can click the cancel button and no changes should have happended
+            $scope.formProperties = angular.copy($scope.property.value.formProperties);
+            
+            for (var i = 0; i < $scope.formProperties.length; i++) {
+			    var formProperty = $scope.formProperties[i];
+			    if (formProperty.enumValues && formProperty.enumValues.length > 0) {
+				    for (var j = 0; j < formProperty.enumValues.length; j++) {
+					    var enumValue = formProperty.enumValues[j];
+					    if (!enumValue.id && !enumValue.name && enumValue.value) {
+						    enumValue.id = enumValue.value;
+						    enumValue.name = enumValue.value;
+					    }
+				    }
+			    }
+			}
+            
+        } else {
+            $scope.formProperties = [];
+        }
+        
+        $scope.enumValues = [];
+
+        $scope.translationsRetrieved = false;
+
+        $scope.labels = {};
+
+        var idPromise = $translate('PROPERTY.FORMPROPERTIES.ID');
+        var namePromise = $translate('PROPERTY.FORMPROPERTIES.NAME');
+        var typePromise = $translate('PROPERTY.FORMPROPERTIES.TYPE');
+
+        $q.all([idPromise, namePromise, typePromise]).then(function (results) {
+            $scope.labels.idLabel = results[0];
+            $scope.labels.nameLabel = results[1];
+            $scope.labels.typeLabel = results[2];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.formProperties,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{field: 'id', displayName: $scope.labels.idLabel},
+                    {field: 'name', displayName: $scope.labels.nameLabel},
+                    {field: 'type', displayName: $scope.labels.typeLabel}]
+            };
+            
+            $scope.enumGridOptions = {
+    		    data: $scope.enumValues,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel },
+                { field: 'name', displayName: $scope.labels.nameLabel}]
+            }
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedProperty = row.entity;
+                    $scope.selectedEnumValue = undefined;
+                    if ($scope.selectedProperty && $scope.selectedProperty.enumValues) {
+                        $scope.enumValues.length = 0;
+                        for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) {
+                            $scope.enumValues.push($scope.selectedProperty.enumValues[i]);
+                        }
+                    }
+                });
+            };
+            
+            $scope.enumGridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.enumGridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedEnumValue = row.entity;
+                });
+            };
+        });
+
+        // Handler for when the value of the type dropdown changes
+        $scope.propertyTypeChanged = function () {
+
+            // Check date. If date, show date pattern
+            if ($scope.selectedProperty.type === 'date') {
+                $scope.selectedProperty.datePattern = 'MM-dd-yyyy hh:mm';
+            } else {
+                delete $scope.selectedProperty.datePattern;
+            }
+
+            // Check enum. If enum, show list of options
+            if ($scope.selectedProperty.type === 'enum') {
+                $scope.selectedProperty.enumValues = [ {id: 'value1', name: 'Value 1'}, {id: 'value2', name: 'Value 2'}];
+                $scope.enumValues.length = 0;
+                for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) {
+                    $scope.enumValues.push($scope.selectedProperty.enumValues[i]);
+                }
+                
+            } else {
+                delete $scope.selectedProperty.enumValues;
+                $scope.enumValues.length = 0;
+            }
+        };
+
+        // Click handler for add button
+        var propertyIndex = 1;
+        $scope.addNewProperty = function () {
+            var newProperty = {
+                id: 'new_property_' + propertyIndex++,
+                name: '',
+                type: 'string',
+                readable: true,
+                writable: true
+            };
+
+            $scope.formProperties.push(newProperty);
+
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newProperty);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeProperty = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.formProperties.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+                $scope.formProperties.splice(index, 1);
+
+                if ($scope.formProperties.length == 0) {
+                    $scope.selectedProperty = undefined;
+                }
+
+                $timeout(function() {
+                    if ($scope.formProperties.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.formProperties[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.movePropertyUp = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.formProperties.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.formProperties[index];
+                    $scope.formProperties.splice(index, 1);
+                    $timeout(function(){
+                        $scope.formProperties.splice(index + -1, 0, temp);
+                        $timeout(function() {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.movePropertyDown = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.formProperties.indexOf(selectedItems[0]);
+                if (index != $scope.formProperties.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.formProperties[index];
+                    $scope.formProperties.splice(index, 1);
+                    $timeout(function(){
+                        $scope.formProperties.splice(index + 1, 0, temp);
+                        $timeout(function() {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+        
+        $scope.addNewEnumValue = function() {
+            if ($scope.selectedProperty) {
+        	    var newEnumValue = { id : '', name : ''};
+        	    $scope.selectedProperty.enumValues.push(newEnumValue);
+        	    $scope.enumValues.push(newEnumValue);
+    	       
+    	        $timeout(function () {
+                    $scope.enumGridApi.selection.toggleRowSelection(newEnumValue);
+                });
+        	}
+        };
+
+        // Click handler for remove button
+        $scope.removeEnumValue = function() {
+            var selectedItems = $scope.enumGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.enumValues.indexOf(selectedItems[0]);
+                $scope.enumGridApi.selection.toggleRowSelection(selectedItems[0]);
+
+                $scope.enumValues.splice(index, 1);
+                $scope.selectedProperty.enumValues.splice(index, 1);
+
+                if ($scope.enumValues.length == 0) {
+                    $scope.selectedEnumValue = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.enumValues.length > 0) {
+                        $scope.enumGridApi.selection.toggleRowSelection($scope.enumValues[0]);
+                    }
+                });
+            }
+        };
+    
+        // Click handler for up button
+        $scope.moveEnumValueUp = function() {
+            var selectedItems = $scope.enumGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.enumValues.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.enumValues[index];
+                    $scope.enumValues.splice(index, 1);
+                    $scope.selectedProperty.enumValues.splice(index, 1);
+                    $timeout(function () {
+                        $scope.enumValues.splice(index + -1, 0, temp);
+                        $scope.selectedProperty.enumValues.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.enumGridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+    
+        // Click handler for down button
+        $scope.moveEnumValueDown = function() {
+            var selectedItems = $scope.enumGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.enumValues.indexOf(selectedItems[0]);
+                if (index != $scope.enumValues.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.enumValues[index];
+                    $scope.enumValues.splice(index, 1);
+                    $scope.selectedProperty.enumValues.splice(index, 1);
+                    $timeout(function () {
+                        $scope.enumValues.splice(index + 1, 0, temp);
+                        $scope.selectedProperty.enumValues.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.enumGridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.formProperties.length > 0) {
+                $scope.property.value = {};
+                $scope.property.value.formProperties = $scope.formProperties;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.$hide();
+            $scope.property.mode = 'read';
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.$hide();
+            $scope.property.mode = 'read';
+        };
+
+    }])
+;

+ 261 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-form-reference-controller.js

@@ -0,0 +1,261 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+angular.module('flowableModeler').controller('FlowableFormReferenceDisplayCtrl',
+    [ '$scope', '$modal', '$http', function($scope, $modal, $http) {
+    
+    if ($scope.property && $scope.property.value && $scope.property.value.id) {
+   		$http.get(FLOWABLE.CONFIG.contextRoot + '/app/rest/models/' + $scope.property.value.id)
+            .success(
+                function(response) {
+                    $scope.form = {
+                    	id: response.id,
+                    	name: response.name
+                    };
+                });
+    }
+	
+}]);
+
+angular.module('flowableModeler').controller('FlowableFormReferenceCtrl',
+    [ '$scope', '$modal', '$http', function($scope, $modal, $http) {
+	
+     // Config for the modal window
+     var opts = {
+         template:  'editor-app/configuration/properties/form-reference-popup.html?version=' + Date.now(),
+         scope: $scope
+     };
+
+     // Open the dialog
+     _internalCreateModal(opts, $modal, $scope);
+}]);
+
+angular.module('flowableModeler').controller('FlowableFormReferencePopupCtrl',
+    [ '$rootScope', '$scope', '$http', '$location', 'editorManager', function($rootScope, $scope, $http, $location, editorManager) {
+	 
+	$scope.state = {'loadingForms' : true, 'formError' : false};
+	
+	$scope.popup = {'state' : 'formReference'};
+    
+    $scope.foldersBreadCrumbs = [];
+    
+    // Close button handler
+    $scope.close = function() {
+    	$scope.property.mode = 'read';
+        $scope.$hide();
+    };
+    
+    // Selecting/deselecting a subprocess
+    $scope.selectForm = function(form, $event) {
+   	 	$event.stopPropagation();
+   	 	if ($scope.selectedForm && $scope.selectedForm.id && form.id == $scope.selectedForm.id) {
+   	 		// un-select the current selection
+   	 		$scope.selectedForm = null;
+   	 	} else {
+   	 		$scope.selectedForm = form;
+   	 	}
+    };
+    
+    // Saving the selected value
+    $scope.save = function() {
+   	 	if ($scope.selectedForm) {
+   	 		$scope.property.value = {
+   	 			'id' : $scope.selectedForm.id, 
+   	 			'name' : $scope.selectedForm.name,
+   	 			'key' : $scope.selectedForm.key
+   	 		};
+   	 		
+   	 	} else {
+   	 		$scope.property.value = null; 
+   	 	}
+   	 	$scope.updatePropertyInModel($scope.property);
+   	 	$scope.close();
+    };
+    
+    // Open the selected value
+    $scope.open = function() {
+        if ($scope.selectedForm) {
+            $scope.property.value = {
+            	'id' : $scope.selectedForm.id, 
+            	'name' : $scope.selectedForm.name,
+            	'key' : $scope.selectedForm.key
+            };
+            
+            $scope.updatePropertyInModel($scope.property);
+            
+            var modelMetaData = editorManager.getBaseModelData();
+            var json = editorManager.getModel();
+            json = JSON.stringify(json);
+
+            var params = {
+                modeltype: modelMetaData.model.modelType,
+                json_xml: json,
+                name: modelMetaData.name,
+                key: modelMetaData.key,
+                description: modelMetaData.description,
+                newversion: false,
+                lastUpdated: modelMetaData.lastUpdated
+            };
+
+            // Update
+            $http({ method: 'POST',
+                data: params,
+                ignoreErrors: true,
+                headers: {'Accept': 'application/json',
+                          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
+                transformRequest: function (obj) {
+                    var str = [];
+                    for (var p in obj) {
+                        str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
+                    }
+                    return str.join("&");
+                },
+                url: FLOWABLE.URL.putModel(modelMetaData.modelId)})
+
+                .success(function (data, status, headers, config) {
+                    editorManager.handleEvents({
+                        type: ORYX.CONFIG.EVENT_SAVED
+                    });
+
+                    var allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape);
+
+					$rootScope.addHistoryItem($scope.selectedShape.resourceId);
+                    $location.path('form-editor/' + $scope.selectedForm.id);
+
+                })
+                .error(function (data, status, headers, config) {
+                    
+                });
+            
+            $scope.close();
+        }
+    };
+    
+    $scope.newForm = function() {
+        $scope.popup.state = 'newForm';
+        
+        var modelMetaData = editorManager.getBaseModelData();
+        
+        $scope.model = {
+            loading: false,
+            form: {
+                 name: '',
+                 key: '',
+                 description: '',
+                 modelType: 2
+            }
+        };
+    };
+    
+    $scope.createForm = function() {
+        
+        if (!$scope.model.form.name || $scope.model.form.name.length == 0 ||
+        	!$scope.model.form.key || $scope.model.form.key.length == 0) {
+        	
+            return;
+        }
+
+        $scope.model.loading = true;
+
+        $http({method: 'POST', url: FLOWABLE.CONFIG.contextRoot + '/app/rest/models', data: $scope.model.form}).
+            success(function(data, status, headers, config) {
+                
+                var newFormId = data.id;
+                $scope.property.value = {
+                	'id' : newFormId, 
+                	'name' : data.name,
+                	'key' : data.key
+               	};
+                $scope.updatePropertyInModel($scope.property);
+                
+                var modelMetaData = editorManager.getBaseModelData();
+                var json = editorManager.getModel();
+                json = JSON.stringify(json);
+
+                var params = {
+                    modeltype: modelMetaData.model.modelType,
+                    json_xml: json,
+                    name: modelMetaData.name,
+                    key: modelMetaData.key,
+                    description: modelMetaData.description,
+                    newversion: false,
+                    lastUpdated: modelMetaData.lastUpdated
+                };
+
+                // Update
+                $http({ method: 'POST',
+                    data: params,
+                    ignoreErrors: true,
+                    headers: {'Accept': 'application/json',
+                              'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
+                    transformRequest: function (obj) {
+                        var str = [];
+                        for (var p in obj) {
+                            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
+                        }
+                        return str.join("&");
+                    },
+                    url: FLOWABLE.URL.putModel(modelMetaData.modelId)})
+
+                    .success(function (data, status, headers, config) {
+                        editorManager.handleEvents({
+                            type: ORYX.CONFIG.EVENT_SAVED
+                        });
+                        
+                        $scope.model.loading = false;
+                        $scope.$hide();
+
+                        var allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape);
+
+                        $rootScope.addHistoryItem($scope.selectedShape.resourceId);
+                        $location.path('form-editor/' + newFormId);
+
+                    })
+                    .error(function (data, status, headers, config) {
+                        $scope.model.loading = false;
+                        $scope.$hide();
+                    });
+                
+            }).
+            error(function(data, status, headers, config) {
+                $scope.model.loading = false;
+                $scope.model.errorMessage = data.message;
+            });
+    };
+    
+    $scope.cancel = function() {
+        $scope.close();
+    };
+
+    $scope.loadForms = function() {
+        var modelMetaData = editorManager.getBaseModelData();
+        $http.get(FLOWABLE.CONFIG.contextRoot + '/app/rest/form-models')
+            .success(
+                function(response) {
+                    $scope.state.loadingForms = false;
+                    $scope.state.formError = false;
+                    $scope.forms = response.data;
+                })
+            .error(
+                function(data, status, headers, config) {
+                    $scope.state.loadingForms = false;
+                    $scope.state.formError = true;
+                });
+    };
+
+    if ($scope.property && $scope.property.value && $scope.property.value.id) {
+   	     $scope.selectedForm = $scope.property.value;
+    }
+
+    $scope.loadForms();
+}]);

+ 179 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-in-parameters-controller.js

@@ -0,0 +1,179 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Input parameters for call activity
+ */
+
+angular.module('flowableModeler').controller('FlowableInParametersCtrl',
+    ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) {
+
+        // Config for the modal window
+        var opts = {
+            template: 'editor-app/configuration/properties/in-parameters-popup.html?version=' + Date.now(),
+            scope: $scope
+        };
+
+        // Open the dialog
+        _internalCreateModal(opts, $modal, $scope);
+    }]);
+
+angular.module('flowableModeler').controller('FlowableInParametersPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing form properties on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null
+            && $scope.property.value.inParameters !== undefined
+            && $scope.property.value.inParameters !== null) {
+            // Note that we clone the json object rather then setting it directly,
+            // this to cope with the fact that the user can click the cancel button and no changes should have happened
+            $scope.parameters = angular.copy($scope.property.value.inParameters);
+        } else {
+            $scope.parameters = [];
+        }
+
+        $scope.translationsRetrieved = false;
+        $scope.labels = {};
+
+        var sourcePromise = $translate('PROPERTY.PARAMETER.SOURCE');
+        var sourceExpressionPromise = $translate('PROPERTY.PARAMETER.SOURCEEXPRESSION');
+        var targetPromise = $translate('PROPERTY.PARAMETER.TARGET');
+
+        $q.all([sourcePromise, sourceExpressionPromise, targetPromise]).then(function (results) {
+            $scope.labels.sourceLabel = results[0];
+            $scope.labels.sourceExpressionLabel = results[1];
+            $scope.labels.targetLabel = results[2];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.parameters,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{field: 'source', displayName: $scope.labels.sourceLabel},
+                    {field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel},
+                    {field: 'target', displayName: $scope.labels.targetLabel}]
+            };
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedParameter = row.entity;
+                });
+            };
+        });
+
+        // Click handler for add button
+        $scope.addNewParameter = function () {
+            var newParameter = {
+                source: '',
+                sourceExpression: '',
+                target: ''
+            };
+
+            $scope.parameters.push(newParameter);
+
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newParameter);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeParameter = function () {
+
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.parameters.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+                $scope.parameters.splice(index, 1);
+
+                if ($scope.parameters.length == 0) {
+                    $scope.selectedParameter = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.parameters.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.parameters[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.moveParameterUp = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.parameters.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.parameters[index];
+                    $scope.parameters.splice(index, 1);
+                    $timeout(function () {
+                        $scope.parameters.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.moveParameterDown = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.parameters.indexOf(selectedItems[0]);
+                if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.parameters[index];
+                    $scope.parameters.splice(index, 1);
+                    $timeout(function () {
+                        $scope.parameters.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.parameters.length > 0) {
+                $scope.property.value = {};
+                $scope.property.value.inParameters = $scope.parameters;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.close();
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+    }]);

+ 145 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-message-definitions-controller.js

@@ -0,0 +1,145 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Execution listeners
+ */
+
+angular.module('flowableModeler').controller('FlowableMessageDefinitionsCtrl', ['$scope', '$modal', function ($scope, $modal) {
+
+    // Config for the modal window
+    var opts = {
+        template: 'editor-app/configuration/properties/message-definitions-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    // Open the dialog
+    _internalCreateModal(opts, $modal, $scope);
+}]);
+
+//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259
+// Will be fixed in a newer version of Angular UI
+angular.module('flowableModeler').controller('FlowableMessageDefinitionsPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing mesage definitions on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null && $scope.property.value.length > 0) {
+
+            if ($scope.property.value.constructor == String) {
+                $scope.messageDefinitions = JSON.parse($scope.property.value);
+            }
+            else {
+                // Note that we clone the json object rather then setting it directly,
+                // this to cope with the fact that the user can click the cancel button and no changes should have happened
+                $scope.messageDefinitions = angular.copy($scope.property.value);
+            }
+
+        } else {
+            $scope.messageDefinitions = [];
+        }
+
+        // Array to contain selected mesage definitions (yes - we only can select one, but ng-grid isn't smart enough)
+        $scope.selectedMessageDefinition = undefined;
+        $scope.translationsRetrieved = false;
+
+        $scope.labels = {};
+
+        var idPromise = $translate('PROPERTY.MESSAGEDEFINITIONS.ID');
+        var namePromise = $translate('PROPERTY.MESSAGEDEFINITIONS.NAME');
+
+        $q.all([idPromise, namePromise]).then(function (results) {
+
+            $scope.labels.idLabel = results[0];
+            $scope.labels.nameLabel = results[1];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.messageDefinitions,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [
+                    {field: 'id', displayName: $scope.labels.idLabel},
+                    {field: 'name', displayName: $scope.labels.nameLabel}]
+            };
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedMessageDefinition = row.entity;
+                });
+            };
+        });
+
+        // Click handler for add button
+        $scope.addNewMessageDefinition = function () {
+            var newMessageDefinition = {id: '', name: ''};
+
+            $scope.messageDefinitions.push(newMessageDefinition);
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newMessageDefinition);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeMessageDefinition = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.messageDefinitions.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+                $scope.messageDefinitions.splice(index, 1);
+
+                if ($scope.messageDefinitions.length == 0) {
+                    $scope.selectedMesageDefinition = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.messageDefinitions.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.messageDefinitions[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.messageDefinitions.length > 0) {
+                $scope.property.value = $scope.messageDefinitions;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+    }]);

+ 41 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-message-scope-controller.js

@@ -0,0 +1,41 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+angular.module('flowableModeler').controller('FlowableMessageRefCtrl', [ '$scope', function($scope) {
+
+    // Find the parent shape on which the message definitions are defined
+    var messageDefinitionsProperty = undefined;
+    var parent = $scope.selectedShape;
+    while (parent !== null && parent !== undefined && messageDefinitionsProperty === undefined) {
+        if (parent.properties && parent.properties.get('oryx-messagedefinitions')) {
+        	messageDefinitionsProperty = parent.properties.get('oryx-messagedefinitions');
+        } else {
+            parent = parent.parent;
+        }
+    }
+
+    try {
+        messageDefinitionsProperty = JSON.parse(messageDefinitionsProperty);
+        if (typeof messageDefinitionsProperty == 'string') {
+            messageDefinitionsProperty = JSON.parse(messageDefinitionsProperty);
+        }
+    } catch (err) {
+        // Do nothing here, just to be sure we try-catch it
+    }
+
+    $scope.messageDefinitions = messageDefinitionsProperty;
+
+
+    $scope.messageChanged = function() {
+    	$scope.updatePropertyInModel($scope.property);
+    };
+}]);

+ 28 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-multiinstance-controller.js

@@ -0,0 +1,28 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Execution listeners
+ */
+
+angular.module('flowableModeler').controller('FlowableMultiInstanceCtrl', [ '$scope', function($scope) {
+
+    if ($scope.property.value == undefined && $scope.property.value == null)
+    {
+    	$scope.property.value = 'None';
+    }
+        
+    $scope.multiInstanceChanged = function() {
+    	$scope.updatePropertyInModel($scope.property);
+    };
+}]);

+ 28 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-ordering-controller.js

@@ -0,0 +1,28 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Adhoc sub process ordering property
+ */
+
+angular.module('flowableModeler').controller('FlowableOrderingCtrl', [ '$scope', function($scope) {
+
+    if ($scope.property.value == undefined && $scope.property.value == null)
+    {
+    	$scope.property.value = 'Parallel';
+    }
+        
+    $scope.orderingChanged = function() {
+    	$scope.updatePropertyInModel($scope.property);
+    };
+}]);

+ 176 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-out-parameters-controller.js

@@ -0,0 +1,176 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Input parameters for call activity
+ */
+
+angular.module('flowableModeler').controller('FlowableOutParametersCtrl',
+    ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) {
+
+        // Config for the modal window
+        var opts = {
+            template: 'editor-app/configuration/properties/out-parameters-popup.html?version=' + Date.now(),
+            scope: $scope
+        };
+
+        // Open the dialog
+        _internalCreateModal(opts, $modal, $scope);
+    }]);
+
+angular.module('flowableModeler').controller('FlowableOutParametersPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing form properties on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null
+            && $scope.property.value.outParameters !== undefined
+            && $scope.property.value.outParameters !== null) {
+            // Note that we clone the json object rather then setting it directly,
+            // this to cope with the fact that the user can click the cancel button and no changes should have happened
+            $scope.parameters = angular.copy($scope.property.value.outParameters);
+        } else {
+            $scope.parameters = [];
+        }
+
+        $scope.translationsRetrieved = false;
+        $scope.labels = {};
+
+        var sourcePromise = $translate('PROPERTY.PARAMETER.SOURCE');
+        var sourceExpressionPromise = $translate('PROPERTY.PARAMETER.SOURCEEXPRESSION');
+        var targetPromise = $translate('PROPERTY.PARAMETER.TARGET');
+
+        $q.all([sourcePromise, sourceExpressionPromise, targetPromise]).then(function (results) {
+            $scope.labels.sourceLabel = results[0];
+            $scope.labels.sourceExpressionLabel = results[1];
+            $scope.labels.targetLabel = results[2];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.parameters,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{field: 'source', displayName: $scope.labels.sourceLabel},
+                    {field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel},
+                    {field: 'target', displayName: $scope.labels.targetLabel}]
+            };
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedParameter = row.entity;
+                });
+            };
+        });
+
+        // Click handler for add button
+        $scope.addNewParameter = function () {
+            var newParameter = {
+                source: '',
+                sourceExpression: '',
+                target: ''};
+
+            $scope.parameters.push(newParameter);
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newParameter);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeParameter = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.parameters.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+                $scope.parameters.splice(index, 1);
+
+                if ($scope.parameters.length == 0) {
+                    $scope.selectedParameter = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.parameters.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.parameters[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.moveParameterUp = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.parameters.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.parameters[index];
+                    $scope.parameters.splice(index, 1);
+                    $timeout(function () {
+                        $scope.parameters.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.moveParameterDown = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.parameters.indexOf(selectedItems[0]);
+                if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.parameters[index];
+                    $scope.parameters.splice(index, 1);
+                    $timeout(function () {
+                        $scope.parameters.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.parameters.length > 0) {
+                $scope.property.value = {};
+                $scope.property.value.outParameters = $scope.parameters;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.close();
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+    }]);

+ 126 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-sequenceflow-order-controller.js

@@ -0,0 +1,126 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Sequence flow order controller
+ */
+
+angular.module('flowableModeler').controller('FlowableSequenceFlowOrderCtrl',
+    [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
+
+    // Config for the modal window
+    var opts = {
+        template:  'editor-app/configuration/properties/sequenceflow-order-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    _internalCreateModal(opts, $modal, $scope);
+}]);
+
+angular.module('flowableModeler').controller('FlowableSequenceFlowOrderPopupCtrl',
+    ['$scope', '$translate', function($scope, $translate) {
+
+    // Find the outgoing sequence flow of the current selected shape
+    var outgoingSequenceFlow = [];
+    var selectedShape = $scope.selectedShape;
+    if (selectedShape) {
+        var outgoingNodes = selectedShape.getOutgoingShapes();
+        for (var i=0; i<outgoingNodes.length; i++) {
+            if (outgoingNodes[i].getStencil().idWithoutNs() === 'SequenceFlow') {
+                var targetActivity = outgoingNodes[i].getTarget();
+                // We need the resourceId of a sequence flow, not the id because that will change with every editor load
+                outgoingSequenceFlow.push({
+                    id : outgoingNodes[i].resourceId,
+                    targetTitle : targetActivity.properties.get('oryx-name'),
+                    targetType : $translate.instant(targetActivity.getStencil().title())
+                });
+            }
+        }
+    } else {
+        console.log('Programmatic error: no selected shape found');
+    }
+
+    // Now we can apply the order which was (possibly) previously saved
+    var orderedOutgoingSequenceFlow = [];
+    if ($scope.property.value && $scope.property.value.sequenceFlowOrder) {
+
+        var sequenceFlowOrderList = $scope.property.value.sequenceFlowOrder;
+
+        // Loop the list of sequence flow that was saved  in the json model and match them with the outgoing sequence flow found above
+        for (var flowIndex=0; flowIndex < sequenceFlowOrderList.length; flowIndex++) {
+
+            // find the sequence flow in the outgoing sequence flows.
+
+            for (var outgoingFlowIndex=0; outgoingFlowIndex < outgoingSequenceFlow.length; outgoingFlowIndex++) {
+                if (outgoingSequenceFlow[outgoingFlowIndex].id === sequenceFlowOrderList[flowIndex]) {
+                    orderedOutgoingSequenceFlow.push(outgoingSequenceFlow[outgoingFlowIndex]);
+                    outgoingSequenceFlow.splice(outgoingFlowIndex, 1);
+                    break;
+                }
+            }
+        }
+
+        // Now all the matching sequence flow we're removed from the outgoing sequence flow list
+        // We can simply apply the remaining ones (these are new vs. the time when the values were saved to the model)
+        orderedOutgoingSequenceFlow = orderedOutgoingSequenceFlow.concat(outgoingSequenceFlow);
+
+    } else {
+        orderedOutgoingSequenceFlow = outgoingSequenceFlow;
+    }
+
+    // Now we can put it on the scope
+    $scope.outgoingSequenceFlow = orderedOutgoingSequenceFlow;
+
+    // Move up click handler
+    $scope.moveUp = function(index) {
+        var temp = $scope.outgoingSequenceFlow[index];
+        $scope.outgoingSequenceFlow[index] = $scope.outgoingSequenceFlow[index - 1];
+        $scope.outgoingSequenceFlow[index - 1] = temp;
+    };
+
+    // Move down click handler
+    $scope.moveDown = function(index) {
+        var temp = $scope.outgoingSequenceFlow[index];
+        $scope.outgoingSequenceFlow[index] = $scope.outgoingSequenceFlow[index + 1];
+        $scope.outgoingSequenceFlow[index + 1] = temp;
+    };
+
+    // Save click handler
+    $scope.save = function() {
+        if ($scope.outgoingSequenceFlow.length > 0) {
+            $scope.property.value = {};
+            $scope.property.value.sequenceFlowOrder = [];
+
+            for (var flowIndex=0; flowIndex < $scope.outgoingSequenceFlow.length; flowIndex++) {
+                $scope.property.value.sequenceFlowOrder.push($scope.outgoingSequenceFlow[flowIndex].id);
+            }
+        } else {
+            $scope.property.value = null;
+        }
+
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    // Cancel click handler
+    $scope.cancel = function() {
+        $scope.close();
+    };
+
+    // Close button handler
+    $scope.close = function() {
+        $scope.property.mode = 'read';
+        $scope.$hide();
+    };
+
+}]);

+ 151 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-signal-definitions-controller.js

@@ -0,0 +1,151 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Execution listeners
+ */
+
+angular.module('flowableModeler').controller('FlowableSignalDefinitionsCtrl', ['$scope', '$modal', function ($scope, $modal) {
+
+    // Config for the modal window
+    var opts = {
+        template: 'editor-app/configuration/properties/signal-definitions-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    // Open the dialog
+    _internalCreateModal(opts, $modal, $scope);
+}]);
+
+//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259
+// Will be fixed in a newer version of Angular UI
+angular.module('flowableModeler').controller('FlowableSignalDefinitionsPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing signal definitions on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null && $scope.property.value.length > 0) {
+
+            if ($scope.property.value.constructor == String) {
+                $scope.signalDefinitions = JSON.parse($scope.property.value);
+            }
+            else {
+                // Note that we clone the json object rather then setting it directly,
+                // this to cope with the fact that the user can click the cancel button and no changes should have happened
+                $scope.signalDefinitions = angular.copy($scope.property.value);
+            }
+
+        } else {
+            $scope.signalDefinitions = [];
+        }
+
+        // Array to contain selected signal definitions (yes - we only can select one, but ng-grid isn't smart enough)
+        $scope.selectedSignalDefinition = undefined;
+        $scope.translationsRetrieved = false;
+
+        $scope.labels = {};
+
+        var idPromise = $translate('PROPERTY.SIGNALDEFINITIONS.ID');
+        var namePromise = $translate('PROPERTY.SIGNALDEFINITIONS.NAME');
+        var scopePromise = $translate('PROPERTY.SIGNALDEFINITIONS.SCOPE');
+
+        $q.all([idPromise, namePromise, scopePromise]).then(function (results) {
+
+            $scope.labels.idLabel = results[0];
+            $scope.labels.nameLabel = results[1];
+            $scope.labels.scopeLabel = results[2];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.signalDefinitions,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [
+                    {field: 'id', displayName: $scope.labels.idLabel},
+                    {field: 'name', displayName: $scope.labels.nameLabel},
+                    {field: 'scope', displayName: $scope.labels.scopeLabel}]
+            };
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedSignalDefinition = row.entity;
+                });
+            };
+        });
+
+        // Click handler for add button
+        $scope.addNewSignalDefinition = function () {
+            var newSignalDefinition = {id: '', name: '', scope: 'global'};
+
+            $scope.signalDefinitions.push(newSignalDefinition);
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newSignalDefinition);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeSignalDefinition = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.signalDefinitions.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+                $scope.signalDefinitions.splice(index, 1);
+
+                if ($scope.signalDefinitions.length == 0) {
+                    $scope.selectedSignalDefinition = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.signalDefinitions.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.signalDefinitions[0]);
+                    }
+                });
+            }
+        };
+
+        $scope.scopeOptions = [{'value': 'global', 'translationId': 'PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL'},
+                                {'value': 'processInstance', 'translationId': 'PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE'}];
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.signalDefinitions.length > 0) {
+                $scope.property.value = $scope.signalDefinitions;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+    }]);

+ 42 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-signal-scope-controller.js

@@ -0,0 +1,42 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+angular.module('flowableModeler').controller('FlowableSignalRefCtrl', [ '$scope', function($scope) {
+
+    // Find the parent shape on which the signal definitions are defined
+    var signalDefinitionsProperty = undefined;
+    var parent = $scope.selectedShape;
+    while (parent !== null && parent !== undefined && signalDefinitionsProperty === undefined) {
+        if (parent.properties && parent.properties.get('oryx-signaldefinitions')) {
+            signalDefinitionsProperty = parent.properties.get('oryx-signaldefinitions');
+        } else {
+            parent = parent.parent;
+        }
+    }
+
+    try {
+        signalDefinitionsProperty = JSON.parse(signalDefinitionsProperty);
+        if (typeof signalDefinitionsProperty == 'string') {
+            signalDefinitionsProperty = JSON.parse(signalDefinitionsProperty);
+        }
+    } catch (err) {
+        // Do nothing here, just to be sure we try-catch it
+    }
+
+    $scope.signalDefinitions = signalDefinitionsProperty;
+
+
+    $scope.signalChanged = function() {
+    	$scope.updatePropertyInModel($scope.property);
+    };
+}]);

+ 356 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties-task-listeners-controller.js

@@ -0,0 +1,356 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Task listeners
+ */
+
+angular.module('flowableModeler').controller('FlowableTaskListenersCtrl',
+    ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) {
+
+        // Config for the modal window
+        var opts = {
+            template: 'editor-app/configuration/properties/task-listeners-popup.html?version=' + Date.now(),
+            scope: $scope
+        };
+
+        // Open the dialog
+        _internalCreateModal(opts, $modal, $scope);
+    }]);
+
+angular.module('flowableModeler').controller('FlowableTaskListenersPopupCtrl',
+    ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
+
+        // Put json representing form properties on scope
+        if ($scope.property.value !== undefined && $scope.property.value !== null
+            && $scope.property.value.taskListeners !== undefined
+            && $scope.property.value.taskListeners !== null) {
+
+            if ($scope.property.value.taskListeners.constructor == String) {
+                $scope.taskListeners = JSON.parse($scope.property.value.taskListeners);
+            }
+            else {
+                // Note that we clone the json object rather then setting it directly,
+                // this to cope with the fact that the user can click the cancel button and no changes should have happened
+                $scope.taskListeners = angular.copy($scope.property.value.taskListeners);
+            }
+
+            for (var i = 0; i < $scope.taskListeners.length; i++) {
+                var taskListener = $scope.taskListeners[i];
+                if (taskListener.className !== undefined && taskListener.className !== '') {
+                    taskListener.implementation = taskListener.className;
+                }
+                else if (taskListener.expression !== undefined && taskListener.expression !== '') {
+                    taskListener.implementation = taskListener.expression;
+                }
+                else if (taskListener.delegateExpression !== undefined && taskListener.delegateExpression !== '') {
+                    taskListener.implementation = taskListener.delegateExpression;
+                }
+            }
+        } else {
+            $scope.taskListeners = [];
+        }
+
+        $scope.selectedListener = undefined;
+        $scope.selectedField = undefined;
+        $scope.fields = [];
+        $scope.translationsRetrieved = false;
+
+        $scope.labels = {};
+
+        var eventPromise = $translate('PROPERTY.TASKLISTENERS.EVENT');
+        var implementationPromise = $translate('PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION');
+        var namePromise = $translate('PROPERTY.TASKLISTENERS.FIELDS.NAME');
+
+        $q.all([eventPromise, implementationPromise, namePromise]).then(function (results) {
+            $scope.labels.eventLabel = results[0];
+            $scope.labels.implementationLabel = results[1];
+            $scope.labels.nameLabel = results[2];
+            $scope.translationsRetrieved = true;
+
+            // Config for grid
+            $scope.gridOptions = {
+                data: $scope.taskListeners,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                enableHorizontalScrollbar: 0,
+                enableColumnMenus: false,
+                enableSorting: false,
+                columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel},
+                    {field: 'implementation', displayName: $scope.labels.implementationLabel}]
+            };
+
+            $scope.gridOptions.onRegisterApi = function (gridApi) {
+                //set gridApi on scope
+                $scope.gridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedListener = row.entity;
+                    $scope.selectedField = undefined;
+                    if ($scope.selectedListener) {
+                        var fields = $scope.selectedListener.fields;
+                        if (fields !== undefined && fields !== null) {
+                            for (var i = 0; i < fields.length; i++) {
+                                var field = fields[i];
+                                if (field.stringValue !== undefined && field.stringValue !== '') {
+                                    field.implementation = field.stringValue;
+                                } else if (field.expression !== undefined && field.expression !== '') {
+                                    field.implementation = field.expression;
+                                } else if (field.string !== undefined && field.string !== '') {
+                                    field.implementation = field.string;
+                                }
+                            }
+                        } else {
+                            $scope.selectedListener.fields = [];
+                        }
+
+                        $scope.fields.length = 0;
+                        for (var i = 0; i < $scope.selectedListener.fields.length; i++) {
+                            $scope.fields.push($scope.selectedListener.fields[i]);
+                        }
+                    }
+                });
+            };
+
+            // Config for field grid
+            $scope.gridFieldOptions = {
+                data: $scope.fields,
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                modifierKeysToMultiSelect: false,
+                columnDefs: [{field: 'name', displayName: $scope.labels.name},
+                    {field: 'implementation', displayName: $scope.labels.implementationLabel}]
+            };
+
+            $scope.gridFieldOptions.onRegisterApi = function (gridApi) {
+                // set gridApi on scope
+                $scope.fieldGridApi = gridApi;
+                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
+                    $scope.selectedField = row.entity;
+                });
+            };
+        });
+
+        $scope.listenerDetailsChanged = function () {
+            if ($scope.selectedListener.className !== '') {
+                $scope.selectedListener.implementation = $scope.selectedListener.className;
+            } else if ($scope.selectedListener.expression !== '') {
+                $scope.selectedListener.implementation = $scope.selectedListener.expression;
+            } else if ($scope.selectedListener.delegateExpression !== '') {
+                $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression;
+            } else {
+                $scope.selectedListener.implementation = '';
+            }
+        };
+
+        // Click handler for add button
+        $scope.addNewListener = function () {
+            var newListener = {
+                event: 'create',
+                implementation: '',
+                className: '',
+                expression: '',
+                delegateExpression: ''
+            };
+            $scope.taskListeners.push(newListener);
+
+            $timeout(function () {
+                $scope.gridApi.selection.toggleRowSelection(newListener);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeListener = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.taskListeners.indexOf(selectedItems[0]);
+                $scope.gridApi.selection.toggleRowSelection(selectedItems[0]);
+
+                $scope.taskListeners.splice(index, 1);
+
+                if ($scope.taskListeners.length == 0) {
+                    $scope.selectedListener = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.taskListeners.length > 0) {
+                        $scope.gridApi.selection.toggleRowSelection($scope.taskListeners[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.moveListenerUp = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.taskListeners.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.taskListeners[index];
+                    $scope.taskListeners.splice(index, 1);
+                    $timeout(function () {
+                        $scope.taskListeners.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.moveListenerDown = function () {
+            var selectedItems = $scope.gridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.taskListeners.indexOf(selectedItems[0]);
+                if (index != $scope.taskListeners.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.taskListeners[index];
+                    $scope.taskListeners.splice(index, 1);
+                    $timeout(function () {
+                        $scope.taskListeners.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.gridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+
+                }
+            }
+        };
+
+        $scope.fieldDetailsChanged = function () {
+            if ($scope.selectedField.stringValue != '') {
+                $scope.selectedField.implementation = $scope.selectedField.stringValue;
+            } else if ($scope.selectedField.expression != '') {
+                $scope.selectedField.implementation = $scope.selectedField.expression;
+            } else if ($scope.selectedField.string != '') {
+                $scope.selectedField.implementation = $scope.selectedField.string;
+            } else {
+                $scope.selectedField.implementation = '';
+            }
+        };
+
+        // Click handler for add button
+        $scope.addNewField = function () {
+            if ($scope.selectedListener) {
+                if ($scope.selectedListener.fields == undefined) {
+                    $scope.selectedListener.fields = [];
+                }
+
+                var newField = {
+                    name: 'fieldName',
+                    implementation: '',
+                    stringValue: '',
+                    expression: '',
+                    string: ''
+                };
+                $scope.fields.push(newField);
+                $scope.selectedListener.fields.push(newField);
+
+                $timeout(function () {
+                    $scope.fieldGridApi.selection.toggleRowSelection(newField);
+                });
+            }
+        };
+
+        // Click handler for remove button
+        $scope.removeField = function () {
+            var selectedItems = $scope.fieldGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                $scope.fieldGridApi.selection.toggleRowSelection(selectedItems[0]);
+
+                $scope.fields.splice(index, 1);
+                $scope.selectedListener.fields.splice(index, 1);
+
+                if ($scope.fields.length == 0) {
+                    $scope.selectedField = undefined;
+                }
+
+                $timeout(function () {
+                    if ($scope.fields.length > 0) {
+                        $scope.fieldGridApi.selection.toggleRowSelection($scope.fields[0]);
+                    }
+                });
+            }
+        };
+
+        // Click handler for up button
+        $scope.moveFieldUp = function () {
+            var selectedItems = $scope.fieldGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                if (index != 0) { // If it's the first, no moving up of course
+                    var temp = $scope.fields[index];
+                    $scope.fields.splice(index, 1);
+                    $scope.selectedListener.fields.splice(index, 1);
+                    $timeout(function () {
+                        $scope.fields.splice(index + -1, 0, temp);
+                        $scope.selectedListener.fields.splice(index + -1, 0, temp);
+                        $timeout(function () {
+                            $scope.fieldGridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+
+                }
+            }
+        };
+
+        // Click handler for down button
+        $scope.moveFieldDown = function () {
+            var selectedItems = $scope.fieldGridApi.selection.getSelectedRows();
+            if (selectedItems && selectedItems.length > 0) {
+                var index = $scope.fields.indexOf(selectedItems[0]);
+                if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course
+                    var temp = $scope.fields[index];
+                    $scope.fields.splice(index, 1);
+                    $scope.selectedListeners.fields.splice(index, 1);
+                    $timeout(function () {
+                        $scope.fields.splice(index + 1, 0, temp);
+                        $scope.selectedListener.fields.splice(index + 1, 0, temp);
+                        $timeout(function () {
+                            $scope.fieldGridApi.selection.toggleRowSelection(temp);
+                        });
+                    });
+                }
+            }
+        };
+
+        // Click handler for save button
+        $scope.save = function () {
+
+            if ($scope.taskListeners.length > 0) {
+                $scope.property.value = {};
+                $scope.property.value.taskListeners = $scope.taskListeners;
+            } else {
+                $scope.property.value = null;
+            }
+
+            $scope.updatePropertyInModel($scope.property);
+            $scope.close();
+        };
+
+        $scope.cancel = function () {
+            $scope.close();
+        };
+
+        // Close button handler
+        $scope.close = function () {
+            $scope.property.mode = 'read';
+            $scope.$hide();
+        };
+
+    }]);

+ 109 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties.js

@@ -0,0 +1,109 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'use strict';
+
+var FLOWABLE = FLOWABLE || {};
+FLOWABLE.PROPERTY_CONFIG =
+{
+    "string": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/string-property-write-mode-template.html"
+    },
+    "boolean": {
+        "templateUrl": "editor-app/configuration/properties/boolean-property-template.html"
+    },
+    "text" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/text-property-write-template.html"
+    },
+    "flowable-multiinstance" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/multiinstance-property-write-template.html"
+    },
+    "flowable-ordering" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/ordering-property-write-template.html"
+    },
+    "oryx-formproperties-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/form-properties-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/form-properties-write-template.html"
+    },
+    "oryx-executionlisteners-multiplecomplex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/execution-listeners-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/execution-listeners-write-template.html"
+    },
+    "oryx-tasklisteners-multiplecomplex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/task-listeners-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/task-listeners-write-template.html"
+    },
+    "oryx-eventlisteners-multiplecomplex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/event-listeners-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/event-listeners-write-template.html"
+    },
+    "oryx-usertaskassignment-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/assignment-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/assignment-write-template.html"
+    },
+    "oryx-servicetaskfields-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/fields-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/fields-write-template.html"
+    },
+    "oryx-callactivityinparameters-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/in-parameters-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/in-parameters-write-template.html"
+    },
+    "oryx-callactivityoutparameters-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/out-parameters-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/out-parameters-write-template.html"
+    },
+    "oryx-subprocessreference-subprocess-link": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-write-template.html"
+    },
+    "oryx-formreference-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/form-reference-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/form-reference-write-template.html"
+    },
+    "oryx-sequencefloworder-complex" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/sequenceflow-order-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/sequenceflow-order-write-template.html"
+    },
+    "oryx-conditionsequenceflow-complex" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/condition-expression-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/condition-expression-write-template.html"
+    },
+    "oryx-signaldefinitions-multiplecomplex" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/signal-definitions-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/signal-definitions-write-template.html"
+    },
+    "oryx-signalref-string" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/signal-property-write-template.html"
+    },
+    "oryx-messagedefinitions-multiplecomplex" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/message-definitions-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/message-definitions-write-template.html"
+    },
+    "oryx-messageref-string" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/message-property-write-template.html"
+    },
+    "oryx-duedatedefinition-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/duedate-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/duedate-write-template.html"
+    },
+    "oryx-decisiontaskdecisiontablereference-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/decisiontable-reference-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/decisiontable-reference-write-template.html"
+    }
+};

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 15 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/assignment-display-template.html


+ 268 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/assignment-popup.html

@@ -0,0 +1,268 @@
+<div class="modal" ng-controller="FlowableAssignmentPopupCtrl">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+                <h2 translate>PROPERTY.ASSIGNMENT.TITLE</h2>
+            </div>
+            <div class="modal-body">
+                <div class="detail-group clearfix">
+
+                    <div class="form-group clearfix">
+                        <div class="col-xs-12">
+                            <label class="col-xs-4">{{'PROPERTY.ASSIGNMENT.TYPE' | translate}}</label>
+
+                            <div class="col-xs-8">
+                                <div class="btn-group btn-group-justified">
+                                    <div class="btn-group">
+                                        <button type="button" class="btn btn-default" ng-click="popup.assignmentObject.type = 'idm'"
+                                                ng-model="popup.assignmentObject.type" ng-class="{'active' : popup.assignmentObject.type == 'idm'}">
+                                            {{'PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE' | translate}}
+                                        </button>
+                                    </div>
+                                    <div class="btn-group">
+                                        <button type="button" class="btn btn-default" ng-click="popup.assignmentObject.type = 'static'"
+                                                ng-model="popup.assignmentObject.type" ng-class="{'active' : popup.assignmentObject.type != 'idm'}">
+                                            {{'PROPERTY.ASSIGNMENT.TYPE.STATIC' | translate}}
+                                        </button>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix" ng-show="popup.assignmentObject.type != 'idm'">
+                        <div class="col-xs-12">
+                            <label>{{'PROPERTY.ASSIGNMENT.ASSIGNEE' | translate}}</label>
+                        </div>
+                        <div class="col-xs-12">
+                            <input type="text" id="assigneeField" class="form-control" ng-model="popup.assignmentObject.static.assignee"
+                                   placeholder="{{'PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER' | translate}}"/>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix" ng-show="popup.assignmentObject.type != 'idm'">
+                        <div class="col-xs-12">
+                            <label>{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS' | translate}}</label>
+                        </div>
+                        <div class="col-xs-12" ng-repeat="candidateUser in popup.assignmentObject.static.candidateUsers">
+                            <input id="userField" class="form-control" type="text" ng-model="candidateUser.value"/>
+                            <i ng-if="popup.assignmentObject.static.candidateUsers.length >1" class="glyphicon glyphicon-minus clickable-property"
+                               ng-click="removeCandidateUserValue($index)"></i>
+                            <i ng-if="$index == (popup.assignmentObject.static.candidateUsers.length - 1)" class="glyphicon glyphicon-plus clickable-property"
+                               ng-click="addCandidateUserValue($index)"></i>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix" ng-show="popup.assignmentObject.type != 'idm'">
+                        <div class="col-xs-12">
+                            <label>{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS' | translate}}</label>
+                        </div>
+                        <div class="col-xs-12" ng-repeat="candidateGroup in popup.assignmentObject.static.candidateGroups">
+                            <input id="groupField" class="form-control" type="text" ng-model="candidateGroup.value"/>
+                            <i ng-if="popup.assignmentObject.static.candidateGroups.length >1" class="glyphicon glyphicon-minus clickable-property"
+                               ng-click="removeCandidateGroupValue($index)"></i>
+                            <i ng-if="$index == (popup.assignmentObject.static.candidateGroups.length - 1)" class="glyphicon glyphicon-plus clickable-property"
+                               ng-click="addCandidateGroupValue($index)"></i>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix" ng-show="popup.assignmentObject.type == 'idm'">
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label>{{'PROPERTY.ASSIGNMENT.IDM.TYPE' | translate}}</label>
+                            </div>
+                            <div class="col-xs-8">
+                                <div class="btn-group span">
+                                    <button class="selection" ng-options="option as (option.title | translate) for option in assignmentOptions"
+                                            bs-select ng-model="assignmentOption" activiti-fix-dropdown-bug>
+                                    </button>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix" ng-show="popup.assignmentObject.type == 'idm' && assignmentOption.id == 'users'">
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label>{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS' | translate}}</label>
+                            </div>
+                            <div class="col-xs-8 clearfix">
+                                <ul class="simple-list"
+                                    ng-show="popup.assignmentObject.idm.candidateUsers.length || popup.assignmentObject.idm.candidateUserFields.length">
+                                    <li ng-repeat="user in popup.assignmentObject.idm.candidateUsers">
+                                        <i class="icon icon-user"></i>
+                                        <span user-name="user"></span>
+
+                                        <div class="actions">
+                                            <a ng-click="removeCandidateUser(user)"><i class="icon icon-remove"></i></a>
+                                        </div>
+                                    </li>
+                                    <li ng-repeat="userField in popup.assignmentObject.idm.candidateUserFields">
+                                        <i class="icon icon-user"></i>
+                                        <span>{{userField.name}}</span>
+                                        <span class="field-type"> - {{userFieldField.id}}</span>
+
+                                        <div class="actions">
+                                            <a ng-click="removeCandidateUserField(userField)"><i class="icon icon-remove"></i></a>
+                                        </div>
+                                    </li>
+                                </ul>
+                                <div class="no-results"
+                                     ng-if="(!popup.assignmentObject.idm.candidateUsers || !popup.assignmentObject.idm.candidateUsers.length) && (!popup.assignmentObject.idm.candidateUserFields || !popup.assignmentObject.idm.candidateUserFields.length)">
+                                    {{'PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS' | translate}}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix" ng-show="popup.assignmentObject.type == 'idm' && assignmentOption.id == 'groups'">
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label>{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS' | translate}}</label>
+                            </div>
+                            <div class="col-xs-8 clearfix">
+                                <ul class="simple-list"
+                                    ng-show="popup.assignmentObject.idm.candidateGroups.length || popup.assignmentObject.idm.candidateGroupFields.length">
+                                    <li ng-repeat="group in popup.assignmentObject.idm.candidateGroups">
+                                        {{group.name}}
+                                        <div class="actions">
+                                            <a ng-click="removeCandidateGroup(group)"><i class="icon icon-remove"></i></a>
+                                        </div>
+                                    </li>
+                                    <li ng-repeat="groupField in popup.assignmentObject.idm.candidateGroupFields">
+                                        {{groupField.name}}
+                                        <div class="actions">
+                                            <a ng-click="removeCandidateGroupField(groupField)"><i class="icon icon-remove"></i></a>
+                                        </div>
+                                    </li>
+                                </ul>
+                                <div class="no-results"
+                                     ng-if="(!popup.assignmentObject.idm.candidateGroups || !popup.assignmentObject.idm.candidateGroups.length) && (!popup.assignmentObject.idm.candidateGroupFields || !popup.assignmentObject.idm.candidateGroupFields.length)">
+                                    {{'PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS' | translate}}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix" ng-show="popup.assignmentObject.type == 'idm' && assignmentOption.id == 'user'">
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label>{{'PROPERTY.ASSIGNMENT.ASSIGNEE' | translate}}</label>
+                            </div>
+                            <div class="col-xs-8">
+                                <label ng-if="!popup.assignmentObject.idm.assignee && !popup.assignmentObject.idm.assigneeField">{{'PROPERTY.ASSIGNMENT.NONE' | translate}}</label>
+                                <ul class="simple-list" ng-if="popup.assignmentObject.idm.assignee || popup.assignmentObject.idm.assigneeField">
+                                    <li>
+                                        <i class="icon icon-user"></i>
+                                        <span ng-if="popup.assignmentObject.idm.assignee" user-name="popup.assignmentObject.idm.assignee"></span>
+                                        <span ng-if="popup.assignmentObject.idm.assigneeField">{{popup.assignmentObject.idm.assigneeField.name}}</span>
+                                        <span ng-if="popup.assignmentObject.idm.assigneeField"
+                                              class="field-type"> - {{popup.assignmentObject.idm.assigneeField.id}}</span>
+
+                                        <div class="actions" ng-if="popup.assignmentObject.idm.assignee || popup.assignmentObject.idm.assigneeField">
+                                            <a ng-click="removeAssignee()"><i class="icon icon-remove"></i></a>
+                                        </div>
+                                    </li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix"
+                         ng-if="popup.assignmentObject.type == 'idm' && (!popup.assignmentObject.assignmentSourceType || popup.assignmentObject.assignmentSourceType == 'search') && (assignmentOption.id == 'user' || assignmentOption.id == 'users')">
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label>{{'PROPERTY.ASSIGNMENT.SEARCH' | translate}}</label>
+                            </div>
+                            <div class="col-xs-8">
+                                <input class="form-control" type="text" id="people-select-input" placeholder="{{'PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER' | translate}}" auto-focus custom-keys
+                                       up-pressed="previousUser()" down-pressed="nextUser()" enter-pressed="confirmUser()" delayed-model="popup.filter" delay="200"/>
+                            </div>
+                        </div>
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label></label>
+                            </div>
+                            <div class="col-xs-8">
+                                <div class="subtle" style="margin: 2px 0 2px 0">
+                                    <span translate="PROPERTY.ASSIGNMENT.MATCHING"></span>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label></label>
+                            </div>
+                            <div class="col-xs-8">
+                                <div class="inline-people-select">
+                                    <ul class="simple-list">
+                                        <li ng-click="confirmUser(user)" ng-repeat="user in popup.userResults" ng-class="{'active': $index == popup.selectedIndex}">
+                                            <div user-picture="user" user-index="$index" user-name="user"></div>
+                                        </li>
+                                    </ul>
+                                    <div class="nothing-to-see" translate="GENERAL.MESSAGE.PEOPLE-NO-MATCHING-RESULTS" ng-show="popup.userResults.length == 0"></div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix"
+                         ng-if="popup.assignmentObject.type == 'idm' && (!popup.assignmentObject.assignmentSourceType || popup.assignmentObject.assignmentSourceType == 'search') && assignmentOption.id == 'groups'">
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label>{{'PROPERTY.ASSIGNMENT.SEARCH' | translate}}</label>
+                            </div>
+                            <div class="col-xs-8">
+                                <input class="form-control" type="text" id="people-select-input" placeholder="{{'PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP' | translate}}" auto-focus custom-keys
+                                       up-pressed="previousGroup()" down-pressed="nextGroup()" enter-pressed="confirmGroup()" delayed-model="popup.groupFilter"
+                                       delay="200"/>
+                            </div>
+                        </div>
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label></label>
+                            </div>
+                            <div class="col-xs-8">
+                                <div class="subtle">
+                                    <span translate="PROPERTY.ASSIGNMENT.MATCHING"></span>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="col-xs-12">
+                            <div class="col-xs-4">
+                                <label></label>
+                            </div>
+                            <div class="col-xs-8">
+                                <div class="inline-people-select">
+                                    <ul class="simple-list">
+                                        <li ng-click="confirmGroup(group);" ng-repeat="group in popup.groupResults"
+                                            ng-class="{'active': $index == popup.selectedGroupIndex}">
+                                            {{group.name}}
+                                        </li>
+                                    </ul>
+                                    <div class="nothing-to-see" translate="GENERAL.MESSAGE.GROUP-NO-MATCHING-RESULTS" ng-show="popup.groupResults.length == 0"></div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-group clearfix">
+                        <div class="col-xs-12">
+                            <div class="col-xs-12">
+                                <label>
+                                    <input type="checkbox" ng-model="assignment.initiatorCanCompleteTask">
+                                    &nbsp;{{'PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE' | translate}}
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button ng-click="close()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+                <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+            </div>
+        </div>
+    </div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/assignment-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableAssignmentCtrl">
+</span>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/boolean-property-template.html

@@ -0,0 +1,4 @@
+
+<div ng-controller="FlowableBooleanPropertyCtrl">
+    <input type="checkbox" ng-model="property.value" ng-change="changeValue()"/>
+</div>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/condition-expression-display-template.html

@@ -0,0 +1,3 @@
+<span ng-if="property.value.expression.type != 'variables' && property.value.expression.staticValue">{{property.value.expression.staticValue|limitTo:20}}</span>
+<span ng-if="property.value && !property.value.expression">{{property.value|limitTo:20}}</span>
+<span ng-if="!property.value">{{'PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY' | translate}}</span>

+ 26 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/condition-expression-popup.html

@@ -0,0 +1,26 @@
+<div class="modal" ng-controller="FlowableConditionExpressionPopupCtrl">
+<div class="modal-dialog modal-wide">
+<div class="modal-content">
+<div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+    <h2 translate>PROPERTY.SEQUENCEFLOW.CONDITION.TITLE</h2>
+</div>
+<div class="modal-body">
+
+    <div class="detail-group clearfix">
+        
+        <div class="col-xs-12">
+            <label class="col-xs-3">{{'PROPERTY.SEQUENCEFLOW.CONDITION.STATIC' | translate}}</label>
+            <div class="col-xs-9">
+                <textarea class="form-control" ng-model="expression.staticValue" style="width:70%; height:100%; max-width: 100%; max-height: 100%; min-height: 50px"/>
+            </div>
+        </div>
+
+    </div>
+    <div class="modal-footer">
+        <button ng-click="close()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+        <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+    </div>
+</div>
+</div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/condition-expression-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableConditionExpressionCtrl">
+</span>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/decisiontable-reference-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="property.value.name">{{property.value.name}}</span>
+<span ng-if="!property.value || !property.value.name" translate>PROPERTY.DECISIONTABLEREFERENCE.EMPTY</span>

+ 74 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/decisiontable-reference-popup.html

@@ -0,0 +1,74 @@
+
+<div class="modal" ng-controller="FlowableDecisionTableReferencePopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+            <div class="modal-header" ng-if="popup.state == 'decisionTableReference'">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+                <h2>
+                    {{'PROPERTY.DECISIONTABLEREFERENCE.TITLE' | translate}}
+                    <span ng-show="selectedDecisionTable != null"> - {{selectedDecisionTable.name}}</span>
+                    <span ng-show="selectedDecisionTable == null"> - {{'PROPERTY.DECISIONTABLEREFERENCE.EMPTY' | translate}}</span>
+
+                </h2>
+            </div>
+            <div class="modal-header" ng-if="popup.state == 'newDecisionTable'"><h2>{{'DECISION-TABLE.POPUP.CREATE-TITLE' | translate}}</h2></div>
+            <div class="modal-body-with-overflow" ng-if="popup.state == 'decisionTableReference'">
+                <div class="detail-group clearfix">
+                    <div class="col-xs-12">
+                        <div class="alert alert-error" ng-show="!state.loadingDecisionTables && state.decisionTableError" translate>PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM</div>
+                    </div>
+                </div>
+                <div class="detail-group clearfix">
+                    <div class="col-xs-12 editor-item-picker">
+                        <div ng-if="!state.loadingDecisionTables && !state.decisionTableError" class="col-xs-4 editor-item-picker-component" ng-repeat="decisionTable in decisionTables" ng-class="{'selected' : decisionTable.decisionTableId == selectedDecisionTable.decisionTableId}" ng-click="selectDecisionTable(decisionTable, $event)">
+                           <div class="controls">
+                               <input type="checkbox" value="option1" ng-click="selectDecisionTable(decisionTable, $event)" ng-checked="decisionTable.id == selectedDecisionTable.id" />
+                           </div>
+                           <h4>{{decisionTable.name}}</h4>
+                           <img ng-src="{{config.contextRoot}}/app/rest/models/{{decisionTable.id}}/thumbnail" />
+                         </div>
+                         <div ng-show="state.loadingDecisionTables">
+                            <p class="loading" translate>PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING</p>
+                         </div>
+                         <div ng-show="!state.loadingDecisionTables && decisionTables.length == 0">
+                            <p translate>PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY</p>
+                         </div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-body" ng-if="popup.state == 'newDecisionTable'">
+                <p>{{'DECISION-TABLE.POPUP.CREATE-DESCRIPTION' | translate}}</p>
+                <div ng-if="model.errorMessage && model.errorMessage.length > 0" class="alert error" style="font-size: 14px; margin-top:20px">
+                  <div class="popup-error" style="font-size: 14px">
+                    <span class="glyphicon glyphicon-remove-circle"></span>
+                    <span>{{model.errorMessage}}</span>
+                  </div>
+                </div>
+                <div class="form-group">
+                    <label for="newDecisionTableName">{{'DECISION-TABLE.NAME' | translate}}</label>
+                    <input ng-disabled="model.loading" type="text" class="form-control"
+                           id="newDecisionTableName" ng-model="model.decisionTable.name" custom-keys enter-pressed="ok()" auto-focus editor-input-check>
+                </div>
+                <div class="form-group">
+                    <label for="newDecisionTableKey">{{'DECISION-TABLE.KEY' | translate}}</label>
+                    <input ng-disabled="model.loading" type="text" class="form-control"
+                           id="newDecisionTableKey" ng-model="model.decisionTable.key" editor-input-check>
+                </div>
+                <div class="form-group">
+                    <label for="newDecisionTableDescription">{{'DECISION-TABLE.DESCRIPTION' | translate}}</label>
+                    <textarea ng-disabled="model.loading" class="form-control" id="newDecisionTableDescription" rows="5" ng-model="model.decisionTable.description"></textarea>
+                </div>
+            </div>
+            <div class="modal-footer" ng-if="popup.state == 'decisionTableReference'">
+                <button ng-click="cancel()" class="btn btn-primary" translate>GENERAL.ACTION.CANCEL</button>
+            	<button ng-disabled="state.decisionTableError" ng-click="newDecisionTable()" class="btn btn-primary" translate>GENERAL.ACTION.NEW-DECISION-TABLE</button>
+            	<button ng-disabled="!selectedDecisionTable || state.decisionTableError" ng-click="open()" class="btn btn-primary" translate>GENERAL.ACTION.OPEN</button>
+                <button ng-disabled="state.decisionTableError" ng-click="save()" class="btn btn-primary" translate>GENERAL.ACTION.SAVE</button>
+            </div>
+            <div class="modal-footer" ng-if="popup.state == 'newDecisionTable'">
+                <button ng-click="cancel()" class="btn btn-primary" translate>GENERAL.ACTION.CANCEL</button>
+                <button ng-disabled="state.decisionTableError || model.decisionTable.name.length == 0 || model.decisionTable.key.length == 0" ng-click="createDecisionTable()" class="btn btn-primary" translate>GENERAL.ACTION.CREATE-DECISION-TABLE</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 2 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/decisiontable-reference-write-template.html

@@ -0,0 +1,2 @@
+<span ng-controller="FlowableDecisionTableReferenceCtrl">
+</span>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/default-value-display-template.html

@@ -0,0 +1,4 @@
+
+<span ng-if="!property.noValue">{{property.value|limitTo:20}}</span>
+<span ng-if="!property.noValue && property.value != null && property.value.length > 20">...</span>
+<span ng-if="property.noValue" translate>PROPERTY.EMPTY</span>

+ 6 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/duedate-display-template.html

@@ -0,0 +1,6 @@
+
+<span ng-if="property.value && property.value.duedate && property.value.duedate.field || property.value.duedate.field.taskDueDateField" translate>PROPERTY.DUEDATE.DEFINED</span>
+<span ng-if="property.value && property.value.duedate && property.value.duedate.fixed" translate>PROPERTY.DUEDATE.DEFINED</span>
+<span ng-if="property.value && property.value.duedateExpression">{{property.value.duedateExpression}}</span>
+<span ng-if="property.value && property.value.length > 0 && !property.value.duedate && !property.value.duedateExpression">{{property.value}}</span>
+<span ng-if="!property.value || property.value.length === 0" translate>PROPERTY.DUEDATE.EMPTY</span>

+ 120 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/duedate-popup.html

@@ -0,0 +1,120 @@
+
+<div class="modal" ng-controller="BpmnEditorDueDatePopupCtrl">
+<div class="modal-dialog">
+<div class="modal-content">
+<div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+    <h2 translate>PROPERTY.DUEDATE.TITLE</h2>
+</div>
+<div class="modal-body">
+    
+    <div class="clearfix first">
+        <div class="col-xs-12">
+            <div class="col-xs-12">
+                <div class="btn-group span">
+                    <button class="selection" data-toggle="dropdown" ng-options="option.id as (option.title | translate) for option in taskDueDateOptions"
+                        bs-select ng-model="popup.selectedDueDateOption" ng-change="dueDateOptionChanged()" activiti-fix-dropdown-bug>
+                       <i class="icon icon-caret-down"></i>
+                   </button>
+                </div>
+            </div>
+        </div>
+    </div>
+    
+    <div class="clearfix first" ng-if="popup.selectedDueDateOption === 'expression'" style="padding-top: 10px">
+        <div class="col-xs-12">
+            <div class="col-xs-4">
+                <label>{{'PROPERTY.DUEDATE.EXPRESSION-LABEL' | translate}}: </label>
+            </div>
+            <div class="col-xs-8">
+                <input id="expression" type="text" class="form-control" ng-model="popup.duedateExpression">
+            </div>
+        </div>
+    </div>
+    
+    <div class="clearfix first" ng-if="popup.selectedDueDateOption === 'field'" style="padding-top: 10px">
+        <div class="col-xs-12">
+            <div class="col-xs-4">
+                <label>{{'PROCESS-BUILDER.FIELD.TIMER.DATE-FIELD' | translate}}: </label>
+            </div>
+            <div class="col-xs-8">
+                <div field-select="popup.duedate.field.taskDueDateField" editor-type="bpmn" all-steps="allSteps" step-id="selectedShape.resourceId" field-type-filter="['date']"></div>
+            </div>
+        </div>
+    </div>
+    
+    <div class="clearfix first" ng-if="popup.selectedDueDateOption === 'field'" style="padding-top: 10px">
+        <div class="col-xs-12">
+            <div class="col-xs-4">
+                <label>{{'PROCESS-BUILDER.FIELD.DUEDATE.CALCULATION-TYPE' | translate}}: </label>
+            </div>
+            <div class="col-xs-8">
+                <div class="btn-group btn-group-justified">
+                  <div class="btn-group">
+                    <button type="button" class="btn btn-default" ng-click="setAddCalculationType()" ng-model="popup.duedate.field.taskDueDateCalculationType" ng-class="{'active' : (!popup.duedate.field.taskDueDateCalculationType || popup.duedate.field.taskDueDateCalculationType == 'add')}">{{'PROCESS-BUILDER.FIELD.DUEDATE.CALCULATION-OPTIONS.ADD' | translate}}</button>
+                  </div>
+                  <div class="btn-group">
+                    <button type="button" class="btn btn-default" ng-click="setSubtractCalculationType()" ng-model="popup.duedate.field.taskDueDateCalculationType" ng-class="{'active' : popup.duedate.field.taskDueDateCalculationType == 'subtract'}">{{'PROCESS-BUILDER.FIELD.DUEDATE.CALCULATION-OPTIONS.SUBTRACT' | translate}}</button>
+                  </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    
+    <div class="clearfix first" ng-if="popup.selectedDueDateOption === 'field'" style="padding-top: 10px">
+        <div class="col-xs-12">
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.YEARS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.field.years">
+            </div>
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.MONTHS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.field.months">
+            </div>
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.DAYS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.field.days">
+            </div>
+        </div>
+        <div class="col-xs-12">
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.HOURS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.field.hours">
+            </div>
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.MINUTES' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.field.minutes">
+            </div>
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.SECONDS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.field.seconds">
+            </div>
+        </div>
+    </div>
+    
+    <div class="clearfix first" ng-if="popup.selectedDueDateOption === 'static'" style="padding-top: 10px">
+        <div class="col-xs-12">
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.YEARS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.fixed.years">
+            </div>
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.MONTHS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.fixed.months">
+            </div>
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.DAYS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.fixed.days">
+            </div>
+        </div>
+        <div class="col-xs-12">
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.HOURS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.fixed.hours">
+            </div>
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.MINUTES' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.fixed.minutes">
+            </div>
+            <div class="col-xs-4">
+                {{'PROCESS-BUILDER.FIELD.TIMER.SECONDS' | translate}}:<input type="number" class="form-control" ng-model="popup.duedate.fixed.seconds">
+            </div>
+        </div>
+    </div>
+
+    <div class="modal-footer">
+        <button ng-click="close()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+        <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+    </div>
+</div>
+</div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/duedate-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="BpmnEditorDueDateCtrl">
+</span>

+ 5 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/errorgrid-critical.html

@@ -0,0 +1,5 @@
+<div class="ui-grid-cell-contents flowable-status">
+	<!-- we inverse the logic here. A false warning is critical. A true warning is a warning -->
+	<div class="flowable-warning" ng-if="row.entity.warning">Warning</div>
+	<div class="flowable-critical" ng-if="!row.entity.warning">Critical</div>
+</div>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/event-listeners-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.EVENTLISTENERS.DISPLAY' | translate:property.value.eventListeners}}</span>
+<span ng-if="property.noValue" translate>PROPERTY.EVENTLISTENERS.EMPTY</span>

+ 119 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/event-listeners-popup.html

@@ -0,0 +1,119 @@
+
+<div class="modal" ng-controller="FlowableEventListenersPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+                <h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h2>
+            </div>
+            <div class="modal-body">
+
+                <div class="row row-no-gutter">
+                	<div class="col-xs-10">
+            	        <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+            	        <div class="pull-right">
+            	            <div class="btn-group">
+            	                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+            	                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+            	            </div>
+            	            <div class="btn-group">
+            	                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewListener()"><i class="glyphicon glyphicon-plus"></i></a>
+            	                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeListener()"><i class="glyphicon glyphicon-minus"></i></a>
+            	            </div>
+            	        </div>
+            		</div>
+            	</div>
+
+            	<div class="row row-no-gutter">
+                  <div ng-if="translationsRetrieved" ng-show="selectedListener" class="col-xs-6">
+                    <div class="form-group">
+            	        	<label>{{'PROPERTY.EVENTLISTENERS.EVENTS' | translate}}</label>
+            	            <div ng-repeat="eventDefinition in selectedListener.events">
+            	            	  <select id="eventField" class="form-control" ng-model="eventDefinition.event" ng-change="listenerDetailsChanged()"
+                                          style="display:inline-block; width:80%;margin-bottom: 10px;">
+                                  <option title="{{'EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP' | translate}}">ACTIVITY_COMPENSATE</option>
+                                  <option title="{{'EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP' | translate}}">ACTIVITY_COMPLETED</option>
+                                  <option title="bla">ACTIVITY_ERROR_RECEIVED</option>
+                                  <option>ACTIVITY_MESSAGE_RECEIVED</option>
+                                  <option>ACTIVITY_SIGNALED</option>
+                                  <option>ACTIVITY_STARTED</option>
+                                  <option>ENGINE_CLOSED</option>
+                                  <option>ENGINE_CREATED</option>
+                                  <option>ENTITY_ACTIVATED</option>
+                                  <option>ENTITY_CREATED</option>
+                                  <option>ENTITY_DELETED</option>
+                                  <option>ENTITY_INITIALIZED</option>
+                                  <option>ENTITY_SUSPENDED</option>
+                                  <option>ENTITY_UPDATED</option>
+                                  <option>JOB_EXECUTION_FAILURE</option>
+                                  <option>JOB_EXECUTION_SUCCESS</option>
+                                  <option>JOB_RETRIES_DECREMENTED</option>
+                                  <option title="{{'EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP' | translate}}">MEMBERSHIP_CREATED</option>
+                                  <option title="{{'EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP' | translate}}">MEMBERSHIP_DELETED</option>
+                                  <option title="{{'EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP' | translate}}">MEMBERSHIPS_DELETED</option>
+                                  <option title="{{'EVENT_TYPE.TASK.ASSIGNED.TOOLTIP' | translate}}">TASK_ASSIGNED</option>
+                                  <option title="{{'EVENT_TYPE.TASK.COMPLETED.TOOLTIP' | translate}}">TASK_COMPLETED</option>
+                                  <option>TIMER_FIRED</option>
+                                  <option title="{{'EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP' | translate}}">UNCAUGHT_BPMN_ERROR</option>
+                                  <option title="{{'EVENT_TYPE.VARIABLE.CREATED.TOOLTIP' | translate}}">VARIABLE_CREATED</option>
+                                  <option title="{{'EVENT_TYPE.VARIABLE.DELETED.TOOLTIP' | translate}}">VARIABLE_DELETED</option>
+                                  <option title="{{'EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP' | translate}}">VARIABLE_UPDATED</option>
+            	               	</select>
+            		            <i ng-if="$index > 0" class="glyphicon glyphicon-minus clickable-property" ng-click="removeEventValue($index)"
+                                   style="margin: 5px 0 5px 10px; font-size: 16px; cursor:pointer;"></i>
+            		            <i class="glyphicon glyphicon-plus clickable-property" ng-click="addEventValue($index)"
+                                   style="margin: 5px 0 5px 10px; font-size: 16px; cursor:pointer;"></i>
+            	            </div>
+
+            	            <div class="form-group" ng-show="selectedListener.event" style="margin-top: 10px;">
+                                <input type="checkbox" id="rethrowField" class="checkbox" ng-model="selectedListener.rethrowEvent" ng-change="listenerDetailsChanged()" style="display:inline-block;"/>
+                                <label for="classField" ng-click="selectedListener.rethrowEvent = !selectedListener.rethrowEvent" style="cursor:pointer;">{{'PROPERTY.EVENTLISTENERS.RETHROW' | translate}}</label>
+                            </div>
+            	       	  </div>
+                     </div>
+                     <div ng-show="selectedListener && selectedListener.events[0].event" class="col-xs-6">
+                     	<div class="form-group" ng-if="!selectedListener.rethrowEvent">
+            		   		<label for="classField"> {{'PROPERTY.EVENTLISTENERS.CLASS' | translate}}</label>
+            		   		<input type="text" id="classField" class="form-control" ng-model="selectedListener.className" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="!selectedListener.rethrowEvent">
+            		   		<label for="delegateExpressionField">{{'PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION' | translate}}</label>
+            		   		<input type="text" id="delegateExpressionField" class="form-control" ng-model="selectedListener.delegateExpression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="!selectedListener.rethrowEvent">
+            		   		<label for="entityTypeField">{{'PROPERTY.EVENTLISTENERS.ENTITYTYPE' | translate}}</label>
+            		   		<input type="text" id="entityTypeField" class="form-control" ng-model="selectedListener.entityType" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="selectedListener.rethrowEvent">
+            		   		<label for="delegateExpressionField">{{'PROPERTY.EVENTLISTENERS.RETHROWTYPE' | translate}}</label>
+            		   		<select id="rethrowTypeField" class="form-control" ng-model="selectedListener.rethrowType" ng-change="rethrowTypeChanged()">
+                                <option>error</option>
+                                <option>message</option>
+                                <option>signal</option>
+                                <option>globalSignal</option>
+                            </select>
+            			</div>
+            			<div class="form-group" ng-if="selectedListener.rethrowEvent && selectedListener.rethrowType === 'error'">
+            		   		<label for="errorCodeField">{{'PROPERTY.EVENTLISTENERS.ERRORCODE' | translate}}</label>
+            		   		<input type="text" id="errorCodeField" class="form-control" ng-model="selectedListener.errorcode" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="selectedListener.rethrowEvent && selectedListener.rethrowType === 'message'">
+            		   		<label for="messageNameField">{{'PROPERTY.EVENTLISTENERS.MESSAGENAME' | translate}}</label>
+            		   		<input type="text" id="messageNameField" class="form-control" ng-model="selectedListener.messagename" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="selectedListener.rethrowEvent && (selectedListener.rethrowType === 'signal' || selectedListener.rethrowType === 'globalSignal')">
+            		   		<label for="messageNameField">{{'PROPERTY.EVENTLISTENERS.SIGNALNAME' | translate}}</label>
+            		   		<input type="text" id="signalNameField" class="form-control" ng-model="selectedListener.signalname" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER' | translate}}" />
+            			</div>
+                     </div>
+                     <div ng-show="!selectedListener" class="col-xs-6 muted no-property-selected" translate>PROPERTY.EVENTLISTENERS.UNSELECTED</div>
+                </div>
+
+            </div>
+            <div class="modal-footer">
+                <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+                <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/event-listeners-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableEventListenersCtrl">
+</span>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/execution-listeners-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.EXECUTIONLISTENERS.DISPLAY' | translate:property.value.executionListeners}}</span>
+<span ng-if="property.noValue" translate>PROPERTY.EXECUTIONLISTENERS.EMPTY</span>

+ 101 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/execution-listeners-popup.html

@@ -0,0 +1,101 @@
+
+<div class="modal" ng-controller="FlowableExecutionListenersPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+                <h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h2>
+            </div>
+            <div class="modal-body">
+
+                <div class="row row-no-gutter">
+                    <div class="col-xs-6">
+                        <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+                        <div class="pull-right">
+                            <div class="btn-group">
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+                            </div>
+                            <div class="btn-group">
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewListener()"><i class="glyphicon glyphicon-plus"></i></a>
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeListener()"><i class="glyphicon glyphicon-minus"></i></a>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="col-xs-6">
+                        <div ng-show="selectedListener">
+
+                            <div class="form-group">
+            			   		<label for="eventField">{{'PROPERTY.EXECUTIONLISTENERS.EVENT' | translate}}</label>
+            			   		<select id="eventField" class="form-control" ng-model="selectedListener.event">
+                                    <option>start</option>
+                                    <option>end</option>
+                                    <option>take</option>
+                                </select>
+            				</div>
+            				<div class="form-group">
+            			   		<label for="classField">{{'PROPERTY.EXECUTIONLISTENERS.CLASS' | translate}}</label>
+            			   		<input type="text" id="classField" class="form-control" ng-model="selectedListener.className" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER' | translate}}" />
+            				</div>
+            				<div class="form-group">
+            			   		<label for="expressionField">{{'PROPERTY.EXECUTIONLISTENERS.EXPRESSION' | translate}}</label>
+            			   		<input type="text" id="expressionField" class="form-control" ng-model="selectedListener.expression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER' | translate}}" />
+            				</div>
+            				<div class="form-group">
+            			   		<label for="delegateExpressionField">{{'PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION' | translate}}</label>
+            			   		<input type="text" id="delegateExpressionField" class="form-control" ng-model="selectedListener.delegateExpression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER' | translate}}" />
+            				</div>
+                        </div>
+                        <div ng-show="!selectedListener" class="muted no-property-selected" translate>PROPERTY.EXECUTIONLISTENERS.UNSELECTED</div>
+                    </div>
+                </div>
+
+                <div class="row row-no-gutter">
+                    <div class="col-xs-6">
+                        <div ng-if="translationsRetrieved" class="kis-field-grid" ui-grid="gridFieldOptions" ui-grid-selection></div>
+                        <div class="pull-right">
+                            <div class="btn-group">
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+                            </div>
+                            <div class="btn-group">
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewField()"><i class="glyphicon glyphicon-plus"></i></a>
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeField()"><i class="glyphicon glyphicon-minus"></i></a>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="col-xs-6">
+                        <div ng-show="selectedField">
+
+            				<div class="form-group">
+            			   		<label for="nameField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME' | translate}}</label>
+            			   		<input type="text" id="nameField" class="form-control" ng-model="selectedField.name" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER' | translate}}" />
+            				</div>
+                            <div class="form-group">
+            			   		<label for="stringValueField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE' | translate}}</label>
+            			   		<input type="text" id="stringValueField" class="form-control" ng-model="selectedField.stringValue" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER' | translate}}" />
+            				</div>
+            				<div class="form-group">
+            			   		<label for="expressionField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION' | translate}}</label>
+            			   		<input type="text" id="expressionField" class="form-control" ng-model="selectedField.expression" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER' | translate}}" />
+            				</div>
+            				<div class="form-group">
+            			   		<label for="stringField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING' | translate}}</label>
+            			   		<textarea id="stringField" class="form-control" ng-model="selectedField.string" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER' | translate}}"></textarea>
+            				</div>
+
+                        </div>
+                        <div ng-show="!selectedField" class="muted no-property-selected"translate>PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY</div>
+                    </div>
+                </div>
+
+            </div>
+            <div class="modal-footer">
+                <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+                <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/execution-listeners-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableExecutionListenersCtrl">
+</span>

+ 17 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/feedback-popup.html

@@ -0,0 +1,17 @@
+
+<div class="modal" ng-controller="BpmnFeedbackPopupCtrl">
+    <div class="modal-dialog">
+        <div class="modal-content">
+			<div class="modal-header">
+            	<h2>{{'PROPERTY.FEEDBACK.TITLE' | translate:property}}</h2>
+            </div>
+            <div class="modal-body">
+            	<p><textarea auto-focus class="form-control" ng-model="model.feedback" style="width:90%; height:100%; max-width: 100%; max-height: 100%; min-height: 300px"/></p>
+           	</div>
+           	<div class="modal-footer">
+            	<button ng-click="cancel()" class="btn btn-primary" translate >ACTION.CANCEL</button>
+              	<button ng-click="send()" ng-disabled="model.feedback.length === 0" class="btn btn-primary" translate >ACTION.SEND</button>
+            </div>
+		</div>
+	</div>
+</div>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/fields-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.FIELDS' | translate:property.value.fields}}</span>
+<span ng-if="property.noValue">{{'PROPERTY.FIELDS.EMPTY' | translate}}</span>

+ 58 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/fields-popup.html

@@ -0,0 +1,58 @@
+
+<div class="modal" ng-controller="FlowableFieldsPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+			<div class="modal-header">
+			    <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+			    <h3>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h3>
+			</div>
+			<div class="modal-body">
+
+			    <div class="row row-no-gutter">
+			        <div class="col-xs-6">
+			            <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+			            <div class="pull-right">
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.UP' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.DOWN' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+			                </div>
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.ADD' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewField()"><i class="glyphicon glyphicon-plus"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.REMOVE' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeField()"><i class="glyphicon glyphicon-minus"></i></a>
+			                </div>
+			            </div>
+			        </div>
+
+			        <div class="col-xs-6">
+			             <div ng-show="selectedField">
+
+			                 <div class="form-group">
+			                     <label translate>PROPERTY.FIELDS.NAME</label>
+			                     <input type="text" class="form-control" ng-model="selectedField.name" placeholder="{{'PROPERTY.FIELDS.NAME.PLACEHOLDER' | translate}}" />
+			                 </div>
+			                 <div>
+			                     <label translate>PROPERTY.FIELDS.STRINGVALUE</label>
+			                     <input type="text" class="form-control" ng-model="selectedField.stringValue" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER' | translate}}" />
+			                 </div>
+			                 <div>
+			                     <label translate>PROPERTY.FIELDS.EXPRESSION</label>
+			                     <input type="text" class="form-control" ng-model="selectedField.expression" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER' | translate}}" />
+			                 </div>
+			                 <div>
+			                     <label translate>PROPERTY.FIELDS.STRING</label>
+			                     <textarea type="text" class="form-control" ng-model="selectedField.string" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.STRING.PLACEHOLDER' | translate}}"></textarea>
+			                 </div>
+
+			            </div>
+			            <div ng-show="!selectedField" class="muted no-property-selected" translate>PROPERTY.FIELDS.EMPTY</div>
+			        </div>
+			    </div>
+
+			</div>
+			<div class="modal-footer">
+			    <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+			    <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+			</div>
+		</div>
+	</div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/fields-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableFieldsCtrl">
+</span>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-properties-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.FORMPROPERTIES.VALUE' | translate:property.value.formProperties}}</span>
+<span ng-if="property.noValue" translate>PROPERTY.FORMPROPERTIES.EMPTY</span>

+ 117 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-properties-popup.html

@@ -0,0 +1,117 @@
+
+<div class="modal" ng-controller="FlowableFormPropertiesPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+                <h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h2>
+            </div>
+            <div class="modal-body">
+            
+                <div class="row row-no-gutter">
+                    <div class="col-xs-6">
+                        <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+                        <div class="pull-right">
+                            <div class="btn-group">
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.UP' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="movePropertyUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.DOWN' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="movePropertyDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+                            </div>
+                            <div class="btn-group">
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.ADD' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewProperty()"><i class="glyphicon glyphicon-plus"></i></a>
+                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.REMOVE' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeProperty()"><i class="glyphicon glyphicon-minus"></i></a>
+                            </div>
+                        </div>
+                    </div>
+            
+                    <div class="col-xs-6">
+                        <div ng-show="selectedProperty">
+            
+                            <div class="form-group">
+            			   		<label for="idField">{{'PROPERTY.FORMPROPERTIES.ID' | translate}}</label>
+            			   		<input id="idField" class="form-control" type="text" ng-model="selectedProperty.id" placeholder="{{'PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER' | translate }}" />
+            				</div>
+            				<div class="form-group">
+            			   		<label for="nameField">{{'PROPERTY.FORMPROPERTIES.NAME' | translate}}</label>
+            			   		<input id="nameField" class="form-control" type="text" ng-model="selectedProperty.name" placeholder="{{'PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER' | translate }}" />
+            				</div>
+            				<div class="form-group">
+            			   		<label for="typeField">{{'PROPERTY.FORMPROPERTIES.TYPE' | translate}}</label>
+            			   		<select id="typeField" class="form-control" ng-model="selectedProperty.type" ng-change="propertyTypeChanged()">
+                                    <option>string</option>
+                                    <option>long</option>
+                                    <option>boolean</option>
+                                    <option>date</option>
+                                    <option>enum</option>
+                                </select>
+            				</div>
+                           	<div class="form-group" ng-show="selectedProperty.datePattern">
+            			   		<label for="datePatternField">{{'PROPERTY.FORMPROPERTIES.DATEPATTERN' | translate}}</label>
+            			   		<input id="datePatternField" class="form-control" type="text" ng-model="selectedProperty.datePattern" placeholder="{{'PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER' | translate }}" />
+            				</div>
+                            <div ng-show="selectedProperty.type == 'enum'" style="padding-bottom:10px">
+                                <div class="row row-no-gutter">
+                                    <div class="col-xs-6">
+                                        <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="enumGridOptions" ui-grid-selection ui-grid-auto-resize></div>
+                                        <div class="pull-right">
+                                            <div class="btn-group">
+                                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveEnumValueUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+                                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveEnumValueDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+                                            </div>
+                                            <div class="btn-group">
+                                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewEnumValue()"><i class="glyphicon glyphicon-plus"></i></a>
+                                                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeEnumValue()"><i class="glyphicon glyphicon-minus"></i></a>
+                                            </div>
+                                        </div>
+                                    </div>
+                            
+                                    <div class="col-xs-6">
+                                        <div ng-show="selectedEnumValue">
+                            
+                                            <div class="form-group">
+                                                <label for="classField">{{'PROPERTY.FORMPROPERTIES.VALUES.ID' | translate}}</label>
+                                                <input type="text" id="classField" class="form-control" ng-model="selectedEnumValue.id" placeholder="{{'PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER' | translate}}" />
+                                            </div>
+                                            <div class="form-group">
+                                                <label for="classField">{{'PROPERTY.FORMPROPERTIES.VALUES.NAME' | translate}}</label>
+                                                <input type="text" id="classField" class="form-control" ng-model="selectedEnumValue.name" placeholder="{{'PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER' | translate}}" />
+                                            </div>
+                                        </div>
+                                        <div ng-show="!selectedEnumValue" class="muted no-property-selected" translate>PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY</div>
+                                    </div>
+                                </div>    
+            				</div>
+                            <div class="form-group">
+            			   		<label for="expressionField">{{'PROPERTY.FORMPROPERTIES.EXPRESSION' | translate}}</label>
+            			   		<input id="expressionField" class="form-control" type="text" ng-model="selectedProperty.expression" placeholder="{{'PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER' | translate }}" />
+            				</div>
+            				<div class="form-group">
+            			   		<label for="variableField">{{'PROPERTY.FORMPROPERTIES.VARIABLE' | translate}}</label>
+            			   		<input id="variableField" class="form-control" type="text" ng-model="selectedProperty.variable" placeholder="{{'PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER' | translate }}" />
+            				</div>
+            				<div class="form-inline">
+            					<div class="form-group col-xs-2" >
+            				   		<label for="requiredField">{{'PROPERTY.FORMPROPERTIES.REQUIRED' | translate}}</label>
+            				   		<input id="requiredField" class="checkbox" type="checkbox" ng-model="selectedProperty.required" />
+            				   	</div>
+            				   	<div class="form-group col-xs-2">
+            				   		<label for="readableField">{{'PROPERTY.FORMPROPERTIES.READABLE' | translate}}</label>
+            				   		<input id="readableField" class="checkbox" type="checkbox" ng-model="selectedProperty.readable" />
+            					</div>
+            					<div class="form-group col-xs-2">
+            						<label for="writableField">{{'PROPERTY.FORMPROPERTIES.WRITABLE' | translate}}</label>
+            			   			<input id="writableField" class="checkbox" type="checkbox" ng-model="selectedProperty.writable" />
+            					</div>
+            				</div>
+                        </div>
+                        <div ng-show="!selectedProperty" class="muted no-property-selected" translate>PROPERTY.FORMPROPERTIES.EMPTY</div>
+                    </div>
+                </div>
+            
+            </div>
+            <div class="modal-footer">
+                <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+                <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-properties-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableFormPropertiesCtrl">
+</span>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-reference-display-template.html

@@ -0,0 +1,4 @@
+<div ng-controller="FlowableFormReferenceDisplayCtrl">
+	<span ng-if="property.value && property.value.id">{{form.name}}</span>
+	<span ng-if="!property.value || !property.value.id" translate>PROPERTY.FORMREFERENCE.EMPTY</span>
+</div>

+ 74 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-reference-popup.html

@@ -0,0 +1,74 @@
+
+<div class="modal" ng-controller="FlowableFormReferencePopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+            <div class="modal-header" ng-if="popup.state != 'newForm'">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+                <h2>
+                    {{'PROPERTY.FORMREFERENCE.TITLE' | translate}}
+                    <span ng-show="selectedForm != null"> - {{selectedForm.name}}</span>
+                    <span ng-show="selectedForm == null"> - {{'PROPERTY.FORMREFERENCE.EMPTY' | translate}}</span> 
+                
+                </h2>
+            </div>
+            <div class="modal-header" ng-if="popup.state == 'newForm'"><h2>{{'FORM.POPUP.CREATE-TITLE' | translate}}</h2></div>
+            <div class="modal-body-with-overflow" ng-if="popup.state != 'newForm'">
+                <div class="detail-group clearfix">
+                    <div class="col-xs-12">
+                        <div class="alert alert-error" ng-show="!state.loadingForms && state.formError" translate>PROPERTY.FORMREFERENCE.ERROR.FORM</div>
+                    </div>
+                </div>
+                <div class="detail-group clearfix">
+                    <div class="col-xs-12 editor-item-picker">
+                        <div ng-if="!state.loadingForms && !state.formError" class="col-xs-4 editor-item-picker-component" ng-repeat="form in forms" ng-class="{'selected' : form.formId == selectedForm.formId}" ng-click="selectForm(form, $event)">
+                           <div class="controls">
+                               <input type="checkbox" value="option1" ng-click="selectForm(form, $event)" ng-checked="form.id == selectedForm.id" />
+                           </div>
+                           <h4>{{form.name}}</h4>
+                           <img ng-src="{{config.contextRoot}}/app/rest/models/{{form.id}}/thumbnail" />
+                         </div>
+                         <div ng-show="state.loadingForms">
+                            <p class="loading" translate>PROPERTY.FORMREFERENCE.FORM.LOADING</p>
+                         </div>
+                         <div ng-show="!state.loadingForms && forms.length == 0">
+                            <p translate>PROPERTY.FORMREFERENCE.FORM.EMPTY</p>
+                         </div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-body" ng-if="popup.state == 'newForm'">
+                <p>{{'FORM.POPUP.CREATE-DESCRIPTION' | translate}}</p>
+                <div ng-if="model.errorMessage && model.errorMessage.length > 0" class="alert error" style="font-size: 14px; margin-top:20px">
+                  <div class="popup-error" style="font-size: 14px">
+                    <span class="glyphicon glyphicon-remove-circle"></span>
+                    <span>{{model.errorMessage}}</span>
+                  </div>
+                </div>
+                <div class="form-group">
+                    <label for="newFormName">{{'FORM.NAME' | translate}}</label>
+                    <input ng-disabled="model.loading" type="text" class="form-control"
+                           id="newFormName" ng-model="model.form.name" custom-keys enter-pressed="ok()" auto-focus editor-input-check>
+                </div>
+                <div class="form-group">
+                    <label for="newFormKey">{{'FORM.KEY' | translate}}</label>
+                    <input ng-disabled="model.loading" type="text" class="form-control"
+                           id="newFormKey" ng-model="model.form.key" editor-input-check>
+                </div>
+                <div class="form-group">
+                    <label for="newFormDescription">{{'FORM.DESCRIPTION' | translate}}</label>
+                    <textarea ng-disabled="model.loading" class="form-control" id="newFormDescription" rows="5" ng-model="model.form.description"></textarea>
+                </div>
+            </div>
+            <div class="modal-footer" ng-if="popup.state != 'newForm'">
+            	<button ng-click="cancel()" class="btn btn-primary" translate>GENERAL.ACTION.CANCEL</button>
+            	<button ng-disabled="state.formError" ng-click="newForm()" class="btn btn-primary" translate>GENERAL.ACTION.NEW-FORM</button>
+            	<button ng-disabled="!selectedForm || state.formError" ng-click="open()" class="btn btn-primary" translate>GENERAL.ACTION.OPEN</button>
+                <button ng-disabled="state.formError" ng-click="save()" class="btn btn-primary" translate>GENERAL.ACTION.SAVE</button>
+            </div>
+            <div class="modal-footer" ng-if="popup.state == 'newForm'">
+                <button ng-click="cancel()" class="btn btn-primary" translate>GENERAL.ACTION.CANCEL</button>
+                <button ng-disabled="state.formError || model.form.name.length == 0 || model.form.key.length == 0" ng-click="createForm()" class="btn btn-primary" translate>GENERAL.ACTION.CREATE-FORM</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/form-reference-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableFormReferenceCtrl">
+</span>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/in-parameters-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.INPARAMETERS.VALUE' | translate:property.value.inParameters}}</span>
+<span ng-if="property.noValue" translate>PROPERTY.INPARAMETERS.EMPTY</span>

+ 53 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/in-parameters-popup.html

@@ -0,0 +1,53 @@
+
+<div class="modal" ng-controller="FlowableInParametersPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+			<div class="modal-header">
+			    <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+			    <h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h2>
+			</div>
+			<div class="modal-body">
+			
+			    <div class="row row-no-gutter">
+			        <div class="col-xs-6">
+                        <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+			            <div class="pull-right">
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.UP' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveParameterUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.DOWN' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveParameterDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+			                </div>
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.ADD' | translate:property}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewParameter()"><i class="glyphicon glyphicon-plus"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.REMOVE' | translate:property}}" data-placement="bottom" data-original-title="" title="" ng-click="removeParameter()"><i class="glyphicon glyphicon-minus"></i></a>
+			                </div>
+			            </div>
+			        </div>
+			
+			        <div class="col-xs-6">
+			            <div ng-show="selectedParameter">
+							
+							<div class="form-group">
+						   		<label for="sourceField">{{'PROPERTY.PARAMETER.SOURCE' | translate}}</label>
+						   		<input type="text" id="sourceField" class="form-control" ng-model="selectedParameter.source" placeholder="{{'PROPERTY.PARAMETER.SOURCE.PLACEHOLDER' | translate}}" />
+							</div>
+							<div class="form-group">
+						   		<label for="expressionField">{{'PROPERTY.PARAMETER.SOURCEEXPRESSION' | translate}}</label>
+						   		<input type="text" id="expressionField" class="form-control" ng-model="selectedParameter.sourceExpression" placeholder="{{'PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER' | translate}}" />
+							</div>
+							<div class="form-group">
+						   		<label for="expressionField">{{'PROPERTY.PARAMETER.TARGET' | translate}}</label>
+						   		<input type="text" id="expressionField" class="form-control" ng-model="selectedParameter.target" placeholder="{{'PROPERTY.PARAMETER.TARGET.PLACEHOLDER' | translate}}" />
+							</div>
+			                
+			            </div>
+			            <div ng-show="!selectedParameter" class="muted no-property-selected" translate>PROPERTY.PARAMETER.EMPTY</div>
+			        </div>
+			    </div>
+			</div>
+			<div class="modal-footer">
+			    <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+			    <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+			</div>
+		</div>
+	</div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/in-parameters-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableInParametersCtrl">
+</span>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/message-definitions-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.MESSAGEDEFINITIONS.DISPLAY' | translate:property.value}}</span>
+<span ng-if="property.noValue" translate>PROPERTY.MESSAGEDEFINITIONS.EMPTY</span>

+ 49 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/message-definitions-popup.html

@@ -0,0 +1,49 @@
+<div class="modal" ng-controller="FlowableMessageDefinitionsPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+                <h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h2>
+            </div>
+
+            <div class="modal-body">
+            
+                <div class="row row-no-gutter">
+
+                	<div class="col-xs-8">
+                        <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+            	        <div class="pull-right">
+            	            <div class="btn-group">
+            	                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewMessageDefinition()"><i class="glyphicon glyphicon-plus"></i></a>
+            	                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeMessageDefinition()"><i class="glyphicon glyphicon-minus"></i></a>
+            	            </div>
+            	        </div>
+            		</div>
+
+                    <div class="col-xs-4" ng-show="selectedMessageDefinition">
+
+                        <div class="form-group">
+                            <label>{{'PROPERTY.MESSAGEDEFINITIONS.ID' | translate}}</label>
+                            <input type="text" class="form-control" ng-model="selectedMessageDefinition.id">
+                        </div>
+
+                        <div class="form-group">
+                            <label>{{'PROPERTY.MESSAGEDEFINITIONS.NAME' | translate}}</label>
+                            <input type="text" class="form-control" ng-model="selectedMessageDefinition.name">
+                        </div>
+
+                    </div>
+
+            	</div>
+            	
+            </div>
+
+            <div class="modal-footer">
+                <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+                <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+            </div>
+
+        </div>
+    </div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/message-definitions-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableMessageDefinitionsCtrl">
+</span>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/message-property-write-template.html

@@ -0,0 +1,4 @@
+<div ng-controller="FlowableMessageRefCtrl">
+    <select ng-model="property.value" ng-change="messageChanged()" ng-options="messageDefinition.id as (messageDefinition.name + ' (' + messageDefinition.id + ')') for messageDefinition in messageDefinitions">
+    </select>
+</div>

+ 8 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/multiinstance-property-write-template.html

@@ -0,0 +1,8 @@
+
+<div ng-controller="FlowableMultiInstanceCtrl">
+    <select ng-model="property.value" ng-change="multiInstanceChanged()">
+    	<option>None</option>
+    	<option>Parallel</option>
+    	<option>Sequential</option>
+    </select>
+</div>

+ 7 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/ordering-property-write-template.html

@@ -0,0 +1,7 @@
+
+<div ng-controller="FlowableOrderingCtrl">
+    <select ng-model="property.value" ng-change="orderingChanged()">
+    	<option>Parallel</option>
+    	<option>Sequential</option>
+    </select>
+</div>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/out-parameters-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.OUTPARAMETERS.VALUE' | translate:property.value.outParameters}}</span>
+<span ng-if="property.noValue" translate>PROPERTY.OUTPARAMETERS.EMPTY</span>

+ 53 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/out-parameters-popup.html

@@ -0,0 +1,53 @@
+
+<div class="modal" ng-controller="FlowableOutParametersPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+			<div class="modal-header">
+			    <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+			    <h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h2>
+			</div>
+			<div class="modal-body">
+			
+			    <div class="row row-no-gutter">
+			        <div class="col-xs-6">
+                        <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+			            <div class="pull-right">
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.UP' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveParameterUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.DOWN' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveParameterDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+			                </div>
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.ADD' | translate:property}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewParameter()"><i class="glyphicon glyphicon-plus"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.REMOVE' | translate:property}}" data-placement="bottom" data-original-title="" title="" ng-click="removeParameter()"><i class="glyphicon glyphicon-minus"></i></a>
+			                </div>
+			            </div>
+			        </div>
+			
+			        <div class="col-xs-6">
+			            <div ng-show="selectedParameter">
+							
+							<div class="form-group">
+						   		<label for="sourceField">{{'PROPERTY.PARAMETER.SOURCE' | translate}}</label>
+						   		<input type="text" id="sourceField" class="form-control" ng-model="selectedParameter.source" placeholder="{{'PROPERTY.PARAMETER.SOURCE.PLACEHOLDER' | translate}}" />
+							</div>
+							<div class="form-group">
+						   		<label for="expressionField">{{'PROPERTY.PARAMETER.SOURCEEXPRESSION' | translate}}</label>
+						   		<input type="text" id="expressionField" class="form-control" ng-model="selectedParameter.sourceExpression" placeholder="{{'PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER' | translate}}" />
+							</div>
+							<div class="form-group">
+						   		<label for="expressionField">{{'PROPERTY.PARAMETER.TARGET' | translate}}</label>
+						   		<input type="text" id="expressionField" class="form-control" ng-model="selectedParameter.target" placeholder="{{'PROPERTY.PARAMETER.TARGET.PLACEHOLDER' | translate}}" />
+							</div>
+			                
+			            </div>
+			            <div ng-show="!selectedParameter" class="muted no-property-selected" translate>PROPERTY.PARAMETER.EMPTY</div>
+			        </div>
+			    </div>
+			</div>
+			<div class="modal-footer">
+			    <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+			    <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+			</div>
+		</div>
+	</div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/out-parameters-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableOutParametersCtrl">
+</span>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/sequenceflow-order-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue" translate>PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY</span>
+<span ng-if="property.noValue" translate>PROPERTY.SEQUENCEFLOW.ORDER.EMPTY</span>

+ 47 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/sequenceflow-order-popup.html

@@ -0,0 +1,47 @@
+
+<div class="modal" ng-controller="FlowableSequenceFlowOrderPopupCtrl">
+    <div class="modal-dialog">
+        <div class="modal-content">
+			<div class="modal-header">
+			    <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+			    <h3>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h3>
+			</div>
+			
+			<div class="modal-body">
+			
+			    <div translate>PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION</div>
+			    <br/>
+			    <ol>
+			        <li class="sequence-flow-order-element" ng-repeat="sequenceFlow in outgoingSequenceFlow">
+			            {{'PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE' | translate:sequenceFlow}}
+			            <a class="btn btn-icon btn-sm"
+			               rel="tooltip"
+			               data-title="{{'ACTION.MOVE.UP' | translate}}"
+			               data-placement="bottom"
+			               data-original-title="" title=""
+			               ng-click="moveUp($index)"
+			               ng-if="$index > 0">
+			                 <i class="glyphicon glyphicon-arrow-up"></i>
+			            </a>
+			            <a class="btn btn-icon btn-sm"
+			               rel="tooltip"
+			               data-title="{{'ACTION.MOVE.DOWN' | translate}}"
+			               data-placement="bottom"
+			               data-original-title=""
+			               title=""
+			               ng-click="moveDown($index)"
+			               ng-if="$index < outgoingSequenceFlow.length - 1">
+			                 <i class="glyphicon glyphicon-arrow-down"></i>
+			            </a>
+			        </li>
+			    </ol>
+			
+			
+			</div>
+			<div class="modal-footer">
+			    <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+			    <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+			</div>
+		</div>
+	</div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/sequenceflow-order-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableSequenceFlowOrderCtrl">
+</span>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/signal-definitions-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.SIGNALDEFINITIONS.DISPLAY' | translate:property.value}}</span>
+<span ng-if="property.noValue" translate>PROPERTY.SIGNALDEFINITIONS.EMPTY</span>

+ 56 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/signal-definitions-popup.html

@@ -0,0 +1,56 @@
+<div class="modal" ng-controller="FlowableSignalDefinitionsPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+                <h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h2>
+            </div>
+
+            <div class="modal-body">
+            
+                <div class="row row-no-gutter">
+
+                	<div class="col-xs-8">
+                        <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+            	        <div class="pull-right">
+            	            <div class="btn-group">
+            	                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewSignalDefinition()"><i class="glyphicon glyphicon-plus"></i></a>
+            	                <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeSignalDefinition()"><i class="glyphicon glyphicon-minus"></i></a>
+            	            </div>
+            	        </div>
+            		</div>
+
+                    <div class="col-xs-4" ng-show="selectedSignalDefinition">
+
+                        <div class="form-group">
+                            <label>{{'PROPERTY.SIGNALDEFINITIONS.ID' | translate}}</label>
+                            <input type="text" class="form-control" ng-model="selectedSignalDefinition.id">
+                        </div>
+
+                        <div class="form-group">
+                            <label>{{'PROPERTY.SIGNALDEFINITIONS.NAME' | translate}}</label>
+                            <input type="text" class="form-control" ng-model="selectedSignalDefinition.name">
+                        </div>
+
+                        <div class="form-group">
+                            <label>{{'PROPERTY.SIGNALDEFINITIONS.SCOPE' | translate}}</label>
+                            <select class="form-control" ng-model="selectedSignalDefinition.scope" ng-change="listenerDetailsChanged()"
+                                    ng-options="option.value as option.translationId | translate for option in scopeOptions">
+                            </select>
+                        </div>
+
+                    </div>
+
+            	</div>
+            	
+            </div>
+
+            <div class="modal-footer">
+                <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+                <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+            </div>
+
+        </div>
+    </div>
+</div>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/signal-definitions-write-template.html

@@ -0,0 +1,3 @@
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableSignalDefinitionsCtrl">
+</span>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/signal-property-write-template.html

@@ -0,0 +1,4 @@
+<div ng-controller="FlowableSignalRefCtrl">
+    <select ng-model="property.value" ng-change="signalChanged()" ng-options="signalDefinition.id as (signalDefinition.name + ' (' + signalDefinition.id + ')') for signalDefinition in signalDefinitions">
+    </select>
+</div>

+ 9 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/string-property-write-mode-template.html

@@ -0,0 +1,9 @@
+
+<div ng-controller="FlowableStringPropertyCtrl">
+    <input type="text" ng-model="property.value"
+    	   class="form-control"
+           auto-focus
+           select-text="property.value"
+           ng-blur="inputBlurred()"
+           ng-keypress="enterPressed($event)"/>
+</div>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/subprocess-reference-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="property.value.name">{{property.value.name}}</span>
+<span ng-if="!property.value || !property.value.name" translate>PROPERTY.SUBPROCESSREFERENCE.EMPTY</span>

+ 43 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/subprocess-reference-popup.html

@@ -0,0 +1,43 @@
+
+<div class="modal" ng-controller="FlowableCollapsedSubprocessReferencePopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+			<div class="modal-header">
+			    <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+			    <h2>
+			        {{'PROPERTY.SUBPROCESSREFERENCE.TITLE' | translate}}
+			        <span ng-show="selectedSubProcess != null"> - {{selectedSubProcess.name}}</span>
+			        <span ng-show="selectedSubProcess == null"> - {{'PROPERTY.SUBPROCESSREFERENCE.EMPTY' | translate}}</span> 
+			    
+			    </h2>
+			</div>
+			<div class="modal-body-with-overflow">
+			    <div class="detail-group clearfix">
+                    <div class="col-xs-12">
+			            <div class="alert alert-error" ng-show="(!state.loadingFolders && !state.loadingSubprocesses) && state.subprocessError" translate>PROPERTY.SUBPROCESSREFERENCE.ERROR.SUBPROCESS</div>
+			        </div>
+			    </div>
+			    <div class="detail-group clearfix">
+                    <div class="col-xs-12 editor-item-picker">
+			            <div ng-if="!state.loadingSubprocesses && !state.subprocessError" class="col-xs-4 editor-item-picker-component" ng-repeat="sub in subProcesses" ng-class="{'selected' : sub.id == selectedSubProcess.id}" ng-click="selectSubProcess(sub, $event)">
+			               <div class="controls">
+			                   <input type="checkbox" value="option1" ng-click="selectSubProcess(sub, $event)" ng-checked="sub.id == selectedSubProcess.id" />
+			               </div>
+			               <h4>{{sub.name}}</h4>
+			               <img src="{{config.contextRoot}}/app/rest/models/{{sub.id}}/thumbnail" />
+			             </div>
+			             <div ng-show="state.loadingSubprocesses">
+			               <p class="loading" translate>PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.LOADING</p>
+			             </div>
+			             <div ng-show="!state.loadingSubprocesses && subProcesses.length == 0">
+			                <p translate>PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.EMPTY</p>
+			             </div>
+			        </div>
+			    </div>
+			</div>
+			<div class="modal-footer">
+			    <button ng-disabled="state.subprocessError" ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+			</div>
+		</div>
+	</div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/subprocess-reference-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableCollapsedSubprocessReferenceCtrl">
+</span>

+ 3 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/task-listeners-display-template.html

@@ -0,0 +1,3 @@
+
+<span ng-if="!property.noValue">{{'PROPERTY.TASKLISTENERS.VALUE' | translate:property.value.taskListeners}}</span>
+<span ng-if="property.noValue" translate>PROPERTY.TASKLISTENERS.EMPTY</span>

+ 102 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/task-listeners-popup.html

@@ -0,0 +1,102 @@
+
+<div class="modal" ng-controller="FlowableTaskListenersPopupCtrl">
+    <div class="modal-dialog modal-wide">
+        <div class="modal-content">
+			<div class="modal-header">
+			    <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+			    <h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h2>
+			</div>
+			<div class="modal-body">
+
+			    <div class="row row-no-gutter">
+			        <div class="col-xs-6">
+			            <div ng-if="translationsRetrieved" class="kis-listener-grid" ui-grid="gridOptions" ui-grid-selection></div>
+			            <div class="pull-right">
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+			                </div>
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewListener()"><i class="glyphicon glyphicon-plus"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeListener()"><i class="glyphicon glyphicon-minus"></i></a>
+			                </div>
+			            </div>
+			        </div>
+
+			        <div class="col-xs-6">
+			            <div ng-show="selectedListener">
+
+			                <div class="form-group">
+						   		<label for="eventField">{{'PROPERTY.TASKLISTENERS.EVENT' | translate}}</label>
+						   		<select id="eventField" class="form-control" ng-model="selectedListener.event">
+			                        <option>create</option>
+			                        <option>assignment</option>
+			                        <option>complete</option>
+			                        <option>delete</option>
+			                    </select>
+							</div>
+							<div class="form-group">
+						   		<label for="classField">{{'PROPERTY.TASKLISTENERS.CLASS' | translate}}</label>
+						   		<input type="text" id="classField" class="form-control" ng-model="selectedListener.className" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER' | translate}}" />
+							</div>
+							<div class="form-group">
+						   		<label for="expressionField">{{'PROPERTY.TASKLISTENERS.EXPRESSION' | translate}}</label>
+						   		<input type="text" id="expressionField" class="form-control" ng-model="selectedListener.expression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER' | translate}}" />
+							</div>
+							<div class="form-group">
+						   		<label for="delegateExpressionField">{{'PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION' | translate}}</label>
+						   		<input type="text" id="delegateExpressionField" class="form-control" ng-model="selectedListener.delegateExpression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER' | translate}}" />
+							</div>
+			            </div>
+			            <div ng-show="!selectedListener" class="muted no-property-selected" translate>PROPERTY.TASKLISTENERS.UNSELECTED</div>
+			        </div>
+			    </div>
+
+			    <div class="row row-no-gutter">
+			        <div class="col-xs-6">
+			            <div ng-if="translationsRetrieved" class="kis-field-grid" ui-grid="gridFieldOptions" ui-grid-selection></div>
+			            <div class="pull-right">
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
+			                </div>
+			                <div class="btn-group">
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewField()"><i class="glyphicon glyphicon-plus"></i></a>
+			                    <a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeField()"><i class="glyphicon glyphicon-minus"></i></a>
+			                </div>
+			            </div>
+			        </div>
+
+			        <div class="col-xs-6">
+			            <div ng-show="selectedField">
+
+							<div class="form-group">
+						   		<label for="nameField">{{'PROPERTY.TASKLISTENERS.FIELDS.NAME' | translate}}</label>
+						   		<input type="text" id="nameField" class="form-control" ng-model="selectedField.name" placeholder="{{'PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER' | translate}}" />
+							</div>
+			                <div class="form-group">
+						   		<label for="stringValueField">{{'PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE' | translate}}</label>
+						   		<input type="text" id="stringValueField" class="form-control" ng-model="selectedField.stringValue" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER' | translate}}" />
+							</div>
+							<div class="form-group">
+						   		<label for="expressionField">{{'PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION' | translate}}</label>
+						   		<input type="text" id="expressionField" class="form-control" ng-model="selectedField.expression" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER' | translate}}" />
+							</div>
+							<div class="form-group">
+						   		<label for="stringField">{{'PROPERTY.TASKLISTENERS.FIELDS.STRING' | translate}}</label>
+						   		<textarea id="stringField" class="form-control" ng-model="selectedField.string" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER' | translate}}"></textarea>
+							</div>
+
+			            </div>
+			            <div ng-show="!selectedField" class="muted no-property-selected"translate>PROPERTY.TASKLISTENERS.FIELDS.EMPTY</div>
+			        </div>
+			    </div>
+
+			</div>
+			<div class="modal-footer">
+			    <button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
+			    <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+			</div>
+		</div>
+	</div>
+</div>

+ 4 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/task-listeners-write-template.html

@@ -0,0 +1,4 @@
+
+<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
+<span ng-controller="FlowableTaskListenersCtrl">
+</span>

+ 17 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/text-popup.html

@@ -0,0 +1,17 @@
+
+<div class="modal" ng-controller="FlowableTextPropertyPopupCtrl">
+    <div class="modal-dialog">
+        <div class="modal-content">
+			<div class="modal-header">
+				<button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">&times;</button>
+			    <h3>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate}} "{{property.title | translate}}"</h3>
+			</div>
+			<div class="modal-body">
+				<p><textarea auto-focus class="form-control" ng-model="property.value" style="width:70%; height:100%; max-width: 100%; max-height: 100%; min-height: 200px"/></p>
+			</div>
+			<div class="modal-footer">
+				<button ng-click="save()" class="btn btn-primary" translate >ACTION.SAVE</button>
+			</div>
+		</div>
+	</div>
+</div>

+ 0 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-flowable-modeler/src/main/resources/static/workflow/modeler/editor/editor-app/configuration/properties/text-property-write-template.html


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است