diff --git a/data/core.yaml b/data/core.yaml index b7f7fbb1f1..d5af134585 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -309,6 +309,12 @@ en: description: Make this line go in the opposite direction. key: V annotation: Reversed a line. + cycle_highway_tag: + title: Cycle Highway Tag + description: Shortcut to cycle selected highway through several different tags. + key: C + annotation: Changed highway tag of selected way. + restriction: This operation is only permitted for highways and untagged lines. split: title: Split description: @@ -1855,6 +1861,7 @@ en: reflect_long: "Reflect features across the longer axis" reflect_short: "Reflect features across the shorter axis" delete: "Delete selected features" + cycle_highway_tag: "Change selected road type" commands: title: "Commands" copy: "Copy selected features" diff --git a/data/shortcuts.json b/data/shortcuts.json index ce189797c9..ed05ce6e36 100644 --- a/data/shortcuts.json +++ b/data/shortcuts.json @@ -280,6 +280,11 @@ "modifiers": ["⌘"], "shortcuts": ["⌫"], "text": "shortcuts.editing.operations.delete" + }, + { + "modifiers": ["⇧"], + "shortcuts": ["operations.cycle_highway_tag.key"], + "text": "shortcuts.editing.operations.cycle_highway_tag" } ] } diff --git a/modules/core/history.js b/modules/core/history.js index deefb97cb5..bb871d9c77 100644 --- a/modules/core/history.js +++ b/modules/core/history.js @@ -118,6 +118,11 @@ export function coreHistory(context) { }, + peekAnnotation: function() { + return _stack[_index].annotation; + }, + + merge: function(entities, extent) { var stack = _stack.map(function(state) { return state.graph; }); _stack[0].graph.rebase(entities, stack, false); diff --git a/modules/operations/cycle_highway_tag.js b/modules/operations/cycle_highway_tag.js new file mode 100644 index 0000000000..e2042ca63f --- /dev/null +++ b/modules/operations/cycle_highway_tag.js @@ -0,0 +1,75 @@ +import { t } from '../util/locale'; +import { actionChangeTags } from '../actions/index'; +import { behaviorOperation } from '../behavior/index'; + + +export function operationCycleHighwayTag(selectedIDs, context) { + var _entityID = selectedIDs[0]; + var _entity = context.entity(_entityID); + var _prevSelectedIDs; + var ROAD_TYPES = ['residential', 'service', 'track', 'unclassified', 'tertiary']; + + + var updateHighwayTag = function (tags) { + var idx = tags.highway ? ROAD_TYPES.indexOf(tags.highway) : -1; + tags.highway = ROAD_TYPES[(idx + 1) % ROAD_TYPES.length]; + }; + + + var operation = function() { + _entity = context.entity(_entityID); + // Calculate whether the changes since the last time this action ran + // are only to highway tags. + if (_prevSelectedIDs) { + var sameSelection = _prevSelectedIDs ? _prevSelectedIDs[0] === selectedIDs[0] : false; + } + + var tags = Object.assign({}, _entity.tags); + updateHighwayTag(tags); + + _prevSelectedIDs = selectedIDs; + + // context peeking tells us the last operation performed. Was it cycle road tags? + if (sameSelection && context.history().peekAnnotation() === operation.annotation()) { + // Coalesce the update of Highway type tags into the previous tag change + context.replace(actionChangeTags(_entityID, tags), operation.annotation()); + } else { + context.perform(actionChangeTags(_entityID, tags), operation.annotation()); + } + }; + + + operation.available = function() { + return selectedIDs.length === 1 && + _entity.type === 'way' && + new Set(_entity.nodes).size > 1; + }; + + + operation.disabled = function() { + if ( Object.keys(_entity.tags).length > 0 && !_entity.tags.highway) { + return 'restriction'; + } + }; + + + operation.tooltip = function() { + var disable = operation.disabled(); + return disable ? + t('operations.cycle_highway_tag.' + disable) : + t('operations.cycle_highway_tag.description'); + }; + + + operation.annotation = function() { + return t('operations.cycle_highway_tag.annotation'); + }; + + + operation.id = 'cycle_highway_tag'; + operation.keys = ['⇧' + t('operations.cycle_highway_tag.key')]; + operation.title = t('operations.cycle_highway_tag.title'); + operation.behavior = behaviorOperation(context).which(operation); + + return operation; +} diff --git a/modules/operations/index.js b/modules/operations/index.js index 77be52df1c..9034560532 100644 --- a/modules/operations/index.js +++ b/modules/operations/index.js @@ -12,3 +12,4 @@ export { operationReverse } from './reverse'; export { operationRotate } from './rotate'; export { operationSplit } from './split'; export { operationStraighten } from './straighten'; +export { operationCycleHighwayTag } from './cycle_highway_tag';