/*! * bpmn-js - bpmn-modeler v0.10.3 * Copyright 2014, 2015 camunda Services GmbH and other contributors * * Released under the bpmn.io license * http://bpmn.io/license * * Source Code: https://github.com/bpmn-io/bpmn-js * * Date: 2015-05-18 */ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.BpmnJS=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + ''; /** * A modeler for BPMN 2.0 diagrams. * * * ## Extending the Modeler * * In order to extend the viewer pass extension modules to bootstrap via the * `additionalModules` option. An extension module is an object that exposes * named services. * * The following example depicts the integration of a simple * logging component that integrates with interaction events: * * * ```javascript * * // logging component * function InteractionLogger(eventBus) { * eventBus.on('element.hover', function(event) { * console.log() * }) * } * * InteractionLogger.$inject = [ 'eventBus' ]; // minification save * * // extension module * var extensionModule = { * __init__: [ 'interactionLogger' ], * interactionLogger: [ 'type', InteractionLogger ] * }; * * // extend the viewer * var bpmnModeler = new Modeler({ additionalModules: [ extensionModule ] }); * bpmnModeler.importXML(...); * ``` * * * ## Customizing / Replacing Components * * You can replace individual diagram components by redefining them in override modules. * This works for all components, including those defined in the core. * * Pass in override modules via the `options.additionalModules` flag like this: * * ```javascript * function CustomContextPadProvider(contextPad) { * * contextPad.registerProvider(this); * * this.getContextPadEntries = function(element) { * // no entries, effectively disable the context pad * return {}; * }; * } * * CustomContextPadProvider.$inject = [ 'contextPad' ]; * * var overrideModule = { * contextPadProvider: [ 'type', CustomContextPadProvider ] * }; * * var bpmnModeler = new Modeler({ additionalModules: [ overrideModule ]}); * ``` * * @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 * @param {Object} [options.moddleExtensions] extension packages to provide * @param {Array} [options.modules] a list of modules to override the default modules * @param {Array} [options.additionalModules] a list of modules to use with the default modules */ function Modeler(options) { Viewer.call(this, options); } inherits(Modeler, Viewer); Modeler.prototype.createDiagram = function(done) { return this.importXML(initialDiagram, done); }; Modeler.prototype.createModdle = function() { var moddle = Viewer.prototype.createModdle.call(this); IdSupport.extend(moddle, new Ids([ 32, 36, 1 ])); return moddle; }; Modeler.prototype._interactionModules = [ // non-modeling components _dereq_(14), _dereq_(173), _dereq_(170), _dereq_(171) ]; Modeler.prototype._modelingModules = [ // modeling components _dereq_(131), _dereq_(91), _dereq_(144), _dereq_(158), _dereq_(107), _dereq_(10), _dereq_(39), _dereq_(30), _dereq_(8), _dereq_(34) ]; // modules the modeler is composed of // // - viewer modules // - interaction modules // - modeling modules Modeler.prototype._modules = [].concat( Modeler.prototype._modules, Modeler.prototype._interactionModules, Modeler.prototype._modelingModules); module.exports = Modeler; },{"10":10,"107":107,"131":131,"14":14,"144":144,"158":158,"170":170,"171":171,"173":173,"193":193,"195":195,"2":2,"30":30,"34":34,"39":39,"50":50,"8":8,"91":91}],2:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325), omit = _dereq_(329), isString = _dereq_(322), isNumber = _dereq_(319); var domify = _dereq_(343), domQuery = _dereq_(346), domRemove = _dereq_(347); var Diagram = _dereq_(73), BpmnModdle = _dereq_(48); var Importer = _dereq_(42); function initListeners(diagram, listeners) { var events = diagram.get('eventBus'); listeners.forEach(function(l) { events.on(l.event, l.handler); }); } 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; } var DEFAULT_OPTIONS = { width: '100%', height: '100%', position: 'relative', container: 'body' }; /** * Ensure the passed argument is a proper unit (defaulting to px) */ function ensureUnit(val) { return val + (isNumber(val) ? 'px' : ''); } /** * A viewer for BPMN 2.0 diagrams. * * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include * additional features. * * * ## Extending the Viewer * * In order to extend the viewer pass extension modules to bootstrap via the * `additionalModules` option. An extension module is an object that exposes * named services. * * The following example depicts the integration of a simple * logging component that integrates with interaction events: * * * ```javascript * * // logging component * function InteractionLogger(eventBus) { * eventBus.on('element.hover', function(event) { * console.log() * }) * } * * InteractionLogger.$inject = [ 'eventBus' ]; // minification save * * // extension module * var extensionModule = { * __init__: [ 'interactionLogger' ], * interactionLogger: [ 'type', InteractionLogger ] * }; * * // extend the viewer * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] }); * bpmnViewer.importXML(...); * ``` * * @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 * @param {Object} [options.moddleExtensions] extension packages to provide * @param {Array} [options.modules] a list of modules to override the default modules * @param {Array} [options.additionalModules] a list of modules to use with the default modules */ function Viewer(options) { this.options = options = assign({}, DEFAULT_OPTIONS, options || {}); var parent = options.container; // support jquery element // unwrap it if passed if (parent.get) { parent = parent.get(0); } // support selector if (isString(parent)) { parent = domQuery(parent); } var container = this.container = domify('
'); parent.appendChild(container); assign(container.style, { width: ensureUnit(options.width), height: ensureUnit(options.height), position: options.position }); /** * The code in the area * must not be changed, see http://bpmn.io/license for more information * * */ /* 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 */ var linkMarkup = '' + '' + ''; container.appendChild(domify(linkMarkup)); /* */ } Viewer.prototype.importXML = function(xml, done) { var self = this; this.moddle = this.createModdle(); this.moddle.fromXML(xml, 'bpmn:Definitions', function(err, definitions, context) { if (err) { err = checkValidationError(err); return done(err); } var parseWarnings = context.warnings; self.importDefinitions(definitions, function(err, importWarnings) { if (err) { return done(err); } done(null, parseWarnings.concat(importWarnings || [])); }); }); }; Viewer.prototype.saveXML = function(options, done) { if (!done) { done = options; options = {}; } var definitions = this.definitions; if (!definitions) { return done(new Error('no definitions loaded')); } this.moddle.toXML(definitions, options, done); }; Viewer.prototype.createModdle = function() { return new BpmnModdle(this.options.moddleExtensions); }; Viewer.prototype.saveSVG = function(options, done) { if (!done) { done = options; options = {}; } var canvas = this.get('canvas'); var contentNode = canvas.getDefaultLayer(), defsNode = canvas._svg.select('defs'); var contents = contentNode.innerSVG(), defs = (defsNode && defsNode.outerSVG()) || ''; var bbox = contentNode.getBBox(); var svg = '\n' + '\n' + '\n' + '' + defs + contents + ''; done(null, svg); }; Viewer.prototype.get = function(name) { if (!this.diagram) { throw new Error('no diagram loaded'); } return this.diagram.get(name); }; Viewer.prototype.invoke = function(fn) { if (!this.diagram) { throw new Error('no diagram loaded'); } return this.diagram.invoke(fn); }; Viewer.prototype.importDefinitions = function(definitions, done) { // use try/catch to not swallow synchronous exceptions // that may be raised during model parsing try { if (this.diagram) { this.clear(); } this.definitions = definitions; var diagram = this.diagram = this._createDiagram(this.options); this._init(diagram); Importer.importBpmnDiagram(diagram, definitions, done); } catch (e) { done(e); } }; Viewer.prototype._init = function(diagram) { initListeners(diagram, this.__listeners || []); }; Viewer.prototype._createDiagram = function(options) { var modules = [].concat(options.modules || this.getModules(), options.additionalModules || []); // add self as an available service modules.unshift({ bpmnjs: [ 'value', this ], moddle: [ 'value', this.moddle ] }); options = omit(options, 'additionalModules'); options = assign(options, { canvas: { container: this.container }, modules: modules }); return new Diagram(options); }; Viewer.prototype.getModules = function() { return this._modules; }; /** * Remove all drawn elements from the viewer. * * After calling this method the viewer can still * be reused for opening another diagram. */ Viewer.prototype.clear = function() { var diagram = this.diagram; if (diagram) { diagram.destroy(); } }; /** * Destroy the viewer instance and remove all its remainders * from the document tree. */ Viewer.prototype.destroy = function() { // clear underlying diagram this.clear(); // remove container domRemove(this.container); }; /** * Register an event listener on the viewer * * @param {String} event * @param {Function} handler */ Viewer.prototype.on = function(event, handler) { var diagram = this.diagram, listeners = this.__listeners = this.__listeners || []; listeners.push({ event: event, handler: handler }); if (diagram) { diagram.get('eventBus').on(event, handler); } }; // modules the viewer is composed of Viewer.prototype._modules = [ _dereq_(3), _dereq_(151), _dereq_(135) ]; module.exports = Viewer; },{"135":135,"151":151,"3":3,"319":319,"322":322,"325":325,"329":329,"343":343,"346":346,"347":347,"42":42,"48":48,"73":73}],3:[function(_dereq_,module,exports){ module.exports = { __depends__: [ _dereq_(6), _dereq_(44) ] }; },{"44":44,"6":6}],4:[function(_dereq_,module,exports){ 'use strict'; var inherits = _dereq_(195), isArray = _dereq_(316), isObject = _dereq_(320), assign = _dereq_(325), forEach = _dereq_(204), every = _dereq_(201), includes = _dereq_(206), some = _dereq_(210); var DefaultRenderer = _dereq_(84), TextUtil = _dereq_(184), DiUtil = _dereq_(45); var createLine = DefaultRenderer.createLine; function BpmnRenderer(events, styles, pathMap) { DefaultRenderer.call(this, styles); var TASK_BORDER_RADIUS = 10; var INNER_OUTER_DIST = 3; var LABEL_STYLE = { fontFamily: 'Arial, sans-serif', fontSize: '12px' }; var textUtil = new TextUtil({ style: LABEL_STYLE, size: { width: 100 } }); var markers = {}; function addMarker(id, element) { markers[id] = element; } function marker(id) { return markers[id]; } function initMarkers(svg) { function createMarker(id, options) { var attrs = assign({ fill: 'black', strokeWidth: 1, strokeLinecap: 'round', strokeDasharray: 'none' }, options.attrs); var ref = options.ref || { x: 0, y: 0 }; var scale = options.scale || 1; // fix for safari / chrome / firefox bug not correctly // resetting stroke dash array if (attrs.strokeDasharray === 'none') { attrs.strokeDasharray = [10000, 1]; } var marker = options.element .attr(attrs) .marker(0, 0, 20, 20, ref.x, ref.y) .attr({ markerWidth: 20 * scale, markerHeight: 20 * scale }); return addMarker(id, marker); } createMarker('sequenceflow-end', { element: svg.path('M 1 5 L 11 10 L 1 15 Z'), ref: { x: 11, y: 10 }, scale: 0.5 }); createMarker('messageflow-start', { element: svg.circle(6, 6, 3.5), attrs: { fill: 'white', stroke: 'black' }, ref: { x: 6, y: 6 } }); createMarker('messageflow-end', { element: svg.path('m 1 5 l 0 -3 l 7 3 l -7 3 z'), attrs: { fill: 'white', stroke: 'black', strokeLinecap: 'butt' }, ref: { x: 8.5, y: 5 } }); createMarker('data-association-end', { element: svg.path('M 1 5 L 11 10 L 1 15'), attrs: { fill: 'white', stroke: 'black' }, ref: { x: 11, y: 10 }, scale: 0.5 }); createMarker('conditional-flow-marker', { element: svg.path('M 0 10 L 8 6 L 16 10 L 8 14 Z'), attrs: { fill: 'white', stroke: 'black' }, ref: { x: -1, y: 10 }, scale: 0.5 }); createMarker('conditional-default-flow-marker', { element: svg.path('M 1 4 L 5 16'), attrs: { stroke: 'black' }, ref: { x: -5, y: 10 }, scale: 0.5 }); } function computeStyle(custom, traits, defaultStyles) { if (!isArray(traits)) { defaultStyles = traits; traits = []; } return styles.style(traits || [], assign(defaultStyles, custom || {})); } function drawCircle(p, width, height, offset, attrs) { if (isObject(offset)) { attrs = offset; offset = 0; } offset = offset || 0; attrs = computeStyle(attrs, { stroke: 'black', strokeWidth: 2, fill: 'white' }); var cx = width / 2, cy = height / 2; return p.circle(cx, cy, Math.round((width + height) / 4 - offset)).attr(attrs); } function drawRect(p, width, height, r, offset, attrs) { if (isObject(offset)) { attrs = offset; offset = 0; } offset = offset || 0; attrs = computeStyle(attrs, { stroke: 'black', strokeWidth: 2, fill: 'white' }); return p.rect(offset, offset, width - offset * 2, height - offset * 2, r).attr(attrs); } function drawDiamond(p, width, height, attrs) { var x_2 = width / 2; var y_2 = height / 2; var points = [x_2, 0, width, y_2, x_2, height, 0, y_2 ]; attrs = computeStyle(attrs, { stroke: 'black', strokeWidth: 2, fill: 'white' }); return p.polygon(points).attr(attrs); } function drawLine(p, waypoints, attrs) { attrs = computeStyle(attrs, [ 'no-fill' ], { stroke: 'black', strokeWidth: 2, fill: 'none' }); return createLine(waypoints, attrs).appendTo(p); } function drawPath(p, d, attrs) { attrs = computeStyle(attrs, [ 'no-fill' ], { strokeWidth: 2, stroke: 'black' }); return p.path(d).attr(attrs); } function as(type) { return function(p, element) { return handlers[type](p, element); }; } function renderer(type) { return handlers[type]; } function renderEventContent(element, p) { var event = getSemantic(element); var isThrowing = isThrowEvent(event); if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) { return renderer('bpmn:MessageEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) { return renderer('bpmn:TimerEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) { return renderer('bpmn:ConditionalEventDefinition')(p, element); } if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) { return renderer('bpmn:SignalEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:CancelEventDefinition') && isTypedEvent(event, 'bpmn:TerminateEventDefinition', { parallelMultiple: false })) { return renderer('bpmn:MultipleEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:CancelEventDefinition') && isTypedEvent(event, 'bpmn:TerminateEventDefinition', { parallelMultiple: true })) { return renderer('bpmn:ParallelMultipleEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) { return renderer('bpmn:EscalationEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) { return renderer('bpmn:LinkEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) { return renderer('bpmn:ErrorEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) { return renderer('bpmn:CancelEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) { return renderer('bpmn:CompensateEventDefinition')(p, element, isThrowing); } if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) { return renderer('bpmn:TerminateEventDefinition')(p, element, isThrowing); } return null; } function renderLabel(p, label, options) { return textUtil.createText(p, label || '', options).addClass('djs-label'); } function renderEmbeddedLabel(p, element, align) { var semantic = getSemantic(element); return renderLabel(p, semantic.name, { box: element, align: align, padding: 5 }); } function renderExternalLabel(p, element, align) { var semantic = getSemantic(element); if (!semantic.name) { element.hidden = true; } return renderLabel(p, semantic.name, { box: element, align: align, style: { fontSize: '11px' } }); } function renderLaneLabel(p, text, element) { var textBox = renderLabel(p, text, { box: { height: 30, width: element.height }, align: 'center-middle' }); var top = -1 * element.height; textBox.transform( 'rotate(270) ' + 'translate(' + top + ',' + 0 + ')' ); } function createPathFromConnection(connection) { var waypoints = connection.waypoints; var pathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y; for (var i = 1; i < waypoints.length; i++) { pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' '; } return pathData; } var handlers = { 'bpmn:Event': function(p, element, attrs) { return drawCircle(p, element.width, element.height, attrs); }, 'bpmn:StartEvent': function(p, element) { var attrs = {}; var semantic = getSemantic(element); if (!semantic.isInterrupting) { attrs = { strokeDasharray: '6', strokeLinecap: 'round' }; } var circle = renderer('bpmn:Event')(p, element, attrs); renderEventContent(element, p); return circle; }, 'bpmn:MessageEventDefinition': function(p, element, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_MESSAGE', { xScaleFactor: 0.9, yScaleFactor: 0.9, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.235, my: 0.315 } }); var fill = isThrowing ? 'black' : 'white'; var stroke = isThrowing ? 'white' : 'black'; var messagePath = drawPath(p, pathData, { strokeWidth: 1, fill: fill, stroke: stroke }); return messagePath; }, 'bpmn:TimerEventDefinition': function(p, element) { var circle = drawCircle(p, element.width, element.height, 0.2 * element.height, { strokeWidth: 2 }); var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', { xScaleFactor: 0.75, yScaleFactor: 0.75, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.5, my: 0.5 } }); drawPath(p, pathData, { strokeWidth: 2, strokeLinecap: 'square' }); for(var i = 0;i < 12;i++) { var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', { xScaleFactor: 0.75, yScaleFactor: 0.75, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.5, my: 0.5 } }); var width = element.width / 2; var height = element.height / 2; drawPath(p, linePathData, { strokeWidth: 1, strokeLinecap: 'square', transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')' }); } return circle; }, 'bpmn:EscalationEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_ESCALATION', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.5, my: 0.555 } }); var fill = isThrowing ? 'black' : 'none'; return drawPath(p, pathData, { strokeWidth: 1, fill: fill }); }, 'bpmn:ConditionalEventDefinition': function(p, event) { var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.5, my: 0.222 } }); return drawPath(p, pathData, { strokeWidth: 1 }); }, 'bpmn:LinkEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_LINK', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.57, my: 0.263 } }); var fill = isThrowing ? 'black' : 'none'; return drawPath(p, pathData, { strokeWidth: 1, fill: fill }); }, 'bpmn:ErrorEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_ERROR', { xScaleFactor: 1.1, yScaleFactor: 1.1, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.2, my: 0.722 } }); var fill = isThrowing ? 'black' : 'none'; return drawPath(p, pathData, { strokeWidth: 1, fill: fill }); }, 'bpmn:CancelEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', { xScaleFactor: 1.0, yScaleFactor: 1.0, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.638, my: -0.055 } }); var fill = isThrowing ? 'black' : 'none'; return drawPath(p, pathData, { strokeWidth: 1, fill: fill }).transform('rotate(45)'); }, 'bpmn:CompensateEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.201, my: 0.472 } }); var fill = isThrowing ? 'black' : 'none'; return drawPath(p, pathData, { strokeWidth: 1, fill: fill }); }, 'bpmn:SignalEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_SIGNAL', { xScaleFactor: 0.9, yScaleFactor: 0.9, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.5, my: 0.2 } }); var fill = isThrowing ? 'black' : 'none'; return drawPath(p, pathData, { strokeWidth: 1, fill: fill }); }, 'bpmn:MultipleEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', { xScaleFactor: 1.1, yScaleFactor: 1.1, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.222, my: 0.36 } }); var fill = isThrowing ? 'black' : 'none'; return drawPath(p, pathData, { strokeWidth: 1, fill: fill }); }, 'bpmn:ParallelMultipleEventDefinition': function(p, event) { var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', { xScaleFactor: 1.2, yScaleFactor: 1.2, containerWidth: event.width, containerHeight: event.height, position: { mx: 0.458, my: 0.194 } }); return drawPath(p, pathData, { strokeWidth: 1 }); }, 'bpmn:EndEvent': function(p, element) { var circle = renderer('bpmn:Event')(p, element, { strokeWidth: 4 }); renderEventContent(element, p, true); return circle; }, 'bpmn:TerminateEventDefinition': function(p, element) { var circle = drawCircle(p, element.width, element.height, 8, { strokeWidth: 4, fill: 'black' }); return circle; }, 'bpmn:IntermediateEvent': function(p, element) { var outer = renderer('bpmn:Event')(p, element, { strokeWidth: 1 }); /* inner */ drawCircle(p, element.width, element.height, INNER_OUTER_DIST, { strokeWidth: 1, fill: 'none' }); renderEventContent(element, p); return outer; }, 'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'), 'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'), 'bpmn:Activity': function(p, element, attrs) { return drawRect(p, element.width, element.height, TASK_BORDER_RADIUS, attrs); }, 'bpmn:Task': function(p, element, attrs) { var rect = renderer('bpmn:Activity')(p, element, attrs); renderEmbeddedLabel(p, element, 'center-middle'); attachTaskMarkers(p, element); return rect; }, 'bpmn:ServiceTask': function(p, element) { var task = renderer('bpmn:Task')(p, element); var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', { abspos: { x: 12, y: 18 } }); /* service bg */ drawPath(p, pathDataBG, { strokeWidth: 1, fill: 'none' }); var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', { abspos: { x: 17.2, y: 18 } }); /* service fill */ drawPath(p, fillPathData, { strokeWidth: 0, stroke: 'none', fill: 'white' }); var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', { abspos: { x: 17, y: 22 } }); /* service */ drawPath(p, pathData, { strokeWidth: 1, fill: 'white' }); return task; }, 'bpmn:UserTask': function(p, element) { var task = renderer('bpmn:Task')(p, element); var x = 15; var y = 12; var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', { abspos: { x: x, y: y } }); /* user path */ drawPath(p, pathData, { strokeWidth: 0.5, fill: 'none' }); var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', { abspos: { x: x, y: y } }); /* user2 path */ drawPath(p, pathData2, { strokeWidth: 0.5, fill: 'none' }); var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', { abspos: { x: x, y: y } }); /* user3 path */ drawPath(p, pathData3, { strokeWidth: 0.5, fill: 'black' }); return task; }, 'bpmn:ManualTask': function(p, element) { var task = renderer('bpmn:Task')(p, element); var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', { abspos: { x: 17, y: 15 } }); /* manual path */ drawPath(p, pathData, { strokeWidth: 0.25, fill: 'white', stroke: 'black' }); return task; }, 'bpmn:SendTask': function(p, element) { var task = renderer('bpmn:Task')(p, element); var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: 21, containerHeight: 14, position: { mx: 0.285, my: 0.357 } }); /* send path */ drawPath(p, pathData, { strokeWidth: 1, fill: 'black', stroke: 'white' }); return task; }, 'bpmn:ReceiveTask' : function(p, element) { var semantic = getSemantic(element); var task = renderer('bpmn:Task')(p, element); var pathData; if (semantic.instantiate) { drawCircle(p, 28, 28, 20 * 0.22, { strokeWidth: 1 }); pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', { abspos: { x: 7.77, y: 9.52 } }); } else { pathData = pathMap.getScaledPath('TASK_TYPE_SEND', { xScaleFactor: 0.9, yScaleFactor: 0.9, containerWidth: 21, containerHeight: 14, position: { mx: 0.3, my: 0.4 } }); } /* receive path */ drawPath(p, pathData, { strokeWidth: 1 }); return task; }, 'bpmn:ScriptTask': function(p, element) { var task = renderer('bpmn:Task')(p, element); var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', { abspos: { x: 15, y: 20 } }); /* script path */ drawPath(p, pathData, { strokeWidth: 1 }); return task; }, 'bpmn:BusinessRuleTask': function(p, element) { var task = renderer('bpmn:Task')(p, element); var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', { abspos: { x: 8, y: 8 } }); var businessHeaderPath = drawPath(p, headerPathData); businessHeaderPath.attr({ strokeWidth: 1, fill: 'AAA' }); var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', { abspos: { x: 8, y: 8 } }); var businessPath = drawPath(p, headerData); businessPath.attr({ strokeWidth: 1 }); return task; }, 'bpmn:SubProcess': function(p, element, attrs) { var rect = renderer('bpmn:Activity')(p, element, attrs); var semantic = getSemantic(element); var expanded = DiUtil.isExpanded(semantic); var isEventSubProcess = !!semantic.triggeredByEvent; if (isEventSubProcess) { rect.attr({ strokeDasharray: '1,2' }); } renderEmbeddedLabel(p, element, expanded ? 'center-top' : 'center-middle'); if (expanded) { attachTaskMarkers(p, element); } else { attachTaskMarkers(p, element, ['SubProcessMarker']); } return rect; }, 'bpmn:AdHocSubProcess': function(p, element) { return renderer('bpmn:SubProcess')(p, element); }, 'bpmn:Transaction': function(p, element) { var outer = renderer('bpmn:SubProcess')(p, element); var innerAttrs = styles.style([ 'no-fill', 'no-events' ]); /* inner path */ drawRect(p, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs); return outer; }, 'bpmn:CallActivity': function(p, element) { return renderer('bpmn:Task')(p, element, { strokeWidth: 5 }); }, 'bpmn:Participant': function(p, element) { var lane = renderer('bpmn:Lane')(p, element, { fill: 'White' }); var expandedPool = DiUtil.isExpanded(element); if (expandedPool) { drawLine(p, [ { x: 30, y: 0 }, { x: 30, y: element.height } ]); var text = getSemantic(element).name; renderLaneLabel(p, text, element); } else { // Collapsed pool draw text inline var text2 = getSemantic(element).name; renderLabel(p, text2, { box: element, align: 'center-middle' }); } var participantMultiplicity = !!(getSemantic(element).participantMultiplicity); if(participantMultiplicity) { renderer('ParticipantMultiplicityMarker')(p, element); } return lane; }, 'bpmn:Lane': function(p, element, attrs) { var rect = drawRect(p, element.width, element.height, 0, attrs || { fill: 'none' }); var semantic = getSemantic(element); if (semantic.$type === 'bpmn:Lane') { var text = semantic.name; renderLaneLabel(p, text, element); } return rect; }, 'bpmn:InclusiveGateway': function(p, element) { var diamond = drawDiamond(p, element.width, element.height); /* circle path */ drawCircle(p, element.width, element.height, element.height * 0.24, { strokeWidth: 2.5, fill: 'none' }); return diamond; }, 'bpmn:ExclusiveGateway': function(p, element) { var diamond = drawDiamond(p, element.width, element.height); var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', { xScaleFactor: 0.4, yScaleFactor: 0.4, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.32, my: 0.3 } }); if (!!(getDi(element).isMarkerVisible)) { drawPath(p, pathData, { strokeWidth: 1, fill: 'black' }); } return diamond; }, 'bpmn:ComplexGateway': function(p, element) { var diamond = drawDiamond(p, element.width, element.height); var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', { xScaleFactor: 0.5, yScaleFactor:0.5, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.46, my: 0.26 } }); /* complex path */ drawPath(p, pathData, { strokeWidth: 1, fill: 'black' }); return diamond; }, 'bpmn:ParallelGateway': function(p, element) { var diamond = drawDiamond(p, element.width, element.height); var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', { xScaleFactor: 0.6, yScaleFactor:0.6, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.46, my: 0.2 } }); /* parallel path */ drawPath(p, pathData, { strokeWidth: 1, fill: 'black' }); return diamond; }, 'bpmn:EventBasedGateway': function(p, element) { var semantic = getSemantic(element); var diamond = drawDiamond(p, element.width, element.height); /* outer circle path */ drawCircle(p, element.width, element.height, element.height * 0.20, { strokeWidth: 1, fill: 'none' }); var type = semantic.eventGatewayType; var instantiate = !!semantic.instantiate; function drawEvent() { var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', { xScaleFactor: 0.18, yScaleFactor: 0.18, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.36, my: 0.44 } }); /* event path */ drawPath(p, pathData, { strokeWidth: 2, fill: 'none' }); } if (type === 'Parallel') { var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', { xScaleFactor: 0.4, yScaleFactor:0.4, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.474, my: 0.296 } }); var parallelPath = drawPath(p, pathData); parallelPath.attr({ strokeWidth: 1, fill: 'none' }); } else if (type === 'Exclusive') { if (!instantiate) { var innerCircle = drawCircle(p, element.width, element.height, element.height * 0.26); innerCircle.attr({ strokeWidth: 1, fill: 'none' }); } drawEvent(); } return diamond; }, 'bpmn:Gateway': function(p, element) { return drawDiamond(p, element.width, element.height); }, 'bpmn:SequenceFlow': function(p, element) { var pathData = createPathFromConnection(element); var path = drawPath(p, pathData, { strokeLinejoin: 'round', markerEnd: marker('sequenceflow-end') }); var sequenceFlow = getSemantic(element); var source = element.source.businessObject; // conditional flow marker if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Task')) { path.attr({ markerStart: marker('conditional-flow-marker') }); } // default marker if (source.default && source.$instanceOf('bpmn:Gateway') && source.default === sequenceFlow) { path.attr({ markerStart: marker('conditional-default-flow-marker') }); } return path; }, 'bpmn:Association': function(p, element, attrs) { attrs = assign({ strokeDasharray: '1,6', strokeLinecap: 'round', strokeLinejoin: 'round' }, attrs || {}); // TODO(nre): style according to directed state return drawLine(p, element.waypoints, attrs); }, 'bpmn:DataInputAssociation': function(p, element) { return renderer('bpmn:Association')(p, element, { markerEnd: marker('data-association-end') }); }, 'bpmn:DataOutputAssociation': function(p, element) { return renderer('bpmn:Association')(p, element, { markerEnd: marker('data-association-end') }); }, 'bpmn:MessageFlow': function(p, element) { var semantic = getSemantic(element), di = getDi(element); var pathData = createPathFromConnection(element); var path = drawPath(p, pathData, { markerEnd: marker('messageflow-end'), markerStart: marker('messageflow-start'), strokeDasharray: '10, 12', strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: '1.5px' }); if (semantic.messageRef) { var midPoint = path.getPointAtLength(path.getTotalLength() / 2); var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', { abspos: { x: midPoint.x, y: midPoint.y } }); var messageAttrs = { strokeWidth: 1 }; if (di.messageVisibleKind === 'initiating') { messageAttrs.fill = 'white'; messageAttrs.stroke = 'black'; } else { messageAttrs.fill = '#888'; messageAttrs.stroke = 'white'; } drawPath(p, markerPathData, messageAttrs); } return path; }, 'bpmn:DataObject': function(p, element) { var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.474, my: 0.296 } }); var elementObject = drawPath(p, pathData, { fill: 'white' }); var semantic = getSemantic(element); if (isCollection(semantic)) { renderDataItemCollection(p, element); } return elementObject; }, 'bpmn:DataObjectReference': as('bpmn:DataObject'), 'bpmn:DataInput': function(p, element) { var arrowPathData = pathMap.getRawPath('DATA_ARROW'); // page var elementObject = renderer('bpmn:DataObject')(p, element); /* input arrow path */ drawPath(p, arrowPathData, { strokeWidth: 1 }); return elementObject; }, 'bpmn:DataOutput': function(p, element) { var arrowPathData = pathMap.getRawPath('DATA_ARROW'); // page var elementObject = renderer('bpmn:DataObject')(p, element); /* output arrow path */ drawPath(p, arrowPathData, { strokeWidth: 1, fill: 'black' }); return elementObject; }, 'bpmn:DataStoreReference': function(p, element) { var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: 0, my: 0.133 } }); var elementStore = drawPath(p, DATA_STORE_PATH, { strokeWidth: 2, fill: 'white' }); return elementStore; }, 'bpmn:BoundaryEvent': function(p, element) { var semantic = getSemantic(element), cancel = semantic.cancelActivity; var attrs = { strokeLinecap: 'round', strokeWidth: 1 }; if (!cancel) { attrs.strokeDasharray = '6'; } var outer = renderer('bpmn:Event')(p, element, attrs); /* inner path */ drawCircle(p, element.width, element.height, INNER_OUTER_DIST, attrs); renderEventContent(element, p); return outer; }, 'bpmn:Group': function(p, element) { return drawRect(p, element.width, element.height, TASK_BORDER_RADIUS, { strokeWidth: 1, strokeDasharray: '8,3,1,3', fill: 'none', pointerEvents: 'none' }); }, 'label': function(p, element) { return renderExternalLabel(p, element, ''); }, 'bpmn:TextAnnotation': function(p, element) { var style = { 'fill': 'none', 'stroke': 'none' }; var textElement = drawRect(p, element.width, element.height, 0, 0, style); var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.0, my: 0.0 } }); drawPath(p, textPathData); var text = getSemantic(element).text || ''; renderLabel(p, text, { box: element, align: 'left-middle', padding: 5 }); return textElement; }, 'ParticipantMultiplicityMarker': function(p, element) { var subProcessPath = pathMap.getScaledPath('MARKER_PARALLEL', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: ((element.width / 2) / element.width), my: (element.height - 15) / element.height } }); drawPath(p, subProcessPath); }, 'SubProcessMarker': function(p, element) { var markerRect = drawRect(p, 14, 14, 0, { strokeWidth: 1 }); // Process marker is placed in the middle of the box // therefore fixed values can be used here markerRect.transform('translate(' + (element.width / 2 - 7.5) + ',' + (element.height - 20) + ')'); var subProcessPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', { xScaleFactor: 1.5, yScaleFactor: 1.5, containerWidth: element.width, containerHeight: element.height, position: { mx: (element.width / 2 - 7.5) / element.width, my: (element.height - 20) / element.height } }); drawPath(p, subProcessPath); }, 'ParallelMarker': function(p, element, position) { var subProcessPath = pathMap.getScaledPath('MARKER_PARALLEL', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: ((element.width / 2 + position.parallel) / element.width), my: (element.height - 20) / element.height } }); drawPath(p, subProcessPath); }, 'SequentialMarker': function(p, element, position) { var sequentialPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: ((element.width / 2 + position.seq) / element.width), my: (element.height - 19) / element.height } }); drawPath(p, sequentialPath); }, 'CompensationMarker': function(p, element, position) { var compensationPath = pathMap.getScaledPath('MARKER_COMPENSATION', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: ((element.width / 2 + position.compensation) / element.width), my: (element.height - 13) / element.height } }); drawPath(p, compensationPath, { strokeWidth: 1 }); }, 'LoopMarker': function(p, element, position) { var loopPath = pathMap.getScaledPath('MARKER_LOOP', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: ((element.width / 2 + position.loop) / element.width), my: (element.height - 7) / element.height } }); drawPath(p, loopPath, { strokeWidth: 1, fill: 'none', strokeLinecap: 'round', strokeMiterlimit: 0.5 }); }, 'AdhocMarker': function(p, element, position) { var loopPath = pathMap.getScaledPath('MARKER_ADHOC', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: ((element.width / 2 + position.adhoc) / element.width), my: (element.height - 15) / element.height } }); drawPath(p, loopPath, { strokeWidth: 1, fill: 'black' }); } }; function attachTaskMarkers(p, element, taskMarkers) { var obj = getSemantic(element); var subprocess = includes(taskMarkers, 'SubProcessMarker'); var position; if (subprocess) { position = { seq: -21, parallel: -22, compensation: -42, loop: -18, adhoc: 10 }; } else { position = { seq: -3, parallel: -6, compensation: -27, loop: 0, adhoc: 10 }; } forEach(taskMarkers, function(marker) { renderer(marker)(p, element, position); }); if (obj.$type === 'bpmn:AdHocSubProcess') { renderer('AdhocMarker')(p, element, position); } if (obj.loopCharacteristics && obj.loopCharacteristics.isSequential === undefined) { renderer('LoopMarker')(p, element, position); return; } if (obj.loopCharacteristics && obj.loopCharacteristics.isSequential !== undefined && !obj.loopCharacteristics.isSequential) { renderer('ParallelMarker')(p, element, position); } if (obj.loopCharacteristics && !!obj.loopCharacteristics.isSequential) { renderer('SequentialMarker')(p, element, position); } if (!!obj.isForCompensation) { renderer('CompensationMarker')(p, element, position); } } function drawShape(parent, element) { var type = element.type; var h = handlers[type]; /* jshint -W040 */ if (!h) { return DefaultRenderer.prototype.drawShape.apply(this, [ parent, element ]); } else { return h(parent, element); } } function drawConnection(parent, element) { var type = element.type; var h = handlers[type]; /* jshint -W040 */ if (!h) { return DefaultRenderer.prototype.drawConnection.apply(this, [ parent, element ]); } else { return h(parent, element); } } function renderDataItemCollection(p, element) { var yPosition = (element.height - 16) / element.height; var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', { xScaleFactor: 1, yScaleFactor: 1, containerWidth: element.width, containerHeight: element.height, position: { mx: 0.451, my: yPosition } }); /* collection path */ drawPath(p, pathData, { strokeWidth: 2 }); } function isCollection(element, filter) { return element.isCollection || (element.elementObjectRef && element.elementObjectRef.isCollection); } function getDi(element) { return element.businessObject.di; } function getSemantic(element) { return element.businessObject; } /** * Checks if eventDefinition of the given element matches with semantic type. * * @return {boolean} true if element is of the given semantic type */ function isTypedEvent(event, eventDefinitionType, filter) { function matches(definition, filter) { return every(filter, function(val, key) { // we want a == conversion here, to be able to catch // undefined == false and friends /* jshint -W116 */ return definition[key] == val; }); } return some(event.eventDefinitions, function(definition) { return definition.$type === eventDefinitionType && matches(event, filter); }); } function isThrowEvent(event) { return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent'); } /////// cropping path customizations ///////////////////////// function componentsToPath(elements) { return elements.join(',').replace(/,?([A-z]),?/g, '$1'); } function getCirclePath(shape) { var cx = shape.x + shape.width / 2, cy = shape.y + shape.height / 2, radius = shape.width / 2; var circlePath = [ ['M', cx, cy], ['m', 0, -radius], ['a', radius, radius, 0, 1, 1, 0, 2 * radius], ['a', radius, radius, 0, 1, 1, 0, -2 * radius], ['z'] ]; return componentsToPath(circlePath); } function getRoundRectPath(shape) { var radius = TASK_BORDER_RADIUS, x = shape.x, y = shape.y, width = shape.width, height = shape.height; var roundRectPath = [ ['M', x + radius, y], ['l', width - radius * 2, 0], ['a', radius, radius, 0, 0, 1, radius, radius], ['l', 0, height - radius * 2], ['a', radius, radius, 0, 0, 1, -radius, radius], ['l', radius * 2 - width, 0], ['a', radius, radius, 0, 0, 1, -radius, -radius], ['l', 0, radius * 2 - height], ['a', radius, radius, 0, 0, 1, radius, -radius], ['z'] ]; return componentsToPath(roundRectPath); } function getDiamondPath(shape) { var width = shape.width, height = shape.height, x = shape.x, y = shape.y, halfWidth = width / 2, halfHeight = height / 2; var diamondPath = [ ['M', x + halfWidth, y], ['l', halfWidth, halfHeight], ['l', -halfWidth, halfHeight], ['l', -halfWidth, -halfHeight], ['z'] ]; return componentsToPath(diamondPath); } function getRectPath(shape) { var x = shape.x, y = shape.y, width = shape.width, height = shape.height; var rectPath = [ ['M', x, y], ['l', width, 0], ['l', 0, height], ['l', -width, 0], ['z'] ]; return componentsToPath(rectPath); } function getShapePath(element) { var obj = getSemantic(element); if (obj.$instanceOf('bpmn:Event')) { return getCirclePath(element); } if (obj.$instanceOf('bpmn:Activity')) { return getRoundRectPath(element); } if (obj.$instanceOf('bpmn:Gateway')) { return getDiamondPath(element); } return getRectPath(element); } // hook onto canvas init event to initialize // connection start/end markers on svg events.on('canvas.init', function(event) { initMarkers(event.svg); }); this.drawShape = drawShape; this.drawConnection = drawConnection; this.getShapePath = getShapePath; } inherits(BpmnRenderer, DefaultRenderer); BpmnRenderer.$inject = [ 'eventBus', 'styles', 'pathMap' ]; module.exports = BpmnRenderer; },{"184":184,"195":195,"201":201,"204":204,"206":206,"210":210,"316":316,"320":320,"325":325,"45":45,"84":84}],5:[function(_dereq_,module,exports){ 'use strict'; var Snap = _dereq_(188); /** * Map containing SVG paths needed by BpmnRenderer. */ function PathMap() { /** * Contains a map of path elements * *

Path definition

* A parameterized path is defined like this: *
   * 'GATEWAY_PARALLEL': {
   *   d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
          '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
   *   height: 17.5,
   *   width:  17.5,
   *   heightElements: [2.5, 7.5],
   *   widthElements: [2.5, 7.5]
   * }
   * 
*

It's important to specify a correct height and width for the path as the scaling * is based on the ratio between the specified height and width in this object and the * height and width that is set as scale target (Note x,y coordinates will be scaled with * individual ratios).

*

The 'heightElements' and 'widthElements' array must contain the values that will be scaled. * The scaling is based on the computed ratios. * Coordinates on the y axis should be in the heightElement's array, they will be scaled using * the computed ratio coefficient. * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets. *

    *
  • The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....
  • *
  • The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....
  • *
* The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index. *

*/ this.pathMap = { 'EVENT_MESSAGE': { d: 'm {mx},{my} l 0,{e.y1} l {e.x1},0 l 0,-{e.y1} z l {e.x0},{e.y0} l {e.x0},-{e.y0}', height: 36, width: 36, heightElements: [6, 14], widthElements: [10.5, 21] }, 'EVENT_SIGNAL': { d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z', height: 36, width: 36, heightElements: [18], widthElements: [10, 20] }, 'EVENT_ESCALATION': { d: 'm {mx},{my} c -{e.x1},{e.y0} -{e.x3},{e.y1} -{e.x5},{e.y4} {e.x1},-{e.y3} {e.x3},-{e.y5} {e.x5},-{e.y6} ' + '{e.x0},{e.y3} {e.x2},{e.y5} {e.x4},{e.y6} -{e.x0},-{e.y0} -{e.x2},-{e.y1} -{e.x4},-{e.y4} z', height: 36, width: 36, heightElements: [2.382, 4.764, 4.926, 6.589333, 7.146, 13.178667, 19.768], widthElements: [2.463, 2.808, 4.926, 5.616, 7.389, 8.424] }, 'EVENT_CONDITIONAL': { d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' + 'M {e.x2},{e.y3} l {e.x0},0 ' + 'M {e.x2},{e.y4} l {e.x0},0 ' + 'M {e.x2},{e.y5} l {e.x0},0 ' + 'M {e.x2},{e.y6} l {e.x0},0 ' + 'M {e.x2},{e.y7} l {e.x0},0 ' + 'M {e.x2},{e.y8} l {e.x0},0 ', height: 36, width: 36, heightElements: [8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5], widthElements: [10.5, 14.5, 12.5] }, 'EVENT_LINK': { d: 'm {mx},{my} 0,{e.y0} -{e.x1},0 0,{e.y1} {e.x1},0 0,{e.y0} {e.x0},-{e.y2} -{e.x0},-{e.y2} z', height: 36, width: 36, heightElements: [4.4375, 6.75, 7.8125], widthElements: [9.84375, 13.5] }, 'EVENT_ERROR': { d: 'm {mx},{my} {e.x0},-{e.y0} {e.x1},-{e.y1} {e.x2},{e.y2} {e.x3},-{e.y3} -{e.x4},{e.y4} -{e.x5},-{e.y5} z', height: 36, width: 36, heightElements: [0.023, 8.737, 8.151, 16.564, 10.591, 8.714], widthElements: [0.085, 6.672, 6.97, 4.273, 5.337, 6.636] }, 'EVENT_CANCEL_45': { d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' + '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z', height: 36, width: 36, heightElements: [4.75, 8.5], widthElements: [4.75, 8.5] }, 'EVENT_COMPENSATION': { d: 'm {mx},{my} {e.x0},-{e.y0} 0,{e.y1} z m {e.x0},0 {e.x0},-{e.y0} 0,{e.y1} z', height: 36, width: 36, heightElements: [5, 10], widthElements: [10] }, 'EVENT_TIMER_WH': { d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ', height: 36, width: 36, heightElements: [10, 2], widthElements: [3, 7] }, 'EVENT_TIMER_LINE': { d: 'M {mx},{my} ' + 'm {e.x0},{e.y0} l -{e.x1},{e.y1} ', height: 36, width: 36, heightElements: [10, 3], widthElements: [0, 0] }, 'EVENT_MULTIPLE': { d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z', height: 36, width: 36, heightElements: [6.28099, 12.56199], widthElements: [3.1405, 9.42149, 12.56198] }, 'EVENT_PARALLEL_MULTIPLE': { d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' + '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z', height: 36, width: 36, heightElements: [2.56228, 7.68683], widthElements: [2.56228, 7.68683] }, 'GATEWAY_EXCLUSIVE': { d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' + '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' + '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z', height: 17.5, width: 17.5, heightElements: [8.5, 6.5312, -6.5312, -8.5], widthElements: [6.5, -6.5, 3, -3, 5, -5] }, 'GATEWAY_PARALLEL': { d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' + '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z', height: 30, width: 30, heightElements: [5, 12.5], widthElements: [5, 12.5] }, 'GATEWAY_EVENT_BASED': { d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z', height: 11, width: 11, heightElements: [-6, 6, 12, -12], widthElements: [9, -3, -12] }, 'GATEWAY_COMPLEX': { d:'m {mx},{my} 0,{e.y0} -{e.x0},-{e.y1} -{e.x1},{e.y2} {e.x0},{e.y1} -{e.x2},0 0,{e.y3} ' + '{e.x2},0 -{e.x0},{e.y1} l {e.x1},{e.y2} {e.x0},-{e.y1} 0,{e.y0} {e.x3},0 0,-{e.y0} {e.x0},{e.y1} ' + '{e.x1},-{e.y2} -{e.x0},-{e.y1} {e.x2},0 0,-{e.y3} -{e.x2},0 {e.x0},-{e.y1} -{e.x1},-{e.y2} ' + '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z', height: 17.125, width: 17.125, heightElements: [4.875, 3.4375, 2.125, 3], widthElements: [3.4375, 2.125, 4.875, 3] }, 'DATA_OBJECT_PATH': { d:'m 0,0 {e.x1},0 {e.x0},{e.y0} 0,{e.y1} -{e.x2},0 0,-{e.y2} {e.x1},0 0,{e.y0} {e.x0},0', height: 61, width: 51, heightElements: [10, 50, 60], widthElements: [10, 40, 50, 60] }, 'DATA_OBJECT_COLLECTION_PATH': { d:'m {mx}, {my} ' + 'm 0 15 l 0 -15 ' + 'm 4 15 l 0 -15 ' + 'm 4 15 l 0 -15 ', height: 61, width: 51, heightElements: [12], widthElements: [1, 6, 12, 15] }, 'DATA_ARROW': { d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z', height: 61, width: 51, heightElements: [], widthElements: [] }, 'DATA_STORE': { d:'m {mx},{my} ' + 'l 0,{e.y2} ' + 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' + 'l 0,-{e.y2} ' + 'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' + 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0 ' + 'm -{e.x2},{e.y0}' + 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0' + 'm -{e.x2},{e.y0}' + 'c {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0', height: 61, width: 61, heightElements: [7, 10, 45], widthElements: [2, 58, 60] }, 'TEXT_ANNOTATION': { d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0', height: 30, width: 10, heightElements: [30], widthElements: [10] }, 'MARKER_SUB_PROCESS': { d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0', height: 10, width: 10, heightElements: [], widthElements: [] }, 'MARKER_PARALLEL': { d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10', height: 10, width: 10, heightElements: [], widthElements: [] }, 'MARKER_SEQUENTIAL': { d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0', height: 10, width: 10, heightElements: [], widthElements: [] }, 'MARKER_COMPENSATION': { d: 'm {mx},{my} 8,-5 0,10 z m 9,0 8,-5 0,10 z', height: 10, width: 21, heightElements: [], widthElements: [] }, 'MARKER_LOOP': { d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' + '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' + '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' + 'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902', height: 13.9, width: 13.7, heightElements: [], widthElements: [] }, 'MARKER_ADHOC': { d: 'm {mx},{my} m 0.84461,2.64411 c 1.05533,-1.23780996 2.64337,-2.07882 4.29653,-1.97997996 2.05163,0.0805 ' + '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' + '1.2775,-0.64078 1.7542,-1.17511 0,0.56023 0,1.12046 0,1.6807 -0.98706,0.96237996 -2.29792,1.62393996 ' + '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' + '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z', height: 4, width: 15, heightElements: [], widthElements: [] }, 'TASK_TYPE_SEND': { d: 'm {mx},{my} l 0,{e.y1} l {e.x1},0 l 0,-{e.y1} z l {e.x0},{e.y0} l {e.x0},-{e.y0}', height: 14, width: 21, heightElements: [6, 14], widthElements: [10.5, 21] }, 'TASK_TYPE_SCRIPT': { d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' + 'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' + 'm -7,-12 l 5,0 ' + 'm -4.5,3 l 4.5,0 ' + 'm -3,3 l 5,0' + 'm -4,3 l 5,0', height: 15, width: 12.6, heightElements: [6, 14], widthElements: [10.5, 21] }, 'TASK_TYPE_USER_1': { d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' + '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' + '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' + 'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' + 'm -8,6 l 0,5.5 m 11,0 l 0,-5' }, 'TASK_TYPE_USER_2': { d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' + '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 ' }, 'TASK_TYPE_USER_3': { d: 'm {mx},{my} m -6.9,-3.80 c 0,0 2.25099998,-2.358 4.27399998,-1.177 2.024,1.181 4.221,1.537 ' + '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' + '-4.20799998,3.36699999 -4.20699998,4.34799999 z' }, 'TASK_TYPE_MANUAL': { d: 'm {mx},{my} c 0.234,-0.01 5.604,0.008 8.029,0.004 0.808,0 1.271,-0.172 1.417,-0.752 0.227,-0.898 ' + '-0.334,-1.314 -1.338,-1.316 -2.467,-0.01 -7.886,-0.004 -8.108,-0.004 -0.014,-0.079 0.016,-0.533 0,-0.61 ' + '0.195,-0.042 8.507,0.006 9.616,0.002 0.877,-0.007 1.35,-0.438 1.353,-1.208 0.003,-0.768 -0.479,-1.09 ' + '-1.35,-1.091 -2.968,-0.002 -9.619,-0.013 -9.619,-0.013 v -0.591 c 0,0 5.052,-0.016 7.225,-0.016 ' + '0.888,-0.002 1.354,-0.416 1.351,-1.193 -0.006,-0.761 -0.492,-1.196 -1.361,-1.196 -3.473,-0.005 ' + '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' + '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' + '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' + '-1.516,1.253 -1.882,2.19 -0.37000002,0.95 -0.17,2.01 -0.166,2.979 0.004,0.718 -0.27300002,1.345 ' + '-0.055,2.063 0.629,2.087 2.425,3.312 4.859,3.318 4.6179995,0.014 9.2379995,-0.139 13.8569995,-0.158 ' + '0.755,-0.004 1.171,-0.301 1.182,-1.033 0.012,-0.754 -0.423,-0.969 -1.183,-0.973 -1.778,-0.01 ' + '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z' }, 'TASK_TYPE_INSTANTIATING_SEND': { d: 'm {mx},{my} l 0,8.4 l 12.6,0 l 0,-8.4 z l 6.3,3.6 l 6.3,-3.6' }, 'TASK_TYPE_SERVICE': { d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' + '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' + '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' + 'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' + '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' + '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' + 'h -2.241173 l 0.0042,1.63124 c -0.353763,0.0736 -0.705369,0.17977 -1.049785,0.32371 -0.344415,0.14437 ' + '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' + 'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' + 'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' + '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' + 'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' + 'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' + '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' + '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z' }, 'TASK_TYPE_SERVICE_FILL': { d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' + '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' + '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z' }, 'TASK_TYPE_BUSINESS_RULE_HEADER': { d: 'm {mx},{my} 0,4 20,0 0,-4 z' }, 'TASK_TYPE_BUSINESS_RULE_MAIN': { d: 'm {mx},{my} 0,12 20,0 0,-12 z' + 'm 0,8 l 20,0 ' + 'm -13,-4 l 0,8' }, 'MESSAGE_FLOW_MARKER': { d: 'm {mx},{my} m -10.5 ,-7 l 0,14 l 21,0 l 0,-14 z l 10.5,6 l 10.5,-6' } }; this.getRawPath = function getRawPath(pathId) { return this.pathMap[pathId].d; }; /** * Scales the path to the given height and width. *

Use case

*

Use case is to scale the content of elements (event, gateways) based * on the element bounding box's size. *

*

Why not transform

*

Scaling a path with transform() will also scale the stroke and IE does not support * the option 'non-scaling-stroke' to prevent this. * Also there are use cases where only some parts of a path should be * scaled.

* * @param {String} pathId The ID of the path. * @param {Object} param

* Example param object scales the path to 60% size of the container (data.width, data.height). *

   *   {
   *     xScaleFactor: 0.6,
   *     yScaleFactor:0.6,
   *     containerWidth: data.width,
   *     containerHeight: data.height,
   *     position: {
   *       mx: 0.46,
   *       my: 0.2,
   *     }
   *   }
   *   
*
    *
  • targetpathwidth = xScaleFactor * containerWidth
  • *
  • targetpathheight = yScaleFactor * containerHeight
  • *
  • Position is used to set the starting coordinate of the path. M is computed: *
      *
    • position.x * containerWidth
    • *
    • position.y * containerHeight
    • *
    * Center of the container
     position: {
       *       mx: 0.5,
       *       my: 0.5,
       *     }
    * Upper left corner of the container *
     position: {
       *       mx: 0.0,
       *       my: 0.0,
       *     }
    *
  • *
*

* */ this.getScaledPath = function getScaledPath(pathId, param) { var rawPath = this.pathMap[pathId]; // positioning // compute the start point of the path var mx, my; if(!!param.abspos) { mx = param.abspos.x; my = param.abspos.y; } else { mx = param.containerWidth * param.position.mx; my = param.containerHeight * param.position.my; } var coordinates = {}; //map for the scaled coordinates if(param.position) { // path var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor; var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor; //Apply height ratio for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) { coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio; } //Apply width ratio for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) { coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio; } } //Apply value to raw path var path = Snap.format( rawPath.d, { mx: mx, my: my, e: coordinates } ); return path; }; } module.exports = PathMap; },{"188":188}],6:[function(_dereq_,module,exports){ module.exports = { renderer: [ 'type', _dereq_(4) ], pathMap: [ 'type', _dereq_(5) ] }; },{"4":4,"5":5}],7:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325), forEach = _dereq_(204); /** * A provider for BPMN 2.0 elements context pad */ function ContextPadProvider(contextPad, modeling, elementFactory, connect, create, bpmnReplace, canvas) { contextPad.registerProvider(this); this._contextPad = contextPad; this._modeling = modeling; this._elementFactory = elementFactory; this._connect = connect; this._create = create; this._bpmnReplace = bpmnReplace; this._canvas = canvas; } ContextPadProvider.$inject = [ 'contextPad', 'modeling', 'elementFactory', 'connect', 'create', 'bpmnReplace', 'canvas' ]; ContextPadProvider.prototype.getContextPadEntries = function(element) { var contextPad = this._contextPad, modeling = this._modeling, elementFactory = this._elementFactory, connect = this._connect, create = this._create, bpmnReplace = this._bpmnReplace, canvas = this._canvas; var actions = {}; if (element.type === 'label') { return actions; } var bpmnElement = element.businessObject; function startConnect(event, element, autoActivate) { connect.start(event, element, autoActivate); } function removeElement(e) { if (element.waypoints) { modeling.removeConnection(element); } else { modeling.removeShape(element); } } function getReplaceMenuPosition(element) { var Y_OFFSET = 5; var diagramContainer = canvas.getContainer(), pad = contextPad.getPad(element).html; var diagramRect = diagramContainer.getBoundingClientRect(), padRect = pad.getBoundingClientRect(); var top = padRect.top - diagramRect.top; var left = padRect.left - diagramRect.left; var pos = { x: left, y: top + padRect.height + Y_OFFSET }; return pos; } function appendAction(type, className, options) { function appendListener(event, element) { var shape = elementFactory.createShape(assign({ type: type }, options)); create.start(event, shape, element); } var shortType = type.replace(/^bpmn\:/, ''); return { group: 'model', className: className, title: 'Append ' + shortType, action: { dragstart: appendListener, click: appendListener } }; } if (bpmnElement.$instanceOf('bpmn:FlowNode')) { if (!bpmnElement.$instanceOf('bpmn:EndEvent') && !bpmnElement.$instanceOf('bpmn:EventBasedGateway') && !isEventType(bpmnElement, 'bpmn:IntermediateThrowEvent', 'bpmn:LinkEventDefinition')) { assign(actions, { 'append.end-event': appendAction('bpmn:EndEvent', 'icon-end-event-none'), 'append.gateway': appendAction('bpmn:ExclusiveGateway', 'icon-gateway-xor'), 'append.append-task': appendAction('bpmn:Task', 'icon-task'), 'append.intermediate-event': appendAction('bpmn:IntermediateThrowEvent', 'icon-intermediate-event-none') }); } if (bpmnElement.$instanceOf('bpmn:EventBasedGateway')) { assign(actions, { 'append.receive-task': appendAction('bpmn:ReceiveTask', 'icon-receive-task'), 'append.message-intermediate-event': appendAction('bpmn:IntermediateCatchEvent', 'icon-intermediate-event-catch-message', { _eventDefinitionType: 'bpmn:MessageEventDefinition'}), 'append.timer-intermediate-event': appendAction('bpmn:IntermediateCatchEvent', 'icon-intermediate-event-catch-timer', { _eventDefinitionType: 'bpmn:TimerEventDefinition'}), 'append.condtion-intermediate-event': appendAction('bpmn:IntermediateCatchEvent', 'icon-intermediate-event-catch-condition', { _eventDefinitionType: 'bpmn:ConditionalEventDefinition'}), 'append.signal-intermediate-event': appendAction('bpmn:IntermediateCatchEvent', 'icon-intermediate-event-catch-signal', { _eventDefinitionType: 'bpmn:SignalEventDefinition'}) }); } // Replace menu entry if (!bpmnElement.$instanceOf('bpmn:SubProcess')) { assign(actions, { 'replace': { group: 'edit', className: 'icon-screw-wrench', title: 'Change type', action: { click: function(event, element) { bpmnReplace.openChooser(getReplaceMenuPosition(element), element); } } } }); } } if (bpmnElement.$instanceOf('bpmn:FlowNode') || bpmnElement.$instanceOf('bpmn:InteractionNode')) { assign(actions, { 'append.text-annotation': appendAction('bpmn:TextAnnotation', 'icon-text-annotation'), 'connect': { group: 'connect', className: 'icon-connection-multi', title: 'Connect using Sequence/MessageFlow', action: { click: startConnect, dragstart: startConnect } } }); } // Delete Element Entry assign(actions, { 'delete': { group: 'edit', className: 'icon-trash', title: 'Remove', action: { click: removeElement, dragstart: removeElement } } }); return actions; }; function isEventType(eventBo, type, definition) { var isType = eventBo.$instanceOf(type); var isDefinition = false; var definitions = eventBo.eventDefinitions || []; forEach(definitions, function(def) { if (def.$type === definition) { isDefinition = true; } }); return isType && isDefinition; } module.exports = ContextPadProvider; },{"204":204,"325":325}],8:[function(_dereq_,module,exports){ module.exports = { __depends__: [ _dereq_(70), _dereq_(97), _dereq_(151), _dereq_(95), _dereq_(99), _dereq_(37) ], __init__: [ 'contextPadProvider' ], contextPadProvider: [ 'type', _dereq_(7) ] }; },{"151":151,"37":37,"7":7,"70":70,"95":95,"97":97,"99":99}],9:[function(_dereq_,module,exports){ 'use strict'; function BpmnKeyBindings(keyboard, spaceTool, lassoTool, directEditing, selection) { keyboard.addListener(function(key, modifiers) { if (keyboard.hasModifier(modifiers)) { return; } // S -> activate space tool if (key === 83) { spaceTool.activateSelection(); return true; } // L -> activate lasso tool if (key === 108) { lassoTool.activateSelection(); return true; } var currentSelection = selection.get(); // E -> activate direct editing if (key === 69) { if (currentSelection.length) { directEditing.activate(currentSelection[0]); } return true; } }); } BpmnKeyBindings.$inject = [ 'keyboard', 'spaceTool', 'lassoTool', 'directEditing', 'selection' ]; module.exports = BpmnKeyBindings; },{}],10:[function(_dereq_,module,exports){ module.exports = { __depends__: [ _dereq_(105) ], __init__: [ 'bpmnKeyBindings' ], bpmnKeyBindings: [ 'type', _dereq_(9) ] }; },{"105":105,"9":9}],11:[function(_dereq_,module,exports){ 'use strict'; var UpdateLabelHandler = _dereq_(13); var LabelUtil = _dereq_(12); var is = _dereq_(47).is, isExpanded = _dereq_(45).isExpanded; var MIN_BOUNDS = { width: 150, height: 50 }; function LabelEditingProvider(eventBus, canvas, directEditing, commandStack, injector) { directEditing.registerProvider(this); commandStack.registerHandler('element.updateLabel', UpdateLabelHandler); // listen to dblclick on non-root elements eventBus.on('element.dblclick', function(event) { directEditing.activate(event.element); }); // complete on followup canvas operation eventBus.on([ 'element.mousedown', 'drag.activate', 'canvas.viewbox.changed' ], function(event) { directEditing.complete(); }); // cancel on command stack changes eventBus.on([ 'commandStack.changed' ], function() { directEditing.cancel(); }); // activate direct editing for activities and text annotations if ('ontouchstart' in document.documentElement) { // we deactivate automatic label editing on mobile devices // as it breaks the user interaction workflow // TODO(nre): we should temporarily focus the edited element here // and release the focused viewport after the direct edit operation is finished } else { eventBus.on('create.end', 500, function(e) { var element = e.shape, canExecute = e.context.canExecute; if (!canExecute) { return; } if (is(element, 'bpmn:Task') || is(element, 'bpmn:TextAnnotation') || (is(element, 'bpmn:SubProcess') && !isExpanded(element))) { directEditing.activate(element); } }); } this._canvas = canvas; this._commandStack = commandStack; } LabelEditingProvider.$inject = [ 'eventBus', 'canvas', 'directEditing', 'commandStack', 'injector' ]; module.exports = LabelEditingProvider; LabelEditingProvider.prototype.activate = function(element) { var text = LabelUtil.getLabel(element); if (text === undefined) { return; } var bbox = this.getEditingBBox(element); // adjust for expanded pools AND lanes if ((is(element, 'bpmn:Participant') && isExpanded(element)) || is(element, 'bpmn:Lane')) { bbox.width = MIN_BOUNDS.width; bbox.height = MIN_BOUNDS.height; bbox.x = bbox.x + 10 - bbox.width / 2; bbox.y = bbox.mid.y - bbox.height / 2; } // adjust for expanded sub processes if (is(element, 'bpmn:SubProcess') && isExpanded(element)) { bbox.height = MIN_BOUNDS.height; bbox.x = bbox.mid.x - bbox.width / 2; bbox.y = bbox.y + 10 - bbox.height / 2; } return { bounds: bbox, text: text }; }; LabelEditingProvider.prototype.getEditingBBox = function(element, maxBounds) { var target = element.label || element; var bbox = this._canvas.getAbsoluteBBox(target); var mid = { x: bbox.x + bbox.width / 2, y: bbox.y + bbox.height / 2 }; // external label if (target.labelTarget) { bbox.width = Math.max(bbox.width, MIN_BOUNDS.width); bbox.height = Math.max(bbox.height, MIN_BOUNDS.height); bbox.x = mid.x - bbox.width / 2; } bbox.mid = mid; return bbox; }; LabelEditingProvider.prototype.update = function(element, newLabel) { this._commandStack.execute('element.updateLabel', { element: element, newLabel: newLabel }); }; },{"12":12,"13":13,"45":45,"47":47}],12:[function(_dereq_,module,exports){ 'use strict'; function getLabelAttr(semantic) { if (semantic.$instanceOf('bpmn:FlowElement') || semantic.$instanceOf('bpmn:Participant') || semantic.$instanceOf('bpmn:Lane') || semantic.$instanceOf('bpmn:SequenceFlow') || semantic.$instanceOf('bpmn:MessageFlow')) { return 'name'; } if (semantic.$instanceOf('bpmn:TextAnnotation')) { return 'text'; } } module.exports.getLabel = function(element) { var semantic = element.businessObject, attr = getLabelAttr(semantic); if (attr) { return semantic[attr] || ''; } }; module.exports.setLabel = function(element, text) { var semantic = element.businessObject, attr = getLabelAttr(semantic); if (attr) { semantic[attr] = text; } var label = element.label || element; // show label label.hidden = false; return label; }; },{}],13:[function(_dereq_,module,exports){ 'use strict'; var LabelUtil = _dereq_(12); /** * A handler that updates the text of a BPMN element. * * @param {EventBus} eventBus */ function UpdateTextHandler(eventBus) { function setText(element, text) { var label = LabelUtil.setLabel(element, text); eventBus.fire('element.changed', { element: label }); } function execute(ctx) { ctx.oldLabel = LabelUtil.getLabel(ctx.element); return setText(ctx.element, ctx.newLabel); } function revert(ctx) { return setText(ctx.element, ctx.oldLabel); } function canExecute(ctx) { return true; } // API this.execute = execute; this.revert = revert; this.canExecute = canExecute; } UpdateTextHandler.$inject = [ 'eventBus' ]; module.exports = UpdateTextHandler; },{"12":12}],14:[function(_dereq_,module,exports){ module.exports = { __depends__: [ _dereq_(77), _dereq_(93), _dereq_(70) ], __init__: [ 'labelEditingProvider' ], labelEditingProvider: [ 'type', _dereq_(11) ] }; },{"11":11,"70":70,"77":77,"93":93}],15:[function(_dereq_,module,exports){ 'use strict'; var map = _dereq_(207), assign = _dereq_(325), pick = _dereq_(330); function BpmnFactory(moddle) { this._model = moddle; } BpmnFactory.$inject = [ 'moddle' ]; BpmnFactory.prototype._needsId = function(element) { return element.$instanceOf('bpmn:RootElement') || element.$instanceOf('bpmn:FlowElement') || element.$instanceOf('bpmn:MessageFlow') || element.$instanceOf('bpmn:Artifact') || element.$instanceOf('bpmn:Participant') || element.$instanceOf('bpmn:Process') || element.$instanceOf('bpmn:Collaboration') || element.$instanceOf('bpmndi:BPMNShape') || element.$instanceOf('bpmndi:BPMNEdge') || element.$instanceOf('bpmndi:BPMNDiagram') || element.$instanceOf('bpmndi:BPMNPlane'); }; BpmnFactory.prototype._ensureId = function(element) { // generate semantic ids for elements // bpmn:SequenceFlow -> SequenceFlow_ID var prefix = (element.$type || '').replace(/^[^:]*:/g, '') + '_'; if (!element.id && this._needsId(element)) { element.id = this._model.ids.nextPrefixed(prefix, element); } }; BpmnFactory.prototype.create = function(type, attrs) { var element = this._model.create(type, attrs || {}); this._ensureId(element); return element; }; BpmnFactory.prototype.createDiLabel = function() { return this.create('bpmndi:BPMNLabel', { bounds: this.createDiBounds() }); }; BpmnFactory.prototype.createDiShape = function(semantic, bounds, attrs) { return this.create('bpmndi:BPMNShape', assign({ bpmnElement: semantic, bounds: this.createDiBounds(bounds) }, attrs)); }; BpmnFactory.prototype.createDiBounds = function(bounds) { return this.create('dc:Bounds', bounds); }; BpmnFactory.prototype.createDiWaypoints = function(waypoints) { return map(waypoints, function(pos) { return this.createDiWaypoint(pos); }, this); }; BpmnFactory.prototype.createDiWaypoint = function(point) { return this.create('dc:Point', pick(point, [ 'x', 'y' ])); }; BpmnFactory.prototype.createDiEdge = function(semantic, waypoints, attrs) { return this.create('bpmndi:BPMNEdge', assign({ bpmnElement: semantic }, attrs)); }; BpmnFactory.prototype.createDiPlane = function(semantic) { return this.create('bpmndi:BPMNPlane', { bpmnElement: semantic }); }; module.exports = BpmnFactory; },{"207":207,"325":325,"330":330}],16:[function(_dereq_,module,exports){ 'use strict'; var inherits = _dereq_(195); var assign = _dereq_(325); var BaseLayouter = _dereq_(164), LayoutUtil = _dereq_(166), ManhattanLayout = _dereq_(167); var is = _dereq_(47).is; function BpmnLayouter() {} inherits(BpmnLayouter, BaseLayouter); module.exports = BpmnLayouter; function getAttachment(waypoints, idx, shape) { var point = waypoints && waypoints[idx]; return point ? (point.original || point) : LayoutUtil.getMidPoint(shape); } BpmnLayouter.prototype.layoutConnection = function(connection, hints) { var source = connection.source, target = connection.target, waypoints = connection.waypoints, start, end; var layoutManhattan, updatedWaypoints; start = getAttachment(waypoints, 0, source); end = getAttachment(waypoints, waypoints && waypoints.length - 1, target); // manhattan layout sequence / message flows if (is(connection, 'bpmn:MessageFlow')) { layoutManhattan = { preferStraight: true, preferVertical: true }; } if (is(connection, 'bpmn:SequenceFlow')) { layoutManhattan = {}; } if (layoutManhattan) { layoutManhattan = assign(layoutManhattan, hints); updatedWaypoints = ManhattanLayout.repairConnection( source, target, start, end, waypoints, layoutManhattan); } return updatedWaypoints || [ start, end ]; }; },{"164":164,"166":166,"167":167,"195":195,"325":325,"47":47}],17:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325), forEach = _dereq_(204), inherits = _dereq_(195); var Collections = _dereq_(175), Model = _dereq_(168); var CommandInterceptor = _dereq_(75); /** * A handler responsible for updating the underlying BPMN 2.0 XML + DI * once changes on the diagram happen */ function BpmnUpdater(eventBus, bpmnFactory, connectionDocking) { CommandInterceptor.call(this, eventBus); this._bpmnFactory = bpmnFactory; var self = this; ////// connection cropping ///////////////////////// // crop connection ends during create/update function cropConnection(e) { var context = e.context, connection; if (!context.cropped) { connection = context.connection; connection.waypoints = connectionDocking.getCroppedWaypoints(connection); context.cropped = true; } } this.executed([ 'connection.layout', 'connection.create', 'connection.reconnectEnd', 'connection.reconnectStart' ], cropConnection); this.reverted([ 'connection.layout' ], function(e) { delete e.context.cropped; }); ////// BPMN + DI update ///////////////////////// // update parent function updateParent(e) { self.updateParent(e.context.shape || e.context.connection); } this.executed([ 'shape.move', 'shape.create', 'shape.delete', 'connection.create', 'connection.move', 'connection.delete' ], updateParent); this.reverted([ 'shape.move', 'shape.create', 'shape.delete', 'connection.create', 'connection.move', 'connection.delete' ], updateParent); /* * ## Updating Parent * * When morphing a Process into a Collaboration or vice-versa, * make sure that both the *semantic* and *di* parent of each element * is updated. * */ function updateRoot(event) { var context = event.context, oldRoot = context.oldRoot, children = oldRoot.children; forEach(children, function(child) { self.updateParent(child); }); } this.executed([ 'canvas.updateRoot' ], updateRoot); this.reverted([ 'canvas.updateRoot' ], updateRoot); // update bounds function updateBounds(e) { self.updateBounds(e.context.shape); } this.executed([ 'shape.move', 'shape.create', 'shape.resize' ], updateBounds); this.reverted([ 'shape.move', 'shape.create', 'shape.resize' ], updateBounds); // attach / detach connection function updateConnection(e) { self.updateConnection(e.context.connection); } this.executed([ 'connection.create', 'connection.move', 'connection.delete', 'connection.reconnectEnd', 'connection.reconnectStart' ], updateConnection); this.reverted([ 'connection.create', 'connection.move', 'connection.delete', 'connection.reconnectEnd', 'connection.reconnectStart' ], updateConnection); // update waypoints function updateConnectionWaypoints(e) { self.updateConnectionWaypoints(e.context.connection); } this.executed([ 'connection.layout', 'connection.move', 'connection.updateWaypoints', 'connection.reconnectEnd', 'connection.reconnectStart' ], updateConnectionWaypoints); this.reverted([ 'connection.layout', 'connection.move', 'connection.updateWaypoints', 'connection.reconnectEnd', 'connection.reconnectStart' ], updateConnectionWaypoints); } inherits(BpmnUpdater, CommandInterceptor); module.exports = BpmnUpdater; BpmnUpdater.$inject = [ 'eventBus', 'bpmnFactory', 'connectionDocking']; /////// implementation ////////////////////////////////// BpmnUpdater.prototype.updateParent = function(element) { // do not update BPMN 2.0 label parent if (element instanceof Model.Label) { return; } var parentShape = element.parent; var businessObject = element.businessObject, parentBusinessObject = parentShape && parentShape.businessObject, parentDi = parentBusinessObject && parentBusinessObject.di; this.updateSemanticParent(businessObject, parentBusinessObject); this.updateDiParent(businessObject.di, parentDi); }; BpmnUpdater.prototype.updateBounds = function(shape) { var di = shape.businessObject.di; var bounds = (shape instanceof Model.Label) ? this._getLabel(di).bounds : di.bounds; assign(bounds, { x: shape.x, y: shape.y, width: shape.width, height: shape.height }); }; BpmnUpdater.prototype.updateDiParent = function(di, parentDi) { if (parentDi && !parentDi.$instanceOf('bpmndi:BPMNPlane')) { parentDi = parentDi.$parent; } if (di.$parent === parentDi) { return; } var planeElements = (parentDi || di.$parent).get('planeElement'); if (parentDi) { planeElements.push(di); di.$parent = parentDi; } else { Collections.remove(planeElements, di); di.$parent = null; } }; function getDefinitions(element) { while (element && !element.$instanceOf('bpmn:Definitions')) { element = element.$parent; } return element; } BpmnUpdater.prototype.updateSemanticParent = function(businessObject, newParent) { var containment; if (businessObject.$parent === newParent) { return; } if (businessObject.$instanceOf('bpmn:FlowElement')) { if (newParent && newParent.$instanceOf('bpmn:Participant')) { newParent = newParent.processRef; } containment = 'flowElements'; } else if (businessObject.$instanceOf('bpmn:Artifact')) { while (newParent && !newParent.$instanceOf('bpmn:Process') && !newParent.$instanceOf('bpmn:SubProcess') && !newParent.$instanceOf('bpmn:Collaboration')) { if (newParent.$instanceOf('bpmn:Participant')) { newParent = newParent.processRef; break; } else { newParent = newParent.$parent; } } containment = 'artifacts'; } else if (businessObject.$instanceOf('bpmn:MessageFlow')) { containment = 'messageFlows'; } else if (businessObject.$instanceOf('bpmn:Participant')) { containment = 'participants'; // make sure the participants process is properly attached / detached // from the XML document var process = businessObject.processRef, definitions; if (process) { definitions = getDefinitions(businessObject.$parent || newParent); if (businessObject.$parent) { Collections.remove(definitions.get('rootElements'), process); process.$parent = null; } if (newParent) { Collections.add(definitions.get('rootElements'), process); process.$parent = definitions; } } } if (!containment) { throw new Error('no parent for ', businessObject, newParent); } var children; if (businessObject.$parent) { // remove from old parent children = businessObject.$parent.get(containment); Collections.remove(children, businessObject); } if (!newParent) { businessObject.$parent = null; } else { // add to new parent children = newParent.get(containment); children.push(businessObject); businessObject.$parent = newParent; } }; BpmnUpdater.prototype.updateConnectionWaypoints = function(connection) { connection.businessObject.di.set('waypoint', this._bpmnFactory.createDiWaypoints(connection.waypoints)); }; BpmnUpdater.prototype.updateConnection = function(connection) { var businessObject = connection.businessObject, newSource = connection.source && connection.source.businessObject, newTarget = connection.target && connection.target.businessObject; var inverseSet = businessObject.$instanceOf('bpmn:SequenceFlow'); if (businessObject.sourceRef !== newSource) { if (inverseSet) { Collections.remove(businessObject.sourceRef && businessObject.sourceRef.get('outgoing'), businessObject); if (newSource) { newSource.get('outgoing').push(businessObject); } } businessObject.sourceRef = newSource; } if (businessObject.targetRef !== newTarget) { if (inverseSet) { Collections.remove(businessObject.targetRef && businessObject.targetRef.get('incoming'), businessObject); if (newTarget) { newTarget.get('incoming').push(businessObject); } } businessObject.targetRef = newTarget; } businessObject.di.set('waypoint', this._bpmnFactory.createDiWaypoints(connection.waypoints)); }; /////// helpers ///////////////////////////////////////// BpmnUpdater.prototype._getLabel = function(di) { if (!di.label) { di.label = this._bpmnFactory.createDiLabel(); } return di.label; }; },{"168":168,"175":175,"195":195,"204":204,"325":325,"75":75}],18:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325), inherits = _dereq_(195); var BaseElementFactory = _dereq_(79), LabelUtil = _dereq_(46); /** * A bpmn-aware factory for diagram-js shapes */ function ElementFactory(bpmnFactory, moddle) { BaseElementFactory.call(this); this._bpmnFactory = bpmnFactory; this._moddle = moddle; } inherits(ElementFactory, BaseElementFactory); ElementFactory.$inject = [ 'bpmnFactory', 'moddle' ]; module.exports = ElementFactory; ElementFactory.prototype.baseCreate = BaseElementFactory.prototype.create; ElementFactory.prototype.create = function(elementType, attrs) { // no special magic for labels, // we assume their businessObjects have already been created // and wired via attrs if (elementType === 'label') { return this.baseCreate(elementType, assign({ type: 'label' }, LabelUtil.DEFAULT_LABEL_SIZE, attrs)); } attrs = attrs || {}; var businessObject = attrs.businessObject, size; if (!businessObject) { if (!attrs.type) { throw new Error('no shape type specified'); } businessObject = this._bpmnFactory.create(attrs.type); } if (!businessObject.di) { if (elementType === 'root') { businessObject.di = this._bpmnFactory.createDiPlane(businessObject, [], { id: businessObject.id + '_di' }); } else if (elementType === 'connection') { businessObject.di = this._bpmnFactory.createDiEdge(businessObject, [], { id: businessObject.id + '_di' }); } else { businessObject.di = this._bpmnFactory.createDiShape(businessObject, {}, { id: businessObject.id + '_di' }); } } if (!!attrs.isExpanded) { businessObject.di.isExpanded = attrs.isExpanded; } if (businessObject.$instanceOf('bpmn:ExclusiveGateway')) { businessObject.di.isMarkerVisible = true; } if (attrs._eventDefinitionType) { var eventDefinitions = businessObject.get('eventDefinitions') || [], newEventDefinition = this._moddle.create(attrs._eventDefinitionType); eventDefinitions.push(newEventDefinition); businessObject.eventDefinitions = eventDefinitions; } size = this._getDefaultSize(businessObject); attrs = assign({ businessObject: businessObject, id: businessObject.id }, size, attrs); return this.baseCreate(elementType, attrs); }; ElementFactory.prototype._getDefaultSize = function(semantic) { if (semantic.$instanceOf('bpmn:SubProcess')) { var isExpanded = semantic.di.isExpanded === true; if (isExpanded) { return { width: 350, height: 200 }; } else { return { width: 100, height: 80 }; } } if (semantic.$instanceOf('bpmn:Task')) { return { width: 100, height: 80 }; } if (semantic.$instanceOf('bpmn:Gateway')) { return { width: 50, height: 50 }; } if (semantic.$instanceOf('bpmn:Event')) { return { width: 36, height: 36 }; } if (semantic.$instanceOf('bpmn:Participant')) { return { width: 600, height: 250 }; } return { width: 100, height: 80 }; }; ElementFactory.prototype.createParticipantShape = function(collapsed) { var participantShape = this.createShape({ type: 'bpmn:Participant' }); if (!collapsed) { participantShape.businessObject.processRef = this._bpmnFactory.create('bpmn:Process'); } return participantShape; }; },{"195":195,"325":325,"46":46,"79":79}],19:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325), forEach = _dereq_(204); var LabelUtil = _dereq_(46); var hasExternalLabel = LabelUtil.hasExternalLabel, getExternalLabelMid = LabelUtil.getExternalLabelMid; function LabelSupport(eventBus, modeling, bpmnFactory) { // create external labels on shape creation eventBus.on([ 'commandStack.shape.create.postExecute', 'commandStack.connection.create.postExecute' ], function(e) { var context = e.context; var element = context.shape || context.connection, businessObject = element.businessObject; var position; if (hasExternalLabel(businessObject)) { position = getExternalLabelMid(element); modeling.createLabel(element, position, { id: businessObject.id + '_label', businessObject: businessObject }); } }); // indicate label is dragged during move // we need to add labels to the list of selected // shapes before the visuals get drawn. // // Hence this awesome magic number. // eventBus.on('shape.move.start', function(e) { var context = e.context, shapes = context.shapes; var labels = []; forEach(shapes, function(element) { var label = element.label; if (label && !label.hidden && context.shapes.indexOf(label) === -1) { labels.push(label); } }); forEach(labels, function(label) { shapes.push(label); }); }); // move labels with shapes eventBus.on([ 'commandStack.shapes.move.postExecute' ], function(e) { var context = e.context, closure = context.closure, enclosedElements = closure.enclosedElements; // ensure we move all labels with their respective elements // if they have not been moved already forEach(enclosedElements, function(e) { if (e.label && !enclosedElements[e.label.id]) { modeling.moveShape(e.label, context.delta, e.parent); } }); }); // update di information on label movement and creation eventBus.on([ 'commandStack.label.create.executed', 'commandStack.shape.moved.executed' ], function(e) { var element = e.context.shape, businessObject = element.businessObject, di = businessObject.di; // we want to trigger on real labels only if (!element.labelTarget) { return; } if (!di.label) { di.label = bpmnFactory.create('bpmndi:BPMNLabel', { bounds: bpmnFactory.create('dc:Bounds') }); } assign(di.label.bounds, { x: element.x, y: element.y, width: element.width, height: element.height }); }); } LabelSupport.$inject = [ 'eventBus', 'modeling', 'bpmnFactory' ]; module.exports = LabelSupport; },{"204":204,"325":325,"46":46}],20:[function(_dereq_,module,exports){ 'use strict'; var inherits = _dereq_(195); var BaseModeling = _dereq_(108); var UpdatePropertiesHandler = _dereq_(29), UpdateCanvasRootHandler = _dereq_(28); /** * BPMN 2.0 modeling features activator * * @param {EventBus} eventBus * @param {ElementFactory} elementFactory * @param {CommandStack} commandStack * @param {BpmnRules} bpmnRules */ function Modeling(eventBus, elementFactory, commandStack, bpmnRules) { BaseModeling.call(this, eventBus, elementFactory, commandStack); this._bpmnRules = bpmnRules; } inherits(Modeling, BaseModeling); Modeling.$inject = [ 'eventBus', 'elementFactory', 'commandStack', 'bpmnRules' ]; module.exports = Modeling; Modeling.prototype.getHandlers = function() { var handlers = BaseModeling.prototype.getHandlers.call(this); handlers['element.updateProperties'] = UpdatePropertiesHandler; handlers['canvas.updateRoot'] = UpdateCanvasRootHandler; return handlers; }; Modeling.prototype.updateLabel = function(element, newLabel) { this._commandStack.execute('element.updateLabel', { element: element, newLabel: newLabel }); }; var getSharedParent = _dereq_(21).getSharedParent; Modeling.prototype.connect = function(source, target, attrs) { var bpmnRules = this._bpmnRules; if (!attrs) { if (bpmnRules.canConnectMessageFlow(source, target)) { attrs = { type: 'bpmn:MessageFlow' }; } else if (bpmnRules.canConnectSequenceFlow(source, target)) { attrs = { type: 'bpmn:SequenceFlow' }; } else { attrs = { type: 'bpmn:Association' }; } } return this.createConnection(source, target, attrs, getSharedParent(source, target)); }; Modeling.prototype.updateProperties = function(element, properties) { this._commandStack.execute('element.updateProperties', { element: element, properties: properties }); }; /** * Transform the current diagram into a collaboration. * * @return {djs.model.Root} the new root element */ Modeling.prototype.makeCollaboration = function() { var collaborationElement = this._create('root', { type: 'bpmn:Collaboration' }); var context = { newRoot: collaborationElement }; this._commandStack.execute('canvas.updateRoot', context); return collaborationElement; }; /** * Transform the current diagram into a process. * * @return {djs.model.Root} the new root element */ Modeling.prototype.makeProcess = function() { var processElement = this._create('root', { type: 'bpmn:Process' }); var context = { newRoot: processElement }; this._commandStack.execute('canvas.updateRoot', context); }; },{"108":108,"195":195,"21":21,"28":28,"29":29}],21:[function(_dereq_,module,exports){ 'use strict'; var find = _dereq_(203); function getParents(element) { var parents = []; while (element) { element = element.parent; if (element) { parents.push(element); } } return parents; } module.exports.getParents = getParents; function getSharedParent(a, b) { var parentsA = getParents(a), parentsB = getParents(b); return find(parentsA, function(parent) { return parentsB.indexOf(parent) !== -1; }); } module.exports.getSharedParent = getSharedParent; },{"203":203}],22:[function(_dereq_,module,exports){ 'use strict'; var inherits = _dereq_(195); var is = _dereq_(47).is; var CommandInterceptor = _dereq_(75); function AppendBehavior(eventBus, elementFactory, bpmnRules) { CommandInterceptor.call(this, eventBus); // assign correct shape position unless already set this.preExecute('shape.append', function(context) { var source = context.source, shape = context.shape; if (!context.position) { if (is(shape, 'bpmn:TextAnnotation')) { context.position = { x: source.x + source.width / 2 + 75, y: source.y - (50) - shape.height / 2 }; } else { context.position = { x: source.x + source.width + 80 + shape.width / 2, y: source.y + source.height / 2 }; } } }, true); } AppendBehavior.$inject = [ 'eventBus', 'elementFactory', 'bpmnRules' ]; inherits(AppendBehavior, CommandInterceptor); module.exports = AppendBehavior; },{"195":195,"47":47,"75":75}],23:[function(_dereq_,module,exports){ 'use strict'; var inherits = _dereq_(195); var CommandInterceptor = _dereq_(75); var is = _dereq_(47).is; /** * BPMN specific create behavior */ function CreateBehavior(eventBus, modeling) { CommandInterceptor.call(this, eventBus); /** * morph process into collaboration before adding * participant onto collaboration */ this.preExecute('shape.create', function(context) { var parent = context.parent, shape = context.shape, position = context.position; if (is(parent, 'bpmn:Process') && is(shape, 'bpmn:Participant')) { // this is going to detach the process root // and set the returned collaboration element // as the new root element var collaborationElement = modeling.makeCollaboration(); // monkey patch the create context // so that the participant is being dropped // onto the new collaboration root instead context.position = position; context.parent = collaborationElement; context.processRoot = parent; } }, true); this.execute('shape.create', function(context) { var processRoot = context.processRoot, shape = context.shape; if (processRoot) { context.oldProcessRef = shape.businessObject.processRef; // assign the participant processRef shape.businessObject.processRef = processRoot.businessObject; } }, true); this.revert('shape.create', function(context) { var processRoot = context.processRoot, shape = context.shape; if (processRoot) { // assign the participant processRef shape.businessObject.processRef = context.oldProcessRef; } }, true); this.postExecute('shape.create', function(context) { var processRoot = context.processRoot, shape = context.shape; if (processRoot) { // process root is already detached at this point var processChildren = processRoot.children.slice(); modeling.moveShapes(processChildren, { x: 0, y: 0 }, shape); } }, true); } CreateBehavior.$inject = [ 'eventBus', 'modeling' ]; inherits(CreateBehavior, CommandInterceptor); module.exports = CreateBehavior; },{"195":195,"47":47,"75":75}],24:[function(_dereq_,module,exports){ 'use strict'; var forEach = _dereq_(204), inherits = _dereq_(195); var CommandInterceptor = _dereq_(75); var is = _dereq_(47).is, getSharedParent = _dereq_(21).getSharedParent; function DropBehavior(eventBus, modeling, bpmnRules) { CommandInterceptor.call(this, eventBus); // remove sequence flows that should not be allowed // after a move operation this.postExecute('shapes.move', function(context) { var closure = context.closure, allConnections = closure.allConnections; forEach(allConnections, function(c) { var source = c.source, target = c.target; var replacementType, remove; /** * Check if incoming or outgoing connections * can stay or could be substituted with an * appropriate replacement. * * This holds true for SequenceFlow <> MessageFlow. */ if (is(c, 'bpmn:SequenceFlow')) { if (!bpmnRules.canConnectSequenceFlow(source, target)) { remove = true; } if (bpmnRules.canConnectMessageFlow(source, target)) { replacementType = 'bpmn:MessageFlow'; } } // transform message flows into sequence flows, if possible if (is(c, 'bpmn:MessageFlow')) { if (!bpmnRules.canConnectMessageFlow(source, target)) { remove = true; } if (bpmnRules.canConnectSequenceFlow(source, target)) { replacementType = 'bpmn:SequenceFlow'; } } if (is(c, 'bpmn:Association') && !bpmnRules.canConnectAssociation(source, target)) { remove = true; } // remove invalid connection if (remove) { modeling.removeConnection(c); } // replace SequenceFlow <> MessageFlow if (replacementType) { modeling.createConnection(source, target, { type: replacementType, waypoints: c.waypoints.slice() }, getSharedParent(source, target)); } }); }, true); } inherits(DropBehavior, CommandInterceptor); DropBehavior.$inject = [ 'eventBus', 'modeling', 'bpmnRules' ]; module.exports = DropBehavior; },{"195":195,"204":204,"21":21,"47":47,"75":75}],25:[function(_dereq_,module,exports){ 'use strict'; var is = _dereq_(47).is; function ModelingFeedback(eventBus, tooltips) { function showError(position, message) { tooltips.add({ position: { x: position.x + 5, y: position.y + 5 }, type: 'error', timeout: 2000, html: '
' + message + '
' }); } eventBus.on([ 'shape.move.rejected', 'create.rejected' ], function(event) { var context = event.context, shape = context.shape, target = context.target; if (is(target, 'bpmn:Collaboration') && is(shape, 'bpmn:FlowNode')) { showError(event, 'flow elements must be children of pools/participants'); } }); } ModelingFeedback.$inject = [ 'eventBus', 'tooltips' ]; module.exports = ModelingFeedback; },{"47":47}],26:[function(_dereq_,module,exports){ 'use strict'; var inherits = _dereq_(195); var CommandInterceptor = _dereq_(75); var is = _dereq_(47).is; /** * BPMN specific remove behavior */ function RemoveBehavior(eventBus, modeling) { CommandInterceptor.call(this, eventBus); /** * morph collaboration diagram into process diagram * after the last participant has been removed */ this.preExecute('shape.delete', function(context) { var shape = context.shape, parent = shape.parent; // activate the behavior if the shape to be removed // is a participant if (is(shape, 'bpmn:Participant')) { context.collaborationRoot = parent; } }, true); this.postExecute('shape.delete', function(context) { var collaborationRoot = context.collaborationRoot; if (collaborationRoot && !collaborationRoot.businessObject.participants.length) { // replace empty collaboration with process diagram modeling.makeProcess(); } }, true); } RemoveBehavior.$inject = [ 'eventBus', 'modeling' ]; inherits(RemoveBehavior, CommandInterceptor); module.exports = RemoveBehavior; },{"195":195,"47":47,"75":75}],27:[function(_dereq_,module,exports){ module.exports = { __init__: [ 'appendBehavior', 'createBehavior', 'dropBehavior', 'removeBehavior', 'modelingFeedback' ], appendBehavior: [ 'type', _dereq_(22) ], dropBehavior: [ 'type', _dereq_(24) ], createBehavior: [ 'type', _dereq_(23) ], removeBehavior: [ 'type', _dereq_(26) ], modelingFeedback: [ 'type', _dereq_(25) ] }; },{"22":22,"23":23,"24":24,"25":25,"26":26}],28:[function(_dereq_,module,exports){ 'use strict'; var Collections = _dereq_(175); function UpdateCanvasRootHandler(canvas, modeling) { this._canvas = canvas; this._modeling = modeling; } UpdateCanvasRootHandler.$inject = [ 'canvas', 'modeling' ]; module.exports = UpdateCanvasRootHandler; 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 Collections.add(bpmnDefinitions.rootElements, newRootBusinessObject); newRootBusinessObject.$parent = bpmnDefinitions; Collections.remove(bpmnDefinitions.rootElements, oldRootBusinessObject); oldRootBusinessObject.$parent = null; // (3) wire di oldRootBusinessObject.di = null; diPlane.bpmnElement = newRootBusinessObject; newRootBusinessObject.di = diPlane; context.oldRoot = 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 Collections.remove(bpmnDefinitions.rootElements, newRootBusinessObject); newRootBusinessObject.$parent = null; Collections.add(bpmnDefinitions.rootElements, oldRootBusinessObject); oldRootBusinessObject.$parent = bpmnDefinitions; // (3) wire di newRootBusinessObject.di = null; diPlane.bpmnElement = oldRootBusinessObject; oldRootBusinessObject.di = diPlane; }; },{"175":175}],29:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325), pick = _dereq_(330), keys = _dereq_(326); var DEFAULT_FLOW = 'default', NAME = 'name', ID = 'id'; /** * 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. */ function UpdatePropertiesHandler(elementRegistry) { this._elementRegistry = elementRegistry; } UpdatePropertiesHandler.$inject = [ 'elementRegistry' ]; module.exports = UpdatePropertiesHandler; ////// 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} the updated element */ UpdatePropertiesHandler.prototype.execute = function(context) { var element = context.element, changed = [ element ]; if (!element) { throw new Error('element required'); } var elementRegistry = this._elementRegistry; var businessObject = element.businessObject, properties = context.properties, oldProperties = context.oldProperties || pick(businessObject, keys(properties)); if (ID in properties) { elementRegistry.updateId(element, properties[ID]); } // 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)); } } if (NAME in properties && element.label) { changed.push(element.label); } // update properties assign(businessObject, properties); // store old values context.oldProperties = oldProperties; context.changed = changed; // indicate changed on objects affected by the update return changed; }; /** * Reverts the update on a BPMN elements properties. * * @param {Object} context * * @return {djs.mode.Base} the updated element */ UpdatePropertiesHandler.prototype.revert = function(context) { var element = context.element, oldProperties = context.oldProperties, businessObject = element.businessObject, elementRegistry = this._elementRegistry; assign(businessObject, context.oldProperties); if (ID in oldProperties) { elementRegistry.updateId(element, oldProperties[ID]); } return context.changed; }; },{"325":325,"326":326,"330":330}],30:[function(_dereq_,module,exports){ module.exports = { __init__: [ 'modeling', 'bpmnUpdater', 'labelSupport' ], __depends__: [ _dereq_(14), _dereq_(32), _dereq_(27), _dereq_(77), _dereq_(160), _dereq_(93) ], bpmnFactory: [ 'type', _dereq_(15) ], bpmnUpdater: [ 'type', _dereq_(17) ], elementFactory: [ 'type', _dereq_(18) ], modeling: [ 'type', _dereq_(20) ], labelSupport: [ 'type', _dereq_(19) ], layouter: [ 'type', _dereq_(16) ], connectionDocking: [ 'type', _dereq_(165) ] }; },{"14":14,"15":15,"16":16,"160":160,"165":165,"17":17,"18":18,"19":19,"20":20,"27":27,"32":32,"77":77,"93":93}],31:[function(_dereq_,module,exports){ 'use strict'; var groupBy = _dereq_(205), size = _dereq_(209), find = _dereq_(203), inherits = _dereq_(195); var getParents = _dereq_(21).getParents, is = _dereq_(47).is, getBusinessObject = _dereq_(47).getBusinessObject, isExpanded = _dereq_(45).isExpanded; var RuleProvider = _dereq_(145); /** * BPMN specific modeling rule */ function BpmnRules(eventBus) { RuleProvider.call(this, eventBus); } inherits(BpmnRules, RuleProvider); BpmnRules.$inject = [ 'eventBus' ]; module.exports = BpmnRules; BpmnRules.prototype.init = function() { this.addRule('connection.create', function(context) { var source = context.source, target = context.target; return canConnect(source, target); }); this.addRule('connection.reconnectStart', function(context) { var connection = context.connection, source = context.hover || context.source, target = connection.target; return canConnect(source, target, connection); }); this.addRule('connection.reconnectEnd', function(context) { var connection = context.connection, source = connection.source, target = context.hover || context.target; return canConnect(source, target, connection); }); this.addRule('connection.updateWaypoints', function(context) { // OK! but visually ignore return null; }); this.addRule('shape.resize', function(context) { var shape = context.shape, newBounds = context.newBounds; return canResize(shape, newBounds); }); this.addRule('shapes.move', function(context) { var target = context.newParent, shapes = context.shapes; return canMove(shapes, target); }); this.addRule([ 'shape.create', 'shape.append' ], function(context) { var target = context.parent, shape = context.shape, source = context.source; return canCreate(shape, target, source); }); }; BpmnRules.prototype.canConnectMessageFlow = canConnectMessageFlow; BpmnRules.prototype.canConnectSequenceFlow = canConnectSequenceFlow; BpmnRules.prototype.canConnectAssociation = canConnectAssociation; BpmnRules.prototype.canMove = canMove; BpmnRules.prototype.canDrop = canDrop; BpmnRules.prototype.canCreate = canCreate; BpmnRules.prototype.canConnect = canConnect; BpmnRules.prototype.canResize = canResize; /** * Utility functions for rule checking */ function nonExistantOrLabel(element) { return !element || isLabel(element); } function isSame(a, b) { return a === b; } function getOrganizationalParent(element) { var bo = getBusinessObject(element); while (bo && !is(bo, 'bpmn:Process')) { if (is(bo, 'bpmn:Participant')) { return bo.processRef || bo; } bo = bo.$parent; } return bo; } function isSameOrganization(a, b) { var parentA = getOrganizationalParent(a), parentB = getOrganizationalParent(b); return parentA === parentB; } function isMessageFlowSource(element) { return is(element, 'bpmn:InteractionNode') && ( !is(element, 'bpmn:Event') || ( is(element, 'bpmn:ThrowEvent') && hasEventDefinitionOrNone(element, 'bpmn:MessageEventDefinition') ) ); } function isMessageFlowTarget(element) { return is(element, 'bpmn:InteractionNode') && ( !is(element, 'bpmn:Event') || ( is(element, 'bpmn:CatchEvent') && hasEventDefinitionOrNone(element, 'bpmn:MessageEventDefinition') ) ); } function getScopeParent(element) { var bo = getBusinessObject(element); if (is(bo, 'bpmn:Participant')) { return null; } while (bo) { bo = bo.$parent; if (is(bo, 'bpmn:FlowElementsContainer')) { return bo; } } return bo; } function isSameScope(a, b) { var scopeParentA = getScopeParent(a), scopeParentB = getScopeParent(b); return scopeParentA && (scopeParentA === scopeParentB); } function hasEventDefinition(element, eventDefinition) { var bo = getBusinessObject(element); return !!find(bo.eventDefinitions || [], function(definition) { return is(definition, eventDefinition); }); } function hasEventDefinitionOrNone(element, eventDefinition) { var bo = getBusinessObject(element); return (bo.eventDefinitions || []).every(function(definition) { return is(definition, eventDefinition); }); } function isSequenceFlowSource(element) { return is(element, 'bpmn:FlowNode') && !is(element, 'bpmn:EndEvent') && !( is(element, 'bpmn:IntermediateThrowEvent') && hasEventDefinition(element, 'bpmn:LinkEventDefinition') ); } function isSequenceFlowTarget(element) { return is(element, 'bpmn:FlowNode') && !is(element, 'bpmn:StartEvent') && !( is(element, 'bpmn:IntermediateCatchEvent') && hasEventDefinition(element, 'bpmn:LinkEventDefinition') ); } function isEventBasedTarget(element) { return is(element, 'bpmn:ReceiveTask') || ( is(element, 'bpmn:IntermediateCatchEvent') && ( hasEventDefinition(element, 'bpmn:MessageEventDefinition') || hasEventDefinition(element, 'bpmn:TimerEventDefinition') || hasEventDefinition(element, 'bpmn:ConditionalEventDefinition') || hasEventDefinition(element, 'bpmn:SignalEventDefinition') ) ); } function isLabel(element) { return element.labelTarget; } function isConnection(element) { return element.waypoints; } function isParent(possibleParent, element) { var allParents = getParents(element); return allParents.indexOf(possibleParent) !== -1; } function canConnect(source, target, connection) { if (nonExistantOrLabel(source) || nonExistantOrLabel(target)) { return null; } // See https://github.com/bpmn-io/bpmn-js/issues/178 // as a workround we disallow connections with same // target and source element. // This rule must be removed if a auto layout for this // connections is implemented. if (isSame(source, target)) { return false; } if (canConnectMessageFlow(source, target) || canConnectSequenceFlow(source, target)) { return true; } if (is(connection, 'bpmn:Association')) { return canConnectAssociation(source, target); } return false; } /** * Can an element be dropped into the target element * * @return {Boolean} */ function canDrop(element, target) { // can move labels everywhere if (isLabel(element) && !isConnection(target)) { return true; } // allow to create new participants on // on existing collaboration and process diagrams if (is(element, 'bpmn:Participant')) { return is(target, 'bpmn:Process') || is(target, 'bpmn:Collaboration'); } // drop flow elements onto flow element containers // and participants if (is(element, 'bpmn:FlowElement')) { if (is(target, 'bpmn:FlowElementsContainer')) { return isExpanded(target) !== false; } return is(target, 'bpmn:Participant'); } if (is(element, 'bpmn:Artifact')) { return is(target, 'bpmn:Collaboration') || is(target, 'bpmn:Participant') || is(target, 'bpmn:Process'); } if (is(element, 'bpmn:MessageFlow')) { return is(target, 'bpmn:Collaboration'); } return false; } function canMove(elements, target) { // only move if they have the same parent var sameParent = size(groupBy(elements, function(s) { return s.parent && s.parent.id; })) === 1; if (!sameParent) { return false; } if (!target) { return true; } return elements.every(function(element) { return canDrop(element, target); }); } function canCreate(shape, target, source) { if (!target) { return false; } if (isLabel(target)) { return null; } if (isSame(source, target)) { return false; } // ensure we do not drop the element // into source if (source && isParent(source, target)) { return false; } return canDrop(shape, target); } function canResize(shape, newBounds) { if (is(shape, 'bpmn:SubProcess')) { return isExpanded(shape) && ( !newBounds || (newBounds.width >= 100 && newBounds.height >= 80) ); } if (is(shape, 'bpmn:Participant')) { return !newBounds || (newBounds.width >= 100 && newBounds.height >= 80); } if (is(shape, 'bpmn:TextAnnotation')) { return true; } return false; } function canConnectAssociation(source, target) { // do not connect connections if (isConnection(source) || isConnection(target)) { return false; } // connect if different parent return !isParent(target, source) && !isParent(source, target); } function canConnectMessageFlow(source, target) { return isMessageFlowSource(source) && isMessageFlowTarget(target) && !isSameOrganization(source, target); } function canConnectSequenceFlow(source, target) { return isSequenceFlowSource(source) && isSequenceFlowTarget(target) && isSameScope(source, target) && !(is(source, 'bpmn:EventBasedGateway') && !isEventBasedTarget(target)); } },{"145":145,"195":195,"203":203,"205":205,"209":209,"21":21,"45":45,"47":47}],32:[function(_dereq_,module,exports){ module.exports = { __depends__: [ _dereq_(147) ], __init__: [ 'bpmnRules' ], bpmnRules: [ 'type', _dereq_(31) ] }; },{"147":147,"31":31}],33:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325); /** * A palette provider for BPMN 2.0 elements. */ function PaletteProvider(palette, create, elementFactory, spaceTool, lassoTool) { this._create = create; this._elementFactory = elementFactory; this._spaceTool = spaceTool; this._lassoTool = lassoTool; palette.registerProvider(this); } module.exports = PaletteProvider; PaletteProvider.$inject = [ 'palette', 'create', 'elementFactory', 'spaceTool', 'lassoTool' ]; PaletteProvider.prototype.getPaletteEntries = function(element) { var actions = {}, create = this._create, elementFactory = this._elementFactory, spaceTool = this._spaceTool, lassoTool = this._lassoTool; function createAction(type, group, className, title, options) { function createListener(event) { var shape = elementFactory.createShape(assign({ type: type }, options)); if (options) { shape.businessObject.di.isExpanded = options.isExpanded; } create.start(event, shape); } var shortType = type.replace(/^bpmn\:/, ''); return { group: group, className: className, title: title || 'Create ' + shortType, action: { dragstart: createListener, click: createListener } }; } function createParticipant(event, collapsed) { create.start(event, elementFactory.createParticipantShape(collapsed)); } assign(actions, { 'lasso-tool': { group: 'tools', className: 'icon-lasso-tool', title: 'Activate the lasso tool', action: { click: function(event) { lassoTool.activateSelection(event); } } }, 'space-tool': { group: 'tools', className: 'icon-space-tool', title: 'Activate the create/remove space tool', action: { click: function(event) { spaceTool.activateSelection(event); } } }, 'tool-separator': { group: 'tools', separator: true }, 'create.start-event': createAction( 'bpmn:StartEvent', 'event', 'icon-start-event-none' ), 'create.intermediate-event': createAction( 'bpmn:IntermediateThrowEvent', 'event', 'icon-intermediate-event-none' ), 'create.end-event': createAction( 'bpmn:EndEvent', 'event', 'icon-end-event-none' ), 'create.exclusive-gateway': createAction( 'bpmn:ExclusiveGateway', 'gateway', 'icon-gateway-xor' ), 'create.task': createAction( 'bpmn:Task', 'activity', 'icon-task' ), 'create.subprocess-collapsed': createAction( 'bpmn:SubProcess', 'activity', 'icon-subprocess-collapsed', 'Create collapsed Sub Process', { isExpanded: false } ), 'create.subprocess-expanded': createAction( 'bpmn:SubProcess', 'activity', 'icon-subprocess-expanded', 'Create expanded SubProcess', { isExpanded: true } ), 'create.participant-expanded': { group: 'collaboration', className: 'icon-participant', title: 'Create Pool/Participant', action: { dragstart: createParticipant, click: createParticipant } } }); return actions; }; },{"325":325}],34:[function(_dereq_,module,exports){ module.exports = { __depends__: [ _dereq_(137), _dereq_(99) ], __init__: [ 'paletteProvider' ], paletteProvider: [ 'type', _dereq_(33) ] }; },{"137":137,"33":33,"99":99}],35:[function(_dereq_,module,exports){ 'use strict'; var forEach = _dereq_(204), filter = _dereq_(202); var REPLACE_OPTIONS = _dereq_(36); var startEventReplace = REPLACE_OPTIONS.START_EVENT, intermediateEventReplace = REPLACE_OPTIONS.INTERMEDIATE_EVENT, endEventReplace = REPLACE_OPTIONS.END_EVENT, gatewayReplace = REPLACE_OPTIONS.GATEWAY, taskReplace = REPLACE_OPTIONS.TASK; /** * A replace menu provider that gives users the controls to choose * and replace BPMN elements with each other. * * @param {BpmnFactory} bpmnFactory * @param {Moddle} moddle * @param {PopupMenu} popupMenu * @param {Replace} replace */ function BpmnReplace(bpmnFactory, moddle, popupMenu, replace, selection) { /** * Prepares a new business object for the replacement element * and triggers the replace operation. * * @param {djs.model.Base} element * @param {Object} target * @return {djs.model.Base} the newly created element */ function replaceElement(element, target) { var type = target.type, oldBusinessObject = element.businessObject, businessObject = bpmnFactory.create(type); var newElement = { type: type, businessObject: businessObject }; // initialize custom BPMN extensions if (target.eventDefinition) { var eventDefinitions = businessObject.get('eventDefinitions'), eventDefinition = moddle.create(target.eventDefinition); eventDefinitions.push(eventDefinition); } if (target.instantiate !== undefined) { businessObject.instantiate = target.instantiate; } if (target.eventGatewayType !== undefined) { businessObject.eventGatewayType = target.eventGatewayType; } // copy size (for activities only) if (oldBusinessObject.$instanceOf('bpmn:Activity')) { // TODO: need also to respect min/max Size newElement.width = element.width; newElement.height = element.height; } // TODO: copy other elligable properties from old business object businessObject.name = oldBusinessObject.name; newElement = replace.replaceElement(element, newElement); selection.select(newElement); return newElement; } function getReplaceOptions(element) { var menuEntries = []; var businessObject = element.businessObject; if (businessObject.$instanceOf('bpmn:StartEvent')) { addEntries(startEventReplace, filterEvents); } else if (businessObject.$instanceOf('bpmn:IntermediateCatchEvent') || businessObject.$instanceOf('bpmn:IntermediateThrowEvent')) { addEntries(intermediateEventReplace, filterEvents); } else if (businessObject.$instanceOf('bpmn:EndEvent')) { addEntries(endEventReplace, filterEvents); } else if (businessObject.$instanceOf('bpmn:Gateway')) { addEntries(gatewayReplace, function(entry) { return entry.target.type !== businessObject.$type; }); } else if (businessObject.$instanceOf('bpmn:FlowNode')) { addEntries(taskReplace, function(entry) { return entry.target.type !== businessObject.$type; }); } function filterEvents(entry) { var target = entry.target; var eventDefinition = businessObject.eventDefinitions && businessObject.eventDefinitions[0].$type; var isEventDefinitionEqual = target.eventDefinition == eventDefinition; var isEventTypeEqual = businessObject.$type == target.type; return ((!isEventDefinitionEqual && isEventTypeEqual) || !isEventTypeEqual) || !(isEventDefinitionEqual && isEventTypeEqual); } function addEntries(entries, filterFun) { // Filter selected type from the array var filteredEntries = filter(entries, filterFun); // Add entries to replace menu forEach(filteredEntries, function(definition) { var entry = addMenuEntry(definition); menuEntries.push(entry); }); } function addMenuEntry(definition) { return { label: definition.label, className: definition.className, action: { name: definition.actionName, handler: function() { replaceElement(element, definition.target); } } }; } return menuEntries; } // API this.openChooser = function(position, element) { var entries = this.getReplaceOptions(element); popupMenu.open('replace-menu', position, entries); }; this.getReplaceOptions = getReplaceOptions; this.replaceElement = replaceElement; } BpmnReplace.$inject = [ 'bpmnFactory', 'moddle', 'popupMenu', 'replace', 'selection' ]; module.exports = BpmnReplace; },{"202":202,"204":204,"36":36}],36:[function(_dereq_,module,exports){ 'use strict'; module.exports.START_EVENT = [ { label: 'Start Event', actionName: 'replace-with-none-start', className: 'icon-start-event-none', target: { type: 'bpmn:StartEvent' } }, { label: 'Intermediate Throw Event', actionName: 'replace-with-intermediate-throwing', className: 'icon-intermediate-event-none', target: { type: 'bpmn:IntermediateThrowEvent' } }, { label: 'End Event', actionName: 'replace-with-message-end', className: 'icon-end-event-none', target: { type: 'bpmn:EndEvent' } }, { label: 'Message Start Event', actionName: 'replace-with-message-start', className: 'icon-start-event-message', target: { type: 'bpmn:StartEvent', eventDefinition: 'bpmn:MessageEventDefinition' } }, { label: 'Timer Start Event', actionName: 'replace-with-timer-start', className: 'icon-start-event-timer', target: { type: 'bpmn:StartEvent', eventDefinition: 'bpmn:TimerEventDefinition' } }, { label: 'Conditional Start Event', actionName: 'replace-with-conditional-start', className: 'icon-start-event-condition', target: { type: 'bpmn:StartEvent', eventDefinition: 'bpmn:ConditionalEventDefinition' } }, { label: 'Signal Start Event', actionName: 'replace-with-signal-start', className: 'icon-start-event-signal', target: { type: 'bpmn:StartEvent', eventDefinition: 'bpmn:SignalEventDefinition' } } ]; module.exports.INTERMEDIATE_EVENT = [ { label: 'Start Event', actionName: 'replace-with-none-start', className: 'icon-start-event-none', target: { type: 'bpmn:StartEvent' } }, { label: 'Intermediate Throw Event', actionName: 'replace-with-message-intermediate-throw', className: 'icon-intermediate-event-none', target: { type: 'bpmn:IntermediateThrowEvent' } }, { label: 'End Event', actionName: 'replace-with-message-end', className: 'icon-end-event-none', target: { type: 'bpmn:EndEvent' } }, { label: 'Message Intermediate Catch Event', actionName: 'replace-with-intermediate-catch', className: 'icon-intermediate-event-catch-message', target: { type: 'bpmn:IntermediateCatchEvent', eventDefinition: 'bpmn:MessageEventDefinition' } }, { label: 'Message Intermediate Throw Event', actionName: 'replace-with-intermediate-throw', className: 'icon-intermediate-event-throw-message', target: { type: 'bpmn:IntermediateThrowEvent', eventDefinition: 'bpmn:MessageEventDefinition' } }, { label: 'Timer Intermediate Catch Event', actionName: 'replace-with-timer-intermediate-catch', className: 'icon-intermediate-event-catch-timer', target: { type: 'bpmn:IntermediateCatchEvent', eventDefinition: 'bpmn:TimerEventDefinition' } }, { label: 'Escalation Intermediate Catch Event', actionName: 'replace-with-escalation-catch', className: 'icon-intermediate-event-catch-escalation', target: { type: 'bpmn:IntermediateCatchEvent', eventDefinition: 'bpmn:EscalationEventDefinition' } }, { label: 'Conditional Intermediate Catch Event', actionName: 'replace-with-conditional-intermediate-catch', className: 'icon-intermediate-event-catch-condition', target: { type: 'bpmn:IntermediateCatchEvent', eventDefinition: 'bpmn:ConditionalEventDefinition' } }, { label: 'Link Intermediate Catch Event', actionName: 'replace-with-link-intermediate-catch', className: 'icon-intermediate-event-catch-link', target: { type: 'bpmn:IntermediateCatchEvent', eventDefinition: 'bpmn:LinkEventDefinition' } }, { label: 'Link Intermediate Throw Event', actionName: 'replace-with-link-intermediate-throw', className: 'icon-intermediate-event-throw-link', target: { type: 'bpmn:IntermediateThrowEvent', eventDefinition: 'bpmn:LinkEventDefinition' } }, { label: 'Compensation Intermediate Throw Event', actionName: 'replace-with-compensation-intermediate-throw', className: 'icon-intermediate-event-throw-compensation', target: { type: 'bpmn:IntermediateThrowEvent', eventDefinition: 'bpmn:CompensateEventDefinition' } }, { label: 'Signal Throw Catch Event', actionName: 'replace-with-throw-intermediate-catch', className: 'icon-intermediate-event-catch-signal', target: { type: 'bpmn:IntermediateCatchEvent', eventDefinition: 'bpmn:SignalEventDefinition' } }, { label: 'Signal Intermediate Throw Event', actionName: 'replace-with-signal-intermediate-throw', className: 'icon-intermediate-event-throw-signal', target: { type: 'bpmn:IntermediateThrowEvent', eventDefinition: 'bpmn:SignalEventDefinition' } } ]; module.exports.END_EVENT = [ { label: 'Start Event', actionName: 'replace-with-none-start', className: 'icon-start-event-none', target: { type: 'bpmn:StartEvent' } }, { label: 'Intermediate Throw Event', actionName: 'replace-with-message-intermediate-throw', className: 'icon-intermediate-event-none', target: { type: 'bpmn:IntermediateThrowEvent' } }, { label: 'End Event', actionName: 'replace-with-none-end', className: 'icon-end-event-none', target: { type: 'bpmn:EndEvent' } }, { label: 'Message End Event', actionName: 'replace-with-message-end', className: 'icon-end-event-message', target: { type: 'bpmn:EndEvent', eventDefinition: 'bpmn:MessageEventDefinition' } }, { label: 'Escalation End Event', actionName: 'replace-with-escalation-end', className: 'icon-end-event-escalation', target: { type: 'bpmn:EndEvent', eventDefinition: 'bpmn:EscalationEventDefinition' } }, { label: 'Error End Event', actionName: 'replace-with-error-end', className: 'icon-end-event-error', target: { type: 'bpmn:EndEvent', eventDefinition: 'bpmn:ErrorEventDefinition' } }, { label: 'Cancel End Event', actionName: 'replace-with-cancel-end', className: 'icon-end-event-cancel', target: { type: 'bpmn:EndEvent', eventDefinition: 'bpmn:CancelEventDefinition' } }, { label: 'Compensation End Event', actionName: 'replace-with-compensation-end', className: 'icon-end-event-compensation', target: { type: 'bpmn:EndEvent', eventDefinition: 'bpmn:CompensateEventDefinition' } }, { label: 'Signal End Event', actionName: 'replace-with-signal-end', className: 'icon-end-event-signal', target: { type: 'bpmn:EndEvent', eventDefinition: 'bpmn:SignalEventDefinition' } }, { label: 'Terminate End Event', actionName: 'replace-with-terminate-end', className: 'icon-end-event-terminate', target: { type: 'bpmn:EndEvent', eventDefinition: 'bpmn:TerminateEventDefinition' } } ]; module.exports.GATEWAY = [ { label: 'Exclusive Gateway', actionName: 'replace-with-exclusive-gateway', className: 'icon-gateway-xor', target: { type: 'bpmn:ExclusiveGateway' } }, { label: 'Parallel Gateway', actionName: 'replace-with-parallel-gateway', className: 'icon-gateway-parallel', target: { type: 'bpmn:ParallelGateway' } }, { label: 'Inclusive Gateway', actionName: 'replace-with-inclusive-gateway', className: 'icon-gateway-or', target: { type: 'bpmn:InclusiveGateway' } }, { label: 'Complex Gateway', actionName: 'replace-with-complex-gateway', className: 'icon-gateway-complex', target: { type: 'bpmn:ComplexGateway' } }, { label: 'Event based Gateway', actionName: 'replace-with-event-based-gateway', className: 'icon-gateway-eventbased', target: { type: 'bpmn:EventBasedGateway', instantiate: false, eventGatewayType: 'Exclusive' } } // Gateways deactivated until https://github.com/bpmn-io/bpmn-js/issues/194 // { // label: 'Event based instantiating Gateway', // actionName: 'replace-with-exclusive-event-based-gateway', // className: 'icon-exclusive-event-based', // target: { // type: 'bpmn:EventBasedGateway' // }, // options: { // businessObject: { instantiate: true, eventGatewayType: 'Exclusive' } // } // }, // { // label: 'Parallel Event based instantiating Gateway', // actionName: 'replace-with-parallel-event-based-instantiate-gateway', // className: 'icon-parallel-event-based-instantiate-gateway', // target: { // type: 'bpmn:EventBasedGateway' // }, // options: { // businessObject: { instantiate: true, eventGatewayType: 'Parallel' } // } // } ]; module.exports.TASK = [ { label: 'Task', actionName: 'replace-with-task', className: 'icon-task', target: { type: 'bpmn:Task' } }, { label: 'Send Task', actionName: 'replace-with-send-task', className: 'icon-send', target: { type: 'bpmn:SendTask' } }, { label: 'Receive Task', actionName: 'replace-with-receive-task', className: 'icon-receive', target: { type: 'bpmn:ReceiveTask' } }, { label: 'User Task', actionName: 'replace-with-user-task', className: 'icon-user', target: { type: 'bpmn:UserTask' } }, { label: 'Manual Task', actionName: 'replace-with-manual-task', className: 'icon-manual', target: { type: 'bpmn:ManualTask' } }, { label: 'Business Rule Task', actionName: 'replace-with-rule-task', className: 'icon-business-rule', target: { type: 'bpmn:BusinessRuleTask' } }, { label: 'Service Task', actionName: 'replace-with-service-task', className: 'icon-service', target: { type: 'bpmn:ServiceTask' } }, { label: 'Script Task', actionName: 'replace-with-script-task', className: 'icon-script', target: { type: 'bpmn:ScriptTask' } } ]; },{}],37:[function(_dereq_,module,exports){ module.exports = { __depends__: [ _dereq_(139), _dereq_(141), _dereq_(151) ], bpmnReplace: [ 'type', _dereq_(35) ] }; },{"139":139,"141":141,"151":151,"35":35}],38:[function(_dereq_,module,exports){ 'use strict'; var inherits = _dereq_(195); var forEach = _dereq_(204); var getBoundingBox = _dereq_(177).getBBox; var is = _dereq_(21).is; var Snapping = _dereq_(154), SnapUtil = _dereq_(153); var is = _dereq_(47).is; var mid = SnapUtil.mid, topLeft = SnapUtil.topLeft, bottomRight = SnapUtil.bottomRight; var round = Math.round; /** * BPMN specific snapping functionality * * * snap on process elements if a pool is created inside a * process diagram * * @param {EventBus} eventBus * @param {Canvas} canvas */ function BpmnSnapping(eventBus, canvas) { // instantiate super Snapping.call(this, eventBus, canvas); /** * Drop participant on process <> process elements snapping */ function initParticipantSnapping(context, shape, elements) { if (!elements.length) { return; } var snapBox = getBoundingBox(elements.filter(function(e) { return !e.labelTarget && !e.waypoints; })); snapBox.x -= 50; snapBox.y -= 20; snapBox.width += 70; snapBox.height += 40; // adjust shape height to include bounding box shape.width = Math.max(shape.width, snapBox.width); shape.height = Math.max(shape.height, snapBox.height); context.participantSnapBox = snapBox; } function snapParticipant(snapBox, shape, event) { var shapeHalfWidth = shape.width / 2 - 30, shapeHalfHeight = shape.height / 2; var currentTopLeft = { x: event.x - shapeHalfWidth - 30, y: event.y - shapeHalfHeight }; var currentBottomRight = { x: event.x + shapeHalfWidth + 30, y: event.y + shapeHalfHeight }; var snapTopLeft = snapBox, snapBottomRight = bottomRight(snapBox); if (currentTopLeft.x >= snapTopLeft.x) { event.x = snapTopLeft.x + 30 + shapeHalfWidth; event.snapped = true; } else if (currentBottomRight.x <= snapBottomRight.x) { event.x = snapBottomRight.x - 30 - shapeHalfWidth; event.snapped = true; } if (currentTopLeft.y >= snapTopLeft.y) { event.y = snapTopLeft.y + shapeHalfHeight; event.snapped = true; } else if (currentBottomRight.y <= snapBottomRight.y) { event.y = snapBottomRight.y - shapeHalfHeight; event.snapped = true; } } eventBus.on('create.start', function(event) { var context = event.context, shape = context.shape, rootElement = canvas.getRootElement(); // snap participant around existing elements (if any) if (is(shape, 'bpmn:Participant') && is(rootElement, 'bpmn:Process')) { initParticipantSnapping(context, shape, rootElement.children); } }); eventBus.on([ 'create.move', 'create.end' ], 1500, function(event) { var context = event.context, shape = context.shape, participantSnapBox = context.participantSnapBox; if (!event.snapped && participantSnapBox) { snapParticipant(participantSnapBox, shape, event); } }); eventBus.on('resize.start', 1500, function(event) { var context = event.context, shape = context.shape; if (is(shape, 'bpmn:SubProcess')) { context.minDimensions = { width: 140, height: 120 }; } if (is(shape, 'bpmn:Participant')) { context.minDimensions = { width: 400, height: 200 }; } if (is(shape, 'bpmn:TextAnnotation')) { context.minDimensions = { width: 50, height: 50 }; } }); } inherits(BpmnSnapping, Snapping); BpmnSnapping.$inject = [ 'eventBus', 'canvas' ]; module.exports = BpmnSnapping; BpmnSnapping.prototype.initSnap = function(event) { var context = event.context, shape = context.shape, shapeMid, shapeBounds, shapeTopLeft, shapeBottomRight, snapContext; snapContext = Snapping.prototype.initSnap.call(this, event); if (is(shape, 'bpmn:Participant')) { // assign higher priority for outer snaps on participants snapContext.setSnapLocations([ 'top-left', 'bottom-right', 'mid' ]); } if (shape) { shapeMid = mid(shape, event); shapeBounds = { width: shape.width, height: shape.height, x: isNaN(shape.x) ? round(shapeMid.x - shape.width / 2) : shape.x, y: isNaN(shape.y) ? round(shapeMid.y - shape.height / 2) : shape.y, }; shapeTopLeft = topLeft(shapeBounds); shapeBottomRight = bottomRight(shapeBounds); snapContext.setSnapOrigin('top-left', { x: shapeTopLeft.x - event.x, y: shapeTopLeft.y - event.y }); snapContext.setSnapOrigin('bottom-right', { x: shapeBottomRight.x - event.x, y: shapeBottomRight.y - event.y }); forEach(shape.outgoing, function(c) { var docking = c.waypoints[0]; docking = docking.original || docking; snapContext.setSnapOrigin(c.id + '-docking', { x: docking.x - event.x, y: docking.y - event.y }); }); forEach(shape.incoming, function(c) { var docking = c.waypoints[c.waypoints.length - 1]; docking = docking.original || docking; snapContext.setSnapOrigin(c.id + '-docking', { x: docking.x - event.x, y: docking.y - event.y }); }); } var source = context.source; if (source) { snapContext.addDefaultSnap('mid', mid(source)); } }; BpmnSnapping.prototype.addTargetSnaps = function(snapPoints, shape, target) { var siblings = this.getSiblings(shape, target); forEach(siblings, function(s) { snapPoints.add('mid', mid(s)); if (is(s, 'bpmn:Participant')) { snapPoints.add('top-left', topLeft(s)); snapPoints.add('bottom-right', bottomRight(s)); } }); forEach(shape.incoming, function(c) { if (siblings.indexOf(c.source) === -1) { snapPoints.add('mid', mid(c.source)); var docking = c.waypoints[0]; snapPoints.add(c.id + '-docking', docking.original || docking); } }); forEach(shape.outgoing, function(c) { if (siblings.indexOf(c.target) === -1) { snapPoints.add('mid', mid(c.target)); var docking = c.waypoints[c.waypoints.length - 1]; snapPoints.add(c.id + '-docking', docking.original || docking); } }); }; },{"153":153,"154":154,"177":177,"195":195,"204":204,"21":21,"47":47}],39:[function(_dereq_,module,exports){ module.exports = { __init__: [ 'snapping' ], snapping: [ 'type', _dereq_(38) ] }; },{"38":38}],40:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325), map = _dereq_(207); var LabelUtil = _dereq_(46); var hasExternalLabel = LabelUtil.hasExternalLabel, getExternalLabelBounds = LabelUtil.getExternalLabelBounds, isExpanded = _dereq_(45).isExpanded, elementToString = _dereq_(43).elementToString; function elementData(semantic, attrs) { return assign({ id: semantic.id, type: semantic.$type, businessObject: semantic }, attrs); } function collectWaypoints(waypoints) { return map(waypoints, function(p) { return { x: p.x, y: p.y }; }); } /** * An importer that adds bpmn elements to the canvas * * @param {EventBus} eventBus * @param {Canvas} canvas * @param {ElementFactory} elementFactory * @param {ElementRegistry} elementRegistry */ function BpmnImporter(eventBus, canvas, elementFactory, elementRegistry) { this._eventBus = eventBus; this._canvas = canvas; this._elementFactory = elementFactory; this._elementRegistry = elementRegistry; } BpmnImporter.$inject = [ 'eventBus', 'canvas', 'elementFactory', 'elementRegistry' ]; module.exports = BpmnImporter; /** * Add bpmn element (semantic) to the canvas onto the * specified parent shape. */ BpmnImporter.prototype.add = function(semantic, parentElement) { var di = semantic.di, element; // ROOT ELEMENT // handle the special case that we deal with a // invisible root element (process or collaboration) if (di.$instanceOf('bpmndi:BPMNPlane')) { // add a virtual element (not being drawn) element = this._elementFactory.createRoot(elementData(semantic)); this._canvas.setRootElement(element); } // SHAPE else if (di.$instanceOf('bpmndi:BPMNShape')) { var collapsed = !isExpanded(semantic); var hidden = parentElement && (parentElement.hidden || parentElement.collapsed); var bounds = semantic.di.bounds; element = this._elementFactory.createShape(elementData(semantic, { collapsed: collapsed, hidden: hidden, x: Math.round(bounds.x), y: Math.round(bounds.y), width: Math.round(bounds.width), height: Math.round(bounds.height) })); this._canvas.addShape(element, parentElement); } // CONNECTION else if (di.$instanceOf('bpmndi:BPMNEdge')) { var source = this._getSource(semantic), target = this._getTarget(semantic); element = this._elementFactory.createConnection(elementData(semantic, { source: source, target: target, waypoints: collectWaypoints(semantic.di.waypoint) })); this._canvas.addConnection(element, parentElement); } else { throw new Error('unknown di ' + elementToString(di) + ' for element ' + elementToString(semantic)); } // (optional) LABEL if (hasExternalLabel(semantic)) { this.addLabel(semantic, element); } this._eventBus.fire('bpmnElement.added', { element: element }); return element; }; /** * add label for an element */ BpmnImporter.prototype.addLabel = function(semantic, element) { var bounds = getExternalLabelBounds(semantic, element); var label = this._elementFactory.createLabel(elementData(semantic, { id: semantic.id + '_label', labelTarget: element, type: 'label', hidden: element.hidden, x: Math.round(bounds.x), y: Math.round(bounds.y), width: Math.round(bounds.width), height: Math.round(bounds.height) })); return this._canvas.addShape(label, element.parent); }; /** * Return the drawn connection end based on the given side. * * @throws {Error} if the end is not yet drawn */ BpmnImporter.prototype._getEnd = function(semantic, side) { var element, refSemantic, type = semantic.$type; refSemantic = semantic[side + 'Ref']; // handle mysterious isMany DataAssociation#sourceRef if (side === 'source' && type === 'bpmn:DataInputAssociation') { refSemantic = refSemantic && refSemantic[0]; } // fix source / target for DataInputAssociation / DataOutputAssociation if (side === 'source' && type === 'bpmn:DataOutputAssociation' || side === 'target' && type === 'bpmn:DataInputAssociation') { refSemantic = semantic.$parent; } element = refSemantic && this._getElement(refSemantic); if (element) { return element; } if (refSemantic) { throw new Error( 'element ' + elementToString(refSemantic) + ' referenced by ' + elementToString(semantic) + '#' + side + 'Ref not yet drawn'); } else { throw new Error(elementToString(semantic) + '#' + side + 'Ref not specified'); } }; BpmnImporter.prototype._getSource = function(semantic) { return this._getEnd(semantic, 'source'); }; BpmnImporter.prototype._getTarget = function(semantic) { return this._getEnd(semantic, 'target'); }; BpmnImporter.prototype._getElement = function(semantic) { return this._elementRegistry.get(semantic.id); }; },{"207":207,"325":325,"43":43,"45":45,"46":46}],41:[function(_dereq_,module,exports){ 'use strict'; var filter = _dereq_(202), find = _dereq_(203), forEach = _dereq_(204); var Refs = _dereq_(356); var elementToString = _dereq_(43).elementToString; var diRefs = new Refs({ name: 'bpmnElement', enumerable: true }, { name: 'di' }); /** * Returns true if an element has the given meta-model type * * @param {ModdleElement} element * @param {String} type * * @return {Boolean} */ function is(element, type) { return element.$instanceOf(type); } /** * Find a suitable display candidate for definitions where the DI does not * correctly specify one. */ function findDisplayCandidate(definitions) { return find(definitions.rootElements, function(e) { return is(e, 'bpmn:Process') || is(e, 'bpmn:Collaboration'); }); } function BpmnTreeWalker(handler) { // list of containers already walked var handledProcesses = []; // list of elements to handle deferred to ensure // prerequisites are drawn var deferred = []; ///// Helpers ///////////////////////////////// function contextual(fn, ctx) { return function(e) { fn(e, ctx); }; } function visit(element, ctx) { var gfx = element.gfx; // avoid multiple rendering of elements if (gfx) { throw new Error('already rendered ' + elementToString(element)); } // call handler return handler.element(element, ctx); } function visitRoot(element, diagram) { return handler.root(element, diagram); } function visitIfDi(element, ctx) { try { return element.di && visit(element, ctx); } catch (e) { logError(e.message, { element: element, error: e }); console.error('failed to import ' + elementToString(element)); console.error(e); } } function logError(message, context) { handler.error(message, context); } ////// DI handling //////////////////////////// function registerDi(di) { var bpmnElement = di.bpmnElement; if (bpmnElement) { if (bpmnElement.di) { logError('multiple DI elements defined for ' + elementToString(bpmnElement), { element: bpmnElement }); } else { diRefs.bind(bpmnElement, 'di'); bpmnElement.di = di; } } else { logError('no bpmnElement referenced in ' + elementToString(di), { element: di }); } } function handleDiagram(diagram) { handlePlane(diagram.plane); } function handlePlane(plane) { registerDi(plane); forEach(plane.planeElement, handlePlaneElement); } function handlePlaneElement(planeElement) { registerDi(planeElement); } ////// Semantic handling ////////////////////// function handleDefinitions(definitions, diagram) { // make sure we walk the correct bpmnElement var diagrams = definitions.diagrams; if (diagram && diagrams.indexOf(diagram) === -1) { throw new Error('diagram not part of bpmn:Definitions'); } if (!diagram && diagrams && diagrams.length) { diagram = diagrams[0]; } // no diagram -> nothing to import if (!diagram) { return; } // load DI from selected diagram only handleDiagram(diagram); var plane = diagram.plane; if (!plane) { throw new Error('no plane for ' + elementToString(diagram)); } var rootElement = plane.bpmnElement; // ensure we default to a suitable display candidate (process or collaboration), // even if non is specified in DI if (!rootElement) { rootElement = findDisplayCandidate(definitions); if (!rootElement) { return logError('no process or collaboration present to display'); } else { logError('correcting missing bpmnElement on ' + elementToString(plane) + ' to ' + elementToString(rootElement)); // correct DI on the fly plane.bpmnElement = rootElement; registerDi(plane); } } var ctx = visitRoot(rootElement, plane); if (is(rootElement, 'bpmn:Process')) { handleProcess(rootElement, ctx); } else if (is(rootElement, 'bpmn:Collaboration')) { handleCollaboration(rootElement, ctx); // force drawing of everything not yet drawn that is part of the target DI handleUnhandledProcesses(definitions.rootElements, ctx); } else { throw new Error('unsupported bpmnElement for ' + elementToString(plane) + ' : ' + elementToString(rootElement)); } // handle all deferred elements handleDeferred(deferred); } function handleDeferred(deferred) { forEach(deferred, function(d) { d(); }); } function handleProcess(process, context) { handleFlowElementsContainer(process, context); handleIoSpecification(process.ioSpecification, context); handleArtifacts(process.artifacts, context); // log process handled handledProcesses.push(process); } function handleUnhandledProcesses(rootElements) { // walk through all processes that have not yet been drawn and draw them // if they contain lanes with DI information. // we do this to pass the free-floating lane test cases in the MIWG test suite var processes = filter(rootElements, function(e) { return is(e, 'bpmn:Process') && e.laneSets && handledProcesses.indexOf(e) === -1; }); processes.forEach(contextual(handleProcess)); } function handleMessageFlow(messageFlow, context) { visitIfDi(messageFlow, context); } function handleMessageFlows(messageFlows, context) { forEach(messageFlows, contextual(handleMessageFlow, context)); } function handleDataAssociation(association, context) { visitIfDi(association, context); } function handleDataInput(dataInput, context) { visitIfDi(dataInput, context); } function handleDataOutput(dataOutput, context) { visitIfDi(dataOutput, context); } function handleArtifact(artifact, context) { // bpmn:TextAnnotation // bpmn:Group // bpmn:Association visitIfDi(artifact, context); } function handleArtifacts(artifacts, context) { forEach(artifacts, function(e) { if (is(e, 'bpmn:Association')) { deferred.push(function() { handleArtifact(e, context); }); } else { handleArtifact(e, context); } }); } function handleIoSpecification(ioSpecification, context) { if (!ioSpecification) { return; } forEach(ioSpecification.dataInputs, contextual(handleDataInput, context)); forEach(ioSpecification.dataOutputs, contextual(handleDataOutput, context)); } function handleSubProcess(subProcess, context) { handleFlowElementsContainer(subProcess, context); handleArtifacts(subProcess.artifacts, context); } function handleFlowNode(flowNode, context) { var childCtx = visitIfDi(flowNode, context); if (is(flowNode, 'bpmn:SubProcess')) { handleSubProcess(flowNode, childCtx || context); } } function handleSequenceFlow(sequenceFlow, context) { visitIfDi(sequenceFlow, context); } function handleDataElement(dataObject, context) { visitIfDi(dataObject, context); } function handleBoundaryEvent(dataObject, context) { visitIfDi(dataObject, context); } function handleLane(lane, context) { var newContext = visitIfDi(lane, context); if (lane.childLaneSet) { handleLaneSet(lane.childLaneSet, newContext || context); } else { var filterList = filter(lane.flowNodeRef, function(e) { return e.$type !== 'bpmn:BoundaryEvent'; }); handleFlowElements(filterList, newContext || context); } } function handleLaneSet(laneSet, context) { forEach(laneSet.lanes, contextual(handleLane, context)); } function handleLaneSets(laneSets, context) { forEach(laneSets, contextual(handleLaneSet, context)); } function handleFlowElementsContainer(container, context) { if (container.laneSets) { handleLaneSets(container.laneSets, context); handleNonFlowNodes(container.flowElements); } else { handleFlowElements(container.flowElements, context); } } function handleNonFlowNodes(flowElements, context) { forEach(flowElements, function(e) { if (is(e, 'bpmn:SequenceFlow')) { deferred.push(function() { handleSequenceFlow(e, context); }); } else if (is(e, 'bpmn:BoundaryEvent')) { deferred.unshift(function() { handleBoundaryEvent(e, context); }); } else if (is(e, 'bpmn:DataObject')) { // SKIP (assume correct referencing via DataObjectReference) } else if (is(e, 'bpmn:DataStoreReference')) { handleDataElement(e, context); } else if (is(e, 'bpmn:DataObjectReference')) { handleDataElement(e, context); } }); } function handleFlowElements(flowElements, context) { forEach(flowElements, function(e) { if (is(e, 'bpmn:SequenceFlow')) { deferred.push(function() { handleSequenceFlow(e, context); }); } else if (is(e, 'bpmn:BoundaryEvent')) { deferred.unshift(function() { handleBoundaryEvent(e, context); }); } else if (is(e, 'bpmn:FlowNode')) { handleFlowNode(e, context); if (is(e, 'bpmn:Activity')) { handleIoSpecification(e.ioSpecification, context); // defer handling of associations deferred.push(function() { forEach(e.dataInputAssociations, contextual(handleDataAssociation, context)); forEach(e.dataOutputAssociations, contextual(handleDataAssociation, context)); }); } } else if (is(e, 'bpmn:DataObject')) { // SKIP (assume correct referencing via DataObjectReference) } else if (is(e, 'bpmn:DataStoreReference')) { handleDataElement(e, context); } else if (is(e, 'bpmn:DataObjectReference')) { handleDataElement(e, context); } else { logError( 'unrecognized flowElement ' + elementToString(e) + ' in context ' + (context ? elementToString(context.businessObject) : null), { element: e, context: context }); } }); } function handleParticipant(participant, context) { var newCtx = visitIfDi(participant, context); var process = participant.processRef; if (process) { handleProcess(process, newCtx || context); } } function handleCollaboration(collaboration) { forEach(collaboration.participants, contextual(handleParticipant)); handleArtifacts(collaboration.artifacts); // handle message flows latest in the process deferred.push(function() { handleMessageFlows(collaboration.messageFlows); }); } ///// API //////////////////////////////// return { handleDefinitions: handleDefinitions }; } module.exports = BpmnTreeWalker; },{"202":202,"203":203,"204":204,"356":356,"43":43}],42:[function(_dereq_,module,exports){ 'use strict'; var BpmnTreeWalker = _dereq_(41); /** * Import the definitions into a diagram. * * Errors and warnings are reported through the specified callback. * * @param {Diagram} diagram * @param {ModdleElement} definitions * @param {Function} done the callback, invoked with (err, [ warning ]) once the import is done */ function importBpmnDiagram(diagram, definitions, done) { var importer = diagram.get('bpmnImporter'), eventBus = diagram.get('eventBus'); var error, warnings = []; function parse(definitions) { var visitor = { root: function(element) { return importer.add(element); }, element: function(element, parentShape) { return importer.add(element, parentShape); }, error: function(message, context) { warnings.push({ message: message, context: context }); } }; var walker = new BpmnTreeWalker(visitor); // import walker.handleDefinitions(definitions); } eventBus.fire('import.start'); try { parse(definitions); } catch (e) { error = e; } eventBus.fire(error ? 'import.error' : 'import.success', { error: error, warnings: warnings }); done(error, warnings); } module.exports.importBpmnDiagram = importBpmnDiagram; },{"41":41}],43:[function(_dereq_,module,exports){ 'use strict'; module.exports.elementToString = function(e) { if (!e) { return ''; } return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />'; }; },{}],44:[function(_dereq_,module,exports){ module.exports = { bpmnImporter: [ 'type', _dereq_(40) ] }; },{"40":40}],45:[function(_dereq_,module,exports){ 'use strict'; var is = _dereq_(47).is, getBusinessObject = _dereq_(47).getBusinessObject; module.exports.isExpanded = function(element) { if (is(element, 'bpmn:CallActivity')) { return false; } if (is(element, 'bpmn:SubProcess')) { return getBusinessObject(element).di.isExpanded; } if (is(element, 'bpmn:Participant')) { return !!getBusinessObject(element).processRef; } return true; }; },{"47":47}],46:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325); var DEFAULT_LABEL_SIZE = module.exports.DEFAULT_LABEL_SIZE = { width: 90, height: 20 }; /** * Returns true if the given semantic has an external label * * @param {BpmnElement} semantic * @return {Boolean} true if has label */ module.exports.hasExternalLabel = function(semantic) { return semantic.$instanceOf('bpmn:Event') || semantic.$instanceOf('bpmn:Gateway') || semantic.$instanceOf('bpmn:DataStoreReference') || semantic.$instanceOf('bpmn:DataObjectReference') || semantic.$instanceOf('bpmn:SequenceFlow') || semantic.$instanceOf('bpmn:MessageFlow'); }; /** * Get the middle of a number of waypoints * * @param {Array} waypoints * @return {Point} the mid point */ var getWaypointsMid = module.exports.getWaypointsMid = function(waypoints) { var mid = waypoints.length / 2 - 1; var first = waypoints[Math.floor(mid)]; var second = waypoints[Math.ceil(mid + 0.01)]; return { x: first.x + (second.x - first.x) / 2, y: first.y + (second.y - first.y) / 2 }; }; var getExternalLabelMid = module.exports.getExternalLabelMid = function(element) { if (element.waypoints) { return getWaypointsMid(element.waypoints); } else { return { x: element.x + element.width / 2, y: element.y + element.height + DEFAULT_LABEL_SIZE.height / 2 }; } }; /** * Returns the bounds of an elements label, parsed from the elements DI or * generated from its bounds. * * @param {BpmnElement} semantic * @param {djs.model.Base} element */ module.exports.getExternalLabelBounds = function(semantic, element) { var mid, size, bounds, di = semantic.di, label = di.label; if (label && label.bounds) { bounds = label.bounds; size = { width: Math.max(DEFAULT_LABEL_SIZE.width, bounds.width), height: bounds.height }; mid = { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 }; } else { mid = getExternalLabelMid(element); size = DEFAULT_LABEL_SIZE; } return assign({ x: mid.x - size.width / 2, y: mid.y - size.height / 2 }, size); }; },{"325":325}],47:[function(_dereq_,module,exports){ 'use strict'; /** * Is an element of the given BPMN type? * * @param {djs.model.Base|ModdleElement} element * @param {String} type * * @return {Boolean} */ function is(element, type) { var bo = getBusinessObject(element); return bo && bo.$instanceOf(type); } module.exports.is = is; /** * Return the business object for a given element. * * @param {djs.model.Base|ModdleElement} element * * @return {ModdleElement} */ function getBusinessObject(element) { return (element && element.businessObject) || element; } module.exports.getBusinessObject = getBusinessObject; },{}],48:[function(_dereq_,module,exports){ module.exports = _dereq_(51); },{"51":51}],49:[function(_dereq_,module,exports){ 'use strict'; var isString = _dereq_(322), isFunction = _dereq_(317), assign = _dereq_(325); var Moddle = _dereq_(57), XmlReader = _dereq_(53), XmlWriter = _dereq_(54); /** * A sub class of {@link Moddle} with support for import and export of BPMN 2.0 xml files. * * @class BpmnModdle * @extends Moddle * * @param {Object|Array} packages to use for instantiating the model * @param {Object} [options] additional options to pass over */ function BpmnModdle(packages, options) { Moddle.call(this, packages, options); } BpmnModdle.prototype = Object.create(Moddle.prototype); module.exports = BpmnModdle; /** * Instantiates a BPMN model tree from a given xml string. * * @param {String} xmlStr * @param {String} [typeName='bpmn:Definitions'] name of the root element * @param {Object} [options] options to pass to the underlying reader * @param {Function} done callback that is invoked with (err, result, parseContext) * once the import completes */ BpmnModdle.prototype.fromXML = function(xmlStr, typeName, options, done) { if (!isString(typeName)) { done = options; options = typeName; typeName = 'bpmn:Definitions'; } if (isFunction(options)) { done = options; options = {}; } var reader = new XmlReader(assign({ model: this, lax: true }, options)); var rootHandler = reader.handler(typeName); reader.fromXML(xmlStr, rootHandler, done); }; /** * Serializes a BPMN 2.0 object tree to XML. * * @param {String} element the root element, typically an instance of `bpmn:Definitions` * @param {Object} [options] to pass to the underlying writer * @param {Function} done callback invoked with (err, xmlStr) once the import completes */ BpmnModdle.prototype.toXML = function(element, options, done) { if (isFunction(options)) { done = options; options = {}; } var writer = new XmlWriter(options); try { var result = writer.toXML(element); done(null, result); } catch (e) { done(e); } }; },{"317":317,"322":322,"325":325,"53":53,"54":54,"57":57}],50:[function(_dereq_,module,exports){ 'use strict'; var ID_PATTERN = /^(.*:)?id$/; /** * Extends the bpmn instance with id support. * * @example * * var moddle, ids; * * require('id-support').extend(moddle, ids); * * moddle.ids.next(); // create a next id * moddle.ids; // ids instance * * // claims id as used * moddle.create('foo:Bar', { id: 'fooobar1' }); * * * @param {Moddle} model * @param {Ids} ids * * @return {Moddle} the extended moddle instance */ module.exports.extend = function(model, ids) { var set = model.properties.set; // do not reinitialize setter // unless it is already initialized if (!model.ids) { model.properties.set = function(target, property, value) { // ensure we log used ids once they are assigned // to model elements if (ID_PATTERN.test(property)) { var assigned = model.ids.assigned(value); if (assigned && assigned !== target) { throw new Error('id <' + value + '> already used'); } model.ids.claim(value, target); } set.call(this, target, property, value); }; } model.ids = ids; return model; }; },{}],51:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(325); var BpmnModdle = _dereq_(49); var packages = { bpmn: _dereq_(66), bpmndi: _dereq_(67), dc: _dereq_(68), di: _dereq_(69) }; module.exports = function(additionalPackages, options) { return new BpmnModdle(assign({}, packages, additionalPackages), options); }; },{"325":325,"49":49,"66":66,"67":67,"68":68,"69":69}],52:[function(_dereq_,module,exports){ 'use strict'; function capitalize(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function lower(string) { return string.charAt(0).toLowerCase() + string.slice(1); } function hasLowerCaseAlias(pkg) { return pkg.xml && pkg.xml.tagAlias === 'lowerCase'; } module.exports.aliasToName = function(alias, pkg) { if (hasLowerCaseAlias(pkg)) { return capitalize(alias); } else { return alias; } }; module.exports.nameToAlias = function(name, pkg) { if (hasLowerCaseAlias(pkg)) { return lower(name); } else { return name; } }; module.exports.DEFAULT_NS_MAP = { 'xsi': 'http://www.w3.org/2001/XMLSchema-instance' }; module.exports.XSI_TYPE = 'xsi:type'; },{}],53:[function(_dereq_,module,exports){ 'use strict'; var reduce = _dereq_(208), forEach = _dereq_(204), find = _dereq_(203), assign = _dereq_(325), defer = _dereq_(215); var Stack = _dereq_(56), SaxParser = _dereq_(55).parser, Moddle = _dereq_(57), parseNameNs = _dereq_(62).parseName, Types = _dereq_(65), coerceType = Types.coerceType, isSimpleType = Types.isSimple, common = _dereq_(52), XSI_TYPE = common.XSI_TYPE, XSI_URI = common.DEFAULT_NS_MAP.xsi, aliasToName = common.aliasToName; function parseNodeAttributes(node) { var nodeAttrs = node.attributes; return reduce(nodeAttrs, function(result, v, k) { var name, ns; if (!v.local) { name = v.prefix; } else { ns = parseNameNs(v.name, v.prefix); name = ns.name; } result[name] = v.value; return result; }, {}); } function normalizeType(node, attr, model) { var nameNs = parseNameNs(attr.value); var uri = node.ns[nameNs.prefix || ''], localName = nameNs.localName, pkg = uri && model.getPackage(uri), typePrefix; if (pkg) { typePrefix = pkg.xml && pkg.xml.typePrefix; if (typePrefix && localName.indexOf(typePrefix) === 0) { localName = localName.slice(typePrefix.length); } attr.value = pkg.prefix + ':' + localName; } } /** * Normalizes namespaces for a node given an optional default namespace and a * number of mappings from uris to default prefixes. * * @param {XmlNode} node * @param {Model} model the model containing all registered namespaces * @param {Uri} defaultNsUri */ function normalizeNamespaces(node, model, defaultNsUri) { var uri, prefix; uri = node.uri || defaultNsUri; if (uri) { var pkg = model.getPackage(uri); if (pkg) { prefix = pkg.prefix; } else { prefix = node.prefix; } node.prefix = prefix; node.uri = uri; } forEach(node.attributes, function(attr) { // normalize xsi:type attributes because the // assigned type may or may not be namespace prefixed if (attr.uri === XSI_URI && attr.local === 'type') { normalizeType(node, attr, model); } normalizeNamespaces(attr, model, null); }); } /** * A parse context. * * @class * * @param {Object} options * @param {ElementHandler} options.parseRoot the root handler for parsing a document * @param {boolean} [options.lax=false] whether or not to ignore invalid elements */ function Context(options) { /** * @property {ElementHandler} parseRoot */ /** * @property {Boolean} lax */ assign(this, options); var elementsById = this.elementsById = {}; var references = this.references = []; var warnings = this.warnings = []; this.addReference = function(reference) { references.push(reference); }; this.addElement = function(id, element) { if (!id || !element) { throw new Error('[xml-reader] id or ctx must not be null'); } elementsById[id] = element; }; this.addWarning = function (w) { warnings.push(w); }; } function BaseHandler() {} BaseHandler.prototype.handleEnd = function() {}; BaseHandler.prototype.handleText = function() {}; BaseHandler.prototype.handleNode = function() {}; /** * A simple pass through handler that does nothing except for * ignoring all input it receives. * * This is used to ignore unknown elements and * attributes. */ function NoopHandler() { } NoopHandler.prototype = new BaseHandler(); NoopHandler.prototype.handleNode = function() { return this; }; function BodyHandler() {} BodyHandler.prototype = new BaseHandler(); BodyHandler.prototype.handleText = function(text) { this.body = (this.body || '') + text; }; function ReferenceHandler(property, context) { this.property = property; this.context = context; } ReferenceHandler.prototype = new BodyHandler(); ReferenceHandler.prototype.handleNode = function(node) { if (this.element) { throw new Error('expected no sub nodes'); } else { this.element = this.createReference(node); } return this; }; ReferenceHandler.prototype.handleEnd = function() { this.element.id = this.body; }; ReferenceHandler.prototype.createReference = function() { return { property: this.property.ns.name, id: '' }; }; function ValueHandler(propertyDesc, element) { this.element = element; this.propertyDesc = propertyDesc; } ValueHandler.prototype = new BodyHandler(); ValueHandler.prototype.handleEnd = function() { var value = this.body, element = this.element, propertyDesc = this.propertyDesc; value = coerceType(propertyDesc.type, value); if (propertyDesc.isMany) { element.get(propertyDesc.name).push(value); } else { element.set(propertyDesc.name, value); } }; function BaseElementHandler() {} BaseElementHandler.prototype = Object.create(BodyHandler.prototype); BaseElementHandler.prototype.handleNode = function(node) { var parser = this, element = this.element, id; if (!element) { element = this.element = this.createElement(node); id = element.id; if (id) { this.context.addElement(id, element); } } else { parser = this.handleChild(node); } return parser; }; /** * @class XMLReader.ElementHandler * */ function ElementHandler(model, type, context) { this.model = model; this.type = model.getType(type); this.context = context; } ElementHandler.prototype = new BaseElementHandler(); ElementHandler.prototype.addReference = function(reference) { this.context.addReference(reference); }; ElementHandler.prototype.handleEnd = function() { var value = this.body, element = this.element, descriptor = element.$descriptor, bodyProperty = descriptor.bodyProperty; if (bodyProperty && value !== undefined) { value = coerceType(bodyProperty.type, value); element.set(bodyProperty.name, value); } }; /** * Create an instance of the model from the given node. * * @param {Element} node the xml node */ ElementHandler.prototype.createElement = function(node) { var attributes = parseNodeAttributes(node), Type = this.type, descriptor = Type.$descriptor, context = this.context, instance = new Type({}); forEach(attributes, function(value, name) { var prop = descriptor.propertiesByName[name]; if (prop && prop.isReference) { context.addReference({ element: instance, property: prop.ns.name, id: value }); } else { if (prop) { value = coerceType(prop.type, value); } instance.set(name, value); } }); return instance; }; ElementHandler.prototype.getPropertyForNode = function(node) { var nameNs = parseNameNs(node.local, node.prefix); var type = this.type, model = this.model, descriptor = type.$descriptor; var propertyName = nameNs.name, property = descriptor.propertiesByName[propertyName], elementTypeName, elementType, typeAnnotation; // search for properties by name first if (property) { if (property.serialize === XSI_TYPE) { typeAnnotation = node.attributes[XSI_TYPE]; // xsi type is optional, if it does not exists the // default type is assumed if (typeAnnotation) { elementTypeName = typeAnnotation.value; // TODO: extract real name from attribute elementType = model.getType(elementTypeName); return assign({}, property, { effectiveType: elementType.$descriptor.name }); } } // search for properties by name first return property; } var pkg = model.getPackage(nameNs.prefix); if (pkg) { elementTypeName = nameNs.prefix + ':' + aliasToName(nameNs.localName, descriptor.$pkg); elementType = model.getType(elementTypeName); // search for collection members later property = find(descriptor.properties, function(p) { return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type); }); if (property) { return assign({}, property, { effectiveType: elementType.$descriptor.name }); } } else { // parse unknown element (maybe extension) property = find(descriptor.properties, function(p) { return !p.isReference && !p.isAttribute && p.type === 'Element'; }); if (property) { return property; } } throw new Error('unrecognized element <' + nameNs.name + '>'); }; ElementHandler.prototype.toString = function() { return 'ElementDescriptor[' + this.type.$descriptor.name + ']'; }; ElementHandler.prototype.valueHandler = function(propertyDesc, element) { return new ValueHandler(propertyDesc, element); }; ElementHandler.prototype.referenceHandler = function(propertyDesc) { return new ReferenceHandler(propertyDesc, this.context); }; ElementHandler.prototype.handler = function(type) { if (type === 'Element') { return new GenericElementHandler(this.model, type, this.context); } else { return new ElementHandler(this.model, type, this.context); } }; /** * Handle the child element parsing * * @param {Element} node the xml node */ ElementHandler.prototype.handleChild = function(node) { var propertyDesc, type, element, childHandler; propertyDesc = this.getPropertyForNode(node); element = this.element; type = propertyDesc.effectiveType || propertyDesc.type; if (isSimpleType(type)) { return this.valueHandler(propertyDesc, element); } if (propertyDesc.isReference) { childHandler = this.referenceHandler(propertyDesc).handleNode(node); } else { childHandler = this.handler(type).handleNode(node); } var newElement = childHandler.element; // child handles may decide to skip elements // by not returning anything if (newElement !== undefined) { if (propertyDesc.isMany) { element.get(propertyDesc.name).push(newElement); } else { element.set(propertyDesc.name, newElement); } if (propertyDesc.isReference) { assign(newElement, { element: element }); this.context.addReference(newElement); } else { // establish child -> parent relationship newElement.$parent = element; } } return childHandler; }; function GenericElementHandler(model, type, context) { this.model = model; this.context = context; } GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype); GenericElementHandler.prototype.createElement = function(node) { var name = node.name, prefix = node.prefix, uri = node.ns[prefix], attributes = node.attributes; return this.model.createAny(name, uri, attributes); }; GenericElementHandler.prototype.handleChild = function(node) { var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node), element = this.element; var newElement = handler.element, children; if (newElement !== undefined) { children = element.$children = element.$children || []; children.push(newElement); // establish child -> parent relationship newElement.$parent = element; } return handler; }; GenericElementHandler.prototype.handleText = function(text) { this.body = this.body || '' + text; }; GenericElementHandler.prototype.handleEnd = function() { if (this.body) { this.element.$body = this.body; } }; /** * A reader for a meta-model * * @param {Object} options * @param {Model} options.model used to read xml files * @param {Boolean} options.lax whether to make parse errors warnings */ function XMLReader(options) { if (options instanceof Moddle) { options = { model: options }; } assign(this, { lax: false }, options); } XMLReader.prototype.fromXML = function(xml, rootHandler, done) { var model = this.model, lax = this.lax, context = new Context({ parseRoot: rootHandler }); var parser = new SaxParser(true, { xmlns: true, trim: true }), stack = new Stack(); rootHandler.context = context; // push root handler stack.push(rootHandler); function resolveReferences() { var elementsById = context.elementsById; var references = context.references; var i, r; for (i = 0; !!(r = references[i]); i++) { var element = r.element; var reference = elementsById[r.id]; var property = element.$descriptor.propertiesByName[r.property]; if (!reference) { context.addWarning({ message: 'unresolved reference <' + r.id + '>', element: r.element, property: r.property, value: r.id }); } if (property.isMany) { var collection = element.get(property.name), idx = collection.indexOf(r); if (!reference) { // remove unresolvable reference collection.splice(idx, 1); } else { // update reference collection[idx] = reference; } } else { element.set(property.name, reference); } } } function handleClose(tagName) { stack.pop().handleEnd(); } function handleOpen(node) { var handler = stack.peek(); normalizeNamespaces(node, model); try { stack.push(handler.handleNode(node)); } catch (e) { var line = this.line, column = this.column; var message = 'unparsable content <' + node.name + '> detected\n\t' + 'line: ' + line + '\n\t' + 'column: ' + column + '\n\t' + 'nested error: ' + e.message; if (lax) { context.addWarning({ message: message, error: e }); console.warn('could not parse node'); console.warn(e); stack.push(new NoopHandler()); } else { console.error('could not parse document'); console.error(e); throw new Error(message); } } } function handleText(text) { stack.peek().handleText(text); } parser.onopentag = handleOpen; parser.oncdata = parser.ontext = handleText; parser.onclosetag = handleClose; parser.onend = resolveReferences; // deferred parse XML to make loading really ascnchronous // this ensures the execution environment (node or browser) // is kept responsive and that certain optimization strategies // can kick in defer(function() { var error; try { parser.write(xml).close(); } catch (e) { error = e; } done(error, error ? undefined : rootHandler.element, context); }); }; XMLReader.prototype.handler = function(name) { return new ElementHandler(this.model, name); }; module.exports = XMLReader; module.exports.ElementHandler = ElementHandler; },{"203":203,"204":204,"208":208,"215":215,"325":325,"52":52,"55":55,"56":56,"57":57,"62":62,"65":65}],54:[function(_dereq_,module,exports){ 'use strict'; var map = _dereq_(207), forEach = _dereq_(204), isString = _dereq_(322), filter = _dereq_(202), assign = _dereq_(325); var Types = _dereq_(65), parseNameNs = _dereq_(62).parseName, common = _dereq_(52), nameToAlias = common.nameToAlias; var XML_PREAMBLE = '\n', ESCAPE_CHARS = /(<|>|'|"|&|\n\r|\n)/g, DEFAULT_NS_MAP = common.DEFAULT_NS_MAP, XSI_TYPE = common.XSI_TYPE; function nsName(ns) { if (isString(ns)) { return ns; } else { return (ns.prefix ? ns.prefix + ':' : '') + ns.localName; } } function getElementNs(ns, descriptor) { if (descriptor.isGeneric) { return descriptor.name; } else { return assign({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns); } } function getPropertyNs(ns, descriptor) { return assign({ localName: descriptor.ns.localName }, ns); } function getSerializableProperties(element) { var descriptor = element.$descriptor; return filter(descriptor.properties, function(p) { var name = p.name; // do not serialize defaults if (!element.hasOwnProperty(name)) { return false; } var value = element[name]; // do not serialize default equals if (value === p.default) { return false; } return p.isMany ? value.length : true; }); } var ESCAPE_MAP = { '\n': '10', '\n\r': '10', '"': '34', '\'': '39', '<': '60', '>': '62', '&': '38' }; /** * Escape a string attribute to not contain any bad values (line breaks, '"', ...) * * @param {String} str the string to escape * @return {String} the escaped string */ function escapeAttr(str) { // ensure we are handling strings here str = isString(str) ? str : '' + str; return str.replace(ESCAPE_CHARS, function(str) { return '&#' + ESCAPE_MAP[str] + ';'; }); } function filterAttributes(props) { return filter(props, function(p) { return p.isAttr; }); } function filterContained(props) { return filter(props, function(p) { return !p.isAttr; }); } function ReferenceSerializer(parent, ns) { this.ns = ns; } ReferenceSerializer.prototype.build = function(element) { this.element = element; return this; }; ReferenceSerializer.prototype.serializeTo = function(writer) { writer .appendIndent() .append('<' + nsName(this.ns) + '>' + this.element.id + '') .appendNewLine(); }; function BodySerializer() {} BodySerializer.prototype.serializeValue = BodySerializer.prototype.serializeTo = function(writer) { var escape = this.escape; if (escape) { writer.append(''); } }; BodySerializer.prototype.build = function(prop, value) { this.value = value; if (prop.type === 'String' && ESCAPE_CHARS.test(value)) { this.escape = true; } return this; }; function ValueSerializer(ns) { this.ns = ns; } ValueSerializer.prototype = new BodySerializer(); ValueSerializer.prototype.serializeTo = function(writer) { writer .appendIndent() .append('<' + nsName(this.ns) + '>'); this.serializeValue(writer); writer .append( '') .appendNewLine(); }; function ElementSerializer(parent, ns) { this.body = []; this.attrs = []; this.parent = parent; this.ns = ns; } ElementSerializer.prototype.build = function(element) { this.element = element; var otherAttrs = this.parseNsAttributes(element); if (!this.ns) { this.ns = this.nsTagName(element.$descriptor); } if (element.$descriptor.isGeneric) { this.parseGeneric(element); } else { var properties = getSerializableProperties(element); this.parseAttributes(filterAttributes(properties)); this.parseContainments(filterContained(properties)); this.parseGenericAttributes(element, otherAttrs); } return this; }; ElementSerializer.prototype.nsTagName = function(descriptor) { var effectiveNs = this.logNamespaceUsed(descriptor.ns); return getElementNs(effectiveNs, descriptor); }; ElementSerializer.prototype.nsPropertyTagName = function(descriptor) { var effectiveNs = this.logNamespaceUsed(descriptor.ns); return getPropertyNs(effectiveNs, descriptor); }; ElementSerializer.prototype.isLocalNs = function(ns) { return ns.uri === this.ns.uri; }; ElementSerializer.prototype.nsAttributeName = function(element) { var ns; if (isString(element)) { ns = parseNameNs(element); } else if (element.ns) { ns = element.ns; } var effectiveNs = this.logNamespaceUsed(ns); // strip prefix if same namespace like parent if (this.isLocalNs(effectiveNs)) { return { localName: ns.localName }; } else { return assign({ localName: ns.localName }, effectiveNs); } }; ElementSerializer.prototype.parseGeneric = function(element) { var self = this, body = this.body, attrs = this.attrs; forEach(element, function(val, key) { if (key === '$body') { body.push(new BodySerializer().build({ type: 'String' }, val)); } else if (key === '$children') { forEach(val, function(child) { body.push(new ElementSerializer(self).build(child)); }); } else if (key.indexOf('$') !== 0) { attrs.push({ name: key, value: escapeAttr(val) }); } }); }; /** * Parse namespaces and return a list of left over generic attributes * * @param {Object} element * @return {Array} */ ElementSerializer.prototype.parseNsAttributes = function(element) { var self = this; var genericAttrs = element.$attrs; var attributes = []; // parse namespace attributes first // and log them. push non namespace attributes to a list // and process them later forEach(genericAttrs, function(value, name) { var nameNs = parseNameNs(name); if (nameNs.prefix === 'xmlns') { self.logNamespace({ prefix: nameNs.localName, uri: value }); } else if (!nameNs.prefix && nameNs.localName === 'xmlns') { self.logNamespace({ uri: value }); } else { attributes.push({ name: name, value: value }); } }); return attributes; }; ElementSerializer.prototype.parseGenericAttributes = function(element, attributes) { var self = this; forEach(attributes, function(attr) { // do not serialize xsi:type attribute // it is set manually based on the actual implementation type if (attr.name === XSI_TYPE) { return; } try { self.addAttribute(self.nsAttributeName(attr.name), attr.value); } catch (e) { console.warn('[writer] missing namespace information for ', attr.name, '=', attr.value, 'on', element, e); } }); }; ElementSerializer.prototype.parseContainments = function(properties) { var self = this, body = this.body, element = this.element; forEach(properties, function(p) { var value = element.get(p.name), isReference = p.isReference, isMany = p.isMany; var ns = self.nsPropertyTagName(p); if (!isMany) { value = [ value ]; } if (p.isBody) { body.push(new BodySerializer().build(p, value[0])); } else if (Types.isSimple(p.type)) { forEach(value, function(v) { body.push(new ValueSerializer(ns).build(p, v)); }); } else if (isReference) { forEach(value, function(v) { body.push(new ReferenceSerializer(self, ns).build(v)); }); } else { // allow serialization via type // rather than element name var asType = p.serialize === XSI_TYPE; forEach(value, function(v) { var serializer; if (asType) { serializer = new TypeSerializer(self, ns); } else { serializer = new ElementSerializer(self); } body.push(serializer.build(v)); }); } }); }; ElementSerializer.prototype.getNamespaces = function() { if (!this.parent) { if (!this.namespaces) { this.namespaces = { prefixMap: {}, uriMap: {}, used: {} }; } } else { this.namespaces = this.parent.getNamespaces(); } return this.namespaces; }; ElementSerializer.prototype.logNamespace = function(ns) { var namespaces = this.getNamespaces(); var existing = namespaces.uriMap[ns.uri]; if (!existing) { namespaces.uriMap[ns.uri] = ns; } namespaces.prefixMap[ns.prefix] = ns.uri; return ns; }; ElementSerializer.prototype.logNamespaceUsed = function(ns) { var element = this.element, model = element.$model, namespaces = this.getNamespaces(); // ns may be // // * prefix only // * prefix:uri var prefix = ns.prefix; var uri = ns.uri || DEFAULT_NS_MAP[prefix] || namespaces.prefixMap[prefix] || (model ? (model.getPackage(prefix) || {}).uri : null); if (!uri) { throw new Error('no namespace uri given for prefix <' + ns.prefix + '>'); } ns = namespaces.uriMap[uri]; if (!ns) { ns = this.logNamespace({ prefix: prefix, uri: uri }); } if (!namespaces.used[ns.uri]) { namespaces.used[ns.uri] = ns; } return ns; }; ElementSerializer.prototype.parseAttributes = function(properties) { var self = this, element = this.element; forEach(properties, function(p) { self.logNamespaceUsed(p.ns); var value = element.get(p.name); if (p.isReference) { value = value.id; } self.addAttribute(self.nsAttributeName(p), value); }); }; ElementSerializer.prototype.addAttribute = function(name, value) { var attrs = this.attrs; if (isString(value)) { value = escapeAttr(value); } attrs.push({ name: name, value: value }); }; ElementSerializer.prototype.serializeAttributes = function(writer) { var attrs = this.attrs, root = !this.parent, namespaces = this.namespaces; function collectNsAttrs() { return map(namespaces.used, function(ns) { var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : ''); return { name: name, value: ns.uri }; }); } if (root) { attrs = collectNsAttrs().concat(attrs); } forEach(attrs, function(a) { writer .append(' ') .append(nsName(a.name)).append('="').append(a.value).append('"'); }); }; ElementSerializer.prototype.serializeTo = function(writer) { var hasBody = this.body.length, indent = !(this.body.length === 1 && this.body[0] instanceof BodySerializer); writer .appendIndent() .append('<' + nsName(this.ns)); this.serializeAttributes(writer); writer.append(hasBody ? '>' : ' />'); if (hasBody) { if (indent) { writer .appendNewLine() .indent(); } forEach(this.body, function(b) { b.serializeTo(writer); }); if (indent) { writer .unindent() .appendIndent(); } writer.append(''); } writer.appendNewLine(); }; /** * A serializer for types that handles serialization of data types */ function TypeSerializer(parent, ns) { ElementSerializer.call(this, parent, ns); } TypeSerializer.prototype = new ElementSerializer(); TypeSerializer.prototype.build = function(element) { var descriptor = element.$descriptor; this.element = element; this.typeNs = this.nsTagName(descriptor); // add xsi:type attribute to represent the elements // actual type var typeNs = this.typeNs, pkg = element.$model.getPackage(typeNs.uri), typePrefix = (pkg.xml && pkg.xml.typePrefix) || ''; this.addAttribute(this.nsAttributeName(XSI_TYPE), (typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName); // do the usual stuff return ElementSerializer.prototype.build.call(this, element); }; TypeSerializer.prototype.isLocalNs = function(ns) { return ns.uri === this.typeNs.uri; }; function SavingWriter() { this.value = ''; this.write = function(str) { this.value += str; }; } function FormatingWriter(out, format) { var indent = ['']; this.append = function(str) { out.write(str); return this; }; this.appendNewLine = function() { if (format) { out.write('\n'); } return this; }; this.appendIndent = function() { if (format) { out.write(indent.join(' ')); } return this; }; this.indent = function() { indent.push(''); return this; }; this.unindent = function() { indent.pop(); return this; }; } /** * A writer for meta-model backed document trees * * @param {Object} options output options to pass into the writer */ function XMLWriter(options) { options = assign({ format: false, preamble: true }, options || {}); function toXML(tree, writer) { var internalWriter = writer || new SavingWriter(); var formatingWriter = new FormatingWriter(internalWriter, options.format); if (options.preamble) { formatingWriter.append(XML_PREAMBLE); } new ElementSerializer().build(tree).serializeTo(formatingWriter); if (!writer) { return internalWriter.value; } } return { toXML: toXML }; } module.exports = XMLWriter; },{"202":202,"204":204,"207":207,"322":322,"325":325,"52":52,"62":62,"65":65}],55:[function(_dereq_,module,exports){ (function (Buffer){ // wrapper for non-node envs ;(function (sax) { sax.parser = function (strict, opt) { return new SAXParser(strict, opt) } sax.SAXParser = SAXParser sax.SAXStream = SAXStream sax.createStream = createStream // When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns. // When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)), // since that's the earliest that a buffer overrun could occur. This way, checks are // as rare as required, but as often as necessary to ensure never crossing this bound. // Furthermore, buffers are only tested at most once per write(), so passing a very // large string into write() might have undesirable effects, but this is manageable by // the caller, so it is assumed to be safe. Thus, a call to write() may, in the extreme // edge case, result in creating at most one complete copy of the string passed in. // Set to Infinity to have unlimited buffers. sax.MAX_BUFFER_LENGTH = 64 * 1024 var buffers = [ "comment", "sgmlDecl", "textNode", "tagName", "doctype", "procInstName", "procInstBody", "entity", "attribName", "attribValue", "cdata", "script" ] sax.EVENTS = // for discoverability. [ "text" , "processinginstruction" , "sgmldeclaration" , "doctype" , "comment" , "attribute" , "opentag" , "closetag" , "opencdata" , "cdata" , "closecdata" , "error" , "end" , "ready" , "script" , "opennamespace" , "closenamespace" ] function SAXParser (strict, opt) { if (!(this instanceof SAXParser)) return new SAXParser(strict, opt) var parser = this clearBuffers(parser) parser.q = parser.c = "" parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH parser.opt = opt || {} parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags parser.looseCase = parser.opt.lowercase ? "toLowerCase" : "toUpperCase" parser.tags = [] parser.closed = parser.closedRoot = parser.sawRoot = false parser.tag = parser.error = null parser.strict = !!strict parser.noscript = !!(strict || parser.opt.noscript) parser.state = S.BEGIN parser.ENTITIES = Object.create(sax.ENTITIES) parser.attribList = [] // namespaces form a prototype chain. // it always points at the current tag, // which protos to its parent tag. if (parser.opt.xmlns) parser.ns = Object.create(rootNS) // mostly just for error reporting parser.trackPosition = parser.opt.position !== false if (parser.trackPosition) { parser.position = parser.line = parser.column = 0 } emit(parser, "onready") } if (!Object.create) Object.create = function (o) { function f () { this.__proto__ = o } f.prototype = o return new f } if (!Object.getPrototypeOf) Object.getPrototypeOf = function (o) { return o.__proto__ } if (!Object.keys) Object.keys = function (o) { var a = [] for (var i in o) if (o.hasOwnProperty(i)) a.push(i) return a } function checkBufferLength (parser) { var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10) , maxActual = 0 for (var i = 0, l = buffers.length; i < l; i ++) { var len = parser[buffers[i]].length if (len > maxAllowed) { // Text/cdata nodes can get big, and since they're buffered, // we can get here under normal conditions. // Avoid issues by emitting the text node now, // so at least it won't get any bigger. switch (buffers[i]) { case "textNode": closeText(parser) break case "cdata": emitNode(parser, "oncdata", parser.cdata) parser.cdata = "" break case "script": emitNode(parser, "onscript", parser.script) parser.script = "" break default: error(parser, "Max buffer length exceeded: "+buffers[i]) } } maxActual = Math.max(maxActual, len) } // schedule the next check for the earliest possible buffer overrun. parser.bufferCheckPosition = (sax.MAX_BUFFER_LENGTH - maxActual) + parser.position } function clearBuffers (parser) { for (var i = 0, l = buffers.length; i < l; i ++) { parser[buffers[i]] = "" } } function flushBuffers (parser) { closeText(parser) if (parser.cdata !== "") { emitNode(parser, "oncdata", parser.cdata) parser.cdata = "" } if (parser.script !== "") { emitNode(parser, "onscript", parser.script) parser.script = "" } } SAXParser.prototype = { end: function () { end(this) } , write: write , resume: function () { this.error = null; return this } , close: function () { return this.write(null) } , flush: function () { flushBuffers(this) } } try { var Stream = _dereq_("stream").Stream } catch (ex) { var Stream = function () {} } var streamWraps = sax.EVENTS.filter(function (ev) { return ev !== "error" && ev !== "end" }) function createStream (strict, opt) { return new SAXStream(strict, opt) } function SAXStream (strict, opt) { if (!(this instanceof SAXStream)) return new SAXStream(strict, opt) Stream.apply(this) this._parser = new SAXParser(strict, opt) this.writable = true this.readable = true var me = this this._parser.onend = function () { me.emit("end") } this._parser.onerror = function (er) { me.emit("error", er) // if didn't throw, then means error was handled. // go ahead and clear error, so we can write again. me._parser.error = null } this._decoder = null; streamWraps.forEach(function (ev) { Object.defineProperty(me, "on" + ev, { get: function () { return me._parser["on" + ev] }, set: function (h) { if (!h) { me.removeAllListeners(ev) return me._parser["on"+ev] = h } me.on(ev, h) }, enumerable: true, configurable: false }) }) } SAXStream.prototype = Object.create(Stream.prototype, { constructor: { value: SAXStream } }) SAXStream.prototype.write = function (data) { if (typeof Buffer === 'function' && typeof Buffer.isBuffer === 'function' && Buffer.isBuffer(data)) { if (!this._decoder) { var SD = _dereq_('string_decoder').StringDecoder this._decoder = new SD('utf8') } data = this._decoder.write(data); } this._parser.write(data.toString()) this.emit("data", data) return true } SAXStream.prototype.end = function (chunk) { if (chunk && chunk.length) this.write(chunk) this._parser.end() return true } SAXStream.prototype.on = function (ev, handler) { var me = this if (!me._parser["on"+ev] && streamWraps.indexOf(ev) !== -1) { me._parser["on"+ev] = function () { var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments) args.splice(0, 0, ev) me.emit.apply(me, args) } } return Stream.prototype.on.call(me, ev, handler) } // character classes and tokens var whitespace = "\r\n\t " // this really needs to be replaced with character classes. // XML allows all manner of ridiculous numbers and digits. , number = "0124356789" , letter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // (Letter | "_" | ":") , quote = "'\"" , entity = number+letter+"#" , attribEnd = whitespace + ">" , CDATA = "[CDATA[" , DOCTYPE = "DOCTYPE" , XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace" , XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/" , rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE } // turn all the string character sets into character class objects. whitespace = charClass(whitespace) number = charClass(number) letter = charClass(letter) // http://www.w3.org/TR/REC-xml/#NT-NameStartChar // This implementation works on strings, a single character at a time // as such, it cannot ever support astral-plane characters (10000-EFFFF) // without a significant breaking change to either this parser, or the // JavaScript language. Implementation of an emoji-capable xml parser // is left as an exercise for the reader. var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/ var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040\.\d-]/ quote = charClass(quote) entity = charClass(entity) attribEnd = charClass(attribEnd) function charClass (str) { return str.split("").reduce(function (s, c) { s[c] = true return s }, {}) } function isRegExp (c) { return Object.prototype.toString.call(c) === '[object RegExp]' } function is (charclass, c) { return isRegExp(charclass) ? !!c.match(charclass) : charclass[c] } function not (charclass, c) { return !is(charclass, c) } var S = 0 sax.STATE = { BEGIN : S++ , TEXT : S++ // general stuff , TEXT_ENTITY : S++ // & and such. , OPEN_WAKA : S++ // < , SGML_DECL : S++ // , SCRIPT : S++ //