extension.js 3.45 KB
Newer Older
sunhongwei's avatar
sunhongwei committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
"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;
}