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.
225 lines
5.3 KiB
225 lines
5.3 KiB
import { |
|
find, |
|
forEach, |
|
map |
|
} from 'min-dash'; |
|
|
|
import BpmnTreeWalker from './BpmnTreeWalker'; |
|
|
|
import { is } from '../util/ModelUtil'; |
|
|
|
|
|
/** |
|
* The importBpmnDiagram result. |
|
* |
|
* @typedef {Object} ImportBPMNDiagramResult |
|
* |
|
* @property {Array<string>} warnings |
|
*/ |
|
|
|
/** |
|
* The importBpmnDiagram error. |
|
* |
|
* @typedef {Error} ImportBPMNDiagramError |
|
* |
|
* @property {Array<string>} warnings |
|
*/ |
|
|
|
/** |
|
* Import the definitions into a diagram. |
|
* |
|
* Errors and warnings are reported through the specified callback. |
|
* |
|
* @param {djs.Diagram} diagram |
|
* @param {ModdleElement<Definitions>} definitions |
|
* @param {ModdleElement<BPMNDiagram>} [bpmnDiagram] the diagram to be rendered |
|
* (if not provided, the first one will be rendered) |
|
* |
|
* Returns {Promise<ImportBPMNDiagramResult, ImportBPMNDiagramError>} |
|
*/ |
|
export function importBpmnDiagram(diagram, definitions, bpmnDiagram) { |
|
|
|
var importer, |
|
eventBus, |
|
translate, |
|
canvas; |
|
|
|
var error, |
|
warnings = []; |
|
|
|
/** |
|
* Walk the diagram semantically, importing (=drawing) |
|
* all elements you encounter. |
|
* |
|
* @param {ModdleElement<Definitions>} definitions |
|
* @param {ModdleElement<BPMNDiagram>} bpmnDiagram |
|
*/ |
|
function render(definitions, bpmnDiagram) { |
|
|
|
var visitor = { |
|
|
|
root: function(element, di) { |
|
return importer.add(element, di); |
|
}, |
|
|
|
element: function(element, di, parentShape) { |
|
return importer.add(element, di, parentShape); |
|
}, |
|
|
|
error: function(message, context) { |
|
warnings.push({ message: message, context: context }); |
|
} |
|
}; |
|
|
|
var walker = new BpmnTreeWalker(visitor, translate); |
|
|
|
|
|
bpmnDiagram = bpmnDiagram || (definitions.diagrams && definitions.diagrams[0]); |
|
|
|
var diagramsToImport = getDiagramsToImport(definitions, bpmnDiagram); |
|
|
|
if (!diagramsToImport) { |
|
throw new Error(translate('no diagram to display')); |
|
} |
|
|
|
// traverse BPMN 2.0 document model, |
|
// starting at definitions |
|
forEach(diagramsToImport, function(diagram) { |
|
walker.handleDefinitions(definitions, diagram); |
|
}); |
|
|
|
var rootId = bpmnDiagram.plane.bpmnElement.id; |
|
|
|
// we do need to account for different ways we create root elements |
|
// each nested imported <root> do have the `_plane` suffix, while |
|
// the root <root> is found under the business object ID |
|
canvas.setRootElement( |
|
canvas.findRoot(rootId + '_plane') || canvas.findRoot(rootId) |
|
); |
|
} |
|
|
|
return new Promise(function(resolve, reject) { |
|
try { |
|
importer = diagram.get('bpmnImporter'); |
|
eventBus = diagram.get('eventBus'); |
|
translate = diagram.get('translate'); |
|
canvas = diagram.get('canvas'); |
|
|
|
eventBus.fire('import.render.start', { definitions: definitions }); |
|
|
|
render(definitions, bpmnDiagram); |
|
|
|
eventBus.fire('import.render.complete', { |
|
error: error, |
|
warnings: warnings |
|
}); |
|
|
|
return resolve({ warnings: warnings }); |
|
} catch (e) { |
|
|
|
e.warnings = warnings; |
|
return reject(e); |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* Returns all diagrams in the same hierarchy as the requested diagram. |
|
* Includes all parent and sub process diagrams. |
|
* |
|
* @param {Array} definitions |
|
* @param {Object} bpmnDiagram |
|
* |
|
* @returns {Array<Object>} |
|
*/ |
|
function getDiagramsToImport(definitions, bpmnDiagram) { |
|
if (!bpmnDiagram) { |
|
return; |
|
} |
|
|
|
var bpmnElement = bpmnDiagram.plane.bpmnElement, |
|
rootElement = bpmnElement; |
|
|
|
if (!is(bpmnElement, 'bpmn:Process') && !is(bpmnElement, 'bpmn:Collaboration')) { |
|
rootElement = findRootProcess(bpmnElement); |
|
} |
|
|
|
// in case the process is part of a collaboration, the plane references the |
|
// collaboration, not the process |
|
var collaboration; |
|
|
|
if (is(rootElement, 'bpmn:Collaboration')) { |
|
collaboration = rootElement; |
|
} else { |
|
collaboration = find(definitions.rootElements, function(element) { |
|
if (!is(element, 'bpmn:Collaboration')) { |
|
return; |
|
} |
|
|
|
return find(element.participants, function(participant) { |
|
return participant.processRef === rootElement; |
|
}); |
|
}); |
|
} |
|
|
|
var rootElements = [ rootElement ]; |
|
|
|
// all collaboration processes can contain sub-diagrams |
|
if (collaboration) { |
|
rootElements = map(collaboration.participants, function(participant) { |
|
return participant.processRef; |
|
}); |
|
|
|
rootElements.push(collaboration); |
|
} |
|
|
|
var allChildren = selfAndAllFlowElements(rootElements); |
|
|
|
// if we have multiple diagrams referencing the same element, we |
|
// use the first in the file |
|
var diagramsToImport = [ bpmnDiagram ]; |
|
var handledElements = [ bpmnElement ]; |
|
|
|
forEach(definitions.diagrams, function(diagram) { |
|
var businessObject = diagram.plane.bpmnElement; |
|
|
|
if ( |
|
allChildren.indexOf(businessObject) !== -1 && |
|
handledElements.indexOf(businessObject) === -1 |
|
) { |
|
diagramsToImport.push(diagram); |
|
handledElements.push(businessObject); |
|
} |
|
}); |
|
|
|
|
|
return diagramsToImport; |
|
} |
|
|
|
function selfAndAllFlowElements(elements) { |
|
var result = []; |
|
|
|
forEach(elements, function(element) { |
|
if (!element) { |
|
return; |
|
} |
|
|
|
result.push(element); |
|
|
|
result = result.concat(selfAndAllFlowElements(element.flowElements)); |
|
}); |
|
|
|
return result; |
|
} |
|
|
|
function findRootProcess(element) { |
|
var parent = element; |
|
|
|
while (parent) { |
|
if (is(parent, 'bpmn:Process')) { |
|
return parent; |
|
} |
|
|
|
parent = parent.$parent; |
|
} |
|
} |