Fixing draw mode bugs

Disabling interactive draw undo for now. I know how to fix it
but it's a bit tricky. So undo will just drop you out to browse
mode for the time being.

Fixes #477.
Fixes #516.
This commit is contained in:
John Firebaugh
2013-01-26 15:24:06 -05:00
parent ec971ceac7
commit e09666bbdc
7 changed files with 108 additions and 90 deletions

View File

@@ -4,13 +4,17 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
controller = mode.controller,
event = d3.dispatch('add', 'addHead', 'addTail', 'addNode', 'addWay'),
way = mode.history.graph().entity(wayId),
nodeId = way.nodes[index],
hover, draw;
var node = iD.Node({loc: map.mouseCoordinates()}),
nodeId = node.id;
history[way.isDegenerate() ? 'replace' : 'perform'](
iD.actions.AddNode(node),
iD.actions.AddWayNode(wayId, node.id, index));
function move() {
history.replace(
iD.actions.MoveNode(nodeId, map.mouseCoordinates()),
history.undoAnnotation());
history.replace(iD.actions.MoveNode(nodeId, map.mouseCoordinates()));
}
function add() {
@@ -34,12 +38,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
}
function undone() {
var way = history.graph().entity(wayId);
if (way) {
controller.enter(mode);
} else {
controller.enter(iD.modes.Browse());
}
controller.enter(iD.modes.Browse());
}
var drawWay = function(surface) {
@@ -73,10 +72,18 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
history.on('undone.draw', null);
};
function ReplaceTemporaryNode(newNode) {
return function(graph) {
return graph
.replace(way.removeNode(nodeId).addNode(newNode.id, index))
.remove(node);
}
}
// Connect the way to an existing node and continue drawing.
drawWay.addNode = function(node, annotation) {
history.perform(
iD.actions.AddWayNode(wayId, node.id, index),
ReplaceTemporaryNode(node),
annotation);
controller.enter(mode);
@@ -88,8 +95,8 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
history.perform(
iD.actions.AddNode(newNode),
iD.actions.AddWayNode(wayId, newNode.id, index),
iD.actions.AddWayNode(way.id, newNode.id, wayIndex),
ReplaceTemporaryNode(newNode),
annotation);
controller.enter(mode);
@@ -99,9 +106,9 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
drawWay.add = function(loc, annotation) {
var newNode = iD.Node({loc: loc});
history.perform(
history.replace(
iD.actions.AddNode(newNode),
iD.actions.AddWayNode(wayId, newNode.id, index),
ReplaceTemporaryNode(newNode),
annotation);
controller.enter(mode);
@@ -110,9 +117,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode) {
// Finish the draw operation, removing the temporary node. If the way has enough
// nodes to be valid, it's selected. Otherwise, return to browse mode.
drawWay.finish = function() {
history.replace(
iD.actions.DeleteNode(nodeId),
history.undoAnnotation());
history.pop();
var way = history.graph().entity(wayId);
if (way) {

View File

@@ -54,9 +54,26 @@ iD.History = function() {
change(previous);
},
pop: function () {
var previous = stack[index].graph;
if (index > 0) {
index--;
stack.pop();
change(previous);
}
},
undo: function () {
var previous = stack[index].graph;
// Pop to the first annotated state.
while (index > 0) {
if (stack[index].annotation) break;
index--;
}
// Pop to the next annotated state.
while (index > 0) {
index--;
if (stack[index].annotation) break;

View File

@@ -14,52 +14,40 @@ iD.modes.AddArea = function() {
history = mode.history,
controller = mode.controller;
function startFromNode(a) {
var way = iD.Way({tags: defaultTags}),
b = iD.Node({loc: a.loc});
function startFromNode(node) {
var way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(b),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, a.id),
iD.actions.AddWayNode(way.id, b.id),
iD.actions.AddWayNode(way.id, a.id),
'started an area');
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawArea(way.id));
}
function startFromWay(other, loc, index) {
var a = iD.Node({loc: loc}),
b = iD.Node({loc: loc}),
var node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(a),
iD.actions.AddNode(b),
iD.actions.AddNode(node),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, a.id),
iD.actions.AddWayNode(way.id, b.id),
iD.actions.AddWayNode(way.id, a.id),
iD.actions.AddWayNode(other.id, a.id, index),
'started an area');
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(other.id, node.id, index));
controller.enter(iD.modes.DrawArea(way.id));
}
function start(loc) {
var a = iD.Node({loc: loc}),
b = iD.Node({loc: loc}),
var node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(a),
iD.actions.AddNode(b),
iD.actions.AddNode(node),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, a.id),
iD.actions.AddWayNode(way.id, b.id),
iD.actions.AddWayNode(way.id, a.id),
'started an area');
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawArea(way.id));
}

View File

@@ -14,71 +14,49 @@ iD.modes.AddLine = function() {
history = mode.history,
controller = mode.controller;
function startFromNode(a) {
var b = iD.Node({loc: a.loc}),
graph = history.graph(),
parent = graph.parentWays(a)[0],
function startFromNode(node) {
var graph = history.graph(),
parent = graph.parentWays(node)[0],
isLine = parent && parent.geometry(graph) === 'line';
if (isLine && parent.first() === a.id) {
history.perform(
iD.actions.AddNode(b),
iD.actions.AddWayNode(parent.id, b.id, 0),
'continued a line');
if (isLine && parent.first() === node.id) {
controller.enter(iD.modes.DrawLine(parent.id, 'backward'));
} else if (isLine && parent.last() === a.id) {
history.perform(
iD.actions.AddNode(b),
iD.actions.AddWayNode(parent.id, b.id),
'continued a line');
} else if (isLine && parent.last() === node.id) {
controller.enter(iD.modes.DrawLine(parent.id, 'forward'));
} else {
var way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(b),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, a.id),
iD.actions.AddWayNode(way.id, b.id),
'continued a line');
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawLine(way.id, 'forward'));
}
}
function startFromWay(other, loc, index) {
var a = iD.Node({loc: loc}),
b = iD.Node({loc: loc}),
var node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(a),
iD.actions.AddNode(b),
iD.actions.AddNode(node),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, a.id),
iD.actions.AddWayNode(way.id, b.id),
iD.actions.AddWayNode(other.id, a.id, index),
'started a line');
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(other.id, node.id, index));
controller.enter(iD.modes.DrawLine(way.id, 'forward'));
}
function start(loc) {
var a = iD.Node({loc: loc}),
b = iD.Node({loc: loc}),
var node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(a),
iD.actions.AddNode(b),
iD.actions.AddNode(node),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, a.id),
iD.actions.AddWayNode(way.id, b.id),
'started a line');
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawLine(way.id, 'forward'));
}

View File

@@ -8,24 +8,25 @@ iD.modes.DrawArea = function(wayId) {
mode.enter = function() {
var way = mode.history.graph().entity(wayId),
index = way.nodes.length - 2,
headId = way.nodes[index - 1],
tailId = way.first();
index = -1,
headId = way.nodes[way.nodes.length - 2],
tailId = way.first(),
annotation = way.isDegenerate() ? 'started an area' : 'continued an area';
function addHeadTail() {
behavior.finish();
}
function addNode(node) {
behavior.addNode(node, way.nodes.length > 2 ? 'added to an area' : '');
behavior.addNode(node, annotation);
}
function addWay(way, loc, index) {
behavior.addWay(way, loc, index, way.nodes.length > 2 ? 'added to an area' : '');
behavior.addWay(way, loc, index, annotation);
}
function add(loc) {
behavior.add(loc, way.nodes.length > 2 ? 'added to an area' : '');
behavior.add(loc, annotation);
}
behavior = iD.behavior.DrawWay(wayId, headId, tailId, index, mode)

View File

@@ -8,9 +8,10 @@ iD.modes.DrawLine = function(wayId, direction) {
mode.enter = function() {
var way = mode.history.graph().entity(wayId),
index = (direction === 'forward') ? way.nodes.length - 1 : 0,
headId = (direction === 'forward') ? way.nodes[index - 1] : way.nodes[index + 1],
tailId = (direction === 'forward') ? way.first() : way.last();
index = (direction === 'forward') ? undefined : 0,
headId = (direction === 'forward') ? way.last() : way.first(),
tailId = (direction === 'forward') ? way.first() : way.last(),
annotation = way.isDegenerate() ? 'started a line' : 'continued a line';
function addHead() {
behavior.finish();
@@ -19,22 +20,22 @@ iD.modes.DrawLine = function(wayId, direction) {
function addTail(node) {
// connect the way in a loop
if (way.nodes.length > 2) {
behavior.addNode(node, 'added to a line');
behavior.addNode(node, annotation);
} else {
behavior.cancel();
}
}
function addNode(node) {
behavior.addNode(node, 'added to a line');
behavior.addNode(node, annotation);
}
function addWay(way, loc, index) {
behavior.addWay(way, loc, index, 'added to a line');
behavior.addWay(way, loc, index, annotation);
}
function add(loc) {
behavior.add(loc, 'added to a line');
behavior.add(loc, annotation);
}
behavior = iD.behavior.DrawWay(wayId, headId, tailId, index, mode)

View File

@@ -70,6 +70,27 @@ describe("iD.History", function () {
});
});
describe("#pop", function () {
it("updates the graph", function () {
history.perform(action, "annotation");
history.pop();
expect(history.undoAnnotation()).to.be.undefined;
});
it("does not push the redo stack", function () {
history.perform(action, "annotation");
history.pop();
expect(history.redoAnnotation()).to.be.undefined;
});
it("emits a change event", function () {
history.perform(action);
history.on('change', spy);
history.pop();
expect(spy).to.have.been.calledWith([]);
});
});
describe("#undo", function () {
it("pops the undo stack", function () {
history.perform(action, "annotation");
@@ -77,6 +98,13 @@ describe("iD.History", function () {
expect(history.undoAnnotation()).to.be.undefined;
});
it("pops past unannotated states", function () {
history.perform(action, "annotation");
history.perform(action);
history.undo();
expect(history.undoAnnotation()).to.be.undefined;
});
it("pushes the redo stack", function () {
history.perform(action, "annotation");
history.undo();