mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-21 07:46:58 +02:00
Merge remote branch 'upstream/master'
This commit is contained in:
@@ -121,6 +121,7 @@
|
||||
<script src='js/id/operations/reverse.js'></script>
|
||||
<script src='js/id/operations/split.js'></script>
|
||||
|
||||
<script src='js/id/graph/difference.js'></script>
|
||||
<script src='js/id/graph/entity.js'></script>
|
||||
<script src='js/id/graph/graph.js'></script>
|
||||
<script src='js/id/graph/history.js'></script>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
iD.actions.Circularize = function(wayId, map) {
|
||||
iD.actions.Circularize = function(wayId, projection) {
|
||||
|
||||
var action = function(graph) {
|
||||
var way = graph.entity(wayId),
|
||||
nodes = graph.childNodes(way),
|
||||
tags = {}, key, role;
|
||||
nodes = _.uniq(graph.childNodes(way));
|
||||
|
||||
var points = nodes.map(function(n) {
|
||||
return map.projection(n.loc);
|
||||
return projection(n.loc);
|
||||
}),
|
||||
centroid = d3.geom.polygon(points).centroid(),
|
||||
radius = d3.median(points, function(p) {
|
||||
@@ -15,14 +14,12 @@ iD.actions.Circularize = function(wayId, map) {
|
||||
circular_nodes = [];
|
||||
|
||||
for (var i = 0; i < 12; i++) {
|
||||
circular_nodes.push(iD.Node({ loc: map.projection.invert([
|
||||
circular_nodes.push(iD.Node({ loc: projection.invert([
|
||||
centroid[0] + Math.cos((i / 12) * Math.PI * 2) * radius,
|
||||
centroid[1] + Math.sin((i / 12) * Math.PI * 2) * radius])
|
||||
}));
|
||||
}
|
||||
|
||||
circular_nodes.push(circular_nodes[0]);
|
||||
|
||||
for (i = 0; i < nodes.length; i++) {
|
||||
if (graph.parentWays(nodes[i]).length > 1) {
|
||||
var closest, closest_dist = Infinity, dist;
|
||||
@@ -34,10 +31,6 @@ iD.actions.Circularize = function(wayId, map) {
|
||||
}
|
||||
}
|
||||
circular_nodes.splice(closest, 1, nodes[i]);
|
||||
if (closest === 0) circular_nodes.splice(circular_nodes.length - 1, 1, nodes[i]);
|
||||
else if (closest === circular_nodes.length - 1) circular_nodes.splice(0, 1, nodes[i]);
|
||||
} else {
|
||||
graph = graph.remove(nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,9 +38,18 @@ iD.actions.Circularize = function(wayId, map) {
|
||||
graph = graph.replace(circular_nodes[i]);
|
||||
}
|
||||
|
||||
return graph.replace(way.update({
|
||||
nodes: _.pluck(circular_nodes, 'id')
|
||||
}));
|
||||
var ids = _.pluck(circular_nodes, 'id'),
|
||||
difference = _.difference(_.uniq(way.nodes), ids);
|
||||
|
||||
ids.push(ids[0]);
|
||||
|
||||
graph = graph.replace(way.update({nodes: ids}));
|
||||
|
||||
for (i = 0; i < difference.length; i++) {
|
||||
graph = iD.actions.DeleteNode(difference[i])(graph);
|
||||
}
|
||||
|
||||
return graph;
|
||||
};
|
||||
|
||||
action.enabled = function(graph) {
|
||||
|
||||
@@ -16,10 +16,13 @@ iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
|
||||
function move(datum) {
|
||||
var loc = context.map().mouseCoordinates();
|
||||
|
||||
if (datum.type === 'node' || datum.type === 'midpoint') {
|
||||
if (datum.type === 'node') {
|
||||
loc = datum.loc;
|
||||
} else if (datum.type === 'way') {
|
||||
loc = iD.geo.chooseIndex(datum, d3.mouse(context.surface().node()), context).loc;
|
||||
} else if (datum.type === 'midpoint' || datum.type === 'way') {
|
||||
var way = datum.type === 'way' ?
|
||||
datum :
|
||||
baseGraph.entity(datum.ways[0].id);
|
||||
loc = iD.geo.chooseIndex(way, d3.mouse(context.surface().node()), context).loc;
|
||||
}
|
||||
|
||||
context.replace(iD.actions.MoveNode(nodeId, loc));
|
||||
|
||||
@@ -45,7 +45,7 @@ iD.behavior.Hash = function(context) {
|
||||
context.map().on('drawn.hash', function() {
|
||||
if (!context.entity(id)) return;
|
||||
selectoff();
|
||||
context.enter(iD.modes.Select([id]));
|
||||
context.enter(iD.modes.Select(context, [id]));
|
||||
});
|
||||
|
||||
context.on('enter.hash', function() {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
iD.Difference represents the difference between two graphs.
|
||||
It knows how to calculate the set of entities that were
|
||||
created, modified, or deleted, and also contains the logic
|
||||
for recursively extending a difference to the complete set
|
||||
of entities that will require a redraw, taking into account
|
||||
child and parent relationships.
|
||||
*/
|
||||
iD.Difference = function (base, head) {
|
||||
var changes = {}, length = 0;
|
||||
|
||||
_.each(head.entities, function(h, id) {
|
||||
var b = base.entities[id];
|
||||
if (h !== b) {
|
||||
changes[id] = {base: b, head: h};
|
||||
length++;
|
||||
}
|
||||
});
|
||||
|
||||
_.each(base.entities, function(b, id) {
|
||||
var h = head.entities[id];
|
||||
if (!changes[id] && h !== b) {
|
||||
changes[id] = {base: b, head: h};
|
||||
length++;
|
||||
}
|
||||
});
|
||||
|
||||
var difference = {};
|
||||
|
||||
difference.length = function () {
|
||||
return length;
|
||||
};
|
||||
|
||||
difference.changes = function() {
|
||||
return changes;
|
||||
};
|
||||
|
||||
difference.extantIDs = function() {
|
||||
var result = [];
|
||||
_.each(changes, function(change, id) {
|
||||
if (change.head) result.push(id);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
difference.modified = function() {
|
||||
var result = [];
|
||||
_.each(changes, function(change) {
|
||||
if (change.base && change.head) result.push(change.head);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
difference.created = function() {
|
||||
var result = [];
|
||||
_.each(changes, function(change) {
|
||||
if (!change.base && change.head) result.push(change.head);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
difference.deleted = function() {
|
||||
var result = [];
|
||||
_.each(changes, function(change) {
|
||||
if (change.base && !change.head) result.push(change.base);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
difference.complete = function(extent) {
|
||||
var result = {}, id, change;
|
||||
|
||||
function addParents(parents) {
|
||||
for (var i = 0; i < parents.length; i++) {
|
||||
var parent = parents[i];
|
||||
|
||||
if (parent.id in result)
|
||||
continue;
|
||||
|
||||
result[parent.id] = parent;
|
||||
addParents(head.parentRelations(parent));
|
||||
}
|
||||
}
|
||||
|
||||
for (id in changes) {
|
||||
change = changes[id];
|
||||
|
||||
var h = change.head,
|
||||
b = change.base,
|
||||
entity = h || b;
|
||||
|
||||
if (extent && !entity.intersects(extent, h ? head : base))
|
||||
continue;
|
||||
|
||||
result[id] = h;
|
||||
|
||||
if (entity.type === 'way') {
|
||||
var nh = h ? h.nodes : [],
|
||||
nb = b ? b.nodes : [],
|
||||
diff;
|
||||
|
||||
diff = _.difference(nh, nb);
|
||||
for (var i = 0; i < diff.length; i++) {
|
||||
result[diff[i]] = head.entity(diff[i]);
|
||||
}
|
||||
|
||||
diff = _.difference(nb, nh);
|
||||
for (var i = 0; i < diff.length; i++) {
|
||||
result[diff[i]] = head.entity(diff[i]);
|
||||
}
|
||||
}
|
||||
|
||||
addParents(head.parentWays(entity));
|
||||
addParents(head.parentRelations(entity));
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return difference;
|
||||
};
|
||||
+1
-10
@@ -43,7 +43,6 @@ iD.Entity.prototype = {
|
||||
|
||||
if (!this.id && this.type) {
|
||||
this.id = iD.Entity.id(this.type);
|
||||
this._updated = true;
|
||||
}
|
||||
|
||||
if (iD.debug) {
|
||||
@@ -63,7 +62,7 @@ iD.Entity.prototype = {
|
||||
},
|
||||
|
||||
update: function(attrs) {
|
||||
return iD.Entity(this, attrs, {_updated: true});
|
||||
return iD.Entity(this, attrs);
|
||||
},
|
||||
|
||||
mergeTags: function(tags) {
|
||||
@@ -80,14 +79,6 @@ iD.Entity.prototype = {
|
||||
return this.update({tags: merged});
|
||||
},
|
||||
|
||||
created: function() {
|
||||
return this._updated && this.osmId().charAt(0) === '-';
|
||||
},
|
||||
|
||||
modified: function() {
|
||||
return this._updated && this.osmId().charAt(0) !== '-';
|
||||
},
|
||||
|
||||
intersects: function(extent, resolver) {
|
||||
return this.extent(resolver).intersects(extent);
|
||||
},
|
||||
|
||||
@@ -232,65 +232,5 @@ iD.Graph.prototype = {
|
||||
}
|
||||
}
|
||||
return items;
|
||||
},
|
||||
|
||||
difference: function (graph) {
|
||||
|
||||
function diff(a, b) {
|
||||
var result = [],
|
||||
keys = Object.keys(a.entities),
|
||||
entity, oldentity, id, i;
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
id = keys[i];
|
||||
entity = a.entities[id];
|
||||
oldentity = b.entities[id];
|
||||
if (entity !== oldentity) {
|
||||
|
||||
// maybe adding affected children better belongs in renderer/map.js?
|
||||
if (entity && entity.type === 'way' &&
|
||||
oldentity && oldentity.type === 'way') {
|
||||
result = result
|
||||
.concat(_.difference(entity.nodes, oldentity.nodes))
|
||||
.concat(_.difference(oldentity.nodes, entity.nodes));
|
||||
|
||||
} else if (entity && entity.type === 'way') {
|
||||
result = result.concat(entity.nodes);
|
||||
|
||||
} else if (oldentity && oldentity.type === 'way') {
|
||||
result = result.concat(oldentity.nodes);
|
||||
}
|
||||
|
||||
result.push(id);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return _.unique(diff(this, graph).concat(diff(graph, this)).sort());
|
||||
},
|
||||
|
||||
modified: function() {
|
||||
var result = [], base = this.base().entities;
|
||||
_.each(this.entities, function(entity, id) {
|
||||
if (entity && base[id]) result.push(id);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
created: function() {
|
||||
var result = [], base = this.base().entities;
|
||||
_.each(this.entities, function(entity, id) {
|
||||
if (entity && !base[id]) result.push(id);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
deleted: function() {
|
||||
var result = [], base = this.base().entities;
|
||||
_.each(this.entities, function(entity, id) {
|
||||
if (!entity && base[id]) result.push(id);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
+23
-23
@@ -21,7 +21,9 @@ iD.History = function() {
|
||||
}
|
||||
|
||||
function change(previous) {
|
||||
dispatch.change(history.graph().difference(previous));
|
||||
var difference = iD.Difference(previous, history.graph());
|
||||
dispatch.change(difference);
|
||||
return difference;
|
||||
}
|
||||
|
||||
var history = {
|
||||
@@ -33,6 +35,8 @@ iD.History = function() {
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
stack[i].graph.rebase(entities);
|
||||
}
|
||||
|
||||
dispatch.change();
|
||||
},
|
||||
|
||||
perform: function () {
|
||||
@@ -42,7 +46,7 @@ iD.History = function() {
|
||||
stack.push(perform(arguments));
|
||||
index++;
|
||||
|
||||
change(previous);
|
||||
return change(previous);
|
||||
},
|
||||
|
||||
replace: function () {
|
||||
@@ -51,7 +55,7 @@ iD.History = function() {
|
||||
// assert(index == stack.length - 1)
|
||||
stack[index] = perform(arguments);
|
||||
|
||||
change(previous);
|
||||
return change(previous);
|
||||
},
|
||||
|
||||
pop: function () {
|
||||
@@ -60,7 +64,7 @@ iD.History = function() {
|
||||
if (index > 0) {
|
||||
index--;
|
||||
stack.pop();
|
||||
change(previous);
|
||||
return change(previous);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -80,7 +84,7 @@ iD.History = function() {
|
||||
}
|
||||
|
||||
dispatch.undone();
|
||||
change(previous);
|
||||
return change(previous);
|
||||
},
|
||||
|
||||
redo: function () {
|
||||
@@ -92,7 +96,7 @@ iD.History = function() {
|
||||
}
|
||||
|
||||
dispatch.redone();
|
||||
change(previous);
|
||||
return change(previous);
|
||||
},
|
||||
|
||||
undoAnnotation: function () {
|
||||
@@ -111,31 +115,27 @@ iD.History = function() {
|
||||
}
|
||||
},
|
||||
|
||||
changes: function () {
|
||||
var initial = stack[0].graph,
|
||||
current = stack[index].graph;
|
||||
difference: function () {
|
||||
var base = stack[0].graph,
|
||||
head = stack[index].graph;
|
||||
return iD.Difference(base, head);
|
||||
},
|
||||
|
||||
changes: function () {
|
||||
var difference = history.difference();
|
||||
return {
|
||||
modified: current.modified().map(function (id) {
|
||||
return current.entity(id);
|
||||
}),
|
||||
created: current.created().map(function (id) {
|
||||
return current.entity(id);
|
||||
}),
|
||||
deleted: current.deleted().map(function (id) {
|
||||
return initial.entity(id);
|
||||
})
|
||||
};
|
||||
modified: difference.modified(),
|
||||
created: difference.created(),
|
||||
deleted: difference.deleted()
|
||||
}
|
||||
},
|
||||
|
||||
hasChanges: function() {
|
||||
return !!this.numChanges();
|
||||
return this.difference().length() > 0;
|
||||
},
|
||||
|
||||
numChanges: function() {
|
||||
return d3.sum(d3.values(this.changes()).map(function(c) {
|
||||
return c.length;
|
||||
}));
|
||||
return this.difference().length();
|
||||
},
|
||||
|
||||
imagery_used: function(source) {
|
||||
|
||||
@@ -16,6 +16,10 @@ window.iD = function () {
|
||||
// the connection requires .storage() to be available on calling.
|
||||
var connection = iD.Connection(context);
|
||||
|
||||
connection.on('load.context', function (err, result) {
|
||||
history.merge(result);
|
||||
});
|
||||
|
||||
/* Straight accessors. Avoid using these if you can. */
|
||||
context.ui = function() { return ui; };
|
||||
context.connection = function() { return connection; };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
iD.operations.Circularize = function(selection, context) {
|
||||
var entityId = selection[0],
|
||||
action = iD.actions.Circularize(entityId, context.map());
|
||||
action = iD.actions.Circularize(entityId, context.projection);
|
||||
|
||||
var operation = function() {
|
||||
var annotation = t('operations.circularize.annotation.' + context.geometry(entityId));
|
||||
|
||||
@@ -2,9 +2,9 @@ iD.operations.Merge = function(selection, context) {
|
||||
var action = iD.actions.Join(selection[0], selection[1]);
|
||||
|
||||
var operation = function() {
|
||||
context.perform(
|
||||
action,
|
||||
t('operations.merge.annotation', {n: selection.length}));
|
||||
var annotation = t('operations.merge.annotation', {n: selection.length}),
|
||||
difference = context.perform(action, annotation);
|
||||
context.enter(iD.modes.Select(context, difference.extantIDs()));
|
||||
};
|
||||
|
||||
operation.available = function() {
|
||||
|
||||
@@ -3,7 +3,9 @@ iD.operations.Split = function(selection, context) {
|
||||
action = iD.actions.Split(entityId);
|
||||
|
||||
var operation = function() {
|
||||
context.perform(action, t('operations.split.annotation'));
|
||||
var annotation = t('operations.split.annotation'),
|
||||
difference = context.perform(action, annotation);
|
||||
context.enter(iD.modes.Select(context, difference.extantIDs()));
|
||||
};
|
||||
|
||||
operation.available = function() {
|
||||
|
||||
+4
-37
@@ -26,9 +26,6 @@ iD.Map = function(context) {
|
||||
surface, tilegroup;
|
||||
|
||||
function map(selection) {
|
||||
context.connection()
|
||||
.on('load.tile', connectionLoad);
|
||||
|
||||
context.history()
|
||||
.on('change.map', redraw);
|
||||
|
||||
@@ -64,44 +61,19 @@ iD.Map = function(context) {
|
||||
extent = map.extent(),
|
||||
graph = context.graph();
|
||||
|
||||
function addParents(parents) {
|
||||
for (var i = 0; i < parents.length; i++) {
|
||||
var parent = parents[i];
|
||||
if (only[parent.id] === undefined) {
|
||||
only[parent.id] = parent;
|
||||
addParents(graph.parentRelations(parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!difference) {
|
||||
all = graph.intersects(extent);
|
||||
filter = d3.functor(true);
|
||||
} else {
|
||||
var only = {};
|
||||
|
||||
for (var j = 0; j < difference.length; j++) {
|
||||
var id = difference[j],
|
||||
entity = graph.entity(id);
|
||||
|
||||
// Even if the entity is false (deleted), it needs to be
|
||||
// removed from the surface
|
||||
only[id] = entity;
|
||||
|
||||
if (entity && entity.intersects(extent, graph)) {
|
||||
addParents(graph.parentWays(only[id]));
|
||||
addParents(graph.parentRelations(only[id]));
|
||||
}
|
||||
}
|
||||
|
||||
all = _.compact(_.values(only));
|
||||
var complete = difference.complete(extent);
|
||||
all = _.compact(_.values(complete));
|
||||
filter = function(d) {
|
||||
if (d.type === 'midpoint') {
|
||||
for (var i = 0; i < d.ways.length; i++) {
|
||||
if (d.ways[i].id in only) return true;
|
||||
if (d.ways[i].id in complete) return true;
|
||||
}
|
||||
} else {
|
||||
return d.id in only;
|
||||
return d.id in complete;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -125,11 +97,6 @@ iD.Map = function(context) {
|
||||
surface.selectAll('.layer *').remove();
|
||||
}
|
||||
|
||||
function connectionLoad(err, result) {
|
||||
context.history().merge(result);
|
||||
redraw(Object.keys(result));
|
||||
}
|
||||
|
||||
function zoomPan() {
|
||||
if (d3.event && d3.event.sourceEvent.type === 'dblclick') {
|
||||
if (!dblclickEnabled) {
|
||||
|
||||
+19
-21
@@ -15,31 +15,29 @@ iD.validate = function(changes, graph) {
|
||||
if (tags.building && tags.building === 'yes') return 'building=yes';
|
||||
}
|
||||
|
||||
if (changes.created.length) {
|
||||
for (var i = 0; i < changes.created.length; i++) {
|
||||
change = changes.created[i];
|
||||
for (var i = 0; i < changes.created.length; i++) {
|
||||
change = changes.created[i];
|
||||
|
||||
if (change.geometry(graph) === 'point' && _.isEmpty(change.tags)) {
|
||||
warnings.push({
|
||||
message: t('validations.untagged_point'),
|
||||
entity: change
|
||||
});
|
||||
}
|
||||
if (change.geometry(graph) === 'point' && _.isEmpty(change.tags)) {
|
||||
warnings.push({
|
||||
message: t('validations.untagged_point'),
|
||||
entity: change
|
||||
});
|
||||
}
|
||||
|
||||
if (change.geometry(graph) === 'line' && _.isEmpty(change.tags)) {
|
||||
warnings.push({ message: t('validations.untagged_line'), entity: change });
|
||||
}
|
||||
if (change.geometry(graph) === 'line' && _.isEmpty(change.tags)) {
|
||||
warnings.push({ message: t('validations.untagged_line'), entity: change });
|
||||
}
|
||||
|
||||
if (change.geometry(graph) === 'area' && _.isEmpty(change.tags)) {
|
||||
warnings.push({ message: t('validations.untagged_area'), entity: change });
|
||||
}
|
||||
if (change.geometry(graph) === 'area' && _.isEmpty(change.tags)) {
|
||||
warnings.push({ message: t('validations.untagged_area'), entity: change });
|
||||
}
|
||||
|
||||
if (change.geometry(graph) === 'line' && tagSuggestsArea(change)) {
|
||||
warnings.push({
|
||||
message: t('validations.tag_suggests_area', {tag: tagSuggestsArea(change)}),
|
||||
entity: change
|
||||
});
|
||||
}
|
||||
if (change.geometry(graph) === 'line' && tagSuggestsArea(change)) {
|
||||
warnings.push({
|
||||
message: t('validations.tag_suggests_area', {tag: tagSuggestsArea(change)}),
|
||||
entity: change
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
<script src='../js/id/operations/reverse.js'></script>
|
||||
<script src='../js/id/operations/split.js'></script>
|
||||
|
||||
<script src='../js/id/graph/difference.js'></script>
|
||||
<script src='../js/id/graph/entity.js'></script>
|
||||
<script src='../js/id/graph/graph.js'></script>
|
||||
<script src='../js/id/graph/history.js'></script>
|
||||
@@ -164,6 +165,7 @@
|
||||
<script src="spec/graph/way.js"></script>
|
||||
<script src="spec/graph/relation.js"></script>
|
||||
<script src="spec/graph/history.js"></script>
|
||||
<script src="spec/graph/difference.js"></script>
|
||||
|
||||
<script src="spec/renderer/background.js"></script>
|
||||
<script src="spec/renderer/map.js"></script>
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
<script src="spec/graph/way.js"></script>
|
||||
<script src="spec/graph/relation.js"></script>
|
||||
<script src="spec/graph/history.js"></script>
|
||||
<script src="spec/graph/difference.js"></script>
|
||||
|
||||
<script src="spec/renderer/background.js"></script>
|
||||
<script src="spec/renderer/map.js"></script>
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
describe("iD.Difference", function () {
|
||||
describe("#changes", function () {
|
||||
it("includes created entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph(),
|
||||
head = base.replace(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.changes()).to.eql({n: {base: undefined, head: node}});
|
||||
});
|
||||
|
||||
it("includes undone created entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph(),
|
||||
head = base.replace(node),
|
||||
diff = iD.Difference(head, base);
|
||||
expect(diff.changes()).to.eql({n: {base: node, head: undefined}});
|
||||
});
|
||||
|
||||
it("includes modified entities", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.update(),
|
||||
base = iD.Graph([n1]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.changes()).to.eql({n: {base: n1, head: n2}});
|
||||
});
|
||||
|
||||
it("includes undone modified entities", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.update(),
|
||||
base = iD.Graph([n1]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(head, base);
|
||||
expect(diff.changes()).to.eql({n: {base: n2, head: n1}});
|
||||
});
|
||||
|
||||
it("includes deleted entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph([node]),
|
||||
head = base.remove(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.changes()).to.eql({n: {base: node, head: undefined}});
|
||||
});
|
||||
|
||||
it("includes undone deleted entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph([node]),
|
||||
head = base.remove(node),
|
||||
diff = iD.Difference(head, base);
|
||||
expect(diff.changes()).to.eql({n: {base: undefined, head: node}});
|
||||
});
|
||||
|
||||
it("doesn't include created entities that were subsequently deleted", function () {
|
||||
var node = iD.Node(),
|
||||
base = iD.Graph(),
|
||||
head = base.replace(node).remove(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.changes()).to.eql({});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#extantIDs", function () {
|
||||
it("includes the ids of created entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph(),
|
||||
head = base.replace(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.extantIDs()).to.eql(['n']);
|
||||
});
|
||||
|
||||
it("includes the ids of modified entities", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.move([1, 2]),
|
||||
base = iD.Graph([n1]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.extantIDs()).to.eql(['n']);
|
||||
});
|
||||
|
||||
it("omits the ids of deleted entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph([node]),
|
||||
head = base.remove(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.extantIDs()).to.eql([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#created", function () {
|
||||
it("returns an array of created entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph(),
|
||||
head = base.replace(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.created()).to.eql([node]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#modified", function () {
|
||||
it("returns an array of modified entities", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.move([1, 2]),
|
||||
base = iD.Graph([n1]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.modified()).to.eql([n2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#deleted", function () {
|
||||
it("returns an array of deleted entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph([node]),
|
||||
head = base.remove(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.deleted()).to.eql([node]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#complete", function () {
|
||||
it("includes created entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph(),
|
||||
head = base.replace(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.complete()['n']).to.equal(node);
|
||||
});
|
||||
|
||||
it("includes modified entities", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.move([1, 2]),
|
||||
base = iD.Graph([n1]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.complete()['n']).to.equal(n2);
|
||||
});
|
||||
|
||||
it("includes deleted entities", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
base = iD.Graph([node]),
|
||||
head = base.remove(node),
|
||||
diff = iD.Difference(base, head);
|
||||
expect(diff.complete()).to.eql({n: undefined});
|
||||
});
|
||||
|
||||
it("includes nodes added to a way", function () {
|
||||
var n1 = iD.Node({id: 'n1'}),
|
||||
n2 = iD.Node({id: 'n2'}),
|
||||
w1 = iD.Way({id: 'w', nodes: ['n1']}),
|
||||
w2 = w1.addNode('n2'),
|
||||
base = iD.Graph([n1, n2, w1]),
|
||||
head = base.replace(w2),
|
||||
diff = iD.Difference(base, head);
|
||||
|
||||
expect(diff.complete()['n2']).to.equal(n2);
|
||||
});
|
||||
|
||||
it("includes nodes removed from a way", function () {
|
||||
var n1 = iD.Node({id: 'n1'}),
|
||||
n2 = iD.Node({id: 'n2'}),
|
||||
w1 = iD.Way({id: 'w', nodes: ['n1', 'n2']}),
|
||||
w2 = w1.removeNode('n2'),
|
||||
base = iD.Graph([n1, n2, w1]),
|
||||
head = base.replace(w2),
|
||||
diff = iD.Difference(base, head);
|
||||
|
||||
expect(diff.complete()['n2']).to.equal(n2);
|
||||
});
|
||||
|
||||
it("includes parent ways of modified nodes", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.move([1, 2]),
|
||||
way = iD.Way({id: 'w', nodes: ['n']}),
|
||||
base = iD.Graph([n1, way]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(base, head);
|
||||
|
||||
expect(diff.complete()['w']).to.equal(way);
|
||||
});
|
||||
|
||||
it("includes parent relations of modified entities", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.move([1, 2]),
|
||||
rel = iD.Relation({id: 'r', members: [{id: 'n'}]}),
|
||||
base = iD.Graph([n1, rel]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(base, head);
|
||||
|
||||
expect(diff.complete()['r']).to.equal(rel);
|
||||
});
|
||||
|
||||
it("includes parent relations of modified entities, recursively", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.move([1, 2]),
|
||||
rel1 = iD.Relation({id: 'r1', members: [{id: 'n'}]}),
|
||||
rel2 = iD.Relation({id: 'r2', members: [{id: 'r1'}]}),
|
||||
base = iD.Graph([n1, rel1, rel2]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(base, head);
|
||||
|
||||
expect(diff.complete()['r2']).to.equal(rel2);
|
||||
});
|
||||
|
||||
it("includes parent relations of parent ways of modified nodes", function () {
|
||||
var n1 = iD.Node({id: 'n'}),
|
||||
n2 = n1.move([1, 2]),
|
||||
way = iD.Way({id: 'w', nodes: ['n']}),
|
||||
rel = iD.Relation({id: 'r', members: [{id: 'w'}]}),
|
||||
base = iD.Graph([n1, way, rel]),
|
||||
head = base.replace(n2),
|
||||
diff = iD.Difference(base, head);
|
||||
|
||||
expect(diff.complete()['r']).to.equal(rel);
|
||||
});
|
||||
|
||||
it("copes with recursive relations", function () {
|
||||
var node = iD.Node({id: 'n'}),
|
||||
rel1 = iD.Relation({id: 'r1', members: [{id: 'n'}, {id: 'r2'}]}),
|
||||
rel2 = iD.Relation({id: 'r2', members: [{id: 'r1'}]}),
|
||||
base = iD.Graph([node, rel1, rel2]),
|
||||
head = base.replace(node.move([1, 2])),
|
||||
diff = iD.Difference(base, head);
|
||||
|
||||
expect(diff.complete()).to.be.ok;
|
||||
});
|
||||
|
||||
it("limits changes to those within a given extent");
|
||||
});
|
||||
});
|
||||
@@ -52,12 +52,6 @@ describe('iD.Entity', function () {
|
||||
expect(e.id).to.equal('w1');
|
||||
});
|
||||
|
||||
it("tags the entity as updated", function () {
|
||||
var tags = {foo: 'bar'},
|
||||
e = iD.Entity().update({tags: tags});
|
||||
expect(e._updated).to.to.be.true;
|
||||
});
|
||||
|
||||
it("doesn't modify the input", function () {
|
||||
var attrs = {tags: {foo: 'bar'}},
|
||||
e = iD.Entity().update(attrs);
|
||||
@@ -104,42 +98,6 @@ describe('iD.Entity', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#created", function () {
|
||||
it("returns falsy by default", function () {
|
||||
expect(iD.Entity({id: 'w1234'}).created()).not.to.be.ok;
|
||||
});
|
||||
|
||||
it("returns falsy for an unmodified Entity", function () {
|
||||
expect(iD.Entity({id: 'w1234'}).created()).not.to.be.ok;
|
||||
});
|
||||
|
||||
it("returns falsy for a modified Entity with positive ID", function () {
|
||||
expect(iD.Entity({id: 'w1234'}).update({}).created()).not.to.be.ok;
|
||||
});
|
||||
|
||||
it("returns truthy for a modified Entity with negative ID", function () {
|
||||
expect(iD.Entity({id: 'w-1234'}).update({}).created()).to.be.ok;
|
||||
});
|
||||
});
|
||||
|
||||
describe("#modified", function () {
|
||||
it("returns falsy by default", function () {
|
||||
expect(iD.Entity({id: 'w1234'}).modified()).not.to.be.ok;
|
||||
});
|
||||
|
||||
it("returns falsy for an unmodified Entity", function () {
|
||||
expect(iD.Entity({id: 'w1234'}).modified()).not.to.be.ok;
|
||||
});
|
||||
|
||||
it("returns truthy for a modified Entity with positive ID", function () {
|
||||
expect(iD.Entity({id: 'w1234'}).update({}).modified()).to.be.ok;
|
||||
});
|
||||
|
||||
it("returns falsy for a modified Entity with negative ID", function () {
|
||||
expect(iD.Entity({id: 'w-1234'}).update({}).modified()).not.to.be.ok;
|
||||
});
|
||||
});
|
||||
|
||||
describe("#intersects", function () {
|
||||
it("returns true for a way with a node within the given extent", function () {
|
||||
var node = iD.Node({loc: [0, 0]}),
|
||||
|
||||
@@ -333,86 +333,4 @@ describe('iD.Graph', function() {
|
||||
expect(graph.childNodes(way)).to.eql([node]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#difference", function () {
|
||||
it("returns an Array of ids of changed entities", function () {
|
||||
var initial = iD.Node({id: "n1"}),
|
||||
updated = initial.update({}),
|
||||
created = iD.Node(),
|
||||
deleted = iD.Node({id: 'n2'}),
|
||||
graph1 = iD.Graph([initial, deleted]),
|
||||
graph2 = graph1.replace(updated).replace(created).remove(deleted);
|
||||
expect(graph2.difference(graph1)).to.eql([created.id, updated.id, deleted.id]);
|
||||
});
|
||||
|
||||
|
||||
it("includes created entities, and reverse", function () {
|
||||
var node = iD.Node(),
|
||||
graph1 = iD.Graph(),
|
||||
graph2 = graph1.replace(node);
|
||||
expect(graph2.difference(graph1)).to.eql([node.id]);
|
||||
expect(graph1.difference(graph2)).to.eql([node.id]);
|
||||
});
|
||||
|
||||
it("includes entities changed from base, and reverse", function () {
|
||||
var node = iD.Node(),
|
||||
graph1 = iD.Graph(node),
|
||||
graph2 = graph1.replace(node.update());
|
||||
expect(graph2.difference(graph1)).to.eql([node.id]);
|
||||
expect(graph1.difference(graph2)).to.eql([node.id]);
|
||||
});
|
||||
|
||||
it("includes already changed entities that were updated, and reverse", function () {
|
||||
var node = iD.Node(),
|
||||
graph1 = iD.Graph().replace(node),
|
||||
graph2 = graph1.replace(node.update());
|
||||
expect(graph2.difference(graph1)).to.eql([node.id]);
|
||||
expect(graph1.difference(graph2)).to.eql([node.id]);
|
||||
});
|
||||
|
||||
it("includes affected child nodes", function () {
|
||||
var n = iD.Node({id: 'n'}),
|
||||
n2 = iD.Node({id: 'n2'}),
|
||||
w1 = iD.Way({id: 'w1', nodes: ['n']}),
|
||||
w1_ = iD.Way({id: 'w1', nodes: ['n', 'n2']}),
|
||||
graph1 = iD.Graph([n, n2, w1]),
|
||||
graph2 = graph1.replace(w1_);
|
||||
expect(graph2.difference(graph1)).to.eql(['n2', 'w1']);
|
||||
expect(graph1.difference(graph2)).to.eql(['n2', 'w1']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("#modified", function () {
|
||||
it("returns an Array of ids of modified entities", function () {
|
||||
var node = iD.Node({id: 'n1'}),
|
||||
node_ = iD.Node({id: 'n1'}),
|
||||
graph = iD.Graph([node]).replace(node_);
|
||||
expect(graph.modified()).to.eql([node.id]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#created", function () {
|
||||
it("returns an Array of ids of created entities", function () {
|
||||
var node1 = iD.Node({id: 'n-1'}),
|
||||
node2 = iD.Node({id: 'n2'}),
|
||||
graph = iD.Graph([node2]).replace(node1);
|
||||
expect(graph.created()).to.eql([node1.id]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#deleted", function () {
|
||||
it("returns an Array of ids of deleted entities", function () {
|
||||
var node1 = iD.Node({id: "n1"}),
|
||||
node2 = iD.Node(),
|
||||
graph = iD.Graph([node1, node2]).remove(node1);
|
||||
expect(graph.deleted()).to.eql([node1.id]);
|
||||
});
|
||||
|
||||
it("doesn't include created entities that were subsequently deleted", function () {
|
||||
var node = iD.Node(),
|
||||
graph = iD.Graph().replace(node).remove(node);
|
||||
expect(graph.deleted()).to.eql([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+45
-10
@@ -13,7 +13,25 @@ describe("iD.History", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#merge", function () {
|
||||
it("merges the entities into all graph versions", function () {
|
||||
var n = iD.Node({id: 'n'});
|
||||
history.merge({n: n});
|
||||
expect(history.graph().entity('n')).to.equal(n);
|
||||
});
|
||||
|
||||
it("emits a change event", function () {
|
||||
history.on('change', spy);
|
||||
history.merge({});
|
||||
expect(spy).to.have.been.called;
|
||||
});
|
||||
});
|
||||
|
||||
describe("#perform", function () {
|
||||
it("returns a difference", function () {
|
||||
expect(history.perform(action).changes()).to.eql({});
|
||||
});
|
||||
|
||||
it("updates the graph", function () {
|
||||
var node = iD.Node();
|
||||
history.perform(function (graph) { return graph.replace(node); });
|
||||
@@ -27,8 +45,8 @@ describe("iD.History", function () {
|
||||
|
||||
it("emits a change event", function () {
|
||||
history.on('change', spy);
|
||||
history.perform(action);
|
||||
expect(spy).to.have.been.calledWith([]);
|
||||
var difference = history.perform(action);
|
||||
expect(spy).to.have.been.calledWith(difference);
|
||||
});
|
||||
|
||||
it("performs multiple actions", function () {
|
||||
@@ -42,6 +60,10 @@ describe("iD.History", function () {
|
||||
});
|
||||
|
||||
describe("#replace", function () {
|
||||
it("returns a difference", function () {
|
||||
expect(history.replace(action).changes()).to.eql({});
|
||||
});
|
||||
|
||||
it("updates the graph", function () {
|
||||
var node = iD.Node();
|
||||
history.replace(function (graph) { return graph.replace(node); });
|
||||
@@ -56,8 +78,8 @@ describe("iD.History", function () {
|
||||
|
||||
it("emits a change event", function () {
|
||||
history.on('change', spy);
|
||||
history.replace(action);
|
||||
expect(spy).to.have.been.calledWith([]);
|
||||
var difference = history.replace(action);
|
||||
expect(spy).to.have.been.calledWith(difference);
|
||||
});
|
||||
|
||||
it("performs multiple actions", function () {
|
||||
@@ -71,6 +93,11 @@ describe("iD.History", function () {
|
||||
});
|
||||
|
||||
describe("#pop", function () {
|
||||
it("returns a difference", function () {
|
||||
history.perform(action, "annotation");
|
||||
expect(history.pop().changes()).to.eql({});
|
||||
});
|
||||
|
||||
it("updates the graph", function () {
|
||||
history.perform(action, "annotation");
|
||||
history.pop();
|
||||
@@ -86,12 +113,16 @@ describe("iD.History", function () {
|
||||
it("emits a change event", function () {
|
||||
history.perform(action);
|
||||
history.on('change', spy);
|
||||
history.pop();
|
||||
expect(spy).to.have.been.calledWith([]);
|
||||
var difference = history.pop();
|
||||
expect(spy).to.have.been.calledWith(difference);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#undo", function () {
|
||||
it("returns a difference", function () {
|
||||
expect(history.undo().changes()).to.eql({});
|
||||
});
|
||||
|
||||
it("pops the undo stack", function () {
|
||||
history.perform(action, "annotation");
|
||||
history.undo();
|
||||
@@ -121,12 +152,16 @@ describe("iD.History", function () {
|
||||
it("emits a change event", function () {
|
||||
history.perform(action);
|
||||
history.on('change', spy);
|
||||
history.undo();
|
||||
expect(spy).to.have.been.calledWith([]);
|
||||
var difference = history.undo();
|
||||
expect(spy).to.have.been.calledWith(difference);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#redo", function () {
|
||||
it("returns a difference", function () {
|
||||
expect(history.redo().changes()).to.eql({});
|
||||
});
|
||||
|
||||
it("emits an redone event", function () {
|
||||
history.perform(action);
|
||||
history.undo();
|
||||
@@ -139,8 +174,8 @@ describe("iD.History", function () {
|
||||
history.perform(action);
|
||||
history.undo();
|
||||
history.on('change', spy);
|
||||
history.redo();
|
||||
expect(spy).to.have.been.calledWith([]);
|
||||
var difference = history.redo();
|
||||
expect(spy).to.have.been.calledWith(difference);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -4,15 +4,6 @@ describe('iD.Node', function () {
|
||||
expect(iD.Node().type).to.equal("node");
|
||||
});
|
||||
|
||||
it("returns a created Entity if no ID is specified", function () {
|
||||
expect(iD.Node().created()).to.be.ok;
|
||||
});
|
||||
|
||||
it("returns an unmodified Entity if ID is specified", function () {
|
||||
expect(iD.Node({id: 'n1234'}).created()).not.to.be.ok;
|
||||
expect(iD.Node({id: 'n1234'}).modified()).not.to.be.ok;
|
||||
});
|
||||
|
||||
it("defaults tags to an empty object", function () {
|
||||
expect(iD.Node().tags).to.eql({});
|
||||
});
|
||||
|
||||
@@ -10,15 +10,6 @@ describe('iD.Relation', function () {
|
||||
expect(iD.Relation().type).to.equal("relation");
|
||||
});
|
||||
|
||||
it("returns a created Entity if no ID is specified", function () {
|
||||
expect(iD.Relation().created()).to.be.ok;
|
||||
});
|
||||
|
||||
it("returns an unmodified Entity if ID is specified", function () {
|
||||
expect(iD.Relation({id: 'r1234'}).created()).not.to.be.ok;
|
||||
expect(iD.Relation({id: 'r1234'}).modified()).not.to.be.ok;
|
||||
});
|
||||
|
||||
it("defaults members to an empty array", function () {
|
||||
expect(iD.Relation().members).to.eql([]);
|
||||
});
|
||||
|
||||
@@ -10,15 +10,6 @@ describe('iD.Way', function() {
|
||||
expect(iD.Way().type).to.equal("way");
|
||||
});
|
||||
|
||||
it("returns a created Entity if no ID is specified", function () {
|
||||
expect(iD.Way().created()).to.be.ok;
|
||||
});
|
||||
|
||||
it("returns an unmodified Entity if ID is specified", function () {
|
||||
expect(iD.Way({id: 'w1234'}).created()).not.to.be.ok;
|
||||
expect(iD.Way({id: 'w1234'}).modified()).not.to.be.ok;
|
||||
});
|
||||
|
||||
it("defaults nodes to an empty array", function () {
|
||||
expect(iD.Way().nodes).to.eql([]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user