mirror of
https://github.com/FoggedLens/iD.git
synced 2026-04-21 11:16:36 +02:00
Merge branch 'edit_menu'
This commit is contained in:
+152
-48
@@ -11,7 +11,7 @@ html, body {
|
||||
}
|
||||
|
||||
body {
|
||||
font: normal 12px/1.6667 -apple-system, BlinkMacSystemFont,
|
||||
font: normal 12px/1.6667 "-apple-system", BlinkMacSystemFont,
|
||||
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell",
|
||||
"Fira Sans", "Droid Sans", "Helvetica Neue", "Arial",
|
||||
sans-serif;
|
||||
@@ -564,6 +564,7 @@ button.save.has-count .count::before {
|
||||
min-width: 768px;
|
||||
}
|
||||
|
||||
|
||||
/* Header for modals / panes
|
||||
------------------------------------------------------- */
|
||||
|
||||
@@ -2499,14 +2500,14 @@ img.tile-removing {
|
||||
bottom:0;
|
||||
border-radius: 0;
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#attrib {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
margin-bottom: 5px;
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#attrib * { pointer-events: all; }
|
||||
@@ -2531,24 +2532,80 @@ img.tile-removing {
|
||||
}
|
||||
|
||||
.source-image {
|
||||
height:20px;
|
||||
height: 20px;
|
||||
vertical-align:top;
|
||||
}
|
||||
|
||||
#footer {
|
||||
width: 100%;
|
||||
float: left;
|
||||
clear: both;
|
||||
pointer-events: all;
|
||||
display: block;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
|
||||
#flash-wrap {
|
||||
display: flex;
|
||||
flex: 0 0 100%;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
max-height: 30px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#flash-wrap .content {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
padding: 2px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
|
||||
#flash-wrap svg.operation-icon {
|
||||
flex: 0 0 auto;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
#flash-wrap div.operation-tip {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
#footer-wrap {
|
||||
display: flex;
|
||||
flex: 0 0 100%;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
max-height: 30px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.footer-show {
|
||||
bottom: 0px;
|
||||
transition: bottom 75ms linear;
|
||||
-moz-transition: bottom 75ms linear;
|
||||
-webkit-transition: bottom 75ms linear;
|
||||
}
|
||||
|
||||
.footer-hide {
|
||||
bottom: -35px;
|
||||
transition: bottom 75ms linear;
|
||||
-moz-transition: bottom 75ms linear;
|
||||
-webkit-transition: bottom 75ms linear;
|
||||
}
|
||||
|
||||
|
||||
#scale-block {
|
||||
display: table-cell;
|
||||
vertical-align: bottom;
|
||||
width: 250px;
|
||||
max-height: 30px;
|
||||
float: left;
|
||||
clear: left;
|
||||
flex: 0 0 250px;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
@@ -2557,13 +2614,16 @@ img.tile-removing {
|
||||
|
||||
#info-block {
|
||||
max-height: 30px;
|
||||
clear: right;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
#scale {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
}
|
||||
[dir='rtl'] #scale {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#scale:hover {
|
||||
cursor: pointer;
|
||||
@@ -2575,6 +2635,9 @@ img.tile-removing {
|
||||
fill: #ccc;
|
||||
text-anchor: start;
|
||||
}
|
||||
[dir='rtl'] #scale text {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#scale path {
|
||||
fill: none;
|
||||
@@ -2583,12 +2646,19 @@ img.tile-removing {
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
|
||||
#about-list {
|
||||
text-align: right;
|
||||
margin-right: 10px;
|
||||
clear: right;
|
||||
overflow: hidden;
|
||||
}
|
||||
[dir='rtl'] #about-list {
|
||||
text-align: left;
|
||||
clear: left;
|
||||
margin-left: 10px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#about-list li {
|
||||
float: right;
|
||||
@@ -2596,12 +2666,24 @@ img.tile-removing {
|
||||
padding: 5px 0 5px 5px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
[dir='rtl'] #about-list li {
|
||||
float: left;
|
||||
border-left: none;
|
||||
border-right: 1px solid rgba(255,255,255,.5);
|
||||
margin-left: 0;
|
||||
margin-right: 5px;
|
||||
padding: 5px 5px 5px 0;
|
||||
}
|
||||
|
||||
|
||||
#about-list li:last-child {
|
||||
border-left: 0;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
[dir='rtl'] #about-list li:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.source-switch a {
|
||||
padding: 2px 4px 4px 4px;
|
||||
@@ -2624,12 +2706,13 @@ img.tile-removing {
|
||||
}
|
||||
|
||||
.api-status {
|
||||
float: right;
|
||||
clear: both;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
padding: 0px 10px;
|
||||
color: #eee;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
[dir='rtl'] .api-status {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.api-status.offline,
|
||||
@@ -2645,6 +2728,7 @@ img.tile-removing {
|
||||
color: #ccf;
|
||||
}
|
||||
|
||||
|
||||
/* Modals
|
||||
------------------------------------------------------- */
|
||||
|
||||
@@ -3095,15 +3179,25 @@ img.tile-removing {
|
||||
border-width: 0 5px 5px;
|
||||
}
|
||||
|
||||
.tooltip-heading {
|
||||
font-weight: bold;
|
||||
background: #F6F6F6;
|
||||
padding: 10px;
|
||||
margin: -10px -10px 10px -10px;
|
||||
border-radius: 3px 3px 0 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.keyhint-wrap {
|
||||
background: #F6F6F6;
|
||||
padding: 10px;
|
||||
margin: 10px -10px -10px;
|
||||
margin: 10px -10px -10px -10px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
|
||||
.tooltip-inner .keyhint {
|
||||
font-weight: bold;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/* Exceptions for tooltip layouts */
|
||||
@@ -3134,6 +3228,7 @@ img.tile-removing {
|
||||
}
|
||||
|
||||
.map-overlay .tooltip-inner,
|
||||
.map-overlay .tooltip-heading,
|
||||
.map-overlay .keyhint-wrap,
|
||||
.entity-editor-pane .tooltip-inner,
|
||||
.warning-section .tooltip-inner {
|
||||
@@ -3159,6 +3254,8 @@ img.tile-removing {
|
||||
left: 60px;
|
||||
}
|
||||
|
||||
/* radial menu (deprecated) */
|
||||
|
||||
.radial-menu-tooltip {
|
||||
opacity: 0.8;
|
||||
display: none;
|
||||
@@ -3196,6 +3293,46 @@ img.tile-removing {
|
||||
color: rgba(40,40,40,.5);
|
||||
}
|
||||
|
||||
/* edit menu */
|
||||
|
||||
.edit-menu-tooltip {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.edit-menu-background {
|
||||
fill: #eee;
|
||||
}
|
||||
|
||||
.edit-menu-item rect {
|
||||
fill: #eee;
|
||||
}
|
||||
|
||||
.edit-menu-item rect:active,
|
||||
.edit-menu-item rect:hover {
|
||||
fill: #ccc;
|
||||
}
|
||||
|
||||
.edit-menu-item.disabled rect {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.edit-menu-item.disabled rect:hover {
|
||||
cursor: not-allowed;
|
||||
fill: #eee;
|
||||
}
|
||||
|
||||
.edit-menu-item use {
|
||||
fill: #222;
|
||||
color: #79f;
|
||||
}
|
||||
|
||||
.edit-menu-item.disabled use {
|
||||
fill: rgba(32,32,32,.2);
|
||||
color: rgba(40,40,40,.2);
|
||||
}
|
||||
|
||||
|
||||
.lasso-path {
|
||||
fill-opacity:0.3;
|
||||
stroke: #fff;
|
||||
@@ -3677,39 +3814,6 @@ img.tile-removing {
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
|
||||
/* footer */
|
||||
[dir='rtl'] #scale-block {
|
||||
float: right;
|
||||
clear: right;
|
||||
}
|
||||
|
||||
[dir='rtl'] #info-block {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
[dir='rtl'] #about-list {
|
||||
text-align: left;
|
||||
clear: left;
|
||||
margin-left: 10px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
[dir='rtl'] #about-list li {
|
||||
float: left;
|
||||
border-left: none;
|
||||
border-right: 1px solid rgba(255,255,255,.5);
|
||||
margin-left: 0;
|
||||
margin-right: 5px;
|
||||
padding: 5px 5px 5px 0;
|
||||
}
|
||||
|
||||
[dir='rtl'] #about-list li:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
[dir='rtl'] #scale text {
|
||||
text-anchor: end;
|
||||
}
|
||||
|
||||
/* increment / decrement control - code by Naoufel Razouane */
|
||||
|
||||
|
||||
+7
-5
@@ -146,7 +146,9 @@ en:
|
||||
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.
|
||||
reflect:
|
||||
title: reflect
|
||||
title:
|
||||
long: Reflect Long
|
||||
short: Reflect Short
|
||||
description:
|
||||
long:
|
||||
single: Reflect this feature across its long axis.
|
||||
@@ -159,10 +161,10 @@ en:
|
||||
short: Y
|
||||
annotation:
|
||||
long:
|
||||
single: Reflected an feature across its long axis.
|
||||
single: Reflected a feature across its long axis.
|
||||
multiple: Reflected multiple features across their long axis.
|
||||
short:
|
||||
single: Reflected an feature across its short axis.
|
||||
single: Reflected a feature across its short axis.
|
||||
multiple: Reflected multiple features across their short axis.
|
||||
incomplete_relation:
|
||||
single: This feature can't be reflected because it hasn't been fully downloaded.
|
||||
@@ -812,8 +814,8 @@ en:
|
||||
close: "The feature editor will remember all of your changes automatically. When you change a feature, the close button will change to a checkmark. **Click the {button} button to close the feature editor**"
|
||||
reselect: "Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the point you just created.**"
|
||||
fixname: "**Change the name, then click the {button} button to close the feature editor.**"
|
||||
reselect_delete: "All features on the map can be deleted. **Click to select the point you created.**"
|
||||
delete: "The menu around the point contains operations that can be performed on it, including delete. **Click on the {button} button to delete the point.**"
|
||||
rightclick: "You can right-click on features to see the list of operations that can be performed on them. **Right-click to select the point you created.**"
|
||||
delete: "**Click on the {button} button to delete the point.**"
|
||||
areas:
|
||||
title: "Areas"
|
||||
add: "Areas are used to show the boundaries of features like lakes, buildings, and residential areas. They can be also be used for more detailed mapping of many features you might normally map as points. **Click the {button} Area button to add a new area.**"
|
||||
|
||||
Vendored
+8
-5
@@ -188,7 +188,10 @@
|
||||
}
|
||||
},
|
||||
"reflect": {
|
||||
"title": "reflect",
|
||||
"title": {
|
||||
"long": "Reflect Long",
|
||||
"short": "Reflect Short"
|
||||
},
|
||||
"description": {
|
||||
"long": {
|
||||
"single": "Reflect this feature across its long axis.",
|
||||
@@ -205,11 +208,11 @@
|
||||
},
|
||||
"annotation": {
|
||||
"long": {
|
||||
"single": "Reflected an feature across its long axis.",
|
||||
"single": "Reflected a feature across its long axis.",
|
||||
"multiple": "Reflected multiple features across their long axis."
|
||||
},
|
||||
"short": {
|
||||
"single": "Reflected an feature across its short axis.",
|
||||
"single": "Reflected a feature across its short axis.",
|
||||
"multiple": "Reflected multiple features across their short axis."
|
||||
}
|
||||
},
|
||||
@@ -666,8 +669,8 @@
|
||||
"close": "The feature editor will remember all of your changes automatically. When you change a feature, the close button will change to a checkmark. **Click the {button} button to close the feature editor**",
|
||||
"reselect": "Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the point you just created.**",
|
||||
"fixname": "**Change the name, then click the {button} button to close the feature editor.**",
|
||||
"reselect_delete": "All features on the map can be deleted. **Click to select the point you created.**",
|
||||
"delete": "The menu around the point contains operations that can be performed on it, including delete. **Click on the {button} button to delete the point.**"
|
||||
"rightclick": "You can right-click on features to see the list of operations that can be performed on them. **Right-click to select the point you created.**",
|
||||
"delete": "**Click on the {button} button to delete the point.**"
|
||||
},
|
||||
"areas": {
|
||||
"title": "Areas",
|
||||
|
||||
@@ -246,9 +246,7 @@ export function behaviorDrawWay(context, wayId, index, mode, baseGraph) {
|
||||
}, 1000);
|
||||
|
||||
if (context.hasEntity(wayId)) {
|
||||
context.enter(
|
||||
modeSelect(context, [wayId]).suppressMenu(true).newFeature(true)
|
||||
);
|
||||
context.enter(modeSelect(context, [wayId]).newFeature(true));
|
||||
} else {
|
||||
context.enter(modeBrowse(context));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as d3 from 'd3';
|
||||
import { d3keybinding } from '../lib/d3.keybinding.js';
|
||||
import { uiFlash } from '../ui';
|
||||
|
||||
|
||||
/* Creates a keybinding behavior for an operation */
|
||||
@@ -7,12 +8,53 @@ export function behaviorOperation(context) {
|
||||
var which, keybinding;
|
||||
|
||||
|
||||
function drawIcon(selection) {
|
||||
var button = selection
|
||||
.append('svg')
|
||||
.attr('class', 'operation-icon')
|
||||
.append('g')
|
||||
.attr('class', 'radial-menu-item radial-menu-item-' + which.id)
|
||||
.attr('transform', 'translate(10,10)')
|
||||
.classed('disabled', which.disabled());
|
||||
|
||||
button
|
||||
.append('circle')
|
||||
.attr('r', 9);
|
||||
|
||||
button
|
||||
.append('use')
|
||||
.attr('transform', 'translate(-7,-7)')
|
||||
.attr('width', '14')
|
||||
.attr('height', '14')
|
||||
.attr('xlink:href', '#operation-' + which.id);
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
|
||||
var behavior = function () {
|
||||
if (which) {
|
||||
if (which && which.available() && !context.inIntro()) {
|
||||
keybinding = d3keybinding('behavior.key.' + which.id);
|
||||
keybinding.on(which.keys, function() {
|
||||
d3.event.preventDefault();
|
||||
if (which.available() && !which.disabled() && !context.inIntro()) {
|
||||
var disabled = which.disabled();
|
||||
|
||||
if (disabled) {
|
||||
uiFlash(3000)
|
||||
.html('')
|
||||
.call(drawIcon)
|
||||
.append('div')
|
||||
.attr('class', 'operation-tip')
|
||||
.text(which.tooltip);
|
||||
|
||||
} else {
|
||||
uiFlash(1500)
|
||||
.html('')
|
||||
.call(drawIcon)
|
||||
.append('div')
|
||||
.attr('class', 'operation-tip')
|
||||
.text(which.annotation() || which.title);
|
||||
|
||||
which();
|
||||
}
|
||||
});
|
||||
|
||||
+97
-22
@@ -1,10 +1,15 @@
|
||||
import * as d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import { modeBrowse, modeSelect } from '../modes/index';
|
||||
import { osmEntity } from '../osm/index';
|
||||
import { geoEuclideanDistance } from '../geo';
|
||||
import { modeBrowse, modeSelect } from '../modes';
|
||||
import { osmEntity } from '../osm';
|
||||
|
||||
|
||||
export function behaviorSelect(context) {
|
||||
var suppressMenu = true,
|
||||
tolerance = 4,
|
||||
p1 = null;
|
||||
|
||||
|
||||
function keydown() {
|
||||
if (d3.event && d3.event.shiftKey) {
|
||||
@@ -22,31 +27,96 @@ export function behaviorSelect(context) {
|
||||
}
|
||||
|
||||
|
||||
function point() {
|
||||
return d3.mouse(context.container().node());
|
||||
}
|
||||
|
||||
|
||||
function contextmenu() {
|
||||
if (!p1) p1 = point();
|
||||
d3.event.preventDefault();
|
||||
suppressMenu = false;
|
||||
click();
|
||||
}
|
||||
|
||||
|
||||
function mousedown() {
|
||||
if (!p1) p1 = point();
|
||||
d3.select(window)
|
||||
.on('mouseup.select', mouseup, true);
|
||||
|
||||
var isShowAlways = +context.storage('edit-menu-show-always') === 1;
|
||||
suppressMenu = !isShowAlways;
|
||||
}
|
||||
|
||||
|
||||
function mouseup() {
|
||||
click();
|
||||
}
|
||||
|
||||
|
||||
function click() {
|
||||
var datum = d3.event.target.__data__,
|
||||
lasso = d3.select('#surface .lasso').node(),
|
||||
d3.select(window)
|
||||
.on('mouseup.select', null, true);
|
||||
|
||||
if (!p1) return;
|
||||
var p2 = point(),
|
||||
dist = geoEuclideanDistance(p1, p2);
|
||||
|
||||
p1 = null;
|
||||
if (dist > tolerance) {
|
||||
return;
|
||||
}
|
||||
|
||||
var isMultiselect = d3.event.shiftKey || d3.select('#surface .lasso').node(),
|
||||
isShowAlways = +context.storage('edit-menu-show-always') === 1,
|
||||
datum = d3.event.target.__data__,
|
||||
mode = context.mode();
|
||||
|
||||
if (datum.type === 'midpoint') {
|
||||
// do nothing
|
||||
} else if (!(datum instanceof osmEntity)) {
|
||||
if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
|
||||
context.enter(modeBrowse(context));
|
||||
|
||||
} else if (!d3.event.shiftKey && !lasso) {
|
||||
// Avoid re-entering Select mode with same entity.
|
||||
if (context.selectedIDs().length !== 1 || context.selectedIDs()[0] !== datum.id) {
|
||||
context.enter(modeSelect(context, [datum.id]));
|
||||
} else {
|
||||
mode.suppressMenu(false).reselect();
|
||||
if (datum.type === 'midpoint') {
|
||||
// clicked midpoint, do nothing..
|
||||
|
||||
} else if (!(datum instanceof osmEntity)) {
|
||||
// clicked nothing..
|
||||
if (!isMultiselect && mode.id !== 'browse') {
|
||||
context.enter(modeBrowse(context));
|
||||
}
|
||||
} else if (context.selectedIDs().indexOf(datum.id) >= 0) {
|
||||
var selectedIDs = _.without(context.selectedIDs(), datum.id);
|
||||
context.enter(selectedIDs.length ? modeSelect(context, selectedIDs) : modeBrowse(context));
|
||||
|
||||
} else {
|
||||
context.enter(modeSelect(context, context.selectedIDs().concat([datum.id])));
|
||||
// clicked an entity..
|
||||
var selectedIDs = context.selectedIDs();
|
||||
|
||||
if (!isMultiselect) {
|
||||
if (selectedIDs.length > 1 && (!suppressMenu && !isShowAlways)) {
|
||||
// multiple things already selected, just show the menu...
|
||||
mode.suppressMenu(false).reselect();
|
||||
} else {
|
||||
// select a single thing..
|
||||
context.enter(modeSelect(context, [datum.id]).suppressMenu(suppressMenu));
|
||||
}
|
||||
|
||||
} else {
|
||||
if (selectedIDs.indexOf(datum.id) !== -1) {
|
||||
// clicked entity is already in the selectedIDs list..
|
||||
if (!suppressMenu && !isShowAlways) {
|
||||
// don't deselect clicked entity, just show the menu.
|
||||
mode.suppressMenu(false).reselect();
|
||||
} else {
|
||||
// deselect clicked entity, then reenter select mode or return to browse mode..
|
||||
selectedIDs = _.without(selectedIDs, 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]);
|
||||
context.enter(modeSelect(context, selectedIDs).suppressMenu(suppressMenu));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reset for next time..
|
||||
suppressMenu = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +125,9 @@ export function behaviorSelect(context) {
|
||||
.on('keydown.select', keydown)
|
||||
.on('keyup.select', keyup);
|
||||
|
||||
selection.on('click.select', click);
|
||||
selection
|
||||
.on('mousedown.select', mousedown)
|
||||
.on('contextmenu.select', contextmenu);
|
||||
|
||||
keydown();
|
||||
};
|
||||
@@ -64,9 +136,12 @@ export function behaviorSelect(context) {
|
||||
behavior.off = function(selection) {
|
||||
d3.select(window)
|
||||
.on('keydown.select', null)
|
||||
.on('keyup.select', null);
|
||||
.on('keyup.select', null)
|
||||
.on('mouseup.select', null, true);
|
||||
|
||||
selection.on('click.select', null);
|
||||
selection
|
||||
.on('mousedown.select', null)
|
||||
.on('contextmenu.select', null);
|
||||
|
||||
keyup();
|
||||
};
|
||||
|
||||
@@ -32,7 +32,7 @@ export function modeAddPoint(context) {
|
||||
);
|
||||
|
||||
context.enter(
|
||||
modeSelect(context, [node.id]).suppressMenu(true).newFeature(true)
|
||||
modeSelect(context, [node.id]).newFeature(true)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ export function modeDragNode(context) {
|
||||
});
|
||||
|
||||
if (reselection.length) {
|
||||
context.enter(modeSelect(context, reselection).suppressMenu(true));
|
||||
context.enter(modeSelect(context, reselection));
|
||||
} else {
|
||||
context.enter(modeBrowse(context));
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ export function modeMove(context, entityIDs, baseGraph) {
|
||||
|
||||
function finish() {
|
||||
d3.event.stopPropagation();
|
||||
context.enter(modeSelect(context, entityIDs).suppressMenu(true));
|
||||
context.enter(modeSelect(context, entityIDs));
|
||||
stopNudge();
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ export function modeMove(context, entityIDs, baseGraph) {
|
||||
context.enter(modeBrowse(context));
|
||||
} else {
|
||||
context.pop();
|
||||
context.enter(modeSelect(context, entityIDs).suppressMenu(true));
|
||||
context.enter(modeSelect(context, entityIDs));
|
||||
}
|
||||
stopNudge();
|
||||
}
|
||||
|
||||
@@ -92,13 +92,13 @@ export function modeRotate(context, entityIDs) {
|
||||
|
||||
function finish() {
|
||||
d3.event.stopPropagation();
|
||||
context.enter(modeSelect(context, entityIDs).suppressMenu(true));
|
||||
context.enter(modeSelect(context, entityIDs));
|
||||
}
|
||||
|
||||
|
||||
function cancel() {
|
||||
context.pop();
|
||||
context.enter(modeSelect(context, entityIDs).suppressMenu(true));
|
||||
context.enter(modeSelect(context, entityIDs));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+48
-36
@@ -28,9 +28,12 @@ import {
|
||||
import { modeBrowse } from './browse';
|
||||
import { modeDragNode } from './drag_node';
|
||||
import * as Operations from '../operations/index';
|
||||
import { uiRadialMenu, uiSelectionList } from '../ui/index';
|
||||
import { uiEditMenu, uiSelectionList } from '../ui';
|
||||
import { uiCmd } from '../ui/cmd';
|
||||
import { utilEntityOrMemberSelector, utilEntitySelector } from '../util/index';
|
||||
import { utilEntityOrMemberSelector, utilEntitySelector } from '../util';
|
||||
|
||||
// deprecation warning - Radial Menu to be removed in iD v3
|
||||
import { uiRadialMenu } from '../ui';
|
||||
|
||||
|
||||
var relatedParent;
|
||||
@@ -54,9 +57,9 @@ export function modeSelect(context, selectedIDs) {
|
||||
modeDragNode(context).selectedIDs(selectedIDs).behavior
|
||||
],
|
||||
inspector,
|
||||
radialMenu,
|
||||
editMenu,
|
||||
newFeature = false,
|
||||
suppressMenu = false,
|
||||
suppressMenu = true,
|
||||
follow = false;
|
||||
|
||||
|
||||
@@ -139,27 +142,24 @@ export function modeSelect(context, selectedIDs) {
|
||||
|
||||
|
||||
function closeMenu() {
|
||||
if (radialMenu) {
|
||||
context.surface().call(radialMenu.close);
|
||||
if (editMenu) {
|
||||
context.surface().call(editMenu.close);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function positionMenu() {
|
||||
if (suppressMenu || !radialMenu) { return; }
|
||||
if (suppressMenu || !editMenu) { return; }
|
||||
|
||||
var entity = singular();
|
||||
if (entity && context.geometry(entity.id) === 'relation') {
|
||||
suppressMenu = true;
|
||||
} else if (entity && entity.type === 'node') {
|
||||
radialMenu.center(context.projection(entity.loc));
|
||||
} else {
|
||||
var point = context.mouse(),
|
||||
viewport = geoExtent(context.projection.clipExtent()).polygon();
|
||||
|
||||
if (geoPointInPolygon(point, viewport)) {
|
||||
radialMenu.center(point);
|
||||
} else {
|
||||
suppressMenu = true;
|
||||
editMenu.center(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,14 +167,15 @@ export function modeSelect(context, selectedIDs) {
|
||||
|
||||
function showMenu() {
|
||||
closeMenu();
|
||||
if (!suppressMenu && radialMenu) {
|
||||
context.surface().call(radialMenu);
|
||||
if (editMenu) {
|
||||
context.surface().call(editMenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function toggleMenu() {
|
||||
if (d3.select('.radial-menu').empty()) {
|
||||
// deprecation warning - Radial Menu to be removed in iD v3
|
||||
if (d3.select('.edit-menu, .radial-menu').empty()) {
|
||||
showMenu();
|
||||
} else {
|
||||
closeMenu();
|
||||
@@ -196,7 +197,9 @@ export function modeSelect(context, selectedIDs) {
|
||||
}
|
||||
|
||||
positionMenu();
|
||||
showMenu();
|
||||
if (!suppressMenu) {
|
||||
showMenu();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -245,6 +248,7 @@ export function modeSelect(context, selectedIDs) {
|
||||
|
||||
d3.event.preventDefault();
|
||||
d3.event.stopPropagation();
|
||||
|
||||
} else if (datum.type === 'midpoint') {
|
||||
context.perform(
|
||||
actionAddMidpoint({loc: datum.loc, edge: datum.edge}, osmNode()),
|
||||
@@ -306,7 +310,7 @@ export function modeSelect(context, selectedIDs) {
|
||||
if (parent) {
|
||||
var way = context.entity(parent);
|
||||
context.enter(
|
||||
modeSelect(context, [way.first()]).follow(true).suppressMenu(true)
|
||||
modeSelect(context, [way.first()]).follow(true)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -318,7 +322,7 @@ export function modeSelect(context, selectedIDs) {
|
||||
if (parent) {
|
||||
var way = context.entity(parent);
|
||||
context.enter(
|
||||
modeSelect(context, [way.last()]).follow(true).suppressMenu(true)
|
||||
modeSelect(context, [way.last()]).follow(true)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -342,7 +346,7 @@ export function modeSelect(context, selectedIDs) {
|
||||
|
||||
if (index !== -1) {
|
||||
context.enter(
|
||||
modeSelect(context, [way.nodes[index]]).follow(true).suppressMenu(true)
|
||||
modeSelect(context, [way.nodes[index]]).follow(true)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -366,7 +370,7 @@ export function modeSelect(context, selectedIDs) {
|
||||
|
||||
if (index !== -1) {
|
||||
context.enter(
|
||||
modeSelect(context, [way.nodes[index]]).follow(true).suppressMenu(true)
|
||||
modeSelect(context, [way.nodes[index]]).follow(true)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -401,7 +405,14 @@ export function modeSelect(context, selectedIDs) {
|
||||
.map(function(o) { return o(selectedIDs, context); })
|
||||
.filter(function(o) { return o.available(); });
|
||||
|
||||
operations.unshift(Operations.operationDelete(selectedIDs, context));
|
||||
// deprecation warning - Radial Menu to be removed in iD v3
|
||||
var isRadialMenu = context.storage('edit-menu-style') === 'radial';
|
||||
if (isRadialMenu) {
|
||||
operations = operations.slice(0,7);
|
||||
operations.unshift(Operations.operationDelete(selectedIDs, context));
|
||||
} else {
|
||||
operations.push(Operations.operationDelete(selectedIDs, context));
|
||||
}
|
||||
|
||||
operations.forEach(function(operation) {
|
||||
if (operation.behavior) {
|
||||
@@ -425,7 +436,11 @@ export function modeSelect(context, selectedIDs) {
|
||||
d3.select(document)
|
||||
.call(keybinding);
|
||||
|
||||
radialMenu = uiRadialMenu(context, operations);
|
||||
|
||||
// deprecation warning - Radial Menu to be removed in iD v3
|
||||
editMenu = isRadialMenu
|
||||
? uiRadialMenu(context, operations)
|
||||
: uiEditMenu(context, operations);
|
||||
|
||||
context.ui().sidebar
|
||||
.select(singular() ? singular().id : null, newFeature);
|
||||
@@ -438,12 +453,15 @@ export function modeSelect(context, selectedIDs) {
|
||||
.on('move.select', closeMenu)
|
||||
.on('drawn.select', selectElements);
|
||||
|
||||
context.surface()
|
||||
.on('dblclick.select', dblclick);
|
||||
|
||||
|
||||
selectElements();
|
||||
|
||||
var show = d3.event && !suppressMenu;
|
||||
|
||||
if (show) {
|
||||
positionMenu();
|
||||
if (selectedIDs.length > 1) {
|
||||
var entities = uiSelectionList(context, selectedIDs);
|
||||
context.ui().sidebar.show(entities);
|
||||
}
|
||||
|
||||
if (follow) {
|
||||
@@ -459,18 +477,12 @@ export function modeSelect(context, selectedIDs) {
|
||||
}
|
||||
|
||||
timeout = window.setTimeout(function() {
|
||||
if (show) {
|
||||
positionMenu();
|
||||
if (!suppressMenu) {
|
||||
showMenu();
|
||||
}
|
||||
}, 270); /* after any centerEase completes */
|
||||
|
||||
context.surface()
|
||||
.on('dblclick.select', dblclick);
|
||||
}, 200);
|
||||
|
||||
if (selectedIDs.length > 1) {
|
||||
var entities = uiSelectionList(context, selectedIDs);
|
||||
context.ui().sidebar.show(entities);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -485,7 +497,7 @@ export function modeSelect(context, selectedIDs) {
|
||||
|
||||
keybinding.off();
|
||||
closeMenu();
|
||||
radialMenu = undefined;
|
||||
editMenu = undefined;
|
||||
|
||||
context.history()
|
||||
.on('undone.select', null)
|
||||
|
||||
@@ -13,7 +13,7 @@ export function operationCircularize(selectedIDs, context) {
|
||||
|
||||
|
||||
var operation = function() {
|
||||
context.perform(action, t('operations.circularize.annotation.' + geometry));
|
||||
context.perform(action, operation.annotation());
|
||||
};
|
||||
|
||||
|
||||
@@ -43,6 +43,11 @@ export function operationCircularize(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return t('operations.circularize.annotation.' + geometry);
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'circularize';
|
||||
operation.keys = [t('operations.circularize.key')];
|
||||
operation.title = t('operations.circularize.title');
|
||||
|
||||
@@ -53,6 +53,11 @@ export function operationContinue(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return t('operations.continue.annotation.line');
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'continue';
|
||||
operation.keys = [t('operations.continue.key')];
|
||||
operation.title = t('operations.continue.title');
|
||||
|
||||
@@ -13,21 +13,15 @@ export function operationDelete(selectedIDs, context) {
|
||||
|
||||
|
||||
var operation = function() {
|
||||
var annotation,
|
||||
nextSelectedID;
|
||||
var nextSelectedID;
|
||||
|
||||
if (selectedIDs.length > 1) {
|
||||
annotation = t('operations.delete.annotation.multiple', { n: selectedIDs.length });
|
||||
|
||||
} else {
|
||||
if (selectedIDs.length === 1) {
|
||||
var id = selectedIDs[0],
|
||||
entity = context.entity(id),
|
||||
geometry = context.geometry(id),
|
||||
parents = context.graph().parentWays(entity),
|
||||
parent = parents[0];
|
||||
|
||||
annotation = t('operations.delete.annotation.' + geometry);
|
||||
|
||||
// Select the next closest node in the way.
|
||||
if (geometry === 'vertex' && parent.nodes.length > 2) {
|
||||
var nodes = parent.nodes,
|
||||
@@ -47,12 +41,10 @@ export function operationDelete(selectedIDs, context) {
|
||||
}
|
||||
}
|
||||
|
||||
context.perform(action, annotation);
|
||||
context.perform(action, operation.annotation());
|
||||
|
||||
if (nextSelectedID && context.hasEntity(nextSelectedID)) {
|
||||
context.enter(
|
||||
modeSelect(context, [nextSelectedID]).follow(true).suppressMenu(true)
|
||||
);
|
||||
context.enter(modeSelect(context, [nextSelectedID]).follow(true));
|
||||
} else {
|
||||
context.enter(modeBrowse(context));
|
||||
}
|
||||
@@ -108,6 +100,13 @@ export function operationDelete(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return selectedIDs.length === 1 ?
|
||||
t('operations.delete.annotation.' + context.geometry(selectedIDs[0])) :
|
||||
t('operations.delete.annotation.multiple', { n: selectedIDs.length });
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'delete';
|
||||
operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
|
||||
operation.title = t('operations.delete.title');
|
||||
|
||||
@@ -18,7 +18,7 @@ export function operationDisconnect(selectedIDs, context) {
|
||||
|
||||
|
||||
var operation = function() {
|
||||
context.perform(action, t('operations.disconnect.annotation'));
|
||||
context.perform(action, operation.annotation());
|
||||
};
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@ export function operationDisconnect(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return t('operations.disconnect.annotation');
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'disconnect';
|
||||
operation.keys = [t('operations.disconnect.key')];
|
||||
operation.title = t('operations.disconnect.title');
|
||||
|
||||
@@ -15,8 +15,7 @@ export function operationMerge(selectedIDs, context) {
|
||||
mergePolygon = actionMergePolygon(selectedIDs);
|
||||
|
||||
var operation = function() {
|
||||
var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
|
||||
action;
|
||||
var action;
|
||||
|
||||
if (!join.disabled(context.graph())) {
|
||||
action = join;
|
||||
@@ -26,12 +25,12 @@ export function operationMerge(selectedIDs, context) {
|
||||
action = mergePolygon;
|
||||
}
|
||||
|
||||
context.perform(action, annotation);
|
||||
context.perform(action, operation.annotation());
|
||||
var ids = selectedIDs.filter(function(id) {
|
||||
var entity = context.hasEntity(id);
|
||||
return entity && entity.type !== 'node';
|
||||
});
|
||||
context.enter(modeSelect(context, ids).suppressMenu(true));
|
||||
context.enter(modeSelect(context, ids));
|
||||
};
|
||||
|
||||
|
||||
@@ -69,6 +68,11 @@ export function operationMerge(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return t('operations.merge.annotation', { n: selectedIDs.length });
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'merge';
|
||||
operation.keys = [t('operations.merge.key')];
|
||||
operation.title = t('operations.merge.title');
|
||||
|
||||
@@ -49,6 +49,13 @@ export function operationMove(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return selectedIDs.length === 1 ?
|
||||
t('operations.move.annotation.' + context.geometry(selectedIDs[0])) :
|
||||
t('operations.move.annotation.multiple');
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'move';
|
||||
operation.keys = [t('operations.move.key')];
|
||||
operation.title = t('operations.move.title');
|
||||
|
||||
@@ -13,7 +13,7 @@ export function operationOrthogonalize(selectedIDs, context) {
|
||||
|
||||
|
||||
var operation = function() {
|
||||
context.perform(action, t('operations.orthogonalize.annotation.' + geometry));
|
||||
context.perform(action, operation.annotation());
|
||||
};
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@ export function operationOrthogonalize(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return t('operations.orthogonalize.annotation.' + geometry);
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'orthogonalize';
|
||||
operation.keys = [t('operations.orthogonalize.key')];
|
||||
operation.title = t('operations.orthogonalize.title');
|
||||
|
||||
@@ -26,7 +26,7 @@ export function operationReflect(selectedIDs, context, axis) {
|
||||
var operation = function() {
|
||||
var action = actionReflect(selectedIDs, context.projection)
|
||||
.useLongAxis(Boolean(axis === 'long'));
|
||||
context.perform(action, t('operations.reflect.annotation.' + axis + '.' + multi));
|
||||
context.perform(action, operation.annotation());
|
||||
};
|
||||
|
||||
|
||||
@@ -67,9 +67,14 @@ export function operationReflect(selectedIDs, context, axis) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return t('operations.reflect.annotation.' + axis + '.' + multi);
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'reflect-' + axis;
|
||||
operation.keys = [t('operations.reflect.key.' + axis)];
|
||||
operation.title = t('operations.reflect.title');
|
||||
operation.title = t('operations.reflect.title.' + axis);
|
||||
operation.behavior = behaviorOperation(context).which(operation);
|
||||
|
||||
return operation;
|
||||
|
||||
@@ -7,7 +7,7 @@ export function operationReverse(selectedIDs, context) {
|
||||
var entityId = selectedIDs[0];
|
||||
|
||||
var operation = function() {
|
||||
context.perform(actionReverse(entityId), t('operations.reverse.annotation'));
|
||||
context.perform(actionReverse(entityId), operation.annotation());
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,11 @@ export function operationReverse(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return t('operations.reverse.annotation');
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'reverse';
|
||||
operation.keys = [t('operations.reverse.key')];
|
||||
operation.title = t('operations.reverse.title');
|
||||
|
||||
@@ -54,6 +54,13 @@ export function operationRotate(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return selectedIDs.length === 1 ?
|
||||
t('operations.rotate.annotation.' + context.geometry(selectedIDs[0])) :
|
||||
t('operations.rotate.annotation.multiple');
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'rotate';
|
||||
operation.keys = [t('operations.rotate.key')];
|
||||
operation.title = t('operations.rotate.title');
|
||||
|
||||
+15
-15
@@ -11,24 +11,19 @@ export function operationSplit(selectedIDs, context) {
|
||||
});
|
||||
|
||||
var entityId = vertices[0],
|
||||
action = actionSplit(entityId);
|
||||
action = actionSplit(entityId),
|
||||
ways = [];
|
||||
|
||||
if (selectedIDs.length > 1) {
|
||||
action.limitWays(_.without(selectedIDs, entityId));
|
||||
if (vertices.length === 1) {
|
||||
if (selectedIDs.length > 1) {
|
||||
action.limitWays(_.without(selectedIDs, entityId));
|
||||
}
|
||||
ways = action.ways(context.graph());
|
||||
}
|
||||
|
||||
|
||||
var operation = function() {
|
||||
var annotation;
|
||||
|
||||
var ways = action.ways(context.graph());
|
||||
if (ways.length === 1) {
|
||||
annotation = t('operations.split.annotation.' + context.geometry(ways[0].id));
|
||||
} else {
|
||||
annotation = t('operations.split.annotation.multiple', {n: ways.length});
|
||||
}
|
||||
|
||||
var difference = context.perform(action, annotation);
|
||||
var difference = context.perform(action, operation.annotation());
|
||||
context.enter(modeSelect(context, difference.extantIDs()));
|
||||
};
|
||||
|
||||
@@ -52,8 +47,6 @@ export function operationSplit(selectedIDs, context) {
|
||||
if (disable) {
|
||||
return t('operations.split.' + disable);
|
||||
}
|
||||
|
||||
var ways = action.ways(context.graph());
|
||||
if (ways.length === 1) {
|
||||
return t('operations.split.description.' + context.geometry(ways[0].id));
|
||||
} else {
|
||||
@@ -62,6 +55,13 @@ export function operationSplit(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return ways.length === 1 ?
|
||||
t('operations.split.annotation.' + context.geometry(ways[0].id)) :
|
||||
t('operations.split.annotation.multiple', { n: ways.length });
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'split';
|
||||
operation.keys = [t('operations.split.key')];
|
||||
operation.title = t('operations.split.title');
|
||||
|
||||
@@ -10,7 +10,7 @@ export function operationStraighten(selectedIDs, context) {
|
||||
|
||||
|
||||
function operation() {
|
||||
context.perform(action, t('operations.straighten.annotation'));
|
||||
context.perform(action, operation.annotation());
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,11 @@ export function operationStraighten(selectedIDs, context) {
|
||||
};
|
||||
|
||||
|
||||
operation.annotation = function() {
|
||||
return t('operations.straighten.annotation');
|
||||
};
|
||||
|
||||
|
||||
operation.id = 'straighten';
|
||||
operation.keys = [t('operations.straighten.key')];
|
||||
operation.title = t('operations.straighten.title');
|
||||
|
||||
+32
-9
@@ -36,6 +36,7 @@ export function rendererMap(context) {
|
||||
dblclickEnabled = true,
|
||||
redrawEnabled = true,
|
||||
transformStart = projection.transform(),
|
||||
transformLast,
|
||||
transformed = false,
|
||||
minzoom = 0,
|
||||
drawLayers = svgLayers(projection, context),
|
||||
@@ -77,7 +78,7 @@ export function rendererMap(context) {
|
||||
if (Array.isArray(stack.selectedIDs)) {
|
||||
followSelected = (stack.selectedIDs.length === 1 && stack.selectedIDs[0][0] === 'n');
|
||||
context.enter(
|
||||
modeSelect(context, stack.selectedIDs).suppressMenu(true).follow(followSelected)
|
||||
modeSelect(context, stack.selectedIDs).follow(followSelected)
|
||||
);
|
||||
}
|
||||
if (!followSelected && stack.transform) {
|
||||
@@ -275,7 +276,9 @@ export function rendererMap(context) {
|
||||
|
||||
|
||||
function zoomPan(manualEvent) {
|
||||
var eventTransform = (manualEvent || d3.event).transform;
|
||||
var event = (manualEvent || d3.event),
|
||||
source = event.sourceEvent,
|
||||
eventTransform = event.transform;
|
||||
|
||||
if (transformStart.x === eventTransform.x &&
|
||||
transformStart.y === eventTransform.y &&
|
||||
@@ -283,11 +286,31 @@ export function rendererMap(context) {
|
||||
return; // no change
|
||||
}
|
||||
|
||||
// Normalize mousewheel - #3029
|
||||
// If wheel delta is provided in LINE units, recalculate it in PIXEL units
|
||||
// We are essentially redoing the calculations that occur here:
|
||||
// https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
|
||||
// See this for more info:
|
||||
// https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
|
||||
if (source && source.type === 'wheel' && source.deltaMode === 1 /* LINE */) {
|
||||
// pick sensible scroll amount if user scrolling fast or slow..
|
||||
var lines = Math.abs(source.deltaY),
|
||||
scroll = lines > 2 ? 40 : lines * 10;
|
||||
|
||||
var t0 = transformed ? transformLast : transformStart,
|
||||
p0 = mouse(source),
|
||||
p1 = t0.invert(p0),
|
||||
k2 = t0.k * Math.pow(2, -source.deltaY * scroll / 500),
|
||||
x2 = p0[0] - p1[0] * k2,
|
||||
y2 = p0[1] - p1[1] * k2;
|
||||
|
||||
eventTransform = d3.zoomIdentity.translate(x2,y2).scale(k2);
|
||||
_selection.node().__zoom = eventTransform;
|
||||
}
|
||||
|
||||
if (ktoz(eventTransform.k * 2 * Math.PI) < minzoom) {
|
||||
surface.interrupt();
|
||||
uiFlash(context.container())
|
||||
.select('.content')
|
||||
.text(t('cannot_zoom'));
|
||||
uiFlash().text(t('cannot_zoom'));
|
||||
setZoom(context.minEditableZoom(), true);
|
||||
queueRedraw();
|
||||
dispatch.call('move', this, map);
|
||||
@@ -301,6 +324,7 @@ export function rendererMap(context) {
|
||||
tY = (eventTransform.y / scale - transformStart.y) * scale;
|
||||
|
||||
transformed = true;
|
||||
transformLast = eventTransform;
|
||||
utilSetTransform(supersurface, tX, tY, scale);
|
||||
queueRedraw();
|
||||
|
||||
@@ -311,7 +335,8 @@ export function rendererMap(context) {
|
||||
function resetTransform() {
|
||||
if (!transformed) return false;
|
||||
|
||||
surface.selectAll('.radial-menu').interrupt().remove();
|
||||
// deprecation warning - Radial Menu to be removed in iD v3
|
||||
surface.selectAll('.edit-menu, .radial-menu').interrupt().remove();
|
||||
utilSetTransform(supersurface, 0, 0);
|
||||
transformed = false;
|
||||
return true;
|
||||
@@ -569,9 +594,7 @@ export function rendererMap(context) {
|
||||
|
||||
if (z2 < minzoom) {
|
||||
surface.interrupt();
|
||||
uiFlash(context.container())
|
||||
.select('.content')
|
||||
.text(t('cannot_zoom'));
|
||||
uiFlash().text(t('cannot_zoom'));
|
||||
z2 = context.minEditableZoom();
|
||||
}
|
||||
|
||||
|
||||
@@ -274,9 +274,7 @@ export function uiCommit(context) {
|
||||
function warningClick(d) {
|
||||
if (d.entity) {
|
||||
context.map().zoomTo(d.entity);
|
||||
context.enter(
|
||||
modeSelect(context, [d.entity.id]).suppressMenu(true)
|
||||
);
|
||||
context.enter(modeSelect(context, [d.entity.id]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,8 +284,7 @@ export function uiCommit(context) {
|
||||
if (change.changeType !== 'deleted' &&
|
||||
context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
|
||||
context.map().zoomTo(entity);
|
||||
context.surface().selectAll(
|
||||
utilEntityOrMemberSelector([entity.id], context.graph()))
|
||||
context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
|
||||
.classed('hover', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
import * as d3 from 'd3';
|
||||
import { geoRoundCoords } from '../geo/index';
|
||||
import { textDirection } from '../util/locale';
|
||||
import { uiTooltipHtml } from './tooltipHtml';
|
||||
|
||||
|
||||
export function uiEditMenu(context, operations) {
|
||||
var menu,
|
||||
center = [0, 0],
|
||||
offset = [0, 0],
|
||||
tooltip;
|
||||
|
||||
var p = 8, // top padding
|
||||
m = 4, // top margin
|
||||
h = 15, // height of icon
|
||||
vpBottomMargin = 45, // viewport bottom margin
|
||||
vpSideMargin = 35, // viewport side margin
|
||||
buttonWidth = 44,
|
||||
buttonHeight = (2 * p + h),
|
||||
menuWidth = buttonWidth,
|
||||
menuHeight = (2 * m) + operations.length * buttonHeight,
|
||||
menuSideMargin = 10,
|
||||
tooltipWidth = 200,
|
||||
tooltipHeight = 200; // a reasonable guess, real height depends on tooltip contents
|
||||
|
||||
|
||||
var editMenu = function (selection) {
|
||||
if (!operations.length) return;
|
||||
|
||||
selection.node().parentNode.focus();
|
||||
|
||||
var isRTL = textDirection === 'rtl',
|
||||
viewport = context.surfaceRect();
|
||||
|
||||
if (!isRTL && (center[0] + menuSideMargin + menuWidth) > (viewport.width - vpSideMargin)) {
|
||||
// menu is going left-to-right and near right viewport edge, go left instead
|
||||
isRTL = true;
|
||||
} else if (isRTL && (center[0] - menuSideMargin - menuWidth) < vpSideMargin) {
|
||||
// menu is going right-to-left and near left viewport edge, go right instead
|
||||
isRTL = false;
|
||||
}
|
||||
|
||||
offset[0] = (isRTL ? -1 * (menuSideMargin + menuWidth) : menuSideMargin);
|
||||
|
||||
if (center[1] + menuHeight > (viewport.height - vpBottomMargin)) {
|
||||
// menu is near bottom viewport edge, shift upwards
|
||||
offset[1] = -1 * (center[1] + menuHeight - viewport.height + vpBottomMargin);
|
||||
}
|
||||
|
||||
var origin = [ center[0] + offset[0], center[1] + offset[1] ];
|
||||
|
||||
menu = selection
|
||||
.append('g')
|
||||
.attr('class', 'edit-menu')
|
||||
.attr('transform', 'translate(' + origin + ')')
|
||||
.attr('opacity', 0);
|
||||
|
||||
menu
|
||||
.transition()
|
||||
.attr('opacity', 1);
|
||||
|
||||
menu
|
||||
.append('rect')
|
||||
.attr('class', 'edit-menu-background')
|
||||
.attr('x', 4)
|
||||
.attr('rx', 4)
|
||||
.attr('ry', 4)
|
||||
.attr('width', menuWidth)
|
||||
.attr('height', menuHeight)
|
||||
.attr('stroke-linecap', 'round');
|
||||
|
||||
|
||||
var button = menu.selectAll('.edit-menu-item')
|
||||
.data(operations)
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', function (d) { return 'edit-menu-item edit-menu-item-' + d.id; })
|
||||
.classed('disabled', function (d) { return d.disabled(); })
|
||||
.attr('transform', function (d, i) {
|
||||
return 'translate(' + geoRoundCoords([
|
||||
0,
|
||||
m + i * buttonHeight
|
||||
]).join(',') + ')';
|
||||
});
|
||||
|
||||
button
|
||||
.append('rect')
|
||||
.attr('x', 4)
|
||||
.attr('width', buttonWidth)
|
||||
.attr('height', buttonHeight)
|
||||
.on('click', click)
|
||||
.on('mousedown', mousedown)
|
||||
.on('mouseover', mouseover)
|
||||
.on('mouseout', mouseout);
|
||||
|
||||
button
|
||||
.append('use')
|
||||
.attr('width', '20')
|
||||
.attr('height', '20')
|
||||
.attr('transform', function () {
|
||||
return 'translate(' + [2 * p, 5] + ')';
|
||||
})
|
||||
.attr('xlink:href', function (d) { return '#operation-' + d.id; });
|
||||
|
||||
tooltip = d3.select(document.body)
|
||||
.append('div')
|
||||
.attr('class', 'tooltip-inner edit-menu-tooltip');
|
||||
|
||||
|
||||
function click(operation) {
|
||||
d3.event.stopPropagation();
|
||||
if (operation.disabled()) return;
|
||||
operation();
|
||||
editMenu.close();
|
||||
}
|
||||
|
||||
function mousedown() {
|
||||
d3.event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
|
||||
}
|
||||
|
||||
function mouseover(d, i) {
|
||||
var tipX, tipY;
|
||||
|
||||
if (!isRTL) {
|
||||
tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
|
||||
} else {
|
||||
tipX = viewport.left + origin[0] - 4 - tooltipWidth;
|
||||
}
|
||||
|
||||
if (tipX + tooltipWidth > viewport.right) {
|
||||
// tip is going left-to-right and near right viewport edge, go left instead
|
||||
tipX = viewport.left + origin[0] - 4 - tooltipWidth;
|
||||
} else if (tipX < viewport.left) {
|
||||
// tip is going right-to-left and near left viewport edge, go right instead
|
||||
tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
|
||||
}
|
||||
|
||||
tipY = viewport.top + origin[1] + (i * buttonHeight);
|
||||
if (tipY + tooltipHeight > viewport.bottom) {
|
||||
// tip is near bottom viewport edge, shift upwards
|
||||
tipY -= tipY + tooltipHeight - viewport.bottom;
|
||||
}
|
||||
|
||||
tooltip
|
||||
.style('left', tipX + 'px')
|
||||
.style('top', tipY + 'px')
|
||||
.style('display', 'block')
|
||||
.html(uiTooltipHtml(d.tooltip(), d.keys[0], d.title));
|
||||
}
|
||||
|
||||
function mouseout() {
|
||||
tooltip.style('display', 'none');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
editMenu.close = function () {
|
||||
if (menu) {
|
||||
menu
|
||||
.style('pointer-events', 'none')
|
||||
.transition()
|
||||
.attr('opacity', 0)
|
||||
.remove();
|
||||
}
|
||||
|
||||
if (tooltip) {
|
||||
tooltip.remove();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
editMenu.center = function (_) {
|
||||
if (!arguments.length) return center;
|
||||
center = _;
|
||||
return editMenu;
|
||||
};
|
||||
|
||||
|
||||
return editMenu;
|
||||
}
|
||||
@@ -272,7 +272,7 @@ export function uiFeatureList(context) {
|
||||
edge = geoChooseEdge(context.childNodes(d.entity), center, context.projection);
|
||||
context.map().center(edge.loc);
|
||||
}
|
||||
context.enter(modeSelect(context, [d.entity.id]).suppressMenu(true));
|
||||
context.enter(modeSelect(context, [d.entity.id]));
|
||||
} else {
|
||||
context.zoomToEntity(d.id);
|
||||
}
|
||||
|
||||
+26
-17
@@ -1,26 +1,35 @@
|
||||
import { uiModal } from './modal';
|
||||
import * as d3 from 'd3';
|
||||
|
||||
var timer;
|
||||
|
||||
export function uiFlash(selection) {
|
||||
var modalSelection = uiModal(selection);
|
||||
export function uiFlash(showDuration) {
|
||||
showDuration = showDuration || 1500;
|
||||
|
||||
modalSelection.select('.modal')
|
||||
.classed('modal-flash', true);
|
||||
if (timer) {
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
modalSelection.select('.content')
|
||||
.classed('modal-section', true)
|
||||
d3.select('#footer-wrap')
|
||||
.attr('class', 'footer-hide');
|
||||
d3.select('#flash-wrap')
|
||||
.attr('class', 'footer-show');
|
||||
|
||||
var content = d3.select('#flash-wrap').selectAll('.content')
|
||||
.data([0]);
|
||||
|
||||
content = content.enter()
|
||||
.append('div')
|
||||
.attr('class', 'description');
|
||||
.attr('class', 'content')
|
||||
.merge(content);
|
||||
|
||||
modalSelection.on('click.flash', function() {
|
||||
modalSelection.remove();
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
modalSelection.remove();
|
||||
return true;
|
||||
}, 1500);
|
||||
timer = d3.timeout(function() {
|
||||
timer = null;
|
||||
d3.select('#footer-wrap')
|
||||
.attr('class', 'footer-show');
|
||||
d3.select('#flash-wrap')
|
||||
.attr('class', 'footer-hide');
|
||||
}, showDuration);
|
||||
|
||||
|
||||
return modalSelection;
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -47,3 +47,5 @@ export { uiTooltipHtml } from './tooltipHtml';
|
||||
export { uiUndoRedo } from './undo_redo';
|
||||
export { uiViewOnOSM } from './view_on_osm';
|
||||
export { uiZoom } from './zoom';
|
||||
|
||||
export { uiEditMenu } from './edit_menu';
|
||||
|
||||
+17
-4
@@ -116,6 +116,7 @@ export function uiInit(context) {
|
||||
.attr('class', 'spinner')
|
||||
.call(uiSpinner(context));
|
||||
|
||||
|
||||
var controls = bar
|
||||
.append('div')
|
||||
.attr('class', 'map-controls');
|
||||
@@ -145,6 +146,7 @@ export function uiInit(context) {
|
||||
.attr('class', 'map-control help-control')
|
||||
.call(uiHelp(context));
|
||||
|
||||
|
||||
var about = content
|
||||
.append('div')
|
||||
.attr('id', 'about');
|
||||
@@ -155,6 +157,12 @@ export function uiInit(context) {
|
||||
.attr('dir', 'ltr')
|
||||
.call(uiAttribution(context));
|
||||
|
||||
about
|
||||
.append('div')
|
||||
.attr('class', 'api-status')
|
||||
.call(uiStatus(context));
|
||||
|
||||
|
||||
var footer = about
|
||||
.append('div')
|
||||
.attr('id', 'footer')
|
||||
@@ -162,15 +170,20 @@ export function uiInit(context) {
|
||||
|
||||
footer
|
||||
.append('div')
|
||||
.attr('class', 'api-status')
|
||||
.call(uiStatus(context));
|
||||
.attr('id', 'flash-wrap')
|
||||
.attr('class', 'footer-hide');
|
||||
|
||||
footer
|
||||
var footerWrap = footer
|
||||
.append('div')
|
||||
.attr('id', 'footer-wrap')
|
||||
.attr('class', 'footer-show');
|
||||
|
||||
footerWrap
|
||||
.append('div')
|
||||
.attr('id', 'scale-block')
|
||||
.call(uiScale(context));
|
||||
|
||||
var aboutList = footer
|
||||
var aboutList = footerWrap
|
||||
.append('div')
|
||||
.attr('id', 'info-block')
|
||||
.append('ul')
|
||||
|
||||
@@ -31,7 +31,7 @@ export function uiIntroPoint(context, reveal) {
|
||||
t('intro.points.add', { button: icon('#icon-point', 'pre-text') }),
|
||||
{ tooltipClass: 'intro-points-add' });
|
||||
|
||||
var corner = [-85.632481,41.944094];
|
||||
var corner = [-85.632481, 41.944094];
|
||||
|
||||
context.on('enter.intro', addPoint);
|
||||
|
||||
@@ -125,11 +125,11 @@ export function uiIntroPoint(context, reveal) {
|
||||
context.on('enter.intro', enterDelete);
|
||||
|
||||
var pointBox = pad(corner, 150, context);
|
||||
reveal(pointBox, t('intro.points.reselect_delete'));
|
||||
reveal(pointBox, t('intro.points.rightclick'));
|
||||
|
||||
context.map().on('move.intro', function() {
|
||||
pointBox = pad(corner, 150, context);
|
||||
reveal(pointBox, t('intro.points.reselect_delete'), {duration: 0});
|
||||
reveal(pointBox, t('intro.points.rightclick'), {duration: 0});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -143,10 +143,15 @@ export function uiIntroPoint(context, reveal) {
|
||||
context.history().on('change.intro', deleted);
|
||||
|
||||
setTimeout(function() {
|
||||
var node = d3.select('.radial-menu-item-delete').node();
|
||||
var pointBox = pad(node.getBoundingClientRect(), 50, context);
|
||||
reveal(pointBox,
|
||||
t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') }));
|
||||
// deprecation warning - Radial Menu to be removed in iD v3
|
||||
var node = d3.select('.edit-menu-item-delete, .radial-menu-item-delete').node();
|
||||
if (!node) {
|
||||
deletePoint();
|
||||
} else {
|
||||
var pointBox = pad(node.getBoundingClientRect(), 50, context);
|
||||
reveal(pointBox,
|
||||
t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') }));
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export function uiRawMemberEditor(context) {
|
||||
|
||||
function selectMember(d) {
|
||||
d3.event.preventDefault();
|
||||
context.enter(modeSelect(context, [d.id]).suppressMenu(true));
|
||||
context.enter(modeSelect(context, [d.id]));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export function uiRawMembershipEditor(context) {
|
||||
|
||||
function selectRelation(d) {
|
||||
d3.event.preventDefault();
|
||||
context.enter(modeSelect(context, [d.relation.id]).suppressMenu(true));
|
||||
context.enter(modeSelect(context, [d.relation.id]));
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export function uiRawMembershipEditor(context) {
|
||||
t('operations.add.annotation.relation')
|
||||
);
|
||||
|
||||
context.enter(modeSelect(context, [relation.id]).suppressMenu(true));
|
||||
context.enter(modeSelect(context, [relation.id]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-7
@@ -63,12 +63,13 @@ export function uiScale(context) {
|
||||
loc2 = projection.invert([maxLength, dims[1]]),
|
||||
scale = scaleDefs(loc1, loc2);
|
||||
|
||||
selection.select('#scalepath')
|
||||
selection.select('#scale-path')
|
||||
.attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
|
||||
|
||||
selection.select('#scaletext')
|
||||
.attr('x', scale.px + 8)
|
||||
.attr('y', tickHeight)
|
||||
selection.select('#scale-textgroup')
|
||||
.attr('transform', 'translate(' + (scale.px + 8) + ',' + tickHeight + ')');
|
||||
|
||||
selection.select('#scale-text')
|
||||
.text(scale.text);
|
||||
}
|
||||
|
||||
@@ -79,14 +80,21 @@ export function uiScale(context) {
|
||||
selection.call(update);
|
||||
}
|
||||
|
||||
var g = selection.append('svg')
|
||||
var scalegroup = selection.append('svg')
|
||||
.attr('id', 'scale')
|
||||
.on('click', switchUnits)
|
||||
.append('g')
|
||||
.attr('transform', 'translate(10,11)');
|
||||
|
||||
g.append('path').attr('id', 'scalepath');
|
||||
g.append('text').attr('id', 'scaletext');
|
||||
scalegroup
|
||||
.append('path')
|
||||
.attr('id', 'scale-path');
|
||||
|
||||
scalegroup
|
||||
.append('g')
|
||||
.attr('id', 'scale-textgroup')
|
||||
.append('text')
|
||||
.attr('id', 'scale-text');
|
||||
|
||||
selection.call(update);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { utilDisplayName } from '../util/index';
|
||||
export function uiSelectionList(context, selectedIDs) {
|
||||
|
||||
function selectEntity(entity) {
|
||||
context.enter(modeSelect(context, [entity.id]).suppressMenu(true));
|
||||
context.enter(modeSelect(context, [entity.id]));
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export function uiSelectionList(context, selectedIDs) {
|
||||
if (index > -1) {
|
||||
selectedIDs.splice(index, 1);
|
||||
}
|
||||
context.enter(modeSelect(context, selectedIDs).suppressMenu(true));
|
||||
context.enter(modeSelect(context, selectedIDs));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { t } from '../util/locale';
|
||||
|
||||
export function uiTooltipHtml(text, key) {
|
||||
var s = '<span>' + text + '</span>';
|
||||
if (key) {
|
||||
s += '<div class="keyhint-wrap">' +
|
||||
'<span> ' + (t('tooltip_keyhint')) + ' </span>' +
|
||||
'<span class="keyhint"> ' + key + '</span></div>';
|
||||
export function uiTooltipHtml(text, key, heading) {
|
||||
var s = '';
|
||||
|
||||
if (heading) {
|
||||
s += '<div class="tooltip-heading"><span>' + heading + '</span></div>';
|
||||
}
|
||||
if (text) {
|
||||
s += '<div class="tooltip-text"><span>' + text + '</span></div>';
|
||||
}
|
||||
if (key) {
|
||||
s += '<div class="keyhint-wrap"><span>' + t('tooltip_keyhint') + '</span>' +
|
||||
'<span class="keyhint">' + key + '</span></div>';
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -43,14 +43,14 @@ describe('iD.behaviorHash', function () {
|
||||
location.hash = 'map=20.00/38.87952/-77.02405';
|
||||
});
|
||||
|
||||
it('stores the current zoom and coordinates in location.hash on map move events', function () {
|
||||
it('stores the current zoom and coordinates in location.hash on map move events', function (done) {
|
||||
location.hash = '';
|
||||
hash();
|
||||
var clock = sinon.useFakeTimers();
|
||||
context.map().center([-77.0, 38.9]);
|
||||
context.map().zoom(2.0);
|
||||
clock.tick(500);
|
||||
expect(location.hash).to.equal('#map=2.00/38.9/-77.0');
|
||||
clock.restore();
|
||||
window.setTimeout(function() {
|
||||
expect(location.hash).to.equal('#map=2.00/38.9/-77.0');
|
||||
done();
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -44,37 +44,49 @@ describe('iD.behaviorSelect', function() {
|
||||
});
|
||||
|
||||
specify('click on entity selects the entity', function() {
|
||||
happen.click(context.surface().selectAll('.' + a.id).node());
|
||||
var el = context.surface().selectAll('.' + a.id).node();
|
||||
happen.mousedown(el);
|
||||
happen.mouseup(el);
|
||||
expect(context.selectedIDs()).to.eql([a.id]);
|
||||
});
|
||||
|
||||
specify('click on empty space clears the selection', function() {
|
||||
context.enter(iD.modeSelect(context, [a.id]));
|
||||
happen.click(context.surface().node());
|
||||
var el = context.surface().node();
|
||||
happen.mousedown(el);
|
||||
happen.mouseup(el);
|
||||
expect(context.mode().id).to.eql('browse');
|
||||
});
|
||||
|
||||
specify('shift-click on unselected entity adds it to the selection', function() {
|
||||
context.enter(iD.modeSelect(context, [a.id]));
|
||||
happen.click(context.surface().selectAll('.' + b.id).node(), {shiftKey: true});
|
||||
var el = context.surface().selectAll('.' + b.id).node();
|
||||
happen.mousedown(el, { shiftKey: true });
|
||||
happen.mouseup(el, { shiftKey: true });
|
||||
expect(context.selectedIDs()).to.eql([a.id, b.id]);
|
||||
});
|
||||
|
||||
specify('shift-click on selected entity removes it from the selection', function() {
|
||||
context.enter(iD.modeSelect(context, [a.id, b.id]));
|
||||
happen.click(context.surface().selectAll('.' + b.id).node(), {shiftKey: true});
|
||||
var el = context.surface().selectAll('.' + b.id).node();
|
||||
happen.mousedown(el, { shiftKey: true });
|
||||
happen.mouseup(el, { shiftKey: true });
|
||||
expect(context.selectedIDs()).to.eql([a.id]);
|
||||
});
|
||||
|
||||
specify('shift-click on last selected entity clears the selection', function() {
|
||||
context.enter(iD.modeSelect(context, [a.id]));
|
||||
happen.click(context.surface().selectAll('.' + a.id).node(), {shiftKey: true});
|
||||
var el = context.surface().selectAll('.' + a.id).node();
|
||||
happen.mousedown(el, { shiftKey: true });
|
||||
happen.mouseup(el, { shiftKey: true });
|
||||
expect(context.mode().id).to.eql('browse');
|
||||
});
|
||||
|
||||
specify('shift-click on empty space leaves the selection unchanged', function() {
|
||||
context.enter(iD.modeSelect(context, [a.id]));
|
||||
happen.click(context.surface().node(), {shiftKey: true});
|
||||
var el = context.surface().node();
|
||||
happen.mousedown(el, { shiftKey: true });
|
||||
happen.mouseup(el, { shiftKey: true });
|
||||
expect(context.selectedIDs()).to.eql([a.id]);
|
||||
});
|
||||
});
|
||||
|
||||
+30
-15
@@ -1,25 +1,40 @@
|
||||
describe('iD.uiFlash', function () {
|
||||
var clock;
|
||||
|
||||
var elem;
|
||||
|
||||
beforeEach(function() {
|
||||
elem = d3.select('body').append('div');
|
||||
});
|
||||
|
||||
afterEach(function() { elem.remove(); });
|
||||
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers();
|
||||
d3.select('body')
|
||||
.append('div')
|
||||
.attr('id', 'flash-wrap')
|
||||
.append('div')
|
||||
.attr('id', 'footer-wrap');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
clock.restore();
|
||||
d3.select('body > div').remove();
|
||||
});
|
||||
|
||||
it('leaves after 1000 ms', function () {
|
||||
var flash = iD.uiFlash(elem);
|
||||
clock.tick(1610);
|
||||
expect(flash.node().parentNode).to.be.null;
|
||||
it('returns a selection', function () {
|
||||
var content = iD.uiFlash(200);
|
||||
expect(content.size()).to.eql(1);
|
||||
expect(content.classed('content')).to.be.ok;
|
||||
});
|
||||
|
||||
it('flash is shown', function () {
|
||||
iD.uiFlash(200);
|
||||
var flashWrap = d3.selectAll('#flash-wrap');
|
||||
var footerWrap = d3.selectAll('#footer-wrap');
|
||||
expect(flashWrap.classed('footer-show')).to.be.ok;
|
||||
expect(footerWrap.classed('footer-hide')).to.be.ok;
|
||||
});
|
||||
|
||||
it('flash goes away', function (done) {
|
||||
iD.uiFlash(200);
|
||||
window.setTimeout(function() {
|
||||
var flashWrap = d3.selectAll('#flash-wrap');
|
||||
var footerWrap = d3.selectAll('#footer-wrap');
|
||||
expect(flashWrap.classed('footer-hide')).to.be.ok;
|
||||
expect(footerWrap.classed('footer-show')).to.be.ok;
|
||||
done();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
describe('iD.utilSessionMutex', function() {
|
||||
var clock, a, b;
|
||||
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(Date.now());
|
||||
});
|
||||
var a, b;
|
||||
|
||||
afterEach(function() {
|
||||
clock.restore();
|
||||
if (a) a.unlock();
|
||||
if (b) b.unlock();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user