/*! * bpmn-js - bpmn-navigated-viewer 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]+)> 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_(56), _dereq_(52) ]; module.exports = Viewer; },{"15":15,"169":169,"172":172,"175":175,"179":179,"190":190,"192":192,"193":193,"3":3,"36":36,"52":52,"56":56,"9":9}],3:[function(_dereq_,module,exports){ module.exports = { __depends__: [ _dereq_(6), _dereq_(11) ] }; },{"11":11,"6":6}],4:[function(_dereq_,module,exports){ 'use strict'; var inherits = _dereq_(79), isArray = _dereq_(166), isObject = _dereq_(170), assign = _dereq_(175), forEach = _dereq_(84), every = _dereq_(81), includes = _dereq_(86), some = _dereq_(89); var DefaultRenderer = _dereq_(44), TextUtil = _dereq_(71), DiUtil = _dereq_(12); 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; },{"12":12,"166":166,"170":170,"175":175,"44":44,"71":71,"79":79,"81":81,"84":84,"86":86,"89":89}],5:[function(_dereq_,module,exports){ 'use strict'; var Snap = _dereq_(74); /** * 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; },{"74":74}],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_(175), map = _dereq_(87); var LabelUtil = _dereq_(13); var hasExternalLabel = LabelUtil.hasExternalLabel, getExternalLabelBounds = LabelUtil.getExternalLabelBounds, isExpanded = _dereq_(12).isExpanded, elementToString = _dereq_(10).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); }; },{"10":10,"12":12,"13":13,"175":175,"87":87}],8:[function(_dereq_,module,exports){ 'use strict'; var filter = _dereq_(82), find = _dereq_(83), forEach = _dereq_(84); var Refs = _dereq_(202); var elementToString = _dereq_(10).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; },{"10":10,"202":202,"82":82,"83":83,"84":84}],9:[function(_dereq_,module,exports){ 'use strict'; var BpmnTreeWalker = _dereq_(8); /** * 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; },{"8":8}],10:[function(_dereq_,module,exports){ 'use strict'; module.exports.elementToString = function(e) { if (!e) { return ''; } return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />'; }; },{}],11:[function(_dereq_,module,exports){ module.exports = { bpmnImporter: [ 'type', _dereq_(7) ] }; },{"7":7}],12:[function(_dereq_,module,exports){ 'use strict'; var is = _dereq_(14).is, getBusinessObject = _dereq_(14).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; }; },{"14":14}],13:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(175); 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); }; },{"175":175}],14:[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; },{}],15:[function(_dereq_,module,exports){ module.exports = _dereq_(17); },{"17":17}],16:[function(_dereq_,module,exports){ 'use strict'; var isString = _dereq_(172), isFunction = _dereq_(167), assign = _dereq_(175); var Moddle = _dereq_(23), XmlReader = _dereq_(19), XmlWriter = _dereq_(20); /** * 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); } }; },{"167":167,"172":172,"175":175,"19":19,"20":20,"23":23}],17:[function(_dereq_,module,exports){ 'use strict'; var assign = _dereq_(175); var BpmnModdle = _dereq_(16); var packages = { bpmn: _dereq_(32), bpmndi: _dereq_(33), dc: _dereq_(34), di: _dereq_(35) }; module.exports = function(additionalPackages, options) { return new BpmnModdle(assign({}, packages, additionalPackages), options); }; },{"16":16,"175":175,"32":32,"33":33,"34":34,"35":35}],18:[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'; },{}],19:[function(_dereq_,module,exports){ 'use strict'; var reduce = _dereq_(88), forEach = _dereq_(84), find = _dereq_(83), assign = _dereq_(175), defer = _dereq_(92); var Stack = _dereq_(22), SaxParser = _dereq_(21).parser, Moddle = _dereq_(23), parseNameNs = _dereq_(28).parseName, Types = _dereq_(31), coerceType = Types.coerceType, isSimpleType = Types.isSimple, common = _dereq_(18), 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; },{"175":175,"18":18,"21":21,"22":22,"23":23,"28":28,"31":31,"83":83,"84":84,"88":88,"92":92}],20:[function(_dereq_,module,exports){ 'use strict'; var map = _dereq_(87), forEach = _dereq_(84), isString = _dereq_(172), filter = _dereq_(82), assign = _dereq_(175); var Types = _dereq_(31), parseNameNs = _dereq_(28).parseName, common = _dereq_(18), 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; },{"172":172,"175":175,"18":18,"28":28,"31":31,"82":82,"84":84,"87":87}],21:[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++ //