I am trying to integrate a modelling tool app which is available as a node module. Using 1.3 has made this a lot easier but I still can’t get it to work as expected.
Running in node, this is what is meant to happen when selecting a component:
Unfortunately when running in Meteor no selection is possible, and an exception when adding new components from the palette to the canvas.
This is based on example code located at bpmn-js-examples/modeler at master · bpmn-io/bpmn-js-examples · GitHub.
The sample code running in node looks like this:
‘use strict’;
var fs = require(‘fs’);
var $ = require(‘jquery’),
BpmnModeler = require(‘bpmn-js/lib/Modeler’);
var container = $(‘#js-drop-zone’);
var canvas = $(‘#js-canvas’);
var renderer = new BpmnModeler({ container: canvas });
var newDiagramXML = fs.readFileSync(__dirname + ‘/…/resources/newDiagram.bpmn’, ‘utf-8’);
function createNewDiagram() {
openDiagram(newDiagramXML);
}
function openDiagram(xml) {
renderer.importXML(xml, function(err) {
if (err) {
container
.removeClass('with-diagram')
.addClass('with-error');
container.find('.error pre').text(err.message);
console.error(err);
} else {
container
.removeClass('with-error')
.addClass('with-diagram');
}
});
}
function saveSVG(done) {
renderer.saveSVG(done);
}
function saveDiagram(done) {
renderer.saveXML({ format: true }, function(err, xml) {
done(err, xml);
});
}
function registerFileDrop(container, callback) {
function handleFileSelect(e) {
console.log(e);
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files;
var file = files[0];
console.log(file);
var reader = new FileReader();
reader.onload = function(e) {
var xml = e.target.result;
callback(xml);
};
reader.readAsText(file);
}
function handleDragOver(e) {
console.log(e);
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
container.get(0).addEventListener(‘dragover’, handleDragOver, false);
container.get(0).addEventListener(‘drop’, handleFileSelect, false);
}
////// file drag / drop ///////////////////////
// check file api availability
if (!window.FileList || !window.FileReader) {
window.alert(
'Looks like you use an older browser that does not support drag and drop. ’ +
‘Try using Chrome, Firefox or the Internet Explorer > 10.’);
} else {
console.log(“registerFileDrop”);
registerFileDrop(container, openDiagram);
}
// bootstrap diagram functions
$(document).on(‘ready’, function() {
$(‘#js-create-diagram’).click(function(e) {
e.stopPropagation();
e.preventDefault();
createNewDiagram();
});
var downloadLink = $(‘#js-download-diagram’);
var downloadSvgLink = $(‘#js-download-svg’);
$(‘.buttons a’).click(function(e) {
console.log(e);
if (!$(this).is(‘.active’)) {
e.preventDefault();
e.stopPropagation();
}
});
function setEncoded(link, name, data) {
var encodedData = encodeURIComponent(data);
if (data) {
link.addClass('active').attr({
'href': 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData,
'download': name
});
} else {
link.removeClass('active');
}
}
var _ = require(‘lodash’);
var exportArtifacts = _.debounce(function() {
saveSVG(function(err, svg) {
setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg);
});
saveDiagram(function(err, xml) {
setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml);
});
}, 500);
renderer.on(‘commandStack.changed’, exportArtifacts);
});
My attempt at the equivalent Meteor code looks like this:
‘use strict’;
var $ = require(‘jquery’);
var BpmnModeler = require(‘bpmn-js/lib/Modeler’);
var newDiagramXML;
Template.index.onCreated(function() {
Meteor.call(‘readFile’, ‘resources/newDiagram.bpmn’, function(err, data) {
if (err) {
console.log(err);
return;
}
newDiagramXML = data;
});
});
var container;
var canvas;
var bpmnModeler;
var fileDropRegistered = false;
Template.index.onRendered(function() {
container = $(‘#js-drop-zone’);
canvas = $(‘#js-canvas’);
bpmnModeler = new BpmnModeler({ container: canvas });
function registerFileDrop(container, callback) {
function handleDragOver(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
function handleFileSelect(e) {
console.log(e);
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files;
var file = files[0];
var reader = new FileReader();
reader.onload = function(e) {
var xml = e.target.result;
callback(xml);
};
console.log(file);
if(file) {
reader.readAsText(file);
}
}
container.get(0).addEventListener('dragover', handleDragOver, false);
container.get(0).addEventListener('drop', handleFileSelect, false);
}
// check file api availability
if (!window.FileList || !window.FileReader) {
window.alert(
'Looks like you use an older browser that does not support drag and drop. ’ +
‘Try using Chrome, Firefox or the Internet Explorer > 10.’);
} else if (fileDropRegistered == false) {
fileDropRegistered = true;
registerFileDrop(container, openDiagram);
}
function setEncoded(link, name, data) {
var encodedData = encodeURIComponent(data);
if (data) {
link.addClass('active').attr({
'href': 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData,
'download': name
});
} else {
link.removeClass('active');
}
}
var downloadLink = $(‘#js-download-diagram’);
var downloadSvgLink = $(‘#js-download-svg’);
var debounce = require(‘lodash/function/debounce’);
var exportArtifacts = debounce(function() {
saveSVG(function(err, svg) {
setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg);
});
saveDiagram(function(err, xml) {
setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml);
});
}, 500);
bpmnModeler.on(‘commandStack.changed’, exportArtifacts);
// bpmnModeler.on(‘commandStack.changed’, exportArtifacts);
});
function createNewDiagram() {
openDiagram(newDiagramXML);
}
function openDiagram(xml) {
bpmnModeler.importXML(xml, function(err) {
if (err) {
container
.removeClass(‘with-diagram’)
.addClass(‘with-error’);
container.find('.error pre').text(err.message);
console.error(err);
} else {
console.log('success!');
container
.removeClass('with-error')
.addClass('with-diagram');
}
});
}
function saveSVG(done) {
bpmnModeler.saveSVG(done);
}
function saveDiagram(done) {
bpmnModeler.saveXML({ format: true }, function(err, xml) {
done(err, xml);
});
}
////// file drag / drop ///////////////////////
// bootstrap diagram functions
$(document).on(‘ready’, function() {
$(‘#js-create-diagram’).click(function(e) {
e.stopPropagation();
e.preventDefault();
createNewDiagram();
});
$(‘.buttons a’).click(function(e) {
console.log(e);
if (!$(this).is(‘.active’)) {
e.preventDefault();
e.stopPropagation();
}
});
});
A good deal of the code has to go into Template.index.onRendered as the otherwise many of the variables will be undefined when they are evaluated.
The main problem seems to be that in Meteor code is executing when it shouldn’t and not executing when it should. For example the when dragging a new item onto the canvas an exception is thrown as the code is executing unexpectedly.
What I would like to understand is how to structure the code in Meteor so that the diagram editor behaves as expected.