diff --git a/js/id/actions/actions.js b/js/id/actions/actions.js
index 593e33d3f..b27c8fbc2 100644
--- a/js/id/actions/actions.js
+++ b/js/id/actions/actions.js
@@ -20,9 +20,19 @@ iD.actions.startWay = function(way) {
};
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
-iD.actions.remove = function(node) {
+iD.actions.remove = function(entity) {
return function(graph) {
- return graph.remove(node, 'removed a feature');
+ graph.parentWays(entity.id)
+ .forEach(function(parent) {
+ graph = iD.actions.removeWayNode(parent, entity)(graph);
+ });
+
+ graph.parentRelations(entity.id)
+ .forEach(function(parent) {
+ graph = iD.actions.removeRelationEntity(parent, entity)(graph);
+ });
+
+ return graph.remove(entity, 'removed a feature');
};
};
@@ -42,6 +52,13 @@ iD.actions.removeWayNode = function(way, node) {
};
};
+iD.actions.removeRelationEntity = function(relation, entity) {
+ return function(graph) {
+ var members = _.without(relation.members, entity.id);
+ return graph.replace(relation.update({members: members}), 'removed from a relation');
+ };
+};
+
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
iD.actions.changeWayDirection = function(way) {
return function(graph) {
diff --git a/js/id/graph/graph.js b/js/id/graph/graph.js
index c829f9a60..8d4d2b666 100644
--- a/js/id/graph/graph.js
+++ b/js/id/graph/graph.js
@@ -15,11 +15,17 @@ iD.Graph.prototype = {
return this.entities[id];
},
- parents: function(id) {
+ parentWays: function(id) {
// This is slow and a bad hack.
return _.filter(this.entities, function(e) {
- if (e.type !== 'way') return false;
- return e.nodes.indexOf(id) !== -1;
+ return e.type === 'way' && e.nodes.indexOf(id) !== -1;
+ });
+ },
+
+ parentRelations: function(id) {
+ // This is slow and a bad hack.
+ return _.filter(this.entities, function(e) {
+ return e.type === 'relation' && e.members.indexOf(id) !== -1;
});
},
diff --git a/js/id/modes/add_road.js b/js/id/modes/add_road.js
index 32a6a7f4e..f353cc3e8 100644
--- a/js/id/modes/add_road.js
+++ b/js/id/modes/add_road.js
@@ -21,7 +21,7 @@ iD.modes.AddRoad = function() {
node = datum;
var id = datum.id;
- var parents = mode.history.graph().parents(id);
+ var parents = mode.history.graph().parentWays(id);
if (parents.length) {
if (parents[0].nodes[0] === id) {
way = parents[0];
diff --git a/js/id/modes/select.js b/js/id/modes/select.js
index b650ac561..de7e0de7b 100644
--- a/js/id/modes/select.js
+++ b/js/id/modes/select.js
@@ -15,7 +15,7 @@ iD.modes.Select = function (entity) {
if (!dragging) {
dragging = iD.util.trueObj([entity.id].concat(
- _.pluck(mode.history.graph().parents(entity.id), 'id')));
+ _.pluck(mode.history.graph().parentWays(entity.id), 'id')));
mode.history.perform(iD.actions.noop());
}
@@ -33,12 +33,6 @@ iD.modes.Select = function (entity) {
});
function remove() {
- // Remove this node from any ways that is a member of
- mode.history.graph().parents(entity.id)
- .filter(function(d) { return d.type === 'way'; })
- .forEach(function(parent) {
- mode.history.perform(iD.actions.removeWayNode(parent, entity));
- });
mode.history.perform(iD.actions.remove(entity));
mode.controller.exit();
}
diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js
index fd018df45..85f9faaae 100644
--- a/js/id/renderer/map.js
+++ b/js/id/renderer/map.js
@@ -30,7 +30,7 @@ iD.Map = function() {
}
dragging = iD.util.trueObj([entity.id].concat(
- _.pluck(history.graph().parents(entity.id), 'id')));
+ _.pluck(history.graph().parentWays(entity.id), 'id')));
history.perform(iD.actions.noop());
}
diff --git a/test/index.html b/test/index.html
index 340b68903..9bbb4bd31 100644
--- a/test/index.html
+++ b/test/index.html
@@ -73,6 +73,7 @@
+
diff --git a/test/index_packaged.html b/test/index_packaged.html
index 3cab98faa..2649c9d31 100644
--- a/test/index_packaged.html
+++ b/test/index_packaged.html
@@ -27,6 +27,7 @@
+
diff --git a/test/spec/actions/remove.js b/test/spec/actions/remove.js
new file mode 100644
index 000000000..b34048f9c
--- /dev/null
+++ b/test/spec/actions/remove.js
@@ -0,0 +1,24 @@
+describe("iD.actions.remove", function () {
+ it("removes the entity from the graph", function () {
+ var entity = iD.Way(),
+ action = iD.actions.remove(entity),
+ graph = action(iD.Graph().replace(entity));
+ expect(graph.entity(entity.id)).to.be.undefined;
+ });
+
+ it("removes a node from parent ways", function () {
+ var node = iD.Node(),
+ way = iD.Way().update({nodes: [node.id]}),
+ action = iD.actions.remove(node),
+ graph = action(iD.Graph().replace(node).replace(way));
+ expect(graph.entity(way.id).nodes).not.to.contain(node.id);
+ });
+
+ it("removes a way from parent relations", function () {
+ var way = iD.Way(),
+ relation = iD.Relation().update({members: [way.id]}),
+ action = iD.actions.remove(way),
+ graph = action(iD.Graph().replace(way).replace(relation));
+ expect(graph.entity(relation.id).members).not.to.contain(way.id);
+ });
+});
diff --git a/test/spec/graph/graph.js b/test/spec/graph/graph.js
index bd12753e0..e41f36bf6 100644
--- a/test/spec/graph/graph.js
+++ b/test/spec/graph/graph.js
@@ -50,6 +50,26 @@ describe('Graph', function() {
});
});
+ describe("#parentWays", function() {
+ it("returns an array of ways that contain the given node id", function () {
+ var node = iD.Node({id: "n1"}),
+ way = iD.Way({id: "w1", nodes: ["n1"]}),
+ graph = iD.Graph({n1: node, w1: way});
+ expect(graph.parentWays("n1")).to.eql([way]);
+ expect(graph.parentWays("n2")).to.eql([]);
+ });
+ });
+
+ describe("#parentRelations", function() {
+ it("returns an array of relations that contain the given entity id", function () {
+ var node = iD.Node({id: "n1"}),
+ relation = iD.Relation({id: "r1", members: ["n1"]}),
+ graph = iD.Graph({n1: node, r1: relation});
+ expect(graph.parentRelations("n1")).to.eql([relation]);
+ expect(graph.parentRelations("n2")).to.eql([]);
+ });
+ });
+
describe("#fetch", function () {
it("replaces node ids with references", function () {
var node = iD.Node({id: "n1"}),