1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | import {
|
8 | assign,
|
9 | find,
|
10 | isFunction,
|
11 | isNumber,
|
12 | omit
|
13 | } from 'min-dash';
|
14 |
|
15 | import {
|
16 | domify,
|
17 | query as domQuery,
|
18 | remove as domRemove
|
19 | } from 'min-dom';
|
20 |
|
21 | import {
|
22 | innerSVG
|
23 | } from 'tiny-svg';
|
24 |
|
25 | import Diagram from 'diagram-js';
|
26 | import BpmnModdle from 'bpmn-moddle';
|
27 |
|
28 | import inherits from 'inherits';
|
29 |
|
30 | import {
|
31 | importBpmnDiagram
|
32 | } from './import/Importer';
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | export default function BaseViewer(options) {
|
50 |
|
51 | options = assign({}, DEFAULT_OPTIONS, options);
|
52 |
|
53 | this._moddle = this._createModdle(options);
|
54 |
|
55 | this._container = this._createContainer(options);
|
56 |
|
57 |
|
58 |
|
59 | addProjectLogo(this._container);
|
60 |
|
61 |
|
62 |
|
63 | this._init(this._container, this._moddle, options);
|
64 | }
|
65 |
|
66 | inherits(BaseViewer, Diagram);
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | BaseViewer.prototype.importXML = function(xml, bpmnDiagram, done) {
|
92 |
|
93 | if (isFunction(bpmnDiagram)) {
|
94 | done = bpmnDiagram;
|
95 | bpmnDiagram = null;
|
96 | }
|
97 |
|
98 |
|
99 | done = done || function() {};
|
100 |
|
101 | var self = this;
|
102 |
|
103 |
|
104 |
|
105 | xml = this._emit('import.parse.start', { xml: xml }) || xml;
|
106 |
|
107 | this._moddle.fromXML(xml, 'bpmn:Definitions', function(err, definitions, context) {
|
108 |
|
109 |
|
110 |
|
111 | definitions = self._emit('import.parse.complete', {
|
112 | error: err,
|
113 | definitions: definitions,
|
114 | context: context
|
115 | }) || definitions;
|
116 |
|
117 | var parseWarnings = context.warnings;
|
118 |
|
119 | if (err) {
|
120 | err = checkValidationError(err);
|
121 |
|
122 | self._emit('import.done', { error: err, warnings: parseWarnings });
|
123 |
|
124 | return done(err, parseWarnings);
|
125 | }
|
126 |
|
127 | self.importDefinitions(definitions, bpmnDiagram, function(err, importWarnings) {
|
128 | var allWarnings = [].concat(parseWarnings, importWarnings || []);
|
129 |
|
130 | self._emit('import.done', { error: err, warnings: allWarnings });
|
131 |
|
132 | done(err, allWarnings);
|
133 | });
|
134 | });
|
135 | };
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 | BaseViewer.prototype.importDefinitions = function(definitions, bpmnDiagram, done) {
|
157 |
|
158 | if (isFunction(bpmnDiagram)) {
|
159 | done = bpmnDiagram;
|
160 | bpmnDiagram = null;
|
161 | }
|
162 |
|
163 |
|
164 | done = done || function() {};
|
165 |
|
166 | this._setDefinitions(definitions);
|
167 |
|
168 | return this.open(bpmnDiagram, done);
|
169 | };
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 | BaseViewer.prototype.open = function(bpmnDiagramOrId, done) {
|
190 |
|
191 | if (isFunction(bpmnDiagramOrId)) {
|
192 | done = bpmnDiagramOrId;
|
193 | bpmnDiagramOrId = null;
|
194 | }
|
195 |
|
196 | var definitions = this._definitions;
|
197 | var bpmnDiagram = bpmnDiagramOrId;
|
198 |
|
199 |
|
200 | done = done || function() {};
|
201 |
|
202 | if (!definitions) {
|
203 | return done(new Error('no XML imported'));
|
204 | }
|
205 |
|
206 | if (typeof bpmnDiagramOrId === 'string') {
|
207 | bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
|
208 |
|
209 | if (!bpmnDiagram) {
|
210 | return done(new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found'));
|
211 | }
|
212 | }
|
213 |
|
214 |
|
215 |
|
216 | try {
|
217 | this.clear();
|
218 | } catch (error) {
|
219 | return done(error);
|
220 | }
|
221 |
|
222 |
|
223 | return importBpmnDiagram(this, definitions, bpmnDiagram, done);
|
224 | };
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 | BaseViewer.prototype.saveXML = function(options, done) {
|
247 |
|
248 | if (!done) {
|
249 | done = options;
|
250 | options = {};
|
251 | }
|
252 |
|
253 | var self = this;
|
254 |
|
255 | var definitions = this._definitions;
|
256 |
|
257 | if (!definitions) {
|
258 | return done(new Error('no definitions loaded'));
|
259 | }
|
260 |
|
261 |
|
262 | definitions = this._emit('saveXML.start', {
|
263 | definitions: definitions
|
264 | }) || definitions;
|
265 |
|
266 | this._moddle.toXML(definitions, options, function(err, xml) {
|
267 |
|
268 | try {
|
269 | xml = self._emit('saveXML.serialized', {
|
270 | error: err,
|
271 | xml: xml
|
272 | }) || xml;
|
273 |
|
274 | self._emit('saveXML.done', {
|
275 | error: err,
|
276 | xml: xml
|
277 | });
|
278 | } catch (e) {
|
279 | console.error('error in saveXML life-cycle listener', e);
|
280 | }
|
281 |
|
282 | done(err, xml);
|
283 | });
|
284 | };
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 | BaseViewer.prototype.saveSVG = function(options, done) {
|
303 |
|
304 | if (!done) {
|
305 | done = options;
|
306 | options = {};
|
307 | }
|
308 |
|
309 | this._emit('saveSVG.start');
|
310 |
|
311 | var svg, err;
|
312 |
|
313 | try {
|
314 | var canvas = this.get('canvas');
|
315 |
|
316 | var contentNode = canvas.getDefaultLayer(),
|
317 | defsNode = domQuery('defs', canvas._svg);
|
318 |
|
319 | var contents = innerSVG(contentNode),
|
320 | defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
|
321 |
|
322 | var bbox = contentNode.getBBox();
|
323 |
|
324 | svg =
|
325 | '<?xml version="1.0" encoding="utf-8"?>\n' +
|
326 | '<!-- created with bpmn-js / http://bpmn.io -->\n' +
|
327 | '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
|
328 | '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
|
329 | 'width="' + bbox.width + '" height="' + bbox.height + '" ' +
|
330 | 'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
|
331 | defs + contents +
|
332 | '</svg>';
|
333 | } catch (e) {
|
334 | err = e;
|
335 | }
|
336 |
|
337 | this._emit('saveSVG.done', {
|
338 | error: err,
|
339 | svg: svg
|
340 | });
|
341 |
|
342 | done(err, svg);
|
343 | };
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 |
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 |
|
377 | BaseViewer.prototype._setDefinitions = function(definitions) {
|
378 | this._definitions = definitions;
|
379 | };
|
380 |
|
381 | BaseViewer.prototype.getModules = function() {
|
382 | return this._modules;
|
383 | };
|
384 |
|
385 |
|
386 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 | BaseViewer.prototype.clear = function() {
|
394 | if (!this.getDefinitions()) {
|
395 |
|
396 |
|
397 | return;
|
398 | }
|
399 |
|
400 |
|
401 |
|
402 |
|
403 |
|
404 |
|
405 | this.get('elementRegistry').forEach(function(element) {
|
406 | var bo = element.businessObject;
|
407 |
|
408 | if (bo && bo.di) {
|
409 | delete bo.di;
|
410 | }
|
411 | });
|
412 |
|
413 |
|
414 | Diagram.prototype.clear.call(this);
|
415 | };
|
416 |
|
417 |
|
418 |
|
419 |
|
420 |
|
421 | BaseViewer.prototype.destroy = function() {
|
422 |
|
423 |
|
424 | Diagram.prototype.destroy.call(this);
|
425 |
|
426 |
|
427 | domRemove(this._container);
|
428 | };
|
429 |
|
430 |
|
431 |
|
432 |
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 |
|
439 |
|
440 | BaseViewer.prototype.on = function(event, priority, callback, target) {
|
441 | return this.get('eventBus').on(event, priority, callback, target);
|
442 | };
|
443 |
|
444 |
|
445 |
|
446 |
|
447 |
|
448 |
|
449 |
|
450 | BaseViewer.prototype.off = function(event, callback) {
|
451 | this.get('eventBus').off(event, callback);
|
452 | };
|
453 |
|
454 | BaseViewer.prototype.attachTo = function(parentNode) {
|
455 |
|
456 | if (!parentNode) {
|
457 | throw new Error('parentNode required');
|
458 | }
|
459 |
|
460 |
|
461 |
|
462 | this.detach();
|
463 |
|
464 |
|
465 | if (parentNode.get && parentNode.constructor.prototype.jquery) {
|
466 | parentNode = parentNode.get(0);
|
467 | }
|
468 |
|
469 | if (typeof parentNode === 'string') {
|
470 | parentNode = domQuery(parentNode);
|
471 | }
|
472 |
|
473 | parentNode.appendChild(this._container);
|
474 |
|
475 | this._emit('attach', {});
|
476 |
|
477 | this.get('canvas').resized();
|
478 | };
|
479 |
|
480 | BaseViewer.prototype.getDefinitions = function() {
|
481 | return this._definitions;
|
482 | };
|
483 |
|
484 | BaseViewer.prototype.detach = function() {
|
485 |
|
486 | var container = this._container,
|
487 | parentNode = container.parentNode;
|
488 |
|
489 | if (!parentNode) {
|
490 | return;
|
491 | }
|
492 |
|
493 | this._emit('detach', {});
|
494 |
|
495 | parentNode.removeChild(container);
|
496 | };
|
497 |
|
498 | BaseViewer.prototype._init = function(container, moddle, options) {
|
499 |
|
500 | var baseModules = options.modules || this.getModules(),
|
501 | additionalModules = options.additionalModules || [],
|
502 | staticModules = [
|
503 | {
|
504 | bpmnjs: [ 'value', this ],
|
505 | moddle: [ 'value', moddle ]
|
506 | }
|
507 | ];
|
508 |
|
509 | var diagramModules = [].concat(staticModules, baseModules, additionalModules);
|
510 |
|
511 | var diagramOptions = assign(omit(options, [ 'additionalModules' ]), {
|
512 | canvas: assign({}, options.canvas, { container: container }),
|
513 | modules: diagramModules
|
514 | });
|
515 |
|
516 |
|
517 | Diagram.call(this, diagramOptions);
|
518 |
|
519 | if (options && options.container) {
|
520 | this.attachTo(options.container);
|
521 | }
|
522 | };
|
523 |
|
524 |
|
525 |
|
526 |
|
527 |
|
528 |
|
529 |
|
530 |
|
531 |
|
532 | BaseViewer.prototype._emit = function(type, event) {
|
533 | return this.get('eventBus').fire(type, event);
|
534 | };
|
535 |
|
536 | BaseViewer.prototype._createContainer = function(options) {
|
537 |
|
538 | var container = domify('<div class="bjs-container"></div>');
|
539 |
|
540 | assign(container.style, {
|
541 | width: ensureUnit(options.width),
|
542 | height: ensureUnit(options.height),
|
543 | position: options.position
|
544 | });
|
545 |
|
546 | return container;
|
547 | };
|
548 |
|
549 | BaseViewer.prototype._createModdle = function(options) {
|
550 | var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
|
551 |
|
552 | return new BpmnModdle(moddleOptions);
|
553 | };
|
554 |
|
555 | BaseViewer.prototype._modules = [];
|
556 |
|
557 |
|
558 |
|
559 |
|
560 | function checkValidationError(err) {
|
561 |
|
562 |
|
563 |
|
564 |
|
565 | var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
|
566 | var match = pattern.exec(err.message);
|
567 |
|
568 | if (match) {
|
569 | err.message =
|
570 | 'unparsable content <' + match[1] + '> detected; ' +
|
571 | 'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
|
572 | }
|
573 |
|
574 | return err;
|
575 | }
|
576 |
|
577 | var DEFAULT_OPTIONS = {
|
578 | width: '100%',
|
579 | height: '100%',
|
580 | position: 'relative'
|
581 | };
|
582 |
|
583 |
|
584 |
|
585 |
|
586 |
|
587 | function ensureUnit(val) {
|
588 | return val + (isNumber(val) ? 'px' : '');
|
589 | }
|
590 |
|
591 |
|
592 |
|
593 |
|
594 |
|
595 |
|
596 |
|
597 |
|
598 |
|
599 |
|
600 | function findBPMNDiagram(definitions, diagramId) {
|
601 | if (!diagramId) {
|
602 | return null;
|
603 | }
|
604 |
|
605 | return find(definitions.diagrams, function(element) {
|
606 | return element.id === diagramId;
|
607 | }) || null;
|
608 | }
|
609 |
|
610 |
|
611 |
|
612 |
|
613 | import {
|
614 | open as openPoweredBy,
|
615 | BPMNIO_IMG
|
616 | } from './util/PoweredByUtil';
|
617 |
|
618 | import {
|
619 | event as domEvent
|
620 | } from 'min-dom';
|
621 |
|
622 |
|
623 |
|
624 |
|
625 |
|
626 |
|
627 |
|
628 |
|
629 |
|
630 | function addProjectLogo(container) {
|
631 | var img = BPMNIO_IMG;
|
632 |
|
633 | var linkMarkup =
|
634 | '<a href="http://bpmn.io" ' +
|
635 | 'target="_blank" ' +
|
636 | 'class="bjs-powered-by" ' +
|
637 | 'title="Powered by bpmn.io" ' +
|
638 | 'style="position: absolute; bottom: 15px; right: 15px; z-index: 100">' +
|
639 | img +
|
640 | '</a>';
|
641 |
|
642 | var linkElement = domify(linkMarkup);
|
643 |
|
644 | container.appendChild(linkElement);
|
645 |
|
646 | domEvent.bind(linkElement, 'click', function(event) {
|
647 | openPoweredBy();
|
648 |
|
649 | event.preventDefault();
|
650 | });
|
651 | }
|
652 |
|
653 |
|
\ | No newline at end of file |