2014-06-11 12:41:55 +00:00
|
|
|
'use strict';
|
|
|
|
|
2014-04-09 08:50:20 +00:00
|
|
|
var Diagram = require('diagram-js'),
|
2014-04-03 17:26:00 +00:00
|
|
|
BpmnModel = require('bpmn-moddle'),
|
2014-04-08 13:23:52 +00:00
|
|
|
$ = require('jquery'),
|
|
|
|
_ = require('lodash');
|
2014-03-18 16:01:24 +00:00
|
|
|
|
2014-08-01 05:47:36 +00:00
|
|
|
var Importer = require('./import/Importer');
|
2014-04-09 08:50:20 +00:00
|
|
|
|
|
|
|
|
2014-05-23 08:58:44 +00:00
|
|
|
function getSvgContents(diagram) {
|
2014-06-23 15:16:13 +00:00
|
|
|
var outerNode = diagram.get('canvas').getContainer();
|
2014-05-23 08:58:44 +00:00
|
|
|
|
|
|
|
var svg = outerNode.innerHTML;
|
2014-06-23 15:16:13 +00:00
|
|
|
return svg.replace(/^<svg[^>]*>|<\/svg>$/g, '')
|
|
|
|
.replace('<desc>Created with Snap</desc>', '')
|
|
|
|
.replace(/<g class="viewport"( transform="[^"]*")?/, '<g');
|
2014-04-04 16:48:37 +00:00
|
|
|
}
|
2014-03-26 16:45:04 +00:00
|
|
|
|
|
|
|
function initListeners(diagram, listeners) {
|
2014-04-03 09:47:26 +00:00
|
|
|
var events = diagram.get('eventBus');
|
2014-03-26 16:45:04 +00:00
|
|
|
|
|
|
|
listeners.forEach(function(l) {
|
|
|
|
events.on(l.event, l.handler);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-06-30 17:04:40 +00:00
|
|
|
function checkValidationError(err) {
|
|
|
|
|
|
|
|
// check if we can help the user by indicating wrong BPMN 2.0 xml
|
|
|
|
// (in case he or the exporting tool did not get that right)
|
|
|
|
|
|
|
|
var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
|
|
|
|
var match = pattern.exec(err.message);
|
|
|
|
|
|
|
|
if (match) {
|
|
|
|
err.message =
|
|
|
|
'unparsable content <' + match[1] + '> detected; ' +
|
|
|
|
'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2014-04-08 13:23:52 +00:00
|
|
|
/**
|
|
|
|
* A viewer for BPMN 2.0 diagrams
|
2014-04-25 14:14:36 +00:00
|
|
|
*
|
2014-08-01 05:55:47 +00:00
|
|
|
* @class
|
|
|
|
*
|
2014-04-08 13:23:52 +00:00
|
|
|
* @param {Object} [options] configuration options to pass to the viewer
|
|
|
|
* @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
|
|
|
|
* @param {String|Number} [options.width] the width of the viewer
|
|
|
|
* @param {String|Number} [options.height] the height of the viewer
|
2014-08-01 05:55:47 +00:00
|
|
|
* @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
|
|
|
|
* @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
|
2014-04-08 13:23:52 +00:00
|
|
|
*/
|
2014-04-04 16:48:37 +00:00
|
|
|
function Viewer(options) {
|
2014-06-11 12:41:55 +00:00
|
|
|
this.options = options = options || {};
|
2014-04-08 13:23:52 +00:00
|
|
|
|
2014-04-04 16:48:37 +00:00
|
|
|
var parent = options.container || $('body');
|
|
|
|
|
2014-04-08 13:23:52 +00:00
|
|
|
var container = $('<div></div>').addClass('bjs-container').css({
|
2014-04-09 12:28:28 +00:00
|
|
|
position: 'relative'
|
2014-04-08 13:23:52 +00:00
|
|
|
}).appendTo(parent);
|
|
|
|
|
|
|
|
_.forEach([ 'width', 'height' ], function(a) {
|
|
|
|
if (options[a]) {
|
|
|
|
container.css(a, options[a]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// unwrap jquery
|
|
|
|
this.container = container.get(0);
|
2014-04-04 16:48:37 +00:00
|
|
|
|
2014-05-06 12:32:54 +00:00
|
|
|
/**
|
|
|
|
* The code in the <project-logo></project-logo> area
|
|
|
|
* must not be changed, see http://bpmn.io/license for more information
|
|
|
|
*
|
|
|
|
* <project-logo>
|
|
|
|
*/
|
2014-05-26 07:14:22 +00:00
|
|
|
|
|
|
|
/* jshint -W101 */
|
|
|
|
|
|
|
|
// inlined ../resources/bpmnjs.png
|
|
|
|
var logoData = 'iVBORw0KGgoAAAANSUhEUgAAADQAAAA0CAMAAADypuvZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADBQTFRFiMte9PrwldFwfcZPqtqN0+zEyOe1XLgjvuKncsJAZ70y6fXh3vDT////UrQV////G2zN+AAAABB0Uk5T////////////////////AOAjXRkAAAHDSURBVHjavJZJkoUgDEBJmAX8979tM8u3E6x20VlYJfFFMoL4vBDxATxZcakIOJTWSmxvKWVIkJ8jHvlRv1F2LFrVISCZI+tCtQx+XfewgVTfyY3plPiQEAzI3zWy+kR6NBhFBYeBuscJLOUuA2WVLpCjVIaFzrNQZArxAZKUQm6gsj37L9Cb7dnIBUKxENaaMJQqMpDXvSL+ktxdGRm2IsKgJGGPg7atwUG5CcFUEuSv+CwQqizTrvDTNXdMU2bMiDWZd8d7QIySWVRsb2vBBioxOFt4OinPBapL+neAb5KL5IJ8szOza2/DYoipUCx+CjO0Bpsv0V6mktNZ+k8rlABlWG0FrOpKYVo8DT3dBeLEjUBAj7moDogVii7nSS9QzZnFcOVBp1g2PyBQ3Vr5aIapN91VJy33HTJLC1iX2FY6F8gRdaAeIEfVONgtFCzZTmoLEdOjBDfsIOA6128gw3eu1shAajdZNAORxuQDJN5A5PbEG6gNIu24QJD5iNyRMZIr6bsHbCtCU/OaOaSvgkUyDMdDa1BXGf5HJ1To+/Ym6mCKT02Y+/Sa126ZKyd3jxhzpc1r8zVL6YM1Qy/kR4ABAFJ6iQUnivhAAAAAAElFTkSuQmCC';
|
|
|
|
|
|
|
|
/* jshint +W101 */
|
2014-04-04 16:48:37 +00:00
|
|
|
|
2014-04-16 11:38:59 +00:00
|
|
|
var a = $('<a href="http://bpmn.io" target="_blank" class="bjs-powered-by" title="Powered by bpmn.io" />').css({
|
2014-04-04 16:48:37 +00:00
|
|
|
position: 'absolute',
|
|
|
|
bottom: 15,
|
|
|
|
right: 15,
|
2014-04-11 15:11:10 +00:00
|
|
|
zIndex: 100
|
2014-04-04 16:48:37 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
var logo = $('<img/>').attr('src', 'data:image/png;base64,' + logoData).appendTo(a);
|
|
|
|
|
|
|
|
a.appendTo(container);
|
2014-05-06 12:32:54 +00:00
|
|
|
|
|
|
|
/* </project-logo> */
|
2014-03-18 16:01:24 +00:00
|
|
|
}
|
|
|
|
|
2014-03-21 20:10:01 +00:00
|
|
|
Viewer.prototype.importXML = function(xml, done) {
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
|
2014-04-03 17:26:00 +00:00
|
|
|
BpmnModel.fromXML(xml, 'bpmn:Definitions', function(err, definitions) {
|
2014-06-30 17:04:40 +00:00
|
|
|
|
2014-03-21 20:10:01 +00:00
|
|
|
if (err) {
|
2014-06-30 17:04:40 +00:00
|
|
|
err = checkValidationError(err);
|
2014-03-21 20:10:01 +00:00
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.importDefinitions(definitions, done);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2014-03-24 10:02:58 +00:00
|
|
|
Viewer.prototype.saveXML = function(options, done) {
|
|
|
|
|
|
|
|
if (!done) {
|
|
|
|
done = options;
|
|
|
|
options = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
var definitions = this.definitions;
|
|
|
|
|
|
|
|
if (!definitions) {
|
|
|
|
return done(new Error('no definitions loaded'));
|
|
|
|
}
|
|
|
|
|
2014-04-03 17:26:00 +00:00
|
|
|
BpmnModel.toXML(definitions, options, function(err, xml) {
|
2014-03-24 10:02:58 +00:00
|
|
|
done(err, xml);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var SVG_HEADER =
|
|
|
|
'<?xml version="1.0" encoding="utf-8"?>\n' +
|
|
|
|
'<!-- created with bpmn-js / http://bpmn.io -->\n' +
|
2014-05-28 10:19:35 +00:00
|
|
|
'<!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" version="1.1">\n';
|
2014-03-24 10:02:58 +00:00
|
|
|
|
2014-04-03 19:20:13 +00:00
|
|
|
var SVG_FOOTER = '</svg>';
|
|
|
|
|
2014-03-24 10:02:58 +00:00
|
|
|
Viewer.prototype.saveSVG = function(options, done) {
|
|
|
|
if (!done) {
|
|
|
|
done = options;
|
|
|
|
options = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.definitions) {
|
|
|
|
return done(new Error('no definitions loaded'));
|
|
|
|
}
|
|
|
|
|
2014-05-23 08:58:44 +00:00
|
|
|
var svgContents = getSvgContents(this.diagram);
|
2014-03-24 10:02:58 +00:00
|
|
|
|
2014-05-23 08:58:44 +00:00
|
|
|
var svg = SVG_HEADER + svgContents + SVG_FOOTER;
|
2014-03-24 10:02:58 +00:00
|
|
|
|
|
|
|
done(null, svg);
|
|
|
|
};
|
|
|
|
|
2014-04-04 16:48:37 +00:00
|
|
|
Viewer.prototype.get = function(name) {
|
|
|
|
|
|
|
|
if (!this.diagram) {
|
2014-06-17 09:19:31 +00:00
|
|
|
throw new Error('no diagram loaded');
|
2014-04-04 16:48:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return this.diagram.get(name);
|
|
|
|
};
|
|
|
|
|
2014-06-17 09:19:31 +00:00
|
|
|
Viewer.prototype.invoke = function(fn) {
|
|
|
|
|
|
|
|
if (!this.diagram) {
|
|
|
|
throw new Error('no diagram loaded');
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.diagram.invoke(fn);
|
|
|
|
};
|
|
|
|
|
2014-08-01 05:47:36 +00:00
|
|
|
Viewer.prototype.importDefinitions = function(definitions, done) {
|
2014-03-18 16:01:24 +00:00
|
|
|
|
2014-04-25 14:14:36 +00:00
|
|
|
var diagram = this.diagram;
|
|
|
|
|
2014-08-01 05:47:36 +00:00
|
|
|
// use try/catch to not swallow synchronous exceptions
|
|
|
|
// that may be raised during model parsing
|
|
|
|
try {
|
|
|
|
if (diagram) {
|
|
|
|
this.clear();
|
|
|
|
}
|
2014-03-18 16:01:24 +00:00
|
|
|
|
2014-08-01 05:55:47 +00:00
|
|
|
this.diagram = diagram = this._createDiagram(this.options);
|
2014-08-01 05:47:36 +00:00
|
|
|
this.definitions = definitions;
|
2014-03-18 16:01:24 +00:00
|
|
|
|
2014-08-01 05:47:36 +00:00
|
|
|
this._init(diagram);
|
2014-06-24 13:50:51 +00:00
|
|
|
|
2014-08-01 05:47:36 +00:00
|
|
|
Importer.importBpmnDiagram(diagram, definitions, done);
|
|
|
|
} catch (e) {
|
|
|
|
done(e);
|
|
|
|
}
|
|
|
|
};
|
2014-03-18 16:01:24 +00:00
|
|
|
|
2014-06-24 13:50:51 +00:00
|
|
|
Viewer.prototype._init = function(diagram) {
|
2014-04-04 16:48:37 +00:00
|
|
|
initListeners(diagram, this.__listeners || []);
|
|
|
|
};
|
|
|
|
|
2014-08-01 05:55:47 +00:00
|
|
|
Viewer.prototype._createDiagram = function(options) {
|
2014-04-09 08:50:20 +00:00
|
|
|
|
2014-08-01 05:55:47 +00:00
|
|
|
var modules = [].concat(options.modules || this.getModules(), options.additionalModules || []);
|
2014-06-17 09:19:31 +00:00
|
|
|
|
|
|
|
// add self as an available service
|
|
|
|
modules.unshift({
|
|
|
|
bpmnjs: [ 'value', this ]
|
|
|
|
});
|
|
|
|
|
2014-08-01 05:55:47 +00:00
|
|
|
options = _.omit(options, 'additionalModules');
|
|
|
|
|
|
|
|
options = _.extend(options, {
|
2014-04-09 08:50:20 +00:00
|
|
|
canvas: { container: this.container },
|
2014-06-17 09:19:31 +00:00
|
|
|
modules: modules
|
2014-04-09 08:50:20 +00:00
|
|
|
});
|
2014-08-01 05:55:47 +00:00
|
|
|
|
|
|
|
return new Diagram(options);
|
2014-03-18 16:01:24 +00:00
|
|
|
};
|
|
|
|
|
2014-06-24 13:50:51 +00:00
|
|
|
|
2014-06-17 09:19:31 +00:00
|
|
|
Viewer.prototype.getModules = function() {
|
|
|
|
return this._modules;
|
|
|
|
};
|
|
|
|
|
2014-06-24 13:50:51 +00:00
|
|
|
/**
|
|
|
|
* Remove all drawn elements from the viewer
|
|
|
|
*/
|
2014-03-20 15:18:23 +00:00
|
|
|
Viewer.prototype.clear = function() {
|
2014-04-04 16:48:37 +00:00
|
|
|
var diagram = this.diagram;
|
|
|
|
|
|
|
|
if (diagram) {
|
|
|
|
diagram.destroy();
|
|
|
|
}
|
2014-03-18 16:01:24 +00:00
|
|
|
};
|
|
|
|
|
2014-06-24 13:50:51 +00:00
|
|
|
/**
|
|
|
|
* Register an event listener on the viewer
|
|
|
|
*
|
|
|
|
* @param {String} event
|
|
|
|
* @param {Function} handler
|
|
|
|
*/
|
2014-03-26 16:45:04 +00:00
|
|
|
Viewer.prototype.on = function(event, handler) {
|
2014-04-25 14:14:36 +00:00
|
|
|
var diagram = this.diagram,
|
|
|
|
listeners = this.__listeners = this.__listeners || [];
|
|
|
|
|
|
|
|
listeners = this.__listeners || [];
|
|
|
|
listeners.push({ event: event, handler: handler });
|
|
|
|
|
|
|
|
if (diagram) {
|
|
|
|
diagram.get('eventBus').on(event, handler);
|
|
|
|
}
|
2014-03-26 16:45:04 +00:00
|
|
|
};
|
|
|
|
|
2014-06-24 13:50:51 +00:00
|
|
|
// modules the viewer is composed of
|
2014-06-17 09:19:31 +00:00
|
|
|
Viewer.prototype._modules = [
|
2014-06-19 07:49:26 +00:00
|
|
|
require('./core'),
|
2014-06-30 14:56:43 +00:00
|
|
|
require('./draw'),
|
2014-08-01 09:40:18 +00:00
|
|
|
require('diagram-js/lib/features/selection'),
|
|
|
|
require('diagram-js/lib/features/overlays')
|
2014-06-11 12:41:55 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
module.exports = Viewer;
|