You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					1508 lines
				
				68 KiB
			
		
		
			
		
	
	
					1508 lines
				
				68 KiB
			| 
											1 year ago
										 | /* Licensed under the Apache License, Version 2.0 (the "License"); | ||
|  |  * you may not use this file except in compliance with the License. | ||
|  |  * You may obtain a copy of the License at | ||
|  |  *  | ||
|  |  *      http://www.apache.org/licenses/LICENSE-2.0
 | ||
|  |  *  | ||
|  |  * Unless required by applicable law or agreed to in writing, software | ||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
|  |  * See the License for the specific language governing permissions and | ||
|  |  * limitations under the License. | ||
|  |  */ | ||
|  | 
 | ||
|  | 'use strict'; | ||
|  | 
 | ||
|  | angular.module('flowableModeler') | ||
|  |     .controller('StencilController', ['$rootScope', '$scope', '$http', '$modal', '$timeout', '$window', 'editorManager', | ||
|  |                                       function ($rootScope, $scope, $http, $modal, $timeout, $window, editorManager) { | ||
|  | 
 | ||
|  |         // Property window toggle state
 | ||
|  |         $scope.propertyWindowState = {'collapsed': false}; | ||
|  | 
 | ||
|  |         // Add reference to global header-config
 | ||
|  |         $scope.headerConfig = FLOWABLE.HEADER_CONFIG; | ||
|  | 
 | ||
|  |         $scope.propertyWindowState.toggle = function () { | ||
|  |             $scope.propertyWindowState.collapsed = !$scope.propertyWindowState.collapsed; | ||
|  |             $timeout(function () { | ||
|  |                 $window.dispatchEvent(new Event("resize")); | ||
|  |             }, 100); | ||
|  |         }; | ||
|  | 
 | ||
|  |         // Code that is dependent on an initialised Editor is wrapped in a promise for the editor
 | ||
|  |         $scope.editorFactory.promise.then(function () { | ||
|  |          | ||
|  |         	/* Build stencil item list */ | ||
|  | 
 | ||
|  |             // Build simple json representation of stencil set
 | ||
|  |             var stencilItemGroups = []; | ||
|  | 
 | ||
|  |             // Helper method: find a group in an array
 | ||
|  |             var findGroup = function (name, groupArray) { | ||
|  |                 for (var index = 0; index < groupArray.length; index++) { | ||
|  |                     if (groupArray[index].name === name) { | ||
|  |                         return groupArray[index]; | ||
|  |                     } | ||
|  |                 } | ||
|  |                 return null; | ||
|  |             }; | ||
|  | 
 | ||
|  |             // Helper method: add a new group to an array of groups
 | ||
|  |             var addGroup = function (groupName, groupArray) { | ||
|  |                 var group = { name: groupName, items: [], paletteItems: [], groups: [], visible: true }; | ||
|  |                 groupArray.push(group); | ||
|  |                 return group; | ||
|  |             }; | ||
|  | 
 | ||
|  |             /* | ||
|  |              StencilSet items | ||
|  |              */ | ||
|  |             var data = editorManager.getStencilData(); | ||
|  | 
 | ||
|  |             var quickMenuDefinition = undefined; | ||
|  |             var ignoreForPaletteDefinition = undefined; | ||
|  |              | ||
|  |             if (data.namespace == 'http://b3mn.org/stencilset/cmmn1.1#') { | ||
|  |                 quickMenuDefinition = ['HumanTask', 'Association']; | ||
|  |                 ignoreForPaletteDefinition = ['CasePlanModel']; | ||
|  |                  | ||
|  |             } else if (data.namespace == 'http://b3mn.org/stencilset/dmn1.2#') { | ||
|  |                 quickMenuDefinition = ['DecisionTableDecision', 'InformationRequirement', 'KnowledgeRequirement']; | ||
|  |                 ignoreForPaletteDefinition = []; | ||
|  |             } else { | ||
|  |                 quickMenuDefinition = ['UserTask', 'EndNoneEvent', 'ExclusiveGateway',  | ||
|  |                                          'CatchTimerEvent', 'ThrowNoneEvent', 'TextAnnotation', | ||
|  |                                          'SequenceFlow', 'Association']; | ||
|  |                                           | ||
|  |                 ignoreForPaletteDefinition = ['SequenceFlow', 'MessageFlow', 'Association', 'DataAssociation', 'DataStore', 'SendTask']; | ||
|  |             } | ||
|  |               | ||
|  |             var quickMenuItems = []; | ||
|  |                | ||
|  |             var morphRoles = []; | ||
|  |             for (var i = 0; i < data.rules.morphingRules.length; i++)  | ||
|  |             { | ||
|  |                 var role = data.rules.morphingRules[i].role; | ||
|  |                 var roleItem = {'role': role, 'morphOptions': []}; | ||
|  |                 morphRoles.push(roleItem); | ||
|  |             } | ||
|  |            | ||
|  |             // Check all received items
 | ||
|  |             for (var stencilIndex = 0; stencilIndex < data.stencils.length; stencilIndex++) { | ||
|  |              | ||
|  |                 // Check if the root group is the 'diagram' group. If so, this item should not be shown.
 | ||
|  |                 var currentGroupName = data.stencils[stencilIndex].groups[0]; | ||
|  |                 if (currentGroupName === 'Diagram' || currentGroupName === 'BPMN.STENCILS.GROUPS.DIAGRAM' ||  | ||
|  |                         currentGroupName === 'CMMN.STENCILS.GROUPS.DIAGRAM' || | ||
|  |                         currentGroupName === 'DMN.STENCILS.GROUPS.DIAGRAM') { | ||
|  |                          | ||
|  |                     continue;  // go to next item
 | ||
|  |                 } | ||
|  |                  | ||
|  |                 var removed = false; | ||
|  |                 if (data.stencils[stencilIndex].removed) { | ||
|  |                     removed = true; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 var currentGroup = undefined; | ||
|  |                 if (!removed) { | ||
|  |                     // Check if this group already exists. If not, we create a new one
 | ||
|  | 
 | ||
|  |                     if (currentGroupName !== null && currentGroupName !== undefined && currentGroupName.length > 0) { | ||
|  | 
 | ||
|  |                         currentGroup = findGroup(currentGroupName, stencilItemGroups); // Find group in root groups array
 | ||
|  |                         if (currentGroup === null) { | ||
|  |                             currentGroup = addGroup(currentGroupName, stencilItemGroups); | ||
|  |                         } | ||
|  | 
 | ||
|  |                         // Add all child groups (if any)
 | ||
|  |                         for (var groupIndex = 1; groupIndex < data.stencils[stencilIndex].groups.length; groupIndex++) { | ||
|  |                             var childGroupName = data.stencils[stencilIndex].groups[groupIndex]; | ||
|  |                             var childGroup = findGroup(childGroupName, currentGroup.groups); | ||
|  |                             if (childGroup === null) { | ||
|  |                                 childGroup = addGroup(childGroupName, currentGroup.groups); | ||
|  |                             } | ||
|  | 
 | ||
|  |                             // The current group variable holds the parent of the next group (if any),
 | ||
|  |                             // and is basically the last element in the array of groups defined in the stencil item
 | ||
|  |                             currentGroup = childGroup; | ||
|  | 
 | ||
|  |                         } | ||
|  | 
 | ||
|  |                     } | ||
|  |                 } | ||
|  |                  | ||
|  |                 // Construct the stencil item
 | ||
|  |                 var stencilItem = {'id': data.stencils[stencilIndex].id, | ||
|  |                     'name': data.stencils[stencilIndex].title, | ||
|  |                     'description': data.stencils[stencilIndex].description, | ||
|  |                     'icon': data.stencils[stencilIndex].icon, | ||
|  |                     'type': data.stencils[stencilIndex].type, | ||
|  |                     'roles': data.stencils[stencilIndex].roles, | ||
|  |                     'removed': removed, | ||
|  |                     'customIcon': false, | ||
|  |                     'canConnect': false, | ||
|  |                     'canConnectTo': false, | ||
|  |                     'canConnectAssociation': false}; | ||
|  |                  | ||
|  |                 if (data.stencils[stencilIndex].customIconId && data.stencils[stencilIndex].customIconId > 0) { | ||
|  |                     stencilItem.customIcon = true; | ||
|  |                     stencilItem.icon = data.stencils[stencilIndex].customIconId; | ||
|  |                 } | ||
|  |                  | ||
|  |                 if (!removed) { | ||
|  |                     if (quickMenuDefinition.indexOf(stencilItem.id) >= 0) { | ||
|  |                       quickMenuItems[quickMenuDefinition.indexOf(stencilItem.id)] = stencilItem; | ||
|  |                     } | ||
|  |                 } | ||
|  |                  | ||
|  |                 if (stencilItem.id === 'TextAnnotation' || stencilItem.id === 'BoundaryCompensationEvent') { | ||
|  |                   stencilItem.canConnectAssociation = true; | ||
|  |                 } | ||
|  |                  | ||
|  |                 for (var i = 0; i < data.stencils[stencilIndex].roles.length; i++) { | ||
|  |                   var stencilRole = data.stencils[stencilIndex].roles[i]; | ||
|  |                   if (data.namespace == 'http://b3mn.org/stencilset/cmmn1.1#') { | ||
|  |                       if (stencilRole === 'association_start') { | ||
|  |                         stencilItem.canConnect = true; | ||
|  |                       } else if (stencilRole === 'association_end') { | ||
|  |                         stencilItem.canConnectTo = true; | ||
|  |                       } | ||
|  |                   } else if (data.namespace == 'http://b3mn.org/stencilset/dmn1.2#') { | ||
|  |                       if (stencilRole === 'information_requirement_start') { | ||
|  |                           stencilItem.canConnect = true; | ||
|  |                       } else if (stencilRole === 'information_requirement_end') { | ||
|  |                           stencilItem.canConnectTo = true; | ||
|  |                       } | ||
|  |                   } else { | ||
|  |                       if (stencilRole === 'sequence_start') { | ||
|  |                         stencilItem.canConnect = true; | ||
|  |                       } else if (stencilRole === 'sequence_end') { | ||
|  |                         stencilItem.canConnectTo = true; | ||
|  |                       } | ||
|  |                   } | ||
|  |                    | ||
|  |                   for (var j = 0; j < morphRoles.length; j++) { | ||
|  |                     if (stencilRole === morphRoles[j].role) { | ||
|  |                       if (!removed) { | ||
|  |                         morphRoles[j].morphOptions.push(stencilItem); | ||
|  |                       } | ||
|  |                       stencilItem.morphRole = morphRoles[j].role; | ||
|  |                       break; | ||
|  |                     } | ||
|  |                   } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (currentGroup) { | ||
|  |                   // Add the stencil item to the correct group
 | ||
|  |                   currentGroup.items.push(stencilItem); | ||
|  |                   if (ignoreForPaletteDefinition.indexOf(stencilItem.id) < 0) { | ||
|  |                     currentGroup.paletteItems.push(stencilItem); | ||
|  |                   } | ||
|  | 
 | ||
|  |                 } else { | ||
|  |                     // It's a root stencil element
 | ||
|  |                     if (!removed) { | ||
|  |                         stencilItemGroups.push(stencilItem); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |              | ||
|  |             for (var i = 0; i < stencilItemGroups.length; i++)  { | ||
|  |               if (stencilItemGroups[i].paletteItems && stencilItemGroups[i].paletteItems.length == 0) { | ||
|  |                 stencilItemGroups[i].visible = false; | ||
|  |               } | ||
|  |             } | ||
|  |              | ||
|  |             $scope.stencilItemGroups = stencilItemGroups; | ||
|  | 
 | ||
|  |             var containmentRules = []; | ||
|  |             for (var i = 0; i < data.rules.containmentRules.length; i++) { | ||
|  |                 var rule = data.rules.containmentRules[i]; | ||
|  |                 containmentRules.push(rule); | ||
|  |             } | ||
|  |             $scope.containmentRules = containmentRules; | ||
|  |              | ||
|  |             // remove quick menu items which are not available anymore due to custom pallette
 | ||
|  |             var availableQuickMenuItems = []; | ||
|  |             for (var i = 0; i < quickMenuItems.length; i++) { | ||
|  |                 if (quickMenuItems[i]) { | ||
|  |                     availableQuickMenuItems[availableQuickMenuItems.length] = quickMenuItems[i]; | ||
|  |                 } | ||
|  |             } | ||
|  |              | ||
|  |             $scope.quickMenuItems = availableQuickMenuItems; | ||
|  |             $scope.morphRoles = morphRoles; | ||
|  | 
 | ||
|  |             /* | ||
|  |              * Listen to selection change events: show properties | ||
|  |              */ | ||
|  |             editorManager.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) { | ||
|  |                 var shapes = event.elements; | ||
|  |                 var canvasSelected = false; | ||
|  |                 if (shapes && shapes.length == 0) { | ||
|  |                     shapes = [editorManager.getCanvas()]; | ||
|  |                     canvasSelected = true; | ||
|  |                 } | ||
|  |                 if (shapes && shapes.length > 0) { | ||
|  | 
 | ||
|  |                     var selectedShape = shapes.first(); | ||
|  |                     var stencil = selectedShape.getStencil(); | ||
|  |                      | ||
|  |                     if ($rootScope.selectedElementBeforeScrolling && stencil.id().indexOf('BPMNDiagram') !== -1 && stencil.id().indexOf('CMMNDiagram') !== -1 && | ||
|  |                         stencil.id().indexOf('DMNDiagram') !== -1) { | ||
|  |                       // ignore canvas event because of empty selection when scrolling stops
 | ||
|  |                       return; | ||
|  |                     } | ||
|  |                      | ||
|  |                     if ($rootScope.selectedElementBeforeScrolling && $rootScope.selectedElementBeforeScrolling.getId() === selectedShape.getId()) { | ||
|  |                       $rootScope.selectedElementBeforeScrolling = null; | ||
|  |                       return; | ||
|  |                     } | ||
|  | 
 | ||
|  |                     // Store previous selection
 | ||
|  |                     $scope.previousSelectedShape = $scope.selectedShape; | ||
|  |                      | ||
|  |                     // Only do something if another element is selected (Oryx fires this event multiple times)
 | ||
|  |                     if ($scope.selectedShape !== undefined && $scope.selectedShape.getId() === selectedShape.getId()) { | ||
|  |                         if ($rootScope.forceSelectionRefresh) { | ||
|  |                             // Switch the flag again, this run will force refresh
 | ||
|  |                             $rootScope.forceSelectionRefresh = false; | ||
|  |                         } else { | ||
|  |                             // Selected the same element again, no need to update anything
 | ||
|  |                             return; | ||
|  |                         } | ||
|  |                     } | ||
|  | 
 | ||
|  |                     var selectedItem = {'title': '', 'properties': []}; | ||
|  | 
 | ||
|  |                     if (canvasSelected) { | ||
|  |                         selectedItem.auditData = { | ||
|  |                             'author': $scope.modelData.createdByUser, | ||
|  |                             'createDate': $scope.modelData.createDate | ||
|  |                         }; | ||
|  |                     } | ||
|  | 
 | ||
|  |                     // Gather properties of selected item
 | ||
|  |                     var properties = stencil.properties(); | ||
|  |                     for (var i = 0; i < properties.length; i++) { | ||
|  |                         var property = properties[i]; | ||
|  |                         if (property.popular() == false) continue; | ||
|  |                         var key = property.prefix() + "-" + property.id(); | ||
|  | 
 | ||
|  |                         if (key === 'oryx-name') { | ||
|  |                             selectedItem.title = selectedShape.properties.get(key); | ||
|  |                         } | ||
|  | 
 | ||
|  |                         // First we check if there is a config for 'key-type' and then for 'type' alone
 | ||
|  |                         var propertyConfig = FLOWABLE.PROPERTY_CONFIG[key + '-' + property.type()]; | ||
|  |                         if (propertyConfig === undefined || propertyConfig === null) { | ||
|  |                             propertyConfig = FLOWABLE.PROPERTY_CONFIG[property.type()]; | ||
|  |                         } | ||
|  | 
 | ||
|  |                         if (propertyConfig === undefined || propertyConfig === null) { | ||
|  |                             console.log('WARNING: no property configuration defined for ' + key + ' of type ' + property.type()); | ||
|  |                         } else { | ||
|  | 
 | ||
|  |                             if (selectedShape.properties.get(key) === 'true') { | ||
|  |                                 selectedShape.properties.set(key, true); | ||
|  |                             } | ||
|  |                              | ||
|  |                             if (FLOWABLE.UI_CONFIG.showRemovedProperties == false && property.isHidden()) | ||
|  |                             { | ||
|  |                               continue; | ||
|  |                             } | ||
|  | 
 | ||
|  |                             var currentProperty = { | ||
|  |                                 'key': key, | ||
|  |                                 'title': property.title(), | ||
|  |                                 'description': property.description(), | ||
|  |                                 'type': property.type(), | ||
|  |                                 'mode': 'read', | ||
|  |                                 'readonly': property.readonly(), | ||
|  |                                 'hidden': property.isHidden(), | ||
|  |                                 'value': selectedShape.properties.get(key) | ||
|  |                             }; | ||
|  |                              | ||
|  |                             if ((currentProperty.type === 'complex' || currentProperty.type === 'multiplecomplex') && currentProperty.value && currentProperty.value.length > 0) { | ||
|  |                                 try { | ||
|  |                                     currentProperty.value = JSON.parse(currentProperty.value); | ||
|  |                                 } catch (err) { | ||
|  |                                     // ignore
 | ||
|  |                                 } | ||
|  |                             } | ||
|  | 
 | ||
|  |                             if (propertyConfig.readModeTemplateUrl !== undefined && propertyConfig.readModeTemplateUrl !== null) { | ||
|  |                                 currentProperty.readModeTemplateUrl = propertyConfig.readModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; | ||
|  |                             } | ||
|  |                             if (propertyConfig.writeModeTemplateUrl !== null && propertyConfig.writeModeTemplateUrl !== null) { | ||
|  |                               currentProperty.writeModeTemplateUrl = propertyConfig.writeModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; | ||
|  |                             } | ||
|  | 
 | ||
|  |                             if ((currentProperty.readonly && propertyConfig.templateUrl !== undefined && propertyConfig.templateUrl !== null) || | ||
|  |                                 (currentProperty.readonly === undefined && propertyConfig.templateUrl !== undefined && propertyConfig.templateUrl !== null)) { | ||
|  |                                 currentProperty.templateUrl = propertyConfig.templateUrl + '?version=' + $rootScope.staticIncludeVersion; | ||
|  |                                 currentProperty.hasReadWriteMode = false; | ||
|  |                             } | ||
|  |                             else { | ||
|  |                                 currentProperty.hasReadWriteMode = true; | ||
|  |                             } | ||
|  | 
 | ||
|  |                             if (currentProperty.value === undefined | ||
|  |                                 || currentProperty.value === null | ||
|  |                                 || currentProperty.value.length == 0) { | ||
|  |                                 currentProperty.noValue = true; | ||
|  |                             } | ||
|  | 
 | ||
|  |                             selectedItem.properties.push(currentProperty); | ||
|  |                         } | ||
|  |                     } | ||
|  | 
 | ||
|  |                     // Need to wrap this in an $apply block, see http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
 | ||
|  |                     $scope.safeApply(function () { | ||
|  |                         $scope.selectedItem = selectedItem; | ||
|  |                         $scope.selectedShape = selectedShape; | ||
|  |                     }); | ||
|  | 
 | ||
|  |                 } else { | ||
|  |                     $scope.safeApply(function () { | ||
|  |                         $scope.selectedItem = {}; | ||
|  |                         $scope.selectedShape = null; | ||
|  |                     }); | ||
|  |                 } | ||
|  |             }); | ||
|  |              | ||
|  |             editorManager.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) { | ||
|  |                | ||
|  |               FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); | ||
|  |               var shapes = event.elements; | ||
|  |                  | ||
|  |               if (shapes && shapes.length == 1) { | ||
|  | 
 | ||
|  |               	  var selectedShape = shapes.first(); | ||
|  |                | ||
|  |                   var a = editorManager.getCanvas().node.getScreenCTM(); | ||
|  |                | ||
|  | 	              var absoluteXY = selectedShape.absoluteXY(); | ||
|  | 	               | ||
|  | 	              absoluteXY.x *= a.a; | ||
|  | 	              absoluteXY.y *= a.d; | ||
|  | 	               | ||
|  | 	              var additionalIEZoom = 1; | ||
|  | 	              if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { | ||
|  |                         var ua = navigator.userAgent; | ||
|  |                         if (ua.indexOf('MSIE') >= 0) { | ||
|  |                             //IE 10 and below
 | ||
|  |                             var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); | ||
|  |                             if (zoom !== 100) { | ||
|  |                                 additionalIEZoom = zoom / 100 | ||
|  |                             } | ||
|  |                         } | ||
|  |                   } | ||
|  | 	                     | ||
|  | 	              if (additionalIEZoom === 1) { | ||
|  | 	                   absoluteXY.y = absoluteXY.y - jQuery("#canvasSection").offset().top + 5; | ||
|  | 	                         absoluteXY.x = absoluteXY.x - jQuery("#canvasSection").offset().left; | ||
|  | 	               | ||
|  | 	              } else { | ||
|  | 	                   var canvasOffsetLeft = jQuery("#canvasSection").offset().left; | ||
|  | 	                   var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); | ||
|  | 	                   var canvasScrollTop = jQuery("#canvasSection").scrollTop(); | ||
|  | 	                    | ||
|  | 	                   var offset = a.e - (canvasOffsetLeft * additionalIEZoom); | ||
|  | 	                   var additionaloffset = 0; | ||
|  | 	                   if (offset > 10) { | ||
|  | 	                       additionaloffset = (offset / additionalIEZoom) - offset; | ||
|  | 	                   } | ||
|  | 	                   absoluteXY.y = absoluteXY.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + 5 + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop); | ||
|  | 	                         absoluteXY.x = absoluteXY.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft); | ||
|  |                   } | ||
|  | 	               | ||
|  | 	              var bounds = new ORYX.Core.Bounds(a.e + absoluteXY.x, a.f + absoluteXY.y, a.e + absoluteXY.x + a.a*selectedShape.bounds.width(), a.f + absoluteXY.y + a.d*selectedShape.bounds.height()); | ||
|  | 	              var shapeXY = bounds.upperLeft(); | ||
|  | 	               | ||
|  | 	              var stencilItem = $scope.getStencilItemById(selectedShape.getStencil().idWithoutNs()); | ||
|  | 	              var morphShapes = []; | ||
|  | 	              if (stencilItem && stencilItem.morphRole) { | ||
|  | 	                  for (var i = 0; i < $scope.morphRoles.length; i++) { | ||
|  | 						  if ($scope.morphRoles[i].role === stencilItem.morphRole) { | ||
|  | 	                    	  morphShapes = $scope.morphRoles[i].morphOptions; | ||
|  | 	                      } | ||
|  | 	                  } | ||
|  | 	              } | ||
|  |                | ||
|  |               	  var x = shapeXY.x; | ||
|  |             	  if (bounds.width() < 48) { | ||
|  |               		  x -= 24; | ||
|  |             	  } | ||
|  |                | ||
|  |               	  if (morphShapes && morphShapes.length > 0) { | ||
|  |                 	// In case the element is not wide enough, start the 2 bottom-buttons more to the left
 | ||
|  |                 	// to prevent overflow in the right-menu
 | ||
|  |                  | ||
|  |                 	var morphButton = document.getElementById('morph-button'); | ||
|  |                 	morphButton.style.display = "block"; | ||
|  |                 	morphButton.style.left = x + 24 +'px'; | ||
|  |                 	morphButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px'; | ||
|  |               	  } | ||
|  |                | ||
|  |               	  var deleteButton = document.getElementById('delete-button'); | ||
|  |               	  deleteButton.style.display = "block"; | ||
|  |               	  deleteButton.style.left = x + 'px'; | ||
|  |               	  deleteButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px'; | ||
|  |               	   | ||
|  |               	  var editable = selectedShape._stencil._jsonStencil.id.endsWith('CollapsedSubProcess') ; | ||
|  | 				  var editButton = document.getElementById('edit-button'); | ||
|  | 				  if (editable) { | ||
|  | 				      editButton.style.display = "block"; | ||
|  |  					  if (morphShapes && morphShapes.length > 0) { | ||
|  | 						editButton.style.left = x + 24 + 24 + 'px'; | ||
|  | 				      } else { | ||
|  | 					 	editButton.style.left = x + 24 +'px'; | ||
|  | 					  } | ||
|  | 					  editButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px'; | ||
|  | 					   | ||
|  | 				  } else { | ||
|  | 					  editButton.style.display = "none"; | ||
|  | 				  } | ||
|  |                | ||
|  |               	  if (stencilItem && (stencilItem.canConnect || stencilItem.canConnectAssociation)) { | ||
|  | 	                var quickButtonCounter = 0; | ||
|  | 	                var quickButtonX = shapeXY.x+bounds.width() + 5; | ||
|  | 	                var quickButtonY = shapeXY.y; | ||
|  | 	                jQuery('.Oryx_button').each(function(i, obj) { | ||
|  | 	                  if (obj.id !== 'morph-button' && obj.id != 'delete-button' && obj.id !== 'edit-button') { | ||
|  | 	                    quickButtonCounter++; | ||
|  | 	                    if (quickButtonCounter > 3) { | ||
|  | 	                      quickButtonX = shapeXY.x+bounds.width() + 5; | ||
|  | 	                      quickButtonY += 24; | ||
|  | 	                      quickButtonCounter = 1; | ||
|  | 	                       | ||
|  | 	                    } else if (quickButtonCounter > 1) { | ||
|  | 	                      quickButtonX += 24; | ||
|  | 	                    } | ||
|  | 	                     | ||
|  | 	                    obj.style.display = "block"; | ||
|  | 	                    obj.style.left = quickButtonX + 'px'; | ||
|  | 	                    obj.style.top = quickButtonY + 'px'; | ||
|  | 	                  } | ||
|  | 	                }); | ||
|  |                   } | ||
|  |                } | ||
|  |             }); | ||
|  |              | ||
|  |             if (!$rootScope.stencilInitialized) { | ||
|  |               FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS, function (event) { | ||
|  |                 jQuery('.Oryx_button').each(function(i, obj) { | ||
|  |                   obj.style.display = "none"; | ||
|  |               }); | ||
|  |               }); | ||
|  | 
 | ||
|  |               /* | ||
|  |                * Listen to property updates and act upon them | ||
|  |                */ | ||
|  |               FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, function (event) { | ||
|  |                   if (event.property && event.property.key) { | ||
|  |                       // If the name property is been updated, we also need to change the title of the currently selected item
 | ||
|  |                       if (event.property.key === 'oryx-name' && $scope.selectedItem !== undefined && $scope.selectedItem !== null) { | ||
|  |                           $scope.selectedItem.title = event.newValue; | ||
|  |                       } | ||
|  | 
 | ||
|  |                       // Update "no value" flag
 | ||
|  |                       event.property.noValue = (event.property.value === undefined | ||
|  |                           || event.property.value === null | ||
|  |                           || event.property.value.length == 0); | ||
|  |                   } | ||
|  |               }); | ||
|  |                | ||
|  |               FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_SHOW_VALIDATION_POPUP, function (event) { | ||
|  |                   // Method to open validation dialog
 | ||
|  |                   var showValidationDialog = function() { | ||
|  |                       $rootScope.currentValidationId = event.validationId; | ||
|  |                       $rootScope.isOnProcessLevel = event.onProcessLevel; | ||
|  | 
 | ||
|  |                       _internalCreateModal({template: 'editor-app/popups/validation-errors.html?version=' + Date.now()},  $modal, $rootScope); | ||
|  |                   }; | ||
|  | 
 | ||
|  |                   showValidationDialog(); | ||
|  |               }); | ||
|  |                | ||
|  |               FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_NAVIGATE_TO_PROCESS, function (event) { | ||
|  |                   var modelMetaData = editorManager.getBaseModelData(); | ||
|  |                   $rootScope.editorHistory.push({ | ||
|  |                         id: modelMetaData.modelId,  | ||
|  |                         name: modelMetaData.name,  | ||
|  |                         type: 'bpmnmodel' | ||
|  |                   }); | ||
|  |                    | ||
|  |               	  $window.location.href = "../editor/#/editor/" + event.processId; | ||
|  |               }); | ||
|  |                | ||
|  |               $rootScope.stencilInitialized = true; | ||
|  |             } | ||
|  |              | ||
|  |             $scope.morphShape = function() { | ||
|  |               $scope.safeApply(function () { | ||
|  |                  | ||
|  |                 var shapes = editorManager.getSelection(); | ||
|  |                 if (shapes && shapes.length == 1) { | ||
|  |                   $rootScope.currentSelectedShape = shapes.first(); | ||
|  |                   var stencilItem = $scope.getStencilItemById($rootScope.currentSelectedShape.getStencil().idWithoutNs()); | ||
|  |                   var morphShapes = []; | ||
|  |                   for (var i = 0; i < $scope.morphRoles.length; i++) { | ||
|  |                     if ($scope.morphRoles[i].role === stencilItem.morphRole) { | ||
|  |                     	morphShapes = $scope.morphRoles[i].morphOptions.slice(); | ||
|  |                     } | ||
|  |                   } | ||
|  | 
 | ||
|  |                   // Method to open shape select dialog (used later on)
 | ||
|  |                         var showSelectShapeDialog = function() | ||
|  |                         { | ||
|  |                             $rootScope.morphShapes = morphShapes; | ||
|  |                             _internalCreateModal({ | ||
|  |                                 backdrop: false, | ||
|  |                                 keyboard: true, | ||
|  |                                 template: 'editor-app/popups/select-shape.html?version=' + Date.now() | ||
|  |                             },  $modal, $rootScope); | ||
|  |                         }; | ||
|  | 
 | ||
|  |                         showSelectShapeDialog(); | ||
|  |                 } | ||
|  |               }); | ||
|  |             }; | ||
|  |              | ||
|  |             $scope.deleteShape = function() { | ||
|  |               FLOWABLE.TOOLBAR.ACTIONS.deleteItem({'$scope': $scope, 'editorManager': editorManager}); | ||
|  |             }; | ||
|  |              | ||
|  |             $scope.quickAddItem = function(newItemId) { | ||
|  |               $scope.safeApply(function () { | ||
|  |                  | ||
|  |                 var shapes = editorManager.getSelection(); | ||
|  |                 if (shapes && shapes.length == 1) { | ||
|  |                   $rootScope.currentSelectedShape = shapes.first(); | ||
|  |                    | ||
|  |                   var containedStencil = undefined; | ||
|  |                   var stencilSets = editorManager.getStencilSets().values(); | ||
|  |                   for (var i = 0; i < stencilSets.length; i++) { | ||
|  |                     var stencilSet = stencilSets[i]; | ||
|  |                   	var nodes = stencilSet.nodes(); | ||
|  |                   	for (var j = 0; j < nodes.length; j++) { | ||
|  |                     	if (nodes[j].idWithoutNs() === newItemId) { | ||
|  |                       	    containedStencil = nodes[j]; | ||
|  |                       		break; | ||
|  |                     	} | ||
|  |                     } | ||
|  |                   } | ||
|  |                    | ||
|  |                   if (!containedStencil) return; | ||
|  |                    | ||
|  |                   var option = {type: $scope.currentSelectedShape.getStencil().namespace() + newItemId, namespace: $scope.currentSelectedShape.getStencil().namespace()}; | ||
|  |                   option['connectedShape'] = $rootScope.currentSelectedShape; | ||
|  |                   option['parent'] = $rootScope.currentSelectedShape.parent; | ||
|  |                   option['containedStencil'] = containedStencil; | ||
|  |                  | ||
|  |                   var args = { sourceShape: $rootScope.currentSelectedShape, targetStencil: containedStencil }; | ||
|  |                   var targetStencil = editorManager.getRules().connectMorph(args); | ||
|  |                    | ||
|  |                   // Check if there can be a target shape
 | ||
|  |                   if (!targetStencil) {  | ||
|  |                   	return;  | ||
|  |                   } | ||
|  |                    | ||
|  |                   option['connectingType'] = targetStencil.id(); | ||
|  | 
 | ||
|  |                   var command = new FLOWABLE.CreateCommand(option, undefined, undefined, editorManager.getEditor()); | ||
|  |                  | ||
|  |                   editorManager.executeCommands([command]); | ||
|  |                 } | ||
|  |               }); | ||
|  |             }; | ||
|  |              | ||
|  |             $scope.editShape = function(){ | ||
|  | 				editorManager.edit($scope.selectedShape.resourceId); | ||
|  | 			}; | ||
|  | 
 | ||
|  |         }); // end of $scope.editorFactory.promise block
 | ||
|  | 
 | ||
|  |         /* Click handler for clicking a property */ | ||
|  |         $scope.propertyClicked = function (index) { | ||
|  |             if (!$scope.selectedItem.properties[index].hidden) { | ||
|  |                 $scope.selectedItem.properties[index].mode = "write"; | ||
|  |             } | ||
|  |         }; | ||
|  | 
 | ||
|  |         /* Helper method to retrieve the template url for a property */ | ||
|  |         $scope.getPropertyTemplateUrl = function (index) { | ||
|  |             return $scope.selectedItem.properties[index].templateUrl; | ||
|  |         }; | ||
|  |         $scope.getPropertyReadModeTemplateUrl = function (index) { | ||
|  |             return $scope.selectedItem.properties[index].readModeTemplateUrl; | ||
|  |         }; | ||
|  |         $scope.getPropertyWriteModeTemplateUrl = function (index) { | ||
|  |             return $scope.selectedItem.properties[index].writeModeTemplateUrl; | ||
|  |         }; | ||
|  | 
 | ||
|  |         /* Method available to all sub controllers (for property controllers) to update the internal Oryx model */ | ||
|  |         $scope.updatePropertyInModel = function (property, shapeId) { | ||
|  | 
 | ||
|  |             var shape = $scope.selectedShape; | ||
|  |             // Some updates may happen when selected shape is already changed, so when an additional
 | ||
|  |             // shapeId is supplied, we need to make sure the correct shape is updated (current or previous)
 | ||
|  |             if (shapeId) { | ||
|  |                 if (shape.id != shapeId && $scope.previousSelectedShape && $scope.previousSelectedShape.id == shapeId) { | ||
|  |                     shape = $scope.previousSelectedShape; | ||
|  |                 } else { | ||
|  |                     shape = null; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             if (!shape) { | ||
|  |                 // When no shape is selected, or no shape is found for the alternative
 | ||
|  |                 // shape ID, do nothing
 | ||
|  |                 return; | ||
|  |             } | ||
|  |             var key = property.key; | ||
|  |             var newValue = property.value; | ||
|  |             var oldValue = shape.properties.get(key); | ||
|  | 
 | ||
|  |             if (newValue != oldValue) { | ||
|  |                 var commandClass = ORYX.Core.Command.extend({ | ||
|  |                     construct: function () { | ||
|  |                         this.key = key; | ||
|  |                         this.oldValue = oldValue; | ||
|  |                         this.newValue = newValue; | ||
|  |                         this.shape = shape; | ||
|  |                         this.facade = editorManager.getEditor(); | ||
|  |                     }, | ||
|  |                     execute: function () { | ||
|  |                         this.shape.setProperty(this.key, this.newValue); | ||
|  |                         this.facade.getCanvas().update(); | ||
|  |                         this.facade.updateSelection(); | ||
|  |                     }, | ||
|  |                     rollback: function () { | ||
|  |                         this.shape.setProperty(this.key, this.oldValue); | ||
|  |                         this.facade.getCanvas().update(); | ||
|  |                         this.facade.updateSelection(); | ||
|  |                     } | ||
|  |                 }); | ||
|  |                 // Instantiate the class
 | ||
|  |                 var command = new commandClass(); | ||
|  | 
 | ||
|  |                 // Execute the command
 | ||
|  |                 editorManager.executeCommands([command]); | ||
|  |                 editorManager.handleEvents({ | ||
|  |                     type: ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED, | ||
|  |                     elements: [shape], | ||
|  |                     key: key | ||
|  |                 }); | ||
|  | 
 | ||
|  |                 // Switch the property back to read mode, now the update is done
 | ||
|  |                 property.mode = 'read'; | ||
|  | 
 | ||
|  |                 // Fire event to all who is interested
 | ||
|  |                 // Fire event to all who want to know about this
 | ||
|  |                 var event = { | ||
|  |                     type: FLOWABLE.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, | ||
|  |                     property: property, | ||
|  |                     oldValue: oldValue, | ||
|  |                     newValue: newValue | ||
|  |                 }; | ||
|  |                 FLOWABLE.eventBus.dispatch(event.type, event); | ||
|  |             } else { | ||
|  |                 // Switch the property back to read mode, no update was needed
 | ||
|  |                 property.mode = 'read'; | ||
|  |             } | ||
|  | 
 | ||
|  |         }; | ||
|  | 
 | ||
|  |         /** | ||
|  |          * Helper method that searches a group for an item with the given id. | ||
|  |          * If not found, will return undefined. | ||
|  |          */ | ||
|  |         $scope.findStencilItemInGroup = function (stencilItemId, group) { | ||
|  | 
 | ||
|  |             var item; | ||
|  | 
 | ||
|  |             // Check all items directly in this group
 | ||
|  |             for (var j = 0; j < group.items.length; j++) { | ||
|  |                 item = group.items[j]; | ||
|  |                 if (item.id === stencilItemId) { | ||
|  |                     return item; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             // Check the child groups
 | ||
|  |             if (group.groups && group.groups.length > 0) { | ||
|  |                 for (var k = 0; k < group.groups.length; k++) { | ||
|  |                     item = $scope.findStencilItemInGroup(stencilItemId, group.groups[k]); | ||
|  |                     if (item) { | ||
|  |                         return item; | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             return undefined; | ||
|  |         }; | ||
|  | 
 | ||
|  |         /** | ||
|  |          * Helper method to find a stencil item. | ||
|  |          */ | ||
|  |         $scope.getStencilItemById = function (stencilItemId) { | ||
|  |             for (var i = 0; i < $scope.stencilItemGroups.length; i++) { | ||
|  |                 var element = $scope.stencilItemGroups[i]; | ||
|  | 
 | ||
|  |                 // Real group
 | ||
|  |                 if (element.items !== null && element.items !== undefined) { | ||
|  |                     var item = $scope.findStencilItemInGroup(stencilItemId, element); | ||
|  |                     if (item) { | ||
|  |                         return item; | ||
|  |                     } | ||
|  |                 } else { // Root stencil item
 | ||
|  |                     if (element.id === stencilItemId) { | ||
|  |                         return element; | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             return undefined; | ||
|  |         }; | ||
|  | 
 | ||
|  |         /* | ||
|  |          * DRAG AND DROP FUNCTIONALITY | ||
|  |          */ | ||
|  | 
 | ||
|  |         $scope.dropCallback = function (event, ui) { | ||
|  |            | ||
|  |             editorManager.handleEvents({ | ||
|  |                 type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, | ||
|  |                 highlightId: "shapeRepo.attached" | ||
|  |             }); | ||
|  |             editorManager.handleEvents({ | ||
|  |                 type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, | ||
|  |                 highlightId: "shapeRepo.added" | ||
|  |             }); | ||
|  |              | ||
|  |             editorManager.handleEvents({ | ||
|  |                 type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, | ||
|  |                 highlightId: "shapeMenu" | ||
|  |             }); | ||
|  |              | ||
|  |             FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); | ||
|  | 
 | ||
|  |             if ($scope.dragCanContain) { | ||
|  | 
 | ||
|  |               var item = $scope.getStencilItemById(ui.draggable[0].id); | ||
|  |                | ||
|  |               var pos = {x: event.pageX, y: event.pageY}; | ||
|  |                | ||
|  |               var additionalIEZoom = 1; | ||
|  |               if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { | ||
|  |                 var ua = navigator.userAgent; | ||
|  |                 if (ua.indexOf('MSIE') >= 0) { | ||
|  |                   //IE 10 and below
 | ||
|  |                   var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); | ||
|  |                   if (zoom !== 100) { | ||
|  |                     additionalIEZoom = zoom / 100; | ||
|  |                   } | ||
|  |                 } | ||
|  |               } | ||
|  |                | ||
|  |               var screenCTM = editorManager.getCanvas().node.getScreenCTM(); | ||
|  | 
 | ||
|  |               // Correcting the UpperLeft-Offset
 | ||
|  |               pos.x -= (screenCTM.e / additionalIEZoom); | ||
|  |               pos.y -= (screenCTM.f / additionalIEZoom); | ||
|  |               // Correcting the Zoom-Factor
 | ||
|  |               pos.x /= screenCTM.a; | ||
|  |               pos.y /= screenCTM.d; | ||
|  |                  | ||
|  |               // Correcting the ScrollOffset
 | ||
|  |               pos.x -= document.documentElement.scrollLeft; | ||
|  |               pos.y -= document.documentElement.scrollTop; | ||
|  |                  | ||
|  |               var parentAbs = $scope.dragCurrentParent.absoluteXY(); | ||
|  |               pos.x -= parentAbs.x; | ||
|  |               pos.y -= parentAbs.y; | ||
|  | 
 | ||
|  |               var containedStencil = undefined; | ||
|  |               var stencilSets = editorManager.getStencilSets().values(); | ||
|  |               for (var i = 0; i < stencilSets.length; i++) { | ||
|  |                 var stencilSet = stencilSets[i]; | ||
|  |                 var nodes = stencilSet.nodes(); | ||
|  |                 for (var j = 0; j < nodes.length; j++) { | ||
|  |                   if (nodes[j].idWithoutNs() === ui.draggable[0].id) { | ||
|  |                     containedStencil = nodes[j]; | ||
|  |                     break; | ||
|  |                   } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (!containedStencil) { | ||
|  |                   var edges = stencilSet.edges(); | ||
|  |                   for (var j = 0; j < edges.length; j++) { | ||
|  |                   if (edges[j].idWithoutNs() === ui.draggable[0].id) { | ||
|  |                     containedStencil = edges[j]; | ||
|  |                     break; | ||
|  |                   } | ||
|  |                 } | ||
|  |               } | ||
|  |             } | ||
|  | 
 | ||
|  |             if (!containedStencil) return; | ||
|  | 
 | ||
|  |             if ($scope.quickMenu) { | ||
|  |               var shapes = editorManager.getSelection(); | ||
|  |               if (shapes && shapes.length == 1) { | ||
|  |                 var currentSelectedShape = shapes.first(); | ||
|  | 
 | ||
|  |                 var option = {}; | ||
|  |                 option.type = currentSelectedShape.getStencil().namespace() + ui.draggable[0].id; | ||
|  |                 option.namespace = currentSelectedShape.getStencil().namespace(); | ||
|  |                 option.connectedShape = currentSelectedShape; | ||
|  |                 option.parent = $scope.dragCurrentParent; | ||
|  |                 option.containedStencil = containedStencil; | ||
|  | 	                 | ||
|  |                 // If the ctrl key is not pressed, 
 | ||
|  |                 // snapp the new shape to the center 
 | ||
|  |                 // if it is near to the center of the other shape
 | ||
|  |                 if (!event.ctrlKey) { | ||
|  |                   // Get the center of the shape
 | ||
|  |                   var cShape = currentSelectedShape.bounds.center(); | ||
|  |                   // Snapp +-20 Pixel horizontal to the center 
 | ||
|  |                   if (20 > Math.abs(cShape.x - pos.x)) { | ||
|  |                     pos.x = cShape.x; | ||
|  |                   } | ||
|  |                   // Snapp +-20 Pixel vertical to the center 
 | ||
|  |                   if (20 > Math.abs(cShape.y - pos.y)) { | ||
|  |                     pos.y = cShape.y; | ||
|  |                   } | ||
|  |                 } | ||
|  | 	                 | ||
|  |                 option.position = pos; | ||
|  | 	               | ||
|  |                 if (containedStencil.idWithoutNs() !== 'SequenceFlow' && containedStencil.idWithoutNs() !== 'Association' &&  | ||
|  |                         containedStencil.idWithoutNs() !== 'MessageFlow' && containedStencil.idWithoutNs() !== 'DataAssociation' && | ||
|  |                         containedStencil.idWithoutNs() !== 'InformationRequirement' && containedStencil.idWithoutNs() !== 'KnowledgeRequirement') { | ||
|  | 	                         | ||
|  |                   var args = { sourceShape: currentSelectedShape, targetStencil: containedStencil }; | ||
|  |                   var targetStencil = editorManager.getRules().connectMorph(args); | ||
|  |                   if (!targetStencil) { // Check if there can be a target shape
 | ||
|  |                   	return;  | ||
|  |                   } | ||
|  |                   option.connectingType = targetStencil.id(); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 var command = new FLOWABLE.CreateCommand(option, $scope.dropTargetElement, pos, editorManager.getEditor()); | ||
|  | 	               | ||
|  |                 editorManager.executeCommands([command]); | ||
|  |               } | ||
|  | 	                 | ||
|  |             } else { | ||
|  |               var canAttach = false; | ||
|  |               if (containedStencil.idWithoutNs() === 'BoundaryErrorEvent' || containedStencil.idWithoutNs() === 'BoundaryTimerEvent' || | ||
|  |                     containedStencil.idWithoutNs() === 'BoundarySignalEvent' || containedStencil.idWithoutNs() === 'BoundaryMessageEvent' || | ||
|  |                     containedStencil.idWithoutNs() === 'BoundaryCancelEvent' || containedStencil.idWithoutNs() === 'BoundaryCompensationEvent') { | ||
|  |                      | ||
|  |                 // Modify position, otherwise boundary event will get position related to left corner of the canvas instead of the container
 | ||
|  |                 pos = editorManager.eventCoordinates( event ); | ||
|  |                 canAttach = true; | ||
|  |               } | ||
|  | 
 | ||
|  |               var option = {}; | ||
|  |               option['type'] = $scope.modelData.model.stencilset.namespace + item.id; | ||
|  |               option['namespace'] = $scope.modelData.model.stencilset.namespace; | ||
|  |               option['position'] = pos; | ||
|  |               option['parent'] = $scope.dragCurrentParent; | ||
|  | 
 | ||
|  |               var commandClass = ORYX.Core.Command.extend({ | ||
|  |                     construct: function(option, dockedShape, canAttach, position, facade){ | ||
|  |                         this.option = option; | ||
|  |                         this.docker = null; | ||
|  |                         this.dockedShape = dockedShape; | ||
|  |                         this.dockedShapeParent = dockedShape.parent || facade.getCanvas(); | ||
|  |                         this.position = position; | ||
|  |                         this.facade = facade; | ||
|  |                         this.selection = this.facade.getSelection(); | ||
|  |                         this.shape = null; | ||
|  |                         this.parent = null; | ||
|  |                         this.canAttach = canAttach; | ||
|  |                     }, | ||
|  |                     execute: function(){ | ||
|  |                         if (!this.shape) { | ||
|  |                             this.shape = this.facade.createShape(option); | ||
|  |                             this.parent = this.shape.parent; | ||
|  |                         } else if (this.parent) { | ||
|  |                             this.parent.add(this.shape); | ||
|  |                         } | ||
|  | 
 | ||
|  |                         if (this.canAttach && this.shape.dockers && this.shape.dockers.length) { | ||
|  |                             this.docker = this.shape.dockers[0]; | ||
|  | 
 | ||
|  |                             this.dockedShapeParent.add(this.docker.parent); | ||
|  | 
 | ||
|  |                             // Set the Docker to the new Shape
 | ||
|  |                             this.docker.setDockedShape(undefined); | ||
|  |                             this.docker.bounds.centerMoveTo(this.position); | ||
|  |                             if (this.dockedShape !== this.facade.getCanvas()) { | ||
|  |                                 this.docker.setDockedShape(this.dockedShape); | ||
|  |                             } | ||
|  |                             this.facade.setSelection( [this.docker.parent] ); | ||
|  |                         } | ||
|  | 
 | ||
|  |                         this.facade.getCanvas().update(); | ||
|  |                         this.facade.updateSelection(); | ||
|  | 
 | ||
|  |                     }, | ||
|  |                     rollback: function(){ | ||
|  |                         if (this.shape) { | ||
|  |                             this.facade.setSelection(this.selection.without(this.shape)); | ||
|  |                             this.facade.deleteShape(this.shape); | ||
|  |                         } | ||
|  |                         if (this.canAttach && this.docker) { | ||
|  |                             this.docker.setDockedShape(undefined); | ||
|  |                         } | ||
|  |                         this.facade.getCanvas().update(); | ||
|  |                         this.facade.updateSelection(); | ||
|  | 
 | ||
|  |                     } | ||
|  |               }); | ||
|  | 
 | ||
|  |               // Update canvas
 | ||
|  |               var command = new commandClass(option, $scope.dragCurrentParent, canAttach, pos, editorManager.getEditor()); | ||
|  |               editorManager.executeCommands([command]); | ||
|  | 
 | ||
|  |               // Fire event to all who want to know about this
 | ||
|  |               var dropEvent = { | ||
|  |                   type: FLOWABLE.eventBus.EVENT_TYPE_ITEM_DROPPED, | ||
|  |                   droppedItem: item, | ||
|  |                   position: pos | ||
|  |               }; | ||
|  |               FLOWABLE.eventBus.dispatch(dropEvent.type, dropEvent); | ||
|  |             } | ||
|  |           } | ||
|  | 
 | ||
|  |           $scope.dragCurrentParent = undefined; | ||
|  |           $scope.dragCurrentParentId = undefined; | ||
|  |           $scope.dragCurrentParentStencil = undefined; | ||
|  |           $scope.dragCanContain = undefined; | ||
|  |           $scope.quickMenu = undefined; | ||
|  |           $scope.dropTargetElement = undefined; | ||
|  |         }; | ||
|  | 
 | ||
|  | 
 | ||
|  |         $scope.overCallback = function (event, ui) { | ||
|  |             $scope.dragModeOver = true; | ||
|  |         }; | ||
|  | 
 | ||
|  |         $scope.outCallback = function (event, ui) { | ||
|  |             $scope.dragModeOver = false; | ||
|  |         }; | ||
|  | 
 | ||
|  |         $scope.startDragCallback = function (event, ui) { | ||
|  |             $scope.dragModeOver = false; | ||
|  |             $scope.quickMenu = false; | ||
|  |             if (!ui.helper.hasClass('stencil-item-dragged')) { | ||
|  |                 ui.helper.addClass('stencil-item-dragged'); | ||
|  |             } | ||
|  |         }; | ||
|  |          | ||
|  |         $scope.startDragCallbackQuickMenu = function (event, ui) { | ||
|  |             $scope.dragModeOver = false; | ||
|  |             $scope.quickMenu = true; | ||
|  |         }; | ||
|  |          | ||
|  |         $scope.dragCallback = function (event, ui) { | ||
|  |            | ||
|  |             if ($scope.dragModeOver != false) { | ||
|  |                | ||
|  |                 var coord = editorManager.eventCoordinatesXY(event.pageX, event.pageY); | ||
|  |                  | ||
|  |                 var additionalIEZoom = 1; | ||
|  |                 if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { | ||
|  |                     var ua = navigator.userAgent; | ||
|  |                     if (ua.indexOf('MSIE') >= 0) { | ||
|  |                         //IE 10 and below
 | ||
|  |                         var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); | ||
|  |                         if (zoom !== 100) { | ||
|  |                             additionalIEZoom = zoom / 100 | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |                  | ||
|  |                 if (additionalIEZoom !== 1) { | ||
|  |                      coord.x = coord.x / additionalIEZoom; | ||
|  |                      coord.y = coord.y / additionalIEZoom; | ||
|  |                 } | ||
|  |                  | ||
|  |                 var aShapes = editorManager.getCanvas().getAbstractShapesAtPosition(coord); | ||
|  |                  | ||
|  |                 if (aShapes.length <= 0) { | ||
|  |                     if (event.helper) { | ||
|  |                         $scope.dragCanContain = false; | ||
|  |                         return false; | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (aShapes[0] instanceof ORYX.Core.Canvas) { | ||
|  |                     editorManager.getCanvas().setHightlightStateBasedOnX(coord.x); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (aShapes.length == 1 && aShapes[0] instanceof ORYX.Core.Canvas) { | ||
|  |                   	var item = $scope.getStencilItemById(event.target.id); | ||
|  |                     var parentCandidate = aShapes[0]; | ||
|  | 
 | ||
|  |                     if (item.id === 'Lane' || item.id === 'BoundaryErrorEvent' || item.id === 'BoundaryMessageEvent' ||  | ||
|  |                             item.id === 'BoundarySignalEvent' || item.id === 'BoundaryTimerEvent' || | ||
|  |                             item.id === 'BoundaryCancelEvent' || item.id === 'BoundaryCompensationEvent' ||  | ||
|  |                             item.id === 'EntryCriterion') { | ||
|  |                          | ||
|  |                         $scope.dragCanContain = false; | ||
|  |                          | ||
|  |                         // Show Highlight
 | ||
|  |                         editorManager.handleEvents({ | ||
|  |                             type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, | ||
|  |                             highlightId: 'shapeRepo.added', | ||
|  |                             elements: [parentCandidate], | ||
|  |                             style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE, | ||
|  |                             color: ORYX.CONFIG.SELECTION_INVALID_COLOR | ||
|  |                         }); | ||
|  |                          | ||
|  |                     } else { | ||
|  |                         $scope.dragCanContain = true; | ||
|  |                         $scope.dragCurrentParent = parentCandidate; | ||
|  |                         $scope.dragCurrentParentId = parentCandidate.id; | ||
|  |                          | ||
|  |                         editorManager.handleEvents({ | ||
|  |                             type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, | ||
|  |                             highlightId: "shapeRepo.added" | ||
|  |                         }); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     editorManager.handleEvents({ | ||
|  |                         type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, | ||
|  |                         highlightId: "shapeRepo.attached" | ||
|  |                     }); | ||
|  |                      | ||
|  |                     return false; | ||
|  |                      | ||
|  |                 } else  { | ||
|  |                     var item = $scope.getStencilItemById(event.target.id); | ||
|  |                      | ||
|  |                     var parentCandidate = aShapes.reverse().find(function (candidate) { | ||
|  |                         return (candidate instanceof ORYX.Core.Canvas | ||
|  |                             || candidate instanceof ORYX.Core.Node | ||
|  |                             || candidate instanceof ORYX.Core.Edge); | ||
|  |                     }); | ||
|  |                      | ||
|  |                     if (!parentCandidate) { | ||
|  |                         $scope.dragCanContain = false; | ||
|  |                         return false; | ||
|  |                     } | ||
|  |                      | ||
|  |                     if (item.type === "node") { | ||
|  |                          | ||
|  |                         // check if the draggable is a boundary event and the parent an Activity
 | ||
|  |                         var _canContain = false; | ||
|  |                         var parentStencilId = parentCandidate.getStencil().id(); | ||
|  | 
 | ||
|  |                         if ($scope.dragCurrentParentId && $scope.dragCurrentParentId === parentCandidate.id) { | ||
|  |                             return false; | ||
|  |                         } | ||
|  | 
 | ||
|  |                         var parentItem = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs()); | ||
|  |                         if (parentCandidate.getStencil().id().endsWith("DecisionServiceSection")) { | ||
|  |                             if (item.id === 'Decision') { | ||
|  |                                 _canContain = true; | ||
|  |                             } | ||
|  |                         } else if (parentItem.roles.indexOf('Activity') > -1) { | ||
|  |                             if (item.roles.indexOf('IntermediateEventOnActivityBoundary') > -1  | ||
|  |                                 || item.roles.indexOf('EntryCriterionOnItemBoundary') > -1 | ||
|  |                                 || item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { | ||
|  |                                 _canContain = true; | ||
|  |                             } | ||
|  |                              | ||
|  |                         } else if(parentItem.roles.indexOf('StageActivity') > -1) { | ||
|  |                             if (item.roles.indexOf('EntryCriterionOnItemBoundary') > -1 | ||
|  |                                 || item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { | ||
|  |                                 _canContain = true; | ||
|  |                             } | ||
|  |                          | ||
|  |                         } else if(parentItem.roles.indexOf('StageModelActivity') > -1) {  | ||
|  |                             if (item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { | ||
|  |                                 _canContain = true; | ||
|  |                             } | ||
|  |                          | ||
|  |                         } else if (parentCandidate.getStencil().idWithoutNs() === 'Pool') { | ||
|  |                           	if (item.id === 'Lane') { | ||
|  |                             	_canContain = true; | ||
|  |                           	} | ||
|  |                         } | ||
|  |                          | ||
|  |                         if (_canContain) { | ||
|  |                             editorManager.handleEvents({ | ||
|  |                                 type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, | ||
|  |                                 highlightId: "shapeRepo.attached", | ||
|  |                                 elements: [parentCandidate], | ||
|  |                                 style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE, | ||
|  |                                 color: ORYX.CONFIG.SELECTION_VALID_COLOR | ||
|  |                             }); | ||
|  | 
 | ||
|  |                             editorManager.handleEvents({ | ||
|  |                                 type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, | ||
|  |                                 highlightId: "shapeRepo.added" | ||
|  |                             }); | ||
|  |                              | ||
|  |                         } else { | ||
|  |                             for (var i = 0; i < $scope.containmentRules.length; i++) { | ||
|  |                                 var rule = $scope.containmentRules[i]; | ||
|  |                                 if (rule.role === parentItem.id) { | ||
|  |                                     for (var j = 0; j < rule.contains.length; j++) { | ||
|  |                                         if (item.roles.indexOf(rule.contains[j]) > -1) { | ||
|  |                                             _canContain = true; | ||
|  |                                             break; | ||
|  |                                         } | ||
|  |                                     } | ||
|  | 
 | ||
|  |                                     if (_canContain) { | ||
|  |                                         break; | ||
|  |                                     } | ||
|  |                                 } | ||
|  |                             } | ||
|  |                              | ||
|  |                             // Show Highlight
 | ||
|  |                             editorManager.handleEvents({ | ||
|  |                                 type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, | ||
|  |                                 highlightId: 'shapeRepo.added', | ||
|  |                                 elements: [parentCandidate], | ||
|  |                                 color: _canContain ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR | ||
|  |                             }); | ||
|  | 
 | ||
|  |                             editorManager.handleEvents({ | ||
|  |                                 type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, | ||
|  |                                 highlightId: "shapeRepo.attached" | ||
|  |                             }); | ||
|  |                         } | ||
|  | 
 | ||
|  |                         $scope.dragCurrentParent = parentCandidate; | ||
|  |                         $scope.dragCurrentParentId = parentCandidate.id; | ||
|  |                         $scope.dragCurrentParentStencil = parentStencilId; | ||
|  |                         $scope.dragCanContain = _canContain; | ||
|  |                          | ||
|  |                     } else  {  | ||
|  |                       var canvasCandidate = editorManager.getCanvas(); | ||
|  |                       var canConnect = false; | ||
|  |                        | ||
|  |                       var targetStencil = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs()); | ||
|  | 	                  if (targetStencil) { | ||
|  | 	                    var associationConnect = false; | ||
|  | 	                    if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { | ||
|  | 	                        associationConnect = true; | ||
|  | 	                    } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { | ||
|  |                             associationConnect = true; | ||
|  |                         } | ||
|  | 	                     | ||
|  | 	                    if (targetStencil.canConnectTo || associationConnect) { | ||
|  | 	                      canConnect = true; | ||
|  | 	                    } | ||
|  | 	                  } | ||
|  |                        | ||
|  |                       //Edge
 | ||
|  |                       $scope.dragCurrentParent = canvasCandidate; | ||
|  |                       $scope.dragCurrentParentId = canvasCandidate.id; | ||
|  |                       $scope.dragCurrentParentStencil = canvasCandidate.getStencil().id(); | ||
|  |                       $scope.dragCanContain = canConnect; | ||
|  |                          | ||
|  |                       // Show Highlight
 | ||
|  |                       editorManager.handleEvents({ | ||
|  |                             type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, | ||
|  |                             highlightId: 'shapeRepo.added', | ||
|  |                             elements: [canvasCandidate], | ||
|  |                             color: ORYX.CONFIG.SELECTION_VALID_COLOR | ||
|  |                       }); | ||
|  | 
 | ||
|  |                       editorManager.handleEvents({ | ||
|  |                             type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, | ||
|  |                             highlightId: "shapeRepo.attached" | ||
|  |                       }); | ||
|  |               		} | ||
|  |                 } | ||
|  |             } | ||
|  |         }; | ||
|  |          | ||
|  |         $scope.dragCallbackQuickMenu = function (event, ui) { | ||
|  |            | ||
|  |             if ($scope.dragModeOver != false) { | ||
|  |                 var coord = editorManager.eventCoordinatesXY(event.pageX, event.pageY); | ||
|  |                  | ||
|  |                 var additionalIEZoom = 1; | ||
|  |                 if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { | ||
|  |                     var ua = navigator.userAgent; | ||
|  |                     if (ua.indexOf('MSIE') >= 0) { | ||
|  |                         //IE 10 and below
 | ||
|  |                         var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); | ||
|  |                         if (zoom !== 100) { | ||
|  |                             additionalIEZoom = zoom / 100 | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |                  | ||
|  |                 if (additionalIEZoom !== 1) { | ||
|  |                      coord.x = coord.x / additionalIEZoom; | ||
|  |                      coord.y = coord.y / additionalIEZoom; | ||
|  |                 } | ||
|  |                  | ||
|  |                 var aShapes = editorManager.getCanvas().getAbstractShapesAtPosition(coord); | ||
|  |                 | ||
|  |                 if (aShapes.length <= 0) { | ||
|  |                     if (event.helper) { | ||
|  |                         $scope.dragCanContain = false; | ||
|  |                         return false; | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (aShapes[0] instanceof ORYX.Core.Canvas) { | ||
|  |                     editorManager.getCanvas().setHightlightStateBasedOnX(coord.x); | ||
|  |                 } | ||
|  |                  | ||
|  |                 var stencil = undefined; | ||
|  |                 var stencilSets = editorManager.getStencilSets().values(); | ||
|  |                 for (var i = 0; i < stencilSets.length; i++) { | ||
|  |                 	var stencilSet = stencilSets[i]; | ||
|  |               		var nodes = stencilSet.nodes(); | ||
|  |               		for (var j = 0; j < nodes.length; j++) { | ||
|  |                 		if (nodes[j].idWithoutNs() === event.target.id) { | ||
|  |                   			stencil = nodes[j]; | ||
|  |                   			break; | ||
|  |                 		} | ||
|  |                     } | ||
|  |                | ||
|  |               		if (!stencil) { | ||
|  |                 		var edges = stencilSet.edges(); | ||
|  |                   		for (var j = 0; j < edges.length; j++) { | ||
|  |                     		if (edges[j].idWithoutNs() === event.target.id) { | ||
|  |                       			stencil = edges[j]; | ||
|  |                       			break; | ||
|  |                     		} | ||
|  |                       	} | ||
|  |               		} | ||
|  |               	} | ||
|  |              | ||
|  |                 var candidate = aShapes.last(); | ||
|  |                  | ||
|  |                 var isValid = false; | ||
|  |                 if (stencil.type() === "node")  { | ||
|  |             		//check containment rules
 | ||
|  |             		var canContain = editorManager.getRules().canContain({containingShape:candidate, containedStencil:stencil}); | ||
|  |              | ||
|  |             		var parentCandidate = aShapes.reverse().find(function (candidate) { | ||
|  |                         return (candidate instanceof ORYX.Core.Canvas | ||
|  |                             || candidate instanceof ORYX.Core.Node | ||
|  |                             || candidate instanceof ORYX.Core.Edge); | ||
|  |                     }); | ||
|  | 
 | ||
|  |                     if (!parentCandidate) { | ||
|  |                         $scope.dragCanContain = false; | ||
|  |                         return false; | ||
|  |                     } | ||
|  |              | ||
|  |             		$scope.dragCurrentParent = parentCandidate; | ||
|  |                     $scope.dragCurrentParentId = parentCandidate.id; | ||
|  |                     $scope.dragCurrentParentStencil = parentCandidate.getStencil().id(); | ||
|  |                     $scope.dragCanContain = canContain; | ||
|  |                     $scope.dropTargetElement = parentCandidate; | ||
|  |                     isValid = canContain; | ||
|  |        | ||
|  |           		} else { //Edge
 | ||
|  |            | ||
|  |             		var shapes = editorManager.getSelection(); | ||
|  |                 	if (shapes && shapes.length == 1) { | ||
|  |                   		var currentSelectedShape = shapes.first(); | ||
|  |                   		var curCan = candidate; | ||
|  |                   		var canConnect = false; | ||
|  |                    | ||
|  |                   		var targetStencil = $scope.getStencilItemById(curCan.getStencil().idWithoutNs()); | ||
|  |                   		if (targetStencil) { | ||
|  |                     		var associationConnect = false; | ||
|  |                     		if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { | ||
|  |                       			associationConnect = true; | ||
|  |                     		} else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { | ||
|  |                         		associationConnect = true; | ||
|  |                     		} | ||
|  |                      | ||
|  |                     		if (targetStencil.canConnectTo || associationConnect) { | ||
|  |                     			while (!canConnect && curCan && !(curCan instanceof ORYX.Core.Canvas)) { | ||
|  |                       				candidate = curCan; | ||
|  |                       				//check connection rules
 | ||
|  |                       				canConnect = editorManager.getRules().canConnect({ | ||
|  | 	                                  sourceShape: currentSelectedShape,  | ||
|  | 	                                  edgeStencil: stencil,  | ||
|  | 	                                  targetShape: curCan | ||
|  | 	                                });  | ||
|  |                       				curCan = curCan.parent; | ||
|  |                     			} | ||
|  |                     		} | ||
|  |                   		} | ||
|  |                   		var parentCandidate = editorManager.getCanvas(); | ||
|  |                  | ||
|  |                 		isValid = canConnect; | ||
|  |                 		$scope.dragCurrentParent = parentCandidate; | ||
|  |                         $scope.dragCurrentParentId = parentCandidate.id; | ||
|  |                         $scope.dragCurrentParentStencil = parentCandidate.getStencil().id(); | ||
|  |                 		$scope.dragCanContain = canConnect; | ||
|  |                 		$scope.dropTargetElement = candidate; | ||
|  |                 	}    | ||
|  |              | ||
|  |           		}  | ||
|  | 
 | ||
|  |                 editorManager.handleEvents({ | ||
|  |           			type:   ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,  | ||
|  |           			highlightId:'shapeMenu', | ||
|  |           			elements: [candidate], | ||
|  |           			color: isValid ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR | ||
|  |         		}); | ||
|  |             } | ||
|  |         }; | ||
|  | 
 | ||
|  |     }]); | ||
|  | 
 | ||
|  | var FLOWABLE = FLOWABLE || {}; | ||
|  | //create command for undo/redo
 | ||
|  | FLOWABLE.CreateCommand = ORYX.Core.Command.extend({ | ||
|  |   construct: function(option, currentReference, position, facade){ | ||
|  |     this.option = option; | ||
|  |     this.currentReference = currentReference; | ||
|  |     this.position = position; | ||
|  |     this.facade = facade; | ||
|  |     this.shape; | ||
|  |     this.edge; | ||
|  |     this.targetRefPos; | ||
|  |     this.sourceRefPos; | ||
|  |     /* | ||
|  |      * clone options parameters | ||
|  |      */ | ||
|  |         this.connectedShape = option.connectedShape; | ||
|  |         this.connectingType = option.connectingType; | ||
|  |         this.namespace = option.namespace; | ||
|  |         this.type = option.type; | ||
|  |         this.containedStencil = option.containedStencil; | ||
|  |         this.parent = option.parent; | ||
|  |         this.currentReference = currentReference; | ||
|  |         this.shapeOptions = option.shapeOptions; | ||
|  |   },       | ||
|  |   execute: function(){ | ||
|  |      | ||
|  |     if (this.shape) { | ||
|  |       if (this.shape instanceof ORYX.Core.Node) { | ||
|  |         this.parent.add(this.shape); | ||
|  |         if (this.edge) { | ||
|  |           this.facade.getCanvas().add(this.edge); | ||
|  |           this.edge.dockers.first().setDockedShape(this.connectedShape); | ||
|  |           this.edge.dockers.first().setReferencePoint(this.sourceRefPos); | ||
|  |           this.edge.dockers.last().setDockedShape(this.shape); | ||
|  |           this.edge.dockers.last().setReferencePoint(this.targetRefPos); | ||
|  |         } | ||
|  |          | ||
|  |         this.facade.setSelection([this.shape]); | ||
|  |          | ||
|  |       } else if (this.shape instanceof ORYX.Core.Edge) { | ||
|  |         this.facade.getCanvas().add(this.shape); | ||
|  |         this.shape.dockers.first().setDockedShape(this.connectedShape); | ||
|  |         this.shape.dockers.first().setReferencePoint(this.sourceRefPos); | ||
|  |       } | ||
|  |     } | ||
|  |     else { | ||
|  |       this.shape = this.facade.createShape(this.option); | ||
|  |       this.edge = (!(this.shape instanceof ORYX.Core.Edge)) ? this.shape.getIncomingShapes().first() : undefined; | ||
|  |     } | ||
|  |      | ||
|  |     if (this.currentReference && this.position) { | ||
|  |        | ||
|  |       if (this.shape instanceof ORYX.Core.Edge) { | ||
|  |        | ||
|  |         if (!(this.currentReference instanceof ORYX.Core.Canvas)) { | ||
|  |           this.shape.dockers.last().setDockedShape(this.currentReference); | ||
|  |            | ||
|  |           if (this.currentReference.getStencil().idWithoutNs() === 'TextAnnotation') | ||
|  |           { | ||
|  |             var midpoint = {}; | ||
|  |             midpoint.x = 0; | ||
|  |             midpoint.y = this.currentReference.bounds.height() / 2; | ||
|  |             this.shape.dockers.last().setReferencePoint(midpoint); | ||
|  |           } | ||
|  |           else | ||
|  |           { | ||
|  |             this.shape.dockers.last().setReferencePoint(this.currentReference.bounds.midPoint()); | ||
|  |           } | ||
|  |         } | ||
|  |         else { | ||
|  |           this.shape.dockers.last().bounds.centerMoveTo(this.position); | ||
|  |         } | ||
|  |         this.sourceRefPos = this.shape.dockers.first().referencePoint; | ||
|  |         this.targetRefPos = this.shape.dockers.last().referencePoint; | ||
|  |          | ||
|  |       } else if (this.edge){ | ||
|  |         this.sourceRefPos = this.edge.dockers.first().referencePoint; | ||
|  |         this.targetRefPos = this.edge.dockers.last().referencePoint; | ||
|  |       } | ||
|  |     } else { | ||
|  |       var containedStencil = this.containedStencil; | ||
|  |       var connectedShape = this.connectedShape; | ||
|  |       var bc = connectedShape.bounds; | ||
|  |       var bs = this.shape.bounds; | ||
|  |        | ||
|  |       var pos = bc.center(); | ||
|  |       if(containedStencil.defaultAlign()==="north") { | ||
|  |         pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2); | ||
|  |       } else if(containedStencil.defaultAlign()==="northeast") { | ||
|  |         pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); | ||
|  |         pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); | ||
|  |       } else if(containedStencil.defaultAlign()==="southeast") { | ||
|  |         pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); | ||
|  |         pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); | ||
|  |       } else if(containedStencil.defaultAlign()==="south") { | ||
|  |         pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2); | ||
|  |       } else if(containedStencil.defaultAlign()==="southwest") { | ||
|  |         pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); | ||
|  |         pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); | ||
|  |       } else if(containedStencil.defaultAlign()==="west") { | ||
|  |         pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2); | ||
|  |       } else if(containedStencil.defaultAlign()==="northwest") { | ||
|  |         pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); | ||
|  |         pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); | ||
|  |       } else { | ||
|  |         pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2); | ||
|  |       } | ||
|  |        | ||
|  |       // Move shape to the new position
 | ||
|  |       this.shape.bounds.centerMoveTo(pos); | ||
|  |        | ||
|  |       // Move all dockers of a node to the position
 | ||
|  |       if (this.shape instanceof ORYX.Core.Node){ | ||
|  |         (this.shape.dockers||[]).each(function(docker){ | ||
|  |           docker.bounds.centerMoveTo(pos); | ||
|  |         }); | ||
|  |       } | ||
|  |        | ||
|  |       //this.shape.update();
 | ||
|  |       this.position = pos; | ||
|  |        | ||
|  |       if (this.edge){ | ||
|  |         this.sourceRefPos = this.edge.dockers.first().referencePoint; | ||
|  |         this.targetRefPos = this.edge.dockers.last().referencePoint; | ||
|  |       } | ||
|  |     } | ||
|  |      | ||
|  |     this.facade.getCanvas().update(); | ||
|  |     this.facade.updateSelection(); | ||
|  | 
 | ||
|  |   }, | ||
|  |   rollback: function(){ | ||
|  |     this.facade.deleteShape(this.shape); | ||
|  |     if(this.edge) { | ||
|  |       this.facade.deleteShape(this.edge); | ||
|  |     } | ||
|  |     //this.currentParent.update();
 | ||
|  |     this.facade.setSelection(this.facade.getSelection().without(this.shape, this.edge)); | ||
|  |   } | ||
|  | }); |