More cleanup of operations and post-paste behavior

* Support move, rotate, reflect, delete post paste on multiselection
* Improve text and error msgs for singular vs multi selections
* Move `disabled` checks from actions to operations
* Reproject center of rotation (closes #3667)
* Cleanup tests
This commit is contained in:
Bryan Housel
2016-12-21 23:58:13 -05:00
parent 38e4900355
commit 37534aed0e
19 changed files with 298 additions and 214 deletions
+10 -9
View File
@@ -19,13 +19,14 @@ describe('iD.actionDeleteMultiple', function () {
expect(graph.hasEntity(n.id)).to.be.undefined;
});
describe('#disabled', function () {
it('returns the result of the first action that is disabled', function () {
var node = iD.Node(),
relation = iD.Relation({members: [{id: 'w'}]}),
graph = iD.Graph([node, relation]),
action = iD.actionDeleteMultiple([node.id, relation.id]);
expect(action.disabled(graph)).to.equal('incomplete_relation');
});
});
// This was moved to operationDelete. We should test operations and move this test there.
// describe('#disabled', function () {
// it('returns the result of the first action that is disabled', function () {
// var node = iD.Node(),
// relation = iD.Relation({members: [{id: 'w'}]}),
// graph = iD.Graph([node, relation]),
// action = iD.actionDeleteMultiple([node.id, relation.id]);
// expect(action.disabled(graph)).to.equal('incomplete_relation');
// });
// });
});
+9 -8
View File
@@ -82,12 +82,13 @@ describe('iD.actionDeleteRelation', function () {
expect(graph.hasEntity(parent.id)).to.be.undefined;
});
describe('#disabled', function() {
it('returns \'incomplete_relation\' if the relation is incomplete', function() {
var relation = iD.Relation({members: [{id: 'w'}]}),
graph = iD.Graph([relation]),
action = iD.actionDeleteRelation(relation.id);
expect(action.disabled(graph)).to.equal('incomplete_relation');
});
});
// This was moved to operationDelete. We should test operations and move this test there.
// describe('#disabled', function() {
// it('returns \'incomplete_relation\' if the relation is incomplete', function() {
// var relation = iD.Relation({members: [{id: 'w'}]}),
// graph = iD.Graph([relation]),
// action = iD.actionDeleteRelation(relation.id);
// expect(action.disabled(graph)).to.equal('incomplete_relation');
// });
// });
});
+26 -25
View File
@@ -69,31 +69,32 @@ describe('iD.actionDeleteWay', function() {
expect(graph.hasEntity(relation.id)).to.be.undefined;
});
describe('#disabled', function () {
it('returns \'part_of_relation\' for members of route and boundary relations', function () {
var a = iD.Way({id: 'a'}),
b = iD.Way({id: 'b'}),
route = iD.Relation({members: [{id: 'a'}], tags: {type: 'route'}}),
boundary = iD.Relation({members: [{id: 'b'}], tags: {type: 'boundary'}}),
graph = iD.Graph([a, b, route, boundary]);
expect(iD.actionDeleteWay('a').disabled(graph)).to.equal('part_of_relation');
expect(iD.actionDeleteWay('b').disabled(graph)).to.equal('part_of_relation');
});
// This was moved to operationDelete. We should test operations and move this test there.
// describe('#disabled', function () {
// it('returns \'part_of_relation\' for members of route and boundary relations', function () {
// var a = iD.Way({id: 'a'}),
// b = iD.Way({id: 'b'}),
// route = iD.Relation({members: [{id: 'a'}], tags: {type: 'route'}}),
// boundary = iD.Relation({members: [{id: 'b'}], tags: {type: 'boundary'}}),
// graph = iD.Graph([a, b, route, boundary]);
// expect(iD.actionDeleteWay('a').disabled(graph)).to.equal('part_of_relation');
// expect(iD.actionDeleteWay('b').disabled(graph)).to.equal('part_of_relation');
// });
it('returns \'part_of_relation\' for outer members of multipolygons', function () {
var way = iD.Way({id: 'w'}),
relation = iD.Relation({members: [{id: 'w', role: 'outer'}], tags: {type: 'multipolygon'}}),
graph = iD.Graph([way, relation]),
action = iD.actionDeleteWay(way.id);
expect(action.disabled(graph)).to.equal('part_of_relation');
});
// it('returns \'part_of_relation\' for outer members of multipolygons', function () {
// var way = iD.Way({id: 'w'}),
// relation = iD.Relation({members: [{id: 'w', role: 'outer'}], tags: {type: 'multipolygon'}}),
// graph = iD.Graph([way, relation]),
// action = iD.actionDeleteWay(way.id);
// expect(action.disabled(graph)).to.equal('part_of_relation');
// });
it('returns falsy for inner members of multipolygons', function () {
var way = iD.Way({id: 'w'}),
relation = iD.Relation({members: [{id: 'w', role: 'inner'}], tags: {type: 'multipolygon'}}),
graph = iD.Graph([way, relation]),
action = iD.actionDeleteWay(way.id);
expect(action.disabled(graph)).not.ok;
});
});
// it('returns falsy for inner members of multipolygons', function () {
// var way = iD.Way({id: 'w'}),
// relation = iD.Relation({members: [{id: 'w', role: 'inner'}], tags: {type: 'multipolygon'}}),
// graph = iD.Graph([way, relation]),
// action = iD.actionDeleteWay(way.id);
// expect(action.disabled(graph)).not.ok;
// });
// });
});
+22 -21
View File
@@ -1,29 +1,30 @@
describe('iD.actionMove', function() {
var projection = d3.geoMercator().scale(250 / Math.PI);
describe('#disabled', function() {
it('returns falsy by default', function() {
var node = iD.Node({loc: [0, 0]}),
action = iD.actionMove([node.id], [0, 0], projection),
graph = iD.Graph([node]);
expect(action.disabled(graph)).not.to.be.ok;
});
// This was moved to operationMove. We should test operations and move this test there.
// describe('#disabled', function() {
// it('returns falsy by default', function() {
// var node = iD.Node({loc: [0, 0]}),
// action = iD.actionMove([node.id], [0, 0], projection),
// graph = iD.Graph([node]);
// expect(action.disabled(graph)).not.to.be.ok;
// });
it('returns \'incomplete_relation\' for an incomplete relation', function() {
var relation = iD.Relation({members: [{id: 1}]}),
action = iD.actionMove([relation.id], [0, 0], projection),
graph = iD.Graph([relation]);
expect(action.disabled(graph)).to.equal('incomplete_relation');
});
// it('returns \'incomplete_relation\' for an incomplete relation', function() {
// var relation = iD.Relation({members: [{id: 1}]}),
// action = iD.actionMove([relation.id], [0, 0], projection),
// graph = iD.Graph([relation]);
// expect(action.disabled(graph)).to.equal('incomplete_relation');
// });
it('returns falsy for a complete relation', function() {
var node = iD.Node({loc: [0, 0]}),
relation = iD.Relation({members: [{id: node.id}]}),
action = iD.actionMove([relation.id], [0, 0], projection),
graph = iD.Graph([node, relation]);
expect(action.disabled(graph)).not.to.be.ok;
});
});
// it('returns falsy for a complete relation', function() {
// var node = iD.Node({loc: [0, 0]}),
// relation = iD.Relation({members: [{id: node.id}]}),
// action = iD.actionMove([relation.id], [0, 0], projection),
// graph = iD.Graph([node, relation]);
// expect(action.disabled(graph)).not.to.be.ok;
// });
// });
it('moves all nodes in a way by the given amount', function() {
var node1 = iD.Node({loc: [0, 0]}),
+6 -19
View File
@@ -2,19 +2,6 @@ describe('iD.actionReflect', function() {
var projection = d3.geoMercator();
it('does not create or remove nodes', function () {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a'], tags: { area: 'yes'}})
]);
graph = iD.actionReflect('-', projection)(graph);
expect(graph.entity('-').nodes).to.have.length(5);
});
it('only operates on areas', function () {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [4, 0]}),
@@ -22,8 +9,8 @@ describe('iD.actionReflect', function() {
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
var graph2 = iD.actionReflect('-', projection)(graph);
expect(graph2).to.deep.equal(graph);
graph = iD.actionReflect(['-'], projection)(graph);
expect(graph.entity('-').nodes).to.have.length(5);
});
@@ -38,9 +25,9 @@ describe('iD.actionReflect', function() {
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a'], tags: { area: 'yes'}})
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionReflect('-', projection)(graph);
graph = iD.actionReflect(['-'], projection)(graph);
expect(graph.entity('a').loc[0]).to.be.closeTo(0, 1e-6);
expect(graph.entity('a').loc[1]).to.be.closeTo(2, 1e-6);
expect(graph.entity('b').loc[0]).to.be.closeTo(4, 1e-6);
@@ -63,9 +50,9 @@ describe('iD.actionReflect', function() {
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a'], tags: { area: 'yes'}})
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionReflect('-', projection).useLongAxis(false)(graph);
graph = iD.actionReflect(['-'], projection).useLongAxis(false)(graph);
expect(graph.entity('a').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('a').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('b').loc[0]).to.be.closeTo(0, 1e-6);