"use strict"; var isFunction = require("min-dash").isFunction, isObject = require("min-dash").isObject, some = require("min-dash").some; var WILDCARD = "*"; function CamundaModdleExtension(eventBus) { var self = this; eventBus.on("moddleCopy.canCopyProperty", function(context) { var property = context.property, parent = context.parent; return self.canCopyProperty(property, parent); }); } CamundaModdleExtension.$inject = ["eventBus"]; /** * Check wether to disallow copying property. */ CamundaModdleExtension.prototype.canCopyProperty = function(property, parent) { // (1) check wether property is allowed in parent if (isObject(property) && !isAllowedInParent(property, parent)) { return false; } // (2) check more complex scenarios if (is(property, "camunda:InputOutput") && !this.canHostInputOutput(parent)) { return false; } if (isAny(property, ["camunda:Connector", "camunda:Field"]) && !this.canHostConnector(parent)) { return false; } if (is(property, "camunda:In") && !this.canHostIn(parent)) { return false; } }; CamundaModdleExtension.prototype.canHostInputOutput = function(parent) { // allowed in camunda:Connector var connector = getParent(parent, "camunda:Connector"); if (connector) { return true; } // special rules inside bpmn:FlowNode var flowNode = getParent(parent, "bpmn:FlowNode"); if (!flowNode) { return false; } if (isAny(flowNode, ["bpmn:StartEvent", "bpmn:Gateway", "bpmn:BoundaryEvent"])) { return false; } if (is(flowNode, "bpmn:SubProcess") && flowNode.get("triggeredByEvent")) { return false; } return true; }; CamundaModdleExtension.prototype.canHostConnector = function(parent) { var serviceTaskLike = getParent(parent, "camunda:ServiceTaskLike"); if (is(serviceTaskLike, "bpmn:MessageEventDefinition")) { // only allow on throw and end events return getParent(parent, "bpmn:IntermediateThrowEvent") || getParent(parent, "bpmn:EndEvent"); } return true; }; CamundaModdleExtension.prototype.canHostIn = function(parent) { var callActivity = getParent(parent, "bpmn:CallActivity"); if (callActivity) { return true; } var signalEventDefinition = getParent(parent, "bpmn:SignalEventDefinition"); if (signalEventDefinition) { // only allow on throw and end events return getParent(parent, "bpmn:IntermediateThrowEvent") || getParent(parent, "bpmn:EndEvent"); } return true; }; module.exports = CamundaModdleExtension; // helpers ////////// function is(element, type) { return element && isFunction(element.$instanceOf) && element.$instanceOf(type); } function isAny(element, types) { return some(types, function(t) { return is(element, t); }); } function getParent(element, type) { if (!type) { return element.$parent; } if (is(element, type)) { return element; } if (!element.$parent) { return; } return getParent(element.$parent, type); } function isAllowedInParent(property, parent) { // (1) find property descriptor var descriptor = property.$type && property.$model.getTypeDescriptor(property.$type); var allowedIn = descriptor && descriptor.meta && descriptor.meta.allowedIn; if (!allowedIn || isWildcard(allowedIn)) { return true; } // (2) check wether property has parent of allowed type return some(allowedIn, function(type) { return getParent(parent, type); }); } function isWildcard(allowedIn) { return allowedIn.indexOf(WILDCARD) !== -1; }