diff --git a/element-templates/.gitignore b/element-templates/.gitignore new file mode 100644 index 00000000..f3766233 --- /dev/null +++ b/element-templates/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +public/ +tmp/ \ No newline at end of file diff --git a/element-templates/README.md b/element-templates/README.md new file mode 100644 index 00000000..1e6052b7 --- /dev/null +++ b/element-templates/README.md @@ -0,0 +1,57 @@ +# bpmn-js Modeler + element templates Example + + +## About + + + +```javascript +import { + BpmnPropertiesPanelModule, + BpmnPropertiesProviderModule, + ElementTemplatesPropertiesProviderModule +} from 'bpmn-js-properties-panel' + + +var bpmnModeler = new BpmnModeler({ + container: canvas, + propertiesPanel: { + parent: '#js-properties-panel' + }, + additionalModules: [ + BpmnPropertiesPanelModule, + BpmnPropertiesProviderModule, + ElementTemplatesPropertiesProviderModule, + ] +}) + +bpmnModeler.get('elementTemplatesLoader').setTemplates(templates) + +``` + +## Building the Example + +You need a [NodeJS](http://nodejs.org) development stack with [npm](https://npmjs.org) and installed to build the project. + +To install all project dependencies execute + +``` +npm install +``` + +Build the example using [webpack](https://webpack.js.org/) via + +``` +npm run all +``` + +Both tasks generate the distribution ready client-side modeler application into the `public` folder. + +Serve the application locally or via a web server (nginx, apache, embedded). diff --git a/element-templates/package.json b/element-templates/package.json new file mode 100644 index 00000000..609a8782 --- /dev/null +++ b/element-templates/package.json @@ -0,0 +1,54 @@ +{ + "name": "bpmn-js-example-element-templates", + "version": "0.0.0", + "description": "A bpmn-js modeler + element templates example", + "main": "app/index.js", + "scripts": { + "all": "run-s bundle", + "dev": "run-s bundle:less watch:js", + "start": "run-s bundle serve", + "serve": "sirv public --port=5002 --watch --dev", + "bundle": "run-s bundle:*", + "bundle:less": "lessc src/app.less public/app.css", + "bundle:js": "webpack -c webpack.config.js", + "watch:js": "run-s \"bundle:js -- --watch\"" + }, + "repository": { + "type": "git", + "url": "https://github.com/bpmn-io/bpmn-js-examples", + "directory": "element-templates" + }, + "author": { + "name": "Beatriz Mendes", + "url": "https://github.com/smbea" + }, + "keywords": [ + "bpmnjs-example", + "element-templates" + ], + "contributors": [ + { + "name": "bpmn.io contributors", + "url": "https://github.com/bpmn-io" + } + ], + "license": "MIT", + "dependencies": { + "@bpmn-io/element-template-chooser": "^0.1.0", + "@bpmn-io/properties-panel": "^0.11.0", + "bpmn-js": "^9.0.3", + "bpmn-js-properties-panel": "^1.0.0-alpha.5", + "css-loader": "^6.7.1", + "jquery": "^3.5.1", + "min-dash": "^3.7.0" + }, + "devDependencies": { + "copy-webpack-plugin": "^7.0.0", + "less": "^4.1.0", + "npm-run-all": "^4.1.5", + "raw-loader": "^4.0.2", + "sirv-cli": "^1.0.10", + "webpack": "^5.16.0", + "webpack-cli": "^4.4.0" + } +} diff --git a/element-templates/src/app.js b/element-templates/src/app.js new file mode 100644 index 00000000..62c62dc3 --- /dev/null +++ b/element-templates/src/app.js @@ -0,0 +1,178 @@ +import $ from 'jquery' +import BpmnModeler from 'bpmn-js/lib/Modeler' + +import { debounce } from 'min-dash' + +import { + BpmnPropertiesPanelModule, + BpmnPropertiesProviderModule, + ElementTemplatesPropertiesProviderModule +} from 'bpmn-js-properties-panel' + +import diagramXML from './newDiagram.bpmn' +import ElementTemplateChooserModule from '@bpmn-io/element-template-chooser' + +var container = $('#js-drop-zone') + +var canvas = $('#js-canvas') + +var templates = [ + { + id: 'template1', + name: 'Template 1', + appliesTo: ['bpmn:Task'], + properties: [ + { + binding: { + name: 'name', + type: 'property' + }, + label: 'Template Name', + type: 'Hidden', + value: 'template-name' + } + ] + } +] + +var bpmnModeler = new BpmnModeler({ + container: canvas, + propertiesPanel: { + parent: '#js-properties-panel' + }, + additionalModules: [ + BpmnPropertiesPanelModule, + BpmnPropertiesProviderModule, + ElementTemplatesPropertiesProviderModule, + ElementTemplateChooserModule // example of a template chooser, can be replaced by custom implementation + ] +}) +container.removeClass('with-diagram') + +function createNewDiagram () { + openDiagram(diagramXML) +} + +async function openDiagram (xml) { + try { + await bpmnModeler.importXML(xml) + + container.removeClass('with-error').addClass('with-diagram') + + bpmnModeler.on('elementTemplates.errors', event => { + const { errors } = event + + showTemplateErrors(errors) + }) + + bpmnModeler.get('elementTemplatesLoader').setTemplates(templates) + + } catch (err) { + container.removeClass('with-diagram').addClass('with-error') + + container.find('.error pre').text(err.message) + + console.error(err) + } +} + +function registerFileDrop (container, callback) { + function handleFileSelect (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) + } + + reader.readAsText(file) + } + + function handleDragOver (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 { + registerFileDrop(container, openDiagram) +} + +// bootstrap diagram functions + +$(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) { + 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 exportArtifacts = debounce(async function () { + try { + const { svg } = await bpmnModeler.saveSVG() + + setEncoded(downloadSvgLink, 'diagram.svg', svg) + } catch (err) { + console.error('Error happened saving SVG: ', err) + + setEncoded(downloadSvgLink, 'diagram.svg', null) + } + + try { + const { xml } = await bpmnModeler.saveXML({ format: true }) + + setEncoded(downloadLink, 'diagram.bpmn', xml) + } catch (err) { + console.log('Error happened saving XML: ', err) + + setEncoded(downloadLink, 'diagram.bpmn', null) + } + }, 500) + + bpmnModeler.on('commandStack.changed', exportArtifacts) +}) diff --git a/element-templates/src/app.less b/element-templates/src/app.less new file mode 100644 index 00000000..51f48719 --- /dev/null +++ b/element-templates/src/app.less @@ -0,0 +1,127 @@ +* { + box-sizing: border-box; +} + +body, +html { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + + font-size: 12px; + + height: 100%; + max-height: 100%; + padding: 0; + margin: 0; +} + +#js-properties-panel { + width: 400px; +} + +a:link { + text-decoration: none; +} + +.content { + position: relative; + width: 100%; + height: 100%; + display: flex; + + > .message { + width: 100%; + height: 100%; + text-align: center; + display: table; + + font-size: 16px; + color: #111; + + .note { + vertical-align: middle; + text-align: center; + display: table-cell; + } + + &.error { + .details { + max-width: 500px; + font-size: 12px; + margin: 20px auto; + text-align: left; + color: #BD2828; + } + + pre { + border: solid 1px #BD2828; + background: #fefafa; + padding: 10px; + color: #BD2828; + } + } + } + &:not(.with-error) .error, + &.with-error .intro, + &.with-diagram .intro { + display: none; + } + + .canvas { + width: 100%; + } + + .canvas, + .properties-panel-parent { + display: none; + } + + &.with-diagram { + .canvas, + .properties-panel-parent { + display: block; + } + } +} + + +.buttons { + position: fixed; + bottom: 20px; + left: 20px; + + padding: 0; + margin: 0; + list-style: none; + + > li { + display: inline-block; + margin-right: 10px; + + > a { + background: #DDD; + border: solid 1px #666; + display: inline-block; + padding: 5px; + } + } + + a { + opacity: 0.3; + } + + a.active { + opacity: 1.0; + } +} + +.properties-panel-parent { + border-left: 1px solid #ccc; + overflow: auto; + &:empty { + display: none; + } + > .djs-properties-panel { + padding-bottom: 70px; + min-height:100%; + } +} diff --git a/element-templates/src/index.html b/element-templates/src/index.html new file mode 100644 index 00000000..2638946f --- /dev/null +++ b/element-templates/src/index.html @@ -0,0 +1,57 @@ + + +
+ +