mirror of
https://github.com/bpmn-io/bpmn-js.git
synced 2025-08-14 01:57:37 +08:00
feat(lib): Promisify public APIs
This commit promisifies following APIs: BaseViewer#importXML BaseViewer#importDefinitions BaseViewer#open BaseViewer#saveXML BaseViewer#saveSVG Modeler#createDiagram Related to https://github.com/bpmn-io/bpmn-js/issues/812 BREAKING CHANGES: * Users are now expected to have Promises either by default or polyfilled as the APIs return a Promise now.
This commit is contained in:

committed by
Nico Rehwaldt

parent
ef2a6d0cd0
commit
04ca31fac9
@ -7,7 +7,6 @@
|
||||
import {
|
||||
assign,
|
||||
find,
|
||||
isFunction,
|
||||
isNumber,
|
||||
omit
|
||||
} from 'min-dash';
|
||||
@ -68,6 +67,21 @@ export default function BaseViewer(options) {
|
||||
|
||||
inherits(BaseViewer, Diagram);
|
||||
|
||||
/**
|
||||
* The importXML result.
|
||||
*
|
||||
* @typedef {Object} ImportXMLResult
|
||||
*
|
||||
* @property {Array<string>} warnings
|
||||
*/
|
||||
|
||||
/**
|
||||
* The importXML error.
|
||||
*
|
||||
* @typedef {Error} ImportXMLError
|
||||
*
|
||||
* @property {Array<string>} warnings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse and render a BPMN 2.0 diagram.
|
||||
@ -89,65 +103,83 @@ inherits(BaseViewer, Diagram);
|
||||
*
|
||||
* @param {string} xml the BPMN 2.0 xml
|
||||
* @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
|
||||
* @param {Function} [done] invoked with (err, warnings=[])
|
||||
*
|
||||
* Returns {Promise<ImportXMLResult, ImportXMLError>}
|
||||
*/
|
||||
BaseViewer.prototype.importXML = wrapForCompatibility(function importXML(xml, bpmnDiagram, done) {
|
||||
|
||||
if (isFunction(bpmnDiagram)) {
|
||||
done = bpmnDiagram;
|
||||
bpmnDiagram = null;
|
||||
}
|
||||
|
||||
// done is optional
|
||||
done = done || function() {};
|
||||
BaseViewer.prototype.importXML = wrapForCompatibility(function importXML(xml, bpmnDiagram) {
|
||||
|
||||
var self = this;
|
||||
|
||||
// hook in pre-parse listeners +
|
||||
// allow xml manipulation
|
||||
xml = this._emit('import.parse.start', { xml: xml }) || xml;
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
this._moddle.fromXML(xml, 'bpmn:Definitions').then(function(result) {
|
||||
var definitions = result.rootElement;
|
||||
var references = result.references;
|
||||
var parseWarnings = result.warnings;
|
||||
var elementsById = result.elementsById;
|
||||
// hook in pre-parse listeners +
|
||||
// allow xml manipulation
|
||||
xml = self._emit('import.parse.start', { xml: xml }) || xml;
|
||||
|
||||
var context = {
|
||||
elementsById: elementsById,
|
||||
references: references,
|
||||
warnings: parseWarnings
|
||||
};
|
||||
self._moddle.fromXML(xml, 'bpmn:Definitions').then(function(result) {
|
||||
var definitions = result.rootElement;
|
||||
var references = result.references;
|
||||
var parseWarnings = result.warnings;
|
||||
var elementsById = result.elementsById;
|
||||
|
||||
// hook in post parse listeners +
|
||||
// allow definitions manipulation
|
||||
definitions = self._emit('import.parse.complete', {
|
||||
error: null,
|
||||
definitions: definitions,
|
||||
context: context
|
||||
}) || definitions;
|
||||
var context = {
|
||||
elementsById: elementsById,
|
||||
references: references,
|
||||
warnings: parseWarnings
|
||||
};
|
||||
|
||||
self.importDefinitions(definitions, bpmnDiagram, function(err, importWarnings) {
|
||||
var allWarnings = [].concat(parseWarnings, importWarnings || []);
|
||||
// hook in post parse listeners +
|
||||
// allow definitions manipulation
|
||||
definitions = self._emit('import.parse.complete', {
|
||||
error: null,
|
||||
definitions: definitions,
|
||||
context: context
|
||||
}) || definitions;
|
||||
|
||||
self._emit('import.done', { error: err, warnings: allWarnings });
|
||||
self.importDefinitions(definitions, bpmnDiagram).then(function(result) {
|
||||
var allWarnings = [].concat(parseWarnings, result.warnings || []);
|
||||
|
||||
done(err, allWarnings);
|
||||
self._emit('import.done', { error: null, warnings: allWarnings });
|
||||
|
||||
return resolve({ warnings: allWarnings });
|
||||
}).catch(function(err) {
|
||||
var allWarnings = [].concat(parseWarnings, err.warnings || []);
|
||||
|
||||
self._emit('import.done', { error: err, warnings: allWarnings });
|
||||
|
||||
return reject(addWarningsToError(err, allWarnings));
|
||||
});
|
||||
}).catch(function(err) {
|
||||
|
||||
self._emit('import.parse.complete', {
|
||||
error: err
|
||||
});
|
||||
|
||||
err = checkValidationError(err);
|
||||
|
||||
self._emit('import.done', { error: err, warnings: err.warnings });
|
||||
|
||||
return reject(err);
|
||||
});
|
||||
}).catch(function(err) {
|
||||
|
||||
self._emit('import.parse.complete', {
|
||||
error: err
|
||||
});
|
||||
|
||||
err = checkValidationError(err);
|
||||
|
||||
self._emit('import.done', { error: err, warnings: err.warnings });
|
||||
|
||||
return done(err, err.warnings);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* The importDefinitions result.
|
||||
*
|
||||
* @typedef {Object} ImportDefinitionsResult
|
||||
*
|
||||
* @property {Array<string>} warnings
|
||||
*/
|
||||
|
||||
/**
|
||||
* The importDefinitions error.
|
||||
*
|
||||
* @typedef {Error} ImportDefinitionsError
|
||||
*
|
||||
* @property {Array<string>} warnings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import parsed definitions and render a BPMN 2.0 diagram.
|
||||
*
|
||||
@ -165,23 +197,45 @@ BaseViewer.prototype.importXML = wrapForCompatibility(function importXML(xml, bp
|
||||
*
|
||||
* @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
|
||||
* @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
|
||||
* @param {Function} [done] invoked with (err, warnings=[])
|
||||
*
|
||||
* Returns {Promise<ImportDefinitionsResult, ImportDefinitionsError>}
|
||||
*/
|
||||
BaseViewer.prototype.importDefinitions = wrapForCompatibility(function importDefinitions(definitions, bpmnDiagram, done) {
|
||||
BaseViewer.prototype.importDefinitions = wrapForCompatibility(function importDefinitions(definitions, bpmnDiagram) {
|
||||
|
||||
if (isFunction(bpmnDiagram)) {
|
||||
done = bpmnDiagram;
|
||||
bpmnDiagram = null;
|
||||
}
|
||||
var self = this;
|
||||
|
||||
// done is optional
|
||||
done = done || function() {};
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
this._setDefinitions(definitions);
|
||||
self._setDefinitions(definitions);
|
||||
|
||||
return this.open(bpmnDiagram, done);
|
||||
self.open(bpmnDiagram).then(function(result) {
|
||||
|
||||
var warnings = result.warnings;
|
||||
|
||||
return resolve({ warnings: warnings });
|
||||
}).catch(function(err) {
|
||||
|
||||
return reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* The open result.
|
||||
*
|
||||
* @typedef {Object} OpenResult
|
||||
*
|
||||
* @property {Array<string>} warnings
|
||||
*/
|
||||
|
||||
/**
|
||||
* The open error.
|
||||
*
|
||||
* @typedef {Error} OpenError
|
||||
*
|
||||
* @property {Array<string>} warnings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Open diagram of previously imported XML.
|
||||
*
|
||||
@ -198,45 +252,63 @@ BaseViewer.prototype.importDefinitions = wrapForCompatibility(function importDef
|
||||
* You can use these events to hook into the life-cycle.
|
||||
*
|
||||
* @param {string|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
|
||||
* @param {Function} [done] invoked with (err, warnings=[])
|
||||
*
|
||||
* Returns {Promise<OpenResult, OpenError>}
|
||||
*/
|
||||
BaseViewer.prototype.open = wrapForCompatibility(function open(bpmnDiagramOrId, done) {
|
||||
|
||||
if (isFunction(bpmnDiagramOrId)) {
|
||||
done = bpmnDiagramOrId;
|
||||
bpmnDiagramOrId = null;
|
||||
}
|
||||
BaseViewer.prototype.open = wrapForCompatibility(function open(bpmnDiagramOrId) {
|
||||
|
||||
var definitions = this._definitions;
|
||||
var bpmnDiagram = bpmnDiagramOrId;
|
||||
|
||||
// done is optional
|
||||
done = done || function() {};
|
||||
var self = this;
|
||||
|
||||
if (!definitions) {
|
||||
return done(new Error('no XML imported'));
|
||||
}
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (!definitions) {
|
||||
var err1 = new Error('no XML imported');
|
||||
|
||||
if (typeof bpmnDiagramOrId === 'string') {
|
||||
bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
|
||||
|
||||
if (!bpmnDiagram) {
|
||||
return done(new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found'));
|
||||
return reject(addWarningsToError(err1, []));
|
||||
}
|
||||
}
|
||||
|
||||
// clear existing rendered diagram
|
||||
// catch synchronous exceptions during #clear()
|
||||
try {
|
||||
this.clear();
|
||||
} catch (error) {
|
||||
return done(error);
|
||||
}
|
||||
if (typeof bpmnDiagramOrId === 'string') {
|
||||
bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
|
||||
|
||||
// perform graphical import
|
||||
return importBpmnDiagram(this, definitions, bpmnDiagram, done);
|
||||
if (!bpmnDiagram) {
|
||||
var err2 = new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found');
|
||||
|
||||
return reject(addWarningsToError(err2, []));
|
||||
}
|
||||
}
|
||||
|
||||
// clear existing rendered diagram
|
||||
// catch synchronous exceptions during #clear()
|
||||
try {
|
||||
self.clear();
|
||||
} catch (error) {
|
||||
|
||||
return reject(addWarningsToError(error, []));
|
||||
}
|
||||
|
||||
// perform graphical import
|
||||
importBpmnDiagram(self, definitions, bpmnDiagram).then(function(result) {
|
||||
|
||||
var warnings = result.warnings;
|
||||
|
||||
return resolve({ warnings: warnings });
|
||||
}).catch(function(err) {
|
||||
|
||||
return reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* The saveXML result.
|
||||
*
|
||||
* @typedef {Object} SaveXMLResult
|
||||
*
|
||||
* @property {string} xml
|
||||
*/
|
||||
|
||||
/**
|
||||
* Export the currently displayed BPMN 2.0 diagram as
|
||||
* a BPMN 2.0 XML document.
|
||||
@ -255,52 +327,63 @@ BaseViewer.prototype.open = wrapForCompatibility(function open(bpmnDiagramOrId,
|
||||
* @param {boolean} [options.format=false] output formatted XML
|
||||
* @param {boolean} [options.preamble=true] output preamble
|
||||
*
|
||||
* @param {Function} done invoked with (err, xml)
|
||||
* Returns {Promise<SaveXMLResult, Error>}
|
||||
*/
|
||||
BaseViewer.prototype.saveXML = wrapForCompatibility(function saveXML(options, done) {
|
||||
BaseViewer.prototype.saveXML = wrapForCompatibility(function saveXML(options) {
|
||||
|
||||
if (!done) {
|
||||
done = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
var self = this;
|
||||
|
||||
var definitions = this._definitions;
|
||||
|
||||
if (!definitions) {
|
||||
return done(new Error('no definitions loaded'));
|
||||
}
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
// allow to fiddle around with definitions
|
||||
definitions = this._emit('saveXML.start', {
|
||||
definitions: definitions
|
||||
}) || definitions;
|
||||
if (!definitions) {
|
||||
var err = new Error('no definitions loaded');
|
||||
|
||||
this._moddle.toXML(definitions, options).then(function(result) {
|
||||
|
||||
var xml = result.xml;
|
||||
|
||||
try {
|
||||
xml = self._emit('saveXML.serialized', {
|
||||
error: null,
|
||||
xml: xml
|
||||
}) || xml;
|
||||
|
||||
self._emit('saveXML.done', {
|
||||
error: null,
|
||||
xml: xml
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('error in saveXML life-cycle listener', e);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
done(null, xml);
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
// allow to fiddle around with definitions
|
||||
definitions = self._emit('saveXML.start', {
|
||||
definitions: definitions
|
||||
}) || definitions;
|
||||
|
||||
self._moddle.toXML(definitions, options).then(function(result) {
|
||||
|
||||
var xml = result.xml;
|
||||
|
||||
try {
|
||||
xml = self._emit('saveXML.serialized', {
|
||||
error: null,
|
||||
xml: xml
|
||||
}) || xml;
|
||||
|
||||
self._emit('saveXML.done', {
|
||||
error: null,
|
||||
xml: xml
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('error in saveXML life-cycle listener', e);
|
||||
}
|
||||
|
||||
return resolve({ xml: xml });
|
||||
}).catch(function(err) {
|
||||
|
||||
return reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* The saveSVG result.
|
||||
*
|
||||
* @typedef {Object} SaveSVGResult
|
||||
*
|
||||
* @property {string} svg
|
||||
*/
|
||||
|
||||
/**
|
||||
* Export the currently displayed BPMN 2.0 diagram as
|
||||
* an SVG image.
|
||||
@ -315,49 +398,56 @@ BaseViewer.prototype.saveXML = wrapForCompatibility(function saveXML(options, do
|
||||
* You can use these events to hook into the life-cycle.
|
||||
*
|
||||
* @param {Object} [options]
|
||||
* @param {Function} done invoked with (err, svgStr)
|
||||
*
|
||||
* Returns {Promise<SaveSVGResult, Error>}
|
||||
*/
|
||||
BaseViewer.prototype.saveSVG = wrapForCompatibility(function saveSVG(options, done) {
|
||||
BaseViewer.prototype.saveSVG = wrapForCompatibility(function saveSVG(options) {
|
||||
|
||||
if (!done) {
|
||||
done = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
this._emit('saveSVG.start');
|
||||
var self = this;
|
||||
|
||||
var svg, err;
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
try {
|
||||
var canvas = this.get('canvas');
|
||||
self._emit('saveSVG.start');
|
||||
|
||||
var contentNode = canvas.getDefaultLayer(),
|
||||
defsNode = domQuery('defs', canvas._svg);
|
||||
var svg, err;
|
||||
|
||||
var contents = innerSVG(contentNode),
|
||||
defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
|
||||
try {
|
||||
var canvas = self.get('canvas');
|
||||
|
||||
var bbox = contentNode.getBBox();
|
||||
var contentNode = canvas.getDefaultLayer(),
|
||||
defsNode = domQuery('defs', canvas._svg);
|
||||
|
||||
svg =
|
||||
'<?xml version="1.0" encoding="utf-8"?>\n' +
|
||||
'<!-- created with bpmn-js / http://bpmn.io -->\n' +
|
||||
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
|
||||
'width="' + bbox.width + '" height="' + bbox.height + '" ' +
|
||||
'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
|
||||
defs + contents +
|
||||
'</svg>';
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
var contents = innerSVG(contentNode),
|
||||
defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
|
||||
|
||||
this._emit('saveSVG.done', {
|
||||
error: err,
|
||||
svg: svg
|
||||
var bbox = contentNode.getBBox();
|
||||
|
||||
svg =
|
||||
'<?xml version="1.0" encoding="utf-8"?>\n' +
|
||||
'<!-- created with bpmn-js / http://bpmn.io -->\n' +
|
||||
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
|
||||
'width="' + bbox.width + '" height="' + bbox.height + '" ' +
|
||||
'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
|
||||
defs + contents +
|
||||
'</svg>';
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
self._emit('saveSVG.done', {
|
||||
error: err,
|
||||
svg: svg
|
||||
});
|
||||
|
||||
if (!err) {
|
||||
return resolve({ svg: svg });
|
||||
}
|
||||
|
||||
return reject(err);
|
||||
});
|
||||
|
||||
done(err, svg);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -574,6 +664,11 @@ BaseViewer.prototype._modules = [];
|
||||
|
||||
// helpers ///////////////
|
||||
|
||||
function addWarningsToError(err, warningsAry) {
|
||||
err.warnings = warningsAry;
|
||||
return err;
|
||||
}
|
||||
|
||||
function checkValidationError(err) {
|
||||
|
||||
// check if we can help the user by indicating wrong BPMN 2.0 xml
|
||||
|
Reference in New Issue
Block a user