Browse Source

新增工作流前端模块

邵鹏 1 year ago
parent
commit
ccac516f36
100 changed files with 40520 additions and 19085 deletions
  1. 10 0
      .idea/.gitignore
  2. 9 0
      .idea/iTDM-web.iml
  3. 8 0
      .idea/modules.xml
  4. 6 0
      .idea/vcs.xml
  5. 15239 19084
      itdmWeb/package-lock.json
  6. 1 1
      itdmWeb/package.json
  7. BIN
      itdmWeb/public/static/diagram-viewer/images/bg.png
  8. BIN
      itdmWeb/public/static/diagram-viewer/images/breadcrumbs.png
  9. BIN
      itdmWeb/public/static/diagram-viewer/images/checker-bg.png
  10. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/blue/message_catch.png
  11. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/business_rule.png
  12. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/error_catch.png
  13. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/error_throw.png
  14. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/manual.png
  15. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/message_catch.png
  16. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/message_throw.png
  17. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/receive.png
  18. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/script.png
  19. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/send.png
  20. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/service.png
  21. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/signal_catch.png
  22. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/signal_throw.png
  23. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/timer.png
  24. BIN
      itdmWeb/public/static/diagram-viewer/images/deployer/user.png
  25. 129 0
      itdmWeb/public/static/diagram-viewer/index.html
  26. 74 0
      itdmWeb/public/static/diagram-viewer/js/ActivitiRest.js
  27. 194 0
      itdmWeb/public/static/diagram-viewer/js/ActivityImpl.js
  28. 603 0
      itdmWeb/public/static/diagram-viewer/js/Color.js
  29. 270 0
      itdmWeb/public/static/diagram-viewer/js/LineBreakMeasurer.js
  30. 387 0
      itdmWeb/public/static/diagram-viewer/js/Polyline.js
  31. 2172 0
      itdmWeb/public/static/diagram-viewer/js/ProcessDiagramCanvas.js
  32. 1087 0
      itdmWeb/public/static/diagram-viewer/js/ProcessDiagramGenerator.js
  33. 125 0
      itdmWeb/public/static/diagram-viewer/js/jquery/jquery.asyncqueue.js
  34. 9266 0
      itdmWeb/public/static/diagram-viewer/js/jquery/jquery.js
  35. 131 0
      itdmWeb/public/static/diagram-viewer/js/jquery/jquery.progressbar.js
  36. 23 0
      itdmWeb/public/static/diagram-viewer/js/jstools.js
  37. 10 0
      itdmWeb/public/static/diagram-viewer/js/raphael.2.1.1.js
  38. 10 0
      itdmWeb/public/static/diagram-viewer/js/raphael.js
  39. 5815 0
      itdmWeb/public/static/diagram-viewer/js/raphael_uncompressed.js
  40. 441 0
      itdmWeb/public/static/diagram-viewer/js/textlayout.js
  41. 126 0
      itdmWeb/public/static/diagram-viewer/style.css
  42. 37 0
      itdmWeb/public/static/editor-app/app-cfg.js
  43. 431 0
      itdmWeb/public/static/editor-app/app.js
  44. 450 0
      itdmWeb/public/static/editor-app/configuration/properties-assignment-controller.js
  45. 58 0
      itdmWeb/public/static/editor-app/configuration/properties-condition-expression-controller.js
  46. 18 0
      itdmWeb/public/static/editor-app/configuration/properties-custom-controllers.js
  47. 115 0
      itdmWeb/public/static/editor-app/configuration/properties-default-controllers.js
  48. 266 0
      itdmWeb/public/static/editor-app/configuration/properties-event-listeners-controller.js
  49. 326 0
      itdmWeb/public/static/editor-app/configuration/properties-execution-listeners-controller.js
  50. 192 0
      itdmWeb/public/static/editor-app/configuration/properties-fields-controller.js
  51. 276 0
      itdmWeb/public/static/editor-app/configuration/properties-form-properties-controller.js
  52. 158 0
      itdmWeb/public/static/editor-app/configuration/properties-in-parameters-controller.js
  53. 137 0
      itdmWeb/public/static/editor-app/configuration/properties-message-definitions-controller.js
  54. 48 0
      itdmWeb/public/static/editor-app/configuration/properties-message-scope-controller.js
  55. 34 0
      itdmWeb/public/static/editor-app/configuration/properties-multiinstance-controller.js
  56. 158 0
      itdmWeb/public/static/editor-app/configuration/properties-out-parameters-controller.js
  57. 130 0
      itdmWeb/public/static/editor-app/configuration/properties-sequenceflow-order-controller.js
  58. 136 0
      itdmWeb/public/static/editor-app/configuration/properties-signal-definitions-controller.js
  59. 47 0
      itdmWeb/public/static/editor-app/configuration/properties-signal-scope-controller.js
  60. 325 0
      itdmWeb/public/static/editor-app/configuration/properties-task-listeners-controller.js
  61. 99 0
      itdmWeb/public/static/editor-app/configuration/properties.js
  62. 37 0
      itdmWeb/public/static/editor-app/configuration/properties/assignment-candidateGroup.html
  63. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/assignment-display-template.html
  64. 61 0
      itdmWeb/public/static/editor-app/configuration/properties/assignment-popup-popup.html
  65. 111 0
      itdmWeb/public/static/editor-app/configuration/properties/assignment-popup.html
  66. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/assignment-write-template.html
  67. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/boolean-property-template.html
  68. 2 0
      itdmWeb/public/static/editor-app/configuration/properties/condition-expression-display-template.html
  69. 29 0
      itdmWeb/public/static/editor-app/configuration/properties/condition-expression-popup.html
  70. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/condition-expression-write-template.html
  71. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/default-value-display-template.html
  72. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/event-listeners-display-template.html
  73. 115 0
      itdmWeb/public/static/editor-app/configuration/properties/event-listeners-popup.html
  74. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/event-listeners-write-template.html
  75. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/execution-listeners-display-template.html
  76. 101 0
      itdmWeb/public/static/editor-app/configuration/properties/execution-listeners-popup.html
  77. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/execution-listeners-write-template.html
  78. 17 0
      itdmWeb/public/static/editor-app/configuration/properties/feedback-popup.html
  79. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/fields-display-template.html
  80. 61 0
      itdmWeb/public/static/editor-app/configuration/properties/fields-popup.html
  81. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/fields-write-template.html
  82. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/form-properties-display-template.html
  83. 117 0
      itdmWeb/public/static/editor-app/configuration/properties/form-properties-popup.html
  84. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/form-properties-write-template.html
  85. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/in-parameters-display-template.html
  86. 53 0
      itdmWeb/public/static/editor-app/configuration/properties/in-parameters-popup.html
  87. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/in-parameters-write-template.html
  88. 2 0
      itdmWeb/public/static/editor-app/configuration/properties/message-definitions-display-template.html
  89. 50 0
      itdmWeb/public/static/editor-app/configuration/properties/message-definitions-popup.html
  90. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/message-definitions-write-template.html
  91. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/message-property-write-template.html
  92. 8 0
      itdmWeb/public/static/editor-app/configuration/properties/multiinstance-property-write-template.html
  93. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/out-parameters-display-template.html
  94. 53 0
      itdmWeb/public/static/editor-app/configuration/properties/out-parameters-popup.html
  95. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/out-parameters-write-template.html
  96. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/sequenceflow-order-display-template.html
  97. 47 0
      itdmWeb/public/static/editor-app/configuration/properties/sequenceflow-order-popup.html
  98. 4 0
      itdmWeb/public/static/editor-app/configuration/properties/sequenceflow-order-write-template.html
  99. 3 0
      itdmWeb/public/static/editor-app/configuration/properties/signal-definitions-display-template.html
  100. 0 0
      itdmWeb/public/static/editor-app/configuration/properties/signal-definitions-popup.html

+ 10 - 0
.idea/.gitignore

@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Zeppelin ignored files
+/ZeppelinRemoteNotebooks/

+ 9 - 0
.idea/iTDM-web.iml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/iTDM-web.iml" filepath="$PROJECT_DIR$/.idea/iTDM-web.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>

File diff suppressed because it is too large
+ 15239 - 19084
itdmWeb/package-lock.json


+ 1 - 1
itdmWeb/package.json

@@ -52,7 +52,7 @@
   },
   "devDependencies": {
     "sass": "^1.34.1",
-    "sass-loader": "^12.1.0", 
+    "sass-loader": "^12.1.0",
     "@babel/polyfill": "^7.2.5",
     "@vue/cli-plugin-babel": "^3.3.0",
     "@vue/cli-plugin-eslint": "^3.3.0",

BIN
itdmWeb/public/static/diagram-viewer/images/bg.png


BIN
itdmWeb/public/static/diagram-viewer/images/breadcrumbs.png


BIN
itdmWeb/public/static/diagram-viewer/images/checker-bg.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/blue/message_catch.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/business_rule.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/error_catch.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/error_throw.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/manual.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/message_catch.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/message_throw.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/receive.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/script.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/send.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/service.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/signal_catch.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/signal_throw.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/timer.png


BIN
itdmWeb/public/static/diagram-viewer/images/deployer/user.png


+ 129 - 0
itdmWeb/public/static/diagram-viewer/index.html

@@ -0,0 +1,129 @@
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  
+  <link rel="stylesheet" href="style.css" type="text/css" media="screen">
+  <script src="js/jstools.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/raphael.js" type="text/javascript" charset="utf-8"></script>
+  
+  <script src="js/jquery/jquery.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/jquery/jquery.progressbar.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/jquery/jquery.asyncqueue.js" type="text/javascript" charset="utf-8"></script>
+  
+  <script src="js/Color.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/Polyline.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/ActivityImpl.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/ActivitiRest.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/LineBreakMeasurer.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/ProcessDiagramGenerator.js" type="text/javascript" charset="utf-8"></script>
+  <script src="js/ProcessDiagramCanvas.js" type="text/javascript" charset="utf-8"></script>
+  
+  <style type="text/css" media="screen">
+    
+  </style>
+</head>
+<body>
+<div class="wrapper">
+  <div id="pb1"></div>
+  <div id="overlayBox" >
+    <div id="diagramBreadCrumbs" class="diagramBreadCrumbs" onmousedown="return false" onselectstart="return false"></div>
+    <div id="diagramHolder" class="diagramHolder"></div>
+    <div class="diagram-info" id="diagramInfo"></div>
+  </div>
+</div>
+<script language='javascript'>
+var DiagramGenerator = {};
+var pb1;
+$(document).ready(function(){
+  var query_string = {};
+  var query = window.location.search.substring(1);
+  var vars = query.split("&");
+  for (var i=0;i<vars.length;i++) {
+    var pair = vars[i].split("=");
+    query_string[pair[0]] = pair[1];
+  } 
+  
+  var processDefinitionId = query_string["processDefinitionId"];
+  var processInstanceId = query_string["processInstanceId"];
+  
+  console.log("Initialize progress bar");
+  
+  pb1 = new $.ProgressBar({
+    boundingBox: '#pb1',
+    label: 'Progressbar!',
+    on: {
+      complete: function() {
+        console.log("Progress Bar COMPLETE");
+        this.set('label', 'complete!');
+        if (processInstanceId) {
+          ProcessDiagramGenerator.drawHighLights(processInstanceId);
+        }
+      },
+      valueChange: function(e) {
+        this.set('label', e.newVal + '%');
+      }
+    },
+    value: 0
+  });
+  console.log("Progress bar inited");
+  
+  ProcessDiagramGenerator.options = {
+    diagramBreadCrumbsId: "diagramBreadCrumbs",
+    diagramHolderId: "diagramHolder",
+    diagramInfoId: "diagramInfo",
+    on: {
+      click: function(canvas, element, contextObject){
+        var mouseEvent = this;
+        console.log("[CLICK] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
+
+        if (contextObject.getProperty("type") == "callActivity") {
+          var processDefinitonKey = contextObject.getProperty("processDefinitonKey");
+          var processDefinitons = contextObject.getProperty("processDefinitons");
+          var processDefiniton = processDefinitons[0];
+          console.log("Load callActivity '" + processDefiniton.processDefinitionKey + "', contextObject: ", contextObject);
+
+          // Load processDefinition
+        ProcessDiagramGenerator.drawDiagram(processDefiniton.processDefinitionId);
+        }
+      },
+      rightClick: function(canvas, element, contextObject){
+        var mouseEvent = this;
+        console.log("[RIGHTCLICK] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
+      },
+      over: function(canvas, element, contextObject){
+        var mouseEvent = this;
+        //console.log("[OVER] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
+
+        // TODO: show tooltip-window with contextObject info
+        ProcessDiagramGenerator.showActivityInfo(contextObject);
+      },
+      out: function(canvas, element, contextObject){
+        var mouseEvent = this;
+        //console.log("[OUT] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
+
+        ProcessDiagramGenerator.hideInfo();
+      }
+    }
+  };
+  
+  var baseUrl = window.document.location.protocol + "//" + window.document.location.host + "/";
+  var shortenedUrl = window.document.location.href.replace(baseUrl, "");
+  baseUrl = baseUrl + shortenedUrl.substring(0, shortenedUrl.indexOf("/"));
+  ActivitiRest.options = {
+    processInstanceHighLightsUrl: baseUrl + "/service/process-instance/{processInstanceId}/highlights?callback=?",
+    processDefinitionUrl: baseUrl + "/service/process-definition/{processDefinitionId}/diagram-layout?callback=?",
+    processDefinitionByKeyUrl: baseUrl + "/service/process-definition/{processDefinitionKey}/diagram-layout?callback=?"
+  };
+  
+  if (processDefinitionId) {
+    ProcessDiagramGenerator.drawDiagram(processDefinitionId);
+    
+  } else {
+    alert("processDefinitionId parameter is required");
+  }
+});
+
+
+</script>
+</body>
+</html>

+ 74 - 0
itdmWeb/public/static/diagram-viewer/js/ActivitiRest.js

@@ -0,0 +1,74 @@
+var ActivitiRest = {
+	options: {},
+	getProcessDefinitionByKey: function(processDefinitionKey, callback) {
+		var url = Lang.sub(this.options.processDefinitionByKeyUrl, {processDefinitionKey: processDefinitionKey});
+		
+		$.ajax({
+			url: url,
+			dataType: 'jsonp',
+			cache: false,
+			async: true,
+			success: function(data, textStatus) {
+				var processDefinition = data;
+				if (!processDefinition) {
+					console.error("Process definition '" + processDefinitionKey + "' not found");
+				} else {
+				  callback.apply({processDefinitionId: processDefinition.id});
+				}
+			}
+		}).done(function(data, textStatus) {
+			console.log("ajax done");
+		}).fail(function(jqXHR, textStatus, error){
+			console.error('Get diagram layout['+processDefinitionKey+'] failure: ', textStatus, 'error: ', error, jqXHR);
+		});
+	},
+	
+	getProcessDefinition: function(processDefinitionId, callback) {
+		var url = Lang.sub(this.options.processDefinitionUrl, {processDefinitionId: processDefinitionId});
+		
+		$.ajax({
+			url: url,
+			dataType: 'jsonp',
+			cache: false,
+			async: true,
+			success: function(data, textStatus) {
+				var processDefinitionDiagramLayout = data;
+				if (!processDefinitionDiagramLayout) {
+					console.error("Process definition diagram layout '" + processDefinitionId + "' not found");
+					return;
+				} else {
+					callback.apply({processDefinitionDiagramLayout: processDefinitionDiagramLayout});
+				}
+			}
+		}).done(function(data, textStatus) {
+			console.log("ajax done");
+		}).fail(function(jqXHR, textStatus, error){
+			console.log('Get diagram layout['+processDefinitionId+'] failure: ', textStatus, jqXHR);
+		});
+	},
+	
+	getHighLights: function(processInstanceId, callback) {
+		var url = Lang.sub(this.options.processInstanceHighLightsUrl, {processInstanceId: processInstanceId});
+		
+		$.ajax({
+			url: url,
+			dataType: 'jsonp',
+			cache: false,
+			async: true,
+			success: function(data, textStatus) {
+				console.log("ajax returned data");
+				var highLights = data;
+				if (!highLights) {
+					console.log("highLights not found");
+					return;
+				} else {
+					callback.apply({highLights: highLights});
+				}
+			}
+		}).done(function(data, textStatus) {
+			console.log("ajax done");
+		}).fail(function(jqXHR, textStatus, error){
+		  console.log('Get HighLights['+processInstanceId+'] failure: ', textStatus, jqXHR);
+		});
+	}
+};

+ 194 - 0
itdmWeb/public/static/diagram-viewer/js/ActivityImpl.js

@@ -0,0 +1,194 @@
+/**
+ * 
+ * @author Tom Baeyens
+ * @author (Javascript) Dmitry Farafonov
+ */
+ 
+var ActivityImpl = function(activityJson){
+	this.outgoingTransitions = [];
+	this.outgoingTransitions = [];
+	this.incomingTransitions = [];
+	this.activityBehavior = null;
+	this.parent = null;
+	this.isScope = false;
+	this.isAsync = false;
+	this.isExclusive = false;
+	this.x = -1;
+	this.y = -1;
+	this.width = -1;
+	this.height = -1;
+	this.properties = {};
+	
+	//console.log("activityJson: ", activityJson);
+	
+	if (activityJson != undefined) {
+		this.setId(activityJson.activityId);
+				
+		for (var propertyName in activityJson.properties) {
+			this.setProperty(propertyName, activityJson.properties[propertyName]);
+		}
+		//this.setProperty("name", activityJson.activityName);
+		//this.setProperty("type", activityJson.activityType);
+		this.setX(activityJson.x);
+		this.setY(activityJson.y);
+		this.setWidth(activityJson.width);
+		this.setHeight(activityJson.height);
+		
+		if (activityJson.multiInstance)
+			this.setProperty("multiInstance", activityJson.multiInstance);
+		if (activityJson.collapsed) {
+			this.setProperty("collapsed", activityJson.collapsed);
+		}
+		if (activityJson.isInterrupting != undefined)
+			this.setProperty("isInterrupting", activityJson.isInterrupting);
+	}
+};
+
+ActivityImpl.prototype = {
+	outgoingTransitions: [],
+	outgoingTransitions: [],
+	incomingTransitions: [],
+	activityBehavior: null,
+	parent: null,
+	isScope: false,
+	isAsync: false,
+	isExclusive: false,
+	
+	id: null,
+	
+	properties: {},
+	
+	// Graphical information
+	x: -1,
+	y: -1,
+	width: -1,
+	height: -1,
+	
+	setId: function(id){
+		this.id = id;
+	},
+	
+	getId: function(){
+		return this.id;
+	},
+	
+	
+	setProperty: function(name, value){
+		this.properties[name] = value;
+	},
+	getProperty: function(name){
+		return this.properties[name];
+	},
+	
+	createOutgoingTransition: function(transitionId){
+	
+	},
+	
+	toString: function(id) {
+		return "Activity("+id+")";
+	},
+	
+	getParentActivity: function(){
+	/*
+		if (parent instanceof ActivityImpl) {
+79       return (ActivityImpl) parent;
+80     }
+81     return null;
+	*/
+	return this.parent;
+	},
+	
+	// restricted setters ///////////////////////////////////////////////////////
+	
+	setOutgoingTransitions: function(outgoingTransitions){
+		this.outgoingTransitions = outgoingTransitions;
+	},
+	
+	setParent: function(parent){
+		this.parent = parent;
+	},
+	
+	setIncomingTransitions: function(incomingTransitions){
+		this.incomingTransitions = incomingTransitions;
+	},
+	
+	// getters and setters //////////////////////////////////////////////////////
+	
+	getOutgoingTransitions: function(){
+		return this.outgoingTransitions;
+	},
+	
+	getActivityBehavior: function(){
+		return this.activityBehavior;
+	},
+	
+	setActivityBehavior: function(activityBehavior){
+		this.activityBehavior = activityBehavior;
+	},
+	
+	getParent: function(){
+		return this.parent;
+	},
+	
+	getIncomingTransitions: function(){
+		return this.incomingTransitions;
+	},
+	
+	isScope: function(){
+		return this.isScope;
+	},
+	
+	setScope: function(isScope){
+		this.isScope = isScope;
+	},
+	
+	getX: function(){
+		return this.x;
+	},
+	
+	setX: function(x){
+		this.x = x;
+	},
+	
+	getY: function(){
+		return this.y;
+	},
+	
+	setY: function(y){
+		this.y = y;
+	},
+	
+	getWidth: function(){
+		return this.width;
+	},
+	
+	setWidth: function(width){
+		this.width = width;
+	},
+	
+	getHeight: function(){
+		return this.height;
+	},
+	
+	setHeight: function(height){
+		this.height = height;
+	},
+	
+  isAsync: function() {
+    return this.isAsync;
+  },
+  
+  setAsync: function(isAsync) {
+    this.isAsync = isAsync;
+  },
+  
+  isExclusive: function() {
+    return this.isExclusive;
+  },
+    
+  setExclusive: function(isExclusive) {
+    this.isExclusive = isExclusive;
+  },
+	
+	vvoid: function(){}
+};

+ 603 - 0
itdmWeb/public/static/diagram-viewer/js/Color.js

@@ -0,0 +1,603 @@
+/**
+ * Web color table
+ * 
+ * @author Dmitry Farafonov
+ */
+
+var Color = {
+   /**
+   * The color white.  In the default sRGB space.
+   */
+  white     : Raphael.getRGB("rgb(255,255,255)"),
+  
+  /**
+   * The color white.  In the default sRGB space.
+   */
+  WHITE : this.white,
+  
+  /**
+   * The color light gray.  In the default sRGB space.
+   */
+  lightGray : Raphael.getRGB("rgb(192, 192, 192)"),
+  
+  /**
+   * The color light gray.  In the default sRGB space.
+   */
+  LIGHT_GRAY : this.lightGray,
+  
+  /**
+   * The color gray.  In the default sRGB space.
+   */
+  gray : Raphael.getRGB("rgb(128, 128, 128)"),
+  
+  /**
+   * The color gray.  In the default sRGB space.
+   */
+  GRAY : this.gray,
+  
+  /**
+   * The color dark gray.  In the default sRGB space.
+   */
+  darkGray : Raphael.getRGB("rgb(64, 64, 64)"),
+  
+  /**
+   * The color dark gray.  In the default sRGB space.
+   */
+  DARK_GRAY : this.darkGray,
+  
+  /**
+   * The color black.  In the default sRGB space.
+   */
+  black : Raphael.getRGB("rgb(0, 0, 0)"),
+  
+  /**
+   * The color black.  In the default sRGB space.
+   */
+  BLACK : this.black,
+  
+  /**
+   * The color red.  In the default sRGB space.
+   */
+  red : Raphael.getRGB("rgb(255, 0, 0)"),
+  
+  /**
+   * The color red.  In the default sRGB space.
+   */
+  RED : this.red,
+  
+  /**
+   * The color pink.  In the default sRGB space.
+   */
+  pink : Raphael.getRGB("rgb(255, 175, 175)"),
+  
+  /**
+   * The color pink.  In the default sRGB space.
+   */
+  PINK : this.pink,
+  
+  /**
+   * The color orange.  In the default sRGB space.
+   */
+  orange : Raphael.getRGB("rgb(255, 200, 0)"),
+  
+  /**
+   * The color orange.  In the default sRGB space.
+   */
+  ORANGE : this.orange,
+  
+  /**
+   * The color yellow.  In the default sRGB space.
+   */
+  yellow : Raphael.getRGB("rgb(255, 255, 0)"),
+  
+  /**
+   * The color yellow.  In the default sRGB space.
+   */
+  YELLOW : this.yellow,
+  
+  /**
+   * The color green.  In the default sRGB space.
+   */
+  green : Raphael.getRGB("rgb(0, 255, 0)"),
+  
+  /**
+   * The color green.  In the default sRGB space.
+   */
+  GREEN : this.green,
+  
+  /**
+   * The color magenta.  In the default sRGB space.
+   */
+  magenta : Raphael.getRGB("rgb(255, 0, 255)"),
+  
+  /**
+   * The color magenta.  In the default sRGB space.
+   */
+  MAGENTA : this.magenta,
+  
+  /**
+   * The color cyan.  In the default sRGB space.
+   */
+  cyan : Raphael.getRGB("rgb(0, 255, 255)"),
+  
+  /**
+   * The color cyan.  In the default sRGB space.
+   */
+  CYAN : this.cyan,
+  
+  /**
+   * The color blue.  In the default sRGB space.
+   */
+  blue : Raphael.getRGB("rgb(0, 0, 255)"),
+  
+  /**
+   * The color blue.  In the default sRGB space.
+   */
+  BLUE : this.blue,
+  
+  /************************************************************************/
+
+  // http://www.stm.dp.ua/web-design/color-html.php
+  
+	Snow			:   Raphael.getRGB("#FFFAFA	"),  // 	255 250 250
+	GhostWhite		:   Raphael.getRGB("#F8F8FF	"),  // 	248 248 255
+	WhiteSmoke		:   Raphael.getRGB("#F5F5F5	"),  // 	245 245 245
+	Gainsboro		:   Raphael.getRGB("#DCDCDC	"),  // 	220 220 220
+	FloralWhite		:   Raphael.getRGB("#FFFAF0	"),  // 	255 250 240
+	OldLace			:   Raphael.getRGB("#FDF5E6	"),  // 	253 245 230
+	Linen			:   Raphael.getRGB("#FAF0E6	"),  // 	250 240 230
+	AntiqueWhite	:   Raphael.getRGB("#FAEBD7	"),  // 	250 235 215
+	PapayaWhip		:   Raphael.getRGB("#FFEFD5	"),  // 	255 239 213
+	BlanchedAlmond	:   Raphael.getRGB("#FFEBCD	"),  // 	255 235 205
+	Bisque			:   Raphael.getRGB("#FFE4C4	"),  // 	255 228 196
+	PeachPuff		:   Raphael.getRGB("#FFDAB9	"),  // 	255 218 185
+	NavajoWhite		:   Raphael.getRGB("#FFDEAD	"),  // 	255 222 173
+	Moccasin		:   Raphael.getRGB("#FFE4B5	"),  // 	255 228 181
+	Cornsilk		:   Raphael.getRGB("#FFF8DC	"),  // 	255 248 220
+	Ivory			:   Raphael.getRGB("#FFFFF0	"),  // 	255 255 240
+	LemonChiffon	:   Raphael.getRGB("#FFFACD	"),  // 	255 250 205
+	Seashell		:   Raphael.getRGB("#FFF5EE	"),  // 	255 245 238
+	Honeydew		:   Raphael.getRGB("#F0FFF0	"),  // 	240 255 240
+	MintCream		:   Raphael.getRGB("#F5FFFA	"),  // 	245 255 250
+	Azure			:   Raphael.getRGB("#F0FFFF	"),  // 	240 255 255
+	AliceBlue		:   Raphael.getRGB("#F0F8FF	"),  // 	240 248 255
+	lavender		:   Raphael.getRGB("#E6E6FA	"),  // 	230 230 250
+	LavenderBlush	:   Raphael.getRGB("#FFF0F5	"),  // 	255 240 245
+	MistyRose		:   Raphael.getRGB("#FFE4E1	"),  // 	255 228 225
+	White			:   Raphael.getRGB("#FFFFFF	"),  // 	255 255 255
+	Black			:   Raphael.getRGB("#000000	"),  // 	0 0 0
+	DarkSlateGray	:   Raphael.getRGB("#2F4F4F	"),  // 	47 79 79
+	DimGrey			:   Raphael.getRGB("#696969	"),  // 	105 105 105
+	SlateGrey		:   Raphael.getRGB("#708090	"),  // 	112 128 144
+	LightSlateGray	:   Raphael.getRGB("#778899	"),  // 	119 136 153
+	Grey			:   Raphael.getRGB("#BEBEBE	"),  // 	190 190 190
+	LightGray		:   Raphael.getRGB("#D3D3D3	"),  // 	211 211 211
+	MidnightBlue	:   Raphael.getRGB("#191970	"),  // 	25 25 112
+	NavyBlue		:   Raphael.getRGB("#000080	"),  // 	0 0 128
+	CornflowerBlue	:   Raphael.getRGB("#6495ED	"),  // 	100 149 237
+	DarkSlateBlue	:   Raphael.getRGB("#483D8B	"),  // 	72 61 139
+	SlateBlue		:   Raphael.getRGB("#6A5ACD	"),  // 	106 90 205
+	MediumSlateBlue	:   Raphael.getRGB("#7B68EE	"),  // 	123 104 238
+	LightSlateBlue	:   Raphael.getRGB("#8470FF	"),  // 	132 112 255
+	MediumBlue		:   Raphael.getRGB("#0000CD	"),  // 	0 0 205
+	RoyalBlue		:   Raphael.getRGB("#4169E1	"),  // 	65 105 225
+	Blue			:   Raphael.getRGB("#0000FF	"),  // 	0 0 255
+	DodgerBlue		:   Raphael.getRGB("#1E90FF	"),  // 	30 144 255
+	DeepSkyBlue		:   Raphael.getRGB("#00BFFF	"),  // 	0 191 255
+	SkyBlue			:   Raphael.getRGB("#87CEEB	"),  // 	135 206 235
+	LightSkyBlue	:   Raphael.getRGB("#87CEFA	"),  // 	135 206 250
+	SteelBlue		:   Raphael.getRGB("#4682B4	"),  // 	70 130 180
+	LightSteelBlue	:   Raphael.getRGB("#B0C4DE	"),  // 	176 196 222
+	LightBlue		:   Raphael.getRGB("#ADD8E6	"),  // 	173 216 230
+	PowderBlue		:   Raphael.getRGB("#B0E0E6	"),  // 	176 224 230
+	PaleTurquoise	:   Raphael.getRGB("#AFEEEE	"),  // 	175 238 238
+	DarkTurquoise	:   Raphael.getRGB("#00CED1	"),  // 	0 206 209
+	MediumTurquoise	:   Raphael.getRGB("#48D1CC	"),  // 	72 209 204
+	Turquoise		:   Raphael.getRGB("#40E0D0	"),  // 	64 224 208
+	Cyan			:   Raphael.getRGB("#00FFFF	"),  // 	0 255 255
+	LightCyan		:   Raphael.getRGB("#E0FFFF	"),  // 	224 255 255
+	CadetBlue		:   Raphael.getRGB("#5F9EA0	"),  // 	95 158 160
+	MediumAquamarine:   Raphael.getRGB("#66CDAA	"),  // 	102 205 170
+	Aquamarine		:   Raphael.getRGB("#7FFFD4	"),  // 	127 255 212
+	DarkGreen		:   Raphael.getRGB("#006400	"),  // 	0 100 0
+	DarkOliveGreen	:   Raphael.getRGB("#556B2F	"),  // 	85 107 47
+	DarkSeaGreen	:   Raphael.getRGB("#8FBC8F	"),  // 	143 188 143
+	SeaGreen		:   Raphael.getRGB("#2E8B57	"),  // 	46 139 87
+	MediumSeaGreen	:   Raphael.getRGB("#3CB371	"),  // 	60 179 113
+	LightSeaGreen	:   Raphael.getRGB("#20B2AA	"),  // 	32 178 170
+	PaleGreen		:   Raphael.getRGB("#98FB98	"),  // 	152 251 152
+	SpringGreen		:   Raphael.getRGB("#00FF7F	"),  // 	0 255 127
+	LawnGreen		:   Raphael.getRGB("#7CFC00	"),  // 	124 252 0
+	Green			:   Raphael.getRGB("#00FF00	"),  // 	0 255 0
+	Chartreuse		:   Raphael.getRGB("#7FFF00	"),  // 	127 255 0
+	MedSpringGreen	:   Raphael.getRGB("#00FA9A	"),  // 	0 250 154
+	GreenYellow		:   Raphael.getRGB("#ADFF2F	"),  // 	173 255 47
+	LimeGreen		:   Raphael.getRGB("#32CD32	"),  // 	50 205 50
+	YellowGreen		:   Raphael.getRGB("#9ACD32	"),  // 	154 205 50
+	ForestGreen		:   Raphael.getRGB("#228B22	"),  // 	34 139 34
+	OliveDrab		:   Raphael.getRGB("#6B8E23	"),  // 	107 142 35
+	DarkKhaki		:   Raphael.getRGB("#BDB76B	"),  // 	189 183 107
+	PaleGoldenrod	:   Raphael.getRGB("#EEE8AA	"),  // 	238 232 170
+	LtGoldenrodYello:   Raphael.getRGB("#FAFAD2	"),  // 	250 250 210
+	LightYellow		:   Raphael.getRGB("#FFFFE0	"),  // 	255 255 224
+	Yellow			:   Raphael.getRGB("#FFFF00	"),  // 	255 255 0
+	Gold			:   Raphael.getRGB("#FFD700	"),  // 	255 215 0
+	LightGoldenrod	:   Raphael.getRGB("#EEDD82	"),  // 	238 221 130
+	goldenrod		:   Raphael.getRGB("#DAA520	"),  // 	218 165 32
+	DarkGoldenrod	:   Raphael.getRGB("#B8860B	"),  // 	184 134 11
+	RosyBrown		:   Raphael.getRGB("#BC8F8F	"),  // 	188 143 143
+	IndianRed		:   Raphael.getRGB("#CD5C5C	"),  // 	205 92 92
+	SaddleBrown		:   Raphael.getRGB("#8B4513	"),  // 	139 69 19
+	Sienna			:   Raphael.getRGB("#A0522D	"),  // 	160 82 45
+	Peru			:   Raphael.getRGB("#CD853F	"),  // 	205 133 63
+	Burlywood		:   Raphael.getRGB("#DEB887	"),  // 	222 184 135
+	Beige			:   Raphael.getRGB("#F5F5DC	"),  // 	245 245 220
+	Wheat			:   Raphael.getRGB("#F5DEB3	"),  // 	245 222 179
+	SandyBrown		:   Raphael.getRGB("#F4A460	"),  // 	244 164 96
+	Tan				:   Raphael.getRGB("#D2B48C	"),  // 	210 180 140
+	Chocolate		:   Raphael.getRGB("#D2691E	"),  // 	210 105 30
+	Firebrick		:   Raphael.getRGB("#B22222	"),  // 	178 34 34
+	Brown			:   Raphael.getRGB("#A52A2A	"),  // 	165 42 42
+	DarkSalmon		:   Raphael.getRGB("#E9967A	"),  // 	233 150 122
+	Salmon			:   Raphael.getRGB("#FA8072	"),  // 	250 128 114
+	LightSalmon		:   Raphael.getRGB("#FFA07A	"),  // 	255 160 122
+	Orange			:   Raphael.getRGB("#FFA500	"),  // 	255 165 0
+	DarkOrange		:   Raphael.getRGB("#FF8C00	"),  // 	255 140 0
+	Coral			:   Raphael.getRGB("#FF7F50	"),  // 	255 127 80
+	LightCoral		:   Raphael.getRGB("#F08080	"),  // 	240 128 128
+	Tomato			:   Raphael.getRGB("#FF6347	"),  // 	255 99 71
+	OrangeRed		:   Raphael.getRGB("#FF4500	"),  // 	255 69 0
+	Red				:   Raphael.getRGB("#FF0000	"),  // 	255 0 0
+	HotPink			:   Raphael.getRGB("#FF69B4	"),  // 	255 105 180
+	DeepPink		:   Raphael.getRGB("#FF1493	"),  // 	255 20 147
+	Pink			:   Raphael.getRGB("#FFC0CB	"),  // 	255 192 203
+	LightPink		:   Raphael.getRGB("#FFB6C1	"),  // 	255 182 193
+	PaleVioletRed	:   Raphael.getRGB("#DB7093	"),  // 	219 112 147
+	Maroon			:   Raphael.getRGB("#B03060	"),  // 	176 48 96
+	MediumVioletRed	:   Raphael.getRGB("#C71585	"),  // 	199 21 133
+	VioletRed		:   Raphael.getRGB("#D02090	"),  // 	208 32 144
+	Magenta			:   Raphael.getRGB("#FF00FF	"),  // 	255 0 255
+	Violet			:   Raphael.getRGB("#EE82EE	"),  // 	238 130 238
+	Plum			:   Raphael.getRGB("#DDA0DD	"),  // 	221 160 221
+	Orchid			:   Raphael.getRGB("#DA70D6	"),  // 	218 112 214
+	MediumOrchid	:   Raphael.getRGB("#BA55D3	"),  // 	186 85 211
+	DarkOrchid		:   Raphael.getRGB("#9932CC	"),  // 	153 50 204
+	DarkViolet		:   Raphael.getRGB("#9400D3	"),  // 	148 0 211
+	BlueViolet		:   Raphael.getRGB("#8A2BE2	"),  // 	138 43 226
+	Purple			:   Raphael.getRGB("#A020F0	"),  // 	160 32 240
+	MediumPurple	:   Raphael.getRGB("#9370DB	"),  // 	147 112 219
+	Thistle			:   Raphael.getRGB("#D8BFD8	"),  // 	216 191 216
+	Snow1			:   Raphael.getRGB("#FFFAFA	"),  // 	255 250 250
+	Snow2			:   Raphael.getRGB("#EEE9E9	"),  // 	238 233 233
+	Snow3			:   Raphael.getRGB("#CDC9C9	"),  // 	205 201 201
+	Snow4			:   Raphael.getRGB("#8B8989	"),  // 	139 137 137
+	Seashell1		:   Raphael.getRGB("#FFF5EE	"),  // 	255 245 238
+	Seashell2		:   Raphael.getRGB("#EEE5DE	"),  // 	238 229 222
+	Seashell3		:   Raphael.getRGB("#CDC5BF	"),  // 	205 197 191
+	Seashell4		:   Raphael.getRGB("#8B8682	"),  // 	139 134 130
+	AntiqueWhite1	:   Raphael.getRGB("#FFEFDB	"),  // 	255 239 219
+	AntiqueWhite2	:   Raphael.getRGB("#EEDFCC	"),  // 	238 223 204
+	AntiqueWhite3	:   Raphael.getRGB("#CDC0B0	"),  // 	205 192 176
+	AntiqueWhite4	:   Raphael.getRGB("#8B8378	"),  // 	139 131 120
+	Bisque1			:   Raphael.getRGB("#FFE4C4	"),  // 	255 228 196
+	Bisque2			:   Raphael.getRGB("#EED5B7	"),  // 	238 213 183
+	Bisque3			:   Raphael.getRGB("#CDB79E	"),  // 	205 183 158
+	Bisque4			:   Raphael.getRGB("#8B7D6B	"),  // 	139 125 107
+	PeachPuff1		:   Raphael.getRGB("#FFDAB9	"),  // 	255 218 185
+	PeachPuff2		:   Raphael.getRGB("#EECBAD	"),  // 	238 203 173
+	PeachPuff3		:   Raphael.getRGB("#CDAF95	"),  // 	205 175 149
+	PeachPuff4		:   Raphael.getRGB("#8B7765	"),  // 	139 119 101
+	NavajoWhite1	:   Raphael.getRGB("#FFDEAD	"),  // 	255 222 173
+	NavajoWhite2	:   Raphael.getRGB("#EECFA1	"),  // 	238 207 161
+	NavajoWhite3	:   Raphael.getRGB("#CDB38B	"),  // 	205 179 139
+	NavajoWhite4	:   Raphael.getRGB("#8B795E	"),  // 	139 121 94
+	LemonChiffon1	:   Raphael.getRGB("#FFFACD	"),  // 	255 250 205
+	LemonChiffon2	:   Raphael.getRGB("#EEE9BF	"),  // 	238 233 191
+	LemonChiffon3	:   Raphael.getRGB("#CDC9A5	"),  // 	205 201 165
+	LemonChiffon4	:   Raphael.getRGB("#8B8970	"),  // 	139 137 112
+	Cornsilk1		:   Raphael.getRGB("#FFF8DC	"),  // 	255 248 220
+	Cornsilk2		:   Raphael.getRGB("#EEE8CD	"),  // 	238 232 205
+	Cornsilk3		:   Raphael.getRGB("#CDC8B1	"),  // 	205 200 177
+	Cornsilk4		:   Raphael.getRGB("#8B8878	"),  // 	139 136 120
+	Ivory1			:   Raphael.getRGB("#FFFFF0	"),  // 	255 255 240
+	Ivory2			:   Raphael.getRGB("#EEEEE0	"),  // 	238 238 224
+	Ivory3			:   Raphael.getRGB("#CDCDC1	"),  // 	205 205 193
+	Ivory4			:   Raphael.getRGB("#8B8B83	"),  // 	139 139 131
+	Honeydew1		:   Raphael.getRGB("#F0FFF0	"),  // 	240 255 240
+	Honeydew2		:   Raphael.getRGB("#E0EEE0	"),  // 	224 238 224
+	Honeydew3		:   Raphael.getRGB("#C1CDC1	"),  // 	193 205 193
+	Honeydew4		:   Raphael.getRGB("#838B83	"),  // 	131 139 131
+	LavenderBlush1	:   Raphael.getRGB("#FFF0F5	"),  // 	255 240 245
+	LavenderBlush2	:   Raphael.getRGB("#EEE0E5	"),  // 	238 224 229
+	LavenderBlush3	:   Raphael.getRGB("#CDC1C5	"),  // 	205 193 197
+	LavenderBlush4	:   Raphael.getRGB("#8B8386	"),  // 	139 131 134
+	MistyRose1		:   Raphael.getRGB("#FFE4E1	"),  // 	255 228 225
+	MistyRose2		:   Raphael.getRGB("#EED5D2	"),  // 	238 213 210
+	MistyRose3		:   Raphael.getRGB("#CDB7B5	"),  // 	205 183 181
+	MistyRose4		:   Raphael.getRGB("#8B7D7B	"),  // 	139 125 123
+	Azure1			:   Raphael.getRGB("#F0FFFF	"),  // 	240 255 255
+	Azure2			:   Raphael.getRGB("#E0EEEE	"),  // 	224 238 238
+	Azure3			:   Raphael.getRGB("#C1CDCD	"),  // 	193 205 205
+	Azure4			:   Raphael.getRGB("#838B8B	"),  // 	131 139 139
+	SlateBlue1		:   Raphael.getRGB("#836FFF	"),  // 	131 111 255
+	SlateBlue2		:   Raphael.getRGB("#7A67EE	"),  // 	122 103 238
+	SlateBlue3		:   Raphael.getRGB("#6959CD	"),  // 	105 89 205
+	SlateBlue4		:   Raphael.getRGB("#473C8B	"),  // 	71 60 139
+	RoyalBlue1		:   Raphael.getRGB("#4876FF	"),  // 	72 118 255
+	RoyalBlue2		:   Raphael.getRGB("#436EEE	"),  // 	67 110 238
+	RoyalBlue3		:   Raphael.getRGB("#3A5FCD	"),  // 	58 95 205
+	RoyalBlue4		:   Raphael.getRGB("#27408B	"),  // 	39 64 139
+	Blue1			:   Raphael.getRGB("#0000FF	"),  // 	0 0 255
+	Blue2			:   Raphael.getRGB("#0000EE	"),  // 	0 0 238
+	Blue3			:   Raphael.getRGB("#0000CD	"),  // 	0 0 205
+	Blue4			:   Raphael.getRGB("#00008B	"),  // 	0 0 139
+	DodgerBlue1		:   Raphael.getRGB("#1E90FF	"),  // 	30 144 255
+	DodgerBlue2		:   Raphael.getRGB("#1C86EE	"),  // 	28 134 238
+	DodgerBlue3		:   Raphael.getRGB("#1874CD	"),  // 	24 116 205
+	DodgerBlue4		:   Raphael.getRGB("#104E8B	"),  // 	16 78 139
+	SteelBlue1		:   Raphael.getRGB("#63B8FF	"),  // 	99 184 255
+	SteelBlue2		:   Raphael.getRGB("#5CACEE	"),  // 	92 172 238
+	SteelBlue3		:   Raphael.getRGB("#4F94CD	"),  // 	79 148 205
+	SteelBlue4		:   Raphael.getRGB("#36648B	"),  // 	54 100 139
+	DeepSkyBlue1	:   Raphael.getRGB("#00BFFF	"),  // 	0 191 255
+	DeepSkyBlue2	:   Raphael.getRGB("#00B2EE	"),  // 	0 178 238
+	DeepSkyBlue3	:   Raphael.getRGB("#009ACD	"),  // 	0 154 205
+	DeepSkyBlue4	:   Raphael.getRGB("#00688B	"),  // 	0 104 139
+	SkyBlue1		:   Raphael.getRGB("#87CEFF	"),  // 	135 206 255
+	SkyBlue2		:   Raphael.getRGB("#7EC0EE	"),  // 	126 192 238
+	SkyBlue3		:   Raphael.getRGB("#6CA6CD	"),  // 	108 166 205
+	SkyBlue4		:   Raphael.getRGB("#4A708B	"),  // 	74 112 139
+	LightSkyBlue1	:   Raphael.getRGB("#B0E2FF	"),  // 	176 226 255
+	LightSkyBlue2	:   Raphael.getRGB("#A4D3EE	"),  // 	164 211 238
+	LightSkyBlue3	:   Raphael.getRGB("#8DB6CD	"),  // 	141 182 205
+	LightSkyBlue4	:   Raphael.getRGB("#607B8B	"),  // 	96 123 139
+	SlateGray1		:   Raphael.getRGB("#C6E2FF	"),  // 	198 226 255
+	SlateGray2		:   Raphael.getRGB("#B9D3EE	"),  // 	185 211 238
+	SlateGray3		:   Raphael.getRGB("#9FB6CD	"),  // 	159 182 205
+	SlateGray4		:   Raphael.getRGB("#6C7B8B	"),  // 	108 123 139
+	LightSteelBlue1	:   Raphael.getRGB("#CAE1FF	"),  // 	202 225 255
+	LightSteelBlue2	:   Raphael.getRGB("#BCD2EE	"),  // 	188 210 238
+	LightSteelBlue3	:   Raphael.getRGB("#A2B5CD	"),  // 	162 181 205
+	LightSteelBlue4	:   Raphael.getRGB("#6E7B8B	"),  // 	110 123 139
+	LightBlue1		:   Raphael.getRGB("#BFEFFF	"),  // 	191 239 255
+	LightBlue2		:   Raphael.getRGB("#B2DFEE	"),  // 	178 223 238
+	LightBlue3		:   Raphael.getRGB("#9AC0CD	"),  // 	154 192 205
+	LightBlue4		:   Raphael.getRGB("#68838B	"),  // 	104 131 139
+	LightCyan1		:   Raphael.getRGB("#E0FFFF	"),  // 	224 255 255
+	LightCyan2		:   Raphael.getRGB("#D1EEEE	"),  // 	209 238 238
+	LightCyan3		:   Raphael.getRGB("#B4CDCD	"),  // 	180 205 205
+	LightCyan4		:   Raphael.getRGB("#7A8B8B	"),  // 	122 139 139
+	PaleTurquoise1	:   Raphael.getRGB("#BBFFFF	"),  // 	187 255 255
+	PaleTurquoise2	:   Raphael.getRGB("#AEEEEE	"),  // 	174 238 238
+	PaleTurquoise3	:   Raphael.getRGB("#96CDCD	"),  // 	150 205 205
+	PaleTurquoise4	:   Raphael.getRGB("#668B8B	"),  // 	102 139 139
+	CadetBlue1		:   Raphael.getRGB("#98F5FF	"),  // 	152 245 255
+	CadetBlue2		:   Raphael.getRGB("#8EE5EE	"),  // 	142 229 238
+	CadetBlue3		:   Raphael.getRGB("#7AC5CD	"),  // 	122 197 205
+	CadetBlue4		:   Raphael.getRGB("#53868B	"),  // 	83 134 139
+	Turquoise1		:   Raphael.getRGB("#00F5FF	"),  // 	0 245 255
+	Turquoise2		:   Raphael.getRGB("#00E5EE	"),  // 	0 229 238
+	Turquoise3		:   Raphael.getRGB("#00C5CD	"),  // 	0 197 205
+	Turquoise4		:   Raphael.getRGB("#00868B	"),  // 	0 134 139
+	Cyan1			:   Raphael.getRGB("#00FFFF	"),  // 	0 255 255
+	Cyan2			:   Raphael.getRGB("#00EEEE	"),  // 	0 238 238
+	Cyan3			:   Raphael.getRGB("#00CDCD	"),  // 	0 205 205
+	Cyan4			:   Raphael.getRGB("#008B8B	"),  // 	0 139 139
+	DarkSlateGray1	:   Raphael.getRGB("#97FFFF	"),  // 	151 255 255
+	DarkSlateGray2	:   Raphael.getRGB("#8DEEEE	"),  // 	141 238 238
+	DarkSlateGray3	:   Raphael.getRGB("#79CDCD	"),  // 	121 205 205
+	DarkSlateGray4	:   Raphael.getRGB("#528B8B	"),  // 	82 139 139
+	Aquamarine1		:   Raphael.getRGB("#7FFFD4	"),  // 	127 255 212
+	Aquamarine2		:   Raphael.getRGB("#76EEC6	"),  // 	118 238 198
+	Aquamarine3		:   Raphael.getRGB("#66CDAA	"),  // 	102 205 170
+	Aquamarine4		:   Raphael.getRGB("#458B74	"),  // 	69 139 116
+	DarkSeaGreen1	:   Raphael.getRGB("#C1FFC1	"),  // 	193 255 193
+	DarkSeaGreen2	:   Raphael.getRGB("#B4EEB4	"),  // 	180 238 180
+	DarkSeaGreen3	:   Raphael.getRGB("#9BCD9B	"),  // 	155 205 155
+	DarkSeaGreen4	:   Raphael.getRGB("#698B69	"),  // 	105 139 105
+	SeaGreen1		:   Raphael.getRGB("#54FF9F	"),  // 	84 255 159
+	SeaGreen2		:   Raphael.getRGB("#4EEE94	"),  // 	78 238 148
+	SeaGreen3		:   Raphael.getRGB("#43CD80	"),  // 	67 205 128
+	SeaGreen4		:   Raphael.getRGB("#2E8B57	"),  // 	46 139 87
+	PaleGreen1		:   Raphael.getRGB("#9AFF9A	"),  // 	154 255 154
+	PaleGreen2		:   Raphael.getRGB("#90EE90	"),  // 	144 238 144
+	PaleGreen3		:   Raphael.getRGB("#7CCD7C	"),  // 	124 205 124
+	PaleGreen4		:   Raphael.getRGB("#548B54	"),  // 	84 139 84
+	SpringGreen1	:   Raphael.getRGB("#00FF7F	"),  // 	0 255 127
+	SpringGreen2	:   Raphael.getRGB("#00EE76	"),  // 	0 238 118
+	SpringGreen3	:   Raphael.getRGB("#00CD66	"),  // 	0 205 102
+	SpringGreen4	:   Raphael.getRGB("#008B45	"),  // 	0 139 69
+	Green1			:   Raphael.getRGB("#00FF00	"),  // 	0 255 0
+	Green2			:   Raphael.getRGB("#00EE00	"),  // 	0 238 0
+	Green3			:   Raphael.getRGB("#00CD00	"),  // 	0 205 0
+	Green4			:   Raphael.getRGB("#008B00	"),  // 	0 139 0
+	Chartreuse1		:   Raphael.getRGB("#7FFF00	"),  // 	127 255 0
+	Chartreuse2		:   Raphael.getRGB("#76EE00	"),  // 	118 238 0
+	Chartreuse3		:   Raphael.getRGB("#66CD00	"),  // 	102 205 0
+	Chartreuse4		:   Raphael.getRGB("#458B00	"),  // 	69 139 0
+	OliveDrab1		:   Raphael.getRGB("#C0FF3E	"),  // 	192 255 62
+	OliveDrab2		:   Raphael.getRGB("#B3EE3A	"),  // 	179 238 58
+	OliveDrab3		:   Raphael.getRGB("#9ACD32	"),  // 	154 205 50
+	OliveDrab4		:   Raphael.getRGB("#698B22	"),  // 	105 139 34
+	DarkOliveGreen1	:   Raphael.getRGB("#CAFF70	"),  // 	202 255 112
+	DarkOliveGreen2	:   Raphael.getRGB("#BCEE68	"),  // 	188 238 104
+	DarkOliveGreen3	:   Raphael.getRGB("#A2CD5A	"),  // 	162 205 90
+	DarkOliveGreen4	:   Raphael.getRGB("#6E8B3D	"),  // 	110 139 61
+	Khaki1			:   Raphael.getRGB("#FFF68F	"),  // 	255 246 143
+	Khaki2			:   Raphael.getRGB("#EEE685	"),  // 	238 230 133
+	Khaki3			:   Raphael.getRGB("#CDC673	"),  // 	205 198 115
+	Khaki4			:   Raphael.getRGB("#8B864E	"),  // 	139 134 78
+	LightGoldenrod1	:   Raphael.getRGB("#FFEC8B	"),  // 	255 236 139
+	LightGoldenrod2	:   Raphael.getRGB("#EEDC82	"),  // 	238 220 130
+	LightGoldenrod3	:   Raphael.getRGB("#CDBE70	"),  // 	205 190 112
+	LightGoldenrod4	:   Raphael.getRGB("#8B814C	"),  // 	139 129 76
+	LightYellow1	:   Raphael.getRGB("#FFFFE0	"),  // 	255 255 224
+	LightYellow2	:   Raphael.getRGB("#EEEED1	"),  // 	238 238 209
+	LightYellow3	:   Raphael.getRGB("#CDCDB4	"),  // 	205 205 180
+	LightYellow4	:   Raphael.getRGB("#8B8B7A	"),  // 	139 139 122
+	Yellow1			:   Raphael.getRGB("#FFFF00	"),  // 	255 255 0
+	Yellow2			:   Raphael.getRGB("#EEEE00	"),  // 	238 238 0
+	Yellow3			:   Raphael.getRGB("#CDCD00	"),  // 	205 205 0
+	Yellow4			:   Raphael.getRGB("#8B8B00	"),  // 	139 139 0
+	Gold1			:   Raphael.getRGB("#FFD700	"),  // 	255 215 0
+	Gold2			:   Raphael.getRGB("#EEC900	"),  // 	238 201 0
+	Gold3			:   Raphael.getRGB("#CDAD00	"),  // 	205 173 0
+	Gold4			:   Raphael.getRGB("#8B7500	"),  // 	139 117 0
+	Goldenrod1		:   Raphael.getRGB("#FFC125	"),  // 	255 193 37
+	Goldenrod2		:   Raphael.getRGB("#EEB422	"),  // 	238 180 34
+	Goldenrod3		:   Raphael.getRGB("#CD9B1D	"),  // 	205 155 29
+	Goldenrod4		:   Raphael.getRGB("#8B6914	"),  // 	139 105 20
+	DarkGoldenrod1	:   Raphael.getRGB("#FFB90F	"),  // 	255 185 15
+	DarkGoldenrod2	:   Raphael.getRGB("#EEAD0E	"),  // 	238 173 14
+	DarkGoldenrod3	:   Raphael.getRGB("#CD950C	"),  // 	205 149 12
+	DarkGoldenrod4	:   Raphael.getRGB("#8B658B	"),  // 	139 101 8
+	RosyBrown1		:   Raphael.getRGB("#FFC1C1	"),  // 	255 193 193
+	RosyBrown2		:   Raphael.getRGB("#EEB4B4	"),  // 	238 180 180
+	RosyBrown3		:   Raphael.getRGB("#CD9B9B	"),  // 	205 155 155
+	RosyBrown4		:   Raphael.getRGB("#8B6969	"),  // 	139 105 105
+	IndianRed1		:   Raphael.getRGB("#FF6A6A	"),  // 	255 106 106
+	IndianRed2		:   Raphael.getRGB("#EE6363	"),  // 	238 99 99
+	IndianRed3		:   Raphael.getRGB("#CD5555	"),  // 	205 85 85
+	IndianRed4		:   Raphael.getRGB("#8B3A3A	"),  // 	139 58 58
+	Sienna1			:   Raphael.getRGB("#FF8247	"),  // 	255 130 71
+	Sienna2			:   Raphael.getRGB("#EE7942	"),  // 	238 121 66
+	Sienna3			:   Raphael.getRGB("#CD6839	"),  // 	205 104 57
+	Sienna4			:   Raphael.getRGB("#8B4726	"),  // 	139 71 38
+	Burlywood1		:   Raphael.getRGB("#FFD39B	"),  // 	255 211 155
+	Burlywood2		:   Raphael.getRGB("#EEC591	"),  // 	238 197 145
+	Burlywood3		:   Raphael.getRGB("#CDAA7D	"),  // 	205 170 125
+	Burlywood4		:   Raphael.getRGB("#8B7355	"),  // 	139 115 85
+	Wheat1			:   Raphael.getRGB("#FFE7BA	"),  // 	255 231 186
+	Wheat2			:   Raphael.getRGB("#EED8AE	"),  // 	238 216 174
+	Wheat3			:   Raphael.getRGB("#CDBA96	"),  // 	205 186 150
+	Wheat4			:   Raphael.getRGB("#8B7E66	"),  // 	139 126 102
+	Tan1			:   Raphael.getRGB("#FFA54F	"),  // 	255 165 79
+	Tan2			:   Raphael.getRGB("#EE9A49	"),  // 	238 154 73
+	Tan3			:   Raphael.getRGB("#CD853F	"),  // 	205 133 63
+	Tan4			:   Raphael.getRGB("#8B5A2B	"),  // 	139 90 43
+	Chocolate1		:   Raphael.getRGB("#FF7F24	"),  // 	255 127 36
+	Chocolate2		:   Raphael.getRGB("#EE7621	"),  // 	238 118 33
+	Chocolate3		:   Raphael.getRGB("#CD661D	"),  // 	205 102 29
+	Chocolate4		:   Raphael.getRGB("#8B4513	"),  // 	139 69 19
+	Firebrick1		:   Raphael.getRGB("#FF3030	"),  // 	255 48 48
+	Firebrick2		:   Raphael.getRGB("#EE2C2C	"),  // 	238 44 44
+	Firebrick3		:   Raphael.getRGB("#CD2626	"),  // 	205 38 38
+	Firebrick4		:   Raphael.getRGB("#8B1A1A	"),  // 	139 26 26
+	Brown1			:   Raphael.getRGB("#FF4040	"),  // 	255 64 64
+	Brown2			:   Raphael.getRGB("#EE3B3B	"),  // 	238 59 59
+	Brown3			:   Raphael.getRGB("#CD3333	"),  // 	205 51 51
+	Brown4			:   Raphael.getRGB("#8B2323	"),  // 	139 35 35
+	Salmon1			:   Raphael.getRGB("#FF8C69	"),  // 	255 140 105
+	Salmon2			:   Raphael.getRGB("#EE8262	"),  // 	238 130 98
+	Salmon3			:   Raphael.getRGB("#CD7054	"),  // 	205 112 84
+	Salmon4			:   Raphael.getRGB("#8B4C39	"),  // 	139 76 57
+	LightSalmon1	:   Raphael.getRGB("#FFA07A	"),  // 	255 160 122
+	LightSalmon2	:   Raphael.getRGB("#EE9572	"),  // 	238 149 114
+	LightSalmon3	:   Raphael.getRGB("#CD8162	"),  // 	205 129 98
+	LightSalmon4	:   Raphael.getRGB("#8B5742	"),  // 	139 87 66
+	Orange1			:   Raphael.getRGB("#FFA500	"),  // 	255 165 0
+	Orange2			:   Raphael.getRGB("#EE9A00	"),  // 	238 154 0
+	Orange3			:   Raphael.getRGB("#CD8500	"),  // 	205 133 0
+	Orange4			:   Raphael.getRGB("#8B5A00	"),  // 	139 90 0
+	DarkOrange1		:   Raphael.getRGB("#FF7F00	"),  // 	255 127 0
+	DarkOrange2		:   Raphael.getRGB("#EE7600	"),  // 	238 118 0
+	DarkOrange3		:   Raphael.getRGB("#CD6600	"),  // 	205 102 0
+	DarkOrange4		:   Raphael.getRGB("#8B4500	"),  // 	139 69 0
+	Coral1			:   Raphael.getRGB("#FF7256	"),  // 	255 114 86
+	Coral2			:   Raphael.getRGB("#EE6A50	"),  // 	238 106 80
+	Coral3			:   Raphael.getRGB("#CD5B45	"),  // 	205 91 69
+	Coral4			:   Raphael.getRGB("#8B3E2F	"),  // 	139 62 47
+	Tomato1			:   Raphael.getRGB("#FF6347	"),  // 	255 99 71
+	Tomato2			:   Raphael.getRGB("#EE5C42	"),  // 	238 92 66
+	Tomato3			:   Raphael.getRGB("#CD4F39	"),  // 	205 79 57
+	Tomato4			:   Raphael.getRGB("#8B3626	"),  // 	139 54 38
+	OrangeRed1		:   Raphael.getRGB("#FF4500	"),  // 	255 69 0
+	OrangeRed2		:   Raphael.getRGB("#EE4000	"),  // 	238 64 0
+	OrangeRed3		:   Raphael.getRGB("#CD3700	"),  // 	205 55 0
+	OrangeRed4		:   Raphael.getRGB("#8B2500	"),  // 	139 37 0
+	Red1			:   Raphael.getRGB("#FF0000	"),  // 	255 0 0
+	Red2			:   Raphael.getRGB("#EE0000	"),  // 	238 0 0
+	Red3			:   Raphael.getRGB("#CD0000	"),  // 	205 0 0
+	Red4			:   Raphael.getRGB("#8B0000	"),  // 	139 0 0
+	DeepPink1		:   Raphael.getRGB("#FF1493	"),  // 	255 20 147
+	DeepPink2		:   Raphael.getRGB("#EE1289	"),  // 	238 18 137
+	DeepPink3		:   Raphael.getRGB("#CD1076	"),  // 	205 16 118
+	DeepPink4		:   Raphael.getRGB("#8B0A50	"),  // 	139 10 80
+	HotPink1		:   Raphael.getRGB("#FF6EB4	"),  // 	255 110 180
+	HotPink2		:   Raphael.getRGB("#EE6AA7	"),  // 	238 106 167
+	HotPink3		:   Raphael.getRGB("#CD6090	"),  // 	205 96 144
+	HotPink4		:   Raphael.getRGB("#8B3A62	"),  // 	139 58 98
+	Pink1			:   Raphael.getRGB("#FFB5C5	"),  // 	255 181 197
+	Pink2			:   Raphael.getRGB("#EEA9B8	"),  // 	238 169 184
+	Pink3			:   Raphael.getRGB("#CD919E	"),  // 	205 145 158
+	Pink4			:   Raphael.getRGB("#8B636C	"),  // 	139 99 108
+	LightPink1		:   Raphael.getRGB("#FFAEB9	"),  // 	255 174 185
+	LightPink2		:   Raphael.getRGB("#EEA2AD	"),  // 	238 162 173
+	LightPink3		:   Raphael.getRGB("#CD8C95	"),  // 	205 140 149
+	LightPink4		:   Raphael.getRGB("#8B5F65	"),  // 	139 95 101
+	PaleVioletRed1	:   Raphael.getRGB("#FF82AB	"),  // 	255 130 171
+	PaleVioletRed2	:   Raphael.getRGB("#EE799F	"),  // 	238 121 159
+	PaleVioletRed3	:   Raphael.getRGB("#CD6889	"),  // 	205 104 137
+	PaleVioletRed4	:   Raphael.getRGB("#8B475D	"),  // 	139 71 93
+	Maroon1			:   Raphael.getRGB("#FF34B3	"),  // 	255 52 179
+	Maroon2			:   Raphael.getRGB("#EE30A7	"),  // 	238 48 167
+	Maroon3			:   Raphael.getRGB("#CD2990	"),  // 	205 41 144
+	Maroon4			:   Raphael.getRGB("#8B1C62	"),  // 	139 28 98
+	VioletRed1		:   Raphael.getRGB("#FF3E96	"),  // 	255 62 150
+	VioletRed2		:   Raphael.getRGB("#EE3A8C	"),  // 	238 58 140
+	VioletRed3		:   Raphael.getRGB("#CD3278	"),  // 	205 50 120
+	VioletRed4		:   Raphael.getRGB("#8B2252	"),  // 	139 34 82
+	Magenta1		:   Raphael.getRGB("#FF00FF	"),  // 	255 0 255
+	Magenta2		:   Raphael.getRGB("#EE00EE	"),  // 	238 0 238
+	Magenta3		:   Raphael.getRGB("#CD00CD	"),  // 	205 0 205
+	Magenta4		:   Raphael.getRGB("#8B008B	"),  // 	139 0 139
+	Orchid1			:   Raphael.getRGB("#FF83FA	"),  // 	255 131 250
+	Orchid2			:   Raphael.getRGB("#EE7AE9	"),  // 	238 122 233
+	Orchid3			:   Raphael.getRGB("#CD69C9	"),  // 	205 105 201
+	Orchid4			:   Raphael.getRGB("#8B4789	"),  // 	139 71 137
+	Plum1			:   Raphael.getRGB("#FFBBFF	"),  // 	255 187 255
+	Plum2			:   Raphael.getRGB("#EEAEEE	"),  // 	238 174 238
+	Plum3			:   Raphael.getRGB("#CD96CD	"),  // 	205 150 205
+	Plum4			:   Raphael.getRGB("#8B668B	"),  // 	139 102 139
+	MediumOrchid1	:   Raphael.getRGB("#E066FF	"),  // 	224 102 255
+	MediumOrchid2	:   Raphael.getRGB("#D15FEE	"),  // 	209 95 238
+	MediumOrchid3	:   Raphael.getRGB("#B452CD	"),  // 	180 82 205
+	MediumOrchid4	:   Raphael.getRGB("#7A378B	"),  // 	122 55 139
+	DarkOrchid1		:   Raphael.getRGB("#BF3EFF	"),  // 	191 62 255
+	DarkOrchid2		:   Raphael.getRGB("#B23AEE	"),  // 	178 58 238
+	DarkOrchid3		:   Raphael.getRGB("#9A32CD	"),  // 	154 50 205
+	DarkOrchid4		:   Raphael.getRGB("#68228B	"),  // 	104 34 139
+	Purple1			:   Raphael.getRGB("#9B30FF	"),  // 	155 48 255
+	Purple2			:   Raphael.getRGB("#912CEE	"),  // 	145 44 238
+	Purple3			:   Raphael.getRGB("#7D26CD	"),  // 	125 38 205
+	Purple4			:   Raphael.getRGB("#551A8B	"),  // 	85 26 139
+	MediumPurple1	:   Raphael.getRGB("#AB82FF	"),  // 	171 130 255
+	MediumPurple2	:   Raphael.getRGB("#9F79EE	"),  // 	159 121 238
+	MediumPurple3	:   Raphael.getRGB("#8968CD	"),  // 	137 104 205
+	MediumPurple4	:   Raphael.getRGB("#5D478B	"),  // 	93 71 139
+	Thistle1		:   Raphael.getRGB("#FFE1FF	"),  // 	255 225 255
+	Thistle2		:   Raphael.getRGB("#EED2EE	"),  // 	238 210 238
+	Thistle3		:   Raphael.getRGB("#CDB5CD	"),  // 	205 181 205
+	Thistle4		:   Raphael.getRGB("#8B7B8B	"),  // 	139 123 139
+	grey11			:   Raphael.getRGB("#1C1C1C	"),  // 	28 28 28
+	grey21			:   Raphael.getRGB("#363636	"),  // 	54 54 54
+	grey31			:   Raphael.getRGB("#4F4F4F	"),  // 	79 79 79
+	grey41			:   Raphael.getRGB("#696969	"),  // 	105 105 105
+	grey51			:   Raphael.getRGB("#828282	"),  // 	130 130 130
+	grey61			:   Raphael.getRGB("#9C9C9C	"),  // 	156 156 156
+	grey71			:   Raphael.getRGB("#B5B5B5	"),  // 	181 181 181
+	gray81			:   Raphael.getRGB("#CFCFCF	"),  // 	207 207 207
+	gray91			:   Raphael.getRGB("#E8E8E8	"),  // 	232 232 232
+	DarkGrey		:   Raphael.getRGB("#A9A9A9	"),  // 	169 169 169
+	DarkBlue		:   Raphael.getRGB("#00008B	"),  // 	0 0 139
+	DarkCyan		:   Raphael.getRGB("#008B8B	"),  // 	0 139 139
+	DarkMagenta		:   Raphael.getRGB("#8B008B	"),  // 	139 0 139
+	DarkRed			:   Raphael.getRGB("#8B0000	"),  // 	139 0 0
+	LightGreen		:   Raphael.getRGB("#90EE90	"),  // 	144 238 144
+
+  
+  
+  get: function(R, G, B){
+	return Raphael.getRGB("rgb(" + R + ", " + G + ", " + B + ")");
+  }
+};

+ 270 - 0
itdmWeb/public/static/diagram-viewer/js/LineBreakMeasurer.js

@@ -0,0 +1,270 @@
+/**
+ * Word wrapping
+ * 
+ * @author (Javascript) Dmitry Farafonov
+ */
+
+		var AttributedStringIterator = function(text){
+				//this.text = this.rtrim(this.ltrim(text));
+				text = text.replace(/(\s)+/, " ");
+				this.text = this.rtrim(text);
+				/*
+				if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
+					throw new IllegalArgumentException("Invalid substring range");
+				}
+				*/
+				this.beginIndex = 0;
+				this.endIndex = this.text.length;
+				this.currentIndex = this.beginIndex;
+				
+				//console.group("[AttributedStringIterator]");
+				var i = 0;
+				var string = this.text;
+				var fullPos = 0;
+				
+				//console.log("string: \"" + string + "\", length: " + string.length);
+				this.startWordOffsets = [];
+				this.startWordOffsets.push(fullPos);
+				
+				// TODO: remove i 1000
+				while (i<1000) {
+					var pos = string.search(/[ \t\n\f-\.\,]/);
+					if (pos == -1)
+						break;
+					
+					// whitespace start
+					fullPos += pos;
+					string = string.substr(pos);
+					////console.log("fullPos: " + fullPos + ", pos: " + pos +  ", string: ", string);
+					
+					// remove whitespaces
+					var pos = string.search(/[^ \t\n\f-\.\,]/);
+					if (pos == -1)
+						break;
+						
+					// whitespace end
+					fullPos += pos;
+					string = string.substr(pos);
+					
+					////console.log("fullPos: " + fullPos);
+					this.startWordOffsets.push(fullPos);
+					
+					i++;
+				}
+				//console.log("startWordOffsets: ", this.startWordOffsets);
+				//console.groupEnd();
+			};
+			AttributedStringIterator.prototype = {
+				getEndIndex: function(pos){
+					if (typeof(pos) == "undefined")
+						return this.endIndex;
+						
+					var string = this.text.substr(pos, this.endIndex - pos);
+					
+					var posEndOfLine = string.search(/[\n]/);
+					if (posEndOfLine == -1)
+						return this.endIndex;
+					else
+						return pos + posEndOfLine;
+				},
+				getBeginIndex: function(){
+					return this.beginIndex;
+				},
+				isWhitespace: function(pos){
+					var str = this.text[pos];
+					var whitespaceChars = " \t\n\f";
+					
+					return (whitespaceChars.indexOf(str) != -1);
+				},
+				isNewLine: function(pos){
+					var str = this.text[pos];
+					var whitespaceChars = "\n";
+					
+					return (whitespaceChars.indexOf(str) != -1);
+				},
+				preceding: function(pos){
+					//console.group("[AttributedStringIterator.preceding]");
+					for(var i in this.startWordOffsets) {
+						var startWordOffset = this.startWordOffsets[i];
+						if (pos < startWordOffset && i>0) {
+							//console.log("startWordOffset: " + this.startWordOffsets[i-1]);
+							//console.groupEnd();
+							return this.startWordOffsets[i-1];
+						}
+					}
+					//console.log("pos: " + pos);
+					//console.groupEnd();
+					return this.startWordOffsets[i];
+				},
+				following: function(pos){
+					//console.group("[AttributedStringIterator.following]");
+					for(var i in this.startWordOffsets) {
+						var startWordOffset = this.startWordOffsets[i];
+						if (pos < startWordOffset && i>0) {
+							//console.log("startWordOffset: " + this.startWordOffsets[i]);
+							//console.groupEnd();
+							return this.startWordOffsets[i];
+						}
+					}
+					//console.log("pos: " + pos);
+					//console.groupEnd();
+					return this.startWordOffsets[i];
+				},
+				ltrim: function(str){
+					var patt2=/^\s+/g;
+					return str.replace(patt2, "");
+				}, 
+				rtrim: function(str){
+					var patt2=/\s+$/g;
+					return str.replace(patt2, "");
+				},
+				getLayout: function(start, limit){
+					return this.text.substr(start, limit - start);
+				},
+				getCharAtPos: function(pos) {
+					return this.text[pos];
+				}
+			};
+
+		var LineBreakMeasurer = function(paper, x, y, text, fontAttrs){
+				this.paper = paper;
+				this.text = new AttributedStringIterator(text);
+				this.fontAttrs = fontAttrs;
+				
+				if (this.text.getEndIndex() - this.text.getBeginIndex() < 1) {
+					throw {message: "Text must contain at least one character.", code: "IllegalArgumentException"};
+				}
+				
+				//this.measurer = new TextMeasurer(paper, this.text, this.fontAttrs);
+				this.limit = this.text.getEndIndex();
+				this.pos = this.start = this.text.getBeginIndex();
+				
+				this.rafaelTextObject = this.paper.text(x, y, this.text.text).attr(fontAttrs).attr("text-anchor", "start");
+				this.svgTextObject = this.rafaelTextObject[0];
+			};
+			LineBreakMeasurer.prototype = {
+				nextOffset: function(wrappingWidth, offsetLimit, requireNextWord) {
+					//console.group("[nextOffset]");
+					var nextOffset = this.pos;
+					if (this.pos < this.limit) {
+						if (offsetLimit <= this.pos) {
+							throw {message: "offsetLimit must be after current position", code: "IllegalArgumentException"};
+						}
+						
+						var charAtMaxAdvance = this.getLineBreakIndex(this.pos, wrappingWidth);
+						//charAtMaxAdvance --;
+						//console.log("charAtMaxAdvance:", charAtMaxAdvance, ", [" + this.text.getCharAtPos(charAtMaxAdvance) + "]");
+						
+						if (charAtMaxAdvance == this.limit) {
+							nextOffset = this.limit;
+							//console.log("charAtMaxAdvance == this.limit");
+						} else if (this.text.isNewLine(charAtMaxAdvance)) {
+							//console.log("isNewLine");
+							nextOffset = charAtMaxAdvance+1;
+						} else if (this.text.isWhitespace(charAtMaxAdvance)) {
+							// TODO: find next noSpaceChar
+							//return nextOffset;
+							nextOffset = this.text.following(charAtMaxAdvance);
+						} else {
+							// Break is in a word;  back up to previous break.
+							/*
+							var testPos = charAtMaxAdvance + 1;
+							if (testPos == this.limit) {
+								console.error("hbz...");
+							} else {
+								nextOffset = this.text.preceding(charAtMaxAdvance);
+							}
+							*/
+							nextOffset = this.text.preceding(charAtMaxAdvance);
+							
+							if (nextOffset <= this.pos) {
+								nextOffset = Math.max(this.pos+1, charAtMaxAdvance);
+							}
+						}
+					}
+					if (nextOffset > offsetLimit) {
+						nextOffset = offsetLimit;
+					}
+					//console.log("nextOffset: " + nextOffset);
+					//console.groupEnd();
+					return nextOffset;
+				},
+				nextLayout: function(wrappingWidth) {
+					//console.groupCollapsed("[nextLayout]");
+					if (this.pos < this.limit) {
+						var requireNextWord = false;
+						var layoutLimit = this.nextOffset(wrappingWidth, this.limit, requireNextWord);
+						//console.log("layoutLimit:", layoutLimit);
+						if (layoutLimit == this.pos) {
+							//console.groupEnd();
+							return null;
+						}
+						var result = this.text.getLayout(this.pos, layoutLimit);
+						//console.log("layout: \"" + result + "\"");
+						
+						// remove end of line
+						
+						//var posEndOfLine = this.text.getEndIndex(this.pos);
+						//if (posEndOfLine < result.length)
+						//	result = result.substr(0, posEndOfLine);
+						
+						this.pos = layoutLimit;
+						
+						//console.groupEnd();
+						return result;
+					} else {
+						//console.groupEnd();
+						return null;
+					}
+				},
+				getLineBreakIndex: function(pos, wrappingWidth) {
+					//console.group("[getLineBreakIndex]");
+					//console.log("pos:"+pos + ", text: \""+ this.text.text.replace(/\n/g, "_").substr(pos, 1) + "\"");
+					
+					var bb = this.rafaelTextObject.getBBox();
+					
+					var charNum = -1;
+					try {
+						var svgPoint = this.svgTextObject.getStartPositionOfChar(pos);
+						//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.blue});
+						svgPoint.x = svgPoint.x + wrappingWidth;
+						//svgPoint.y = bb.y;
+						//console.log("svgPoint:", svgPoint);
+					
+						//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.red});
+					
+						charNum = this.svgTextObject.getCharNumAtPosition(svgPoint);
+					} catch (e){
+						console.warn("getStartPositionOfChar error, pos:" + pos);
+						/*
+						var testPos = pos + 1;
+						if (testPos < this.limit) {
+							return testPos
+						}
+						*/
+					}
+					//console.log("charNum:", charNum);
+					if (charNum == -1) {
+						//console.groupEnd();
+						return this.text.getEndIndex(pos);
+					} else {
+						// When case there is new line between pos and charnum then use this new line
+						var newLineIndex = this.text.getEndIndex(pos);
+						if (newLineIndex < charNum ) {
+							console.log("newLineIndex <= charNum, newLineIndex:"+newLineIndex+", charNum:"+charNum, "\"" + this.text.text.substr(newLineIndex+1).replace(/\n/g, "?") + "\"");
+							//console.groupEnd();
+							
+							return newLineIndex;
+						}
+							
+						//var charAtMaxAdvance  = this.text.text.substring(charNum, charNum + 1);
+						var charAtMaxAdvance  = this.text.getCharAtPos(charNum);
+						//console.log("!!charAtMaxAdvance: " + charAtMaxAdvance);
+						//console.groupEnd();
+						return charNum;
+					}
+				}, 
+				getPosition: function() {
+					return this.pos;
+				}
+			};

+ 387 - 0
itdmWeb/public/static/diagram-viewer/js/Polyline.js

@@ -0,0 +1,387 @@
+/**
+ * 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) {
+	/* 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 = false;
+	
+	this.init();
+};
+
+Polyline.prototype = {
+	id: null,
+	points: [],
+	path: [],
+	anchors: [],
+	strokeWidth: 1,
+	radius: 15,
+	showDetails: false,
+	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),
+				line2 = this.getLine(i);
+			
+			//this.pushAnchor(ANCHOR_TYPE.middle, line1.x1 + line1.x2-line1.x1, line1.y1 + line1.y2-line1.y1);
+			this.pushAnchor(ANCHOR_TYPE.main,  line1.x2, line1.y2);
+			//this.pushAnchor(ANCHOR_TYPE.middle,  line2.x1 + line2.x2-line2.x1, line2.y1 + line2.y2-line2.y1);
+		}
+		
+		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){
+		return {x1: this.points[i].x, y1: this.points[i].y, x2: this.points[i+1].x, y2: this.points[i+1].y};
+	},
+	getLine: function(i){
+		var line = this._getLine(i);
+		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){
+		var line = this.getLine(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 {
+			// ��������� anchors, �������� ������� ��� �������, ������� � index
+			//var anchor = this.getAnchor()
+			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));
+				//console.log("isDefaultConditionAvailable", this.isDefaultConditionAvailable);
+				
+				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;
+					
+				if (this.showDetails) {
+					var c = ProcessDiagramCanvas.g.path("M"+targetX+","+targetY+"L"+ax+","+ay).attr({stroke: Color.get(255, 153, 51), "stroke-dasharray": "- "});
+					var c = ProcessDiagramCanvas.g.path("M"+nextSrcX+","+nextSrcY+"L"+bx+","+by).attr({stroke: Color.get(255, 153, 51), "stroke-dasharray": "- "});
+					var c = ProcessDiagramCanvas.g.ellipse(ax, ay, 2, 2).attr({stroke: Color.SlateGrey});
+					var c = ProcessDiagramCanvas.g.ellipse(bx, by, 2, 2).attr({stroke: Color.SlateGrey});
+					var c = ProcessDiagramCanvas.g.ellipse(cx, cy, this.radius, this.radius).attr({stroke: Color.Gainsboro});
+					var c = ProcessDiagramCanvas.g.ellipse(targetX, targetY, 2, 2).attr({fill: Color.red});
+					var c = ProcessDiagramCanvas.g.ellipse(nextSrcX, nextSrcY, 2, 2).attr({fill: Color.red});
+				}
+			} 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));
+				//console.log("-- isDefaultConditionAvailable", this.isDefaultConditionAvailable);
+			}
+
+			// 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) {
+			console.log("closePath:", this.closePath);
+			path.push(["Z"]);
+		}
+		
+		this.path = path;
+	},
+	
+	transform: function(transformation){
+		this.element.transform(transformation);
+	},
+	attr: function(attrs){
+		//console.log("attrs: " +attrs, "", this.element);
+		// 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 = [];
+	//console.log("Polygone rebuildPath");
+	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;
+};
+/*
+Polygone.prototype.transform = function(transformation){
+	this.element.transform(transformation);
+};
+*/

File diff suppressed because it is too large
+ 2172 - 0
itdmWeb/public/static/diagram-viewer/js/ProcessDiagramCanvas.js


File diff suppressed because it is too large
+ 1087 - 0
itdmWeb/public/static/diagram-viewer/js/ProcessDiagramGenerator.js


+ 125 - 0
itdmWeb/public/static/diagram-viewer/js/jquery/jquery.asyncqueue.js

@@ -0,0 +1,125 @@
+/*
+* This file is part of the jquery plugin "asyncQueue".
+*
+* (c) Sebastien Roch <roch.sebastien@gmail.com>
+* @author (parallel) Dmitry Farafonov
+*
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
+*/
+(function($){
+    $.AsyncQueue = function() {
+        var that = this,
+            queue = [],
+			completeFunc,
+            failureFunc,
+            paused = false,
+            lastCallbackData,
+            _run,
+			_complete,
+			inQueue = 0,
+			defaultTimeOut = 10;
+
+        _run = function() {
+            var f = queue.shift();
+
+            if (f) {
+				inQueue++;
+				setTimeout(function(){
+					f.fn.apply(that, [that]);
+				
+					if (!f.isParallel)
+						if (paused === false) {
+							_run();
+						}
+					inQueue --;
+					if (inQueue == 0 && queue.length == 0)
+						_complete();
+				}, f.timeOut);                
+				
+				if (f.isParallel)
+					if (paused === false) {
+						_run();
+					}
+            }
+        };
+		
+		_complete = function(){
+			if (completeFunc)
+					completeFunc.apply(that, [that]);
+		};
+
+		this.onComplete = function(func) {
+            completeFunc = func;
+        };
+		
+		this.onFailure = function(func) {
+            failureFunc = func;
+        };
+
+        this.add = function(func) {
+			// TODO: add callback for queue[i] complete
+			
+			var obj = arguments[0];
+			if (obj && Object.prototype.toString.call(obj) === "[object Array]") {
+				var fn = arguments[1];
+				var timeOut = (typeof(arguments[2]) != "undefined")? arguments[2] : defaultTimeOut;
+				if (typeof(fn) == "function") {
+					for(var i = 0; i < obj.length; i++) {
+						var f = function(objx){
+							queue.push({isParallel: true, fn: function(){fn.apply(that, [that, objx]);}, timeOut: timeOut});
+						}(obj[i])
+					}
+				}
+			} else {
+				var fn = arguments[0];
+				var timeOut = (typeof(arguments[1]) != "undefined")? arguments[2] : defaultTimeOut;
+				queue.push({isParallel: false, fn: func, timeOut: timeOut});
+			}
+            return this;
+        };
+		
+		this.addParallel = function(func, timeOut) {
+			// TODO: add callback for queue[i] complete
+			
+            queue.push({isParallel: true, fn: func, timeOut: timeOut});
+            return this;
+        };
+
+        this.storeData = function(dataObject) {
+            lastCallbackData = dataObject;
+            return this;
+        };
+
+        this.lastCallbackData = function () {
+            return lastCallbackData;
+        };
+
+        this.run = function() {
+            paused = false;
+            _run();
+        };
+
+        this.pause = function () {
+            paused = true;
+            return this;
+        };
+
+        this.failure = function() {
+            paused = true;
+            if (failureFunc) {
+                var args = [that];
+                for(i = 0; i < arguments.length; i++) {
+                    args.push(arguments[i]);
+                }
+                failureFunc.apply(that, args);
+            }
+        };
+		
+		this.size = function(){
+			return queue.length;
+		};
+
+        return this;
+    }
+})(jQuery);

File diff suppressed because it is too large
+ 9266 - 0
itdmWeb/public/static/diagram-viewer/js/jquery/jquery.js


+ 131 - 0
itdmWeb/public/static/diagram-viewer/js/jquery/jquery.progressbar.js

@@ -0,0 +1,131 @@
+/*
+ * @ Dmitry Farafonov
+ */
+
+(function($){
+$.ProgressBar = function(options) {
+	this.element = $(options.boundingBox);
+	if (options.on && options.on.complete){
+		this.onComplete = options.on.complete;
+	}
+	if (options.on && options.on.valueChange){
+		this.onValueChange = options.on.valueChange;
+	}
+	
+	this._create();
+	
+	if (options.label)
+		this.set("label", options.label);
+	if (options.value)
+		this.value(options.value);
+	if (options.max)
+		this.set("max", options.max);
+};
+$.ProgressBar.prototype = {
+	options: {
+		value: 0,
+		max: 100
+	},
+
+	min: 0,
+
+	_create: function() {
+		this.element
+			.addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+			.attr({
+				role: "progressbar",
+				"aria-valuemin": this.min,
+				"aria-valuemax": this.options.max,
+				"aria-valuenow": this._value()
+			});
+
+		this.valueDiv = $( "<div class='ui-progressbar-label'></div>" )
+			.appendTo( this.element );
+			
+		this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
+			.appendTo( this.element );
+
+		this.oldValue = this._value();
+		this._refreshValue();
+	},
+
+	_destroy: function() {
+		this.element
+			.removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+			.removeAttr( "role" )
+			.removeAttr( "aria-valuemin" )
+			.removeAttr( "aria-valuemax" )
+			.removeAttr( "aria-valuenow" );
+
+		this.valueDiv.remove();
+	},
+
+	value: function( newValue ) {
+		if ( newValue === undefined ) {
+			return this._value();
+		}
+
+		this._setOption( "value", newValue );
+		return this;
+	},
+
+	_setOption: function( key, value ) {
+		if ( key === "value" ) {
+			//var oldVal = this.options.value;
+			this.options.value = value;
+			this._refreshValue();
+			
+			if (this.onValueChange)
+				this.onValueChange.apply(this, [{oldVal: this.oldValue, newVal: value}]);
+			
+			if ( this._value() === this.options.max ) {
+				//this._trigger( "complete" );
+				if (this.onComplete)
+					this.onComplete.apply(this);
+			}
+		} else if (key === "label") {
+			$(this.element).find(".ui-progressbar-label").html(value);
+		} else if (key === "max") {
+			this.options.max = value;
+		}
+
+		//this._super( key, value );
+	},
+
+	_value: function() {
+		var val = this.options.value;
+		// normalize invalid value
+		if ( typeof val !== "number" ) {
+			val = 0;
+		}
+		return Math.min( this.options.max, Math.max( this.min, val ) );
+	},
+
+	_percentage: function() {
+		return 100 * this._value() / this.options.max;
+	},
+
+	_refreshValue: function() {
+		var value = this.value(),
+			percentage = this._percentage();
+
+		if ( this.oldValue !== value ) {
+			this.oldValue = value;
+			//this._trigger( "change" );
+		}
+
+		this.valueDiv
+			.toggle( value > this.min )
+			.toggleClass( "ui-corner-right", value === this.options.max )
+			.width( percentage.toFixed(0) + "%" );
+		this.element.attr( "aria-valuenow", value );
+		
+		//$(this.element).find(".ui-progressbar-label").html(value + "%");
+	},
+	
+	set: function(key, value){
+		this._setOption(key, value);
+	}
+};
+
+})( jQuery );

+ 23 - 0
itdmWeb/public/static/diagram-viewer/js/jstools.js

@@ -0,0 +1,23 @@
+if (typeof(console) == "undefined") {
+  var console = {
+    info: function(){},
+    warn: function(){},
+    error: function(){},
+    log: function(){},
+    time: function(){},
+    timeEnd: function(){}
+  };
+}
+
+if(!Array.isArray) {
+  Array.isArray = function (vArg) {
+    return Object.prototype.toString.call(vArg) === "[object Array]";
+  };
+}
+
+if (!Object.isSVGElement) {
+  Object.isSVGElement = function(vArg) {
+  var str = Object.prototype.toString.call(vArg);
+  return (str.indexOf("[object SVG") == 0);
+  };
+}

File diff suppressed because it is too large
+ 10 - 0
itdmWeb/public/static/diagram-viewer/js/raphael.2.1.1.js


File diff suppressed because it is too large
+ 10 - 0
itdmWeb/public/static/diagram-viewer/js/raphael.js


File diff suppressed because it is too large
+ 5815 - 0
itdmWeb/public/static/diagram-viewer/js/raphael_uncompressed.js


+ 441 - 0
itdmWeb/public/static/diagram-viewer/js/textlayout.js

@@ -0,0 +1,441 @@
+	window.onload = function () {
+			var paper = Raphael("holder");
+
+			//var curve = paper.ellipse(100, 100, 1, 1).attr({"stroke-width": 0, fill: Color.red});
+			
+			var text = "Betty Botter bought some butter but, she said, the butter's bitter. If I put it in my batter, it will make my batter bitter. But a bit of better butter will make my batter better. So, she bought a bit of butter, better than her bitter butter, and she put it in her batter, and the batter was not bitter. It was better Betty Botter bought a bit better butter.";
+			var font = {font: "11px Arial", "font-style":"italic", opacity: 1, "fill": LABEL_COLOR, stroke: LABEL_COLOR, "stroke-width":.3};
+			var font = {font: "11px Arial", opacity: 1, "fill": LABEL_COLOR};
+			var boxWidth = 100
+			
+			var AttributedStringIterator = function(text){
+				//this.text = this.rtrim(this.ltrim(text));
+				text = text.replace(/(\s)+/, " ");
+				this.text = this.rtrim(text);
+				/*
+				if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
+					throw new IllegalArgumentException("Invalid substring range");
+				}
+				*/
+				this.beginIndex = 0;
+				this.endIndex = this.text.length;
+				this.currentIndex = this.beginIndex;
+				
+				//console.group("[AttributedStringIterator]");
+				var i = 0;
+				var string = this.text;
+				var fullPos = 0;
+				
+				//console.log("string: \"" + string + "\", length: " + string.length);
+				this.startWordOffsets = [];
+				this.startWordOffsets.push(fullPos);
+				
+				// TODO: remove i 1000
+				while (i<1000) {
+					var pos = string.search(/[ \t\n\f-\.\,]/);
+					if (pos == -1)
+						break;
+					
+					// whitespace start
+					fullPos += pos;
+					string = string.substr(pos);
+					////console.log("fullPos: " + fullPos + ", pos: " + pos +  ", string: ", string);
+					
+					// remove whitespaces
+					var pos = string.search(/[^ \t\n\f-\.\,]/);
+					if (pos == -1)
+						break;
+						
+					// whitespace end
+					fullPos += pos;
+					string = string.substr(pos);
+					
+					////console.log("fullPos: " + fullPos);
+					this.startWordOffsets.push(fullPos);
+					
+					i++;
+				}
+				//console.log("startWordOffsets: ", this.startWordOffsets);
+				//console.groupEnd();
+			};
+			AttributedStringIterator.prototype = {
+				getEndIndex: function(pos){
+					if (typeof(pos) == "undefined")
+						return this.endIndex;
+						
+					var string = this.text.substr(pos, this.endIndex - pos);
+					
+					var posEndOfLine = string.search(/[\n]/);
+					if (posEndOfLine == -1)
+						return this.endIndex;
+					else
+						return pos + posEndOfLine;
+				},
+				getBeginIndex: function(){
+					return this.beginIndex;
+				},
+				isWhitespace: function(pos){
+					var str = this.text[pos];
+					var whitespaceChars = " \t\n\f";
+					
+					return (whitespaceChars.indexOf(str) != -1);
+				},
+				isNewLine: function(pos){
+					var str = this.text[pos];
+					var whitespaceChars = "\n";
+					
+					return (whitespaceChars.indexOf(str) != -1);
+				},
+				preceding: function(pos){
+					//console.group("[AttributedStringIterator.preceding]");
+					for(var i in this.startWordOffsets) {
+						var startWordOffset = this.startWordOffsets[i];
+						if (pos < startWordOffset && i>0) {
+							//console.log("startWordOffset: " + this.startWordOffsets[i-1]);
+							//console.groupEnd();
+							return this.startWordOffsets[i-1];
+						}
+					}
+					//console.log("pos: " + pos);
+					//console.groupEnd();
+					return this.startWordOffsets[i];
+				},
+				following: function(pos){
+					//console.group("[AttributedStringIterator.following]");
+					for(var i in this.startWordOffsets) {
+						var startWordOffset = this.startWordOffsets[i];
+						if (pos < startWordOffset && i>0) {
+							//console.log("startWordOffset: " + this.startWordOffsets[i]);
+							//console.groupEnd();
+							return this.startWordOffsets[i];
+						}
+					}
+					//console.log("pos: " + pos);
+					//console.groupEnd();
+					return this.startWordOffsets[i];
+				},
+				ltrim: function(str){
+					var patt2=/^\s+/g;
+					return str.replace(patt2, "");
+				}, 
+				rtrim: function(str){
+					var patt2=/\s+$/g;
+					return str.replace(patt2, "");
+				},
+				getLayout: function(start, limit){
+					return this.text.substr(start, limit - start);
+				},
+				getCharAtPos: function(pos) {
+					return this.text[pos];
+				}
+			};
+			
+			/*
+			var TextMeasurer = function(paper, text, fontAttrs){
+				this.text = text;
+				this.paper = paper;
+				this.fontAttrs = fontAttrs;
+				
+				this.fStart = this.text.getBeginIndex();
+
+			};
+			TextMeasurer.prototype = {
+				getLineBreakIndex: function(start, maxAdvance){
+					var localStart = start - this.fStart;
+				},
+				getLayout: function(){
+				}
+			}
+			*/
+			
+			
+			var LineBreakMeasurer = function(paper, text, fontAttrs){
+				this.paper = paper;
+				this.text = new AttributedStringIterator(text);
+				this.fontAttrs = fontAttrs;
+				
+				if (this.text.getEndIndex() - this.text.getBeginIndex() < 1) {
+					throw {message: "Text must contain at least one character.", code: "IllegalArgumentException"};
+				}
+				
+				//this.measurer = new TextMeasurer(paper, this.text, this.fontAttrs);
+				this.limit = this.text.getEndIndex();
+				this.pos = this.start = this.text.getBeginIndex();
+				
+				this.rafaelTextObject = this.paper.text(100, 100, this.text.text).attr(fontAttrs).attr("text-anchor", "start");
+				this.svgTextObject = this.rafaelTextObject[0];
+			};
+			LineBreakMeasurer.prototype = {
+				nextOffset: function(wrappingWidth, offsetLimit, requireNextWord) {
+					//console.group("[nextOffset]");
+					var nextOffset = this.pos;
+					if (this.pos < this.limit) {
+						if (offsetLimit <= this.pos) {
+							throw {message: "offsetLimit must be after current position", code: "IllegalArgumentException"};
+						}
+						
+						var charAtMaxAdvance = this.getLineBreakIndex(this.pos, wrappingWidth);
+						//charAtMaxAdvance --;
+						//console.log("charAtMaxAdvance:", charAtMaxAdvance, ", [" + this.text.getCharAtPos(charAtMaxAdvance) + "]");
+						
+						if (charAtMaxAdvance == this.limit) {
+							nextOffset = this.limit;
+							//console.log("charAtMaxAdvance == this.limit");
+						} else if (this.text.isNewLine(charAtMaxAdvance)) {
+							console.log("isNewLine");
+							nextOffset = charAtMaxAdvance+1;
+						} else if (this.text.isWhitespace(charAtMaxAdvance)) {
+							// TODO: find next noSpaceChar
+							//return nextOffset;
+							nextOffset = this.text.following(charAtMaxAdvance);
+						} else {
+							// Break is in a word;  back up to previous break.
+							/*
+							var testPos = charAtMaxAdvance + 1;
+							if (testPos == this.limit) {
+								console.error("hbz...");
+							} else {
+								nextOffset = this.text.preceding(charAtMaxAdvance);
+							}
+							*/
+							nextOffset = this.text.preceding(charAtMaxAdvance);
+							
+							if (nextOffset <= this.pos) {
+								nextOffset = Math.max(this.pos+1, charAtMaxAdvance);
+							}
+						}
+					}
+					if (nextOffset > offsetLimit) {
+						nextOffset = offsetLimit;
+					}
+					//console.log("nextOffset: " + nextOffset);
+					//console.groupEnd();
+					return nextOffset;
+				},
+				nextLayout: function(wrappingWidth) {
+					//console.groupCollapsed("[nextLayout]");
+					if (this.pos < this.limit) {
+						var requireNextWord = false;
+						var layoutLimit = this.nextOffset(wrappingWidth, this.limit, requireNextWord);
+						//console.log("layoutLimit:", layoutLimit);
+						if (layoutLimit == this.pos) {
+							//console.groupEnd();
+							return null;
+						}
+						var result = this.text.getLayout(this.pos, layoutLimit);
+						//console.log("layout: \"" + result + "\"");
+						
+						// remove end of line
+						
+						//var posEndOfLine = this.text.getEndIndex(this.pos);
+						//if (posEndOfLine < result.length)
+						//	result = result.substr(0, posEndOfLine);
+						
+						this.pos = layoutLimit;
+						
+						//console.groupEnd();
+						return result;
+					} else {
+						//console.groupEnd();
+						return null;
+					}
+				},
+				getLineBreakIndex: function(pos, wrappingWidth) {
+					//console.group("[getLineBreakIndex]");
+					//console.log("pos:"+pos + ", text: \""+ this.text.text.replace(/\n/g, "_").substr(pos, 1) + "\"");
+					
+					var bb = this.rafaelTextObject.getBBox();
+					
+					var charNum = -1;
+					try {
+						var svgPoint = this.svgTextObject.getStartPositionOfChar(pos);
+						//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.blue});
+						svgPoint.x = svgPoint.x + wrappingWidth;
+						//svgPoint.y = bb.y;
+						//console.log("svgPoint:", svgPoint);
+					
+						//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.red});
+					
+						charNum = this.svgTextObject.getCharNumAtPosition(svgPoint);
+					} catch (e){
+						console.warn("getStartPositionOfChar error, pos:" + pos);
+						/*
+						var testPos = pos + 1;
+						if (testPos < this.limit) {
+							return testPos
+						}
+						*/
+					}
+					//console.log("charNum:", charNum);
+					if (charNum == -1) {
+						//console.groupEnd();
+						return this.text.getEndIndex(pos);
+					} else {
+						// When case there is new line between pos and charnum then use this new line
+						var newLineIndex = this.text.getEndIndex(pos);
+						if (newLineIndex < charNum ) {
+							console.log("newLineIndex <= charNum, newLineIndex:"+newLineIndex+", charNum:"+charNum, "\"" + this.text.text.substr(newLineIndex+1).replace(/\n/g, "↵") + "\"");
+							//console.groupEnd();
+							
+							return newLineIndex;
+						}
+							
+						//var charAtMaxAdvance  = this.text.text.substring(charNum, charNum + 1);
+						var charAtMaxAdvance  = this.text.getCharAtPos(charNum);
+						//console.log("!!charAtMaxAdvance: " + charAtMaxAdvance);
+						//console.groupEnd();
+						return charNum;
+					}
+				}, 
+				getPosition: function() {
+					return this.pos;
+				}
+			};
+			
+			
+			
+			// ******
+			function drawMultilineText(text, x, y, boxWidth, boxHeight, options) {
+				var TEXT_PADDING = 3;
+				var width = boxWidth - (2 * TEXT_PADDING);
+				if (boxHeight)
+					var height = boxHeight - (2 * TEXT_PADDING);
+			
+				var layouts = [];
+				
+				var measurer = new LineBreakMeasurer(paper, text, font);
+				var lineHeight = measurer.rafaelTextObject.getBBox().height;
+				console.log("text: ", text.replace(/\n/g, "↵"));
+				
+				if (height) {
+					var availableLinesCount = parseInt(height/lineHeight);
+					console.log("availableLinesCount: " + availableLinesCount);
+				}
+				
+				var i = 1;
+				while (measurer.getPosition() < measurer.text.getEndIndex()) {
+					var layout = measurer.nextLayout(width);
+					//console.log("LAYOUT: " + layout + ", getPosition: " + measurer.getPosition());
+					
+					if (layout != null) {
+						if (!availableLinesCount || i < availableLinesCount) {
+							layouts.push(layout);
+						} else {
+							layouts.push(fitTextToWidth(layout + "...", boxWidth));
+							break;
+						}
+					}
+					i++;
+				};
+				console.log(layouts);
+				
+				measurer.rafaelTextObject.attr({"text": layouts.join("\n")});
+				//measurer.rafaelTextObject.attr({"text-anchor": "end"});
+				//measurer.rafaelTextObject.attr({"text-anchor": "middle"});
+				if (options)
+					measurer.rafaelTextObject.attr({"text-anchor": options["text-anchor"]});
+					
+				var bb = measurer.rafaelTextObject.getBBox();
+				//measurer.rafaelTextObject.attr({"x": x + boxWidth/2});
+				if (options["vertical-align"] == "top")
+					measurer.rafaelTextObject.attr({"y": y + bb.height/2 + TEXT_PADDING});
+				else
+					measurer.rafaelTextObject.attr({"y": y + height/2});
+				//var bb = measurer.rafaelTextObject.getBBox();
+				
+				if (measurer.rafaelTextObject.attr("text-anchor") == "middle" )
+					measurer.rafaelTextObject.attr("x",  x + boxWidth/2 + TEXT_PADDING/2);
+				else if (measurer.rafaelTextObject.attr("text-anchor") == "end" )
+					measurer.rafaelTextObject.attr("x",  x + boxWidth + TEXT_PADDING/2);
+				else 
+					measurer.rafaelTextObject.attr("x", x + boxWidth/2 - bb.width/2 + TEXT_PADDING/2);
+				
+				var boxStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "};
+				/*
+				var box = paper.rect(x+.0 + boxWidth/2 - bb.width/2+ TEXT_PADDING/2, y + .5 + boxHeight/2 - bb.height/2, width, height).attr(boxStyle);
+				box.attr("height", bb.height);
+				*/
+				//var box = paper.rect(bb.x - .5 + bb.width/2 + TEXT_PADDING, bb.y + bb.height/2, bb.width, bb.height).attr(boxStyle);
+				
+				var textAreaCX = x + boxWidth/2;
+				var textAreaCY = y + height/2;
+				var dotLeftTop = paper.ellipse(x, y, 3, 3).attr({"stroke-width": 0, fill: Color.LightSteelBlue, stroke: "none"});
+				var dotCenter = paper.ellipse(textAreaCX, textAreaCY, 3, 3).attr({fill: Color.LightSteelBlue2, stroke: "none"});
+
+				/*
+				// real bbox
+				var bb = measurer.rafaelTextObject.getBBox();
+				var rect = paper.rect(bb.x+.5, bb.y + .5, bb.width, bb.height).attr({"stroke-width": 1});
+				*/
+				var boxStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "};
+				var rect = paper.rect(x+.5, y + .5, boxWidth, boxHeight).attr(boxStyle);
+			}
+			
+			
+			
+			
+			/*
+			for (var i=0; i<1; i++) {
+				var t = text;
+				//var t = "Высококвалифицирова";
+				
+				var text = paper.text(300, 100, t).attr(font).attr("text-anchor", "start");
+				var bbText = text.getBBox();
+				paper.rect(300+.5, 100 + .5, bbText.width, bbText.height).attr({"stroke-width": 1});
+				console.log("t: ", t.replace(/\n/g, "↵"));
+				
+				while (measurer.getPosition() < measurer.text.getEndIndex()) {
+					var layout = measurer.nextLayout(width);
+					//console.log("LAYOUT: " + layout + ", getPosition: " + measurer.getPosition());
+					if (layout != null)
+						layouts.push(layout);
+				};
+				
+				measurer.rafaelTextObject.attr("text", layouts.join("\n"));
+				var bb = measurer.rafaelTextObject.getBBox();
+				var rect = paper.rect(bb.x+.5, bb.y + .5, bb.width, bb.height).attr({"stroke-width": 1});
+				
+				lay.push(layouts);
+				console.log(layouts);
+			}
+			*/
+			
+			
+			var fitTextToWidth = function(original, width) {
+				var text = original;
+
+				// TODO: move attr on parameters
+				var attr = {font: "11px Arial", opacity: 0};
+				
+				// remove length for "..."
+				var dots = paper.text(0, 0, "...").attr(attr).hide();
+				var dotsBB = dots.getBBox();
+				
+				var maxWidth = width - dotsBB.width;
+				
+				var textElement = paper.text(0, 0, text).attr(attr).hide();
+				var bb = textElement.getBBox();
+				
+				// it's a little bit incorrect with "..."
+				while (bb.width > maxWidth && text.length > 0) {
+					text = text.substring(0, text.length - 1);
+					textElement.attr({"text": text});
+					bb = textElement.getBBox();
+				}
+
+				// remove element from paper
+				textElement.remove();
+				
+				if (text != original) {
+					text = text + "...";
+				}
+
+				return text;
+			}
+			
+			
+			var x=100, y=90, height=20;
+			var options = {"text-anchor": "middle", "boxHeight": 150, "vertical-align": "top"};
+			var options = {"boxHeight": 150, "vertical-align": "top"};
+			drawMultilineText(text, x, y, 150, 100, options);
+	};

+ 126 - 0
itdmWeb/public/static/diagram-viewer/style.css

@@ -0,0 +1,126 @@
+body {
+    background: #fafafa;
+    color: #708090;
+    /* font: 300 100.1% "Helvetica Neue", Helvetica, "Arial Unicode MS", Arial, sans-serif; */
+	font-family: Verdana, sans-serif, Arial;
+	font-size: 10px;
+}
+.wrapper{
+	height: 100%;
+	position: relative;
+	width: 100%;
+}
+/*
+#holder {
+    height: 480px;
+    width: 640px;
+	b_ackground: #F8F8FF;
+	
+	-moz-border-radius: 10px;
+	-webkit-border-radius: 10px;
+	-webkit-box-shadow: 0 1px 3px #666;
+	background: #DDD url(./images/bg.png);
+	/* background: #DDD url(./images/checker-bg.png); * /
+	b_order:0px solid #dedede;
+}
+*/
+div.diagramHolder {
+	float:left; 
+}
+div.diagram{
+	border:1px solid #dedede;
+	margin: 5px;
+	padding: 5px;
+	background: #FFF;
+}
+div.diagram.hidden{
+	display:none;
+}
+svg {
+	background: #DDD url(./images/bg.png);
+}
+
+div.diagram-info {
+	float:left;
+	position: relative;
+	padding: 5px;
+}
+
+/* Breadcrumbs */
+
+#diagramBreadCrumbs {
+	margin-left: 2px;
+	margin-right: 2px;
+	margin-top: 10px;
+}
+#diagramBreadCrumbs ul {
+	list-style: none;
+	
+	background-color: white;
+	border: 1px solid #DEDEDE;
+	border-color: #C0C2C5;
+	margin: 0;
+	
+	margin-bottom: 10px;
+	margin-left: 0;
+	
+	-webkit-padding-start: 0px;
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+}
+#diagramBreadCrumbs li {
+	/*text-decoration: underline;*/
+	display: inline-block;
+	vertical-align: middle;
+	padding-left: .75em;
+	padding-right: 0;
+	cursor: pointer;
+}
+#diagramBreadCrumbs li.selected {
+	color: #9370DB;
+	color: #4876FF;
+	color: #4F94CD;
+	font-weight: bold;
+}
+#diagramBreadCrumbs li span {
+	background: url(images/breadcrumbs.png) no-repeat 100% 50%;
+	display: block;
+	padding: .5em 15px .5em 0;
+}
+
+
+/* Progress bar */
+
+.ui-progressbar { 
+	height: 25px;
+	/*height:2em; text-align: left; overflow: hidden; */
+	background: white;
+	border: 1px solid #949DAD;
+	margin: 2px;
+	overflow: hidden;
+	padding: 1px;
+	position: relative;
+
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+}
+.ui-progressbar .ui-progressbar-value {
+	m_argin: -1px;
+	height:100%;
+	background: #D4E4FF;
+	
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+}
+.ui-widget-header a { color: #222222/*{fcHeader}*/; }
+
+.ui-progressbar .ui-progressbar-label{
+	position: absolute;
+	margin-top: 7px;
+	border:0px solid red;
+	width: 100%;
+	text-align: center;
+}

+ 37 - 0
itdmWeb/public/static/editor-app/app-cfg.js

@@ -0,0 +1,37 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+'use strict';
+
+
+var ACTIVITI = ACTIVITI || {};
+ 
+ACTIVITI.CONFIG = {
+ 
+	'contextRoot' :window.parent.getMyVue.apiUrl+'/service',
+  'baseUrl':window.parent.getMyVue.apiUrl
+};
+
+
+function getWebRootPath() {
+	let webRoot = document.location.href;
+	webRoot = webRoot.substring(webRoot.indexOf('//') + 2, webRoot.length);
+	webRoot = webRoot.substring(webRoot.indexOf('/') + 1, webRoot.length);
+	webRoot = webRoot.substring(0, webRoot.indexOf('/'));
+	return "/" + webRoot + "/";
+}

+ 431 - 0
itdmWeb/public/static/editor-app/app.js

@@ -0,0 +1,431 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+'use strict';
+
+var activitiModeler = angular.module('activitiModeler', [
+    'ngCookies',
+    'ngResource',
+    'ngSanitize',
+    'ngRoute',
+    'ngDragDrop',
+    'mgcrea.ngStrap',
+    'ngGrid',
+    'ngAnimate',
+    'pascalprecht.translate',
+    'duScroll',
+    'tm.pagination'
+]);
+
+var activitiModule = activitiModeler;
+
+activitiModeler
+// Initialize routes
+    .config(['$selectProvider', '$translateProvider', function ($selectProvider, $translateProvider) {
+
+        // Override caret for bs-select directive
+        angular.extend($selectProvider.defaults, {
+            caretHtml: '&nbsp;<i class="icon icon-caret-down"></i>'
+        });
+
+        // Initialize angular-translate
+        $translateProvider.useStaticFilesLoader({
+            prefix: './editor-app/i18n/',
+            suffix: '.json'
+        });
+
+        $translateProvider.preferredLanguage('en');
+
+        // remember language
+        $translateProvider.useCookieStorage();
+
+    }])
+    .run(['$rootScope', '$timeout', '$modal', '$translate', '$location', '$window', '$http', '$q',
+        function ($rootScope, $timeout, $modal, $translate, $location, $window, $http, $q) {
+
+            $rootScope.config = ACTIVITI.CONFIG;
+
+            $rootScope.editorInitialized = false;
+
+            $rootScope.editorFactory = $q.defer();
+
+            $rootScope.forceSelectionRefresh = false;
+
+            $rootScope.ignoreChanges = false; // by default never ignore changes
+
+            $rootScope.validationErrors = [];
+
+            $rootScope.staticIncludeVersion = Date.now();
+
+            /**
+             * A 'safer' apply that avoids concurrent updates (which $apply allows).
+             */
+            $rootScope.safeApply = function (fn) {
+                var phase = this.$root.$$phase;
+                if (phase == '$apply' || phase == '$digest') {
+                    if (fn && (typeof(fn) === 'function')) {
+                        fn();
+                    }
+                } else {
+                    this.$apply(fn);
+                }
+            };
+
+
+            /**
+             * Initialize the event bus: couple all Oryx events with a dispatch of the
+             * event of the event bus. This way, it gets much easier to attach custom logic
+             * to any event.
+             */
+
+            /* Helper method to fetch model from server (always needed) */
+            function fetchModel(modelId) {
+
+                var modelUrl = KISBPM.URL.getModel(modelId);
+
+                $http({method: 'GET', url: modelUrl}).success(function (data, status, headers, config) {
+                    $rootScope.editor = new ORYX.Editor(data);
+                    $rootScope.modelData = angular.fromJson(data);
+                    $rootScope.editorFactory.resolve();
+                }).error(function (data, status, headers, config) {
+                    console.log('Error loading model with id ' + modelId + ' ' + data);
+                });
+            }
+
+
+            function initScrollHandling() {
+                var canvasSection = jQuery('#canvasSection');
+                canvasSection.scroll(function () {
+
+                    // Hides the resizer and quick menu items during scrolling
+
+                    var selectedElements = $rootScope.editor.selection;
+                    var subSelectionElements = $rootScope.editor._subSelection;
+
+                    $rootScope.selectedElements = selectedElements;
+                    $rootScope.subSelectionElements = subSelectionElements;
+                    if (selectedElements && selectedElements.length > 0) {
+                        $rootScope.selectedElementBeforeScrolling = selectedElements[0];
+                    }
+
+                    jQuery('.Oryx_button').each(function (i, obj) {
+                        $rootScope.orginalOryxButtonStyle = obj.style.display;
+                        obj.style.display = 'none';
+                    });
+
+                    jQuery('.resizer_southeast').each(function (i, obj) {
+                        $rootScope.orginalResizerSEStyle = obj.style.display;
+                        obj.style.display = 'none';
+                    });
+                    jQuery('.resizer_northwest').each(function (i, obj) {
+                        $rootScope.orginalResizerNWStyle = obj.style.display;
+                        obj.style.display = 'none';
+                    });
+                    $rootScope.editor.handleEvents({type: ORYX.CONFIG.EVENT_CANVAS_SCROLL});
+                });
+
+                canvasSection.scrollStopped(function () {
+
+                    // Puts the quick menu items and resizer back when scroll is stopped.
+
+                    $rootScope.editor.setSelection([]); // needed cause it checks for element changes and does nothing if the elements are the same
+                    $rootScope.editor.setSelection($rootScope.selectedElements, $rootScope.subSelectionElements);
+                    $rootScope.selectedElements = undefined;
+                    $rootScope.subSelectionElements = undefined;
+
+                    function handleDisplayProperty(obj) {
+                        if (jQuery(obj).position().top > 0) {
+                            obj.style.display = 'block';
+                        } else {
+                            obj.style.display = 'none';
+                        }
+                    }
+
+                    jQuery('.Oryx_button').each(function (i, obj) {
+                        handleDisplayProperty(obj);
+                    });
+
+                    jQuery('.resizer_southeast').each(function (i, obj) {
+                        handleDisplayProperty(obj);
+                    });
+                    jQuery('.resizer_northwest').each(function (i, obj) {
+                        handleDisplayProperty(obj);
+                    });
+
+                });
+            }
+
+            /**
+             * Initialize the Oryx Editor when the content has been loaded
+             */
+            $rootScope.$on('$includeContentLoaded', function (event) {
+                if (!$rootScope.editorInitialized) {
+
+                    ORYX._loadPlugins();
+
+                    var modelId = EDITOR.UTIL.getParameterByName('modelId');
+                    fetchModel(modelId);
+
+                    $rootScope.window = {};
+                    var updateWindowSize = function () {
+                        $rootScope.window.width = $window.innerWidth;
+                        $rootScope.window.height = $window.innerHeight;
+                    };
+
+                    // Window resize hook
+                    angular.element($window).bind('resize', function () {
+                        $rootScope.safeApply(updateWindowSize());
+                    });
+
+                    $rootScope.$watch('window.forceRefresh', function (newValue) {
+                        if (newValue) {
+                            $timeout(function () {
+                                updateWindowSize();
+                                $rootScope.window.forceRefresh = false;
+                            });
+                        }
+                    });
+
+                    updateWindowSize();
+
+                    // Hook in resizing of main panels when window resizes
+                    // TODO: perhaps move to a separate JS-file?
+                    jQuery(window).resize(function () {
+
+                        // Calculate the offset based on the bottom of the module header
+                        var offset = jQuery("#editor-header").offset();
+                        var propSectionHeight = jQuery('#propertySection').height();
+                        var canvas = jQuery('#canvasSection');
+                        var mainHeader = jQuery('#main-header');
+
+                        if (offset == undefined || offset === null
+                            || propSectionHeight === undefined || propSectionHeight === null
+                            || canvas === undefined || canvas === null || mainHeader === null) {
+                            return;
+                        }
+
+                        if ($rootScope.editor) {
+                            var selectedElements = $rootScope.editor.selection;
+                            var subSelectionElements = $rootScope.editor._subSelection;
+
+                            $rootScope.selectedElements = selectedElements;
+                            $rootScope.subSelectionElements = subSelectionElements;
+                            if (selectedElements && selectedElements.length > 0) {
+                                $rootScope.selectedElementBeforeScrolling = selectedElements[0];
+
+                                $rootScope.editor.setSelection([]); // needed cause it checks for element changes and does nothing if the elements are the same
+                                $rootScope.editor.setSelection($rootScope.selectedElements, $rootScope.subSelectionElements);
+                                $rootScope.selectedElements = undefined;
+                                $rootScope.subSelectionElements = undefined;
+                            }
+                        }
+
+                        var totalAvailable = jQuery(window).height() - offset.top - mainHeader.height() - 50;
+                        canvas.height(totalAvailable - propSectionHeight);
+                        jQuery('#paletteSection').height(totalAvailable);
+
+                        // Update positions of the resize-markers, according to the canvas
+
+                        var actualCanvas = null;
+                        if (canvas && canvas[0].children[1]) {
+                            actualCanvas = canvas[0].children[1];
+                        }
+
+                        var canvasTop = canvas.position().top;
+                        var canvasLeft = canvas.position().left;
+                        var canvasHeight = canvas[0].clientHeight;
+                        var canvasWidth = canvas[0].clientWidth;
+                        var iconCenterOffset = 8;
+                        var widthDiff = 0;
+
+                        var actualWidth = 0;
+                        if (actualCanvas) {
+                            // In some browsers, the SVG-element clientwidth isn't available, so we revert to the parent
+                            actualWidth = actualCanvas.clientWidth || actualCanvas.parentNode.clientWidth;
+                        }
+
+
+                        if (actualWidth < canvas[0].clientWidth) {
+                            widthDiff = actualWidth - canvas[0].clientWidth;
+                            // In case the canvas is smaller than the actual viewport, the resizers should be moved
+                            canvasLeft -= widthDiff / 2;
+                            canvasWidth += widthDiff;
+                        }
+
+                        var iconWidth = 17;
+                        var iconOffset = 20;
+
+                        var north = jQuery('#canvas-grow-N');
+                        north.css('top', canvasTop + iconOffset + 'px');
+                        north.css('left', canvasLeft - 10 + (canvasWidth - iconWidth) / 2 + 'px');
+
+                        var south = jQuery('#canvas-grow-S');
+                        south.css('top', (canvasTop + canvasHeight - iconOffset - iconCenterOffset) + 'px');
+                        south.css('left', canvasLeft - 10 + (canvasWidth - iconWidth) / 2 + 'px');
+
+                        var east = jQuery('#canvas-grow-E');
+                        east.css('top', canvasTop - 10 + (canvasHeight - iconWidth) / 2 + 'px');
+                        east.css('left', (canvasLeft + canvasWidth - iconOffset - iconCenterOffset) + 'px');
+
+                        var west = jQuery('#canvas-grow-W');
+                        west.css('top', canvasTop - 10 + (canvasHeight - iconWidth) / 2 + 'px');
+                        west.css('left', canvasLeft + iconOffset + 'px');
+
+                        north = jQuery('#canvas-shrink-N');
+                        north.css('top', canvasTop + iconOffset + 'px');
+                        north.css('left', canvasLeft + 10 + (canvasWidth - iconWidth) / 2 + 'px');
+
+                        south = jQuery('#canvas-shrink-S');
+                        south.css('top', (canvasTop + canvasHeight - iconOffset - iconCenterOffset) + 'px');
+                        south.css('left', canvasLeft + 10 + (canvasWidth - iconWidth) / 2 + 'px');
+
+                        east = jQuery('#canvas-shrink-E');
+                        east.css('top', canvasTop + 10 + (canvasHeight - iconWidth) / 2 + 'px');
+                        east.css('left', (canvasLeft + canvasWidth - iconOffset - iconCenterOffset) + 'px');
+
+                        west = jQuery('#canvas-shrink-W');
+                        west.css('top', canvasTop + 10 + (canvasHeight - iconWidth) / 2 + 'px');
+                        west.css('left', canvasLeft + iconOffset + 'px');
+                    });
+
+                    jQuery(window).trigger('resize');
+
+                    jQuery.fn.scrollStopped = function (callback) {
+                        jQuery(this).scroll(function () {
+                            var self = this, $this = jQuery(self);
+                            if ($this.data('scrollTimeout')) {
+                                clearTimeout($this.data('scrollTimeout'));
+                            }
+                            $this.data('scrollTimeout', setTimeout(callback, 50, self));
+                        });
+                    };
+
+                    // Always needed, cause the DOM element on which the scroll event listeners are attached are changed for every new model
+                    initScrollHandling();
+
+                    $rootScope.editorInitialized = true;
+                }
+            });
+
+            /**
+             * Initialize the event bus: couple all Oryx events with a dispatch of the
+             * event of the event bus. This way, it gets much easier to attach custom logic
+             * to any event.
+             */
+
+            $rootScope.editorFactory.promise.then(function () {
+
+                KISBPM.eventBus.editor = $rootScope.editor;
+
+                var eventMappings = [
+                    {
+                        oryxType: ORYX.CONFIG.EVENT_SELECTION_CHANGED,
+                        kisBpmType: KISBPM.eventBus.EVENT_TYPE_SELECTION_CHANGE
+                    },
+                    {oryxType: ORYX.CONFIG.EVENT_DBLCLICK, kisBpmType: KISBPM.eventBus.EVENT_TYPE_DOUBLE_CLICK},
+                    {oryxType: ORYX.CONFIG.EVENT_MOUSEOUT, kisBpmType: KISBPM.eventBus.EVENT_TYPE_MOUSE_OUT},
+                    {oryxType: ORYX.CONFIG.EVENT_MOUSEOVER, kisBpmType: KISBPM.eventBus.EVENT_TYPE_MOUSE_OVER}
+
+                ];
+
+                eventMappings.forEach(function (eventMapping) {
+                    $rootScope.editor.registerOnEvent(eventMapping.oryxType, function (event) {
+                        KISBPM.eventBus.dispatch(eventMapping.kisBpmType, event);
+                    });
+                });
+
+                $rootScope.editor.registerOnEvent(ORYX.CONFIG.EVENT_SHAPEREMOVED, function (event) {
+                    var validateButton = document.getElementById(event.shape.resourceId + "-validate-button");
+                    if (validateButton) {
+                        validateButton.style.display = 'none';
+                    }
+                });
+
+                // The Oryx canvas is ready (we know since we're in this promise callback) and the
+                // event bus is ready. The editor is now ready for use
+                KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_EDITOR_READY, {type: KISBPM.eventBus.EVENT_TYPE_EDITOR_READY});
+
+            });
+
+            // Alerts
+            $rootScope.alerts = {
+                queue: []
+            };
+
+            $rootScope.showAlert = function (alert) {
+                if (alert.queue.length > 0) {
+                    alert.current = alert.queue.shift();
+                    // Start timout for message-pruning
+                    alert.timeout = $timeout(function () {
+                        if (alert.queue.length == 0) {
+                            alert.current = undefined;
+                            alert.timeout = undefined;
+                        } else {
+                            $rootScope.showAlert(alert);
+                        }
+                    }, (alert.current.type == 'error' ? 5000 : 1000));
+                } else {
+                    $rootScope.alerts.current = undefined;
+                }
+            };
+
+            $rootScope.addAlert = function (message, type) {
+                var newAlert = {message: message, type: type};
+                if (!$rootScope.alerts.timeout) {
+                    // Timeout for message queue is not running, start one
+                    $rootScope.alerts.queue.push(newAlert);
+                    $rootScope.showAlert($rootScope.alerts);
+                } else {
+                    $rootScope.alerts.queue.push(newAlert);
+                }
+            };
+
+            $rootScope.dismissAlert = function () {
+                if (!$rootScope.alerts.timeout) {
+                    $rootScope.alerts.current = undefined;
+                } else {
+                    $timeout.cancel($rootScope.alerts.timeout);
+                    $rootScope.alerts.timeout = undefined;
+                    $rootScope.showAlert($rootScope.alerts);
+                }
+            };
+
+            $rootScope.addAlertPromise = function (promise, type) {
+                if (promise) {
+                    promise.then(function (data) {
+                        $rootScope.addAlert(data, type);
+                    });
+                }
+            };
+
+        }
+    ])
+
+    // Moment-JS date-formatting filter
+    .filter('dateformat', function () {
+        return function (date, format) {
+            if (date) {
+                if (format) {
+                    return moment(date).format(format);
+                } else {
+                    return moment(date).calendar();
+                }
+            }
+            return '';
+        };
+    });

+ 450 - 0
itdmWeb/public/static/editor-app/configuration/properties-assignment-controller.js

@@ -0,0 +1,450 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Assignment
+ */
+
+
+var KisBpmAssignmentCtrl = ['$scope', '$modal', '$http', function ($scope, $modal, $http) {
+
+    // Config for the modal window
+    var opts = {
+        template: 'editor-app/configuration/properties/assignment-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    // Open the dialog
+    $modal(opts);
+}];
+
+var KisBpmAssignmentPopupCtrl = ['$scope', '$modal', '$http', function ($scope, $modal, $http) {
+
+
+    // 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 = {};
+    }
+
+    if ($scope.assignment.candidateUsers == undefined || $scope.assignment.candidateUsers.length == 0) {
+        $scope.assignment.candidateUsers = [{value: ''}];
+    }
+
+
+    if ($scope.assignment.assignee == undefined || $scope.assignment.assignee == '') {
+        $scope.assignment.assignee = '';
+    }
+
+    // Click handler for + button after enum value
+    var userValueIndex = 1;
+    $scope.addCandidateUserValue = function (index) {
+        $scope.assignment.candidateUsers.splice(index + 1, 0, {value: 'value ' + userValueIndex++});
+    };
+
+    // Click handler for - button after enum value
+    $scope.removeCandidateUserValue = function (index) {
+        $scope.assignment.candidateUsers.splice(index, 1);
+    };
+
+    if ($scope.assignment.candidateGroups == undefined || $scope.assignment.candidateGroups.length == 0) {
+        $scope.assignment.candidateGroups = [{value: ''}];
+    }
+
+    var groupValueIndex = 1;
+    $scope.addCandidateGroupValue = function (index) {
+        $scope.assignment.candidateGroups.splice(index + 1, 0, {value: 'value ' + groupValueIndex++});
+    };
+
+    // Click handler for - button after enum value
+    $scope.removeCandidateGroupValue = function (index) {
+        $scope.assignment.candidateGroups.splice(index, 1);
+    };
+
+    //Open the dialog to select users
+    $scope.choseAssignment = function (flag) {
+        var opts = {
+            template: 'editor-app/configuration/properties/assignment-popup-popup.html?version=' + Date.now(),
+            scope: $scope
+        };
+        $scope.choseAssignmentFlag = flag;
+        // Open the dialog
+        $modal(opts);
+    };
+
+    //Open the dialog to select candidateGroups
+    $scope.choseCandidateGroups = function () {
+        var opts = {
+            template: 'editor-app/configuration/properties/assignment-candidateGroup.html?version=' + Date.now(),
+            scope: $scope
+        };
+        // Open the dialog
+        $modal(opts);
+    };
+
+    $scope.dynCandidateUser = function (position) {
+        $scope.assignment.assignee = "${" + position.code + "}";
+        $scope.assignment.assigneeshowname = position.name;
+        if (typeof $scope.property.value === 'string') {
+            $scope.property.value = {};
+        }
+        $scope.property.value.assignment = $scope.assignment;
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    $scope.save = function () {
+        $scope.property.value = {};
+        handleAssignmentInput($scope);
+        $scope.property.value.assignment = $scope.assignment;
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    // Close button handler
+    $scope.close = function () {
+        handleAssignmentInput($scope);
+        $scope.property.mode = 'read';
+        $scope.$hide();
+    };
+
+    var handleAssignmentInput = function ($scope) {
+        if ($scope.assignment.candidateUsers) {
+            var emptyUsers = true;
+            var toRemoveIndexes = [];
+            for (var i = 0; i < $scope.assignment.candidateUsers.length; i++) {
+                if ($scope.assignment.candidateUsers[i].value != '') {
+                    emptyUsers = false;
+                } else {
+                    toRemoveIndexes[toRemoveIndexes.length] = i;
+                }
+            }
+
+            for (var i = 0; i < toRemoveIndexes.length; i++) {
+                $scope.assignment.candidateUsers.splice(toRemoveIndexes[i], 1);
+            }
+
+            if (emptyUsers) {
+                $scope.assignment.candidateUsers = undefined;
+            }
+        }
+
+        if ($scope.assignment.candidateGroups) {
+            var emptyGroups = true;
+            var toRemoveIndexes = [];
+            for (var i = 0; i < $scope.assignment.candidateGroups.length; i++) {
+                if ($scope.assignment.candidateGroups[i].value != '') {
+                    emptyGroups = false;
+                } else {
+                    toRemoveIndexes[toRemoveIndexes.length] = i;
+                }
+            }
+
+            for (var i = 0; i < toRemoveIndexes.length; i++) {
+                $scope.assignment.candidateGroups.splice(toRemoveIndexes[i], 1);
+            }
+
+            if (emptyGroups) {
+                $scope.assignment.candidateGroups = undefined;
+            }
+        }
+    };
+
+    //因新打开的界面上选定的数据要传输到当前modal中,所以使用此方式,这是angular.js中不同控制器之间传输数据的方式
+    $scope.$on('choseAssigneesStr', function (event, data, nameData) {
+        var infos = data.split(",");
+        var nameInfos = nameData.split(",");
+        // $scope.assignment.candidateUsers= [];
+        for (var i = 0; i < infos.length; i++) {
+            $scope.assignment.candidateUsers.push({value: infos[i], nameValue: nameInfos[i]});
+            // $scope.assignment.candidateUsers[i].value = infos[i];
+        }
+        //清空第一个
+        if ((!$scope.assignment.candidateUsers[0].value) || $scope.assignment.candidateUsers[0] == '') {
+            //清空第一个元素
+            $scope.assignment.candidateUsers.splice(0, 1);
+        }
+    });
+    $scope.$on('choseAssigneeStr', function (event, data) {
+    
+        $scope.assignment.assignee = data;
+    });
+    $scope.$on('choseAssigneeNameStr', function (event, data) {
+        $scope.assignment.assigneeshowname = data;
+    });
+    $scope.$on('choseCandidateGroupsStr', function (event, data, nameData) {
+        // $scope.assignment.candidateGroups[0].value = data;
+        var infos = data.split(",");
+        var nameInfos = nameData.split(",");
+
+        for (var i = 0; i < infos.length; i++) {
+            // $scope.assignment.candidateGroups[i].value = infos[i];
+            $scope.assignment.candidateGroups.push({value: infos[i], nameValue: nameInfos[i]});
+        }
+
+        //清空第一个
+        if ((!$scope.assignment.candidateGroups[0].value) || $scope.assignment.candidateGroups[0] == '') {
+            //清空第一个元素
+            $scope.assignment.candidateGroups.splice(0, 1);
+        }
+
+    });
+}];
+
+  // 用户列表
+
+var KisBpmChoseAssignmentCtrl = ['$scope', '$http', function ($scope, $http) {
+
+    $scope.keyword = '';
+    $scope.reload = true;
+    $scope.paginationConf = {
+        currentPage: 1,
+        totalItems: 100,
+        itemsPerPage: 10,
+        pagesLength: 5,
+        perPageOptions: [10, 20, 30, 40, 50],
+        onChange: function () {
+            if (!$scope.reload) {
+                return;
+            }
+            $scope.reloadList();//重新加载  这个方法会重复调用两次  
+            $scope.reload = false;
+            setTimeout(function () { 
+                $scope.reload = true; 
+            }, 200); 
+        }
+    };
+
+    // 刷新列表方法
+    $scope.reloadList = function () {
+        $scope.findPage($scope.paginationConf.currentPage, $scope.paginationConf.itemsPerPage);
+    }
+
+    // 分页方法,请求数据
+    $scope.findPage = function (page, limit) {
+      let accounts = [];
+        $http({
+            method: 'get',
+            headers: {
+                'Accept': 'application/json',
+                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
+               
+            },
+            url: ACTIVITI.CONFIG.baseUrl + '/sys/user/actUserList/'+ page + '/' + limit + "?keyword=" + $scope.keyword
+        })
+            .success(function (data, status, headers, config) {
+             
+                //封装数据
+                let obj = data.result;
+                
+                if (data != null && data.code == 0) {
+                  
+                    obj.records.forEach(function (e, i) {
+                        accounts.push({id: e.id, code: e.username, name: e.realname, index: i});
+                    })
+                }
+                $scope.accounts = accounts;
+                $scope.paginationConf.totalItems = obj.total;
+            })
+           .error(function (data, status, headers, config) {
+            });
+    }
+
+    //模态框左侧组的点击事件:根据所点击的组获取当前组的所有用户
+    $scope.queryByRole = function (value) {
+        //初始化表格
+        $scope.keyword = '';
+        $scope.paginationConf.currentPage = 1;
+        $scope.reloadList();
+    };
+
+    $scope.queryByKeyword = function () {
+        
+        $scope.paginationConf.currentPage = 1;
+        $scope.reloadList();
+    }
+
+    $scope.reset = function () {
+        $scope.keyword = "";
+        $scope.paginationConf.currentPage = 1;
+        $scope.reloadList();
+    }
+
+    //初始化左边菜单栏数据,并触发第一个菜单的点击事件
+    let roles = [];
+    $scope.getAllRoles = function (successCallback) {
+        $http({
+            method: 'get',
+            headers: {
+                'Accept': 'application/json',
+                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
+                'X-Access-Token': ACTIVITI.CONFIG.token
+            },
+            url: ACTIVITI.CONFIG.baseUrl + '/sys/role/getRoleList'
+        })
+
+            .success(function (data, status, headers, config) {
+                let obj = data.result;
+                for (var i = 0; i < obj.length; i++) {
+                    roles.push({id: obj[i].id, name: obj[i].roleName});
+                }
+                $scope.roles = roles;
+            })
+            .error(function (data, status, headers, config) {
+            });
+    };
+    $scope.getAllRoles(function () {
+    });
+
+
+    // Close button handler
+    $scope.close = function () {
+        $scope.$hide();
+    };
+    $scope.formData = {};
+    $scope.candidateUser = {};
+
+    //Save Data
+    $scope.save = function () {
+ 
+        if ($scope.choseAssignmentFlag == "assignee") {
+
+            var choseAssignees = $scope.accounts;
+            var choseAssigneesStr = "";
+            var choseAssigneesNameStr = "";
+            for (var i = 0; i < choseAssignees.length; i++) {
+                if (choseAssignees[i].checked) {
+                    choseAssigneesStr = choseAssignees[i].id;
+                    choseAssigneesNameStr = choseAssignees[i].name;
+                    break;
+                }
+            }
+            $scope.$emit('choseAssigneeStr', choseAssigneesStr);
+            $scope.$emit('choseAssigneeNameStr', choseAssigneesNameStr);
+        } else if ($scope.choseAssignmentFlag == "assignees") {
+            var choseAssignees = $scope.accounts;
+            var choseAssigneesStr = "";
+            var choseAssigneesNameStr = "";
+            for (var i = 0; i < choseAssignees.length; i++) {
+                if (choseAssignees[i].selected) {
+                    choseAssigneesStr += choseAssignees[i].id + ",";
+                    choseAssigneesNameStr += choseAssignees[i].name + ",";
+                }
+            }
+            choseAssigneesStr = choseAssigneesStr.substring(0, choseAssigneesStr.length - 1);
+            choseAssigneesNameStr = choseAssigneesNameStr.substring(0, choseAssigneesNameStr.length - 1);
+            $scope.$emit('choseAssigneesStr', choseAssigneesStr, choseAssigneesNameStr);
+        }
+        $scope.close();
+    };
+    $scope.selectAll = function () {
+        var choseAssignees = $scope.accounts;
+        for (var i = 0; i < choseAssignees.length; i++) {
+            choseAssignees[i].selected = true;
+        }
+        $scope.accounts = choseAssignees;
+    };
+    $scope.rowClick = function (id) {
+      
+        var type = $scope.choseAssignmentFlag;
+        var choseAssignees = $scope.accounts;
+        for (var i = 0; i < choseAssignees.length; i++) {
+            if (type == "assignee") {
+                if (choseAssignees[i].id == id) {
+                    choseAssignees[i].checked = true;
+                } else {
+                    choseAssignees[i].checked = false;
+                }
+            } else if (type == "assignees") {
+                if (choseAssignees[i].id == id) {
+                    choseAssignees[i].selected = choseAssignees[i].selected ? false : true;
+                }
+            }
+        }
+        $scope.accounts = choseAssignees;
+    }
+}];
+
+
+var KisBpmChoseCandidateGroupsCtrl = ['$scope', '$http', function ($scope, $http) {
+
+    var candidateGroups = [];
+    $scope.getAllRoles = function (successCallback) {
+        $http({
+            method: 'get',
+            headers: {
+                'Accept': 'application/json',
+                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
+            },
+            url: ACTIVITI.CONFIG.baseUrl + '/sys/role/getRoleList'
+        })
+            .success(function (data, status, headers, config) {
+                let obj = data.result;
+                for (let i = 0; i < obj.length; i++) {
+                    candidateGroups.push({id: obj[i].id, name: obj[i].roleName, description: obj[i].description});
+                }
+                $scope.candidateGroups = candidateGroups;
+            })
+            .error(function (data, status, headers, config) {
+            });
+    };
+    $scope.getAllRoles(function () {
+    });
+
+    // Close button handler
+    $scope.close = function () {
+        $scope.$hide();
+    };
+
+    $scope.save = function () {
+        var choseCandidateGroups = $scope.candidateGroups;
+        var choseCandidateGroupsStr = "";
+        var choseAssigneesNameStr = "";
+        for (var i = 0; i < choseCandidateGroups.length; i++) {
+            if (choseCandidateGroups[i].selected) {
+                choseCandidateGroupsStr += choseCandidateGroups[i].id + ",";
+                choseAssigneesNameStr += choseCandidateGroups[i].description + ",";
+            }
+        }
+        choseCandidateGroupsStr = choseCandidateGroupsStr.substring(0, choseCandidateGroupsStr.length - 1);
+        choseAssigneesNameStr = choseAssigneesNameStr.substring(0, choseAssigneesNameStr.length - 1);
+        $scope.$emit('choseCandidateGroupsStr', choseCandidateGroupsStr, choseAssigneesNameStr);
+        $scope.close();
+    }
+
+    $scope.selectAll = function () {
+        var candidateGroups = $scope.candidateGroups;
+        for (var i = 0; i < candidateGroups.length; i++) {
+            candidateGroups[i].selected = true;
+        }
+        $scope.candidateGroups = candidateGroups;
+    };
+    $scope.rowClick = function (id) {
+        var candidateGroups = $scope.candidateGroups;
+        for (var i = 0; i < candidateGroups.length; i++) {
+            if (candidateGroups[i].id == id) {
+                candidateGroups[i].selected = candidateGroups[i].selected ? false : true;
+            }
+        }
+        $scope.candidateGroups = candidateGroups;
+    }
+}];

+ 58 - 0
itdmWeb/public/static/editor-app/configuration/properties-condition-expression-controller.js

@@ -0,0 +1,58 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Condition expression
+ */
+
+var KisBpmConditionExpressionCtrl = [ '$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
+    $modal(opts);
+}];
+
+var KisBpmConditionExpressionPopupCtrl = [ '$scope', '$translate', '$http', function($scope, $translate, $http) {
+
+	// Put json representing condition on scope
+    if ($scope.property.value !== undefined && $scope.property.value !== null) {
+
+        $scope.conditionExpression = {value: $scope.property.value};
+        
+    } else {
+        $scope.conditionExpression = {value: ''};
+    }
+	
+    $scope.save = function() {
+        $scope.property.value = $scope.conditionExpression.value;
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    // Close button handler
+    $scope.close = function() {
+    	$scope.property.mode = 'read';
+    	$scope.$hide();
+    };
+}];

+ 18 - 0
itdmWeb/public/static/editor-app/configuration/properties-custom-controllers.js

@@ -0,0 +1,18 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */

+ 115 - 0
itdmWeb/public/static/editor-app/configuration/properties-default-controllers.js

@@ -0,0 +1,115 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * String controller
+ */
+
+var KisBpmStringPropertyCtrl = [ '$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 (keyEvent && keyEvent.which === 13) {
+    		keyEvent.preventDefault();
+	        $scope.inputBlurred(); // we want to do the same as if the user would blur the input field
+    	}
+    };
+    
+    $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
+ */
+
+var KisBpmBooleanPropertyCtrl = ['$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['oryx-defaultflow'];
+                                if (defaultFlowProp) {
+                                    flows[i].setProperty('oryx-defaultflow', false, true);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        $scope.updatePropertyInModel($scope.property);
+    };
+
+}];
+
+/*
+ * Text controller
+ */
+
+var KisBpmTextPropertyCtrl = [ '$scope', '$modal', function($scope, $modal) {
+
+    var opts = {
+        template:  'editor-app/configuration/properties/text-popup.html?version=' + Date.now(),
+        scope: $scope
+    };
+
+    // Open the dialog
+    $modal(opts);
+}];
+
+var KisBpmTextPropertyPopupCtrl = ['$scope', function($scope) {
+    
+    $scope.save = function() {
+        $scope.updatePropertyInModel($scope.property);
+        $scope.close();
+    };
+
+    $scope.close = function() {
+        $scope.property.mode = 'read';
+        $scope.$hide();
+    };
+}];

+ 266 - 0
itdmWeb/public/static/editor-app/configuration/properties-event-listeners-controller.js

@@ -0,0 +1,266 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Execution listeners
+ */
+
+var KisBpmEventListenersCtrl = [ '$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
+    $modal(opts);
+}];
+
+//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
+var KisBpmEventListenersPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
+
+    // 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 = [];
+    }
+
+    // Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
+    $scope.selectedListeners = [];
+    $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: 'eventListeners',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedListeners,
+            afterSelectionChange: function (rowItem, event) {
+            	
+            	if ($scope.selectedListeners.length > 0)
+            	{
+	            	var fields = $scope.selectedListeners[0].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;
+	                    	}
+	            		}
+	            	}
+	            	
+	            	if (!$scope.selectedListeners[0].events || $scope.selectedListeners[0].events.length == 0)
+	                {
+	                	$scope.selectedListeners[0].events = [{event: ''}];
+	                }
+            	}
+            },
+            columnDefs: [{ field: 'event', displayName: $scope.labels.eventLabel },
+                { field: 'implementation', displayName: $scope.labels.implementationLabel }]
+        };
+    });
+    
+    // Click handler for + button after enum value
+    $scope.addEventValue = function(index) {
+        $scope.selectedListeners[0].events.splice(index + 1, 0, {event: ''});
+    };
+
+    // Click handler for - button after enum value
+    $scope.removeEventValue = function(index) {
+        $scope.selectedListeners[0].events.splice(index, 1);
+        $scope.listenerDetailsChanged();
+    };
+    
+    $scope.listenerDetailsChanged = function() {
+    	var listener = $scope.selectedListeners[0];
+    	if (listener.events)
+    	{
+    		var eventText = '';
+    		for (var i = 0; i < listener.events.length; i++)
+    		{
+    			if (i > 0)
+    			{
+    				eventText += ", ";
+    			}
+    			eventText += listener.events[i].event;
+    		}
+    		$scope.selectedListeners[0].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.selectedListeners[0].implementation = implementationText;
+    	}
+    	else
+    	{
+        	if ($scope.selectedListeners[0].className !== '')
+        	{
+        		$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].className;
+        	}
+        	else if ($scope.selectedListeners[0].delegateExpression !== '')
+        	{
+        		$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].delegateExpression;
+        	}
+        	else
+        	{
+        		$scope.selectedListeners[0].implementation = '';
+        	}
+    	}
+    };
+
+    // Click handler for add button
+    $scope.addNewListener = function() {
+        $scope.eventListeners.push({ event : '',
+            implementation : '',
+            className : '',
+            delegateExpression: '',
+            retrowEvent: false});
+    };
+
+    // Click handler for remove button
+    $scope.removeListener = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.eventListeners.indexOf($scope.selectedListeners[0]);
+            $scope.gridOptions.selectItem(index, false);
+            $scope.eventListeners.splice(index, 1);
+
+            $scope.selectedListeners.length = 0;
+            if (index < $scope.eventListeners.length) {
+                $scope.gridOptions.selectItem(index + 1, true);
+            } else if ($scope.eventListeners.length > 0) {
+                $scope.gridOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveListenerUp = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.eventListeners.indexOf($scope.selectedListeners[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.eventListeners[index];
+                $scope.eventListeners.splice(index, 1);
+                $timeout(function(){
+                    $scope.eventListeners.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveListenerDown = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.eventListeners.indexOf($scope.selectedListeners[0]);
+            if (index != $scope.eventListeners.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.eventListeners[index];
+                $scope.eventListeners.splice(index, 1);
+                $timeout(function(){
+                    $scope.eventListeners.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // 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();
+    };
+
+}];

+ 326 - 0
itdmWeb/public/static/editor-app/configuration/properties-execution-listeners-controller.js

@@ -0,0 +1,326 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Execution listeners
+ */
+
+var KisBpmExecutionListenersCtrl = [ '$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
+    $modal(opts);
+}];
+
+var KisBpmExecutionListenersPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
+
+    // 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 = [];
+    }
+
+    // Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
+    $scope.selectedListeners = [];
+    $scope.selectedFields = [];
+    $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: 'executionListeners',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedListeners,
+            afterSelectionChange: function (rowItem, event) {
+                $scope.selectedFields.length = 0;
+                if ($scope.selectedListeners.length > 0)
+                {
+                    var fields = $scope.selectedListeners[0].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;
+                            }
+                        }
+                    }
+                }
+            },
+            columnDefs: [{ field: 'event', displayName: $scope.labels.eventLabel },
+                { field: 'implementation', displayName: $scope.labels.implementationLabel }]
+        };
+        
+        // Config for field grid
+        $scope.gridFieldOptions = {
+            data: 'selectedListeners[0].fields',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedFields,
+            columnDefs: [{ field: 'name', displayName: $scope.labels.nameLabel },
+                { field: 'implementation', displayName: $scope.labels.implementationLabel}]
+        };
+    });
+    
+    $scope.listenerDetailsChanged = function() {
+        if ($scope.selectedListeners[0].className !== '')
+        {
+            $scope.selectedListeners[0].implementation = $scope.selectedListeners[0].className;
+        }
+        else if ($scope.selectedListeners[0].expression !== '')
+        {
+            $scope.selectedListeners[0].implementation = $scope.selectedListeners[0].expression;
+        }
+        else if ($scope.selectedListeners[0].delegateExpression !== '')
+        {
+            $scope.selectedListeners[0].implementation = $scope.selectedListeners[0].delegateExpression;
+        }
+        else
+        {
+            $scope.selectedListeners[0].implementation = '';
+        }
+    };
+
+    // Click handler for add button
+    $scope.addNewListener = function() {
+        $scope.executionListeners.push({ event : 'start',
+            implementation : '',
+            className : '',
+            expression: '',
+            delegateExpression: ''});
+    };
+
+    // Click handler for remove button
+    $scope.removeListener = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.executionListeners.indexOf($scope.selectedListeners[0]);
+            $scope.gridOptions.selectItem(index, false);
+            $scope.executionListeners.splice(index, 1);
+
+            $scope.selectedListeners.length = 0;
+            if (index < $scope.executionListeners.length) {
+                $scope.gridOptions.selectItem(index + 1, true);
+            } else if ($scope.executionListeners.length > 0) {
+                $scope.gridOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveListenerUp = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.executionListeners.indexOf($scope.selectedListeners[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.executionListeners[index];
+                $scope.executionListeners.splice(index, 1);
+                $timeout(function(){
+                    $scope.executionListeners.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveListenerDown = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.executionListeners.indexOf($scope.selectedListeners[0]);
+            if (index != $scope.executionListeners.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.executionListeners[index];
+                $scope.executionListeners.splice(index, 1);
+                $timeout(function(){
+                    $scope.executionListeners.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+    
+    $scope.fieldDetailsChanged = function() {
+        if ($scope.selectedFields[0].stringValue !== '')
+        {
+            $scope.selectedFields[0].implementation = $scope.selectedFields[0].stringValue;
+        }
+        else if ($scope.selectedFields[0].expression !== '')
+        {
+            $scope.selectedFields[0].implementation = $scope.selectedFields[0].expression;
+        }
+        else if ($scope.selectedFields[0].string !== '')
+        {
+            $scope.selectedFields[0].implementation = $scope.selectedFields[0].string;
+        }
+        else
+        {
+            $scope.selectedFields[0].implementation = '';
+        }
+    };
+
+    // Click handler for add button
+    $scope.addNewField = function() {
+        if ($scope.selectedListeners.length > 0)
+        {
+            if ($scope.selectedListeners[0].fields == undefined)
+            {
+                $scope.selectedListeners[0].fields = [];
+            }
+            $scope.selectedListeners[0].fields.push({ name : 'fieldName',
+                implementation : '',
+                stringValue : '',
+                expression: '',
+                string: ''});
+        }
+    };
+
+    // Click handler for remove button
+    $scope.removeField = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
+            $scope.gridFieldOptions.selectItem(index, false);
+            $scope.selectedListeners[0].fields.splice(index, 1);
+
+            $scope.selectedFields.length = 0;
+            if (index < $scope.selectedListeners[0].fields.length) {
+                $scope.gridFieldOptions.selectItem(index + 1, true);
+            } else if ($scope.selectedListeners[0].fields.length > 0) {
+                $scope.gridFieldOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveFieldUp = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.selectedListeners[0].fields[index];
+                $scope.selectedListeners[0].fields.splice(index, 1);
+                $timeout(function(){
+                    $scope.selectedListeners[0].fields.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveFieldDown = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
+            if (index != $scope.selectedListeners[0].fields.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.selectedListeners[0].fields[index];
+                $scope.selectedListeners[0].fields.splice(index, 1);
+                $timeout(function(){
+                    $scope.selectedListeners[0].fields.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // 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';
+    };
+
+}];

+ 192 - 0
itdmWeb/public/static/editor-app/configuration/properties-fields-controller.js

@@ -0,0 +1,192 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Task listeners
+ */
+
+var KisBpmFieldsCtrl = [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
+
+    // Config for the modal window
+    var opts = {
+        template:  'editor-app/configuration/properties/fields-popup.html',
+        scope: $scope
+    };
+
+    // Open the dialog
+    $modal(opts);
+}];
+
+var KisBpmFieldsPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
+
+    // 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 = [];
+    }
+
+    // Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
+    $scope.selectedFields = [];
+    $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: 'fields',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected: false,
+            selectedItems: $scope.selectedFields,
+            columnDefs: [{field: 'name', displayName: $scope.labels.nameLabel},
+                {field: 'implementation', displayName: $scope.labels.implementationLabel}]
+        };
+    });
+    
+    $scope.fieldDetailsChanged = function() {
+    	if ($scope.selectedFields[0].stringValue != '')
+    	{
+    		$scope.selectedFields[0].implementation = $scope.selectedFields[0].stringValue;
+    	}
+    	else if ($scope.selectedFields[0].expression != '')
+    	{
+    		$scope.selectedFields[0].implementation = $scope.selectedFields[0].expression;
+    	}
+    	else if ($scope.selectedFields[0].string != '')
+    	{
+    		$scope.selectedFields[0].implementation = $scope.selectedFields[0].string;
+    	}
+    	else
+    	{
+    		$scope.selectedFields[0].implementation = '';
+    	}
+    };
+
+    // Click handler for add button
+    $scope.addNewField = function() {
+    	$scope.fields.push({ name : 'fieldName',
+            implementation : '',
+            stringValue : '',
+            expression: '',
+            string: ''});
+    };
+
+    // Click handler for remove button
+    $scope.removeField = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.fields.indexOf($scope.selectedFields[0]);
+            $scope.gridOptions.selectItem(index, false);
+            $scope.fields.splice(index, 1);
+
+            $scope.selectedFields.length = 0;
+            if (index < $scope.fields.length) {
+                $scope.gridOptions.selectItem(index + 1, true);
+            } else if ($scope.fields.length > 0) {
+                $scope.gridOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveFieldUp = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.fields.indexOf($scope.selectedFields[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.fields[index];
+                $scope.fields.splice(index, 1);
+                $timeout(function(){
+                	$scope.fields.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveFieldDown = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.fields.indexOf($scope.selectedFields[0]);
+            if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.fields[index];
+                $scope.fields.splice(index, 1);
+                $timeout(function(){
+                	$scope.fields.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // 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.close();
+    };
+
+    // Close button handler
+    $scope.close = function() {
+        $scope.property.mode = 'read';
+        $scope.$hide();
+    };
+}];

+ 276 - 0
itdmWeb/public/static/editor-app/configuration/properties-form-properties-controller.js

@@ -0,0 +1,276 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Form Properties
+ */
+
+var KisBpmFormPropertiesCtrl = [ '$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
+    $modal(opts);
+}];
+
+var KisBpmFormPropertiesPopupCtrl = ['$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 = [];
+    }
+
+    // Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
+    $scope.selectedProperties = [];
+    $scope.selectedEnumValues = [];
+    
+    $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: 'formProperties',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedProperties,
+            columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel },
+                { field: 'name', displayName: $scope.labels.nameLabel},
+                { field: 'type', displayName: $scope.labels.typeLabel}]
+        };
+        
+        $scope.enumGridOptions = {
+    		data: 'selectedProperties[0].enumValues',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedEnumValues,
+            columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel },
+                { field: 'name', displayName: $scope.labels.nameLabel}]
+        }
+    });
+
+    // Handler for when the value of the type dropdown changes
+    $scope.propertyTypeChanged = function() {
+
+        // Check date. If date, show date pattern
+        if ($scope.selectedProperties[0].type === 'date') {
+            $scope.selectedProperties[0].datePattern = 'MM-dd-yyyy hh:mm';
+            
+        } else {
+            delete $scope.selectedProperties[0].datePattern;
+        }
+
+        // Check enum. If enum, show list of options
+        if ($scope.selectedProperties[0].type === 'enum') {
+            $scope.selectedProperties[0].enumValues = [ {id: 'value1', name: 'Value 1'}, {id: 'value2', name: 'Value 2'}];
+            
+        } else {
+            delete $scope.selectedProperties[0].enumValues;
+        }
+    };
+
+    // Click handler for add button
+    var propertyIndex = 1;
+    $scope.addNewProperty = function() {
+        $scope.formProperties.push({ id : 'new_property_' + propertyIndex++,
+            name : '',
+            type : 'string',
+            readable: true,
+            writable: true});
+        
+        $timeout(function(){
+        	$scope.gridOptions.selectItem($scope.formProperties.length - 1, true);
+        });
+    };
+
+    // Click handler for remove button
+    $scope.removeProperty = function() {
+        if ($scope.selectedProperties.length > 0) {
+            var index = $scope.formProperties.indexOf($scope.selectedProperties[0]);
+            $scope.gridOptions.selectItem(index, false);
+            $scope.formProperties.splice(index, 1);
+
+            $scope.selectedProperties.length = 0;
+            if (index < $scope.formProperties.length) {
+                $scope.gridOptions.selectItem(index + 1, true);
+            } else if ($scope.formProperties.length > 0) {
+                $scope.gridOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.movePropertyUp = function() {
+        if ($scope.selectedProperties.length > 0) {
+            var index = $scope.formProperties.indexOf($scope.selectedProperties[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.formProperties[index];
+                $scope.formProperties.splice(index, 1);
+                $timeout(function(){
+                    $scope.formProperties.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.movePropertyDown = function() {
+        if ($scope.selectedProperties.length > 0) {
+            var index = $scope.formProperties.indexOf($scope.selectedProperties[0]);
+            if (index != $scope.formProperties.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.formProperties[index];
+                $scope.formProperties.splice(index, 1);
+                $timeout(function(){
+                    $scope.formProperties.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+    
+    $scope.addNewEnumValue = function() {
+    	if ($scope.selectedProperties.length > 0) {
+	        $scope.selectedProperties[0].enumValues.push({ id : '', name : ''});
+    	}
+    	
+    	$timeout(function(){
+        	$scope.enumGridOptions.selectItem($scope.selectedProperties[0].enumValues.length - 1, true);
+        });
+    };
+
+    // Click handler for remove button
+    $scope.removeEnumValue = function() {
+    	if ($scope.selectedProperties.length > 0 && $scope.selectedEnumValues.length > 0) {
+            var index = $scope.selectedProperties[0].enumValues.indexOf($scope.selectedEnumValues[0]);
+            $scope.enumGridOptions.selectItem(index, false);
+            $scope.selectedProperties[0].enumValues.splice(index, 1);
+
+            $scope.selectedEnumValues.length = 0;
+            if (index < $scope.selectedProperties[0].enumValues.length) {
+            	$timeout(function(){
+            		$scope.enumGridOptions.selectItem(index + 1, true);
+            	});
+            	
+            } else if ($scope.selectedProperties[0].enumValues.length > 0) {
+            	$timeout(function(){
+            		$scope.enumGridOptions.selectItem(index - 1, true);
+            	});
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveEnumValueUp = function() {
+    	if ($scope.selectedProperties.length > 0 && $scope.selectedEnumValues.length > 0) {
+    		var index = $scope.selectedProperties[0].enumValues.indexOf($scope.selectedEnumValues[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.selectedProperties[0].enumValues[index];
+                $scope.selectedProperties[0].enumValues.splice(index, 1);
+                $timeout(function(){
+                    $scope.selectedProperties[0].enumValues.splice(index + -1, 0, temp);
+                });
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveEnumValueDown = function() {
+    	if ($scope.selectedProperties.length > 0 && $scope.selectedEnumValues.length > 0) {
+    		var index = $scope.selectedProperties[0].enumValues.indexOf($scope.selectedEnumValues[0]);
+            if (index != $scope.selectedProperties[0].enumValues.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.selectedProperties[0].enumValues[index];
+                $scope.selectedProperties[0].enumValues.splice(index, 1);
+                $timeout(function(){
+                    $scope.selectedProperties[0].enumValues.splice(index + 1, 0, 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';
+    };
+
+}];

+ 158 - 0
itdmWeb/public/static/editor-app/configuration/properties-in-parameters-controller.js

@@ -0,0 +1,158 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Input parameters for call activity
+ */
+
+var KisBpmInParametersCtrl = [ '$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
+    $modal(opts);
+}];
+
+var KisBpmInParametersPopupCtrl = ['$scope', '$q', '$translate', function($scope, $q, $translate) {
+
+    // 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 = [];
+    }
+
+    // Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
+    $scope.selectedParameters = [];
+    $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: 'parameters',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedParameters,
+            columnDefs: [{ field: 'source', displayName: $scope.labels.sourceLabel },
+                         { field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel },
+                         { field: 'target', displayName: $scope.labels.targetLabel }]
+        };
+    });
+
+    // Click handler for add button
+    $scope.addNewParameter = function() {
+        $scope.parameters.push({ source : '',
+            sourceExpression : '',
+            target : ''});
+    };
+
+    // Click handler for remove button
+    $scope.removeParameter = function() {
+        if ($scope.selectedParameters.length > 0) {
+            var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
+            $scope.gridOptions.selectItem(index, false);
+            $scope.parameters.splice(index, 1);
+
+            $scope.selectedParameters.length = 0;
+            if (index < $scope.parameters.length) {
+                $scope.gridOptions.selectItem(index + 1, true);
+            } else if ($scope.parameters.length > 0) {
+                $scope.gridOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveParameterUp = function() {
+        if ($scope.selectedParameters.length > 0) {
+            var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.parameters[index];
+                $scope.parameters.splice(index, 1);
+                $timeout(function(){
+                    $scope.parameters.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveParameterDown = function() {
+        if ($scope.selectedParameters.length > 0) {
+            var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
+            if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.parameters[index];
+                $scope.parameters.splice(index, 1);
+                $timeout(function(){
+                    $scope.parameters.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // 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();
+    };
+
+}];

+ 137 - 0
itdmWeb/public/static/editor-app/configuration/properties-message-definitions-controller.js

@@ -0,0 +1,137 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Execution listeners
+ */
+
+angular.module('activitiModeler').controller('ActivitiMessageDefinitionsCtrl', ['$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
+    $modal(opts);
+}]);
+
+//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('activitiModeler').controller('ActivitiMessageDefinitionsPopupCtrl',
+    ['$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.selectedMessages = [];
+        $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: 'messageDefinitions',
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                keepLastSelected : false,
+                selectedItems: $scope.selectedMessages,
+                columnDefs: [
+                    {field: 'id', displayName: $scope.labels.idLabel},
+                    {field: 'name', displayName: $scope.labels.nameLabel}]
+            };
+        });
+
+        // Click handler for add button
+        $scope.addNewMessageDefinition = function () {
+            var newMessageDefinition = {id: '', name: ''};
+
+            $scope.messageDefinitions.push(newMessageDefinition);
+            $timeout(function () {
+            	$scope.gridOptions.selectItem($scope.messageDefinitions.length - 1, true);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeMessageDefinition = function () {
+        	if ($scope.selectedMessages && $scope.selectedMessages.length > 0) {
+            	var index = $scope.messageDefinitions.indexOf($scope.selectedMessages[0]);
+                $scope.gridOptions.selectItem(index, false);
+                $scope.messageDefinitions.splice(index, 1);
+
+                $scope.selectedMessages.length = 0;
+                if (index < $scope.messageDefinitions.length) {
+                    $scope.gridOptions.selectItem(index + 1, true);
+                } else if ($scope.messageDefinitions.length > 0) {
+                    $scope.gridOptions.selectItem(index - 1, true);
+                }
+            }
+        };
+
+        // 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();
+        };
+
+    }]);

+ 48 - 0
itdmWeb/public/static/editor-app/configuration/properties-message-scope-controller.js

@@ -0,0 +1,48 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+angular.module('activitiModeler').controller('ActivitiMessageRefCtrl', [ '$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['oryx-messagedefinitions']) {
+            messageDefinitionsProperty = parent.properties['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);
+    };
+}]);

+ 34 - 0
itdmWeb/public/static/editor-app/configuration/properties-multiinstance-controller.js

@@ -0,0 +1,34 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Execution listeners
+ */
+
+var KisBpmMultiInstanceCtrl = [ '$scope', function($scope) {
+
+    if ($scope.property.value == undefined && $scope.property.value == null)
+    {
+    	$scope.property.value = 'None';
+    }
+        
+    $scope.multiInstanceChanged = function() {
+    	$scope.updatePropertyInModel($scope.property);
+    };
+}];

+ 158 - 0
itdmWeb/public/static/editor-app/configuration/properties-out-parameters-controller.js

@@ -0,0 +1,158 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Input parameters for call activity
+ */
+
+var KisBpmOutParametersCtrl = [ '$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
+    $modal(opts);
+}];
+
+var KisBpmOutParametersPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
+
+    // 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 = [];
+    }
+
+    // Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
+    $scope.selectedParameters = [];
+    $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: 'parameters',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedParameters,
+            columnDefs: [{ field: 'source', displayName: $scope.labels.sourceLabel },
+                         { field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel },
+                         { field: 'target', displayName: $scope.labels.targetLabel }]
+        };
+    });
+
+    // Click handler for add button
+    $scope.addNewParameter = function() {
+        $scope.parameters.push({ source : '',
+            sourceExpression : '',
+            target : ''});
+    };
+
+    // Click handler for remove button
+    $scope.removeParameter = function() {
+        if ($scope.selectedParameters.length > 0) {
+            var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
+            $scope.gridOptions.selectItem(index, false);
+            $scope.parameters.splice(index, 1);
+
+            $scope.selectedParameters.length = 0;
+            if (index < $scope.parameters.length) {
+                $scope.gridOptions.selectItem(index + 1, true);
+            } else if ($scope.parameters.length > 0) {
+                $scope.gridOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveParameterUp = function() {
+        if ($scope.selectedParameters.length > 0) {
+            var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.parameters[index];
+                $scope.parameters.splice(index, 1);
+                $timeout(function(){
+                    $scope.parameters.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveParameterDown = function() {
+        if ($scope.selectedParameters.length > 0) {
+            var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
+            if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.parameters[index];
+                $scope.parameters.splice(index, 1);
+                $timeout(function(){
+                    $scope.parameters.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // 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();
+    };
+
+}];

+ 130 - 0
itdmWeb/public/static/editor-app/configuration/properties-sequenceflow-order-controller.js

@@ -0,0 +1,130 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Sequence flow order controller
+ */
+
+var KisBpmSequenceFlowOrderCtrl = [ '$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
+    };
+
+    $modal(opts);
+}];
+
+var KisBpmSequenceFlowOrderPopupCtrl = ['$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().title() === 'Sequence flow') {
+                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['oryx-name'],
+                    targetType : 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();
+    };
+
+}];

+ 136 - 0
itdmWeb/public/static/editor-app/configuration/properties-signal-definitions-controller.js

@@ -0,0 +1,136 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+angular.module('activitiModeler').controller('ActivitiSignalDefinitionsCtrl', ['$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
+    $modal(opts);
+}]);
+
+//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('activitiModeler').controller('ActivitiSignalDefinitionsPopupCtrl',
+    ['$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.selectedSignals = [];
+        $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: 'signalDefinitions',
+                headerRowHeight: 28,
+                enableRowSelection: true,
+                enableRowHeaderSelection: false,
+                multiSelect: false,
+                keepLastSelected : false,
+                selectedItems: $scope.selectedSignals,
+                columnDefs: [
+                    {field: 'id', displayName: $scope.labels.idLabel},
+                    {field: 'name', displayName: $scope.labels.nameLabel},
+                    {field: 'scope', displayName: $scope.labels.scopeLabel}]
+            };
+        });
+
+        // Click handler for add button
+        $scope.addNewSignalDefinition = function () {
+            var newSignalDefinition = {id: '', name: '', scope: 'global'};
+
+            $scope.signalDefinitions.push(newSignalDefinition);
+            $timeout(function () {
+            	$scope.gridOptions.selectItem($scope.signalDefinitions.length - 1, true);
+            });
+        };
+
+        // Click handler for remove button
+        $scope.removeSignalDefinition = function () {
+            if ($scope.selectedSignals && $scope.selectedSignals.length > 0) {
+            	var index = $scope.signalDefinitions.indexOf($scope.selectedSignals[0]);
+                $scope.gridOptions.selectItem(index, false);
+                $scope.signalDefinitions.splice(index, 1);
+
+                $scope.selectedSignals.length = 0;
+                if (index < $scope.signalDefinitions.length) {
+                    $scope.gridOptions.selectItem(index + 1, true);
+                } else if ($scope.signalDefinitions.length > 0) {
+                    $scope.gridOptions.selectItem(index - 1, true);
+                }
+            }
+        };
+
+        // 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();
+        };
+
+    }]);

+ 47 - 0
itdmWeb/public/static/editor-app/configuration/properties-signal-scope-controller.js

@@ -0,0 +1,47 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+angular.module('activitiModeler').controller('ActivitiSignalRefCtrl', [ '$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['oryx-signaldefinitions']) {
+            signalDefinitionsProperty = parent.properties['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);
+    };
+}]);

+ 325 - 0
itdmWeb/public/static/editor-app/configuration/properties-task-listeners-controller.js

@@ -0,0 +1,325 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Task listeners
+ */
+
+var KisBpmTaskListenersCtrl = [ '$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
+    $modal(opts);
+}];
+
+var KisBpmTaskListenersPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
+
+    // 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 = [];
+    }
+
+    // Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
+    $scope.selectedListeners = [];
+    $scope.selectedFields = [];
+    $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: 'taskListeners',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedListeners,
+            afterSelectionChange: function (rowItem, event) {
+                $scope.selectedFields.length = 0;
+                if ($scope.selectedListeners.length > 0)
+                {
+                    var fields = $scope.selectedListeners[0].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;
+                            }
+                        }
+                    }
+                }
+            },
+            columnDefs: [{ field: 'event', displayName: $scope.labels.eventLabel },
+                { field: 'implementation', displayName: $scope.labels.implementationLabel}]
+        };
+        
+        // Config for field grid
+        $scope.gridFieldOptions = {
+            data: 'selectedListeners[0].fields',
+            enableRowReordering: true,
+            headerRowHeight: 28,
+            multiSelect: false,
+            keepLastSelected : false,
+            selectedItems: $scope.selectedFields,
+            columnDefs: [{ field: 'name', displayName: $scope.labels.name },
+                { field: 'implementation', displayName: $scope.labels.implementationLabel}]
+        };
+    });
+    
+    $scope.listenerDetailsChanged = function() {
+        if ($scope.selectedListeners[0].className !== '')
+        {
+            $scope.selectedListeners[0].implementation = $scope.selectedListeners[0].className;
+        }
+        else if ($scope.selectedListeners[0].expression !== '')
+        {
+            $scope.selectedListeners[0].implementation = $scope.selectedListeners[0].expression;
+        }
+        else if ($scope.selectedListeners[0].delegateExpression !== '')
+        {
+            $scope.selectedListeners[0].implementation = $scope.selectedListeners[0].delegateExpression;
+        }
+        else
+        {
+            $scope.selectedListeners[0].implementation = '';
+        }
+    };
+
+    // Click handler for add button
+    $scope.addNewListener = function() {
+        $scope.taskListeners.push({ event : 'create',
+            implementation : '',
+            className : '',
+            expression: '',
+            delegateExpression: ''});
+    };
+
+    // Click handler for remove button
+    $scope.removeListener = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.taskListeners.indexOf($scope.selectedListeners[0]);
+            $scope.gridOptions.selectItem(index, false);
+            $scope.taskListeners.splice(index, 1);
+
+            $scope.selectedListeners.length = 0;
+            if (index < $scope.taskListeners.length) {
+                $scope.gridOptions.selectItem(index + 1, true);
+            } else if ($scope.taskListeners.length > 0) {
+                $scope.gridOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveListenerUp = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.taskListeners.indexOf($scope.selectedListeners[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.taskListeners[index];
+                $scope.taskListeners.splice(index, 1);
+                $timeout(function(){
+                    $scope.taskListeners.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveListenerDown = function() {
+        if ($scope.selectedListeners.length > 0) {
+            var index = $scope.taskListeners.indexOf($scope.selectedListeners[0]);
+            if (index != $scope.taskListeners.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.taskListeners[index];
+                $scope.taskListeners.splice(index, 1);
+                $timeout(function(){
+                    $scope.taskListeners.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+    
+    $scope.fieldDetailsChanged = function() {
+        if ($scope.selectedFields[0].stringValue != '')
+        {
+            $scope.selectedFields[0].implementation = $scope.selectedFields[0].stringValue;
+        }
+        else if ($scope.selectedFields[0].expression != '')
+        {
+            $scope.selectedFields[0].implementation = $scope.selectedFields[0].expression;
+        }
+        else if ($scope.selectedFields[0].string != '')
+        {
+            $scope.selectedFields[0].implementation = $scope.selectedFields[0].string;
+        }
+        else
+        {
+            $scope.selectedFields[0].implementation = '';
+        }
+    };
+
+    // Click handler for add button
+    $scope.addNewField = function() {
+        if ($scope.selectedListeners.length > 0)
+        {
+            if ($scope.selectedListeners[0].fields == undefined)
+            {
+                $scope.selectedListeners[0].fields = [];
+            }
+            $scope.selectedListeners[0].fields.push({ name : 'fieldName',
+                implementation : '',
+                stringValue : '',
+                expression: '',
+                string: ''});
+        }
+    };
+
+    // Click handler for remove button
+    $scope.removeField = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
+            $scope.gridFieldOptions.selectItem(index, false);
+            $scope.selectedListeners[0].fields.splice(index, 1);
+
+            $scope.selectedFields.length = 0;
+            if (index < $scope.selectedListeners[0].fields.length) {
+                $scope.gridFieldOptions.selectItem(index + 1, true);
+            } else if ($scope.selectedListeners[0].fields.length > 0) {
+                $scope.gridFieldOptions.selectItem(index - 1, true);
+            }
+        }
+    };
+
+    // Click handler for up button
+    $scope.moveFieldUp = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
+            if (index != 0) { // If it's the first, no moving up of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.selectedListeners[0].fields[index];
+                $scope.selectedListeners[0].fields.splice(index, 1);
+                $timeout(function(){
+                    $scope.selectedListeners[0].fields.splice(index + -1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // Click handler for down button
+    $scope.moveFieldDown = function() {
+        if ($scope.selectedFields.length > 0) {
+            var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
+            if (index != $scope.selectedListeners[0].fields.length - 1) { // If it's the last element, no moving down of course
+                // Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
+                var temp = $scope.selectedListeners[0].fields[index];
+                $scope.selectedListeners[0].fields.splice(index, 1);
+                $timeout(function(){
+                    $scope.selectedListeners[0].fields.splice(index + 1, 0, temp);
+                }, 100);
+
+            }
+        }
+    };
+
+    // 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();
+    };
+
+}];

+ 99 - 0
itdmWeb/public/static/editor-app/configuration/properties.js

@@ -0,0 +1,99 @@
+/*
+ * Activiti Modeler component part of the Activiti project
+ * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+'use strict';
+
+var KISBPM = KISBPM || {};
+KISBPM.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"
+    },
+    "kisbpm-multiinstance" : {
+        "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/multiinstance-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-complex": {
+        "readModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-display-template.html",
+        "writeModeTemplateUrl": "editor-app/configuration/properties/subprocess-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"
+    }
+};

+ 37 - 0
itdmWeb/public/static/editor-app/configuration/properties/assignment-candidateGroup.html

@@ -0,0 +1,37 @@
+<div class="modal" ng-controller="KisBpmChoseCandidateGroupsCtrl">
+    <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" style="min-height: 350px;overflow: auto;">
+                <div class="row row-no-gutter" style="padding: 0 20px">
+                    <table class="table table-bordered table-condensed table-hover table-striped">
+                        <thead>
+                        <tr class="active">
+                            <th style="text-align: center">序号</th>
+                            <th style="text-align: center">组名</th>
+                            <th style="text-align: center">描述</th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <tr style="text-align: center" ng-repeat="candidateGroup in candidateGroups"
+                            ng-class="candidateGroup.selected==true?'info':''" ng-click="rowClick(candidateGroup.id)">
+                            <td>{{$index+1}}</td>
+                            <td>{{candidateGroup.name}}</td>
+                            <td>{{candidateGroup.description}}</td>
+                        </tr>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+            <div class="modal-footer">
+               <!-- <button type="button" class="btn btn-default"ng-click="selectAll()">全选</button> -->
+                <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
itdmWeb/public/static/editor-app/configuration/properties/assignment-display-template.html

@@ -0,0 +1,4 @@
+<span ng-if="property.value.assignment.assignee">{{'PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY' | translate:property.value.assignment }} </span>
+<span ng-if="property.value.assignment.candidateUsers.length > 0">{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.candidateUsers}} </span>
+<span ng-if="property.value.assignment.candidateGroups.length > 0">{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.candidateGroups}} </span>
+<span ng-if="!property.value.assignment.assignee && (!property.value.assignment.candidateUsers || property.value.assignment.candidateUsers.length == 0) && (!property.value.assignment.candidateGroups || property.value.assignment.candidateGroups.length == 0)" translate>PROPERTY.ASSIGNMENT.EMPTY</span>

+ 61 - 0
itdmWeb/public/static/editor-app/configuration/properties/assignment-popup-popup.html

@@ -0,0 +1,61 @@
+<div class="modal" ng-controller="KisBpmChoseAssignmentCtrl">
+    <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" style="height: 450px;">
+                <div class="row row-no-gutter" style="padding: 0 20px 10px 20px">
+                    <div class="btn-group btn-group-sm">
+                        <!-- <button type="button" class="btn btn-default"
+                                ng-click="queryByRole('oa_user')"> 全部
+                        </button> -->
+                      <!--  <button type="button" class="btn btn-default" ng-repeat="role in roles"
+                                ng-click="queryByRole(role.id)"> {{role.name}}
+                        </button> -->
+                    </div>
+                </div>
+                <div class="row row-no-gutter" style="padding: 0 20px;height: 370px;overflow-x: auto">
+
+                    <div class="input-group col-md-6 input-group-sm" style="padding: 10px 0 5px 0">
+                        <input type="text" class="form-control" placeholder="请输入用户姓名或用户名" ng-model="keyword">
+                        <span class="input-group-btn">
+                            <button class="btn btn-default" type="button" ng-click="queryByKeyword()"><span class="glyphicon glyphicon-search"></span></button>
+                        </span>
+                    </div>
+
+                    <table id="userTable" class="table table-bordered table-condensed table-hover table-striped">
+                        <thead>
+                        <tr class="active">
+                            <th style="text-align: center;width: 100px">序号</th>
+                            <th style="text-align: center;width: 200px">姓名</th>
+                            <th style="text-align: center;width: 200px">用户名</th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <tr ng-repeat="account in accounts" style="text-align: center"
+                            ng-class="account.checked==true||account.selected==true?'info':''"
+                            ng-click="rowClick(account.id)">
+                            <td ng-value="account.name">{{$index+1}}</td>
+                            <td ng-value="account.name">{{account.name}}</td>
+                            <td>{{account.code}}</td>
+                        </tr>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+
+            <div class="modal-footer">
+                <tm-pagination conf="paginationConf"></tm-pagination>
+              <!--  <button ng-if="choseAssignmentFlag=='assignees'" type="button" class="btn btn-default"
+                        ng-click="selectAll()">全选
+                </button> -->
+                <button ng-click="close()" translate class="btn btn-inverse">ACTION.CANCEL</button>
+                <button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 111 - 0
itdmWeb/public/static/editor-app/configuration/properties/assignment-popup.html

@@ -0,0 +1,111 @@
+<div class="modal" ng-controller="KisBpmAssignmentPopupCtrl">
+    <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 style="padding:0 20px">
+                    <div class="row row-no-gutter">
+                        <div class="form-group">
+                            <label for="assigneeField">{{'PROPERTY.ASSIGNMENT.ASSIGNEE' | translate}}</label>
+
+                            <input type="text" id="assigneeShowField" class="form-control" readonly
+                                   ng-model="assignment.assigneeshowname"
+                                   placeholder="{{'PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER' | translate}}"
+                                   ng-click="choseAssignment('assignee')"
+                                   ng-value="candidateUser.choseAssigneeShowname"/>
+                            <input type="text" id="assigneeField" class="form-control" ng-hide="true"
+                                   ng-model="assignment.assignee"
+                                   placeholder="{{'PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER' | translate}}"
+                                   ng-value="candidateUser.choseAssignee"/>
+                        </div>
+                    </div>
+                    <div class="row row-no-gutter">
+                        <div class="form-group">
+                            <label for="userField">{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS' | translate}}</label>
+                            <div ng-repeat="candidateUser in assignment.candidateUsers">
+                                <input id="userNameField" class="form-control" type="text" readonly
+                                       ng-model="candidateUser.nameValue" ng-click="choseAssignment('assignees')"
+                                       ng-value="candidateUser.value"/>
+                                <input id="userField" class="form-control" type="text" ng-hide="true"
+                                       ng-model="candidateUser.value" ng-value="candidateUser.value"/>
+                                <i class="glyphicon glyphicon-minus clickable-property"
+                                   ng-click="removeCandidateUserValue($index)"></i>
+                                <i ng-if="$index == (assignment.candidateUsers.length - 1)"
+                                   class="glyphicon glyphicon-plus clickable-property"
+                                   ng-click="addCandidateUserValue($index)"></i>
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <label for="groupField">{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS' | translate}}</label>
+                            <div ng-repeat="candidateGroup in assignment.candidateGroups">
+                                <input id="groupNameField" class="form-control" type="text" readonly
+                                       ng-model="candidateGroup.nameValue" ng-click="choseCandidateGroups()"/>
+                                <input id="groupField" class="form-control" type="text" ng-model="candidateGroup.value"
+                                       ng-hide="true"/>
+                                <i class="glyphicon glyphicon-minus clickable-property"
+                                   ng-click="removeCandidateGroupValue($index)"></i>
+                                <i ng-if="$index == (assignment.candidateGroups.length - 1)"
+                                   class="glyphicon glyphicon-plus clickable-property"
+                                   ng-click="addCandidateGroupValue($index)"></i>
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <div>
+                                <label for="groupField">动态代理人</label>
+                            </div>
+                            <div class="btn-group">
+                                <button ng-click="dynCandidateUser({name:'申请人',code:'applyUser'})"
+                                        class="btn btn-default">申请人
+                                </button>
+                              <!--  <button ng-repeat="position in deptPositions" class="btn btn-default"
+                                        ng-click="dynCandidateUser(position)"> {{position.name}}
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'会签人员',code:'assignee'})"
+                                        class="btn btn-default">会签人员
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'信息审校人',code:'noticeReviewer'})"
+                                        class="btn btn-default">信息审校人
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'维修人',code:'repairsUser'})"
+                                        class="btn btn-default">接单人
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'采购员',code:'purchaser'})"
+                                        class="btn btn-default">采购员
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'采购部主任',code:'purchasingDirector'})"
+                                        class="btn btn-default">采购部主任
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'采购部分管领导',code:'procurementLeader'})"
+                                        class="btn btn-default">采购部分管领导
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'询价人',code:'repairsAskPerson'})"
+                                        class="btn btn-default">询价人
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'维修人',code:'repairsPerson'})"
+                                        class="btn btn-default">维修人
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'部门主任',code:'budgetDeptDto.deptDirectorId'})"
+                                        class="btn btn-default">部门主任
+                                </button>
+                                <button ng-click="dynCandidateUser({name:'部门分管领导',code:'budgetDeptDto.deptLeaderId'})"
+                                        class="btn btn-default">部门分管领导
+                                </button> -->
+                            </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>
+</div>

+ 4 - 0
itdmWeb/public/static/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="KisBpmAssignmentCtrl">
+</span>

+ 4 - 0
itdmWeb/public/static/editor-app/configuration/properties/boolean-property-template.html

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

+ 2 - 0
itdmWeb/public/static/editor-app/configuration/properties/condition-expression-display-template.html

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

+ 29 - 0
itdmWeb/public/static/editor-app/configuration/properties/condition-expression-popup.html

@@ -0,0 +1,29 @@
+
+<div class="modal" ng-controller="KisBpmConditionExpressionPopupCtrl">
+<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.SEQUENCEFLOW.CONDITION.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-3">{{'PROPERTY.SEQUENCEFLOW.CONDITION.STATIC' | translate}}</label>
+                <div class="col-xs-9">
+                    <textarea class="form-control" ng-model="conditionExpression.value" style="width:90%; height:100%; max-width: 100%; max-height: 100%; min-height: 100px"/>
+                </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>
+</div>

+ 4 - 0
itdmWeb/public/static/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="KisBpmConditionExpressionCtrl">
+</span>

+ 4 - 0
itdmWeb/public/static/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>

+ 3 - 0
itdmWeb/public/static/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>

+ 115 - 0
itdmWeb/public/static/editor-app/configuration/properties/event-listeners-popup.html

@@ -0,0 +1,115 @@
+
+<div class="modal" ng-controller="KisBpmEventListenersPopupCtrl">
+    <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}}</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" ng-grid="gridOptions"></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="selectedListeners.length > 0" class="col-xs-6">
+            			<div class="form-group">
+            	        	<label for="userField">{{'PROPERTY.EVENTLISTENERS.EVENTS' | translate}}</label>
+            	            <div ng-repeat="eventDefinition in selectedListeners[0].events">
+            	            	<select id="eventField" class="form-control" ng-model="eventDefinition.event" ng-change="listenerDetailsChanged()">
+            	            		<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)"></i>
+            		            <i class="glyphicon glyphicon-plus clickable-property" ng-click="addEventValue($index)"></i>
+            	            </div>
+            	            <div class="form-group">
+            			   		<label for="classField">{{'PROPERTY.EVENTLISTENERS.RETHROW' | translate}}</label>
+            			   		<input type="checkbox" id="rethrowField" class="form-control" ng-model="selectedListeners[0].rethrowEvent" ng-change="listenerDetailsChanged()" />
+            				</div>
+            	       	</div>
+                     </div>
+                     <div ng-show="selectedListeners.length > 0 && selectedListeners[0].events[0].event" class="col-xs-6">
+                     	<div class="form-group" ng-if="!selectedListeners[0].rethrowEvent">
+            		   		<label for="classField">{{'PROPERTY.EVENTLISTENERS.CLASS' | translate}}</label>
+            		   		<input type="text" id="classField" class="form-control" ng-model="selectedListeners[0].className" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="!selectedListeners[0].rethrowEvent">
+            		   		<label for="delegateExpressionField">{{'PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION' | translate}}</label>
+            		   		<input type="text" id="delegateExpressionField" class="form-control" ng-model="selectedListeners[0].delegateExpression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="!selectedListeners[0].rethrowEvent">
+            		   		<label for="entityTypeField">{{'PROPERTY.EVENTLISTENERS.ENTITYTYPE' | translate}}</label>
+            		   		<input type="text" id="entityTypeField" class="form-control" ng-model="selectedListeners[0].entityType" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="selectedListeners[0].rethrowEvent">
+            		   		<label for="delegateExpressionField">{{'PROPERTY.EVENTLISTENERS.RETHROWTYPE' | translate}}</label>
+            		   		<select id="rethrowTypeField" class="form-control" ng-model="selectedListeners[0].rethrowType" ng-change="rethrowTypeChanged()">
+                                <option>error</option>
+                                <option>message</option>
+                                <option>signal</option>
+                                <option>globalSignal</option>
+                            </select>
+            			</div>
+            			<div class="form-group" ng-if="selectedListeners[0].rethrowType === 'error'">
+            		   		<label for="errorCodeField">{{'PROPERTY.EVENTLISTENERS.ERRORCODE' | translate}}</label>
+            		   		<input type="text" id="errorCodeField" class="form-control" ng-model="selectedListeners[0].errorcode" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="selectedListeners[0].rethrowType === 'message'">
+            		   		<label for="messageNameField">{{'PROPERTY.EVENTLISTENERS.MESSAGENAME' | translate}}</label>
+            		   		<input type="text" id="messageNameField" class="form-control" ng-model="selectedListeners[0].messagename" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER' | translate}}" />
+            			</div>
+            			<div class="form-group" ng-if="selectedListeners[0].rethrowType === 'signal' || selectedListeners[0].rethrowType === 'globalSignal'">
+            		   		<label for="messageNameField">{{'PROPERTY.EVENTLISTENERS.SIGNALNAME' | translate}}</label>
+            		   		<input type="text" id="signalNameField" class="form-control" ng-model="selectedListeners[0].signalname" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER' | translate}}" />
+            			</div>
+                     </div>
+                     <div ng-show="selectedListeners.length == 0" 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
itdmWeb/public/static/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="KisBpmEventListenersCtrl">
+</span>

+ 3 - 0
itdmWeb/public/static/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
itdmWeb/public/static/editor-app/configuration/properties/execution-listeners-popup.html

@@ -0,0 +1,101 @@
+
+<div class="modal" ng-controller="KisBpmExecutionListenersPopupCtrl">
+    <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}}</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" ng-grid="gridOptions"></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="selectedListeners.length > 0">
+            
+                            <div class="form-group">
+            			   		<label for="eventField">{{'PROPERTY.EXECUTIONLISTENERS.EVENT' | translate}}</label>
+            			   		<select id="eventField" class="form-control" ng-model="selectedListeners[0].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="selectedListeners[0].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="selectedListeners[0].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="selectedListeners[0].delegateExpression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER' | translate}}" />
+            				</div>
+                        </div>
+                        <div ng-show="selectedListeners.length == 0" 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" ng-grid="gridFieldOptions"></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="selectedFields.length > 0">
+            
+            				<div class="form-group">
+            			   		<label for="nameField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME' | translate}}</label>
+            			   		<input type="text" id="nameField" class="form-control" ng-model="selectedFields[0].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="selectedFields[0].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="selectedFields[0].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="selectedFields[0].string" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER' | translate}}"></textarea>
+            				</div>
+                            
+                        </div>
+                        <div ng-show="selectedFields.length == 0" 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
itdmWeb/public/static/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="KisBpmExecutionListenersCtrl">
+</span>

+ 17 - 0
itdmWeb/public/static/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
itdmWeb/public/static/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>

+ 61 - 0
itdmWeb/public/static/editor-app/configuration/properties/fields-popup.html

@@ -0,0 +1,61 @@
+
+<div class="modal" ng-controller="KisBpmFieldsPopupCtrl">
+    <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}}</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" ng-grid="gridOptions"></div>
+			            <div class="pull-right">
+			                <div class="btn-group">
+			                    <a href="#" 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 href="#" 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 href="#" 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 href="#" 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="selectedFields.length > 0">
+
+			                <div class="form-group">
+                                <label for="fieldName">{{'PROPERTY.FIELDS.NAME' | translate}}</label>
+                                <input type="text" id="fieldName"  class="form-control" ng-model="selectedFields[0].name" placeholder="{{'PROPERTY.FIELDS.NAME.PLACEHOLDER' | translate}}" />
+                            </div>
+
+                            <div class="form-group">
+                            <label for="fieldStringValue">{{'PROPERTY.FIELDS.STRINGVALUE' | translate}}</label>
+                                <input type="text" id="fieldStringValue"  class="form-control" ng-model="selectedFields[0].stringValue" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER' | translate}}" />
+                            </div>
+
+                            <div class="form-group">
+                            <label for="fieldExpression">{{'PROPERTY.FIELDS.EXPRESSION' | translate}}</label>
+                                <input type="text" id="fieldExpression"  class="form-control" ng-model="selectedFields[0].expression" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER' | translate}}" />
+                            </div>
+
+                            <div class="form-group">
+                            <label for="fieldString">{{'PROPERTY.FIELDS.STRING' | translate}}</label>
+			                        <textarea type="text" id="fieldString"  class="form-control" ng-model="selectedFields[0].string" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.STRING.PLACEHOLDER' | translate}}"></textarea>
+                            </div>
+
+			            </div>
+			            <div ng-show="selectedFields.length == 0" 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
itdmWeb/public/static/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="KisBpmFieldsCtrl">
+</span>

+ 3 - 0
itdmWeb/public/static/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
itdmWeb/public/static/editor-app/configuration/properties/form-properties-popup.html

@@ -0,0 +1,117 @@
+
+<div class="modal" ng-controller="KisBpmFormPropertiesPopupCtrl">
+    <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}}</h2>
+            </div>
+            <div class="modal-body">
+            
+                <div class="row row-no-gutter">
+                    <div class="col-xs-6">
+                        <div ng-if="translationsRetrieved" class="default-grid" ng-grid="gridOptions"></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="selectedProperties.length > 0">
+            
+                            <div class="form-group">
+            			   		<label for="idField">{{'PROPERTY.FORMPROPERTIES.ID' | translate}}</label>
+            			   		<input id="idField" class="form-control" type="text" ng-model="selectedProperties[0].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="selectedProperties[0].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="selectedProperties[0].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="selectedProperties[0].datePattern">
+            			   		<label for="datePatternField">{{'PROPERTY.FORMPROPERTIES.DATEPATTERN' | translate}}</label>
+            			   		<input id="datePatternField" class="form-control" type="text" ng-model="selectedProperties[0].datePattern" placeholder="{{'PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER' | translate }}" />
+            				</div>
+                            <div ng-if="selectedProperties[0].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" ng-grid="enumGridOptions"></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="selectedEnumValues.length > 0">
+				            
+				                            <div class="form-group">
+				            			   		<label for="classField">{{'PROPERTY.FORMPROPERTIES.VALUES.ID' | translate}}</label>
+				            			   		<input type="text" id="classField" class="form-control" ng-model="selectedEnumValues[0].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="selectedEnumValues[0].name" placeholder="{{'PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER' | translate}}" />
+				            				</div>
+				                        </div>
+				                        <div ng-show="selectedEnumValues.length == 0" 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="selectedProperties[0].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="selectedProperties[0].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="form-control" type="checkbox" ng-model="selectedProperties[0].required" />
+            				   	</div>
+            				   	<div class="form-group col-xs-2">
+            				   		<label for="readableField">{{'PROPERTY.FORMPROPERTIES.READABLE' | translate}}</label>
+            				   		<input id="readableField" class="form-control" type="checkbox" ng-model="selectedProperties[0].readable" />
+            					</div>
+            					<div class="form-group col-xs-2">
+            						<label for="writableField">{{'PROPERTY.FORMPROPERTIES.WRITABLE' | translate}}</label>
+            			   			<input id="writableField" class="form-control" type="checkbox" ng-model="selectedProperties[0].writable" />
+            					</div>
+            				</div>
+                        </div>
+                        <div ng-show="selectedProperties.length == 0" 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
itdmWeb/public/static/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="KisBpmFormPropertiesCtrl">
+</span>

+ 3 - 0
itdmWeb/public/static/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
itdmWeb/public/static/editor-app/configuration/properties/in-parameters-popup.html

@@ -0,0 +1,53 @@
+
+<div class="modal" ng-controller="KisBpmInParametersPopupCtrl">
+    <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}}</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" ng-grid="gridOptions"></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="selectedParameters.length > 0">
+							
+							<div class="form-group">
+						   		<label for="sourceField">{{'PROPERTY.PARAMETER.SOURCE' | translate}}</label>
+						   		<input type="text" id="sourceField" class="form-control" ng-model="selectedParameters[0].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="selectedParameters[0].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="selectedParameters[0].target" placeholder="{{'PROPERTY.PARAMETER.TARGET.PLACEHOLDER' | translate}}" />
+							</div>
+			                
+			            </div>
+			            <div ng-show="selectedParameters.length == 0" 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
itdmWeb/public/static/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="KisBpmInParametersCtrl">
+</span>

+ 2 - 0
itdmWeb/public/static/editor-app/configuration/properties/message-definitions-display-template.html

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

+ 50 - 0
itdmWeb/public/static/editor-app/configuration/properties/message-definitions-popup.html

@@ -0,0 +1,50 @@
+
+<div class="modal" ng-controller="ActivitiMessageDefinitionsPopupCtrl">
+    <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}}</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" ng-grid="gridOptions"></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="selectedMessages && selectedMessages.length > 0">
+
+                        <div class="form-group">
+                            <label>{{'PROPERTY.MESSAGEDEFINITIONS.ID' | translate}}</label>
+                            <input type="text" class="form-control" ng-model="selectedMessages[0].id">
+                        </div>
+
+                        <div class="form-group">
+                            <label>{{'PROPERTY.MESSAGEDEFINITIONS.NAME' | translate}}</label>
+                            <input type="text" class="form-control" ng-model="selectedMessages[0].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>

+ 3 - 0
itdmWeb/public/static/editor-app/configuration/properties/message-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="ActivitiMessageDefinitionsCtrl">
+</span>

+ 4 - 0
itdmWeb/public/static/editor-app/configuration/properties/message-property-write-template.html

@@ -0,0 +1,4 @@
+<div ng-controller="ActivitiMessageRefCtrl">
+    <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
itdmWeb/public/static/editor-app/configuration/properties/multiinstance-property-write-template.html

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

+ 3 - 0
itdmWeb/public/static/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
itdmWeb/public/static/editor-app/configuration/properties/out-parameters-popup.html

@@ -0,0 +1,53 @@
+
+<div class="modal" ng-controller="KisBpmOutParametersPopupCtrl">
+    <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}}</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" ng-grid="gridOptions"></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="selectedParameters.length > 0">
+							
+							<div class="form-group">
+						   		<label for="sourceField">{{'PROPERTY.PARAMETER.SOURCE' | translate}}</label>
+						   		<input type="text" id="sourceField" class="form-control" ng-model="selectedParameters[0].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="selectedParameters[0].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="selectedParameters[0].target" placeholder="{{'PROPERTY.PARAMETER.TARGET.PLACEHOLDER' | translate}}" />
+							</div>
+			                
+			            </div>
+			            <div ng-show="selectedParameters.length == 0" 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
itdmWeb/public/static/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="KisBpmOutParametersCtrl">
+</span>

+ 3 - 0
itdmWeb/public/static/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
itdmWeb/public/static/editor-app/configuration/properties/sequenceflow-order-popup.html

@@ -0,0 +1,47 @@
+
+<div class="modal" ng-controller="KisBpmSequenceFlowOrderPopupCtrl">
+    <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}}</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
itdmWeb/public/static/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="KisBpmSequenceFlowOrderCtrl">
+</span>

+ 3 - 0
itdmWeb/public/static/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>

+ 0 - 0
itdmWeb/public/static/editor-app/configuration/properties/signal-definitions-popup.html


Some files were not shown because too many files changed in this diff