4 changed files with 679 additions and 3 deletions
@ -0,0 +1,524 @@ |
|||
import { |
|||
assign, |
|||
forEach, |
|||
isArray, |
|||
every |
|||
} from 'min-dash'; |
|||
|
|||
import { |
|||
is |
|||
} from 'bpmn-js/lib/util/ModelUtil'; |
|||
|
|||
import { |
|||
isExpanded, |
|||
isEventSubProcess |
|||
} from 'bpmn-js/lib/util/DiUtil'; |
|||
|
|||
import { |
|||
isAny |
|||
} from 'bpmn-js/lib/features/modeling/util/ModelingUtil'; |
|||
|
|||
import { |
|||
getChildLanes |
|||
} from 'bpmn-js/lib/features/modeling/util/LaneUtil'; |
|||
|
|||
import { |
|||
hasPrimaryModifier |
|||
} from 'diagram-js/lib/util/Mouse'; |
|||
|
|||
|
|||
/** |
|||
* A provider for BPMN 2.0 elements context pad |
|||
*/ |
|||
export default function ContextPadProvider( |
|||
config, injector, eventBus, |
|||
contextPad, modeling, elementFactory, |
|||
connect, create, popupMenu, |
|||
canvas, rules, translate) { |
|||
|
|||
config = config || {}; |
|||
|
|||
contextPad.registerProvider(this); |
|||
|
|||
this._contextPad = contextPad; |
|||
|
|||
this._modeling = modeling; |
|||
|
|||
this._elementFactory = elementFactory; |
|||
this._connect = connect; |
|||
this._create = create; |
|||
this._popupMenu = popupMenu; |
|||
this._canvas = canvas; |
|||
this._rules = rules; |
|||
this._translate = translate; |
|||
|
|||
if (config.autoPlace !== false) { |
|||
this._autoPlace = injector.get('autoPlace', false); |
|||
} |
|||
|
|||
eventBus.on('create.end', 250, function(event) { |
|||
var context = event.context, |
|||
shape = context.shape; |
|||
|
|||
if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) { |
|||
return; |
|||
} |
|||
|
|||
var entries = contextPad.getEntries(shape); |
|||
|
|||
if (entries.replace) { |
|||
entries.replace.action.click(event, shape); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
ContextPadProvider.$inject = [ |
|||
'config.contextPad', |
|||
'injector', |
|||
'eventBus', |
|||
'contextPad', |
|||
'modeling', |
|||
'elementFactory', |
|||
'connect', |
|||
'create', |
|||
'popupMenu', |
|||
'canvas', |
|||
'rules', |
|||
'translate' |
|||
]; |
|||
|
|||
ContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) { |
|||
var modeling = this._modeling; |
|||
|
|||
var actions = {}; |
|||
|
|||
if (this._isDeleteAllowed(elements)) { |
|||
assign(actions, { |
|||
'delete': { |
|||
group: 'edit', |
|||
className: 'bpmn-icon-trash', |
|||
title: this._translate('Remove'), |
|||
action: { |
|||
click: function(event, elements) { |
|||
modeling.removeElements(elements.slice()); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
return actions; |
|||
}; |
|||
|
|||
/** |
|||
* @param {djs.model.Base[]} elements |
|||
* @return {boolean} |
|||
*/ |
|||
ContextPadProvider.prototype._isDeleteAllowed = function(elements) { |
|||
|
|||
var baseAllowed = this._rules.allowed('elements.delete', { |
|||
elements: elements |
|||
}); |
|||
|
|||
if (isArray(baseAllowed)) { |
|||
return every(baseAllowed, function(element) { |
|||
return includes(baseAllowed, element); |
|||
}); |
|||
} |
|||
|
|||
return baseAllowed; |
|||
}; |
|||
|
|||
ContextPadProvider.prototype.getContextPadEntries = function(element) { |
|||
var contextPad = this._contextPad, |
|||
modeling = this._modeling, |
|||
|
|||
elementFactory = this._elementFactory, |
|||
connect = this._connect, |
|||
create = this._create, |
|||
popupMenu = this._popupMenu, |
|||
rules = this._rules, |
|||
autoPlace = this._autoPlace, |
|||
translate = this._translate; |
|||
|
|||
var actions = {}; |
|||
|
|||
if (element.type === 'label') { |
|||
return actions; |
|||
} |
|||
|
|||
var businessObject = element.businessObject; |
|||
|
|||
function startConnect(event, element) { |
|||
connect.start(event, element); |
|||
} |
|||
|
|||
function removeElement(e, element) { |
|||
modeling.removeElements([ element ]); |
|||
} |
|||
|
|||
function getReplaceMenuPosition(element) { |
|||
|
|||
var Y_OFFSET = 5; |
|||
|
|||
var pad = contextPad.getPad(element).html; |
|||
|
|||
var padRect = pad.getBoundingClientRect(); |
|||
|
|||
var pos = { |
|||
x: padRect.left, |
|||
y: padRect.bottom + Y_OFFSET |
|||
}; |
|||
|
|||
return pos; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Create an append action |
|||
* |
|||
* @param {string} type |
|||
* @param {string} className |
|||
* @param {string} [title] |
|||
* @param {Object} [options] |
|||
* |
|||
* @return {Object} descriptor |
|||
*/ |
|||
function appendAction(type, className, title, options) { |
|||
|
|||
if (typeof title !== 'string') { |
|||
options = title; |
|||
title = translate('Append {type}', { type: type.replace(/^bpmn:/, '') }); |
|||
} |
|||
|
|||
function appendStart(event, element) { |
|||
|
|||
var shape = elementFactory.createShape(assign({ type: type }, options)); |
|||
create.start(event, shape, { |
|||
source: element |
|||
}); |
|||
} |
|||
|
|||
|
|||
var append = autoPlace ? function(event, element) { |
|||
var shape = elementFactory.createShape(assign({ type: type }, options)); |
|||
|
|||
autoPlace.append(element, shape); |
|||
} : appendStart; |
|||
|
|||
|
|||
return { |
|||
group: 'model', |
|||
className: className, |
|||
title: title, |
|||
action: { |
|||
dragstart: appendStart, |
|||
click: append |
|||
} |
|||
}; |
|||
} |
|||
|
|||
function splitLaneHandler(count) { |
|||
|
|||
return function(event, element) { |
|||
|
|||
// actual split
|
|||
modeling.splitLane(element, count); |
|||
|
|||
// refresh context pad after split to
|
|||
// get rid of split icons
|
|||
contextPad.open(element, true); |
|||
}; |
|||
} |
|||
|
|||
|
|||
if (isAny(businessObject, [ 'bpmn:Lane', 'bpmn:Participant' ]) && isExpanded(element)) { |
|||
|
|||
var childLanes = getChildLanes(element); |
|||
|
|||
assign(actions, { |
|||
'lane-insert-above': { |
|||
group: 'lane-insert-above', |
|||
className: 'bpmn-icon-lane-insert-above', |
|||
title: translate('Add Lane above'), |
|||
action: { |
|||
click: function(event, element) { |
|||
modeling.addLane(element, 'top'); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
|
|||
if (childLanes.length < 2) { |
|||
|
|||
if (element.height >= 120) { |
|||
assign(actions, { |
|||
'lane-divide-two': { |
|||
group: 'lane-divide', |
|||
className: 'bpmn-icon-lane-divide-two', |
|||
title: translate('Divide into two Lanes'), |
|||
action: { |
|||
click: splitLaneHandler(2) |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
if (element.height >= 180) { |
|||
assign(actions, { |
|||
'lane-divide-three': { |
|||
group: 'lane-divide', |
|||
className: 'bpmn-icon-lane-divide-three', |
|||
title: translate('Divide into three Lanes'), |
|||
action: { |
|||
click: splitLaneHandler(3) |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
assign(actions, { |
|||
'lane-insert-below': { |
|||
group: 'lane-insert-below', |
|||
className: 'bpmn-icon-lane-insert-below', |
|||
title: translate('Add Lane below'), |
|||
action: { |
|||
click: function(event, element) { |
|||
modeling.addLane(element, 'bottom'); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
|
|||
} |
|||
|
|||
if (is(businessObject, 'bpmn:FlowNode')) { |
|||
|
|||
if (is(businessObject, 'bpmn:EventBasedGateway')) { |
|||
|
|||
assign(actions, { |
|||
'append.receive-task': appendAction( |
|||
'bpmn:ReceiveTask', |
|||
'bpmn-icon-receive-task', |
|||
translate('Append ReceiveTask') |
|||
), |
|||
'append.message-intermediate-event': appendAction( |
|||
'bpmn:IntermediateCatchEvent', |
|||
'bpmn-icon-intermediate-event-catch-message', |
|||
translate('Append MessageIntermediateCatchEvent'), |
|||
{ eventDefinitionType: 'bpmn:MessageEventDefinition' } |
|||
), |
|||
'append.timer-intermediate-event': appendAction( |
|||
'bpmn:IntermediateCatchEvent', |
|||
'bpmn-icon-intermediate-event-catch-timer', |
|||
translate('Append TimerIntermediateCatchEvent'), |
|||
{ eventDefinitionType: 'bpmn:TimerEventDefinition' } |
|||
), |
|||
'append.condition-intermediate-event': appendAction( |
|||
'bpmn:IntermediateCatchEvent', |
|||
'bpmn-icon-intermediate-event-catch-condition', |
|||
translate('Append ConditionIntermediateCatchEvent'), |
|||
{ eventDefinitionType: 'bpmn:ConditionalEventDefinition' } |
|||
), |
|||
'append.signal-intermediate-event': appendAction( |
|||
'bpmn:IntermediateCatchEvent', |
|||
'bpmn-icon-intermediate-event-catch-signal', |
|||
translate('Append SignalIntermediateCatchEvent'), |
|||
{ eventDefinitionType: 'bpmn:SignalEventDefinition' } |
|||
) |
|||
}); |
|||
} else |
|||
|
|||
if (isEventType(businessObject, 'bpmn:BoundaryEvent', 'bpmn:CompensateEventDefinition')) { |
|||
|
|||
assign(actions, { |
|||
'append.compensation-activity': |
|||
appendAction( |
|||
'bpmn:Task', |
|||
'bpmn-icon-task', |
|||
translate('Append compensation activity'), |
|||
{ |
|||
isForCompensation: true |
|||
} |
|||
) |
|||
}); |
|||
} else |
|||
|
|||
if (!is(businessObject, 'bpmn:EndEvent') && |
|||
!businessObject.isForCompensation && |
|||
!isEventType(businessObject, 'bpmn:IntermediateThrowEvent', 'bpmn:LinkEventDefinition') && |
|||
!isEventSubProcess(businessObject)) { |
|||
|
|||
assign(actions, { |
|||
'append.end-event': appendAction( |
|||
'bpmn:EndEvent', |
|||
'bpmn-icon-end-event-none', |
|||
translate('Append EndEvent') |
|||
), |
|||
'append.gateway': appendAction( |
|||
'bpmn:ExclusiveGateway', |
|||
'bpmn-icon-gateway-none', |
|||
translate('Append Gateway') |
|||
), |
|||
'append.append-user-task': appendAction( |
|||
'bpmn:Task', |
|||
'bpmn-icon-user-task', |
|||
translate('添加用户任务') |
|||
), |
|||
'append.intermediate-event': appendAction( |
|||
'bpmn:IntermediateThrowEvent', |
|||
'bpmn-icon-intermediate-event-none', |
|||
translate('Append Intermediate/Boundary Event') |
|||
) |
|||
}); |
|||
} |
|||
} |
|||
|
|||
if (!popupMenu.isEmpty(element, 'bpmn-replace')) { |
|||
|
|||
// Replace menu entry
|
|||
assign(actions, { |
|||
'replace': { |
|||
group: 'edit', |
|||
className: 'bpmn-icon-screw-wrench', |
|||
title: translate('Change type'), |
|||
action: { |
|||
click: function(event, element) { |
|||
|
|||
var position = assign(getReplaceMenuPosition(element), { |
|||
cursor: { x: event.x, y: event.y } |
|||
}); |
|||
|
|||
popupMenu.open(element, 'bpmn-replace', position, { |
|||
title: translate('Change element'), |
|||
width: 300, |
|||
search: true |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
if (is(businessObject, 'bpmn:SequenceFlow')) { |
|||
assign(actions, { |
|||
'append.text-annotation': appendAction( |
|||
'bpmn:TextAnnotation', |
|||
'bpmn-icon-text-annotation' |
|||
) |
|||
}); |
|||
} |
|||
|
|||
if ( |
|||
isAny(businessObject, [ |
|||
'bpmn:FlowNode', |
|||
'bpmn:InteractionNode', |
|||
'bpmn:DataObjectReference', |
|||
'bpmn:DataStoreReference', |
|||
]) |
|||
) { |
|||
assign(actions, { |
|||
'append.text-annotation': appendAction( |
|||
'bpmn:TextAnnotation', |
|||
'bpmn-icon-text-annotation' |
|||
), |
|||
|
|||
'connect': { |
|||
group: 'connect', |
|||
className: 'bpmn-icon-connection-multi', |
|||
title: translate( |
|||
'Connect using ' + |
|||
(businessObject.isForCompensation |
|||
? '' |
|||
: 'Sequence/MessageFlow or ') + |
|||
'Association' |
|||
), |
|||
action: { |
|||
click: startConnect, |
|||
dragstart: startConnect, |
|||
}, |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
if (is(businessObject, 'bpmn:TextAnnotation')) { |
|||
assign(actions, { |
|||
'connect': { |
|||
group: 'connect', |
|||
className: 'bpmn-icon-connection-multi', |
|||
title: translate('Connect using Association'), |
|||
action: { |
|||
click: startConnect, |
|||
dragstart: startConnect, |
|||
}, |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
if (isAny(businessObject, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) { |
|||
assign(actions, { |
|||
'connect': { |
|||
group: 'connect', |
|||
className: 'bpmn-icon-connection-multi', |
|||
title: translate('Connect using DataInputAssociation'), |
|||
action: { |
|||
click: startConnect, |
|||
dragstart: startConnect |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
if (is(businessObject, 'bpmn:Group')) { |
|||
assign(actions, { |
|||
'append.text-annotation': appendAction('bpmn:TextAnnotation', 'bpmn-icon-text-annotation') |
|||
}); |
|||
} |
|||
|
|||
// delete element entry, only show if allowed by rules
|
|||
var deleteAllowed = rules.allowed('elements.delete', { elements: [ element ] }); |
|||
|
|||
if (isArray(deleteAllowed)) { |
|||
|
|||
// was the element returned as a deletion candidate?
|
|||
deleteAllowed = deleteAllowed[0] === element; |
|||
} |
|||
|
|||
if (deleteAllowed) { |
|||
assign(actions, { |
|||
'delete': { |
|||
group: 'edit', |
|||
className: 'bpmn-icon-trash', |
|||
title: translate('Remove'), |
|||
action: { |
|||
click: removeElement |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
return actions; |
|||
}; |
|||
|
|||
|
|||
// helpers /////////
|
|||
|
|||
function isEventType(eventBo, type, definition) { |
|||
|
|||
var isType = eventBo.$instanceOf(type); |
|||
var isDefinition = false; |
|||
|
|||
var definitions = eventBo.eventDefinitions || []; |
|||
forEach(definitions, function(def) { |
|||
if (def.$type === definition) { |
|||
isDefinition = true; |
|||
} |
|||
}); |
|||
|
|||
return isType && isDefinition; |
|||
} |
|||
|
|||
function includes(array, item) { |
|||
return array.indexOf(item) !== -1; |
|||
} |
@ -0,0 +1,142 @@ |
|||
import { assign } from "min-dash"; |
|||
|
|||
export default function CustomPalette( |
|||
palette, |
|||
create, |
|||
elementFactory, |
|||
handTool, |
|||
lassoTool, |
|||
spaceTool, |
|||
globalConnect, |
|||
translate |
|||
) { |
|||
this.create = create; |
|||
this.elementFactory = elementFactory; |
|||
this.handTool = handTool; |
|||
this.lassoTool = lassoTool; |
|||
this.spaceTool = spaceTool; |
|||
this.globalConnect = globalConnect; |
|||
this.translate = translate; |
|||
|
|||
palette.registerProvider(this); |
|||
} |
|||
|
|||
CustomPalette.$inject = [ |
|||
"palette", |
|||
"create", |
|||
"elementFactory", |
|||
"handTool", |
|||
"lassoTool", |
|||
"spaceTool", |
|||
"globalConnect", |
|||
"translate" |
|||
]; |
|||
|
|||
CustomPalette.prototype.getPaletteEntries = function (element) { |
|||
const { |
|||
create, |
|||
elementFactory, |
|||
handTool, |
|||
lassoTool, |
|||
spaceTool, |
|||
globalConnect, |
|||
translate |
|||
} = this; |
|||
|
|||
function createAction(type, group, className, title, options) { |
|||
function createListener(event) { |
|||
var shape = elementFactory.createShape(assign({ type: type }, options)); |
|||
|
|||
if (options) { |
|||
shape.businessObject.di.isExpanded = options.isExpanded; |
|||
} |
|||
|
|||
create.start(event, shape); |
|||
} |
|||
|
|||
var shortType = type.replace(/^bpmn:/, ""); |
|||
|
|||
return { |
|||
group: group, |
|||
className: className, |
|||
title: title || translate("Create {type}", { type: shortType }), |
|||
action: { |
|||
dragstart: createListener, |
|||
click: createListener |
|||
} |
|||
}; |
|||
} |
|||
|
|||
return { |
|||
'hand-tool': { |
|||
group: 'tools', |
|||
className: 'bpmn-icon-hand-tool', |
|||
title: '激活抓手工具', |
|||
action: { |
|||
click: function(event) { |
|||
handTool.activateHand(event); |
|||
} |
|||
} |
|||
}, |
|||
"lasso-tool": { |
|||
group: "tools", |
|||
className: "bpmn-icon-lasso-tool", |
|||
title: "激活套索工具", |
|||
action: { |
|||
click: function (event) { |
|||
lassoTool.activateSelection(event); |
|||
} |
|||
} |
|||
}, |
|||
'space-tool': { |
|||
group: 'tools', |
|||
className: 'bpmn-icon-space-tool', |
|||
title: translate('Activate the create/remove space tool'), |
|||
action: { |
|||
click: function(event) { |
|||
spaceTool.activateSelection(event); |
|||
} |
|||
} |
|||
}, |
|||
'global-connect-tool': { |
|||
group: 'tools', |
|||
className: 'bpmn-icon-connection-multi', |
|||
title: translate('Activate the global connect tool'), |
|||
action: { |
|||
click: function(event) { |
|||
globalConnect.start(event); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
"tool-separator": { |
|||
group: "tools", |
|||
separator: true |
|||
}, |
|||
|
|||
"create.start-event": createAction( |
|||
"bpmn:StartEvent", |
|||
"event", |
|||
"bpmn-icon-start-event-none", |
|||
"创建开始节点" |
|||
), |
|||
"create.end-event": createAction( |
|||
"bpmn:EndEvent", |
|||
"event", |
|||
"bpmn-icon-end-event-none", |
|||
"创建结束节点" |
|||
), |
|||
"create.user-task": createAction( |
|||
"bpmn:UserTask", |
|||
"activity", |
|||
"bpmn-icon-user-task", |
|||
"创建用户任务" |
|||
), |
|||
"create.exclusive-gateway": createAction( |
|||
"bpmn:ExclusiveGateway", |
|||
"gateway", |
|||
"bpmn-icon-gateway-xor", |
|||
"创建排他网关" |
|||
) |
|||
}; |
|||
}; |
@ -0,0 +1,8 @@ |
|||
import CustomContextPad from './CustomContextPad'; |
|||
import CustomPalette from "./CustomPalette"; |
|||
|
|||
export default { |
|||
__init__: [ 'paletteProvider','contextPadProvider'], |
|||
paletteProvider: [ 'type', CustomPalette ], |
|||
contextPadProvider: [ 'type', CustomContextPad ], |
|||
}; |
Loading…
Reference in new issue