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.
ocr/htmlweb/modeler/editor-app/editormanager.js

323 lines
13 KiB

/* 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.
*/
/**
* Created by Pardo David on 3/01/2017.
* For this service to work the user must call bootEditor method
*/
angular.module("flowableModeler").factory("editorManager", ["$http", function ($http) {
var editorManager = Class.create({
initialize: function () {
this.treeFilteredElements = ["SubProcess", "CollapsedSubProcess"];
this.canvasTracker = new Hash();
this.structualIcons = {
"SubProcess": "expanded.subprocess.png",
"CollapsedSubProcess": "subprocess.png",
"EventSubProcess": "event.subprocess.png"
};
this.current = this.modelId;
this.loading = true;
},
getModelId: function () {
return this.modelId;
},
setModelId: function (modelId){
this.modelId = modelId;
},
getCurrentModelId: function () {
return this.current;
},
setStencilData: function(stencilData){
//we don't want a references!
this.stencilData = jQuery.extend(true, {},stencilData);
},
getStencilData: function () {
return this.stencilData;
},
getSelection: function () {
return this.editor.selection;
},
getSubSelection: function () {
return this.editor._subSelection;
},
handleEvents: function (events) {
this.editor.handleEvents(events);
},
setSelection: function (selection) {
this.editor.setSelection(selection);
},
registerOnEvent: function (event, callback) {
this.editor.registerOnEvent(event, callback);
},
getChildShapeByResourceId: function (resourceId) {
return this.editor.getCanvas().getChildShapeByResourceId(resourceId);
},
getJSON: function () {
return this.editor.getJSON();
},
getStencilSets: function () {
return this.editor.getStencilSets();
},
getEditor: function () {
return this.editor; //TODO: find out if we can avoid exposing the editor object to angular.
},
executeCommands: function (commands) {
this.editor.executeCommands(commands);
},
getCanvas: function () {
return this.editor.getCanvas();
},
getRules: function () {
return this.editor.getRules();
},
eventCoordinates: function (coordinates) {
return this.editor.eventCoordinates(coordinates);
},
eventCoordinatesXY: function (x, y) {
return this.editor.eventCoordinatesXY(x, y);
},
updateSelection: function () {
this.editor.updateSelection();
},
/**
* @returns the modeldata as received from the server. This does not represent the current editor data.
*/
getBaseModelData: function () {
return this.modelData;
},
edit: function (resourceId) {
//Save the current canvas in the canvastracker if it is the root process.
this.syncCanvasTracker();
this.loading = true;
var shapes = this.getCanvas().getChildren();
shapes.each(function (shape) {
this.editor.deleteShape(shape);
}.bind(this));
shapes = this.canvasTracker.get(resourceId);
if(!shapes){
shapes = JSON.stringify([]);
}
this.editor.loadSerialized({
childShapes: shapes
});
this.getCanvas().update();
this.current = resourceId;
this.loading = false;
FLOWABLE.eventBus.dispatch("EDITORMANAGER-EDIT-ACTION", {});
FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_UNDO_REDO_RESET, {});
},
getTree: function () {
//build a tree of all subprocesses and there children.
var result = new Hash();
var parent = this.getModel();
result.set("name", parent.properties["name"] || "No name provided");
result.set("id", this.modelId);
result.set("type", "root");
result.set("current", this.current === this.modelId)
var childShapes = parent.childShapes;
var children = this._buildTreeChildren(childShapes);
result.set("children", children);
return result.toObject();
},
_buildTreeChildren: function (childShapes) {
var children = [];
for (var i = 0; i < childShapes.length; i++) {
var childShape = childShapes[i];
var stencilId = childShape.stencil.id;
//we are currently only interested in the expanded subprocess and collapsed processes
if (stencilId && this.treeFilteredElements.indexOf(stencilId) > -1) {
var child = new Hash();
child.set("name", childShape.properties.name || "No name provided");
child.set("id", childShape.resourceId);
child.set("type", stencilId);
child.set("current", childShape.resourceId === this.current);
//check if childshapes
if (stencilId === "CollapsedSubProcess") {
//the save function stores the real object as a childshape
//it is possible that there is no child element because the user did not open the collapsed subprocess.
if (childShape.childShapes.length === 0) {
child.set("children", []);
} else {
child.set("children", this._buildTreeChildren(childShape.childShapes));
}
child.set("editable", true);
} else {
child.set("children", this._buildTreeChildren(childShape.childShapes));
child.set("editable", false);
}
child.set("icon", this.structualIcons[stencilId]);
children.push(child.toObject());
}
}
return children;
},
syncCanvasTracker: function () {
var shapes = this.getCanvas().getChildren();
var jsonShapes = [];
shapes.each(function (shape) {
//toJson is an summary object but its not a json string.!!!!!
jsonShapes.push(shape.toJSON());
});
this.canvasTracker.set(this.current, JSON.stringify(jsonShapes));
},
getModel: function () {
this.syncCanvasTracker();
var modelMetaData = this.getBaseModelData();
var stencilId = undefined;
var stencilSetNamespace = undefined;
var stencilSetUrl = undefined;
if (modelMetaData.model.stencilset.namespace == 'http://b3mn.org/stencilset/cmmn1.1#') {
stencilId = 'CMMNDiagram';
stencilSetNamespace = 'http://b3mn.org/stencilset/cmmn1.1#';
stencilSetUrl = '../editor/stencilsets/cmmn1.1/cmmn1.1.json';
} else {
stencilId = 'BPMNDiagram';
stencilSetNamespace = 'http://b3mn.org/stencilset/bpmn2.0#';
stencilSetUrl = '../editor/stencilsets/bpmn2.0/bpmn2.0.json';
}
//this is an object.
var editorConfig = this.editor.getJSON();
var model = {
modelId: this.modelId,
bounds: editorConfig.bounds,
properties: editorConfig.properties,
childShapes: JSON.parse(this.canvasTracker.get(this.modelId)),
stencil: {
id: stencilId,
},
stencilset: {
namespace: stencilSetNamespace,
url: stencilSetUrl
}
};
this._mergeCanvasToChild(model);
return model;
},
setModelData: function(response){
this.modelData = response.data;
},
bootEditor: function () {
//TODO: populate the canvas with correct json sections.
//resetting the state
this.canvasTracker = new Hash();
var config = jQuery.extend(true, {}, this.modelData); //avoid a reference to the original object.
if(!config.model.childShapes){
config.model.childShapes = [];
}
this.findAndRegisterCanvas(config.model.childShapes); //this will remove any childshapes of a collapseable subprocess.
this.canvasTracker.set(config.modelId, JSON.stringify(config.model.childShapes)); //this will be overwritten almost instantly.
this.editor = new ORYX.Editor(config);
this.current = this.editor.id;
this.loading = false;
FLOWABLE.eventBus.editor = this.editor;
FLOWABLE.eventBus.dispatch("ORYX-EDITOR-LOADED", {});
FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_EDITOR_BOOTED, {});
},
findAndRegisterCanvas: function (childShapes) {
for (var i = 0; i < childShapes.length; i++) {
var childShape = childShapes[i];
if (childShape.stencil.id === "CollapsedSubProcess") {
if (childShape.childShapes.length > 0) {
//the canvastracker will auto correct itself with a new canvasmodel see this.edit()...
this.findAndRegisterCanvas(childShape.childShapes);
//a canvas can't be nested as a child because the editor would crash on redundant information.
this.canvasTracker.set(childShape.resourceId, JSON.stringify(childShape.childShapes));
//reference to config will clear the value.
childShape.childShapes = [];
} else {
this.canvasTracker.set(childShape.resourceId, '[]');
}
}
}
},
_mergeCanvasToChild: function (parent) {
for (var i = 0; i < parent.childShapes.length; i++) {
var childShape = parent.childShapes[i]
if(childShape.stencil.id === "CollapsedSubProcess"){
var elements = this.canvasTracker.get(childShape.resourceId);
if(elements){
elements = JSON.parse(elements);
}else{
elements = [];
}
childShape.childShapes = elements;
this._mergeCanvasToChild(childShape);
}else if(childShape.stencil.id === "SubProcess"){
this._mergeCanvasToChild(childShape);
}else{
//do nothing?
}
}
},
dispatchOryxEvent: function (event) {
FLOWABLE.eventBus.dispatchOryxEvent(event);
},
isLoading: function(){
return this.loading;
},
navigateTo: function(resourceId){
//TODO: this could be improved by check if the resourceId is not equal to the current tracker...
this.syncCanvasTracker();
var found = false;
this.canvasTracker.each(function(pair){
var key = pair.key;
var children = JSON.parse(pair.value);
var targetable = this._findTarget(children, resourceId);
if (!found && targetable){
this.edit(key);
var flowableShape = this.getCanvas().getChildShapeByResourceId(targetable);
this.setSelection([flowableShape],[],true);
found = true;
}
},this);
},
_findTarget: function(children,resourceId){
for(var i =0; i < children.length; i++){
var child = children[i];
if(child.resourceId === resourceId){
return child.resourceId;
}else if(child.properties && child.properties["overrideid"] === resourceId){
return child.resourceId;
}else{
var result = this._findTarget(child.childShapes,resourceId);
if(result){
return result;
}
}
}
return false;
}
});
return new editorManager();
}]);