diff --git a/index.html b/index.html
index f3129da2d..e1a84a50f 100644
--- a/index.html
+++ b/index.html
@@ -147,6 +147,7 @@
+
diff --git a/js/id/actions/copy_entity.js b/js/id/actions/copy_entity.js
new file mode 100644
index 000000000..3db8678b4
--- /dev/null
+++ b/js/id/actions/copy_entity.js
@@ -0,0 +1,11 @@
+iD.actions.CopyEntity = function(entity, deep) {
+ return function(graph) {
+ var newEntities = entity.copy({}, deep, graph);
+
+ for (var i = 0, imax = newEntities.length; i !== imax; i++) {
+ graph = graph.replace(newEntities[i]);
+ }
+
+ return graph;
+ };
+};
diff --git a/test/index.html b/test/index.html
index f5cc7da2a..a5039eedb 100644
--- a/test/index.html
+++ b/test/index.html
@@ -126,6 +126,7 @@
+
@@ -225,6 +226,7 @@
+
diff --git a/test/index_packaged.html b/test/index_packaged.html
index 9df77e3cc..324ed0b69 100644
--- a/test/index_packaged.html
+++ b/test/index_packaged.html
@@ -35,6 +35,7 @@
+
diff --git a/test/spec/actions/copy_entity.js b/test/spec/actions/copy_entity.js
new file mode 100644
index 000000000..14f2de0fb
--- /dev/null
+++ b/test/spec/actions/copy_entity.js
@@ -0,0 +1,76 @@
+describe("iD.actions.CopyEntity", function () {
+ it("copies a Node and adds it to the graph", function () {
+ var a = iD.Node({id: 'a'}),
+ base = iD.Graph([a]),
+ head = iD.actions.CopyEntity(a)(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('a')).to.be.ok;
+ expect(created).to.have.length(1);
+ expect(created[0]).to.be.an.instanceof(iD.Node);
+ });
+
+ it("shallow copies a Way and adds it to the graph", function () {
+ var a = iD.Node({id: 'a'}),
+ b = iD.Node({id: 'b'}),
+ w = iD.Way({id: 'w', nodes: ['a', 'b']}),
+ base = iD.Graph([a, b, w]),
+ head = iD.actions.CopyEntity(w)(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('w')).to.be.ok;
+ expect(created).to.have.length(1);
+ expect(created[0]).to.be.an.instanceof(iD.Way);
+ });
+
+ it("deep copies a Way and child Nodes and adds them to the graph", function () {
+ var a = iD.Node({id: 'a'}),
+ b = iD.Node({id: 'b'}),
+ w = iD.Way({id: 'w', nodes: ['a', 'b']}),
+ base = iD.Graph([a, b, w]),
+ head = iD.actions.CopyEntity(w, true)(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('w')).to.be.ok;
+ expect(created).to.have.length(3);
+ expect(created[0]).to.be.an.instanceof(iD.Way);
+ expect(created[1]).to.be.an.instanceof(iD.Node);
+ expect(created[2]).to.be.an.instanceof(iD.Node);
+ });
+
+ it("shallow copies a Relation and adds it to the graph", function () {
+ var a = iD.Node({id: 'a'}),
+ b = iD.Node({id: 'b'}),
+ w = iD.Way({id: 'w', nodes: ['a', 'b']}),
+ r = iD.Relation({id: 'r', members: [{id: 'w'}]}),
+ base = iD.Graph([a, b, w, r]),
+ head = iD.actions.CopyEntity(r)(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('r')).to.be.ok;
+ expect(created).to.have.length(1);
+ expect(created[0]).to.be.an.instanceof(iD.Relation);
+ });
+
+ it("deep copies a Relation, member Ways, and child Nodes and adds them to the graph", function () {
+ var a = iD.Node({id: 'a'}),
+ b = iD.Node({id: 'b'}),
+ w = iD.Way({id: 'w', nodes: ['a', 'b']}),
+ r = iD.Relation({id: 'r', members: [{id: 'w'}]}),
+ base = iD.Graph([a, b, w, r]),
+ head = iD.actions.CopyEntity(r, true)(base),
+ diff = iD.Difference(base, head),
+ created = diff.created();
+
+ expect(head.hasEntity('r')).to.be.ok;
+ expect(created).to.have.length(4);
+ expect(created[0]).to.be.an.instanceof(iD.Relation);
+ expect(created[1]).to.be.an.instanceof(iD.Way);
+ expect(created[2]).to.be.an.instanceof(iD.Node);
+ expect(created[3]).to.be.an.instanceof(iD.Node);
+ });
+});