bpmn-js/lib/features/modeling/cmd/UpdateFlowNodeRefsHandler.js

186 lines
4.3 KiB
JavaScript

'use strict';
var collectLanes = require('../util/LaneUtil').collectLanes;
var getLanesRoot = require('../util/LaneUtil').getLanesRoot;
var is = require('../../../util/ModelUtil').is;
var Collections = require('diagram-js/lib/util/Collections');
var asTRBL = require('diagram-js/lib/layout/LayoutUtil').asTRBL;
var FLOW_NODE_REFS_ATTR = 'flowNodeRef',
LANES_ATTR = 'lanes';
/**
* A handler that updates lane refs on changed elements
*/
function UpdateFlowNodeRefsHandler(elementRegistry) {
this._elementRegistry = elementRegistry;
}
UpdateFlowNodeRefsHandler.$inject = [ 'elementRegistry' ];
module.exports = UpdateFlowNodeRefsHandler;
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) {
Collections.remove(lanes, oldLane);
Collections.remove(oldLane.get(FLOW_NODE_REFS_ATTR), flowNode);
});
// wire new
update.add.forEach(function(newLane) {
Collections.add(lanes, newLane);
Collections.add(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) {
Collections.remove(lanes, newLane);
Collections.remove(newLane.get(FLOW_NODE_REFS_ATTR), flowNode);
});
// wire old
update.remove.forEach(function(oldLane) {
Collections.add(lanes, oldLane);
Collections.add(oldLane.get(FLOW_NODE_REFS_ATTR), flowNode);
});
});
// TODO(nikku): return changed elements
// return [ ... ];
};