From 7a0d0352d23b82e65b0708c981b92bf26005c152 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 14 Apr 2018 23:12:53 -0400 Subject: [PATCH] Use `connection.disabled` to prevent dragging from breaking a relation (closes #4921) --- modules/modes/drag_node.js | 81 +++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/modules/modes/drag_node.js b/modules/modes/drag_node.js index 04e875014..f726b9dbb 100644 --- a/modules/modes/drag_node.js +++ b/modules/modes/drag_node.js @@ -119,7 +119,9 @@ export function modeDragNode(context) { if (_isCancelled) { if (hasHidden) { - uiFlash().text(t('modes.drag_node.connected_to_hidden'))(); + uiFlash() + .duration(4000) + .text(t('modes.drag_node.connected_to_hidden'))(); } return drag.cancel(); } @@ -178,14 +180,15 @@ export function modeDragNode(context) { var target = d && d.properties && d.properties.entity; var targetLoc = target && target.loc; var targetNodes = d && d.properties && d.properties.nodes; + var edge; if (targetLoc) { // snap to node/vertex - a point target with `.loc` loc = targetLoc; } else if (targetNodes) { // snap to way - a line target with `.nodes` - var choice = geoChooseEdge(targetNodes, context.mouse(), context.projection, end.id); - if (choice) { - loc = choice.loc; + edge = geoChooseEdge(targetNodes, context.mouse(), context.projection, end.id); + if (edge) { + loc = edge.loc; } } } @@ -200,17 +203,33 @@ export function modeDragNode(context) { // Check if this connection to `target` could cause relations to break.. if (target) { - isInvalid = isRelationConflict([entity.id, target.id], context.graph()); - if (isInvalid && !context.surface().classed('nope')) { - uiFlash().text(t('operations.connect.relation'))(); - } + isInvalid = hasRelationConflict(entity, target, edge, context.graph()); } // Check if this drag causes the geometry to break.. if (!isInvalid) { - isInvalid = isInvalidGeometry(entity, context.graph()); + isInvalid = hasInvalidGeometry(entity, context.graph()); } + + var nope = context.surface().classed('nope'); + if (isInvalid === 'relation' || isInvalid === 'restriction') { + if (!nope) { // about to nope - show hint + uiFlash() + .duration(4000) + .text(t('operations.connect.' + isInvalid, + { relation: context.presets().item('type/restriction').name() } + ))(); + } + } else { + if (nope) { // about to un-nope, remove hint + uiFlash() + .duration(1) + .text('')(); + } + } + + var nopeDisabled = context.surface().classed('nope-disabled'); if (nopeDisabled) { context.surface() @@ -226,39 +245,29 @@ export function modeDragNode(context) { } - // See also actionConnect.disabled() - // (similar, but this code can also check node-way) - function isRelationConflict(ids, graph) { - var seen = {}; + // Uses `actionConnect.disabled()` to know whether this connection is ok.. + function hasRelationConflict(entity, target, edge, graph) { + var testGraph = graph.update(); // copy - for (var i = 0; i < ids.length; i++) { - var ent1 = graph.entity(ids[i]); + // if snapping to way - add midpoint there and consider that the target.. + if (edge) { + var midpoint = osmNode(); + var action = actionAddMidpoint({ + loc: edge.loc, + edge: [target.nodes[edge.index - 1], target.nodes[edge.index]] + }, midpoint); - var toCheck = [ent1]; - if (ent1.type === 'node') { - toCheck = toCheck.concat(graph.parentWays(ent1)); - } - for (var j = 0; j < toCheck.length; j++) { - var ent2 = toCheck[j]; - - var relations = graph.parentRelations(ent2); - for (var k = 0; k < relations.length; k++) { - var relation = relations[k]; - var role = relation.memberById(ent2.id).role || ''; - - if (seen[relation.id] !== undefined && seen[relation.id] !== role) { - return 'relation'; - } else { - seen[relation.id] = role; - } - } - } + testGraph = action(testGraph); + target = midpoint; } - return false; + + // can we connect to it? + var ids = [entity.id, target.id]; + return actionConnect(ids).disabled(testGraph); } - function isInvalidGeometry(entity, graph) { + function hasInvalidGeometry(entity, graph) { var parents = graph.parentWays(entity); var i, j, k;