mirror of
https://github.com/FoggedLens/iD.git
synced 2026-03-31 01:09:22 +02:00
Add entity copy methods
This commit is contained in:
@@ -44,7 +44,11 @@ iD.Entity.prototype = {
|
||||
var source = sources[i];
|
||||
for (var prop in source) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, prop)) {
|
||||
this[prop] = source[prop];
|
||||
if (source[prop] === undefined) {
|
||||
delete this[prop];
|
||||
} else {
|
||||
this[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,6 +69,23 @@ iD.Entity.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
copy: function(attrs) {
|
||||
var clone = {},
|
||||
omit = {};
|
||||
|
||||
_.each(['tags', 'loc', 'nodes', 'members'], function(prop) {
|
||||
if (this.hasOwnProperty(prop)) clone[prop] = _.cloneDeep(this[prop]);
|
||||
}, this);
|
||||
|
||||
_.each(['id', 'user', 'v', 'version'], function(prop) {
|
||||
omit[prop] = undefined;
|
||||
});
|
||||
|
||||
// Returns an array so that we can support deep copying ways and relations.
|
||||
// The first array element will contain this.copy, followed by any descendants.
|
||||
return [ iD.Entity(this, _.extend(clone, (attrs || {}), omit)) ];
|
||||
},
|
||||
|
||||
osmId: function() {
|
||||
return iD.Entity.id.toOSM(this.id);
|
||||
},
|
||||
|
||||
@@ -20,6 +20,32 @@ _.extend(iD.Relation.prototype, {
|
||||
type: 'relation',
|
||||
members: [],
|
||||
|
||||
copy: function(attrs, deep, resolver) {
|
||||
var fn = iD.Entity.prototype.copy;
|
||||
|
||||
if (deep && resolver && this.isComplete(resolver)) {
|
||||
var members = [],
|
||||
descendants = [],
|
||||
replacements = {},
|
||||
i, oldmember, oldid, newid, child;
|
||||
|
||||
for (i = 0; i < this.members.length; i++) {
|
||||
oldmember = this.members[i];
|
||||
oldid = oldmember.id;
|
||||
newid = replacements[oldid];
|
||||
if (!newid) {
|
||||
child = resolver.entity(oldid).copy({}, true, resolver);
|
||||
newid = replacements[oldid] = child[0].id;
|
||||
descendants = child.concat(descendants);
|
||||
}
|
||||
members.push({id: newid, type: oldmember.type, role: oldmember.role});
|
||||
}
|
||||
return fn.call(this, _.extend(attrs, {members: members})).concat(descendants);
|
||||
} else {
|
||||
return fn.call(this, attrs);
|
||||
}
|
||||
},
|
||||
|
||||
extent: function(resolver, memo) {
|
||||
return resolver.transient(this, 'extent', function() {
|
||||
if (memo && memo[this.id]) return iD.geo.Extent();
|
||||
|
||||
@@ -12,6 +12,31 @@ _.extend(iD.Way.prototype, {
|
||||
type: 'way',
|
||||
nodes: [],
|
||||
|
||||
copy: function(attrs, deep, resolver) {
|
||||
var fn = iD.Entity.prototype.copy;
|
||||
|
||||
if (deep && resolver) {
|
||||
var nodes = [],
|
||||
descendants = [],
|
||||
replacements = {},
|
||||
i, oldid, newid, child;
|
||||
|
||||
for (i = 0; i < this.nodes.length; i++) {
|
||||
oldid = this.nodes[i];
|
||||
newid = replacements[oldid];
|
||||
if (!newid) {
|
||||
child = resolver.entity(oldid).copy();
|
||||
newid = replacements[oldid] = child[0].id;
|
||||
descendants = child.concat(descendants);
|
||||
}
|
||||
nodes.push(newid);
|
||||
}
|
||||
return fn.call(this, _.extend(attrs, {nodes: nodes})).concat(descendants);
|
||||
} else {
|
||||
return fn.call(this, attrs);
|
||||
}
|
||||
},
|
||||
|
||||
extent: function(resolver) {
|
||||
return resolver.transient(this, 'extent', function() {
|
||||
var extent = iD.geo.Extent();
|
||||
|
||||
@@ -36,6 +36,32 @@ describe('iD.Entity', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#copy", function () {
|
||||
it("returns a new Entity", function () {
|
||||
var a = iD.Entity(),
|
||||
result = a.copy();
|
||||
expect(result).to.have.length(1);
|
||||
expect(result[0]).to.be.an.instanceof(iD.Entity);
|
||||
expect(a).not.to.equal(result[0]);
|
||||
});
|
||||
|
||||
it("resets 'id', 'user', 'v', and 'version' properties", function () {
|
||||
var a = iD.Entity({id: 'n1234', version: 10, v: 4, user: 'bot-mode'}),
|
||||
b = a.copy()[0];
|
||||
expect(b.isNew()).to.be.ok;
|
||||
expect(b.version).to.be.undefined;
|
||||
expect(b.v).to.be.undefined;
|
||||
expect(b.user).to.be.undefined;
|
||||
});
|
||||
|
||||
it("copies tags", function () {
|
||||
var a = iD.Entity({id: 'n1234', version: 10, user: 'test', tags: {foo: 'foo'}}),
|
||||
b = a.copy()[0];
|
||||
expect(b.tags).not.to.equal(a.tags);
|
||||
expect(b.tags).to.deep.equal(a.tags);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#update", function () {
|
||||
it("returns a new Entity", function () {
|
||||
var a = iD.Entity(),
|
||||
|
||||
@@ -26,6 +26,54 @@ describe('iD.Relation', function () {
|
||||
expect(iD.Relation({tags: {foo: 'bar'}}).tags).to.eql({foo: 'bar'});
|
||||
});
|
||||
|
||||
describe("#copy", function () {
|
||||
it("returns a new Relation", function () {
|
||||
var r1 = iD.Relation({id: 'r1'}),
|
||||
result = r1.copy(),
|
||||
r2 = result[0];
|
||||
|
||||
expect(result).to.have.length(1);
|
||||
expect(r2).to.be.an.instanceof(iD.Relation);
|
||||
expect(r1).not.to.equal(r2);
|
||||
});
|
||||
|
||||
it("keeps same members when deep = false", function () {
|
||||
var a = iD.Node({id: 'a'}),
|
||||
b = iD.Node({id: 'b'}),
|
||||
c = iD.Node({id: 'c'}),
|
||||
w1 = iD.Way({id: 'w1', nodes: ['a','b','c','a']}),
|
||||
r1 = iD.Relation({id: 'r1', members: [{id: 'w1', role: 'outer'}]}),
|
||||
graph = iD.Graph([a, b, c, w1, r1]),
|
||||
result = r1.copy(),
|
||||
r2 = result[0];
|
||||
|
||||
expect(result).to.have.length(1);
|
||||
expect(r1.members).not.to.equal(r2.members);
|
||||
expect(r1.members).to.deep.equal(r2.members);
|
||||
});
|
||||
|
||||
it("makes new members when deep = true", function () {
|
||||
var a = iD.Node({id: 'a'}),
|
||||
b = iD.Node({id: 'b'}),
|
||||
c = iD.Node({id: 'c'}),
|
||||
w1 = iD.Way({id: 'w1', nodes: ['a','b','c','a']}),
|
||||
r1 = iD.Relation({id: 'r1', members: [{id: 'w1', role: 'outer'}]}),
|
||||
graph = iD.Graph([a, b, c, w1, r1]),
|
||||
result = r1.copy({}, true, graph),
|
||||
r2 = result[0];
|
||||
|
||||
expect(result).to.have.length(5);
|
||||
expect(result[0]).to.be.an.instanceof(iD.Relation);
|
||||
expect(result[1]).to.be.an.instanceof(iD.Way);
|
||||
expect(result[2]).to.be.an.instanceof(iD.Node);
|
||||
expect(result[3]).to.be.an.instanceof(iD.Node);
|
||||
expect(result[4]).to.be.an.instanceof(iD.Node);
|
||||
|
||||
expect(r2.members[0].id).not.to.equal(r1.members[0].id);
|
||||
expect(r2.members[0].role).to.equal(r1.members[0].role);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#extent", function () {
|
||||
it("returns the minimal extent containing the extents of all members", function () {
|
||||
var a = iD.Node({loc: [0, 0]}),
|
||||
|
||||
@@ -26,6 +26,53 @@ describe('iD.Way', function() {
|
||||
expect(iD.Way({tags: {foo: 'bar'}}).tags).to.eql({foo: 'bar'});
|
||||
});
|
||||
|
||||
describe("#copy", function () {
|
||||
it("returns a new Way", function () {
|
||||
var w1 = iD.Way({id: 'w1'}),
|
||||
result = w1.copy(),
|
||||
w2 = result[0];
|
||||
|
||||
expect(result).to.have.length(1);
|
||||
expect(w2).to.be.an.instanceof(iD.Way);
|
||||
expect(w1).not.to.equal(w2);
|
||||
});
|
||||
|
||||
it("keeps same nodes when deep = false", function () {
|
||||
var a = iD.Node({id: 'a'}),
|
||||
b = iD.Node({id: 'b'}),
|
||||
c = iD.Node({id: 'c'}),
|
||||
w1 = iD.Entity({id: 'w1', nodes: ['a','b','c','a']}),
|
||||
graph = iD.Graph([a, b, c, w1]),
|
||||
result = w1.copy(),
|
||||
w2 = result[0];
|
||||
|
||||
expect(result).to.have.length(1);
|
||||
expect(w1.nodes).not.to.equal(w2.nodes);
|
||||
expect(w1.nodes).to.deep.equal(w2.nodes);
|
||||
});
|
||||
|
||||
it("makes new nodes when deep = true", function () {
|
||||
var a = iD.Node({id: 'a'}),
|
||||
b = iD.Node({id: 'b'}),
|
||||
c = iD.Node({id: 'c'}),
|
||||
w1 = iD.Entity({id: 'w1', nodes: ['a','b','c','a']}),
|
||||
graph = iD.Graph([a, b, c, w1]),
|
||||
result = w1.copy({}, true, graph),
|
||||
w2 = result[0];
|
||||
|
||||
expect(result).to.have.length(4);
|
||||
expect(result[0]).to.be.an.instanceof(iD.Way);
|
||||
expect(result[1]).to.be.an.instanceof(iD.Node);
|
||||
expect(result[2]).to.be.an.instanceof(iD.Node);
|
||||
expect(result[3]).to.be.an.instanceof(iD.Node);
|
||||
|
||||
expect(w2.nodes[0]).not.to.equal(w1.nodes[0]);
|
||||
expect(w2.nodes[1]).not.to.equal(w1.nodes[1]);
|
||||
expect(w2.nodes[2]).not.to.equal(w1.nodes[2]);
|
||||
expect(w2.nodes[3]).to.equal(w2.nodes[0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#first", function () {
|
||||
it("returns the first node", function () {
|
||||
expect(iD.Way({nodes: ['a', 'b', 'c']}).first()).to.equal('a');
|
||||
|
||||
Reference in New Issue
Block a user