diff --git a/index.html b/index.html
index 93c5171a6..69f83f76b 100644
--- a/index.html
+++ b/index.html
@@ -71,7 +71,6 @@
-
@@ -80,12 +79,9 @@
-
-
-
diff --git a/js/id/actions/add_relation_member.js b/js/id/actions/add_relation_member.js
deleted file mode 100644
index 45e24a0b0..000000000
--- a/js/id/actions/add_relation_member.js
+++ /dev/null
@@ -1,9 +0,0 @@
-iD.actions.AddRelationMember = function(relationId, member, index) {
- return function(graph) {
- var relation = graph.entity(relationId),
- members = relation.members.slice();
-
- members.splice((index === undefined) ? members.length : index, 0, member);
- return graph.replace(relation.update({members: members}));
- };
-};
diff --git a/js/id/actions/add_way_node.js b/js/id/actions/add_way_node.js
index d685c3295..3e4fffcfc 100644
--- a/js/id/actions/add_way_node.js
+++ b/js/id/actions/add_way_node.js
@@ -1,10 +1,6 @@
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
iD.actions.AddWayNode = function(wayId, nodeId, index) {
return function(graph) {
- var way = graph.entity(wayId),
- node = graph.entity(nodeId),
- nodes = way.nodes.slice();
- nodes.splice((index === undefined) ? nodes.length : index, 0, nodeId);
- return graph.replace(way.update({nodes: nodes}));
+ return graph.replace(graph.entity(wayId).addNode(nodeId, index));
};
};
diff --git a/js/id/actions/delete_node.js b/js/id/actions/delete_node.js
index a2d54fecb..a93129ce3 100644
--- a/js/id/actions/delete_node.js
+++ b/js/id/actions/delete_node.js
@@ -5,12 +5,17 @@ iD.actions.DeleteNode = function(nodeId) {
graph.parentWays(node)
.forEach(function(parent) {
- graph = iD.actions.RemoveWayNode(parent.id, nodeId)(graph);
+ parent = parent.removeNode(nodeId);
+ graph = graph.replace(parent);
+
+ if (parent.isDegenerate()) {
+ graph = iD.actions.DeleteWay(parent.id)(graph);
+ }
});
graph.parentRelations(node)
.forEach(function(parent) {
- graph = iD.actions.RemoveRelationMember(parent.id, nodeId)(graph);
+ graph = graph.replace(parent.removeMember(nodeId));
});
return graph.remove(node);
diff --git a/js/id/actions/delete_way.js b/js/id/actions/delete_way.js
index c2065a756..19e9e7c2a 100644
--- a/js/id/actions/delete_way.js
+++ b/js/id/actions/delete_way.js
@@ -5,7 +5,7 @@ iD.actions.DeleteWay = function(wayId) {
graph.parentRelations(way)
.forEach(function(parent) {
- graph = iD.actions.RemoveRelationMember(parent.id, wayId)(graph);
+ graph = graph.replace(parent.removeMember(wayId));
});
way.nodes.forEach(function (nodeId) {
@@ -15,7 +15,7 @@ iD.actions.DeleteWay = function(wayId) {
// can be deleted on earlier iterations of this loop.
if (!node) return;
- graph = iD.actions.RemoveWayNode(wayId, nodeId)(graph);
+ graph = graph.replace(way.removeNode(nodeId));
if (!graph.parentWays(node).length &&
!graph.parentRelations(node).length) {
diff --git a/js/id/actions/move_node.js b/js/id/actions/move_node.js
index 9204fcb67..433242ff6 100644
--- a/js/id/actions/move_node.js
+++ b/js/id/actions/move_node.js
@@ -2,7 +2,6 @@
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
iD.actions.MoveNode = function(nodeId, loc) {
return function(graph) {
- var node = graph.entity(nodeId);
- return graph.replace(node.update({loc: loc}));
+ return graph.replace(graph.entity(nodeId).move(loc));
};
};
diff --git a/js/id/actions/move_way.js b/js/id/actions/move_way.js
index ea547cc44..09ab8fd50 100644
--- a/js/id/actions/move_way.js
+++ b/js/id/actions/move_way.js
@@ -6,7 +6,7 @@ iD.actions.MoveWay = function(wayId, delta, projection) {
var node = graph.entity(id),
start = projection(node.loc),
end = projection.invert([start[0] + delta[0], start[1] + delta[1]]);
- graph = iD.actions.MoveNode(id, end)(graph);
+ graph = graph.replace(node.move(end));
});
return graph;
diff --git a/js/id/actions/remove_relation_member.js b/js/id/actions/remove_relation_member.js
deleted file mode 100644
index e72dd7ca0..000000000
--- a/js/id/actions/remove_relation_member.js
+++ /dev/null
@@ -1,9 +0,0 @@
-iD.actions.RemoveRelationMember = function(relationId, memberId) {
- return function(graph) {
- var relation = graph.entity(relationId),
- members = _.reject(relation.members, function(r) {
- return r.id === memberId;
- });
- return graph.replace(relation.update({members: members}));
- };
-};
diff --git a/js/id/actions/remove_way_node.js b/js/id/actions/remove_way_node.js
deleted file mode 100644
index 8c589a20c..000000000
--- a/js/id/actions/remove_way_node.js
+++ /dev/null
@@ -1,17 +0,0 @@
-iD.actions.RemoveWayNode = function(wayId, nodeId) {
- return function(graph) {
- var way = graph.entity(wayId), nodes;
- // If this is the connecting node in a closed area
- if (way.nodes.length > 1 &&
- _.indexOf(way.nodes, nodeId) === 0 &&
- _.lastIndexOf(way.nodes, nodeId) === way.nodes.length - 1) {
- // Remove the node
- nodes = _.without(way.nodes, nodeId);
- // And reclose the way on the new first node.
- nodes.push(nodes[0]);
- } else {
- nodes = _.without(way.nodes, nodeId);
- }
- return graph.replace(way.update({nodes: nodes}));
- };
-};
diff --git a/js/id/actions/reverse_way.js b/js/id/actions/reverse_way.js
index a845fe844..160017637 100644
--- a/js/id/actions/reverse_way.js
+++ b/js/id/actions/reverse_way.js
@@ -65,7 +65,8 @@ iD.actions.ReverseWay = function(wayId) {
graph.parentRelations(way).forEach(function (relation) {
relation.members.forEach(function (member, index) {
if (member.id === way.id && (role = {forward: 'backward', backward: 'forward'}[member.role])) {
- graph = iD.actions.UpdateRelationMember(relation.id, {role: role}, index)(graph);
+ relation = relation.updateMember({role: role}, index);
+ graph = graph.replace(relation);
}
});
});
diff --git a/js/id/actions/split_way.js b/js/id/actions/split_way.js
index d716880cf..f6d502b97 100644
--- a/js/id/actions/split_way.js
+++ b/js/id/actions/split_way.js
@@ -37,11 +37,8 @@ iD.actions.SplitWay = function(nodeId, newWayId) {
if (relation.isRestriction()) {
var via = relation.memberByRole('via');
if (via && newWay.contains(via.id)) {
- graph = iD.actions.UpdateRelationMember(
- relation.id,
- {id: newWay.id},
- relation.memberById(way.id).index
- )(graph);
+ relation = relation.updateMember({id: newWay.id}, relation.memberById(way.id).index);
+ graph = graph.replace(relation);
}
} else {
var role = relation.memberById(way.id).role,
@@ -55,11 +52,8 @@ iD.actions.SplitWay = function(nodeId, newWayId) {
}
}
- graph = iD.actions.AddRelationMember(
- relation.id,
- {id: newWay.id, type: 'way', role: role},
- i <= j ? i + 1 : i
- )(graph);
+ relation = relation.addMember({id: newWay.id, type: 'way', role: role}, i <= j ? i + 1 : i);
+ graph = graph.replace(relation);
}
});
diff --git a/js/id/actions/unjoin_node.js b/js/id/actions/unjoin_node.js
index 4bc7a5ca7..037c56137 100644
--- a/js/id/actions/unjoin_node.js
+++ b/js/id/actions/unjoin_node.js
@@ -20,13 +20,10 @@ iD.actions.UnjoinNode = function(nodeId, newNodeId) {
return;
var index = parent.nodes.indexOf(nodeId),
- newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags}),
- nodes = parent.nodes.slice();
-
- nodes.splice(index, 1, newNode.id);
+ newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags});
graph = graph.replace(newNode);
- graph = graph.replace(parent.update({nodes: nodes}));
+ graph = graph.replace(parent.updateNode(newNode.id, index));
});
return graph;
diff --git a/js/id/actions/update_relation_member.js b/js/id/actions/update_relation_member.js
deleted file mode 100644
index 29eb79afe..000000000
--- a/js/id/actions/update_relation_member.js
+++ /dev/null
@@ -1,9 +0,0 @@
-iD.actions.UpdateRelationMember = function(relationId, properties, index) {
- return function(graph) {
- var relation = graph.entity(relationId),
- members = relation.members.slice();
-
- members.splice(index, 1, _.extend({}, members[index], properties));
- return graph.replace(relation.update({members: members}));
- };
-};
diff --git a/js/id/graph/node.js b/js/id/graph/node.js
index d72bf6442..df9c253a4 100644
--- a/js/id/graph/node.js
+++ b/js/id/graph/node.js
@@ -17,5 +17,9 @@ _.extend(iD.Node.prototype, {
geometry: function() {
return this._poi ? 'point' : 'vertex';
+ },
+
+ move: function(loc) {
+ return this.update({loc: loc});
}
});
diff --git a/js/id/graph/relation.js b/js/id/graph/relation.js
index 2dd325438..48a86c920 100644
--- a/js/id/graph/relation.js
+++ b/js/id/graph/relation.js
@@ -48,6 +48,23 @@ _.extend(iD.Relation.prototype, {
}
},
+ addMember: function(member, index) {
+ var members = this.members.slice();
+ members.splice(index === undefined ? members.length : index, 0, member);
+ return this.update({members: members});
+ },
+
+ updateMember: function(member, index) {
+ var members = this.members.slice();
+ members.splice(index, 1, _.extend({}, members[index], member));
+ return this.update({members: members});
+ },
+
+ removeMember: function(id) {
+ var members = _.reject(this.members, function(m) { return m.id === id; });
+ return this.update({members: members});
+ },
+
isRestriction: function() {
return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
},
diff --git a/js/id/graph/way.js b/js/id/graph/way.js
index 35834e761..0de0e55a1 100644
--- a/js/id/graph/way.js
+++ b/js/id/graph/way.js
@@ -58,7 +58,34 @@ _.extend(iD.Way.prototype, {
!this.tags.barrier);
},
+ isDegenerate: function() {
+ return _.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
+ },
+
geometry: function() {
return this.isArea() ? 'area' : 'line';
+ },
+
+ addNode: function(id, index) {
+ var nodes = this.nodes.slice();
+ nodes.splice(index === undefined ? nodes.length : index, 0, id);
+ return this.update({nodes: nodes});
+ },
+
+ updateNode: function(id, index) {
+ var nodes = this.nodes.slice();
+ nodes.splice(index, 1, id);
+ return this.update({nodes: nodes});
+ },
+
+ removeNode: function(id) {
+ var nodes = _.without(this.nodes, id);
+
+ // Preserve circularity
+ if (this.nodes.length > 1 && this.first() === id && this.last() === id) {
+ nodes.push(nodes[0]);
+ }
+
+ return this.update({nodes: nodes});
}
});
diff --git a/js/id/id.js b/js/id/id.js
index 9d7fb38bf..3646ba074 100644
--- a/js/id/id.js
+++ b/js/id/id.js
@@ -192,7 +192,7 @@ window.iD = function(container) {
.on('⌃+Z', function() { history.undo(); })
.on('⌘+⇧+Z', function() { history.redo(); })
.on('⌃+⇧+Z', function() { history.redo(); })
- .on('⌫', function(e) { e.preventDefault(); });
+ .on('⌫', function() { d3.event.preventDefault(); });
d3.select(document)
.call(keybinding);
diff --git a/js/id/modes/draw_area.js b/js/id/modes/draw_area.js
index a90d13c9c..494d1affb 100644
--- a/js/id/modes/draw_area.js
+++ b/js/id/modes/draw_area.js
@@ -12,9 +12,8 @@ iD.modes.DrawArea = function(wayId) {
history = mode.history,
controller = mode.controller,
way = history.graph().entity(wayId),
- headId = (way.nodes.length == 1) ?
- way.nodes[0] :
- way.nodes[way.nodes.length - 2],
+ index = way.nodes.length - 1,
+ headId = way.nodes[index - 1],
tailId = way.first(),
node = iD.Node({loc: map.mouseCoordinates()});
@@ -24,12 +23,20 @@ iD.modes.DrawArea = function(wayId) {
history.perform(
iD.actions.AddNode(node),
- iD.actions.AddWayNode(way.id, node.id, -1));
+ iD.actions.AddWayNode(way.id, node.id, index));
surface.selectAll('.way, .node')
.filter(function (d) { return d.id === wayId || d.id === node.id; })
.classed('active', true);
+ function ReplaceTemporaryNode(replacementId) {
+ return function(graph) {
+ graph = graph.replace(graph.entity(wayId).updateNode(replacementId, index));
+ graph = graph.remove(node);
+ return graph;
+ }
+ }
+
function mousemove() {
history.replace(iD.actions.MoveNode(node.id, map.mouseCoordinates()));
}
@@ -55,8 +62,7 @@ iD.modes.DrawArea = function(wayId) {
} else if (datum.type === 'node' && datum.id !== node.id) {
// connect the way to an existing node
history.replace(
- iD.actions.DeleteNode(node.id),
- iD.actions.AddWayNode(way.id, datum.id, -1),
+ ReplaceTemporaryNode(datum.id),
way.nodes.length > 2 ? 'added to an area' : '');
controller.enter(iD.modes.DrawArea(wayId));
@@ -77,13 +83,11 @@ iD.modes.DrawArea = function(wayId) {
iD.actions.DeleteNode(node.id),
iD.actions.DeleteNode(headId));
- if (history.graph().fetch(wayId).nodes.length === 2) {
- history.replace(
- iD.actions.DeleteNode(way.nodes[0]),
- iD.actions.DeleteWay(wayId));
- controller.enter(iD.modes.Browse());
- } else {
+ if (history.graph().entity(wayId)) {
controller.enter(iD.modes.DrawArea(wayId));
+ } else {
+ // The way was deleted because it had too few nodes.
+ controller.enter(iD.modes.Browse());
}
}
@@ -95,8 +99,15 @@ iD.modes.DrawArea = function(wayId) {
function ret() {
d3.event.preventDefault();
+
history.replace(iD.actions.DeleteNode(node.id));
- controller.enter(iD.modes.Select(way, true));
+
+ if (history.graph().entity(wayId)) {
+ controller.enter(iD.modes.Select(way, true));
+ } else {
+ // The way was deleted because it had too few nodes.
+ controller.enter(iD.modes.Browse());
+ }
}
surface
diff --git a/js/id/modes/draw_line.js b/js/id/modes/draw_line.js
index 3b3892aa6..b8fabeca5 100644
--- a/js/id/modes/draw_line.js
+++ b/js/id/modes/draw_line.js
@@ -13,7 +13,7 @@ iD.modes.DrawLine = function(wayId, direction) {
controller = mode.controller,
way = history.graph().entity(wayId),
node = iD.Node({loc: map.mouseCoordinates()}),
- index = (direction === 'forward') ? undefined : 0,
+ index = (direction === 'forward') ? way.nodes.length : 0,
headId = (direction === 'forward') ? way.last() : way.first(),
tailId = (direction === 'forward') ? way.first() : way.last();
@@ -35,6 +35,14 @@ iD.modes.DrawLine = function(wayId, direction) {
.filter(function (d) { return d.id === wayId || d.id === node.id; })
.classed('active', true);
+ function ReplaceTemporaryNode(replacementId) {
+ return function(graph) {
+ graph = graph.replace(graph.entity(wayId).updateNode(replacementId, index));
+ graph = graph.remove(node);
+ return graph;
+ }
+ }
+
function mousemove() {
history.replace(iD.actions.MoveNode(node.id, map.mouseCoordinates()));
}
@@ -46,8 +54,7 @@ iD.modes.DrawLine = function(wayId, direction) {
// connect the way in a loop
if (way.nodes.length > 2) {
history.replace(
- iD.actions.DeleteNode(node.id),
- iD.actions.AddWayNode(wayId, tailId, index),
+ ReplaceTemporaryNode(tailId),
'added to a line');
controller.enter(iD.modes.Select(way, true));
@@ -66,8 +73,7 @@ iD.modes.DrawLine = function(wayId, direction) {
} else if (datum.type === 'node' && datum.id !== node.id) {
// connect the way to an existing node
history.replace(
- iD.actions.DeleteNode(node.id),
- iD.actions.AddWayNode(wayId, datum.id, index),
+ ReplaceTemporaryNode(datum.id),
'added to a line');
controller.enter(iD.modes.DrawLine(wayId, direction));
@@ -106,11 +112,11 @@ iD.modes.DrawLine = function(wayId, direction) {
iD.actions.DeleteNode(node.id),
iD.actions.DeleteNode(headId));
- if (history.graph().fetch(wayId).nodes.length === 0) {
- history.replace(iD.actions.DeleteWay(wayId));
- controller.enter(iD.modes.Browse());
- } else {
+ if (history.graph().entity(wayId)) {
controller.enter(iD.modes.DrawLine(wayId, direction));
+ } else {
+ // The way was deleted because it had too few nodes.
+ controller.enter(iD.modes.Browse());
}
}
@@ -122,8 +128,15 @@ iD.modes.DrawLine = function(wayId, direction) {
function ret() {
d3.event.preventDefault();
+
history.replace(iD.actions.DeleteNode(node.id));
- controller.enter(iD.modes.Select(way, true));
+
+ if (history.graph().entity(wayId)) {
+ controller.enter(iD.modes.Select(way, true));
+ } else {
+ // The way was deleted because it had too few nodes.
+ controller.enter(iD.modes.Browse());
+ }
}
surface
diff --git a/js/id/modes/select.js b/js/id/modes/select.js
index 2b92cfedd..d80d6fffd 100644
--- a/js/id/modes/select.js
+++ b/js/id/modes/select.js
@@ -15,13 +15,9 @@ iD.modes.Select = function(entity, initial) {
iD.actions.DeleteWay(entity.id),
'deleted a way');
} else if (entity.type === 'node') {
- var parents = mode.history.graph().parentWays(entity),
- operations = [iD.actions.DeleteNode(entity.id)];
- parents.forEach(function(parent) {
- if (_.uniq(parent.nodes).length === 1) operations.push(iD.actions.DeleteWay(parent.id));
- });
- mode.history.perform.apply(mode.history,
- operations.concat(['deleted a node']));
+ mode.history.perform(
+ iD.actions.DeleteNode(entity.id),
+ 'deleted a node');
}
mode.controller.exit();
diff --git a/test/index.html b/test/index.html
index 6df3944d9..e7e6701a6 100644
--- a/test/index.html
+++ b/test/index.html
@@ -66,7 +66,6 @@
-
@@ -75,12 +74,9 @@
-
-
-
@@ -128,21 +124,16 @@
-
-
-
-
-
diff --git a/test/index_packaged.html b/test/index_packaged.html
index 6dc1391a9..5a013b45c 100644
--- a/test/index_packaged.html
+++ b/test/index_packaged.html
@@ -33,7 +33,6 @@
-
@@ -42,12 +41,9 @@
-
-
-
diff --git a/test/spec/actions/add_relation_member.js b/test/spec/actions/add_relation_member.js
deleted file mode 100644
index aeae8e353..000000000
--- a/test/spec/actions/add_relation_member.js
+++ /dev/null
@@ -1,37 +0,0 @@
-describe("iD.actions.AddRelationMember", function () {
- it("adds a member at the end of the relation", function () {
- var relation = iD.Relation(),
- graph = iD.Graph([relation]);
-
- graph = iD.actions.AddRelationMember(relation.id, {id: '1'})(graph);
-
- expect(graph.entity(relation.id).members).to.eql([{id: '1'}]);
- });
-
- it("adds a member at index 0", function () {
- var relation = iD.Relation({members: [{id: '1'}]}),
- graph = iD.Graph([relation]);
-
- graph = iD.actions.AddRelationMember(relation.id, {id: '2'}, 0)(graph);
-
- expect(graph.entity(relation.id).members).to.eql([{id: '2'}, {id: '1'}]);
- });
-
- it("adds a member at a positive index", function () {
- var relation = iD.Relation({members: [{id: '1'}, {id: '3'}]}),
- graph = iD.Graph([relation]);
-
- graph = iD.actions.AddRelationMember(relation.id, {id: '2'}, 1)(graph);
-
- expect(graph.entity(relation.id).members).to.eql([{id: '1'}, {id: '2'}, {id: '3'}]);
- });
-
- it("adds a member at a negative index", function () {
- var relation = iD.Relation({members: [{id: '1'}, {id: '3'}]}),
- graph = iD.Graph([relation]);
-
- graph = iD.actions.AddRelationMember(relation.id, {id: '2'}, -1)(graph);
-
- expect(graph.entity(relation.id).members).to.eql([{id: '1'}, {id: '2'}, {id: '3'}]);
- });
-});
diff --git a/test/spec/actions/add_way_node.js b/test/spec/actions/add_way_node.js
deleted file mode 100644
index 5c774e5e4..000000000
--- a/test/spec/actions/add_way_node.js
+++ /dev/null
@@ -1,29 +0,0 @@
-describe("iD.actions.AddWayNode", function () {
- it("adds a node to the end of a way", function () {
- var way = iD.Way(),
- node = iD.Node({id: "n1"}),
- graph = iD.actions.AddWayNode(way.id, node.id)(iD.Graph([way, node]));
- expect(graph.entity(way.id).nodes).to.eql(["n1"]);
- });
-
- it("adds a node to a way at index 0", function () {
- var way = iD.Way({nodes: ["n1", "n3"]}),
- node = iD.Node({id: "n2"}),
- graph = iD.actions.AddWayNode(way.id, node.id, 0)(iD.Graph([way, node]));
- expect(graph.entity(way.id).nodes).to.eql(["n2", "n1", "n3"]);
- });
-
- it("adds a node to a way at a positive index", function () {
- var way = iD.Way({nodes: ["n1", "n3"]}),
- node = iD.Node({id: "n2"}),
- graph = iD.actions.AddWayNode(way.id, node.id, 1)(iD.Graph([way, node]));
- expect(graph.entity(way.id).nodes).to.eql(["n1", "n2", "n3"]);
- });
-
- it("adds a node to a way at a negative index", function () {
- var way = iD.Way({nodes: ["n1", "n3"]}),
- node = iD.Node({id: "n2"}),
- graph = iD.actions.AddWayNode(way.id, node.id, -1)(iD.Graph([way, node]));
- expect(graph.entity(way.id).nodes).to.eql(["n1", "n2", "n3"]);
- });
-});
diff --git a/test/spec/actions/delete_node.js b/test/spec/actions/delete_node.js
index a73f7e33f..93860117f 100644
--- a/test/spec/actions/delete_node.js
+++ b/test/spec/actions/delete_node.js
@@ -24,4 +24,22 @@ describe("iD.actions.DeleteNode", function () {
graph = action(iD.Graph([node1, node2, relation]));
expect(graph.entity(relation.id).members).to.eql([{ id: node2.id }]);
});
+
+ it("deletes parent ways that would otherwise have less than two nodes", function () {
+ var node1 = iD.Node(),
+ node2 = iD.Node(),
+ way = iD.Way({nodes: [node1.id, node2.id]}),
+ action = iD.actions.DeleteNode(node1.id),
+ graph = action(iD.Graph([node1, node2, way]));
+ expect(graph.entity(way.id)).to.be.undefined;
+ });
+
+ it("deletes degenerate circular ways", function () {
+ var node1 = iD.Node(),
+ node2 = iD.Node(),
+ way = iD.Way({nodes: [node1.id, node2.id, node1.id]}),
+ action = iD.actions.DeleteNode(node2.id),
+ graph = action(iD.Graph([node1, node2, way]));
+ expect(graph.entity(way.id)).to.be.undefined;
+ });
});
diff --git a/test/spec/actions/remove_relation_member.js b/test/spec/actions/remove_relation_member.js
deleted file mode 100644
index d989b749b..000000000
--- a/test/spec/actions/remove_relation_member.js
+++ /dev/null
@@ -1,8 +0,0 @@
-describe("iD.actions.RemoveRelationMember", function () {
- it("removes a member from a relation", function () {
- var node = iD.Node(),
- relation = iD.Way({members: [{ id: node.id }]}),
- graph = iD.actions.RemoveRelationMember(relation.id, node.id)(iD.Graph([node, relation]));
- expect(graph.entity(relation.id).members).to.eql([]);
- });
-});
diff --git a/test/spec/actions/remove_way_node.js b/test/spec/actions/remove_way_node.js
deleted file mode 100644
index 6e5751b76..000000000
--- a/test/spec/actions/remove_way_node.js
+++ /dev/null
@@ -1,8 +0,0 @@
-describe("iD.actions.RemoveWayNode", function () {
- it("removes a node from a way", function () {
- var node = iD.Node({id: "n1"}),
- way = iD.Way({id: "w1", nodes: ["n1"]}),
- graph = iD.actions.RemoveWayNode(way.id, node.id)(iD.Graph({n1: node, w1: way}));
- expect(graph.entity(way.id).nodes).to.eql([]);
- });
-});
diff --git a/test/spec/actions/update_relation_member.js b/test/spec/actions/update_relation_member.js
deleted file mode 100644
index c85d72b34..000000000
--- a/test/spec/actions/update_relation_member.js
+++ /dev/null
@@ -1,8 +0,0 @@
-describe("iD.actions.UpdateRelationMember", function () {
- it("updates the properties of the relation member at the specified index", function () {
- var node = iD.Node(),
- relation = iD.Relation({members: [{id: node.id, role: 'forward'}]}),
- graph = iD.actions.UpdateRelationMember(relation.id, {role: 'backward'}, 0)(iD.Graph([node, relation]));
- expect(graph.entity(relation.id).members).to.eql([{id: node.id, role: 'backward'}]);
- });
-});
diff --git a/test/spec/graph/relation.js b/test/spec/graph/relation.js
index 58b1767f4..d8619726a 100644
--- a/test/spec/graph/relation.js
+++ b/test/spec/graph/relation.js
@@ -104,6 +104,42 @@ describe('iD.Relation', function () {
});
});
+ describe("#addMember", function () {
+ it("adds a member at the end of the relation", function () {
+ var r = iD.Relation();
+ expect(r.addMember({id: '1'}).members).to.eql([{id: '1'}]);
+ });
+
+ it("adds a member at index 0", function () {
+ var r = iD.Relation({members: [{id: '1'}]});
+ expect(r.addMember({id: '2'}, 0).members).to.eql([{id: '2'}, {id: '1'}]);
+ });
+
+ it("adds a member at a positive index", function () {
+ var r = iD.Relation({members: [{id: '1'}, {id: '3'}]});
+ expect(r.addMember({id: '2'}, 1).members).to.eql([{id: '1'}, {id: '2'}, {id: '3'}]);
+ });
+
+ it("adds a member at a negative index", function () {
+ var r = iD.Relation({members: [{id: '1'}, {id: '3'}]});
+ expect(r.addMember({id: '2'}, -1).members).to.eql([{id: '1'}, {id: '2'}, {id: '3'}]);
+ });
+ });
+
+ describe("#updateMember", function () {
+ it("updates the properties of the relation member at the specified index", function () {
+ var r = iD.Relation({members: [{role: 'forward'}]});
+ expect(r.updateMember({role: 'backward'}, 0).members).to.eql([{role: 'backward'}]);
+ });
+ });
+
+ describe("#removeMember", function () {
+ it("removes a member", function () {
+ var r = iD.Relation({members: [{id: 'a'}]});
+ expect(r.removeMember('a').members).to.eql([]);
+ });
+ });
+
describe("#multipolygon", function () {
specify("single polygon consisting of a single way", function () {
var a = iD.Node(),
diff --git a/test/spec/graph/way.js b/test/spec/graph/way.js
index 37df6b648..87d7d0029 100644
--- a/test/spec/graph/way.js
+++ b/test/spec/graph/way.js
@@ -117,6 +117,31 @@ describe('iD.Way', function() {
});
});
+ describe("#isDegenerate", function() {
+ it("returns true for a linear way with zero or one nodes", function () {
+ expect(iD.Way({nodes: []}).isDegenerate()).to.equal(true);
+ expect(iD.Way({nodes: ['a']}).isDegenerate()).to.equal(true);
+ });
+
+ it("returns true for a circular way with only one unique node", function () {
+ expect(iD.Way({nodes: ['a', 'a']}).isDegenerate()).to.equal(true);
+ });
+
+ it("returns false for a linear way with two or more nodes", function () {
+ expect(iD.Way({nodes: ['a', 'b']}).isDegenerate()).to.equal(false);
+ });
+
+ it("returns true for an area with zero, one, or two unique nodes", function () {
+ expect(iD.Way({tags: {area: 'yes'}, nodes: []}).isDegenerate()).to.equal(true);
+ expect(iD.Way({tags: {area: 'yes'}, nodes: ['a', 'a']}).isDegenerate()).to.equal(true);
+ expect(iD.Way({tags: {area: 'yes'}, nodes: ['a', 'b', 'a']}).isDegenerate()).to.equal(true);
+ });
+
+ it("returns false for an area with three or more unique nodes", function () {
+ expect(iD.Way({tags: {area: 'yes'}, nodes: ['a', 'b', 'c', 'a']}).isDegenerate()).to.equal(false);
+ });
+ });
+
describe("#geometry", function() {
it("returns 'line' when the way is not an area", function () {
expect(iD.Way().geometry()).to.equal('line');
@@ -126,4 +151,52 @@ describe('iD.Way', function() {
expect(iD.Way({tags: { area: 'yes' }}).geometry()).to.equal('area');
});
});
+
+ describe("#addNode", function () {
+ it("adds a node to the end of a way", function () {
+ var w = iD.Way();
+ expect(w.addNode('a').nodes).to.eql(['a']);
+ });
+
+ it("adds a node to a way at index 0", function () {
+ var w = iD.Way({nodes: ['a', 'b']});
+ expect(w.addNode('c', 0).nodes).to.eql(['c', 'a', 'b']);
+ });
+
+ it("adds a node to a way at a positive index", function () {
+ var w = iD.Way({nodes: ['a', 'b']});
+ expect(w.addNode('c', 1).nodes).to.eql(['a', 'c', 'b']);
+ });
+
+ it("adds a node to a way at a negative index", function () {
+ var w = iD.Way({nodes: ['a', 'b']});
+ expect(w.addNode('c', -1).nodes).to.eql(['a', 'c', 'b']);
+ });
+ });
+
+ describe("#updateNode", function () {
+ it("updates the node id at the specified index", function () {
+ var w = iD.Way({nodes: ['a', 'b', 'c']});
+ expect(w.updateNode('d', 1).nodes).to.eql(['a', 'd', 'c']);
+ });
+ });
+
+ describe("#removeNode", function () {
+ it("removes the node", function () {
+ var a = iD.Node({id: 'a'}),
+ w = iD.Way({nodes: ['a']});
+
+ expect(w.removeNode('a').nodes).to.eql([]);
+ });
+
+ it("preserves circularity", function () {
+ var a = iD.Node({id: 'a'}),
+ b = iD.Node({id: 'b'}),
+ c = iD.Node({id: 'c'}),
+ d = iD.Node({id: 'd'}),
+ w = iD.Way({nodes: ['a', 'b', 'c', 'd', 'a']});
+
+ expect(w.removeNode('a').nodes).to.eql(['b', 'c', 'd', 'b']);
+ });
+ });
});