Files
iD/modules/operations/copy.js

152 lines
4.4 KiB
JavaScript

import { event as d3_event } from 'd3-selection';
import { t } from '../core/localizer';
import { behaviorOperation } from '../behavior/operation';
import { uiCmd } from '../ui/cmd';
import { geoExtent } from '../geo';
import { utilArrayGroupBy, utilGetAllNodes } from '../util';
export function operationCopy(context, selectedIDs) {
var _multi = selectedIDs.length === 1 ? 'single' : 'multiple';
function getFilteredIdsToCopy() {
return selectedIDs.filter(function(selectedID) {
var entity = context.graph().hasEntity(selectedID);
// don't copy untagged vertices separately from ways
return entity.hasInterestingTags() || entity.geometry(context.graph()) !== 'vertex';
});
}
var operation = function() {
if (!getSelectionText()) {
d3_event.preventDefault();
}
var graph = context.graph();
var selected = groupEntities(getFilteredIdsToCopy(), graph);
var canCopy = [];
var skip = {};
var entity;
var i;
for (i = 0; i < selected.relation.length; i++) {
entity = selected.relation[i];
if (!skip[entity.id] && entity.isComplete(graph)) {
canCopy.push(entity.id);
skip = getDescendants(entity.id, graph, skip);
}
}
for (i = 0; i < selected.way.length; i++) {
entity = selected.way[i];
if (!skip[entity.id]) {
canCopy.push(entity.id);
skip = getDescendants(entity.id, graph, skip);
}
}
for (i = 0; i < selected.node.length; i++) {
entity = selected.node[i];
if (!skip[entity.id]) {
canCopy.push(entity.id);
}
}
context.copyIDs(canCopy);
if (_point &&
(canCopy.length !== 1 || graph.entity(canCopy[0]).type !== 'node')) {
// store the anchor coordinates if copying more than a single node
context.copyLonLat(context.projection.invert(_point));
} else {
context.copyLonLat(null);
}
};
function groupEntities(ids, graph) {
var entities = ids.map(function (id) { return graph.entity(id); });
return Object.assign(
{ relation: [], way: [], node: [] },
utilArrayGroupBy(entities, 'type')
);
}
function getDescendants(id, graph, descendants) {
var entity = graph.entity(id);
var children;
descendants = descendants || {};
if (entity.type === 'relation') {
children = entity.members.map(function(m) { return m.id; });
} else if (entity.type === 'way') {
children = entity.nodes;
} else {
children = [];
}
for (var i = 0; i < children.length; i++) {
if (!descendants[children[i]]) {
descendants[children[i]] = true;
descendants = getDescendants(children[i], graph, descendants);
}
}
return descendants;
}
function getSelectionText() {
return window.getSelection().toString();
}
operation.available = function() {
return getFilteredIdsToCopy().length > 0;
};
operation.disabled = function() {
var nodes = utilGetAllNodes(getFilteredIdsToCopy(), context.graph());
var extent = nodes.reduce(function(extent, node) {
return extent.extend(node.extent(context.graph()));
}, geoExtent());
if (extent.area() && extent.percentContainedIn(context.map().extent()) < 0.8) {
return 'too_large';
}
return false;
};
operation.tooltip = function() {
var disable = operation.disabled();
return disable ?
t('operations.copy.' + disable + '.' + _multi) :
t('operations.copy.description' + '.' + _multi);
};
operation.annotation = function() {
return selectedIDs.length === 1 ?
t('operations.copy.annotation.single') :
t('operations.copy.annotation.multiple', { n: selectedIDs.length.toString() });
};
var _point;
operation.point = function(val) {
_point = val;
return operation;
};
operation.id = 'copy';
operation.keys = [uiCmd('⌘C')];
operation.title = t('operations.copy.title');
operation.behavior = behaviorOperation(context).which(operation);
return operation;
}