Move the edit menu logic to uiInit

Make context the first argument of operation objects
Add Paste operation to edit menu when opening the context menu on a blank area of the map (close #2508)
This commit is contained in:
Quincy Morgan
2020-05-14 15:49:35 -04:00
parent c939924f83
commit db9eed2434
32 changed files with 256 additions and 148 deletions

View File

@@ -88,6 +88,15 @@ en:
annotation:
single: Copied a feature.
multiple: "Copied {n} features."
paste:
title: Paste
description:
single: "Add a duplicate {feature} here."
multiple: "Add {n} duplicate features here."
annotation:
single: Pasted a feature.
multiple: "Pasted {n} features."
nothing_copied: No features have been copied.
circularize:
title: Circularize
description:

12
dist/locales/en.json vendored
View File

@@ -114,6 +114,18 @@
"multiple": "Copied {n} features."
}
},
"paste": {
"title": "Paste",
"description": {
"single": "Add a duplicate {feature} here.",
"multiple": "Add {n} duplicate features here."
},
"annotation": {
"single": "Pasted a feature.",
"multiple": "Pasted {n} features."
},
"nothing_copied": "No features have been copied."
},
"circularize": {
"title": "Circularize",
"description": {

View File

@@ -6,7 +6,7 @@ import { geoExtent, geoPointInPolygon, geoVecSubtract } from '../geo';
import { modeMove } from '../modes/move';
import { uiCmd } from '../ui/cmd';
// see also `operationPaste`
export function behaviorPaste(context) {
function doPaste() {
@@ -22,13 +22,13 @@ export function behaviorPaste(context) {
if (!geoPointInPolygon(mouse, viewport)) return;
var extent = geoExtent();
var oldIDs = context.copyIDs();
if (!oldIDs.length) return;
var extent = geoExtent();
var oldGraph = context.copyGraph();
var newIDs = [];
if (!oldIDs.length) return;
var action = actionCopyEntities(oldIDs, oldGraph);
context.perform(action);

View File

@@ -1,7 +1,6 @@
import { event as d3_event, select as d3_select } from 'd3-selection';
import { geoVecLength } from '../geo';
import { prefs } from '../core/preferences';
import { modeBrowse } from '../modes/browse';
import { modeSelect } from '../modes/select';
import { modeSelectData } from '../modes/select_data';
@@ -12,8 +11,6 @@ import { utilFastMouse } from '../util/util';
export function behaviorSelect(context) {
// legacy option to show menu on every click
var _alwaysShowMenu = +prefs('edit-menu-show-always') === 1;
var _tolerancePx = 4;
var _lastPointerEvent = null;
var _showMenu = false;
@@ -35,7 +32,7 @@ export function behaviorSelect(context) {
function keydown() {
if (d3_event.keyCode === 32) {
// don't react to spacebar events during text input
// don't react to spacebar events during text input
var activeNode = document.activeElement;
if (activeNode && new Set(['INPUT', 'TEXTAREA']).has(activeNode.nodeName)) return;
}
@@ -80,7 +77,6 @@ export function behaviorSelect(context) {
} else if (d3_event.keyCode === 32) { // spacebar
d3_event.preventDefault();
_lastInteractionType = 'spacebar';
_showMenu = _alwaysShowMenu;
click();
}
}
@@ -98,8 +94,6 @@ export function behaviorSelect(context) {
d3_select(window)
.on(_pointerPrefix + 'up.select', pointerup, true);
_showMenu = _alwaysShowMenu;
}
@@ -176,6 +170,7 @@ export function behaviorSelect(context) {
if (entity) datum = entity;
if (datum && datum.type === 'midpoint') {
// treat targeting midpoints as if targeting the parent way
datum = datum.parents[0];
}
@@ -187,36 +182,27 @@ export function behaviorSelect(context) {
context.selectedErrorID(null);
if (!isMultiselect) {
if (selectedIDs.length > 1 && (_showMenu && !_alwaysShowMenu)) {
// multiple things already selected, just show the menu...
mode.reselect().showMenu(point, _lastInteractionType);
} else {
if (selectedIDs.length <= 1 || !_showMenu) {
// always enter modeSelect even if the entity is already
// selected since listeners may expect `context.enter` events,
// e.g. in the walkthrough
newMode = modeSelect(context, [datum.id]);
context.enter(newMode);
if (_showMenu) newMode.showMenu(point, _lastInteractionType);
}
} else {
if (selectedIDs.indexOf(datum.id) !== -1) {
// clicked entity is already in the selectedIDs list..
if (_showMenu && !_alwaysShowMenu) {
// don't deselect clicked entity, just show the menu.
mode.reselect().showMenu(point, _lastInteractionType);
} else {
if (!_showMenu) {
// deselect clicked entity, then reenter select mode or return to browse mode..
selectedIDs = selectedIDs.filter(function(id) { return id !== datum.id; });
context.enter(selectedIDs.length ? modeSelect(context, selectedIDs) : modeBrowse(context));
}
} else {
// clicked entity is not in the selected list, add it..
selectedIDs = selectedIDs.concat([datum.id]);
newMode = modeSelect(context, selectedIDs);
context.enter(newMode);
if (_showMenu) newMode.showMenu(point, _lastInteractionType);
}
}
@@ -243,6 +229,11 @@ export function behaviorSelect(context) {
}
}
context.ui().closeEditMenu();
// always request to show the edit menu in case the mode needs it
if (_showMenu) context.ui().showEditMenu(point, _lastInteractionType);
resetProperties();
}

View File

@@ -8,6 +8,7 @@ import { behaviorSelect } from '../behavior/select';
import { modeDragNode } from './drag_node';
import { modeDragNote } from './drag_note';
import { operationPaste } from '../operations/paste';
export function modeBrowse(context) {
var mode = {
@@ -60,5 +61,10 @@ export function modeBrowse(context) {
};
mode.operations = function() {
return [operationPaste(context)];
};
return mode;
}

View File

@@ -30,12 +30,12 @@ export function modeMove(context, entityIDs, baseGraph) {
var keybinding = utilKeybinding('move');
var behaviors = [
behaviorEdit(context),
operationCircularize(entityIDs, context).behavior,
operationDelete(entityIDs, context).behavior,
operationOrthogonalize(entityIDs, context).behavior,
operationReflectLong(entityIDs, context).behavior,
operationReflectShort(entityIDs, context).behavior,
operationRotate(entityIDs, context).behavior
operationCircularize(context, entityIDs).behavior,
operationDelete(context, entityIDs).behavior,
operationOrthogonalize(context, entityIDs).behavior,
operationReflectLong(context, entityIDs).behavior,
operationReflectShort(context, entityIDs).behavior,
operationRotate(context, entityIDs).behavior
];
var annotation = entityIDs.length === 1 ?
t('operations.move.annotation.' + context.graph().geometry(entityIDs[0])) :

View File

@@ -34,12 +34,12 @@ export function modeRotate(context, entityIDs) {
var keybinding = utilKeybinding('rotate');
var behaviors = [
behaviorEdit(context),
operationCircularize(entityIDs, context).behavior,
operationDelete(entityIDs, context).behavior,
operationMove(entityIDs, context).behavior,
operationOrthogonalize(entityIDs, context).behavior,
operationReflectLong(entityIDs, context).behavior,
operationReflectShort(entityIDs, context).behavior
operationCircularize(context, entityIDs).behavior,
operationDelete(context, entityIDs).behavior,
operationMove(context, entityIDs).behavior,
operationOrthogonalize(context, entityIDs).behavior,
operationReflectLong(context, entityIDs).behavior,
operationReflectShort(context, entityIDs).behavior
];
var annotation = entityIDs.length === 1 ?
t('operations.rotate.annotation.' + context.graph().geometry(entityIDs[0])) :

View File

@@ -17,7 +17,6 @@ import { modeDragNode } from './drag_node';
import { modeDragNote } from './drag_note';
import { osmNode, osmWay } from '../osm';
import * as Operations from '../operations/index';
import { uiEditMenu } from '../ui/edit_menu';
import { uiCmd } from '../ui/cmd';
import {
utilArrayIntersection, utilDeepMemberSelector, utilEntityOrDeepMemberSelector,
@@ -46,7 +45,6 @@ export function modeSelect(context, selectedIDs) {
modeDragNote(context).behavior
];
var inspector; // unused?
var _editMenu; // uiEditMenu
var _newFeature = false;
var _follow = false;
@@ -141,44 +139,6 @@ export function modeSelect(context, selectedIDs) {
}
function closeMenu() {
// remove any existing menu no matter how it was added
context.map().supersurface
.select('.edit-menu').remove();
}
mode.showMenu = function(anchorPoint, triggerType) {
// remove any displayed menu
closeMenu();
// disable menu if in wide selection, for example
if (!context.map().editableDataEnabled()) return;
// don't show the menu for relations alone
if (selectedIDs.every(function(id) {
return context.graph().geometry(id) === 'relation';
})) return;
var surfaceNode = context.surface().node();
if (surfaceNode.focus) { // FF doesn't support it
// focus the surface or else clicking off the menu may not trigger modeBrowse
surfaceNode.focus();
}
// don't load the menu until it's needed
if (!_editMenu) _editMenu = uiEditMenu(context);
_editMenu
.anchorLoc(anchorPoint)
.triggerType(triggerType)
.operations(operations);
// render the menu
context.map().supersurface.call(_editMenu);
};
mode.selectedIDs = function() {
return selectedIDs;
};
@@ -189,12 +149,6 @@ export function modeSelect(context, selectedIDs) {
};
mode.reselect = function() {
if (!checkSelectedIDs()) return;
return mode;
};
mode.newFeature = function(val) {
if (!arguments.length) return _newFeature;
_newFeature = val;
@@ -219,12 +173,12 @@ export function modeSelect(context, selectedIDs) {
});
operations = Object.values(Operations)
.map(function(o) { return o(selectedIDs, context); })
.map(function(o) { return o(context, selectedIDs); })
.filter(function(o) { return o.available() && o.id !== 'delete' && o.id !== 'downgrade'; });
var downgradeOperation = Operations.operationDowngrade(selectedIDs, context);
var downgradeOperation = Operations.operationDowngrade(context, selectedIDs);
// don't allow delete if downgrade is available
var lastOperation = !context.inIntro() && downgradeOperation.available() ? downgradeOperation : Operations.operationDelete(selectedIDs, context);
var lastOperation = !context.inIntro() && downgradeOperation.available() ? downgradeOperation : Operations.operationDelete(context, selectedIDs);
operations.push(lastOperation);
@@ -235,9 +189,13 @@ export function modeSelect(context, selectedIDs) {
});
// remove any displayed menu
closeMenu();
context.ui().closeEditMenu();
}
mode.operations = function() {
return operations;
};
mode.enter = function() {
if (!checkSelectedIDs()) return;
@@ -269,11 +227,10 @@ export function modeSelect(context, selectedIDs) {
// reselect after change in case relation members were removed or added
selectElements();
})
.on('undone.select', update)
.on('redone.select', update);
.on('undone.select', checkSelectedIDs)
.on('redone.select', checkSelectedIDs);
context.map()
.on('move.select', closeMenu)
.on('drawn.select', selectElements)
.on('crossEditableZoom.select', function() {
selectElements();
@@ -301,12 +258,6 @@ export function modeSelect(context, selectedIDs) {
}
function update() {
closeMenu();
checkSelectedIDs();
}
function didDoubleUp(loc) {
if (!context.map().withinEditableZoom()) return;
@@ -500,7 +451,7 @@ export function modeSelect(context, selectedIDs) {
d3_select(document)
.call(keybinding.unbind);
closeMenu();
context.ui().closeEditMenu();
context.history()
.on('change.select', null)

View File

@@ -4,7 +4,7 @@ import { behaviorOperation } from '../behavior/operation';
import { utilGetAllNodes } from '../util';
export function operationCircularize(selectedIDs, context) {
export function operationCircularize(context, selectedIDs) {
var _extent;
var _actions = selectedIDs.map(getAction).filter(Boolean);
var _amount = _actions.length === 1 ? 'single' : 'multiple';

View File

@@ -4,7 +4,7 @@ import { behaviorOperation } from '../behavior/operation';
import { utilArrayGroupBy } from '../util';
export function operationContinue(selectedIDs, context) {
export function operationContinue(context, selectedIDs) {
var graph = context.graph();
var entities = selectedIDs.map(function(id) { return graph.entity(id); });
var geometries = Object.assign(

View File

@@ -5,7 +5,7 @@ import { behaviorOperation } from '../behavior/operation';
import { uiCmd } from '../ui/cmd';
import { utilArrayGroupBy } from '../util';
export function operationCopy(selectedIDs, context) {
export function operationCopy(context, selectedIDs) {
function getFilteredIdsToCopy() {
return selectedIDs.filter(function(selectedID) {
@@ -112,7 +112,7 @@ export function operationCopy(selectedIDs, context) {
operation.annotation = function() {
return selectedIDs.length === 1 ?
t('operations.copy.annotation.single') :
t('operations.copy.annotation.multiple', { n: selectedIDs.length });
t('operations.copy.annotation.multiple', { n: selectedIDs.length.toString() });
};

View File

@@ -8,7 +8,7 @@ import { uiCmd } from '../ui/cmd';
import { utilGetAllNodes } from '../util';
export function operationDelete(selectedIDs, context) {
export function operationDelete(context, selectedIDs) {
var multi = (selectedIDs.length === 1 ? 'single' : 'multiple');
var action = actionDeleteMultiple(selectedIDs);
var nodes = utilGetAllNodes(selectedIDs, context.graph());

View File

@@ -4,7 +4,7 @@ import { behaviorOperation } from '../behavior/operation';
import { utilGetAllNodes } from '../util/index';
export function operationDisconnect(selectedIDs, context) {
export function operationDisconnect(context, selectedIDs) {
var vertexIDs = [];
var wayIDs = [];
var otherIDs = [];

View File

@@ -5,7 +5,7 @@ import { t } from '../core/localizer';
import { uiCmd } from '../ui/cmd';
import { presetManager } from '../presets';
export function operationDowngrade(selectedIDs, context) {
export function operationDowngrade(context, selectedIDs) {
var affectedFeatureCount = 0;
var downgradeType;

View File

@@ -4,7 +4,7 @@ import { modeSelect } from '../modes/select';
import { t } from '../core/localizer';
import { presetManager } from '../presets';
export function operationExtract(selectedIDs, context) {
export function operationExtract(context, selectedIDs) {
var entityID = selectedIDs.length && selectedIDs[0];
var action = actionExtract(entityID);

View File

@@ -8,6 +8,7 @@ export { operationExtract } from './extract';
export { operationMerge } from './merge';
export { operationMove } from './move';
export { operationOrthogonalize } from './orthogonalize';
export { operationPaste } from './paste';
export { operationReflectShort, operationReflectLong } from './reflect';
export { operationReverse } from './reverse';
export { operationRotate } from './rotate';

View File

@@ -9,7 +9,7 @@ import { behaviorOperation } from '../behavior/operation';
import { modeSelect } from '../modes/select';
import { presetManager } from '../presets';
export function operationMerge(selectedIDs, context) {
export function operationMerge(context, selectedIDs) {
var join = actionJoin(selectedIDs);
var merge = actionMerge(selectedIDs);

View File

@@ -5,7 +5,7 @@ import { modeMove } from '../modes/move';
import { utilGetAllNodes } from '../util';
export function operationMove(selectedIDs, context) {
export function operationMove(context, selectedIDs) {
var multi = (selectedIDs.length === 1 ? 'single' : 'multiple');
var nodes = utilGetAllNodes(selectedIDs, context.graph());
var coords = nodes.map(function(n) { return n.loc; });

View File

@@ -4,7 +4,7 @@ import { behaviorOperation } from '../behavior/operation';
import { utilGetAllNodes } from '../util';
export function operationOrthogonalize(selectedIDs, context) {
export function operationOrthogonalize(context, selectedIDs) {
var _extent;
var _type;
var _actions = selectedIDs.map(chooseAction).filter(Boolean);

View File

@@ -0,0 +1,95 @@
import { actionCopyEntities } from '../actions/copy_entities';
import { actionMove } from '../actions/move';
import { modeSelect } from '../modes/select';
import { geoExtent, geoVecSubtract } from '../geo';
import { t } from '../core/localizer';
import { uiCmd } from '../ui/cmd';
import { utilDisplayLabel } from '../util/util';
// see also `behaviorPaste`
export function operationPaste(context) {
var _point;
var operation = function() {
if (!_point) return;
var oldIDs = context.copyIDs();
if (!oldIDs.length) return;
var projection = context.projection;
var extent = geoExtent();
var oldGraph = context.copyGraph();
var newIDs = [];
var action = actionCopyEntities(oldIDs, oldGraph);
context.perform(action);
var copies = action.copies();
var originals = new Set();
Object.values(copies).forEach(function(entity) { originals.add(entity.id); });
for (var id in copies) {
var oldEntity = oldGraph.entity(id);
var newEntity = copies[id];
extent._extend(oldEntity.extent(oldGraph));
// Exclude child nodes from newIDs if their parent way was also copied.
var parents = context.graph().parentWays(newEntity);
var parentCopied = parents.some(function(parent) {
return originals.has(parent.id);
});
if (!parentCopied) {
newIDs.push(newEntity.id);
}
}
// Put pasted objects where mouse pointer is..
var center = projection(extent.center());
var delta = geoVecSubtract(_point, center);
context.replace(actionMove(newIDs, delta, projection), operation.annotation());
context.enter(modeSelect(context, newIDs));
};
operation.point = function(val) {
_point = val;
return operation;
};
operation.available = function() {
return context.mode().id === 'browse';
};
operation.disabled = function() {
return !context.copyIDs().length;
};
operation.tooltip = function() {
var oldGraph = context.copyGraph();
var ids = context.copyIDs();
if (!ids.length) {
return t('operations.paste.nothing_copied');
}
return ids.length === 1 ?
t('operations.paste.description.single', { feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph) }) :
t('operations.paste.description.multiple', { n: ids.length.toString() });
};
operation.annotation = function() {
var ids = context.copyIDs();
return ids.length === 1 ?
t('operations.paste.annotation.single') :
t('operations.paste.annotation.multiple', { n: ids.length.toString() });
};
operation.id = 'paste';
operation.keys = [uiCmd('⌘V')];
operation.title = t('operations.paste.title');
return operation;
}

View File

@@ -5,17 +5,17 @@ import { geoExtent } from '../geo';
import { utilGetAllNodes } from '../util';
export function operationReflectShort(selectedIDs, context) {
return operationReflect(selectedIDs, context, 'short');
export function operationReflectShort(context, selectedIDs) {
return operationReflect(context, selectedIDs, 'short');
}
export function operationReflectLong(selectedIDs, context) {
return operationReflect(selectedIDs, context, 'long');
export function operationReflectLong(context, selectedIDs) {
return operationReflect(context, selectedIDs, 'long');
}
export function operationReflect(selectedIDs, context, axis) {
export function operationReflect(context, selectedIDs, axis) {
axis = axis || 'long';
var multi = (selectedIDs.length === 1 ? 'single' : 'multiple');
var nodes = utilGetAllNodes(selectedIDs, context.graph());

View File

@@ -3,7 +3,7 @@ import { actionReverse } from '../actions/reverse';
import { behaviorOperation } from '../behavior/operation';
export function operationReverse(selectedIDs, context) {
export function operationReverse(context, selectedIDs) {
var operation = function() {
context.perform(function combinedReverseAction(graph) {

View File

@@ -5,7 +5,7 @@ import { modeRotate } from '../modes/rotate';
import { utilGetAllNodes } from '../util';
export function operationRotate(selectedIDs, context) {
export function operationRotate(context, selectedIDs) {
var multi = (selectedIDs.length === 1 ? 'single' : 'multiple');
var nodes = utilGetAllNodes(selectedIDs, context.graph());
var coords = nodes.map(function(n) { return n.loc; });

View File

@@ -4,7 +4,7 @@ import { behaviorOperation } from '../behavior/operation';
import { modeSelect } from '../modes/select';
export function operationSplit(selectedIDs, context) {
export function operationSplit(context, selectedIDs) {
var vertices = selectedIDs
.filter(function(id) { return context.graph().geometry(id) === 'vertex'; });
var entityID = vertices[0];

View File

@@ -5,7 +5,7 @@ import { behaviorOperation } from '../behavior/operation';
import { utilArrayDifference, utilGetAllNodes } from '../util/index';
export function operationStraighten(selectedIDs, context) {
export function operationStraighten(context, selectedIDs) {
var wayIDs = selectedIDs.filter(function(id) { return id.charAt(0) === 'w'; });
var nodeIDs = selectedIDs.filter(function(id) { return id.charAt(0) === 'n'; });

View File

@@ -14,6 +14,7 @@ import { utilGetDimensions } from '../util/dimensions';
import { uiAccount } from './account';
import { uiAttribution } from './attribution';
import { uiContributors } from './contributors';
import { uiEditMenu } from './edit_menu';
import { uiFeatureInfo } from './feature_info';
import { uiFlash } from './flash';
import { uiFullScreen } from './full_screen';
@@ -548,6 +549,48 @@ export function uiInit(context) {
};
var _editMenu; // uiEditMenu
ui.showEditMenu = function(anchorPoint, triggerType, operations) {
// remove any displayed menu
ui.closeEditMenu();
if (!operations && context.mode().operations) operations = context.mode().operations();
if (!operations || !operations.length) return;
// disable menu if in wide selection, for example
if (!context.map().editableDataEnabled()) return;
var surfaceNode = context.surface().node();
if (surfaceNode.focus) { // FF doesn't support it
// focus the surface or else clicking off the menu may not trigger modeBrowse
surfaceNode.focus();
}
// don't load the menu until it's needed
if (!_editMenu) _editMenu = uiEditMenu(context);
operations.forEach(function(operation) {
if (operation.point) operation.point(anchorPoint);
});
_editMenu
.anchorLoc(anchorPoint)
.triggerType(triggerType)
.operations(operations);
// render the menu
context.map().supersurface.call(_editMenu);
};
ui.closeEditMenu = function() {
// remove any existing menu no matter how it was added
context.map().supersurface
.select('.edit-menu').remove();
};
var _saveLoading = d3_select(null);
context.uploader()

View File

@@ -53,7 +53,7 @@ export function uiPresetList(context) {
d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
d3_event.preventDefault();
d3_event.stopPropagation();
operationDelete(_entityIDs, context)();
operationDelete(context, _entityIDs)();
// hack to let undo work when search is autofocused
} else if (search.property('value').length === 0 &&

View File

@@ -65,7 +65,7 @@ export function validationDisconnectedWay() {
entityIds: [singleEntity.id],
onClick: function(context) {
var id = this.issue.entityIds[0];
var operation = operationDelete([id], context);
var operation = operationDelete(context, [id]);
if (!operation.disabled()) {
operation();
}

View File

@@ -107,12 +107,12 @@ export function validationMissingTag(context) {
var deleteOnClick;
var id = this.entityIds[0];
var operation = operationDelete([id], context);
var operation = operationDelete(context, [id]);
var disabledReasonID = operation.disabled();
if (!disabledReasonID) {
deleteOnClick = function(context) {
var id = this.issue.entityIds[0];
var operation = operationDelete([id], context);
var operation = operationDelete(context, [id]);
if (!operation.disabled()) {
operation();
}

View File

@@ -2,6 +2,6 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="20" height="20" viewBox="0 0 20 20">
<path d="M12,11 C12.276,11 12.5,11.224 12.5,11.5 L12.5,12.5 L13.5,12.5 C13.776,12.5 14,12.724 14,13 C14,13.276 13.776,13.5 13.5,13.5 L12.5,13.5 L12.5,14.5 C12.5,14.776 12.276,15 12,15 C11.724,15 11.5,14.776 11.5,14.5 L11.5,13.5 L10.5,13.5 C10.224,13.5 10,13.276 10,13 C10,12.724 10.224,12.5 10.5,12.5 L11.5,12.5 L11.5,11.5 C11.5,11.224 11.724,11 12,11 z" fill="inherit"/>
<path d="M16,8 C16.552,8 17,8.448 17,9 L17,17 C17,17.552 16.552,18 16,18 L8,18 C7.448,18 7,17.552 7,17 L7,9 C7,8.448 7.448,8 8,8 L16,8 z M15,10 L9,10 L9,16 L15,16 L15,10 z" fill="inherit"/>
<path d="M16,8 C16.552,8 17,8.448 17,9 L17,17 C17,17.552 16.552,18 16,18 L8,18 C7.448,18 7,17.552 7,17 L7,9 C7,8.448 7.448,8 8,8 L16,8 z M15,10 L9,10 L9,16 L15,16 L15,10 z" fill="currentColor"/>
<path d="M8.5,1.5 C9.26,1.654 8.943,1.478 9.466,2 L12,2 C12.552,2 13,2.448 13,3 L13,7 L11,7 L11,4 L9.466,4 C8.943,4.523 9.26,4.347 8.5,4.5 L6.5,4.5 C5.74,4.347 6.057,4.523 5.534,4 L4,4 L4,14 L6,14 L6,16 L3,16 C2.448,16 2,15.552 2,15 L2,3 C2,2.448 2.448,2 3,2 L5.534,2 C6.057,1.477 5.74,1.654 6.5,1.5 L8.5,1.5 z" fill="inherit"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -37,52 +37,52 @@ describe('iD.operationExtract', function () {
});
it('is not available for no selected ids', function () {
var result = iD.operationExtract([], fakeContext).available();
var result = iD.operationExtract(fakeContext, []).available();
expect(result).to.be.not.ok;
});
it('is not available for two selected ids', function () {
var result = iD.operationExtract(['a', 'b'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['a', 'b']).available();
expect(result).to.be.not.ok;
});
it('is not available for unknown selected id', function () {
var result = iD.operationExtract(['z'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['z']).available();
expect(result).to.be.not.ok;
});
it('is not available for selected way', function () {
var result = iD.operationExtract(['x'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['x']).available();
expect(result).to.be.not.ok;
});
it('is not available for selected node with tags, no parent way', function () {
var result = iD.operationExtract(['e'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['e']).available();
expect(result).to.be.not.ok;
});
it('is not available for selected node with no tags, no parent way', function () {
var result = iD.operationExtract(['f'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['f']).available();
expect(result).to.be.not.ok;
});
it('is not available for selected node with no tags, parent way', function () {
var result = iD.operationExtract(['c'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['c']).available();
expect(result).to.be.not.ok;
});
it('is not available for selected node with no tags, two parent ways', function () {
var result = iD.operationExtract(['d'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['d']).available();
expect(result).to.be.not.ok;
});
it('is available for selected node with tags, parent way', function () {
var result = iD.operationExtract(['a'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['a']).available();
expect(result).to.be.ok;
});
it('is available for selected node with tags, two parent ways', function () {
var result = iD.operationExtract(['b'], fakeContext).available();
var result = iD.operationExtract(fakeContext, ['b']).available();
expect(result).to.be.ok;
});
});
@@ -96,7 +96,7 @@ describe('iD.operationExtract', function () {
iD.osmNode(createFakeNode('c', false)),
iD.osmWay({ id: 'x', nodes: ['a', 'b', 'c'] })
]);
var result = iD.operationExtract(['b'], fakeContext).disabled();
var result = iD.operationExtract(fakeContext, ['b']).disabled();
expect(result).to.be.not.ok;
});
@@ -108,7 +108,7 @@ describe('iD.operationExtract', function () {
iD.osmWay({ id: 'x', nodes: ['a', 'b', 'c'] }),
iD.osmRelation({ id: 'r', members: [{ id: 'b', role: 'label' }] })
]);
var result = iD.operationExtract(['b'], fakeContext).disabled();
var result = iD.operationExtract(fakeContext, ['b']).disabled();
expect(result).to.be.not.ok;
});
@@ -133,7 +133,7 @@ describe('iD.operationExtract', function () {
]
})
]);
var result = iD.operationExtract(['d'], fakeContext).disabled();
var result = iD.operationExtract(fakeContext, ['d']).disabled();
expect(result).to.eql('restriction');
});
@@ -159,7 +159,7 @@ describe('iD.operationExtract', function () {
]
})
]);
var result = iD.operationExtract(['d'], fakeContext).disabled();
var result = iD.operationExtract(fakeContext, ['d']).disabled();
expect(result).to.eql('restriction');
});
});

View File

@@ -42,77 +42,77 @@ describe('iD.operationStraighten', function () {
});
it('is not available for no selected ids', function () {
var result = iD.operationStraighten([], fakeContext).available();
var result = iD.operationStraighten(fakeContext, []).available();
expect(result).to.be.not.ok;
});
it('is not available for way with only 2 nodes', function () {
var result = iD.operationStraighten(['w1'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w1']).available();
expect(result).to.be.not.ok;
});
it('is available for way with only 2 nodes connected to another 2-node way', function () {
var result = iD.operationStraighten(['w1', 'w1-2'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w1', 'w1-2']).available();
expect(result).to.be.ok;
});
it('is not available for non-continuous ways', function () {
var result = iD.operationStraighten(['w2', 'w4'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w2', 'w4']).available();
expect(result).to.be.not.ok;
});
it('is available for selected way with more than 2 nodes', function () {
var result = iD.operationStraighten(['w2'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w2']).available();
expect(result).to.be.ok;
});
it('is available for selected, ordered, continuous ways', function () {
var result = iD.operationStraighten(['w1', 'w2', 'w3'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w1', 'w2', 'w3']).available();
expect(result).to.be.ok;
});
it('is available for selected, un-ordered, continuous ways', function () {
var result = iD.operationStraighten(['w1', 'w3', 'w2'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w1', 'w3', 'w2']).available();
expect(result).to.be.ok;
});
it('is available for selected, continuous ways with different way-directions', function () {
var result = iD.operationStraighten(['w1', 'w3', 'w2-2'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w1', 'w3', 'w2-2']).available();
expect(result).to.be.ok;
});
it('is available for 2 selected nodes in the same way, more than one node apart', function () {
var result = iD.operationStraighten(['w5', 'n9', 'n11'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w5', 'n9', 'n11']).available();
expect(result).to.be.ok;
});
it('is available for 2 selected nodes in adjacent ways, more than one node apart', function () {
var result = iD.operationStraighten(['w2', 'w3', 'n5', 'n3'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w2', 'w3', 'n5', 'n3']).available();
expect(result).to.be.ok;
});
it('is available for 2 selected nodes in non-adjacent ways, providing inbetween ways are selected', function () {
var result = iD.operationStraighten(['n2', 'n7', 'w4', 'w1', 'w3', 'w2'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['n2', 'n7', 'w4', 'w1', 'w3', 'w2']).available();
expect(result).to.be.ok;
});
it('is available for 2 selected nodes in non-adjacent, non-same-directional ways, providing inbetween ways are selected', function () {
var result = iD.operationStraighten(['n2', 'n7', 'w4', 'w1', 'w3', 'w2-2'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['n2', 'n7', 'w4', 'w1', 'w3', 'w2-2']).available();
expect(result).to.be.ok;
});
it('is not available for nodes not on selected ways', function () {
var result = iD.operationStraighten(['w5', 'n4', 'n11'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w5', 'n4', 'n11']).available();
expect(result).to.be.not.ok;
});
it('is not available for one selected node', function () {
var result = iD.operationStraighten(['w5', 'n9'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w5', 'n9']).available();
expect(result).to.be.not.ok;
});
it('is not available for more than two selected nodes', function () {
var result = iD.operationStraighten(['w5', 'n9', 'n11', 'n12'], fakeContext).available();
var result = iD.operationStraighten(fakeContext, ['w5', 'n9', 'n11', 'n12']).available();
expect(result).to.be.not.ok;
});
});