From 9e15903306bea723287969f86bbf3f2d50ed8508 Mon Sep 17 00:00:00 2001 From: Philipp Fromme Date: Mon, 28 Oct 2019 14:09:55 +0100 Subject: [PATCH] feat(modeling): connect reverse --- lib/features/attach-support/AttachSupport.js | 5 +- lib/features/bendpoints/BendpointMove.js | 153 +++++++++++++----- .../bendpoints/BendpointMovePreview.js | 83 ++++++---- .../bendpoints/ConnectionSegmentMove.js | 1 + lib/features/connect/Connect.js | 90 ++++++++--- lib/features/connect/ConnectPreview.js | 43 +++-- lib/features/modeling/Modeling.js | 15 ++ .../cmd/ReconnectConnectionHandler.js | 32 ++-- .../modeling/cmd/ReplaceShapeHandler.js | 10 +- .../attach-support/rules/AttachRules.js | 24 +-- .../features/bendpoints/BendpointsMoveSpec.js | 7 +- .../bendpoints/rules/BendpointRules.js | 14 +- test/spec/features/connect/ConnectSpec.js | 41 ++++- .../features/connect/rules/ConnectRules.js | 2 +- .../global-connect/GlobalConnectSpec.js | 4 +- 15 files changed, 365 insertions(+), 159 deletions(-) diff --git a/lib/features/attach-support/AttachSupport.js b/lib/features/attach-support/AttachSupport.js index b4a6cbdd8..95e7954ca 100644 --- a/lib/features/attach-support/AttachSupport.js +++ b/lib/features/attach-support/AttachSupport.js @@ -154,9 +154,10 @@ export default function AttachSupport(injector, eventBus, canvas, rules, modelin forEach(shape.attachers, function(attacher) { + // TODO: check reverse // remove invalid outgoing connections forEach(attacher.outgoing.slice(), function(connection) { - var allowed = rules.allowed('connection.reconnectStart', { + var allowed = rules.allowed('connection.reconnect', { connection: connection, source: connection.source, target: connection.target @@ -169,7 +170,7 @@ export default function AttachSupport(injector, eventBus, canvas, rules, modelin // remove invalid incoming connections forEach(attacher.incoming.slice(), function(connection) { - var allowed = rules.allowed('connection.reconnectEnd', { + var allowed = rules.allowed('connection.reconnect', { connection: connection, source: connection.source, target: connection.target diff --git a/lib/features/bendpoints/BendpointMove.js b/lib/features/bendpoints/BendpointMove.js index e72a41ca7..b6217743b 100644 --- a/lib/features/bendpoints/BendpointMove.js +++ b/lib/features/bendpoints/BendpointMove.js @@ -2,10 +2,6 @@ import { filterRedundantWaypoints } from '../../layout/LayoutUtil'; -var COMMAND_BENDPOINT_UPDATE = 'connection.updateWaypoints', - COMMAND_RECONNECT_START = 'connection.reconnectStart', - COMMAND_RECONNECT_END = 'connection.reconnectEnd'; - var round = Math.round; @@ -22,27 +18,25 @@ export default function BendpointMove(injector, eventBus, canvas, dragging, rule this.start = function(event, connection, bendpointIndex, insert) { var type, - context, waypoints = connection.waypoints, gfx = canvas.getGraphics(connection); if (!insert && bendpointIndex === 0) { - type = COMMAND_RECONNECT_START; + type = 'reconnectStart'; } else if (!insert && bendpointIndex === waypoints.length - 1) { - type = COMMAND_RECONNECT_END; + type = 'reconnectEnd'; } else { - type = COMMAND_BENDPOINT_UPDATE; + type = 'updateWaypoints'; } - context = { - connection: connection, - bendpointIndex: bendpointIndex, - insert: insert, - type: type - }; + var command = type === 'updateWaypoints' ? 'connection.updateWaypoints' : 'connection.reconnect'; - var allowed = context.allowed = rules.allowed(context.type, context); + var allowed = rules.allowed(command, { + connection: connection, + source: connection.source, + target: connection.target + }); if (allowed === false) { return; @@ -52,67 +46,106 @@ export default function BendpointMove(injector, eventBus, canvas, dragging, rule data: { connection: connection, connectionGfx: gfx, - context: context + context: { + bendpointIndex: bendpointIndex, + connection: connection, + insert: insert, + type: type + } } }); }; eventBus.on('bendpoint.move.hover', function(event) { - var context = event.context; - context.hover = event.hover; + var context = event.context, + connection = context.connection, + source = connection.source, + target = connection.target, + hover = event.hover, + type = context.type; - if (event.hover) { + // cache hover state + context.hover = hover; - // asks whether reconnect / bendpoint move / bendpoint add - // is allowed at the given position - var allowed = context.allowed = rules.allowed(context.type, context); + var allowed; - if (allowed) { - context.target = context.hover; - } + if (!hover) { + return; + } + + var command = type === 'updateWaypoints' ? 'connection.updateWaypoints' : 'connection.reconnect'; + + allowed = context.allowed = rules.allowed(command, { + connection: connection, + source: type === 'reconnectStart' ? hover : source, + target: type === 'reconnectEnd' ? hover : target + }); + + if (allowed) { + context.source = type === 'reconnectStart' ? hover : source; + context.target = type === 'reconnectEnd' ? hover : target; + + return; + } + + if (allowed === false) { + allowed = context.allowed = rules.allowed(command, { + connection: connection, + source: type === 'reconnectEnd' ? hover : target, + target: type === 'reconnectStart' ? hover : source + }); + } + + if (allowed) { + context.source = type === 'reconnectEnd' ? hover : target; + context.target = type === 'reconnectStart' ? hover : source; } }); eventBus.on([ 'bendpoint.move.out', 'bendpoint.move.cleanup' ], function(event) { var context = event.context; + context.hover = null; + context.source = null; context.target = null; + context.allowed = false; }); eventBus.on('bendpoint.move.end', function(event) { - var context = event.context, connection = context.connection, + source = context.source, + target = context.target, + type = context.type, originalWaypoints = connection.waypoints, newWaypoints = originalWaypoints.slice(), bendpointIndex = context.bendpointIndex, allowed = context.allowed, insert = context.insert, - bendpoint, hints; // ensure we have actual pixel values bendpoint // coordinates (important when zoom level was > 1 during move) - bendpoint = { + var docking = { x: round(event.x), y: round(event.y) }; - if (allowed && context.type === COMMAND_RECONNECT_START) { - modeling.reconnectStart(context.connection, context.target, bendpoint); - } else if (allowed && context.type === COMMAND_RECONNECT_END) { - modeling.reconnectEnd(context.connection, context.target, bendpoint); - } else if (allowed !== false && context.type === COMMAND_BENDPOINT_UPDATE) { + if (!allowed) { + return false; + } + + if (type === 'updateWaypoints') { if (insert) { // insert new bendpoint - newWaypoints.splice(bendpointIndex, 0, bendpoint); + newWaypoints.splice(bendpointIndex, 0, docking); } else { // swap previous waypoint with the moved one - newWaypoints[bendpointIndex] = bendpoint; + newWaypoints[bendpointIndex] = docking; } // pass hints on the actual moved bendpoint @@ -139,7 +172,23 @@ export default function BendpointMove(injector, eventBus, canvas, dragging, rule modeling.updateWaypoints(context.connection, filterRedundantWaypoints(newWaypoints), hints); } else { - return false; + + // TODO: not working + if (type === 'reconnectStart') { + newWaypoints = replaceFirst(newWaypoints, docking); + + if (isReverse(context)) { + newWaypoints = newWaypoints.reverse(); + } + } else if (type === 'reconnectEnd') { + newWaypoints = replaceLast(newWaypoints, docking); + + if (isReverse(context)) { + newWaypoints = newWaypoints.reverse(); + } + } + + modeling.reconnect(connection, source, target, newWaypoints); } }); } @@ -151,4 +200,34 @@ BendpointMove.$inject = [ 'dragging', 'rules', 'modeling' -]; \ No newline at end of file +]; + + +// helpers ////////// + +function isReverse(context) { + var hover = context.hover, + source = context.source, + target = context.target, + type = context.type; + + if (type === 'reconnectStart') { + return hover && target && hover === target; + } + + if (type === 'reconnectEnd') { + return hover && source && hover === source; + } +} + +function replaceFirst(array, item) { + array.splice(0, 1, item); + + return array; +} + +function replaceLast(array, item) { + array.splice(array.length - 1, 1, item); + + return array; +} \ No newline at end of file diff --git a/lib/features/bendpoints/BendpointMovePreview.js b/lib/features/bendpoints/BendpointMovePreview.js index c20c7421e..e698660b5 100644 --- a/lib/features/bendpoints/BendpointMovePreview.js +++ b/lib/features/bendpoints/BendpointMovePreview.js @@ -20,9 +20,6 @@ var MARKER_OK = 'connect-ok', MARKER_CONNECT_UPDATING = 'djs-updating', MARKER_ELEMENT_HIDDEN = 'djs-element-hidden'; -var COMMAND_RECONNECT_START = 'connection.reconnectStart', - COMMAND_RECONNECT_END = 'connection.reconnectEnd'; - var HIGH_PRIORITY = 1100; /** @@ -36,7 +33,6 @@ export default function BendpointMovePreview(injector, eventBus, canvas) { // DRAGGING IMPLEMENTATION eventBus.on('bendpoint.move.start', function(event) { - var context = event.context, connection = context.connection, originalWaypoints = connection.waypoints, @@ -67,15 +63,12 @@ export default function BendpointMovePreview(injector, eventBus, canvas) { var context = event.context, allowed = context.allowed, hover = context.hover, - moveType = context.type; + type = context.type; if (hover) { canvas.addMarker(hover, MARKER_CONNECT_HOVER); - if ( - moveType !== COMMAND_RECONNECT_START && - moveType !== COMMAND_RECONNECT_END - ) { + if (type === 'updateWaypoints') { return; } @@ -93,21 +86,22 @@ export default function BendpointMovePreview(injector, eventBus, canvas) { 'bendpoint.move.out', 'bendpoint.move.cleanup' ], HIGH_PRIORITY, function(event) { - - // remove connect marker - // if it was added - var hover = event.context.hover; + var context = event.context, + hover = context.hover, + target = context.target; if (hover) { canvas.removeMarker(hover, MARKER_CONNECT_HOVER); - canvas.removeMarker(hover, event.context.target ? MARKER_OK : MARKER_NOT_OK); + canvas.removeMarker(hover, target ? MARKER_OK : MARKER_NOT_OK); } }); eventBus.on('bendpoint.move.move', function(event) { - var context = event.context, - moveType = context.type, + allowed = context.allowed, + bendpointIndex = context.bendpointIndex, + hover = context.hover, + type = context.type, connection = event.connection, originalWaypoints = connection.waypoints, waypoints = originalWaypoints.slice(), @@ -120,16 +114,33 @@ export default function BendpointMovePreview(injector, eventBus, canvas) { target: connection.target }; - if (moveType === COMMAND_RECONNECT_START) { - hints.source = context.target; - hints.connectionStart = bendpoint; - } else if (moveType === COMMAND_RECONNECT_END) { - hints.target = context.target; - hints.connectionEnd = bendpoint; + if (type === 'reconnectStart') { + if (isReverse(context)) { + hints.connectionEnd = bendpoint; + hints.source = connection.target; + hints.target = hover; + + waypoints = waypoints.reverse(); + } else { + hints.connectionStart = bendpoint; + hints.source = hover; + } + } else if (type === 'reconnectEnd') { + if (isReverse(context)) { + hints.connectionStart = bendpoint; + hints.target = connection.source; + hints.source = hover; + + waypoints = waypoints.reverse(); + } else { + hints.connectionEnd = bendpoint; + hints.target = context.target; + } + } else { hints.noCropping = true; hints.noLayout = true; - waypoints[context.bendpointIndex] = bendpoint; + waypoints[ bendpointIndex ] = bendpoint; } if (connectionDocking) { @@ -148,7 +159,7 @@ export default function BendpointMovePreview(injector, eventBus, canvas) { // remove overlapping points hints.waypoints = filterRedundantWaypoints(waypoints); - connectionPreview.drawPreview(context, context.allowed, hints); + connectionPreview.drawPreview(context, allowed, hints); } // add dragger gfx @@ -159,10 +170,10 @@ export default function BendpointMovePreview(injector, eventBus, canvas) { 'bendpoint.move.end', 'bendpoint.move.cancel' ], HIGH_PRIORITY, function(event) { - var context = event.context, + connection = context.connection, hover = context.hover, - connection = context.connection; + target = context.target; // reassign original waypoints connection.waypoints = context.originalWaypoints; @@ -175,7 +186,7 @@ export default function BendpointMovePreview(injector, eventBus, canvas) { if (hover) { canvas.removeMarker(hover, MARKER_OK); - canvas.removeMarker(hover, context.target ? MARKER_OK : MARKER_NOT_OK); + canvas.removeMarker(hover, target ? MARKER_OK : MARKER_NOT_OK); } if (connectionPreview) { @@ -189,3 +200,21 @@ BendpointMovePreview.$inject = [ 'eventBus', 'canvas' ]; + + +// helpers ////////// + +function isReverse(context) { + var hover = context.hover, + source = context.source, + target = context.target, + type = context.type; + + if (type === 'reconnectStart') { + return hover && target && hover === target; + } + + if (type === 'reconnectEnd') { + return hover && source && hover === source; + } +} \ No newline at end of file diff --git a/lib/features/bendpoints/ConnectionSegmentMove.js b/lib/features/bendpoints/ConnectionSegmentMove.js index 442673c3e..91f988b9c 100644 --- a/lib/features/bendpoints/ConnectionSegmentMove.js +++ b/lib/features/bendpoints/ConnectionSegmentMove.js @@ -338,6 +338,7 @@ export default function ConnectionSegmentMove( eventBus.on('connectionSegment.move.hover', function(event) { event.context.hover = event.hover; + canvas.addMarker(event.hover, MARKER_CONNECT_HOVER); }); diff --git a/lib/features/connect/Connect.js b/lib/features/connect/Connect.js index 7cde32cf9..f1c62f451 100644 --- a/lib/features/connect/Connect.js +++ b/lib/features/connect/Connect.js @@ -2,6 +2,11 @@ import { getMid } from '../../layout/LayoutUtil'; +import { + isNil, + isObject +} from 'min-dash'; + export default function Connect(eventBus, dragging, modeling, rules) { @@ -14,43 +19,69 @@ export default function Connect(eventBus, dragging, modeling, rules) { }); } + function canConnectReverse(source, target) { + return canConnect(target, source); + } + // event handlers eventBus.on('connect.hover', function(event) { var context = event.context, - source = context.source, + start = context.start, hover = event.hover, canExecute; - canExecute = context.canExecute = canConnect(source, hover); + // cache hover state + context.hover = hover; + + canExecute = context.canExecute = canConnect(start, hover); + + // ignore hover + if (isNil(canExecute)) { + return; + } + + if (canExecute !== false) { + context.source = start; + context.target = hover; + + return; + } + + canExecute = context.canExecute = canConnectReverse(start, hover); - // simply ignore hover - if (canExecute === null) { + // ignore hover + if (isNil(canExecute)) { return; } - context.target = hover; + if (canExecute !== false) { + context.source = hover; + context.target = start; + } }); eventBus.on([ 'connect.out', 'connect.cleanup' ], function(event) { var context = event.context; + context.hover = null; + context.source = null; context.target = null; + context.canExecute = false; }); eventBus.on('connect.end', function(event) { - var context = event.context, - source = context.source, - sourcePosition = context.sourcePosition, - target = context.target, - targetPosition = { + canExecute = context.canExecute, + connectionStart = context.connectionStart, + connectionEnd = { x: event.x, y: event.y }, - canExecute = context.canExecute || canConnect(source, target); + source = context.source, + target = context.target; if (!canExecute) { return false; @@ -58,11 +89,11 @@ export default function Connect(eventBus, dragging, modeling, rules) { var attrs = null, hints = { - connectionStart: sourcePosition, - connectionEnd: targetPosition + connectionStart: isReverse(context) ? connectionEnd : connectionStart, + connectionEnd: isReverse(context) ? connectionStart : connectionEnd }; - if (typeof canExecute === 'object') { + if (isObject(canExecute)) { attrs = canExecute; } @@ -76,24 +107,23 @@ export default function Connect(eventBus, dragging, modeling, rules) { * Start connect operation. * * @param {DOMEvent} event - * @param {djs.model.Base} source - * @param {Point} [sourcePosition] - * @param {Boolean} [autoActivate=false] + * @param {djs.model.Base} start + * @param {Point} [connectionStart] + * @param {boolean} [autoActivate=false] */ - this.start = function(event, source, sourcePosition, autoActivate) { - - if (typeof sourcePosition !== 'object') { - autoActivate = sourcePosition; - sourcePosition = getMid(source); + this.start = function(event, start, connectionStart, autoActivate) { + if (!isObject(connectionStart)) { + autoActivate = connectionStart; + connectionStart = getMid(start); } dragging.init(event, 'connect', { autoActivate: autoActivate, data: { - shape: source, + shape: start, context: { - source: source, - sourcePosition: sourcePosition + start: start, + connectionStart: connectionStart } } }); @@ -106,3 +136,13 @@ Connect.$inject = [ 'modeling', 'rules' ]; + + +// helpers ////////// + +function isReverse(context) { + var hover = context.hover, + source = context.source; + + return hover && source && hover === source; +} \ No newline at end of file diff --git a/lib/features/connect/ConnectPreview.js b/lib/features/connect/ConnectPreview.js index fa38f2213..748490f04 100644 --- a/lib/features/connect/ConnectPreview.js +++ b/lib/features/connect/ConnectPreview.js @@ -16,19 +16,28 @@ export default function ConnectPreview(injector, eventBus, canvas) { connectionPreview && eventBus.on('connect.move', function(event) { var context = event.context, + canConnect = context.canExecute, + hover = context.hover, source = context.source, - target = context.target, - canConnect = context.canExecute; + start = context.start, + startPosition = context.startPosition, + target = context.target; - var endPosition = { + var connectionStart = isReverse(context) ? { + x: event.x, + y: event.y + } : startPosition; + + var connectionEnd = isReverse(context) ? startPosition : { x: event.x, y: event.y }; connectionPreview.drawPreview(context, canConnect, { - source: source, - target: target, - connectionEnd: endPosition + source: source || start, + target: target || hover, + connectionStart: connectionStart, + connectionEnd: connectionEnd }); }); @@ -45,12 +54,15 @@ export default function ConnectPreview(injector, eventBus, canvas) { canvas.addMarker(hover, canExecute ? MARKER_OK : MARKER_NOT_OK); }); - eventBus.on([ 'connect.out', 'connect.cleanup' ], HIGH_PRIORITY, function(event) { - var context = event.context; + eventBus.on([ + 'connect.out', + 'connect.cleanup' + ], HIGH_PRIORITY, function(event) { + var hover = event.hover; - // remove marker before target is removed from context - if (context.target) { - canvas.removeMarker(context.target, context.canExecute ? MARKER_OK : MARKER_NOT_OK); + if (hover) { + canvas.removeMarker(hover, MARKER_OK); + canvas.removeMarker(hover, MARKER_NOT_OK); } }); @@ -64,3 +76,12 @@ ConnectPreview.$inject = [ 'eventBus', 'canvas' ]; + +// helpers ////////// + +function isReverse(context) { + var hover = context.hover, + source = context.source; + + return hover && source && hover === source; +} diff --git a/lib/features/modeling/Modeling.js b/lib/features/modeling/Modeling.js index a28249248..724e010a9 100644 --- a/lib/features/modeling/Modeling.js +++ b/lib/features/modeling/Modeling.js @@ -75,9 +75,12 @@ Modeling.prototype.getHandlers = function() { 'connection.updateWaypoints': UpdateWaypointsHandler, + // TODO: remove 'connection.reconnectStart': ReconnectConnectionHandler, 'connection.reconnectEnd': ReconnectConnectionHandler, + 'connection.reconnect': ReconnectConnectionHandler, + 'elements.create': CreateElementsHandler, 'elements.move': MoveElementsHandler, 'elements.delete': DeleteElementsHandler, @@ -466,6 +469,18 @@ Modeling.prototype.updateWaypoints = function(connection, newWaypoints, hints) { this._commandStack.execute('connection.updateWaypoints', context); }; +Modeling.prototype.reconnect = function(connection, source, target, waypoints, hints) { + var context = { + connection: connection, + newSource: source, + newTarget: target, + dockingOrPoints: waypoints, + hints: hints || {} + }; + + this._commandStack.execute('connection.reconnect', context); +}; + Modeling.prototype.reconnectStart = function(connection, newSource, dockingOrPoints, hints) { var context = { connection: connection, diff --git a/lib/features/modeling/cmd/ReconnectConnectionHandler.js b/lib/features/modeling/cmd/ReconnectConnectionHandler.js index 85d2a0ff9..cd0ade47a 100644 --- a/lib/features/modeling/cmd/ReconnectConnectionHandler.js +++ b/lib/features/modeling/cmd/ReconnectConnectionHandler.js @@ -11,20 +11,11 @@ export default function ReconnectConnectionHandler(modeling) { ReconnectConnectionHandler.$inject = [ 'modeling' ]; ReconnectConnectionHandler.prototype.execute = function(context) { - var newSource = context.newSource, newTarget = context.newTarget, connection = context.connection, dockingOrPoints = context.dockingOrPoints; - if (!newSource && !newTarget) { - throw new Error('newSource or newTarget are required'); - } - - if (newSource && newTarget) { - throw new Error('must specify either newSource or newTarget'); - } - if (isArray(dockingOrPoints)) { context.oldWaypoints = connection.waypoints; connection.waypoints = dockingOrPoints; @@ -45,30 +36,29 @@ ReconnectConnectionHandler.prototype.execute = function(context) { ReconnectConnectionHandler.prototype.postExecute = function(context) { var connection = context.connection, - dockingOrPoints = context.dockingOrPoints, newSource = context.newSource, - movedEnd = newSource ? 'connectionStart' : 'connectionEnd', - newWaypoint, - hints = context.hints, - layoutHints = {}; + newTarget = context.newTarget, + dockingOrPoints = context.dockingOrPoints, + hints = context.hints; if (hints.layoutConnection === false) { return; } - if (isArray(dockingOrPoints)) { - newWaypoint = newSource ? dockingOrPoints[0] : dockingOrPoints[dockingOrPoints.length - 1]; - } else { - newWaypoint = dockingOrPoints; + var layoutHints = {}; + + if (newSource) { + layoutHints.connectionStart = getDocking(isArray(dockingOrPoints) ? dockingOrPoints[ 0 ] : dockingOrPoints); } - layoutHints[movedEnd] = getDocking(newWaypoint); + if (newTarget) { + layoutHints.connectionEnd = getDocking(isArray(dockingOrPoints) ? dockingOrPoints[ dockingOrPoints.length - 1 ] : dockingOrPoints); + } this._modeling.layoutConnection(connection, layoutHints); }; ReconnectConnectionHandler.prototype.revert = function(context) { - var oldSource = context.oldSource, oldTarget = context.oldTarget, oldWaypoints = context.oldWaypoints, @@ -91,7 +81,7 @@ ReconnectConnectionHandler.prototype.revert = function(context) { -// helper /////////////// +// helpers ////////// function getDocking(point) { return point.original || point; diff --git a/lib/features/modeling/cmd/ReplaceShapeHandler.js b/lib/features/modeling/cmd/ReplaceShapeHandler.js index e964bf0a9..60ad6f63d 100644 --- a/lib/features/modeling/cmd/ReplaceShapeHandler.js +++ b/lib/features/modeling/cmd/ReplaceShapeHandler.js @@ -43,8 +43,10 @@ ReplaceShapeHandler.prototype.preExecute = function(context) { hints = context.hints, newShape; - function canReconnect(type, source, target, connection) { - return rules.allowed(type, { + function canReconnect(source, target, connection) { + + // TODO(nikku) -> swap : testcover this + return rules.allowed('connection.reconnect', { source: source, target: target, connection: connection @@ -90,7 +92,7 @@ ReplaceShapeHandler.prototype.preExecute = function(context) { var waypoints = connection.waypoints, docking = waypoints[waypoints.length - 1], source = connection.source, - allowed = canReconnect('connection.reconnectEnd', source, newShape, connection); + allowed = canReconnect(source, newShape, connection); if (allowed) { self.reconnectEnd(connection, newShape, docking, { layoutConnection: hints.layoutConnection }); @@ -101,7 +103,7 @@ ReplaceShapeHandler.prototype.preExecute = function(context) { var waypoints = connection.waypoints, docking = waypoints[0], target = connection.target, - allowed = canReconnect('connection.reconnectStart', newShape, target, connection); + allowed = canReconnect(newShape, target, connection); if (allowed) { self.reconnectStart(connection, newShape, docking, { layoutConnection: hints.layoutConnection }); diff --git a/test/spec/features/attach-support/rules/AttachRules.js b/test/spec/features/attach-support/rules/AttachRules.js index fed9dc0ea..bb8bcf7c3 100644 --- a/test/spec/features/attach-support/rules/AttachRules.js +++ b/test/spec/features/attach-support/rules/AttachRules.js @@ -44,18 +44,22 @@ AttachRules.prototype.init = function() { } }); - this.addRule('connection.reconnectEnd', function(context) { - if (context.target.host.parent.id === 'parent') { - return false; - } - return true; - }); + this.addRule('connection.reconnect', function(context) { - this.addRule('connection.reconnectStart', function(context) { - if (context.source.host.parent.id === 'parent') { - return false; + // do not allow reconnection to element + // that is attached to #parent element + + var source = context.source, + target = context.target; + + function isChildOfElementWithIdParent(element) { + return element && element.parent.id === 'parent'; } - return true; + + return ![ + source.host, + target.host + ].some(isChildOfElementWithIdParent); }); // restrict resizing only for hosts (defaults to allow all) diff --git a/test/spec/features/bendpoints/BendpointsMoveSpec.js b/test/spec/features/bendpoints/BendpointsMoveSpec.js index 46035c050..4e85c62c0 100755 --- a/test/spec/features/bendpoints/BendpointsMoveSpec.js +++ b/test/spec/features/bendpoints/BendpointsMoveSpec.js @@ -304,8 +304,11 @@ describe('features/bendpoints - move', function() { inject(function(eventBus, bendpointMove, dragging) { // given - var rule = sinon.stub().returns(false); - eventBus.on('commandStack.connection.reconnectEnd.canExecute', Infinity, rule); + function rule() { + return false; + } + + eventBus.on('commandStack.connection.reconnect.canExecute', Infinity, rule); // when bendpointMove.start(canvasEvent({ x: 500, y: 500 }), connection, 2); diff --git a/test/spec/features/bendpoints/rules/BendpointRules.js b/test/spec/features/bendpoints/rules/BendpointRules.js index 32a1bc952..2a4995b64 100755 --- a/test/spec/features/bendpoints/rules/BendpointRules.js +++ b/test/spec/features/bendpoints/rules/BendpointRules.js @@ -13,22 +13,16 @@ inherits(ConnectRules, RuleProvider); ConnectRules.prototype.init = function() { - function isSameType(connection, newSource, newTarget) { - var source = newSource || connection.source, - target = newTarget || connection.target; + this.addRule('connection.reconnect', function(context) { - return source.type === target.type; - } + var source = context.source, + target = context.target; - this.addRule('connection.reconnectStart', function(context) { - return isSameType(context.connection, context.hover); + return source.type === target.type; }); this.addRule('connection.updateWaypoints', function(context) { return true; }); - this.addRule('connection.reconnectEnd', function(context) { - return isSameType(context.connection, null, context.hover); - }); }; \ No newline at end of file diff --git a/test/spec/features/connect/ConnectSpec.js b/test/spec/features/connect/ConnectSpec.js index 352cbbb34..2affd8d6b 100755 --- a/test/spec/features/connect/ConnectSpec.js +++ b/test/spec/features/connect/ConnectSpec.js @@ -16,6 +16,8 @@ import rulesModule from './rules'; import connectModule from 'lib/features/connect'; import connectionPreviewModule from 'lib/features/connection-preview'; +import { getMid } from 'lib/layout/LayoutUtil'; + var testModules = [ modelingModule, @@ -26,13 +28,13 @@ var testModules = [ describe('features/connect', function() { - var rootShape, shape1, shape2, shape1child, shapeFrame; + var rootShape, shape1, shape2, shape1Gfx, shape2Gfx, shape1child, shapeFrame; function setManualDragging(dragging) { dragging.setOptions({ manual: true }); } - function setupDiagram(elementFactory, canvas) { + function setupDiagram(canvas, elementFactory) { rootShape = elementFactory.createRoot({ id: 'root' @@ -47,6 +49,8 @@ describe('features/connect', function() { canvas.addShape(shape1, rootShape); + shape1Gfx = canvas.getGraphics(shape1); + shape2 = elementFactory.createShape({ id: 's2', x: 500, y: 100, width: 100, height: 100 @@ -54,6 +58,7 @@ describe('features/connect', function() { canvas.addShape(shape2, rootShape); + shape2Gfx = canvas.getGraphics(shape2); shape1child = elementFactory.createShape({ id: 's3', @@ -87,22 +92,44 @@ describe('features/connect', function() { it('should connect if allowed', inject(function(connect, dragging) { // when - connect.start(canvasEvent({ x: 0, y: 0 }), shape1); + connect.start(canvasEvent(getMid(shape1)), shape1, true); - dragging.move(canvasEvent({ x: 40, y: 30 })); + dragging.move(canvasEvent(getMid(shape2))); + + dragging.hover({ element: shape2, gfx: shape2Gfx }); - dragging.hover(canvasEvent({ x: 10, y: 10 }, { element: shape2 })); dragging.end(); var newConnection = shape1.outgoing[0]; // then expect(newConnection).to.exist; + expect(newConnection.source).to.equal(shape1); expect(newConnection.target).to.equal(shape2); })); - it('should not connect if rejected', inject(function(connect, rules, dragging) { + it('should connect reverse if allowed', inject(function(connect, dragging) { + + // when + connect.start(canvasEvent(getMid(shape2)), shape2, true); + + dragging.move(canvasEvent(getMid(shape1))); + + dragging.hover({ element: shape1, gfx: shape1Gfx }); + + dragging.end(); + + var newConnection = shape2.outgoing[0]; + + // then + expect(newConnection).to.exist; + expect(newConnection.source).to.equal(shape2); + expect(newConnection.target).to.equal(shape1); + })); + + + it('should NOT connect if not allowed', inject(function(connect, rules, dragging) { // assume var context = { @@ -125,7 +152,7 @@ describe('features/connect', function() { })); - it('should not connect with null target', inject(function(connect, rules, dragging) { + it('should NOT connect if no target', inject(function(connect, rules, dragging) { // when connect.start(canvasEvent({ x: 0, y: 0 }), shape1); diff --git a/test/spec/features/connect/rules/ConnectRules.js b/test/spec/features/connect/rules/ConnectRules.js index d7483f39d..f98093f0b 100755 --- a/test/spec/features/connect/rules/ConnectRules.js +++ b/test/spec/features/connect/rules/ConnectRules.js @@ -21,7 +21,7 @@ ConnectRules.prototype.init = function() { var source = context.source, target = context.target; - if (isFrameElement(target)) { + if (isFrameElement(source) || isFrameElement(target)) { return false; } diff --git a/test/spec/features/global-connect/GlobalConnectSpec.js b/test/spec/features/global-connect/GlobalConnectSpec.js index 2c41a1c9d..2e84d1879 100644 --- a/test/spec/features/global-connect/GlobalConnectSpec.js +++ b/test/spec/features/global-connect/GlobalConnectSpec.js @@ -55,8 +55,8 @@ describe('features/global-connect-tool', function() { var shape = shapeAbleToStartConnection; var connectSpy = sinon.spy(function(event) { expect(event.context).to.eql({ - source: shape, - sourcePosition: { x: 150, y: 130 } + start: shape, + startPosition: { x: 150, y: 130 } }); });