Merge branch 'master' into summer_toboggan

This commit is contained in:
hikemaniac
2018-10-28 19:51:51 +01:00
committed by GitHub
78 changed files with 937 additions and 387 deletions
+12 -2
View File
@@ -3,6 +3,7 @@ import { actionAddEntity } from '../actions';
import { behaviorDraw } from '../behavior';
import { modeBrowse, modeSelect } from './index';
import { osmNode } from '../osm';
import { actionAddMidpoint } from '../actions';
export function modeAddPoint(context) {
@@ -37,8 +38,17 @@ export function modeAddPoint(context) {
}
function addWay(loc) {
add(loc);
function addWay(loc, edge) {
var node = osmNode();
context.perform(
actionAddMidpoint({loc: loc, edge: edge}, node),
t('operations.add.annotation.vertex')
);
context.enter(
modeSelect(context, [node.id]).newFeature(true)
);
}
+2 -2
View File
@@ -335,7 +335,7 @@ export default {
loadSigns: function(context, projection) {
// if we are looking at signs, we'll actually need to fetch images too
loadTiles('images', apibase + 'images?', projection);
loadTiles('objects', apibase + 'objects?', projection);
loadTiles('objects', apibase + 'map_features?layers=trafficsigns&', projection);
},
@@ -636,7 +636,7 @@ export default {
function loadDetection(detectionKey) {
var url = apibase + 'detections/' +
var url = apibase + 'image_detections/' +
detectionKey + '?' + utilQsString({ client_id: clientId });
d3_request(url)
+3 -1
View File
@@ -182,7 +182,9 @@ export default {
init: function() {
inflight = {};
taginfoCache = {};
popularKeys = {};
popularKeys = {
postal_code: true // #5377
};
// Fetch popular keys. We'll exclude these from `values`
// lookups because they stress taginfo, and they aren't likely
+2 -2
View File
@@ -6,7 +6,7 @@ export function svgTagClasses() {
var primaries = [
'building', 'highway', 'railway', 'waterway', 'aeroway',
'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
'leisure', 'military', 'place', 'man_made', 'attraction'
'leisure', 'military', 'place', 'man_made', 'route', 'attraction'
];
var statuses = [
'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
@@ -15,7 +15,7 @@ export function svgTagClasses() {
var secondaries = [
'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
'surface', 'tracktype', 'footway', 'crossing', 'service', 'sport',
'public_transport'
'public_transport', 'location', 'parking'
];
var tagClassRe = /^tag-/;
var _tags = function(entity) { return entity.tags; };
+1 -1
View File
@@ -318,7 +318,7 @@ export function uiHelp(context) {
function clickHelp(d, i) {
var rtl = (textDirection === 'rtl');
pane.property('scrollTop', 0);
content.property('scrollTop', 0);
doctitle.html(d.title);
body.html(d.html);
+132 -12
View File
@@ -61,7 +61,7 @@ export function uiPresetList(context) {
.call(svgIcon('#iD-icon-close'));
}
function keydown() {
function initialKeydown() {
// hack to let delete shortcut work when search is autofocused
if (search.property('value').length === 0 &&
(d3_event.keyCode === d3_keybinding.keyCodes['⌫'] ||
@@ -69,6 +69,8 @@ export function uiPresetList(context) {
d3_event.preventDefault();
d3_event.stopPropagation();
operationDelete([id], context)();
// hack to let undo work when search is autofocused
} else if (search.property('value').length === 0 &&
(d3_event.ctrlKey || d3_event.metaKey) &&
d3_event.keyCode === d3_keybinding.keyCodes.z) {
@@ -76,7 +78,21 @@ export function uiPresetList(context) {
d3_event.stopPropagation();
context.undo();
} else if (!d3_event.ctrlKey && !d3_event.metaKey) {
d3_select(this).on('keydown', null);
// don't check for delete/undo hack on future keydown events
d3_select(this).on('keydown', keydown);
keydown.call(this);
}
}
function keydown() {
// down arrow
if (d3_event.keyCode === d3_keybinding.keyCodes['↓'] &&
// if insertion point is at the end of the string
search.node().selectionStart === search.property('value').length) {
d3_event.preventDefault();
d3_event.stopPropagation();
// move focus to the first item in the preset list
list.select('.preset-list-button').node().focus();
}
}
@@ -114,7 +130,7 @@ export function uiPresetList(context) {
.attr('placeholder', t('inspector.search'))
.attr('type', 'search')
.call(utilNoAuto)
.on('keydown', keydown)
.on('keydown', initialKeydown)
.on('keypress', keypress)
.on('input', inputevent);
@@ -159,6 +175,84 @@ export function uiPresetList(context) {
.style('opacity', 1);
}
function itemKeydown(){
// the actively focused item
var item = d3_select(this.closest('.preset-list-item'));
var parentItem = d3_select(item.node().parentElement.closest('.preset-list-item'));
// arrow down, move focus to the next, lower item
if (d3_event.keyCode === d3_keybinding.keyCodes['↓']) {
d3_event.preventDefault();
d3_event.stopPropagation();
// the next item in the list at the same level
var nextItem = d3_select(item.node().nextElementSibling);
// if there is no next item in this list
if (nextItem.empty()) {
// if there is a parent item
if (!parentItem.empty()) {
// the item is the last item of a sublist,
// select the next item at the parent level
nextItem = d3_select(parentItem.node().nextElementSibling);
}
// if the focused item is expanded
} else if (d3_select(this).classed('expanded')) {
// select the first subitem instead
nextItem = item.select('.subgrid .preset-list-item:first-child');
}
if (!nextItem.empty()) {
// focus on the next item
nextItem.select('.preset-list-button').node().focus();
}
// arrow up, move focus to the previous, higher item
} else if (d3_event.keyCode === d3_keybinding.keyCodes['↑']) {
d3_event.preventDefault();
d3_event.stopPropagation();
// the previous item in the list at the same level
var previousItem = d3_select(item.node().previousElementSibling);
// if there is no previous item in this list
if (previousItem.empty()) {
// if there is a parent item
if (!parentItem.empty()) {
// the item is the first subitem of a sublist,
// select the parent item
previousItem = parentItem;
}
// if the previous item is expanded
} else if (previousItem.select('.preset-list-button').classed('expanded')) {
// select the last subitem of the sublist of the previous item
previousItem = previousItem.select('.subgrid .preset-list-item:last-child');
}
if (!previousItem.empty()) {
// focus on the previous item
previousItem.select('.preset-list-button').node().focus();
}
else {
// the focus is at the top of the list, move focus back to the search field
var search = d3_select(this.closest('.preset-list-pane')).select('.preset-search-input');
search.node().focus();
}
}
// arrow left, move focus to the parent item if there is one
else if (d3_event.keyCode === d3_keybinding.keyCodes[(textDirection === 'rtl') ? '→' : '←']) {
d3_event.preventDefault();
d3_event.stopPropagation();
// if there is a parent item
if (!parentItem.empty()) {
// focus on the parent item
parentItem.select('.preset-list-button').node().focus();
}
}
// arrow right, choose this item
else if (d3_event.keyCode === d3_keybinding.keyCodes[(textDirection === 'rtl') ? '←' : '→']) {
d3_event.preventDefault();
d3_event.stopPropagation();
item.datum().choose();
}
}
function CategoryItem(preset) {
var box, sublist, shown = false;
@@ -167,6 +261,17 @@ export function uiPresetList(context) {
var wrap = selection.append('div')
.attr('class', 'preset-list-button-wrap category col12');
function click() {
var isExpanded = d3_select(this).classed('expanded');
var iconName = isExpanded ?
(textDirection === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward') : '#iD-icon-down';
d3_select(this)
.classed('expanded', !isExpanded);
d3_select(this).selectAll('div.label svg.icon use')
.attr('href', iconName);
item.choose();
}
var button = wrap
.append('button')
.attr('class', 'preset-list-button')
@@ -174,15 +279,29 @@ export function uiPresetList(context) {
.call(uiPresetIcon()
.geometry(context.geometry(id))
.preset(preset))
.on('click', function() {
var isExpanded = d3_select(this).classed('expanded');
var iconName = isExpanded ?
(textDirection === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward') : '#iD-icon-down';
d3_select(this)
.classed('expanded', !isExpanded);
d3_select(this).selectAll('div.label svg.icon use')
.attr('href', iconName);
item.choose();
.on('click', click)
.on('keydown', function() {
// right arrow, expand the focused item
if (d3_event.keyCode === d3_keybinding.keyCodes[(textDirection === 'rtl') ? '←' : '→']) {
d3_event.preventDefault();
d3_event.stopPropagation();
// if the item isn't expanded
if (!d3_select(this).classed('expanded')) {
// toggle expansion (expand the item)
click.call(this);
}
// left arrow, collapse the focused item
} else if (d3_event.keyCode === d3_keybinding.keyCodes[(textDirection === 'rtl') ? '→' : '←']) {
d3_event.preventDefault();
d3_event.stopPropagation();
// if the item is expanded
if (d3_select(this).classed('expanded')) {
// toggle expansion (collapse the item)
click.call(this);
}
} else {
itemKeydown.call(this);
}
});
var label = button
@@ -245,6 +364,7 @@ export function uiPresetList(context) {
.geometry(context.geometry(id))
.preset(preset))
.on('click', item.choose)
.on('keydown', itemKeydown)
.append('div')
.attr('class', 'label')
.text(preset.name());
+71 -7
View File
@@ -15,7 +15,8 @@ import { uiDisclosure } from './disclosure';
import {
utilDisplayName,
utilDisplayType,
utilNoAuto
utilNoAuto,
utilHighlightEntity
} from '../util';
@@ -23,9 +24,34 @@ export function uiRawMemberEditor(context) {
var taginfo = services.taginfo,
_entityID;
function downloadMember(d) {
d3_event.preventDefault();
// display the loading indicator
d3_select(this.parentNode).classed('tag-reference-loading', true);
context.loadEntity(d.id);
}
function zoomToMember(d) {
d3_event.preventDefault();
var entity = context.entity(d.id);
context.map().zoomTo(entity);
// highlight the feature in case it wasn't previously on-screen
utilHighlightEntity(d.id, true, context);
}
function selectMember(d) {
d3_event.preventDefault();
var entity = context.entity(d.id);
var mapExtent = context.map().extent();
if (!entity.intersects(mapExtent, context.graph())) {
// zoom to the entity if its extent is not visible now
context.map().zoomTo(entity);
}
context.enter(modeSelect(context, [d.id]));
}
@@ -107,27 +133,64 @@ export function uiRawMemberEditor(context) {
enter
.each(function(d) {
if (d.member) {
// highlight the member feature in the map while hovering on the list item
d3_select(this).on('mouseover', function() {
utilHighlightEntity(d.id, true, context);
});
d3_select(this).on('mouseout', function() {
utilHighlightEntity(d.id, false, context);
});
var label = d3_select(this).append('label')
.attr('class', 'form-label')
.append('a')
.attr('class', 'form-label');
var labelLink = label.append('a')
.attr('href', '#')
.on('click', selectMember);
label.append('span')
labelLink.append('span')
.attr('class', 'member-entity-type')
.text(function(d) {
var matched = context.presets().match(d.member, context.graph());
return (matched && matched.name()) || utilDisplayType(d.member.id);
});
label.append('span')
labelLink.append('span')
.attr('class', 'member-entity-name')
.text(function(d) { return utilDisplayName(d.member); });
var buttonWrap = label.append('div')
.attr('class', 'form-label-button-wrap');
buttonWrap.append('button')
.attr('class', 'download-icon')
.attr('title', t('icons.zoom_to'))
.attr('tabindex', -1)
.call(svgIcon('#iD-icon-geolocate'))
.on('click', zoomToMember);
} else {
d3_select(this).append('label')
.attr('class', 'form-label')
var incompleteLabel = d3_select(this).append('label')
.attr('class', 'form-label');
incompleteLabel.append('span')
.attr('class', 'member-entity-type')
.text(t('inspector.'+d.type, { id: d.id }));
incompleteLabel.append('span')
.attr('class', 'member-entity-name')
.text(t('inspector.incomplete', { id: d.id }));
var wrap = incompleteLabel.append('div')
.attr('class', 'form-label-button-wrap');
wrap.append('button')
.attr('class', 'download-icon')
.attr('title', t('icons.download'))
.attr('tabindex', -1)
.call(svgIcon('#iD-icon-load'))
.on('click', downloadMember);
}
});
@@ -144,6 +207,7 @@ export function uiRawMemberEditor(context) {
enter
.append('button')
.attr('tabindex', -1)
.attr('title', t('icons.remove'))
.attr('class', 'remove button-input-action member-delete minor')
.on('click', deleteMember)
.call(svgIcon('#iD-operation-delete'));
+11 -1
View File
@@ -24,7 +24,7 @@ import { osmEntity, osmRelation } from '../osm';
import { services } from '../services';
import { svgIcon } from '../svg';
import { uiDisclosure } from './disclosure';
import { utilDisplayName, utilNoAuto } from '../util';
import { utilDisplayName, utilNoAuto, utilHighlightEntity } from '../util';
export function uiRawMembershipEditor(context) {
@@ -173,6 +173,16 @@ export function uiRawMembershipEditor(context) {
.append('li')
.attr('class', 'member-row member-row-normal form-field');
enter.each(function(d){
// highlight the relation in the map while hovering on the list item
d3_select(this).on('mouseover', function() {
utilHighlightEntity(d.relation.id, true, context);
});
d3_select(this).on('mouseout', function() {
utilHighlightEntity(d.relation.id, false, context);
});
});
var label = enter
.append('label')
.attr('class', 'form-label')
+16 -2
View File
@@ -1,10 +1,13 @@
import { event as d3_event } from 'd3-selection';
import {
event as d3_event,
select as d3_select
} from 'd3-selection';
import { t } from '../util/locale';
import { modeSelect } from '../modes';
import { osmEntity } from '../osm';
import { svgIcon } from '../svg';
import { utilDisplayName } from '../util';
import { utilDisplayName, utilHighlightEntity } from '../util';
export function uiSelectionList(context, selectedIDs) {
@@ -64,6 +67,17 @@ export function uiSelectionList(context, selectedIDs) {
.attr('class', 'feature-list-item')
.on('click', selectEntity);
enter
.each(function(d) {
// highlight the feature in the map while hovering on the list item
d3_select(this).on('mouseover', function() {
utilHighlightEntity(d.id, true, context);
});
d3_select(this).on('mouseout', function() {
utilHighlightEntity(d.id, false, context);
});
});
var label = enter
.append('button')
.attr('class', 'label');
+2
View File
@@ -7,12 +7,14 @@ export { utilDisplayType } from './util';
export { utilEditDistance } from './util';
export { utilEntitySelector } from './util';
export { utilEntityOrMemberSelector } from './util';
export { utilEntityOrDeepMemberSelector } from './util';
export { utilFastMouse } from './util';
export { utilFunctor } from './util';
export { utilGetAllNodes } from './util';
export { utilGetPrototypeOf } from './util';
export { utilGetSetValue } from './get_set_value';
export { utilHashcode } from './util';
export { utilHighlightEntity } from './util';
export { utilIdleWorker } from './idle_worker';
export { utilNoAuto } from './util';
export { utilPrefixCSSProperty } from './util';
+33
View File
@@ -34,6 +34,32 @@ export function utilEntityOrMemberSelector(ids, graph) {
}
export function utilEntityOrDeepMemberSelector(ids, graph) {
var seen = {};
var allIDs = [];
function addEntityAndMembersIfNotYetSeen(id) {
// avoid infinite recursion for circular relations by skipping seen entities
if (seen[id]) return;
// mark the entity as seen
seen[id] = true;
// add the id;
allIDs.push(id);
if (graph.hasEntity(id)) {
var entity = graph.entity(id);
if (entity.type === 'relation' && entity.members) {
entity.members.forEach(function(member){
addEntityAndMembersIfNotYetSeen(member.id);
});
}
}
}
ids.forEach(function(id) {
addEntityAndMembersIfNotYetSeen(id);
});
return utilEntitySelector(allIDs);
}
export function utilGetAllNodes(ids, graph) {
var seen = {};
var nodes = [];
@@ -282,3 +308,10 @@ export function utilHashcode(str) {
}
return hash;
}
// Adds or removes highlight styling for the specified entity's SVG elements in the map.
export function utilHighlightEntity(id, highlighted, context) {
context.surface()
.selectAll(utilEntityOrDeepMemberSelector([id], context.graph()))
.classed('highlighted', highlighted);
}