diff --git a/modules/svg/debug.js b/modules/svg/debug.js index 24ea028ec..df9b135cb 100644 --- a/modules/svg/debug.js +++ b/modules/svg/debug.js @@ -66,7 +66,7 @@ export function Debug(projection, context) { legendItems.enter() .append('span') .attr('class', function(d) { return 'debug-legend-item ' + d.class; }) - .text(function(d) { return d.label; }) + .text(function(d) { return d.label; }); var layer = selection.selectAll('.layer-debug') diff --git a/modules/ui/fields/access.js b/modules/ui/fields/access.js index 1f4dc852c..f4e08b282 100644 --- a/modules/ui/fields/access.js +++ b/modules/ui/fields/access.js @@ -4,6 +4,7 @@ import { rebind } from '../../util/rebind'; import { getSetValue } from '../../util/get_set_value'; import { d3combobox } from '../../lib/d3.combobox.js'; + export function access(field) { var dispatch = d3.dispatch('change'), items; @@ -12,17 +13,18 @@ export function access(field) { var wrap = selection.selectAll('.preset-input-wrap') .data([0]); - var divEnter = wrap.enter().append('div') - .attr('class', 'cf preset-input-wrap'); - divEnter.append('ul'); - wrap = wrap.merge(divEnter); + wrap = wrap.enter() + .append('div') + .attr('class', 'cf preset-input-wrap') + .append('ul') + .merge(wrap); items = wrap.select('ul').selectAll('li') .data(field.keys); // Enter - - var enter = items.enter().append('li') + var enter = items.enter() + .append('li') .attr('class', function(d) { return 'cf preset-access-' + d; }); enter.append('span') @@ -42,21 +44,23 @@ export function access(field) { .data(access.options(d))); }); - items = items.merge(enter); // Update + items = items.merge(enter); wrap.selectAll('.preset-input-access') .on('change', change) .on('blur', change); } + function change(d) { var tag = {}; tag[d] = getSetValue(d3.select(this)) || undefined; dispatch.call('change', this, tag); } + access.options = function(type) { var options = ['no', 'permissive', 'private', 'destination']; @@ -77,6 +81,7 @@ export function access(field) { }); }; + var placeholders = { footway: { foot: 'designated', diff --git a/modules/ui/fields/address.js b/modules/ui/fields/address.js index 5901123f3..51e93f7fa 100644 --- a/modules/ui/fields/address.js +++ b/modules/ui/fields/address.js @@ -21,6 +21,7 @@ export function address(field, context) { postcode: 1/3 }; + function getStreets() { var extent = entity.extent(context.graph()), l = extent.center(), @@ -47,6 +48,7 @@ export function address(field, context) { } } + function getCities() { var extent = entity.extent(context.graph()), l = extent.center(), @@ -81,6 +83,7 @@ export function address(field, context) { } } + function getPostCodes() { var extent = entity.extent(context.graph()), l = extent.center(), @@ -103,20 +106,22 @@ export function address(field, context) { } } + function address(selection) { isInitialized = false; wrap = selection.selectAll('.preset-input-wrap') .data([0]); - // Enter - - wrap.enter() + wrap = wrap.enter() .append('div') - .attr('class', 'preset-input-wrap'); + .attr('class', 'preset-input-wrap') + .merge(wrap); + var center = entity.extent(context.graph()).center(), addressFormat; + nominatim.init(); nominatim.countryCode(center, function (err, countryCode) { addressFormat = _.find(addressFormats, function (a) { @@ -152,7 +157,6 @@ export function address(field, context) { .style('width', function (d) { return d.width * 100 + '%'; }); // Update - wrap.selectAll('.addr-street') .call(d3combobox() .fetcher(function(value, callback) { @@ -183,6 +187,7 @@ export function address(field, context) { }); } + function change(onInput) { return function() { var tags = {}; @@ -196,18 +201,21 @@ export function address(field, context) { }; } + function updateTags(tags) { getSetValue(wrap.selectAll('input'), function (field) { return tags['addr:' + field.id] || ''; }); } + address.entity = function(_) { if (!arguments.length) return entity; entity = _; return address; }; + address.tags = function(tags) { if (isInitialized) { updateTags(tags); @@ -218,10 +226,12 @@ export function address(field, context) { } }; + address.focus = function() { var node = wrap.selectAll('input').node(); if (node) node.focus(); }; + return rebind(address, dispatch, 'on'); } diff --git a/modules/ui/fields/check.js b/modules/ui/fields/check.js index 071c19080..9b01c4641 100644 --- a/modules/ui/fields/check.js +++ b/modules/ui/fields/check.js @@ -5,12 +5,16 @@ import { oneWayTags } from '../../core/index'; export { check as defaultcheck }; + export function check(field) { var dispatch = d3.dispatch('change'), options = field.strings && field.strings.options, values = [], texts = [], - entity, value, box, text, label; + box = d3.select(null), + text = d3.select(null), + label = d3.select(null), + entity, value; if (options) { for (var k in options) { @@ -26,6 +30,7 @@ export function check(field) { } } + var check = function(selection) { // hack: pretend oneway field is a oneway_yes field // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841 @@ -43,19 +48,14 @@ export function check(field) { label = selection.selectAll('.preset-input-wrap') .data([0]); - var enter = label.enter().append('label') + var enter = label.enter() + .append('label') .attr('class', 'preset-input-wrap'); enter.append('input') .property('indeterminate', field.type === 'check') .attr('type', 'checkbox') - .attr('id', 'preset-input-' + field.id); - - enter.append('span') - .text(texts[0]) - .attr('class', 'value'); - - box = label.select('input') + .attr('id', 'preset-input-' + field.id) .on('click', function() { var t = {}; t[field.key] = values[(values.indexOf(value) + 1) % values.length]; @@ -63,15 +63,24 @@ export function check(field) { d3.event.stopPropagation(); }); - text = label.select('span.value'); + enter.append('span') + .text(texts[0]) + .attr('class', 'value'); + + label = label.merge(enter); + + box = label.selectAll('input'); + text = label.selectAll('span.value'); }; + check.entity = function(_) { if (!arguments.length) return entity; entity = _; return check; }; + check.tags = function(tags) { value = tags[field.key]; box.property('indeterminate', field.type === 'check' && !value); @@ -80,6 +89,7 @@ export function check(field) { label.classed('set', !!value); }; + check.focus = function() { box.node().focus(); }; diff --git a/modules/ui/raw_tag_editor.js b/modules/ui/raw_tag_editor.js index 2427d52a2..d56840ab8 100644 --- a/modules/ui/raw_tag_editor.js +++ b/modules/ui/raw_tag_editor.js @@ -9,7 +9,7 @@ import { TagReference } from './tag_reference'; export function RawTagEditor(context) { - var event = d3.dispatch('change'), + var dispatch = d3.dispatch('change'), showBlank = false, state, preset, @@ -61,30 +61,38 @@ export function RawTagEditor(context) { .merge(newTag) .on('click', addTag); + var items = list.selectAll('li') .data(entries, function(d) { return d.key; }); + items.exit() + .each(unbind) + .remove(); + // Enter var enter = items.enter() .append('li') .attr('class', 'tag-row cf'); - enter.append('div') + enter + .append('div') .attr('class', 'key-wrap') .append('input') .property('type', 'text') .attr('class', 'key') .attr('maxlength', 255); - enter.append('div') + enter + .append('div') .attr('class', 'input-wrap-position') .append('input') .property('type', 'text') .attr('class', 'value') .attr('maxlength', 255); - enter.append('button') + enter + .append('button') .attr('tabindex', -1) .attr('class', 'remove minor') .call(Icon('#operation-delete')); @@ -96,25 +104,26 @@ export function RawTagEditor(context) { // Update items = items.merge(enter); - items.order(); - items.each(function(tag) { - var isRelation = (context.entity(id).type === 'relation'), - reference; - if (isRelation && tag.key === 'type') - reference = TagReference({rtype: tag.value}, context); - else - reference = TagReference({key: tag.key, value: tag.value}, context); + items + .each(function(tag) { + var isRelation = (context.entity(id).type === 'relation'), + reference; + if (isRelation && tag.key === 'type') { + reference = TagReference({rtype: tag.value}, context); + } else { + reference = TagReference({key: tag.key, value: tag.value}, context); + } - if (state === 'hover') { - reference.showing(false); - } + if (state === 'hover') { + reference.showing(false); + } - d3.select(this) - .call(reference.button) - .call(reference.body); - }); + d3.select(this) + .call(reference.button) + .call(reference.body); + }); getSetValue(items.selectAll('input.key') .attr('title', function(d) { return d.key; }) @@ -131,13 +140,9 @@ export function RawTagEditor(context) { function(d) { return d.value; } ); - items.select('button.remove') + items.selectAll('button.remove') .on('click', removeTag); - items.exit() - .each(unbind) - .remove(); - function pushMore() { if (d3.event.keyCode === 9 && !d3.event.shiftKey && @@ -218,21 +223,21 @@ export function RawTagEditor(context) { tag[kNew] = d.value; d.key = kNew; // Maintain DOM identity through the subsequent update. this.value = kNew; - event.call('change', this, tag); + dispatch.call('change', this, tag); } function valueChange(d) { var tag = {}; tag[d.key] = this.value; - event.call('change', this, tag); + dispatch.call('change', this, tag); } function removeTag(d) { var tag = {}; tag[d.key] = undefined; - event.call('change', this, tag); + dispatch.call('change', this, tag); d3.select(this.parentNode).remove(); } @@ -278,5 +283,5 @@ export function RawTagEditor(context) { }; - return rebind(rawTagEditor, event, 'on'); + return rebind(rawTagEditor, dispatch, 'on'); } diff --git a/modules/ui/selection_list.js b/modules/ui/selection_list.js index 71ea703b5..f72f73f87 100644 --- a/modules/ui/selection_list.js +++ b/modules/ui/selection_list.js @@ -5,12 +5,14 @@ import { Icon } from '../svg/index'; import { Select } from '../modes/index'; import { displayName } from '../util/index'; + export function SelectionList(context, selectedIDs) { function selectEntity(entity) { context.enter(Select(context, [entity.id]).suppressMenu(true)); } + function deselectEntity(entity) { d3.event.stopPropagation(); var index = selectedIDs.indexOf(entity.id); @@ -20,24 +22,30 @@ export function SelectionList(context, selectedIDs) { context.enter(Select(context, selectedIDs).suppressMenu(true)); } + function selectionList(selection) { selection.classed('selection-list-pane', true); - var header = selection.append('div') + var header = selection + .append('div') .attr('class', 'header fillL cf'); - header.append('h3') + header + .append('h3') .text(t('inspector.multiselect')); - var listWrap = selection.append('div') + var listWrap = selection + .append('div') .attr('class', 'inspector-body'); - var list = listWrap.append('div') + var list = listWrap + .append('div') .attr('class', 'feature-list cf'); context.history().on('change.selection-list', drawList); drawList(); + function drawList() { var entities = selectedIDs .map(function(id) { return context.hasEntity(id); }) @@ -46,30 +54,41 @@ export function SelectionList(context, selectedIDs) { var items = list.selectAll('.feature-list-item') .data(entities, Entity.key); - var enter = items.enter().append('div') + items.exit() + .remove(); + + // Enter + var enter = items.enter() + .append('div') .attr('class', 'feature-list-item') .on('click', selectEntity); - // Enter - var label = enter.append('button') + var label = enter + .append('button') .attr('class', 'label'); - enter.append('button') + enter + .append('button') .attr('class', 'close') .on('click', deselectEntity) .call(Icon('#icon-close')); - label.append('span') + label + .append('span') .attr('class', 'entity-geom-icon') .call(Icon('', 'pre-text')); - label.append('span') + label + .append('span') .attr('class', 'entity-type'); - label.append('span') + label + .append('span') .attr('class', 'entity-name'); // Update + items = items.merge(enter); + items.selectAll('.entity-geom-icon use') .attr('href', function() { var entity = this.parentNode.parentNode.__data__; @@ -81,13 +100,8 @@ export function SelectionList(context, selectedIDs) { items.selectAll('.entity-name') .text(function(entity) { return displayName(entity); }); - - // Exit - items.exit() - .remove(); } } return selectionList; - } diff --git a/modules/ui/source_switch.js b/modules/ui/source_switch.js index 3b8c961db..fd16ae425 100644 --- a/modules/ui/source_switch.js +++ b/modules/ui/source_switch.js @@ -26,7 +26,8 @@ export function SourceSwitch(context) { } var sourceSwitch = function(selection) { - selection.append('a') + selection + .append('a') .attr('href', '#') .text(t('source_switch.live')) .classed('live', true) diff --git a/modules/ui/spinner.js b/modules/ui/spinner.js index 37c41ab1f..a995a2b50 100644 --- a/modules/ui/spinner.js +++ b/modules/ui/spinner.js @@ -2,7 +2,8 @@ export function Spinner(context) { var connection = context.connection(); return function(selection) { - var img = selection.append('img') + var img = selection + .append('img') .attr('src', context.imagePath('loader-black.gif')) .style('opacity', 0); diff --git a/modules/ui/tag_reference.js b/modules/ui/tag_reference.js index 4fba84fd9..3345c0250 100644 --- a/modules/ui/tag_reference.js +++ b/modules/ui/tag_reference.js @@ -11,6 +11,7 @@ export function TagReference(tag, context) { loaded, showing; + function findLocal(data) { var locale = Detect().locale.toLowerCase(), localized; @@ -36,6 +37,7 @@ export function TagReference(tag, context) { }); } + function load(param) { button.classed('tag-reference-loading', true); @@ -83,6 +85,7 @@ export function TagReference(tag, context) { }); } + function done() { loaded = true; @@ -96,6 +99,7 @@ export function TagReference(tag, context) { showing = true; } + function hide(selection) { selection = selection || body.transition().duration(200); @@ -106,50 +110,56 @@ export function TagReference(tag, context) { showing = false; } + tagReference.button = function(selection) { button = selection.selectAll('.tag-reference-button') .data([0]); - button.enter() + button = button.enter() .append('button') + .on('click', function () { + d3.event.stopPropagation(); + d3.event.preventDefault(); + if (showing) { + hide(); + } else if (loaded) { + done(); + } else { + if (context.taginfo()) { + load(tag); + } + } + }) .attr('class', 'tag-reference-button') .attr('tabindex', -1) - .call(Icon('#icon-inspect')); - - button.on('click', function () { - d3.event.stopPropagation(); - d3.event.preventDefault(); - if (showing) { - hide(); - } else if (loaded) { - done(); - } else { - if (context.taginfo()) { - load(tag); - } - } - }); + .call(Icon('#icon-inspect')) + .merge(button); }; + tagReference.body = function(selection) { body = selection.selectAll('.tag-reference-body') .data([0]); - body.enter().append('div') + body = body.enter() + .append('div') .attr('class', 'tag-reference-body cf') .style('max-height', '0') - .style('opacity', '0'); + .style('opacity', '0') + .merge(body); if (showing === false) { hide(body); } }; + tagReference.showing = function(_) { if (!arguments.length) return showing; showing = _; return tagReference; }; + return tagReference; }