Skip to content

Commit

Permalink
Prevent some actions on features that extend beyond the loaded map
Browse files Browse the repository at this point in the history
(closes #2248)
  • Loading branch information
bhousel committed Apr 9, 2019
1 parent 2660a85 commit df1a2ea
Show file tree
Hide file tree
Showing 18 changed files with 219 additions and 159 deletions.
15 changes: 15 additions & 0 deletions data/core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ en:
not_closed: This can't be made circular because it's not a loop.
too_large: This can't be made circular because not enough of it is currently visible.
connected_to_hidden: This can't be made circular because it is connected to a hidden feature.
not_downloaded: This can't be made circular because parts of it have not yet been downloaded.
orthogonalize:
title: Square
description:
Expand All @@ -115,13 +116,15 @@ en:
not_squarish: This can't be made square because it is not squarish.
too_large: This can't be made square because not enough of it is currently visible.
connected_to_hidden: This can't be made square because it is connected to a hidden feature.
not_downloaded: This can't be made square because parts of it have not yet been downloaded.
straighten:
title: Straighten
description: Straighten this line.
key: S
annotation: Straightened a line.
too_bendy: This can't be straightened because it bends too much.
connected_to_hidden: This line can't be straightened because it is connected to a hidden feature.
not_downloaded: This line can't be straightened because parts of it have not yet been downloaded.
delete:
title: Delete
description:
Expand All @@ -146,6 +149,9 @@ en:
connected_to_hidden:
single: This feature can't be deleted because it is connected to a hidden feature.
multiple: These features can't be deleted because some are connected to hidden features.
not_downloaded:
single: This feature can't be deleted because parts of it have not yet been downloaded.
multiple: These features can't be deleted because parts of them have not yet been downloaded.
has_wikidata_tag:
single: This feature can't be deleted because it has a Wikidata tag.
multiple: These features can't be deleted because some have Wikidata tags.
Expand Down Expand Up @@ -229,6 +235,9 @@ en:
connected_to_hidden:
single: This feature can't be moved because it is connected to a hidden feature.
multiple: These features can't be moved because some are connected to hidden features.
not_downloaded:
single: This feature can't be moved because parts of it have not yet been downloaded.
multiple: These features can't be moved because parts of them have not yet been downloaded.
reflect:
title:
long: Reflect Long
Expand Down Expand Up @@ -259,6 +268,9 @@ en:
connected_to_hidden:
single: This feature can't be reflected because it is connected to a hidden feature.
multiple: These features can't be reflected because some are connected to hidden features.
not_downloaded:
single: This feature can't be reflected because parts of it have not yet been downloaded.
multiple: These features can't be reflected because parts of them have not yet been downloaded.
rotate:
title: Rotate
description:
Expand All @@ -278,6 +290,9 @@ en:
connected_to_hidden:
single: This feature can't be rotated because it is connected to a hidden feature.
multiple: These features can't be rotated because some are connected to hidden features.
not_downloaded:
single: This feature can't be rotated because parts of it have not yet been downloaded.
multiple: These features can't be rotated because parts of them have not yet been downloaded.
reverse:
title: Reverse
description: Make this line go in the opposite direction.
Expand Down
25 changes: 22 additions & 3 deletions dist/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@
},
"not_closed": "This can't be made circular because it's not a loop.",
"too_large": "This can't be made circular because not enough of it is currently visible.",
"connected_to_hidden": "This can't be made circular because it is connected to a hidden feature."
"connected_to_hidden": "This can't be made circular because it is connected to a hidden feature.",
"not_downloaded": "This can't be made circular because parts of it have not yet been downloaded."
},
"orthogonalize": {
"title": "Square",
Expand All @@ -146,15 +147,17 @@
"square_enough": "This can't be made more square than it already is.",
"not_squarish": "This can't be made square because it is not squarish.",
"too_large": "This can't be made square because not enough of it is currently visible.",
"connected_to_hidden": "This can't be made square because it is connected to a hidden feature."
"connected_to_hidden": "This can't be made square because it is connected to a hidden feature.",
"not_downloaded": "This can't be made square because parts of it have not yet been downloaded."
},
"straighten": {
"title": "Straighten",
"description": "Straighten this line.",
"key": "S",
"annotation": "Straightened a line.",
"too_bendy": "This can't be straightened because it bends too much.",
"connected_to_hidden": "This line can't be straightened because it is connected to a hidden feature."
"connected_to_hidden": "This line can't be straightened because it is connected to a hidden feature.",
"not_downloaded": "This line can't be straightened because parts of it have not yet been downloaded."
},
"delete": {
"title": "Delete",
Expand Down Expand Up @@ -186,6 +189,10 @@
"single": "This feature can't be deleted because it is connected to a hidden feature.",
"multiple": "These features can't be deleted because some are connected to hidden features."
},
"not_downloaded": {
"single": "This feature can't be deleted because parts of it have not yet been downloaded.",
"multiple": "These features can't be deleted because parts of them have not yet been downloaded."
},
"has_wikidata_tag": {
"single": "This feature can't be deleted because it has a Wikidata tag.",
"multiple": "These features can't be deleted because some have Wikidata tags."
Expand Down Expand Up @@ -290,6 +297,10 @@
"connected_to_hidden": {
"single": "This feature can't be moved because it is connected to a hidden feature.",
"multiple": "These features can't be moved because some are connected to hidden features."
},
"not_downloaded": {
"single": "This feature can't be moved because parts of it have not yet been downloaded.",
"multiple": "These features can't be moved because parts of them have not yet been downloaded."
}
},
"reflect": {
Expand Down Expand Up @@ -332,6 +343,10 @@
"connected_to_hidden": {
"single": "This feature can't be reflected because it is connected to a hidden feature.",
"multiple": "These features can't be reflected because some are connected to hidden features."
},
"not_downloaded": {
"single": "This feature can't be reflected because parts of it have not yet been downloaded.",
"multiple": "These features can't be reflected because parts of them have not yet been downloaded."
}
},
"rotate": {
Expand All @@ -357,6 +372,10 @@
"connected_to_hidden": {
"single": "This feature can't be rotated because it is connected to a hidden feature.",
"multiple": "These features can't be rotated because some are connected to hidden features."
},
"not_downloaded": {
"single": "This feature can't be rotated because parts of it have not yet been downloaded.",
"multiple": "These features can't be rotated because parts of them have not yet been downloaded."
}
},
"reverse": {
Expand Down
3 changes: 2 additions & 1 deletion modules/actions/circularize.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,9 @@ export function actionCircularize(wayId, projection, maxAngle) {


action.disabled = function(graph) {
if (!graph.entity(wayId).isClosed())
if (!graph.entity(wayId).isClosed()) {
return 'not_closed';
}
};


Expand Down
6 changes: 3 additions & 3 deletions modules/core/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ export function setAreaKeys(value) {


export function coreContext() {
var context = {};
var dispatch = d3_dispatch('enter', 'exit', 'change');
var context = utilRebind({}, dispatch, 'on');

context.version = '2.14.3';

// create a special translation that contains the keys in place of the strings
Expand All @@ -54,8 +56,6 @@ export function coreContext() {
addTranslation('en', dataEn);
setLocale('en');

var dispatch = d3_dispatch('enter', 'exit', 'change');
context = utilRebind(context, dispatch, 'on');

// https://github.com/openstreetmap/iD/issues/772
// http://mathiasbynens.be/notes/localstorage-pattern#comment-9
Expand Down
4 changes: 2 additions & 2 deletions modules/core/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as Validations from '../validations/index';

export function coreValidator(context) {
var dispatch = d3_dispatch('validated');
var validator = {};
var validator = utilRebind({}, dispatch, 'on');

var _rules = {};
var _disabledRules = {};
Expand Down Expand Up @@ -305,7 +305,7 @@ export function coreValidator(context) {
});


return utilRebind(validator, dispatch, 'on');
return validator;
}


Expand Down
19 changes: 13 additions & 6 deletions modules/operations/circularize.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { t } from '../util/locale';
import { actionCircularize } from '../actions';
import { behaviorOperation } from '../behavior';
import { utilGetAllNodes } from '../util';


export function operationCircularize(selectedIDs, context) {
Expand All @@ -9,7 +10,8 @@ export function operationCircularize(selectedIDs, context) {
var extent = entity.extent(context.graph());
var geometry = context.geometry(entityID);
var action = actionCircularize(entityID, context.projection);

var nodes = utilGetAllNodes(selectedIDs, context.graph());
var coords = nodes.map(function(n) { return n.loc; });

var operation = function() {
context.perform(action, operation.annotation());
Expand All @@ -24,13 +26,18 @@ export function operationCircularize(selectedIDs, context) {


operation.disabled = function() {
var reason;
if (extent.percentContainedIn(context.extent()) < 0.8) {
reason = 'too_large';
var osm = context.connection();
var reason = action.disabled(context.graph());
if (reason) {
return reason;
} else if (extent.percentContainedIn(context.extent()) < 0.8) {
return 'too_large';
} else if (osm && !coords.every(osm.isDataLoaded)) {
return 'not_downloaded';
} else if (context.hasHiddenConnections(entityID)) {
reason = 'connected_to_hidden';
return 'connected_to_hidden';
}
return action.disabled(context.graph()) || reason;
return false;
};


Expand Down
9 changes: 6 additions & 3 deletions modules/operations/continue.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,20 @@ export function operationContinue(selectedIDs, context) {


operation.available = function() {
return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
return geometries.vertex.length === 1 &&
geometries.line.length <= 1 &&
!context.features().hasHiddenConnections(vertex, context.graph());
};


operation.disabled = function() {
var candidates = candidateWays();
if (candidates.length === 0)
if (candidates.length === 0) {
return 'not_eligible';
if (candidates.length > 1)
} else if (candidates.length > 1) {
return 'multiple';
}
return false;
};


Expand Down
54 changes: 29 additions & 25 deletions modules/operations/delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,42 @@ import { behaviorOperation } from '../behavior';
import { geoExtent, geoSphericalDistance } from '../geo';
import { modeBrowse, modeSelect } from '../modes';
import { uiCmd } from '../ui';
import { utilGetAllNodes } from '../util';


export function operationDelete(selectedIDs, context) {
var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
action = actionDeleteMultiple(selectedIDs),
extent = selectedIDs.reduce(function(extent, id) {
return extent.extend(context.entity(id).extent(context.graph()));
}, geoExtent());
var multi = (selectedIDs.length === 1 ? 'single' : 'multiple');
var action = actionDeleteMultiple(selectedIDs);
var nodes = utilGetAllNodes(selectedIDs, context.graph());
var coords = nodes.map(function(n) { return n.loc; });
var extent = nodes.reduce(function(extent, node) {
return extent.extend(node.extent(context.graph()));
}, geoExtent());


var operation = function() {
var nextSelectedID;
var nextSelectedLoc;

if (selectedIDs.length === 1) {
var id = selectedIDs[0],
entity = context.entity(id),
geometry = context.geometry(id),
parents = context.graph().parentWays(entity),
parent = parents[0];
var id = selectedIDs[0];
var entity = context.entity(id);
var geometry = context.geometry(id);
var parents = context.graph().parentWays(entity);
var parent = parents[0];

// Select the next closest node in the way.
if (geometry === 'vertex') {
var nodes = parent.nodes,
i = nodes.indexOf(id);
var nodes = parent.nodes;
var i = nodes.indexOf(id);

if (i === 0) {
i++;
} else if (i === nodes.length - 1) {
i--;
} else {
var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc);
var b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
i = a < b ? i - 1 : i + 1;
}

Expand Down Expand Up @@ -67,19 +70,21 @@ export function operationDelete(selectedIDs, context) {


operation.disabled = function() {
var reason;
var osm = context.connection();
if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
reason = 'too_large';
return 'too_large';
} else if (osm && !coords.every(osm.isDataLoaded)) {
return 'not_downloaded';
} else if (selectedIDs.some(context.hasHiddenConnections)) {
reason = 'connected_to_hidden';
return 'connected_to_hidden';
} else if (selectedIDs.some(protectedMember)) {
reason = 'part_of_relation';
return 'part_of_relation';
} else if (selectedIDs.some(incompleteRelation)) {
reason = 'incomplete_relation';
return 'incomplete_relation';
} else if (selectedIDs.some(hasWikidataTag)) {
reason = 'has_wikidata_tag';
return 'has_wikidata_tag';
}
return reason;
return false;

function hasWikidataTag(id) {
var entity = context.entity(id);
Expand All @@ -97,16 +102,15 @@ export function operationDelete(selectedIDs, context) {

var parents = context.graph().parentRelations(entity);
for (var i = 0; i < parents.length; i++) {
var parent = parents[i],
type = parent.tags.type,
role = parent.memberById(id).role || 'outer';
var parent = parents[i];
var type = parent.tags.type;
var role = parent.memberById(id).role || 'outer';
if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
return true;
}
}
return false;
}

};


Expand Down
13 changes: 8 additions & 5 deletions modules/operations/detach_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,22 @@ export function operationDetachNode(selectedIDs, context) {


operation.disabled = function () {
var reason;
if (selectedIDs.some(context.hasHiddenConnections)) {
reason = 'connected_to_hidden';
var reason = action.disabled(context.graph());
if (reason) {
return reason;
} else if (selectedIDs.some(context.hasHiddenConnections)) {
return 'connected_to_hidden';
}
return action.disabled(context.graph()) || reason;
return false;
};


operation.tooltip = function () {
var disableReason = operation.disabled();
if (disableReason) {
return t('operations.detach_node.' + disableReason,
{ relation: context.presets().item('type/restriction').name() });
{ relation: context.presets().item('type/restriction').name() }
);
} else {
return t('operations.detach_node.description');
}
Expand Down
Loading

0 comments on commit df1a2ea

Please sign in to comment.