Skip to content

Instantly share code, notes, and snippets.

@adbre
Created August 17, 2016 06:24
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adbre/2353693cb40e0af0404613e52f87d05b to your computer and use it in GitHub Desktop.
Save adbre/2353693cb40e0af0404613e52f87d05b to your computer and use it in GitHub Desktop.
'use strict';
var forEach = require('lodash/collection/forEach');
var HIGH_PRIORITY = 10001;
function ReadOnly(
eventBus,
contextPad,
dragging,
directEditing,
editorActions,
modeling,
palette,
paletteProvider) {
this._readOnly = false;
this._eventBus = eventBus;
var self = this;
eventBus.on('readOnly.changed', HIGH_PRIORITY, function (e) {
self._readOnly = e.readOnly;
if (e.readOnly) {
directEditing.cancel();
contextPad.close();
dragging.cancel();
}
palette._update();
});
function intercept(obj, fnName, cb) {
var fn = obj[fnName];
obj[fnName] = function () {
return cb.call(this, fn, arguments);
};
}
function ignoreWhenReadOnly(obj, fnName) {
intercept(obj, fnName, function (fn, args) {
if (self._readOnly) {
return;
}
return fn.apply(this, args);
});
}
function throwIfReadOnly(obj, fnName) {
intercept(obj, fnName, function (fn, args) {
if (self._readOnly) {
throw new Error('model is read-only');
}
return fn.apply(this, args);
});
}
ignoreWhenReadOnly(contextPad, 'open');
ignoreWhenReadOnly(dragging, 'init');
ignoreWhenReadOnly(directEditing, 'activate');
ignoreWhenReadOnly(editorActions._actions, 'undo');
ignoreWhenReadOnly(editorActions._actions, 'redo');
ignoreWhenReadOnly(editorActions._actions, 'copy');
ignoreWhenReadOnly(editorActions._actions, 'paste');
ignoreWhenReadOnly(editorActions._actions, 'removeSelection');
// BpmnEditorActions
ignoreWhenReadOnly(editorActions._actions, 'spaceTool');
ignoreWhenReadOnly(editorActions._actions, 'lassoTool');
ignoreWhenReadOnly(editorActions._actions, 'globalConnectTool');
ignoreWhenReadOnly(editorActions._actions, 'distributeElements');
ignoreWhenReadOnly(editorActions._actions, 'alignElements');
ignoreWhenReadOnly(editorActions._actions, 'directEditing');
throwIfReadOnly(modeling, 'moveShape');
throwIfReadOnly(modeling, 'updateAttachment');
throwIfReadOnly(modeling, 'moveElements');
throwIfReadOnly(modeling, 'moveConnection');
throwIfReadOnly(modeling, 'layoutConnection');
throwIfReadOnly(modeling, 'createConnection');
throwIfReadOnly(modeling, 'createShape');
throwIfReadOnly(modeling, 'createLabel');
throwIfReadOnly(modeling, 'appendShape');
throwIfReadOnly(modeling, 'removeElements');
throwIfReadOnly(modeling, 'distributeElements');
throwIfReadOnly(modeling, 'removeShape');
throwIfReadOnly(modeling, 'removeConnection');
throwIfReadOnly(modeling, 'replaceShape');
throwIfReadOnly(modeling, 'pasteElements');
throwIfReadOnly(modeling, 'alignElements');
throwIfReadOnly(modeling, 'resizeShape');
throwIfReadOnly(modeling, 'createSpace');
throwIfReadOnly(modeling, 'updateWaypoints');
throwIfReadOnly(modeling, 'reconnectStart');
throwIfReadOnly(modeling, 'reconnectEnd');
intercept(paletteProvider, 'getPaletteEntries', function (fn, args) {
var entries = fn.apply(this, args);
if (self._readOnly) {
var allowedEntries = [
'hand-tool'
];
forEach(entries, function (value, key) {
if (allowedEntries.indexOf(key) === -1) {
delete entries[key];
}
});
}
return entries;
});
}
ReadOnly.$inject = [
'eventBus',
'contextPad',
'dragging',
'directEditing',
'editorActions',
'modeling',
'palette',
'paletteProvider',
];
module.exports = ReadOnly;
ReadOnly.prototype.readOnly = function (readOnly) {
var newValue = !!readOnly,
oldValue = !!this._readOnly;
if (readOnly === undefined || newValue === oldValue) {
return oldValue;
}
this._readOnly = newValue;
this._eventBus.fire('readOnly.changed', { readOnly: newValue });
return newValue;
};
@dgouissem
Copy link

dgouissem commented Dec 7, 2016

Hello Adam ,
Could you please, give me some code hints, in order to use this implementation,
Where I can integrate and call the readOnly.js for example in this bpmn-js-examples .

Thanks and regards,

@adbre
Copy link
Author

adbre commented Jan 11, 2017

To add it in the bpmn-js-example build chain you need to include the ReadOnly.js file and add it to the BpmnModeler class (see how other modules are included).

To activate/disable readOnly state

modeler.get('readOnly').readOnly(true|false);

See also https://forum.bpmn.io/t/changing-from-modeler-to-viewer-and-back-again/900/12 for more info

@Tricinty
Copy link

Tricinty commented Jun 8, 2018

Hi Adam,
Unfortunately, this method does not work anymore, can you please give me a hint how I can get to work.

Thanks and regards,

@philippfromme
Copy link

@Tricinty what exavtly does not work anymore?

@haumacher
Copy link

The lines

    ignoreWhenReadOnly(editorActions._actions, 'undo');
    ignoreWhenReadOnly(editorActions._actions, 'redo');
    ignoreWhenReadOnly(editorActions._actions, 'copy');
    ignoreWhenReadOnly(editorActions._actions, 'paste');
    ignoreWhenReadOnly(editorActions._actions, 'removeSelection');
    // BpmnEditorActions
    ignoreWhenReadOnly(editorActions._actions, 'spaceTool');
    ignoreWhenReadOnly(editorActions._actions, 'lassoTool');
    ignoreWhenReadOnly(editorActions._actions, 'globalConnectTool');
    ignoreWhenReadOnly(editorActions._actions, 'distributeElements');
    ignoreWhenReadOnly(editorActions._actions, 'alignElements');
    ignoreWhenReadOnly(editorActions._actions, 'directEditing');

Cause the editor actions module to crash later on, since the actions are now registered when the diagram is loaded. One could defer patching the actions with this code instead:

    eventBus.on('editorActions.init', function() {
    	ignoreWhenReadOnly(editorActions._actions, 'undo');
    	ignoreWhenReadOnly(editorActions._actions, 'redo');
    	ignoreWhenReadOnly(editorActions._actions, 'copy');
    	ignoreWhenReadOnly(editorActions._actions, 'paste');
    	ignoreWhenReadOnly(editorActions._actions, 'removeSelection');
    	// BpmnEditorActions
    	ignoreWhenReadOnly(editorActions._actions, 'spaceTool');
    	ignoreWhenReadOnly(editorActions._actions, 'lassoTool');
    	ignoreWhenReadOnly(editorActions._actions, 'globalConnectTool');
    	ignoreWhenReadOnly(editorActions._actions, 'distributeElements');
    	ignoreWhenReadOnly(editorActions._actions, 'alignElements');
    	ignoreWhenReadOnly(editorActions._actions, 'directEditing');
    });

Additionally, dynamically loading the read-only module must now use code like this (the parameter has changed to additionalModules instead of modules in the original post):

var readOnlyModule = {
	__init__: ['readOnly'],
	readOnly: ['type', ReadOnly]
};

var viewer = new BpmnJS({
	container : ... ,
	additionalModules: [readOnlyModule]
});
			
viewer.get('readOnly').readOnly(true);

However, using this module produces a disabled modeler that is unable to scroll the diagram with the mouse within its viewport (when clicking within the diagram), which is unusable for non-trivial diagrams. The problem is that

ignoreWhenReadOnly(dragging, 'init');

breaks the hand-tool that allows scrolling the diagram. Without the line, one can start dragging individual shapes but not drop them again.

@haumacher
Copy link

The alternative to the "ReadOnly"-Module is using either a modler or a viewer - the constructor function for the viewer is also available in the modeler - I searched for this quite a long time:

var Modeler = editMode ? BpmnJS : BpmnJS.NavigatedViewer;
var viewer = new Modeler({
	container : ...
});

This has the drawback that when switching from viewer to modeler, one has to re-draw the diagram (loosing potential scroll positions) but is way better than having a "Viewer" that is much less convienent that the "original" viewer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment