update
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import {
|
||||
filter
|
||||
} from 'min-dash';
|
||||
|
||||
import {
|
||||
eachElement
|
||||
} from 'diagram-js/lib/util/Elements';
|
||||
|
||||
import {
|
||||
getLanesRoot,
|
||||
getChildLanes,
|
||||
LANE_INDENTATION
|
||||
} from '../util/LaneUtil';
|
||||
|
||||
|
||||
/**
|
||||
* A handler that allows us to add a new lane
|
||||
* above or below an existing one.
|
||||
*
|
||||
* @param {Modeling} modeling
|
||||
*/
|
||||
export default function AddLaneHandler(modeling, spaceTool) {
|
||||
this._modeling = modeling;
|
||||
this._spaceTool = spaceTool;
|
||||
}
|
||||
|
||||
AddLaneHandler.$inject = [
|
||||
'modeling',
|
||||
'spaceTool'
|
||||
];
|
||||
|
||||
|
||||
AddLaneHandler.prototype.preExecute = function(context) {
|
||||
|
||||
var spaceTool = this._spaceTool,
|
||||
modeling = this._modeling;
|
||||
|
||||
var shape = context.shape,
|
||||
location = context.location;
|
||||
|
||||
var lanesRoot = getLanesRoot(shape);
|
||||
|
||||
var isRoot = lanesRoot === shape,
|
||||
laneParent = isRoot ? shape : shape.parent;
|
||||
|
||||
var existingChildLanes = getChildLanes(laneParent);
|
||||
|
||||
// (0) add a lane if we currently got none and are adding to root
|
||||
if (!existingChildLanes.length) {
|
||||
modeling.createShape({ type: 'bpmn:Lane' }, {
|
||||
x: shape.x + LANE_INDENTATION,
|
||||
y: shape.y,
|
||||
width: shape.width - LANE_INDENTATION,
|
||||
height: shape.height
|
||||
}, laneParent);
|
||||
}
|
||||
|
||||
// (1) collect affected elements to create necessary space
|
||||
var allAffected = [];
|
||||
|
||||
eachElement(lanesRoot, function(element) {
|
||||
allAffected.push(element);
|
||||
|
||||
if (element === shape) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return filter(element.children, function(c) {
|
||||
return c !== shape;
|
||||
});
|
||||
});
|
||||
|
||||
var offset = location === 'top' ? -120 : 120,
|
||||
lanePosition = location === 'top' ? shape.y : shape.y + shape.height,
|
||||
spacePos = lanePosition + (location === 'top' ? 10 : -10),
|
||||
direction = location === 'top' ? 'n' : 's';
|
||||
|
||||
var adjustments = spaceTool.calculateAdjustments(allAffected, 'y', offset, spacePos);
|
||||
|
||||
spaceTool.makeSpace(adjustments.movingShapes, adjustments.resizingShapes, { x: 0, y: offset }, direction);
|
||||
|
||||
// (2) create new lane at open space
|
||||
context.newLane = modeling.createShape({ type: 'bpmn:Lane' }, {
|
||||
x: shape.x + (isRoot ? LANE_INDENTATION : 0),
|
||||
y: lanePosition - (location === 'top' ? 120 : 0),
|
||||
width: shape.width - (isRoot ? LANE_INDENTATION : 0),
|
||||
height: 120
|
||||
}, laneParent);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
export default function IdClaimHandler(moddle) {
|
||||
this._moddle = moddle;
|
||||
}
|
||||
|
||||
IdClaimHandler.$inject = [ 'moddle' ];
|
||||
|
||||
|
||||
IdClaimHandler.prototype.execute = function(context) {
|
||||
var ids = this._moddle.ids,
|
||||
id = context.id,
|
||||
element = context.element,
|
||||
claiming = context.claiming;
|
||||
|
||||
if (claiming) {
|
||||
ids.claim(id, element);
|
||||
} else {
|
||||
ids.unclaim(id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Command revert implementation.
|
||||
*/
|
||||
IdClaimHandler.prototype.revert = function(context) {
|
||||
var ids = this._moddle.ids,
|
||||
id = context.id,
|
||||
element = context.element,
|
||||
claiming = context.claiming;
|
||||
|
||||
if (claiming) {
|
||||
ids.unclaim(id);
|
||||
} else {
|
||||
ids.claim(id, element);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
import { is } from '../../../util/ModelUtil';
|
||||
|
||||
import {
|
||||
getLanesRoot,
|
||||
computeLanesResize
|
||||
} from '../util/LaneUtil';
|
||||
|
||||
import {
|
||||
eachElement
|
||||
} from 'diagram-js/lib/util/Elements';
|
||||
|
||||
import {
|
||||
asTRBL
|
||||
} from 'diagram-js/lib/layout/LayoutUtil';
|
||||
|
||||
import {
|
||||
substractTRBL
|
||||
} from 'diagram-js/lib/features/resize/ResizeUtil';
|
||||
|
||||
|
||||
/**
|
||||
* A handler that resizes a lane.
|
||||
*
|
||||
* @param {Modeling} modeling
|
||||
*/
|
||||
export default function ResizeLaneHandler(modeling, spaceTool) {
|
||||
this._modeling = modeling;
|
||||
this._spaceTool = spaceTool;
|
||||
}
|
||||
|
||||
ResizeLaneHandler.$inject = [
|
||||
'modeling',
|
||||
'spaceTool'
|
||||
];
|
||||
|
||||
|
||||
ResizeLaneHandler.prototype.preExecute = function(context) {
|
||||
|
||||
var shape = context.shape,
|
||||
newBounds = context.newBounds,
|
||||
balanced = context.balanced;
|
||||
|
||||
if (balanced !== false) {
|
||||
this.resizeBalanced(shape, newBounds);
|
||||
} else {
|
||||
this.resizeSpace(shape, newBounds);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Resize balanced, adjusting next / previous lane sizes.
|
||||
*
|
||||
* @param {djs.model.Shape} shape
|
||||
* @param {Bounds} newBounds
|
||||
*/
|
||||
ResizeLaneHandler.prototype.resizeBalanced = function(shape, newBounds) {
|
||||
|
||||
var modeling = this._modeling;
|
||||
|
||||
var resizeNeeded = computeLanesResize(shape, newBounds);
|
||||
|
||||
// resize the lane
|
||||
modeling.resizeShape(shape, newBounds);
|
||||
|
||||
// resize other lanes as needed
|
||||
resizeNeeded.forEach(function(r) {
|
||||
modeling.resizeShape(r.shape, r.newBounds);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Resize, making actual space and moving below / above elements.
|
||||
*
|
||||
* @param {djs.model.Shape} shape
|
||||
* @param {Bounds} newBounds
|
||||
*/
|
||||
ResizeLaneHandler.prototype.resizeSpace = function(shape, newBounds) {
|
||||
var spaceTool = this._spaceTool;
|
||||
|
||||
var shapeTrbl = asTRBL(shape),
|
||||
newTrbl = asTRBL(newBounds);
|
||||
|
||||
var trblDiff = substractTRBL(newTrbl, shapeTrbl);
|
||||
|
||||
var lanesRoot = getLanesRoot(shape);
|
||||
|
||||
var allAffected = [],
|
||||
allLanes = [];
|
||||
|
||||
eachElement(lanesRoot, function(element) {
|
||||
allAffected.push(element);
|
||||
|
||||
if (is(element, 'bpmn:Lane') || is(element, 'bpmn:Participant')) {
|
||||
allLanes.push(element);
|
||||
}
|
||||
|
||||
return element.children;
|
||||
});
|
||||
|
||||
var change,
|
||||
spacePos,
|
||||
direction,
|
||||
offset,
|
||||
adjustments;
|
||||
|
||||
if (trblDiff.bottom || trblDiff.top) {
|
||||
|
||||
change = trblDiff.bottom || trblDiff.top;
|
||||
spacePos = shape.y + (trblDiff.bottom ? shape.height : 0) + (trblDiff.bottom ? -10 : 10);
|
||||
direction = trblDiff.bottom ? 's' : 'n';
|
||||
|
||||
offset = trblDiff.top > 0 || trblDiff.bottom < 0 ? -change : change;
|
||||
|
||||
adjustments = spaceTool.calculateAdjustments(allAffected, 'y', offset, spacePos);
|
||||
|
||||
spaceTool.makeSpace(adjustments.movingShapes, adjustments.resizingShapes, { x: 0, y: change }, direction);
|
||||
}
|
||||
|
||||
|
||||
if (trblDiff.left || trblDiff.right) {
|
||||
|
||||
change = trblDiff.right || trblDiff.left;
|
||||
spacePos = shape.x + (trblDiff.right ? shape.width : 0) + (trblDiff.right ? -10 : 100);
|
||||
direction = trblDiff.right ? 'e' : 'w';
|
||||
|
||||
offset = trblDiff.left > 0 || trblDiff.right < 0 ? -change : change;
|
||||
|
||||
adjustments = spaceTool.calculateAdjustments(allLanes, 'x', offset, spacePos);
|
||||
|
||||
spaceTool.makeSpace(adjustments.movingShapes, adjustments.resizingShapes, { x: change, y: 0 }, direction);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
assign,
|
||||
forEach
|
||||
} from 'min-dash';
|
||||
|
||||
|
||||
var DEFAULT_COLORS = {
|
||||
fill: undefined,
|
||||
stroke: undefined
|
||||
};
|
||||
|
||||
|
||||
export default function SetColorHandler(commandStack) {
|
||||
this._commandStack = commandStack;
|
||||
}
|
||||
|
||||
SetColorHandler.$inject = [
|
||||
'commandStack'
|
||||
];
|
||||
|
||||
|
||||
SetColorHandler.prototype.postExecute = function(context) {
|
||||
var elements = context.elements,
|
||||
colors = context.colors || DEFAULT_COLORS;
|
||||
|
||||
var self = this;
|
||||
|
||||
var di = {};
|
||||
|
||||
if ('fill' in colors) {
|
||||
assign(di, { fill: colors.fill });
|
||||
}
|
||||
|
||||
if ('stroke' in colors) {
|
||||
assign(di, { stroke: colors.stroke });
|
||||
}
|
||||
|
||||
forEach(elements, function(element) {
|
||||
|
||||
self._commandStack.execute('element.updateProperties', {
|
||||
element: element,
|
||||
properties: {
|
||||
di: di
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
getChildLanes,
|
||||
LANE_INDENTATION
|
||||
} from '../util/LaneUtil';
|
||||
|
||||
|
||||
/**
|
||||
* A handler that splits a lane into a number of sub-lanes,
|
||||
* creating new sub lanes, if neccessary.
|
||||
*
|
||||
* @param {Modeling} modeling
|
||||
*/
|
||||
export default function SplitLaneHandler(modeling, translate) {
|
||||
this._modeling = modeling;
|
||||
this._translate = translate;
|
||||
}
|
||||
|
||||
SplitLaneHandler.$inject = [
|
||||
'modeling',
|
||||
'translate'
|
||||
];
|
||||
|
||||
|
||||
SplitLaneHandler.prototype.preExecute = function(context) {
|
||||
|
||||
var modeling = this._modeling,
|
||||
translate = this._translate;
|
||||
|
||||
var shape = context.shape,
|
||||
newLanesCount = context.count;
|
||||
|
||||
var childLanes = getChildLanes(shape),
|
||||
existingLanesCount = childLanes.length;
|
||||
|
||||
if (existingLanesCount > newLanesCount) {
|
||||
throw new Error(translate('more than {count} child lanes', { count: newLanesCount }));
|
||||
}
|
||||
|
||||
var newLanesHeight = Math.round(shape.height / newLanesCount);
|
||||
|
||||
// Iterate from top to bottom in child lane order,
|
||||
// resizing existing lanes and creating new ones
|
||||
// so that they split the parent proportionally.
|
||||
//
|
||||
// Due to rounding related errors, the bottom lane
|
||||
// needs to take up all the remaining space.
|
||||
var laneY,
|
||||
laneHeight,
|
||||
laneBounds,
|
||||
newLaneAttrs,
|
||||
idx;
|
||||
|
||||
for (idx = 0; idx < newLanesCount; idx++) {
|
||||
|
||||
laneY = shape.y + idx * newLanesHeight;
|
||||
|
||||
// if bottom lane
|
||||
if (idx === newLanesCount - 1) {
|
||||
laneHeight = shape.height - (newLanesHeight * idx);
|
||||
} else {
|
||||
laneHeight = newLanesHeight;
|
||||
}
|
||||
|
||||
laneBounds = {
|
||||
x: shape.x + LANE_INDENTATION,
|
||||
y: laneY,
|
||||
width: shape.width - LANE_INDENTATION,
|
||||
height: laneHeight
|
||||
};
|
||||
|
||||
if (idx < existingLanesCount) {
|
||||
// resize existing lane
|
||||
modeling.resizeShape(childLanes[idx], laneBounds);
|
||||
} else {
|
||||
// create a new lane at position
|
||||
newLaneAttrs = {
|
||||
type: 'bpmn:Lane'
|
||||
};
|
||||
|
||||
modeling.createShape(newLaneAttrs, laneBounds, shape);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
add as collectionAdd,
|
||||
remove as collectionRemove
|
||||
} from 'diagram-js/lib/util/Collections';
|
||||
|
||||
|
||||
export default function UpdateCanvasRootHandler(canvas, modeling) {
|
||||
this._canvas = canvas;
|
||||
this._modeling = modeling;
|
||||
}
|
||||
|
||||
UpdateCanvasRootHandler.$inject = [
|
||||
'canvas',
|
||||
'modeling'
|
||||
];
|
||||
|
||||
|
||||
UpdateCanvasRootHandler.prototype.execute = function(context) {
|
||||
|
||||
var canvas = this._canvas;
|
||||
|
||||
var newRoot = context.newRoot,
|
||||
newRootBusinessObject = newRoot.businessObject,
|
||||
oldRoot = canvas.getRootElement(),
|
||||
oldRootBusinessObject = oldRoot.businessObject,
|
||||
bpmnDefinitions = oldRootBusinessObject.$parent,
|
||||
diPlane = oldRootBusinessObject.di;
|
||||
|
||||
// (1) replace process old <> new root
|
||||
canvas.setRootElement(newRoot, true);
|
||||
|
||||
// (2) update root elements
|
||||
collectionAdd(bpmnDefinitions.rootElements, newRootBusinessObject);
|
||||
newRootBusinessObject.$parent = bpmnDefinitions;
|
||||
|
||||
collectionRemove(bpmnDefinitions.rootElements, oldRootBusinessObject);
|
||||
oldRootBusinessObject.$parent = null;
|
||||
|
||||
// (3) wire di
|
||||
oldRootBusinessObject.di = null;
|
||||
|
||||
diPlane.bpmnElement = newRootBusinessObject;
|
||||
newRootBusinessObject.di = diPlane;
|
||||
|
||||
context.oldRoot = oldRoot;
|
||||
|
||||
// TODO(nikku): return changed elements?
|
||||
// return [ newRoot, oldRoot ];
|
||||
};
|
||||
|
||||
|
||||
UpdateCanvasRootHandler.prototype.revert = function(context) {
|
||||
|
||||
var canvas = this._canvas;
|
||||
|
||||
var newRoot = context.newRoot,
|
||||
newRootBusinessObject = newRoot.businessObject,
|
||||
oldRoot = context.oldRoot,
|
||||
oldRootBusinessObject = oldRoot.businessObject,
|
||||
bpmnDefinitions = newRootBusinessObject.$parent,
|
||||
diPlane = newRootBusinessObject.di;
|
||||
|
||||
// (1) replace process old <> new root
|
||||
canvas.setRootElement(oldRoot, true);
|
||||
|
||||
// (2) update root elements
|
||||
collectionRemove(bpmnDefinitions.rootElements, newRootBusinessObject);
|
||||
newRootBusinessObject.$parent = null;
|
||||
|
||||
collectionAdd(bpmnDefinitions.rootElements, oldRootBusinessObject);
|
||||
oldRootBusinessObject.$parent = bpmnDefinitions;
|
||||
|
||||
// (3) wire di
|
||||
newRootBusinessObject.di = null;
|
||||
|
||||
diPlane.bpmnElement = oldRootBusinessObject;
|
||||
oldRootBusinessObject.di = diPlane;
|
||||
|
||||
// TODO(nikku): return changed elements?
|
||||
// return [ newRoot, oldRoot ];
|
||||
};
|
||||
@@ -0,0 +1,193 @@
|
||||
import {
|
||||
collectLanes,
|
||||
getLanesRoot
|
||||
} from '../util/LaneUtil';
|
||||
|
||||
import {
|
||||
is
|
||||
} from '../../../util/ModelUtil';
|
||||
|
||||
import {
|
||||
add as collectionAdd,
|
||||
remove as collectionRemove
|
||||
} from 'diagram-js/lib/util/Collections';
|
||||
|
||||
import {
|
||||
asTRBL
|
||||
} from 'diagram-js/lib/layout/LayoutUtil';
|
||||
|
||||
var FLOW_NODE_REFS_ATTR = 'flowNodeRef',
|
||||
LANES_ATTR = 'lanes';
|
||||
|
||||
|
||||
/**
|
||||
* A handler that updates lane refs on changed elements
|
||||
*/
|
||||
export default function UpdateFlowNodeRefsHandler(elementRegistry) {
|
||||
this._elementRegistry = elementRegistry;
|
||||
}
|
||||
|
||||
UpdateFlowNodeRefsHandler.$inject = [
|
||||
'elementRegistry'
|
||||
];
|
||||
|
||||
|
||||
UpdateFlowNodeRefsHandler.prototype.computeUpdates = function(flowNodeShapes, laneShapes) {
|
||||
|
||||
var handledNodes = {};
|
||||
|
||||
var updates = [];
|
||||
|
||||
var participantCache = {};
|
||||
|
||||
var allFlowNodeShapes = [];
|
||||
|
||||
function isInLaneShape(element, laneShape) {
|
||||
|
||||
var laneTrbl = asTRBL(laneShape);
|
||||
|
||||
var elementMid = {
|
||||
x: element.x + element.width / 2,
|
||||
y: element.y + element.height / 2
|
||||
};
|
||||
|
||||
return elementMid.x > laneTrbl.left &&
|
||||
elementMid.x < laneTrbl.right &&
|
||||
elementMid.y > laneTrbl.top &&
|
||||
elementMid.y < laneTrbl.bottom;
|
||||
}
|
||||
|
||||
function addFlowNodeShape(flowNodeShape) {
|
||||
if (!handledNodes[flowNodeShape.id]) {
|
||||
allFlowNodeShapes.push(flowNodeShape);
|
||||
handledNodes[flowNodeShape.id] = flowNodeShape;
|
||||
}
|
||||
}
|
||||
|
||||
function getAllLaneShapes(flowNodeShape) {
|
||||
|
||||
var root = getLanesRoot(flowNodeShape);
|
||||
|
||||
if (!participantCache[root.id]) {
|
||||
participantCache[root.id] = collectLanes(root);
|
||||
}
|
||||
|
||||
return participantCache[root.id];
|
||||
}
|
||||
|
||||
function getNewLanes(flowNodeShape) {
|
||||
if (!flowNodeShape.parent) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var allLaneShapes = getAllLaneShapes(flowNodeShape);
|
||||
|
||||
return allLaneShapes.filter(function(l) {
|
||||
return isInLaneShape(flowNodeShape, l);
|
||||
}).map(function(shape) {
|
||||
return shape.businessObject;
|
||||
});
|
||||
}
|
||||
|
||||
laneShapes.forEach(function(laneShape) {
|
||||
var root = getLanesRoot(laneShape);
|
||||
|
||||
if (!root || handledNodes[root.id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var children = root.children.filter(function(c) {
|
||||
return is(c, 'bpmn:FlowNode');
|
||||
});
|
||||
|
||||
children.forEach(addFlowNodeShape);
|
||||
|
||||
handledNodes[root.id] = root;
|
||||
});
|
||||
|
||||
flowNodeShapes.forEach(addFlowNodeShape);
|
||||
|
||||
|
||||
allFlowNodeShapes.forEach(function(flowNodeShape) {
|
||||
|
||||
var flowNode = flowNodeShape.businessObject;
|
||||
|
||||
var lanes = flowNode.get(LANES_ATTR),
|
||||
remove = lanes.slice(),
|
||||
add = getNewLanes(flowNodeShape);
|
||||
|
||||
updates.push({ flowNode: flowNode, remove: remove, add: add });
|
||||
});
|
||||
|
||||
laneShapes.forEach(function(laneShape) {
|
||||
|
||||
var lane = laneShape.businessObject;
|
||||
|
||||
// lane got removed XX-)
|
||||
if (!laneShape.parent) {
|
||||
lane.get(FLOW_NODE_REFS_ATTR).forEach(function(flowNode) {
|
||||
updates.push({ flowNode: flowNode, remove: [ lane ], add: [] });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return updates;
|
||||
};
|
||||
|
||||
UpdateFlowNodeRefsHandler.prototype.execute = function(context) {
|
||||
|
||||
var updates = context.updates;
|
||||
|
||||
if (!updates) {
|
||||
updates = context.updates = this.computeUpdates(context.flowNodeShapes, context.laneShapes);
|
||||
}
|
||||
|
||||
|
||||
updates.forEach(function(update) {
|
||||
|
||||
var flowNode = update.flowNode,
|
||||
lanes = flowNode.get(LANES_ATTR);
|
||||
|
||||
// unwire old
|
||||
update.remove.forEach(function(oldLane) {
|
||||
collectionRemove(lanes, oldLane);
|
||||
collectionRemove(oldLane.get(FLOW_NODE_REFS_ATTR), flowNode);
|
||||
});
|
||||
|
||||
// wire new
|
||||
update.add.forEach(function(newLane) {
|
||||
collectionAdd(lanes, newLane);
|
||||
collectionAdd(newLane.get(FLOW_NODE_REFS_ATTR), flowNode);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(nikku): return changed elements
|
||||
// return [ ... ];
|
||||
};
|
||||
|
||||
|
||||
UpdateFlowNodeRefsHandler.prototype.revert = function(context) {
|
||||
|
||||
var updates = context.updates;
|
||||
|
||||
updates.forEach(function(update) {
|
||||
|
||||
var flowNode = update.flowNode,
|
||||
lanes = flowNode.get(LANES_ATTR);
|
||||
|
||||
// unwire new
|
||||
update.add.forEach(function(newLane) {
|
||||
collectionRemove(lanes, newLane);
|
||||
collectionRemove(newLane.get(FLOW_NODE_REFS_ATTR), flowNode);
|
||||
});
|
||||
|
||||
// wire old
|
||||
update.remove.forEach(function(oldLane) {
|
||||
collectionAdd(lanes, oldLane);
|
||||
collectionAdd(oldLane.get(FLOW_NODE_REFS_ATTR), flowNode);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(nikku): return changed elements
|
||||
// return [ ... ];
|
||||
};
|
||||
@@ -0,0 +1,234 @@
|
||||
import {
|
||||
reduce,
|
||||
keys,
|
||||
forEach,
|
||||
assign
|
||||
} from 'min-dash';
|
||||
|
||||
import {
|
||||
getBusinessObject
|
||||
} from '../../../util/ModelUtil';
|
||||
|
||||
var DEFAULT_FLOW = 'default',
|
||||
ID = 'id',
|
||||
DI = 'di';
|
||||
|
||||
var NULL_DIMENSIONS = {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* A handler that implements a BPMN 2.0 property update.
|
||||
*
|
||||
* This should be used to set simple properties on elements with
|
||||
* an underlying BPMN business object.
|
||||
*
|
||||
* Use respective diagram-js provided handlers if you would
|
||||
* like to perform automated modeling.
|
||||
*/
|
||||
export default function UpdatePropertiesHandler(
|
||||
elementRegistry, moddle, translate,
|
||||
modeling, textRenderer) {
|
||||
|
||||
this._elementRegistry = elementRegistry;
|
||||
this._moddle = moddle;
|
||||
this._translate = translate;
|
||||
this._modeling = modeling;
|
||||
this._textRenderer = textRenderer;
|
||||
}
|
||||
|
||||
UpdatePropertiesHandler.$inject = [
|
||||
'elementRegistry',
|
||||
'moddle',
|
||||
'translate',
|
||||
'modeling',
|
||||
'textRenderer'
|
||||
];
|
||||
|
||||
|
||||
// api //////////////////////
|
||||
|
||||
/**
|
||||
* Updates a BPMN element with a list of new properties
|
||||
*
|
||||
* @param {Object} context
|
||||
* @param {djs.model.Base} context.element the element to update
|
||||
* @param {Object} context.properties a list of properties to set on the element's
|
||||
* businessObject (the BPMN model element)
|
||||
*
|
||||
* @return {Array<djs.model.Base>} the updated element
|
||||
*/
|
||||
UpdatePropertiesHandler.prototype.execute = function(context) {
|
||||
|
||||
var element = context.element,
|
||||
changed = [ element ],
|
||||
translate = this._translate;
|
||||
|
||||
if (!element) {
|
||||
throw new Error(translate('element required'));
|
||||
}
|
||||
|
||||
var elementRegistry = this._elementRegistry,
|
||||
ids = this._moddle.ids;
|
||||
|
||||
var businessObject = element.businessObject,
|
||||
properties = unwrapBusinessObjects(context.properties),
|
||||
oldProperties = context.oldProperties || getProperties(businessObject, properties);
|
||||
|
||||
if (isIdChange(properties, businessObject)) {
|
||||
ids.unclaim(businessObject[ID]);
|
||||
|
||||
elementRegistry.updateId(element, properties[ID]);
|
||||
|
||||
ids.claim(properties[ID], businessObject);
|
||||
}
|
||||
|
||||
// correctly indicate visual changes on default flow updates
|
||||
if (DEFAULT_FLOW in properties) {
|
||||
|
||||
if (properties[DEFAULT_FLOW]) {
|
||||
changed.push(elementRegistry.get(properties[DEFAULT_FLOW].id));
|
||||
}
|
||||
|
||||
if (businessObject[DEFAULT_FLOW]) {
|
||||
changed.push(elementRegistry.get(businessObject[DEFAULT_FLOW].id));
|
||||
}
|
||||
}
|
||||
|
||||
// update properties
|
||||
setProperties(businessObject, properties);
|
||||
|
||||
// store old values
|
||||
context.oldProperties = oldProperties;
|
||||
context.changed = changed;
|
||||
|
||||
// indicate changed on objects affected by the update
|
||||
return changed;
|
||||
};
|
||||
|
||||
|
||||
UpdatePropertiesHandler.prototype.postExecute = function(context) {
|
||||
var element = context.element,
|
||||
label = element.label;
|
||||
|
||||
var text = label && getBusinessObject(label).name;
|
||||
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get layouted text bounds and resize external
|
||||
// external label accordingly
|
||||
var newLabelBounds = this._textRenderer.getExternalLabelBounds(label, text);
|
||||
|
||||
this._modeling.resizeShape(label, newLabelBounds, NULL_DIMENSIONS);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverts the update on a BPMN elements properties.
|
||||
*
|
||||
* @param {Object} context
|
||||
*
|
||||
* @return {djs.model.Base} the updated element
|
||||
*/
|
||||
UpdatePropertiesHandler.prototype.revert = function(context) {
|
||||
|
||||
var element = context.element,
|
||||
properties = context.properties,
|
||||
oldProperties = context.oldProperties,
|
||||
businessObject = element.businessObject,
|
||||
elementRegistry = this._elementRegistry,
|
||||
ids = this._moddle.ids;
|
||||
|
||||
// update properties
|
||||
setProperties(businessObject, oldProperties);
|
||||
|
||||
if (isIdChange(properties, businessObject)) {
|
||||
ids.unclaim(properties[ID]);
|
||||
|
||||
elementRegistry.updateId(element, oldProperties[ID]);
|
||||
|
||||
ids.claim(oldProperties[ID], businessObject);
|
||||
}
|
||||
|
||||
return context.changed;
|
||||
};
|
||||
|
||||
|
||||
function isIdChange(properties, businessObject) {
|
||||
return ID in properties && properties[ID] !== businessObject[ID];
|
||||
}
|
||||
|
||||
|
||||
function getProperties(businessObject, properties) {
|
||||
var propertyNames = keys(properties);
|
||||
|
||||
return reduce(propertyNames, function(result, key) {
|
||||
|
||||
// handle DI seperately
|
||||
if (key !== DI) {
|
||||
result[key] = businessObject.get(key);
|
||||
} else {
|
||||
result[key] = getDiProperties(businessObject.di, keys(properties.di));
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
||||
|
||||
function getDiProperties(di, propertyNames) {
|
||||
return reduce(propertyNames, function(result, key) {
|
||||
result[key] = di.get(key);
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
||||
|
||||
function setProperties(businessObject, properties) {
|
||||
forEach(properties, function(value, key) {
|
||||
|
||||
if (key !== DI) {
|
||||
businessObject.set(key, value);
|
||||
} else {
|
||||
// only update, if businessObject.di exists
|
||||
if (businessObject.di) {
|
||||
setDiProperties(businessObject.di, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function setDiProperties(di, properties) {
|
||||
forEach(properties, function(value, key) {
|
||||
di.set(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var referencePropertyNames = [ 'default' ];
|
||||
|
||||
/**
|
||||
* Make sure we unwrap the actual business object
|
||||
* behind diagram element that may have been
|
||||
* passed as arguments.
|
||||
*
|
||||
* @param {Object} properties
|
||||
*
|
||||
* @return {Object} unwrappedProps
|
||||
*/
|
||||
function unwrapBusinessObjects(properties) {
|
||||
|
||||
var unwrappedProps = assign({}, properties);
|
||||
|
||||
referencePropertyNames.forEach(function(name) {
|
||||
if (name in properties) {
|
||||
unwrappedProps[name] = getBusinessObject(unwrappedProps[name]);
|
||||
}
|
||||
});
|
||||
|
||||
return unwrappedProps;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
export default function UpdateSemanticParentHandler(bpmnUpdater) {
|
||||
this._bpmnUpdater = bpmnUpdater;
|
||||
}
|
||||
|
||||
UpdateSemanticParentHandler.$inject = [ 'bpmnUpdater' ];
|
||||
|
||||
|
||||
UpdateSemanticParentHandler.prototype.execute = function(context) {
|
||||
var dataStoreBo = context.dataStoreBo,
|
||||
newSemanticParent = context.newSemanticParent,
|
||||
newDiParent = context.newDiParent;
|
||||
|
||||
context.oldSemanticParent = dataStoreBo.$parent;
|
||||
context.oldDiParent = dataStoreBo.di.$parent;
|
||||
|
||||
// update semantic parent
|
||||
this._bpmnUpdater.updateSemanticParent(dataStoreBo, newSemanticParent);
|
||||
|
||||
// update DI parent
|
||||
this._bpmnUpdater.updateDiParent(dataStoreBo.di, newDiParent);
|
||||
};
|
||||
|
||||
UpdateSemanticParentHandler.prototype.revert = function(context) {
|
||||
var dataStoreBo = context.dataStoreBo,
|
||||
oldSemanticParent = context.oldSemanticParent,
|
||||
oldDiParent = context.oldDiParent;
|
||||
|
||||
// update semantic parent
|
||||
this._bpmnUpdater.updateSemanticParent(dataStoreBo, oldSemanticParent);
|
||||
|
||||
// update DI parent
|
||||
this._bpmnUpdater.updateDiParent(dataStoreBo.di, oldDiParent);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user