iD.behavior.Paste = function(context) { var keybinding = d3.keybinding('paste'); function omitTag(v, k) { return ( k === 'phone' || k === 'fax' || k === 'email' || k === 'website' || k === 'url' || k === 'note' || k === 'description' || k.indexOf('name') !== -1 || k.indexOf('wiki') === 0 || k.indexOf('addr:') === 0 || k.indexOf('contact:') === 0 ); } function doPaste() { d3.event.preventDefault(); var mouse = context.mouse(), projection = context.projection, viewport = iD.geo.Extent(projection.clipExtent()).polygon(); if (!iD.geo.pointInPolygon(mouse, viewport)) return; var extent = iD.geo.Extent(), oldIDs = context.copyIDs(), oldGraph = context.copyGraph(), newIDs = [], i, j; if (!oldIDs.length) return; for (i = 0; i < oldIDs.length; i++) { var oldEntity = oldGraph.entity(oldIDs[i]), action = iD.actions.CopyEntity(oldEntity.id, oldGraph, true), newEntities; extent._extend(oldEntity.extent(oldGraph)); context.perform(action); // First element in `newEntities` contains the copied Entity, // Subsequent array elements contain any descendants.. newEntities = action.newEntities(); newIDs.push(newEntities[0].id); for (j = 0; j < newEntities.length; j++) { var newEntity = newEntities[j], tags = _.omit(newEntity.tags, omitTag); context.perform(iD.actions.ChangeTags(newEntity.id, tags)); } } // Put pasted objects where mouse pointer is.. var center = projection(extent.center()), delta = [ mouse[0] - center[0], mouse[1] - center[1] ]; context.perform(iD.actions.Move(newIDs, delta, projection)); context.enter(iD.modes.Move(context, newIDs)); } function paste() { keybinding.on(iD.ui.cmd('⌘V'), doPaste); d3.select(document).call(keybinding); return paste; } paste.off = function() { d3.select(document).call(keybinding.off); }; return paste; };