From ce12c34efe52667606f463bafbb1bbb1ba535116 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 2 Aug 2017 17:11:47 -0400 Subject: [PATCH 01/16] WIP refactor field rendering code out of preset editor --- modules/ui/field.js | 75 ++++++++++++++++ modules/ui/index.js | 1 + modules/ui/preset.js | 209 +++++++++++++++++++++++-------------------- 3 files changed, 188 insertions(+), 97 deletions(-) create mode 100644 modules/ui/field.js diff --git a/modules/ui/field.js b/modules/ui/field.js new file mode 100644 index 000000000..3ab3e580e --- /dev/null +++ b/modules/ui/field.js @@ -0,0 +1,75 @@ +import * as d3 from 'd3'; +import _ from 'lodash'; +import { uiFields } from './fields'; +import { utilRebind } from '../util'; + + +export function uiField(context, dispatch, presetField, entity, show) { + + var field = _.clone(presetField), + tags; + + + field.render = uiFields[field.type](field, context) + .on('change', function(t, onInput) { + dispatch.call('change', field, t, onInput); + }); + + if (field.render.entity) { + field.render.entity(entity); + } + + field.keys = field.keys || [field.key]; + + field.show = show; + + + field.shown = function() { + return field.show || _.some(field.keys, function(key) { return !!tags[key]; }); + }; + + + field.modified = function() { + var original = context.graph().base().entities[entity.id]; + return _.some(field.keys, function(key) { + return original ? tags[key] !== original.tags[key] : tags[key]; + }); + }; + + + field.revert = function() { + var original = context.graph().base().entities[entity.id], + t = {}; + field.keys.forEach(function(key) { + t[key] = original ? original.tags[key] : undefined; + }); + return t; + }; + + + field.present = function() { + return _.some(field.keys, function(key) { + return tags[key]; + }); + }; + + + field.remove = function() { + var t = {}; + field.keys.forEach(function(key) { + t[key] = undefined; + }); + return t; + }; + + + field.tags = function(_) { + if (!arguments.length) return tags; + tags = _; + return field; + }; + + + return field; +} + diff --git a/modules/ui/index.js b/modules/ui/index.js index 76dd5fd31..4ecf2b9cc 100644 --- a/modules/ui/index.js +++ b/modules/ui/index.js @@ -13,6 +13,7 @@ export { uiEditMenu } from './edit_menu'; export { uiEntityEditor } from './entity_editor'; export { uiFeatureInfo } from './feature_info'; export { uiFeatureList } from './feature_list'; +export { uiField } from './field'; export { uiFlash } from './flash'; export { uiFullScreen } from './full_screen'; export { uiGeolocate } from './geolocate'; diff --git a/modules/ui/preset.js b/modules/ui/preset.js index fd1defff1..86a8c0d69 100644 --- a/modules/ui/preset.js +++ b/modules/ui/preset.js @@ -2,10 +2,10 @@ import * as d3 from 'd3'; import _ from 'lodash'; import { d3combobox } from '../lib/d3.combobox.js'; import { t, textDirection } from '../util/locale'; -import { modeBrowse } from '../modes/index'; -import { svgIcon } from '../svg/index'; +import { modeBrowse } from '../modes'; +import { svgIcon } from '../svg'; import { uiDisclosure } from './disclosure'; -import { uiFields } from './fields/index'; +import { uiField } from './field'; import { uiTagReference } from './tag_reference'; import { utilGetSetValue, @@ -24,63 +24,59 @@ export function uiPreset(context) { id; - // Field Constructor - function UIField(field, entity, show) { - field = _.clone(field); + // // Field Constructor + // function UIField(field, entity, show) { + // field = _.clone(field); - field.input = uiFields[field.type](field, context) - .on('change', function(t, onInput) { - dispatch.call('change', field, t, onInput); - }); + // field.input = uiFields[field.type](field, context) + // .on('change', function(t, onInput) { + // dispatch.call('change', field, t, onInput); + // }); - if (field.input.entity) field.input.entity(entity); + // if (field.input.entity) field.input.entity(entity); - field.keys = field.keys || [field.key]; + // field.keys = field.keys || [field.key]; - field.show = show; + // field.show = show; - field.shown = function() { - return field.show || _.some(field.keys, function(key) { return !!tags[key]; }); - }; + // field.shown = function() { + // return field.show || _.some(field.keys, function(key) { return !!tags[key]; }); + // }; - field.modified = function() { - var original = context.graph().base().entities[entity.id]; - return _.some(field.keys, function(key) { - return original ? tags[key] !== original.tags[key] : tags[key]; - }); - }; + // field.modified = function() { + // var original = context.graph().base().entities[entity.id]; + // return _.some(field.keys, function(key) { + // return original ? tags[key] !== original.tags[key] : tags[key]; + // }); + // }; - field.revert = function() { - var original = context.graph().base().entities[entity.id], - t = {}; - field.keys.forEach(function(key) { - t[key] = original ? original.tags[key] : undefined; - }); - return t; - }; + // field.revert = function() { + // var original = context.graph().base().entities[entity.id], + // t = {}; + // field.keys.forEach(function(key) { + // t[key] = original ? original.tags[key] : undefined; + // }); + // return t; + // }; - field.present = function() { - return _.some(field.keys, function(key) { - return tags[key]; - }); - }; + // field.present = function() { + // return _.some(field.keys, function(key) { + // return tags[key]; + // }); + // }; - field.remove = function() { - var t = {}; - field.keys.forEach(function(key) { - t[key] = undefined; - }); - return t; - }; + // field.remove = function() { + // var t = {}; + // field.keys.forEach(function(key) { + // t[key] = undefined; + // }); + // return t; + // }; - return field; - } + // return field; + // } - function fieldKey(field) { - return field.id; - } - function presets(selection) { selection.call(uiDisclosure() @@ -107,17 +103,23 @@ export function uiPreset(context) { preset.fields.forEach(function(field) { if (field.matchGeometry(geometry)) { - fieldsArr.push(UIField(field, entity, true)); + fieldsArr.push( + uiField(context, dispatch, field, entity, true).tags(tags) + ); } }); if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) { - fieldsArr.push(UIField(presets.field('restrictions'), entity, true)); + fieldsArr.push( + uiField(context, dispatch, presets.field('restrictions'), entity, true).tags(tags) + ); } presets.universal().forEach(function(field) { if (preset.fields.indexOf(field) < 0) { - fieldsArr.push(UIField(field, entity)); + fieldsArr.push( + uiField(context, dispatch, field, entity).tags(tags) + ); } }); } @@ -135,8 +137,8 @@ export function uiPreset(context) { .merge(form); - var fields = form.selectAll('.form-field') - .data(shown, fieldKey); + var fields = form.selectAll('.preset-form-field') + .data(shown, function(d) { return d.id; }); fields.exit() .remove(); @@ -144,60 +146,47 @@ export function uiPreset(context) { // Enter var enter = fields.enter() .append('div') - .attr('class', function(field) { - return 'form-field form-field-' + field.id; - }); + .attr('class', function(d) { return 'preset-form-field preset-form-field-' + d.id; }); - var label = enter - .append('label') - .attr('class', 'form-label') - .attr('for', function(field) { return 'preset-input-' + field.id; }) - .text(function(field) { return field.label(); }); - var wrap = label - .append('div') - .attr('class', 'form-label-button-wrap'); + // var label = enter + // .append('label') + // .attr('class', 'form-label') + // .attr('for', function(d) { return 'preset-input-' + d.id; }) + // .text(function(d) { return d.label(); }); - wrap.append('button') - .attr('class', 'remove-icon') - .attr('tabindex', -1) - .call(svgIcon('#operation-delete')); + // var wrap = label + // .append('div') + // .attr('class', 'form-label-button-wrap'); - wrap.append('button') - .attr('class', 'modified-icon') - .attr('tabindex', -1) - .call( - (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo') - ); + // wrap.append('button') + // .attr('class', 'remove-icon') + // .attr('tabindex', -1) + // .call(svgIcon('#operation-delete')); + + // wrap.append('button') + // .attr('class', 'modified-icon') + // .attr('tabindex', -1) + // .call( + // (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo') + // ); // Update fields = fields .merge(enter); - fields.selectAll('.form-label-button-wrap .remove-icon') - .on('click', remove); + // fields.selectAll('.form-label-button-wrap .remove-icon') + // .on('click', remove); - fields.selectAll('.modified-icon') - .on('click', revert); + // fields.selectAll('.modified-icon') + // .on('click', revert); fields .order() - .classed('modified', function(field) { return field.modified(); }) - .classed('present', function(field) { return field.present(); }) .each(function(field) { - var referenceKey = field.key; - if (field.type === 'multiCombo') { // lookup key without the trailing ':' - referenceKey = referenceKey.replace(/:$/, ''); - } - var reference = uiTagReference(field.reference || { key: referenceKey }, context); - - if (state === 'hover') { - reference.showing(false); - } - d3.select(this) - .call(field.input) + .call(field.render) .selectAll('input') .on('keydown', function() { // if user presses enter, and combobox is not active, accept edits.. @@ -206,14 +195,40 @@ export function uiPreset(context) { } }); - d3.select(this) - .call(reference.body) - .select('.form-label-button-wrap') - .call(reference.button); - - field.input.tags(tags); + field.render.tags(tags); }); + // .classed('modified', function(d) { return d.modified(); }) + // .classed('present', function(d) { return d.present(); }) + // .each(function(field) { + // var referenceKey = field.key; + // if (field.type === 'multiCombo') { // lookup key without the trailing ':' + // referenceKey = referenceKey.replace(/:$/, ''); + // } + // var reference = uiTagReference(field.reference || { key: referenceKey }, context); + + // if (state === 'hover') { + // reference.showing(false); + // } + + // d3.select(this) + // .call(field.render) + // .selectAll('input') + // .on('keydown', function() { + // // if user presses enter, and combobox is not active, accept edits.. + // if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) { + // context.enter(modeBrowse(context)); + // } + // }); + + // d3.select(this) + // .call(reference.body) + // .select('.form-label-button-wrap') + // .call(reference.button); + + // field.render.tags(tags); + // }); + notShown = notShown.map(function(field) { return { title: field.label(), From f6e76665a001159ce75c8b44912f3ce05e777d7b Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 2 Aug 2017 17:49:02 -0400 Subject: [PATCH 02/16] Rename uiPreset -> uiPresetEditor (consistent with raw tag editor, raw member editor, etc) --- modules/index.js | 1 + modules/ui/entity_editor.js | 4 +- modules/ui/index.js | 2 +- modules/ui/{preset.js => preset_editor.js} | 80 ++++------------------ 4 files changed, 17 insertions(+), 70 deletions(-) rename modules/ui/{preset.js => preset_editor.js} (79%) diff --git a/modules/index.js b/modules/index.js index 7b79ecf9f..e14719f0e 100644 --- a/modules/index.js +++ b/modules/index.js @@ -37,6 +37,7 @@ export { rendererFeatures as Features } from './renderer/features'; export { rendererMap as Map } from './renderer/map'; export { rendererTileLayer as TileLayer } from './renderer/tile_layer'; export { utilDetect as Detect } from './util/detect'; +export { uiPresetEditor as uiPreset } from './ui/preset_editor'; export var debug = false; diff --git a/modules/ui/entity_editor.js b/modules/ui/entity_editor.js index 4f2e0e2fc..91ff7e0cf 100644 --- a/modules/ui/entity_editor.js +++ b/modules/ui/entity_editor.js @@ -10,7 +10,7 @@ import { uiRawMemberEditor } from './raw_member_editor'; import { uiRawMembershipEditor } from './raw_membership_editor'; import { uiRawTagEditor } from './raw_tag_editor'; import { uiTagReference } from './tag_reference'; -import { uiPreset } from './preset'; +import { uiPresetEditor } from './preset_editor'; import { utilRebind } from '../util'; @@ -24,7 +24,7 @@ export function uiEntityEditor(context) { activePreset, reference; - var presetEditor = uiPreset(context) + var presetEditor = uiPresetEditor(context) .on('change', changeTags); var rawTagEditor = uiRawTagEditor(context) .on('change', changeTags); diff --git a/modules/ui/index.js b/modules/ui/index.js index 4ecf2b9cc..3abe1ebb2 100644 --- a/modules/ui/index.js +++ b/modules/ui/index.js @@ -27,7 +27,7 @@ export { uiMapInMap } from './map_in_map'; export { uiModal } from './modal'; export { uiModes } from './modes'; export { uiNotice } from './notice'; -export { uiPreset } from './preset'; +export { uiPresetEditor } from './preset_editor'; export { uiPresetIcon } from './preset_icon'; export { uiPresetList } from './preset_list'; export { uiRadialMenu } from './radial_menu'; diff --git a/modules/ui/preset.js b/modules/ui/preset_editor.js similarity index 79% rename from modules/ui/preset.js rename to modules/ui/preset_editor.js index 86a8c0d69..54545e50c 100644 --- a/modules/ui/preset.js +++ b/modules/ui/preset_editor.js @@ -14,7 +14,7 @@ import { } from '../util'; -export function uiPreset(context) { +export function uiPresetEditor(context) { var dispatch = d3.dispatch('change'), expandedPreference = (context.storage('preset_fields.expanded') !== 'false'), state, @@ -24,61 +24,7 @@ export function uiPreset(context) { id; - // // Field Constructor - // function UIField(field, entity, show) { - // field = _.clone(field); - - // field.input = uiFields[field.type](field, context) - // .on('change', function(t, onInput) { - // dispatch.call('change', field, t, onInput); - // }); - - // if (field.input.entity) field.input.entity(entity); - - // field.keys = field.keys || [field.key]; - - // field.show = show; - - // field.shown = function() { - // return field.show || _.some(field.keys, function(key) { return !!tags[key]; }); - // }; - - // field.modified = function() { - // var original = context.graph().base().entities[entity.id]; - // return _.some(field.keys, function(key) { - // return original ? tags[key] !== original.tags[key] : tags[key]; - // }); - // }; - - // field.revert = function() { - // var original = context.graph().base().entities[entity.id], - // t = {}; - // field.keys.forEach(function(key) { - // t[key] = original ? original.tags[key] : undefined; - // }); - // return t; - // }; - - // field.present = function() { - // return _.some(field.keys, function(key) { - // return tags[key]; - // }); - // }; - - // field.remove = function() { - // var t = {}; - // field.keys.forEach(function(key) { - // t[key] = undefined; - // }); - // return t; - // }; - - // return field; - // } - - - - function presets(selection) { + function presetEditor(selection) { selection.call(uiDisclosure() .title(t('inspector.all_fields')) .expanded(expandedPreference) @@ -305,38 +251,38 @@ export function uiPreset(context) { } - presets.preset = function(_) { + presetEditor.preset = function(_) { if (!arguments.length) return preset; - if (preset && preset.id === _.id) return presets; + if (preset && preset.id === _.id) return presetEditor; preset = _; fieldsArr = null; - return presets; + return presetEditor; }; - presets.state = function(_) { + presetEditor.state = function(_) { if (!arguments.length) return state; state = _; - return presets; + return presetEditor; }; - presets.tags = function(_) { + presetEditor.tags = function(_) { if (!arguments.length) return tags; tags = _; // Don't reset fieldsArr here. - return presets; + return presetEditor; }; - presets.entityID = function(_) { + presetEditor.entityID = function(_) { if (!arguments.length) return id; - if (id === _) return presets; + if (id === _) return presetEditor; id = _; fieldsArr = null; - return presets; + return presetEditor; }; - return utilRebind(presets, dispatch, 'on'); + return utilRebind(presetEditor, dispatch, 'on'); } From 1bf514b7fcab93dd1fd8ed962c16184f14768049 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 3 Aug 2017 01:10:59 -0400 Subject: [PATCH 03/16] Move field rendering code from preset_editor to field.js --- css/80_app.css | 10 +-- modules/ui/entity_editor.js | 4 +- modules/ui/field.js | 135 ++++++++++++++++++++++++++------- modules/ui/intro/navigation.js | 2 +- modules/ui/preset_editor.js | 107 ++++---------------------- 5 files changed, 132 insertions(+), 126 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index edd94ac5b..98b1adf60 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1024,22 +1024,22 @@ button.save.has-count .count::before { /* preset form basics */ -.inspector-preset { +.preset-editor { overflow: hidden; padding-bottom: 10px; } -.inspector-preset a.hide-toggle { +.preset-editor a.hide-toggle { margin: 0 20px 10px 20px; } -.inspector-preset .preset-form { +.preset-editor .preset-form { padding: 10px; margin: 0 10px 10px 10px; border-radius: 8px; } -.inspector-preset .preset-form:empty { +.preset-editor .preset-form:empty { display: none; } @@ -1056,7 +1056,7 @@ button.save.has-count .count::before { transition: margin-bottom 200ms; } -.form-field:last-child { +.wrap-form-field:last-child .form-field { margin-bottom: 0; } diff --git a/modules/ui/entity_editor.js b/modules/ui/entity_editor.js index 91ff7e0cf..497d560f8 100644 --- a/modules/ui/entity_editor.js +++ b/modules/ui/entity_editor.js @@ -88,7 +88,7 @@ export function uiEntityEditor(context) { enter .append('div') - .attr('class', 'inspector-border inspector-preset'); + .attr('class', 'inspector-border preset-editor'); enter .append('div') @@ -129,7 +129,7 @@ export function uiEntityEditor(context) { body.select('.preset-list-item .label') .text(activePreset.name()); - body.select('.inspector-preset') + body.select('.preset-editor') .call(presetEditor .preset(activePreset) .entityID(id) diff --git a/modules/ui/field.js b/modules/ui/field.js index 3ab3e580e..b9021964d 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -1,22 +1,23 @@ import * as d3 from 'd3'; import _ from 'lodash'; +import { textDirection } from '../util/locale'; +import { svgIcon } from '../svg'; import { uiFields } from './fields'; -import { utilRebind } from '../util'; +import { uiTagReference } from './tag_reference'; export function uiField(context, dispatch, presetField, entity, show) { - var field = _.clone(presetField), tags; - field.render = uiFields[field.type](field, context) + field.impl = uiFields[field.type](field, context) .on('change', function(t, onInput) { dispatch.call('change', field, t, onInput); }); - if (field.render.entity) { - field.render.entity(entity); + if (field.impl.entity) { + field.impl.entity(entity); } field.keys = field.keys || [field.key]; @@ -24,42 +25,117 @@ export function uiField(context, dispatch, presetField, entity, show) { field.show = show; - field.shown = function() { - return field.show || _.some(field.keys, function(key) { return !!tags[key]; }); - }; - - - field.modified = function() { + function isModified() { var original = context.graph().base().entities[entity.id]; return _.some(field.keys, function(key) { return original ? tags[key] !== original.tags[key] : tags[key]; }); - }; + } - field.revert = function() { - var original = context.graph().base().entities[entity.id], - t = {}; - field.keys.forEach(function(key) { - t[key] = original ? original.tags[key] : undefined; - }); - return t; - }; - - - field.present = function() { + function isPresent() { return _.some(field.keys, function(key) { return tags[key]; }); - }; + } - field.remove = function() { + function revert(d) { + d3.event.stopPropagation(); + d3.event.preventDefault(); + + var original = context.graph().base().entities[entity.id], + t = {}; + d.keys.forEach(function(key) { + t[key] = original ? original.tags[key] : undefined; + }); + + dispatch.call('change', d, t); + } + + + function remove(d) { + d3.event.stopPropagation(); + d3.event.preventDefault(); + var t = {}; - field.keys.forEach(function(key) { + d.keys.forEach(function(key) { t[key] = undefined; }); - return t; + + dispatch.call('change', d, t); + } + + + field.render = function(selection) { + var container = selection.selectAll('.form-field') + .data([field]); + + // Enter + var enter = container.enter() + .append('div') + .attr('class', function(d) { return 'form-field form-field-' + d.id; }); + + var label = enter + .append('label') + .attr('class', 'form-label') + .attr('for', function(d) { return 'preset-input-' + d.id; }) + .text(function(d) { return d.label(); }); + + var wrap = label + .append('div') + .attr('class', 'form-label-button-wrap'); + + wrap + .append('button') + .attr('class', 'remove-icon') + .attr('tabindex', -1) + .call(svgIcon('#operation-delete')); + + wrap + .append('button') + .attr('class', 'modified-icon') + .attr('tabindex', -1) + .call( + (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo') + ); + + + // Update + container = container + .merge(enter); + + container.selectAll('.form-label-button-wrap .remove-icon') + .on('click', remove); + + container.selectAll('.form-label-button-wrap .modified-icon') + .on('click', revert); + + container + .classed('modified', isModified()) + .classed('present', isPresent()) + .each(function(d) { + var referenceKey = d.key; + if (d.type === 'multiCombo') { // lookup key without the trailing ':' + referenceKey = referenceKey.replace(/:$/, ''); + } + var reference = uiTagReference(d.reference || { key: referenceKey }, context); + +//FIXME + // if (state === 'hover') { + // reference.showing(false); + // } + + d3.select(this) + .call(d.impl); + + d3.select(this) + .call(reference.body) + .select('.form-label-button-wrap') + .call(reference.button); + + d.impl.tags(tags); + }); }; @@ -70,6 +146,11 @@ export function uiField(context, dispatch, presetField, entity, show) { }; + field.isShown = function() { + return field.show || _.some(field.keys, function(key) { return !!tags[key]; }); + }; + + return field; } diff --git a/modules/ui/intro/navigation.js b/modules/ui/intro/navigation.js index 003aa3c15..e3f93222c 100644 --- a/modules/ui/intro/navigation.js +++ b/modules/ui/intro/navigation.js @@ -326,7 +326,7 @@ export function uiIntroNavigation(context, reveal) { var onClick = function() { continueTo(closeTownHall); }; - reveal('.inspector-body .inspector-preset', + reveal('.inspector-body .preset-editor', t('intro.navigation.fields_townhall'), { buttonText: t('intro.ok'), buttonCallback: onClick } ); diff --git a/modules/ui/preset_editor.js b/modules/ui/preset_editor.js index 54545e50c..1899a8d25 100644 --- a/modules/ui/preset_editor.js +++ b/modules/ui/preset_editor.js @@ -1,12 +1,9 @@ import * as d3 from 'd3'; -import _ from 'lodash'; import { d3combobox } from '../lib/d3.combobox.js'; -import { t, textDirection } from '../util/locale'; +import { t } from '../util/locale'; import { modeBrowse } from '../modes'; -import { svgIcon } from '../svg'; import { uiDisclosure } from './disclosure'; import { uiField } from './field'; -import { uiTagReference } from './tag_reference'; import { utilGetSetValue, utilNoAuto, @@ -29,7 +26,7 @@ export function uiPresetEditor(context) { .title(t('inspector.all_fields')) .expanded(expandedPreference) .on('toggled', toggled) - .content(content) + .content(render) ); function toggled(expanded) { @@ -39,7 +36,7 @@ export function uiPresetEditor(context) { } - function content(selection) { + function render(selection) { if (!fieldsArr) { var entity = context.entity(id), geometry = context.geometry(id), @@ -62,7 +59,7 @@ export function uiPresetEditor(context) { } presets.universal().forEach(function(field) { - if (preset.fields.indexOf(field) < 0) { + if (preset.fields.indexOf(field) === -1) { fieldsArr.push( uiField(context, dispatch, field, entity).tags(tags) ); @@ -70,8 +67,8 @@ export function uiPresetEditor(context) { }); } - var shown = fieldsArr.filter(function(field) { return field.shown(); }), - notShown = fieldsArr.filter(function(field) { return !field.shown(); }); + var shown = fieldsArr.filter(function(field) { return field.isShown(); }), + notShown = fieldsArr.filter(function(field) { return !field.isShown(); }); var form = selection.selectAll('.preset-form') @@ -83,7 +80,7 @@ export function uiPresetEditor(context) { .merge(form); - var fields = form.selectAll('.preset-form-field') + var fields = form.selectAll('.wrap-form-field') .data(shown, function(d) { return d.id; }); fields.exit() @@ -92,47 +89,17 @@ export function uiPresetEditor(context) { // Enter var enter = fields.enter() .append('div') - .attr('class', function(d) { return 'preset-form-field preset-form-field-' + d.id; }); - - - // var label = enter - // .append('label') - // .attr('class', 'form-label') - // .attr('for', function(d) { return 'preset-input-' + d.id; }) - // .text(function(d) { return d.label(); }); - - // var wrap = label - // .append('div') - // .attr('class', 'form-label-button-wrap'); - - // wrap.append('button') - // .attr('class', 'remove-icon') - // .attr('tabindex', -1) - // .call(svgIcon('#operation-delete')); - - // wrap.append('button') - // .attr('class', 'modified-icon') - // .attr('tabindex', -1) - // .call( - // (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo') - // ); - + .attr('class', function(d) { return 'wrap-form-field wrap-form-field-' + d.id; }); // Update fields = fields .merge(enter); - // fields.selectAll('.form-label-button-wrap .remove-icon') - // .on('click', remove); - - // fields.selectAll('.modified-icon') - // .on('click', revert); - fields .order() - .each(function(field) { + .each(function(d) { d3.select(this) - .call(field.render) + .call(d.render) .selectAll('input') .on('keydown', function() { // if user presses enter, and combobox is not active, accept edits.. @@ -141,39 +108,9 @@ export function uiPresetEditor(context) { } }); - field.render.tags(tags); + d.tags(tags); }); - // .classed('modified', function(d) { return d.modified(); }) - // .classed('present', function(d) { return d.present(); }) - // .each(function(field) { - // var referenceKey = field.key; - // if (field.type === 'multiCombo') { // lookup key without the trailing ':' - // referenceKey = referenceKey.replace(/:$/, ''); - // } - // var reference = uiTagReference(field.reference || { key: referenceKey }, context); - - // if (state === 'hover') { - // reference.showing(false); - // } - - // d3.select(this) - // .call(field.render) - // .selectAll('input') - // .on('keydown', function() { - // // if user presses enter, and combobox is not active, accept edits.. - // if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) { - // context.enter(modeBrowse(context)); - // } - // }); - - // d3.select(this) - // .call(reference.body) - // .select('.form-label-button-wrap') - // .call(reference.button); - - // field.render.tags(tags); - // }); notShown = notShown.map(function(field) { return { @@ -229,25 +166,13 @@ export function uiPresetEditor(context) { function show(field) { - field = field.field; - field.show = true; - content(selection); - field.input.focus(); +//FIXME + // field = field.field; + // field.show = true; + // render(selection); + // field.input.focus(); } - - function revert(field) { - d3.event.stopPropagation(); - d3.event.preventDefault(); - dispatch.call('change', field, field.revert()); - } - - - function remove(field) { - d3.event.stopPropagation(); - d3.event.preventDefault(); - dispatch.call('change', field, field.remove()); - } } From 2e278ba5ef9ed07d4e525faec0b80271ab0ae6cb Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 3 Aug 2017 10:28:07 -0400 Subject: [PATCH 04/16] Fix "Add Field" combo --- modules/ui/field.js | 5 +++++ modules/ui/preset_editor.js | 16 ++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/modules/ui/field.js b/modules/ui/field.js index b9021964d..f763096b8 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -151,6 +151,11 @@ export function uiField(context, dispatch, presetField, entity, show) { }; + field.focus = function() { + field.impl.focus(); + }; + + return field; } diff --git a/modules/ui/preset_editor.js b/modules/ui/preset_editor.js index 1899a8d25..4d0735224 100644 --- a/modules/ui/preset_editor.js +++ b/modules/ui/preset_editor.js @@ -161,18 +161,14 @@ export function uiPresetEditor(context) { .container(context.container()) .data(notShown) .minItems(1) - .on('accept', show) + .on('accept', function (d) { + var field = d.field; + field.show = true; + render(selection); + field.focus(); + }) ); - - function show(field) { -//FIXME - // field = field.field; - // field.show = true; - // render(selection); - // field.input.focus(); - } - } From 6fe1efaf35481e03eba30bed1d1cb072c8e503ab Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 3 Aug 2017 11:13:07 -0400 Subject: [PATCH 05/16] Some variables and formatting --- modules/ui/entity_editor.js | 49 ++++++++++++++++++++++--------------- modules/ui/field.js | 1 + modules/ui/preset_editor.js | 14 +++++------ 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/modules/ui/entity_editor.js b/modules/ui/entity_editor.js index 497d560f8..cb642fe8e 100644 --- a/modules/ui/entity_editor.js +++ b/modules/ui/entity_editor.js @@ -20,7 +20,7 @@ export function uiEntityEditor(context) { coalesceChanges = false, modified = false, base, - id, + entityId, activePreset, reference; @@ -31,7 +31,7 @@ export function uiEntityEditor(context) { function entityEditor(selection) { - var entity = context.entity(id), + var entity = context.entity(entityId), tags = _.clone(entity.tags); // Header @@ -63,7 +63,9 @@ export function uiEntityEditor(context) { .merge(enter); header.selectAll('.preset-reset') - .on('click', function() { dispatch.call('choose', this, activePreset); }); + .on('click', function() { + dispatch.call('choose', this, activePreset); + }); // Body @@ -119,12 +121,15 @@ export function uiEntityEditor(context) { .call(reference.body); body.selectAll('.preset-reset') - .on('click', function() { dispatch.call('choose', this, activePreset); }); + .on('click', function() { + dispatch.call('choose', this, activePreset); + }); body.select('.preset-list-item button') .call(uiPresetIcon() - .geometry(context.geometry(id)) - .preset(activePreset)); + .geometry(context.geometry(entityId)) + .preset(activePreset) + ); body.select('.preset-list-item .label') .text(activePreset.name()); @@ -132,22 +137,25 @@ export function uiEntityEditor(context) { body.select('.preset-editor') .call(presetEditor .preset(activePreset) - .entityID(id) + .entityID(entityId) .tags(tags) - .state(state)); + .state(state) + ); body.select('.raw-tag-editor') .call(rawTagEditor .preset(activePreset) - .entityID(id) + .entityID(entityId) .tags(tags) - .state(state)); + .state(state) + ); if (entity.type === 'relation') { body.select('.raw-member-editor') .style('display', 'block') .call(uiRawMemberEditor(context) - .entityID(id)); + .entityID(entityId) + ); } else { body.select('.raw-member-editor') .style('display', 'none'); @@ -155,7 +163,8 @@ export function uiEntityEditor(context) { body.select('.raw-membership-editor') .call(uiRawMembershipEditor(context) - .entityID(id)); + .entityID(entityId) + ); body.select('.key-trap') .on('keydown.key-trap', function() { @@ -174,7 +183,7 @@ export function uiEntityEditor(context) { function historyChanged() { if (state === 'hide') return; - var entity = context.hasEntity(id), + var entity = context.hasEntity(entityId), graph = context.graph(); if (!entity) return; @@ -226,7 +235,7 @@ export function uiEntityEditor(context) { // Tag changes that fire on input can all get coalesced into a single // history operation when the user leaves the field. #2342 function changeTags(changed, onInput) { - var entity = context.entity(id), + var entity = context.entity(entityId), annotation = t('operations.change_tags.annotation'), tags = _.clone(entity.tags); @@ -242,9 +251,9 @@ export function uiEntityEditor(context) { if (!_.isEqual(entity.tags, tags)) { if (coalesceChanges) { - context.overwrite(actionChangeTags(id, tags), annotation); + context.overwrite(actionChangeTags(entityId, tags), annotation); } else { - context.perform(actionChangeTags(id, tags), annotation); + context.perform(actionChangeTags(entityId, tags), annotation); coalesceChanges = !!onInput; } } @@ -267,10 +276,10 @@ export function uiEntityEditor(context) { entityEditor.entityID = function(_) { - if (!arguments.length) return id; - id = _; + if (!arguments.length) return entityId; + entityId = _; base = context.graph(); - entityEditor.preset(context.presets().match(context.entity(id), base)); + entityEditor.preset(context.presets().match(context.entity(entityId), base)); entityEditor.modified(false); coalesceChanges = false; return entityEditor; @@ -281,7 +290,7 @@ export function uiEntityEditor(context) { if (!arguments.length) return activePreset; if (_ !== activePreset) { activePreset = _; - reference = uiTagReference(activePreset.reference(context.geometry(id)), context) + reference = uiTagReference(activePreset.reference(context.geometry(entityId)), context) .showing(false); } return entityEditor; diff --git a/modules/ui/field.js b/modules/ui/field.js index f763096b8..58caa4018 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -142,6 +142,7 @@ export function uiField(context, dispatch, presetField, entity, show) { field.tags = function(_) { if (!arguments.length) return tags; tags = _; + // field.impl.tags(tags); return field; }; diff --git a/modules/ui/preset_editor.js b/modules/ui/preset_editor.js index 4d0735224..f87c08251 100644 --- a/modules/ui/preset_editor.js +++ b/modules/ui/preset_editor.js @@ -18,7 +18,7 @@ export function uiPresetEditor(context) { fieldsArr, preset, tags, - id; + entityId; function presetEditor(selection) { @@ -38,8 +38,8 @@ export function uiPresetEditor(context) { function render(selection) { if (!fieldsArr) { - var entity = context.entity(id), - geometry = context.geometry(id), + var entity = context.entity(entityId), + geometry = context.geometry(entityId), presets = context.presets(); fieldsArr = []; @@ -108,7 +108,7 @@ export function uiPresetEditor(context) { } }); - d.tags(tags); + // d.tags(tags); }); @@ -197,9 +197,9 @@ export function uiPresetEditor(context) { presetEditor.entityID = function(_) { - if (!arguments.length) return id; - if (id === _) return presetEditor; - id = _; + if (!arguments.length) return entityId; + if (entityId === _) return presetEditor; + entityId = _; fieldsArr = null; return presetEditor; }; From 7076bcef1625ef86528dc3a769301cd33c4294d6 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 3 Aug 2017 11:28:10 -0400 Subject: [PATCH 06/16] uiField now dispatches own events --- modules/ui/field.js | 8 +++++--- modules/ui/preset_editor.js | 14 +++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/modules/ui/field.js b/modules/ui/field.js index 58caa4018..74364fb83 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -4,10 +4,12 @@ import { textDirection } from '../util/locale'; import { svgIcon } from '../svg'; import { uiFields } from './fields'; import { uiTagReference } from './tag_reference'; +import { utilRebind } from '../util'; -export function uiField(context, dispatch, presetField, entity, show) { - var field = _.clone(presetField), +export function uiField(context, presetField, entity, show) { + var dispatch = d3.dispatch('change'), + field = _.clone(presetField), tags; @@ -157,6 +159,6 @@ export function uiField(context, dispatch, presetField, entity, show) { }; - return field; + return utilRebind(field, dispatch, 'on'); } diff --git a/modules/ui/preset_editor.js b/modules/ui/preset_editor.js index f87c08251..3ad1ce88d 100644 --- a/modules/ui/preset_editor.js +++ b/modules/ui/preset_editor.js @@ -47,24 +47,32 @@ export function uiPresetEditor(context) { preset.fields.forEach(function(field) { if (field.matchGeometry(geometry)) { fieldsArr.push( - uiField(context, dispatch, field, entity, true).tags(tags) + uiField(context, field, entity, true) ); } }); if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) { fieldsArr.push( - uiField(context, dispatch, presets.field('restrictions'), entity, true).tags(tags) + uiField(context, presets.field('restrictions'), entity, true) ); } presets.universal().forEach(function(field) { if (preset.fields.indexOf(field) === -1) { fieldsArr.push( - uiField(context, dispatch, field, entity).tags(tags) + uiField(context, field, entity) ); } }); + + fieldsArr.forEach(function(field) { + field + .tags(tags) + .on('change', function(t, onInput) { + dispatch.call('change', field, t, onInput); + }); + }); } var shown = fieldsArr.filter(function(field) { return field.isShown(); }), From 6950220cedd8d618481b13e6bc80da8bb280c0a3 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 3 Aug 2017 12:11:17 -0400 Subject: [PATCH 07/16] Update the tags before rendering --- modules/ui/field.js | 1 - modules/ui/preset_editor.js | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ui/field.js b/modules/ui/field.js index 74364fb83..f8c7cdc48 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -144,7 +144,6 @@ export function uiField(context, presetField, entity, show) { field.tags = function(_) { if (!arguments.length) return tags; tags = _; - // field.impl.tags(tags); return field; }; diff --git a/modules/ui/preset_editor.js b/modules/ui/preset_editor.js index 3ad1ce88d..25d6e6915 100644 --- a/modules/ui/preset_editor.js +++ b/modules/ui/preset_editor.js @@ -61,20 +61,23 @@ export function uiPresetEditor(context) { presets.universal().forEach(function(field) { if (preset.fields.indexOf(field) === -1) { fieldsArr.push( - uiField(context, field, entity) + uiField(context, field, entity, false) ); } }); fieldsArr.forEach(function(field) { field - .tags(tags) .on('change', function(t, onInput) { dispatch.call('change', field, t, onInput); }); }); } + fieldsArr.forEach(function(field) { + field.tags(tags); + }); + var shown = fieldsArr.filter(function(field) { return field.isShown(); }), notShown = fieldsArr.filter(function(field) { return !field.isShown(); }); @@ -115,8 +118,6 @@ export function uiPresetEditor(context) { context.enter(modeBrowse(context)); } }); - - // d.tags(tags); }); From 216a04d96218007c71eeb3ab9ded1e5dba5ba00e Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 3 Aug 2017 13:32:08 -0400 Subject: [PATCH 08/16] Restore code to set state=hover (not sure if actually needed) Also, fix hover style for textarea --- css/80_app.css | 1 + modules/ui/field.js | 17 ++++++++++++----- modules/ui/preset_editor.js | 4 +++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 98b1adf60..c28651a2b 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1146,6 +1146,7 @@ button.save.has-count .count::before { .inspector-hover .form-field-multicombo, .inspector-hover .structure-extras-wrap, .inspector-hover input, +.inspector-hover textarea, .inspector-hover label { background: #ececec; } diff --git a/modules/ui/field.js b/modules/ui/field.js index f8c7cdc48..069dc9805 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -10,7 +10,8 @@ import { utilRebind } from '../util'; export function uiField(context, presetField, entity, show) { var dispatch = d3.dispatch('change'), field = _.clone(presetField), - tags; + state = '', + tags = {}; field.impl = uiFields[field.type](field, context) @@ -123,10 +124,9 @@ export function uiField(context, presetField, entity, show) { } var reference = uiTagReference(d.reference || { key: referenceKey }, context); -//FIXME - // if (state === 'hover') { - // reference.showing(false); - // } + if (state === 'hover') { + reference.showing(false); + } d3.select(this) .call(d.impl); @@ -141,6 +141,13 @@ export function uiField(context, presetField, entity, show) { }; + field.state = function(_) { + if (!arguments.length) return state; + state = _; + return field; + }; + + field.tags = function(_) { if (!arguments.length) return tags; tags = _; diff --git a/modules/ui/preset_editor.js b/modules/ui/preset_editor.js index 25d6e6915..5b129651a 100644 --- a/modules/ui/preset_editor.js +++ b/modules/ui/preset_editor.js @@ -75,7 +75,9 @@ export function uiPresetEditor(context) { } fieldsArr.forEach(function(field) { - field.tags(tags); + field + .state(state) + .tags(tags); }); var shown = fieldsArr.filter(function(field) { return field.isShown(); }), From f2399ff9ae8f467a13ee8d3e77c7415ba708c7ae Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 4 Aug 2017 15:32:36 -0400 Subject: [PATCH 09/16] Fixed widths of form buttons. Responsive widths is weird for fields in fields --- css/80_app.css | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index c28651a2b..50eb8ccab 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -968,7 +968,7 @@ button.save.has-count .count::before { position: absolute; top: 0; right: 0; - width: 10%; + width: 32px; background: #fafafa; } @@ -1097,7 +1097,7 @@ button.save.has-count .count::before { .form-label button { border-left: 1px solid #ccc; - width: 10%; + width: 32px; height: 100%; border-radius: 0; background: #f6f6f6; @@ -1404,10 +1404,10 @@ input[type=number] { } .spin-control { - width: 20%; - height: 29px; + width: 64px; + height: 30px; display: inline-block; - margin-left: -20%; + margin-left: -64px; margin-bottom: -11px; position: relative; } @@ -1417,7 +1417,7 @@ input[type=number] { position: relative; float: left; height: 100%; - width: 50%; + width: 32px; border-left: 1px solid #CCC; border-radius: 0; background: rgba(0, 0, 0, 0); @@ -1531,11 +1531,11 @@ input[type=number] { } .form-field .wiki-title ~ .combobox-caret { - right: 10%; + right: 32px; } [dir='rtl'] .form-field .wiki-title ~ .combobox-caret { right: auto; - left: 10%; + left: 32px; } /* Localized field */ @@ -1550,8 +1550,8 @@ input[type=number] { .form-field .button-input-action { position: relative; right: 1px; - width: 10%; - margin-left: -10%; + width: 32px; + margin-left: -32px; border: 1px solid #CCC; border-top-width: 0; border-right-width: 0; @@ -1561,7 +1561,7 @@ input[type=number] { } [dir='rtl'] .form-field .button-input-action { margin-left: 0; - margin-right: -10%; + margin-right: -32px; border-right-width: 1px; border-radius: 0 0 0 4px; } From 76e605568e219eb9868a074daf4f9c0d018205ff Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 4 Aug 2017 17:45:47 -0400 Subject: [PATCH 10/16] WIP: refactor bridge/tunnel layer field to use uiField --- data/presets.yaml | 2 + data/presets/fields.json | 5 +- data/presets/fields/layer.json | 7 +- dist/locales/en.json | 3 +- modules/ui/fields/radio.js | 314 ++++++++++++++++++--------------- 5 files changed, 184 insertions(+), 147 deletions(-) diff --git a/data/presets.yaml b/data/presets.yaml index 9b503802e..8ad29bdbf 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -634,6 +634,8 @@ en: layer: # layer=* label: Layer + # layer field placeholder + placeholder: '0' leaf_cycle: # leaf_cycle=* label: Leaf Cycle diff --git a/data/presets/fields.json b/data/presets/fields.json index ead82bb63..2f6ce6767 100644 --- a/data/presets/fields.json +++ b/data/presets/fields.json @@ -883,8 +883,9 @@ }, "layer": { "key": "layer", - "type": "combo", - "label": "Layer" + "type": "number", + "label": "Layer", + "placeholder": "0" }, "leaf_cycle_singular": { "key": "leaf_cycle", diff --git a/data/presets/fields/layer.json b/data/presets/fields/layer.json index d66d60c0a..29039f46a 100644 --- a/data/presets/fields/layer.json +++ b/data/presets/fields/layer.json @@ -1,5 +1,6 @@ { "key": "layer", - "type": "combo", - "label": "Layer" -} \ No newline at end of file + "type": "number", + "label": "Layer", + "placeholder": "0" +} diff --git a/dist/locales/en.json b/dist/locales/en.json index 39d7c52c7..18d65d682 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -1624,7 +1624,8 @@ "placeholder": "1, 2, 3..." }, "layer": { - "label": "Layer" + "label": "Layer", + "placeholder": "0" }, "leaf_cycle_singular": { "label": "Leaf Cycle", diff --git a/modules/ui/fields/radio.js b/modules/ui/fields/radio.js index eca522493..17db4e6cb 100644 --- a/modules/ui/fields/radio.js +++ b/modules/ui/fields/radio.js @@ -1,11 +1,12 @@ import * as d3 from 'd3'; import { t } from '../../util/locale'; -import { d3combobox } from '../../lib/d3.combobox.js'; -import { services } from '../../services/index'; +// import { d3combobox } from '../../lib/d3.combobox.js'; +// import { services } from '../../services'; +import { uiField } from '../field'; import { utilGetSetValue, - utilNoAuto, + // utilNoAuto, utilRebind } from '../../util'; @@ -15,13 +16,14 @@ export { uiFieldRadio as uiFieldStructureRadio }; export function uiFieldRadio(field, context) { var dispatch = d3.dispatch('change'), - taginfo = services.taginfo, + // taginfo = services.taginfo, placeholder = d3.select(null), wrap = d3.select(null), labels = d3.select(null), radios = d3.select(null), - typeInput = d3.select(null), - layerInput = d3.select(null), + // typeInput = d3.select(null), + // layerInput = d3.select(null), + layerField, oldType = {}, entity; @@ -32,31 +34,31 @@ export function uiFieldRadio(field, context) { return !node.empty() && node.datum(); } - // returns the tag value for a display value - function tagValue(dispVal) { - dispVal = snake(clean(dispVal || '')); - return dispVal.toLowerCase() || 'yes'; - } + // // returns the tag value for a display value + // function tagValue(dispVal) { + // dispVal = snake(clean(dispVal || '')); + // return dispVal.toLowerCase() || 'yes'; + // } - // returns the display value for a tag value - function displayValue(tagVal) { - tagVal = tagVal || ''; - return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal); - } + // // returns the display value for a tag value + // function displayValue(tagVal) { + // tagVal = tagVal || ''; + // return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal); + // } - function snake(s) { - return s.replace(/\s+/g, '_'); - } + // function snake(s) { + // return s.replace(/\s+/g, '_'); + // } - function unsnake(s) { - return s.replace(/_+/g, ' '); - } + // function unsnake(s) { + // return s.replace(/_+/g, ' '); + // } - function clean(s) { - return s.split(';') - .map(function(s) { return s.trim(); }) - .join(';'); - } + // function clean(s) { + // return s.split(';') + // .map(function(s) { return s.trim(); }) + // .join(';'); + // } function radio(selection) { @@ -101,10 +103,11 @@ export function uiFieldRadio(field, context) { radios = labels.selectAll('input') .on('change', changeRadio); + } - function structureExtras(selection) { + function structureExtras(selection, tags) { var selected = selectedKey(); var extrasWrap = selection.selectAll('.structure-extras-wrap') @@ -118,152 +121,183 @@ export function uiFieldRadio(field, context) { .attr('class', 'structure-extras-wrap') .merge(extrasWrap); - var list = extrasWrap.selectAll('ul') - .data([0]); + // var list = extrasWrap.selectAll('ul') + // .data([0]); - list = list.enter() - .append('ul') - .merge(list); + // list = list.enter() + // .append('ul') + // .merge(list); - // Type - var typeItem = list.selectAll('.structure-type-item') - .data([0]); + // // Type + // var typeItem = list.selectAll('.structure-type-item') + // .data([0]); - var typeEnter = typeItem.enter() - .append('li') - .attr('class', 'cf structure-type-item'); + // var typeEnter = typeItem.enter() + // .append('li') + // .attr('class', 'cf structure-type-item'); - typeEnter - .append('span') - .attr('class', 'col6 label structure-label-type') - .attr('for', 'structure-input-type') - .text(t('inspector.radio.structure.type')); + // typeEnter + // .append('span') + // .attr('class', 'col6 label structure-label-type') + // .attr('for', 'structure-input-type') + // .text(t('inspector.radio.structure.type')); - typeEnter - .append('div') - .attr('class', 'col6 structure-input-type-wrap') - .append('input') - .attr('type', 'text') - .attr('class', 'structure-input-type') - .attr('placeholder', t('inspector.radio.structure.default')) - .call(utilNoAuto); + // typeEnter + // .append('div') + // .attr('class', 'col6 structure-input-type-wrap') + // .append('input') + // .attr('type', 'text') + // .attr('class', 'structure-input-type') + // .attr('placeholder', t('inspector.radio.structure.default')) + // .call(utilNoAuto); - typeItem = typeItem - .merge(typeEnter); + // typeItem = typeItem + // .merge(typeEnter); - typeInput = typeItem.selectAll('.structure-input-type'); + // typeInput = typeItem.selectAll('.structure-input-type'); - if (taginfo) { - typeInput - .call(d3combobox() - .container(context.container()) - .fetcher(typeFetcher) - ); - } + // if (taginfo) { + // typeInput + // .call(d3combobox() + // .container(context.container()) + // .fetcher(typeFetcher) + // ); + // } - typeInput - .on('change', changeType) - .on('blur', changeType); + // typeInput + // .on('change', changeType) + // .on('blur', changeType); // Layer var showLayer = (selected === 'bridge' || selected === 'tunnel'); + if (!layerField) { + var field = context.presets().field('layer'); + layerField = uiField(context, field, entity, true) + .on('change', changeLayer); + } - var layerItem = list.selectAll('.structure-layer-item') - .data(showLayer ? [0] : []); + layerField.tags(tags); + + var layerItem = extrasWrap.selectAll('.structure-layer-item') + .data(layerField && showLayer ? [0] : []); + + // Exit layerItem.exit() .remove(); + // Enter var layerEnter = layerItem.enter() - .append('li') + .append('div') .attr('class', 'cf structure-layer-item'); - layerEnter - .append('span') - .attr('class', 'col6 label structure-label-layer') - .attr('for', 'structure-input-layer') - .text(t('inspector.radio.structure.layer')); - - layerEnter - .append('div') - .attr('class', 'col6 structure-input-layer-wrap') - .append('input') - .attr('type', 'text') - .attr('class', 'structure-input-layer') - .attr('placeholder', '0') - .call(utilNoAuto); - - var spin = layerEnter - .append('div') - .attr('class', 'spin-control'); - - spin - .append('button') - .datum(-1) - .attr('class', 'decrement') - .attr('tabindex', -1); - - spin - .append('button') - .datum(1) - .attr('class', 'increment') - .attr('tabindex', -1); - + // Update layerItem = layerItem .merge(layerEnter); - layerInput = layerItem.selectAll('.structure-input-layer') - .on('change', changeLayer) - .on('blur', changeLayer); + layerItem + .call(layerField.render); - layerItem.selectAll('button') - .on('click', function(d) { - d3.event.preventDefault(); - var num = parseInt(layerInput.node().value || 0, 10); - if (!isNaN(num)) layerInput.node().value = num + d; - changeLayer(); - }); + + // var layerItem = list.selectAll('.structure-layer-item') + // .data(showLayer ? [0] : []); + + // layerItem.exit() + // .remove(); + + // var layerEnter = layerItem.enter() + // .append('li') + // .attr('class', 'cf structure-layer-item'); + + // layerEnter + // .append('span') + // .attr('class', 'col6 label structure-label-layer') + // .attr('for', 'structure-input-layer') + // .text(t('inspector.radio.structure.layer')); + + // layerEnter + // .append('div') + // .attr('class', 'col6 structure-input-layer-wrap') + // .append('input') + // .attr('type', 'text') + // .attr('class', 'structure-input-layer') + // .attr('placeholder', '0') + // .call(utilNoAuto); + + // var spin = layerEnter + // .append('div') + // .attr('class', 'spin-control'); + + // spin + // .append('button') + // .datum(-1) + // .attr('class', 'decrement') + // .attr('tabindex', -1); + + // spin + // .append('button') + // .datum(1) + // .attr('class', 'increment') + // .attr('tabindex', -1); + + // layerItem = layerItem + // .merge(layerEnter); + + // layerInput = layerItem.selectAll('.structure-input-layer') + // .on('change', changeLayer) + // .on('blur', changeLayer); + + // layerItem.selectAll('button') + // .on('click', function(d) { + // d3.event.preventDefault(); + // var num = parseInt(layerInput.node().value || 0, 10); + // if (!isNaN(num)) layerInput.node().value = num + d; + // changeLayer(); + // }); } - function typeFetcher(q, callback) { - taginfo.values({ - debounce: true, - key: selectedKey(), - query: q - }, function(err, data) { - if (err) return; - var comboData = data.map(function(d) { - return { - key: d.value, - value: unsnake(d.value), - title: d.title - }; - }); - if (callback) callback(comboData); - }); - } + // function typeFetcher(q, callback) { + // taginfo.values({ + // debounce: true, + // key: selectedKey(), + // query: q + // }, function(err, data) { + // if (err) return; + // var comboData = data.map(function(d) { + // return { + // key: d.value, + // value: unsnake(d.value), + // title: d.title + // }; + // }); + // if (callback) callback(comboData); + // }); + // } - function changeType() { - var key = selectedKey(), - t = {}; + // function changeType() { + // var key = selectedKey(), + // t = {}; - if (!key) return; - var val = tagValue(utilGetSetValue(typeInput)); - t[key] = val; - if (val !== 'no') oldType[key] = val; - dispatch.call('change', this, t); - } + // if (!key) return; + // var val = tagValue(utilGetSetValue(typeInput)); + // t[key] = val; + // if (val !== 'no') oldType[key] = val; + // dispatch.call('change', this, t); + // } - function changeLayer() { + function changeLayer(t, onInput) { // note: don't use utilGetSetValue here because we want 0 to be falsy. - var t = { layer: layerInput.node().value || undefined }; - dispatch.call('change', this, t); + // var t = { layer: layerInput.node().value || undefined }; + if (t.layer === '0') { + t.layer = undefined; + } + dispatch.call('change', this, t, onInput); } @@ -324,9 +358,7 @@ export function uiFieldRadio(field, context) { } if (field.type === 'structureRadio') { - wrap.call(structureExtras); - utilGetSetValue(typeInput, displayValue(typeVal) || ''); - utilGetSetValue(layerInput, tags.layer || ''); + wrap.call(structureExtras, tags); } }; From 8a399096b2e3b96e76e349f4e0f316cc2a854f63 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 5 Aug 2017 00:33:20 -0400 Subject: [PATCH 11/16] Add options for fields, allow unwrapped fields (no label, buttons, etc) --- css/80_app.css | 1 + modules/ui/field.js | 80 +++++++++++++++++++--------------- modules/ui/fields/radio.js | 87 ++++++++----------------------------- modules/ui/preset_editor.js | 6 +-- 4 files changed, 69 insertions(+), 105 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 50eb8ccab..dad03b124 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1056,6 +1056,7 @@ button.save.has-count .count::before { transition: margin-bottom 200ms; } +.form-field.nowrap, .wrap-form-field:last-child .form-field { margin-bottom: 0; } diff --git a/modules/ui/field.js b/modules/ui/field.js index 069dc9805..148369f1d 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -7,7 +7,12 @@ import { uiTagReference } from './tag_reference'; import { utilRebind } from '../util'; -export function uiField(context, presetField, entity, show) { +export function uiField(context, presetField, entity, options) { + options = _.extend({ + show: true, + wrap: true + }, options); + var dispatch = d3.dispatch('change'), field = _.clone(presetField), state = '', @@ -25,7 +30,7 @@ export function uiField(context, presetField, entity, show) { field.keys = field.keys || [field.key]; - field.show = show; + field.show = options.show; function isModified() { @@ -77,31 +82,34 @@ export function uiField(context, presetField, entity, show) { // Enter var enter = container.enter() .append('div') - .attr('class', function(d) { return 'form-field form-field-' + d.id; }); + .attr('class', function(d) { return 'form-field form-field-' + d.id; }) + .classed('nowrap', !options.wrap); - var label = enter - .append('label') - .attr('class', 'form-label') - .attr('for', function(d) { return 'preset-input-' + d.id; }) - .text(function(d) { return d.label(); }); + if (options.wrap) { + var label = enter + .append('label') + .attr('class', 'form-label') + .attr('for', function(d) { return 'preset-input-' + d.id; }) + .text(function(d) { return d.label(); }); - var wrap = label - .append('div') - .attr('class', 'form-label-button-wrap'); + var wrap = label + .append('div') + .attr('class', 'form-label-button-wrap'); - wrap - .append('button') - .attr('class', 'remove-icon') - .attr('tabindex', -1) - .call(svgIcon('#operation-delete')); + wrap + .append('button') + .attr('class', 'remove-icon') + .attr('tabindex', -1) + .call(svgIcon('#operation-delete')); - wrap - .append('button') - .attr('class', 'modified-icon') - .attr('tabindex', -1) - .call( - (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo') - ); + wrap + .append('button') + .attr('class', 'modified-icon') + .attr('tabindex', -1) + .call( + (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo') + ); + } // Update @@ -118,23 +126,27 @@ export function uiField(context, presetField, entity, show) { .classed('modified', isModified()) .classed('present', isPresent()) .each(function(d) { - var referenceKey = d.key; - if (d.type === 'multiCombo') { // lookup key without the trailing ':' - referenceKey = referenceKey.replace(/:$/, ''); - } - var reference = uiTagReference(d.reference || { key: referenceKey }, context); + if (options.wrap) { + var referenceKey = d.key; + if (d.type === 'multiCombo') { // lookup key without the trailing ':' + referenceKey = referenceKey.replace(/:$/, ''); + } + var reference = uiTagReference(d.reference || { key: referenceKey }, context); - if (state === 'hover') { - reference.showing(false); + if (state === 'hover') { + reference.showing(false); + } } d3.select(this) .call(d.impl); - d3.select(this) - .call(reference.body) - .select('.form-label-button-wrap') - .call(reference.button); + if (options.wrap) { + d3.select(this) + .call(reference.body) + .select('.form-label-button-wrap') + .call(reference.button); + } d.impl.tags(tags); }); diff --git a/modules/ui/fields/radio.js b/modules/ui/fields/radio.js index 17db4e6cb..f11b98736 100644 --- a/modules/ui/fields/radio.js +++ b/modules/ui/fields/radio.js @@ -121,12 +121,12 @@ export function uiFieldRadio(field, context) { .attr('class', 'structure-extras-wrap') .merge(extrasWrap); - // var list = extrasWrap.selectAll('ul') - // .data([0]); + var list = extrasWrap.selectAll('ul') + .data([0]); - // list = list.enter() - // .append('ul') - // .merge(list); + list = list.enter() + .append('ul') + .merge(list); // // Type @@ -174,14 +174,14 @@ export function uiFieldRadio(field, context) { var showLayer = (selected === 'bridge' || selected === 'tunnel'); if (!layerField) { var field = context.presets().field('layer'); - layerField = uiField(context, field, entity, true) + layerField = uiField(context, field, entity, { wrap: false }) .on('change', changeLayer); } layerField.tags(tags); - var layerItem = extrasWrap.selectAll('.structure-layer-item') + var layerItem = list.selectAll('.structure-layer-item') .data(layerField && showLayer ? [0] : []); // Exit @@ -190,73 +190,26 @@ export function uiFieldRadio(field, context) { // Enter var layerEnter = layerItem.enter() - .append('div') + .append('li') .attr('class', 'cf structure-layer-item'); + layerEnter + .append('span') + .attr('class', 'col6 label structure-label-layer') + .attr('for', 'preset-input-layer') + .text(t('inspector.radio.structure.layer')); + + layerEnter + .append('div') + .attr('class', 'col6 structure-input-layer-wrap'); + // Update layerItem = layerItem .merge(layerEnter); - layerItem + layerItem.selectAll('.structure-input-layer-wrap') .call(layerField.render); - - // var layerItem = list.selectAll('.structure-layer-item') - // .data(showLayer ? [0] : []); - - // layerItem.exit() - // .remove(); - - // var layerEnter = layerItem.enter() - // .append('li') - // .attr('class', 'cf structure-layer-item'); - - // layerEnter - // .append('span') - // .attr('class', 'col6 label structure-label-layer') - // .attr('for', 'structure-input-layer') - // .text(t('inspector.radio.structure.layer')); - - // layerEnter - // .append('div') - // .attr('class', 'col6 structure-input-layer-wrap') - // .append('input') - // .attr('type', 'text') - // .attr('class', 'structure-input-layer') - // .attr('placeholder', '0') - // .call(utilNoAuto); - - // var spin = layerEnter - // .append('div') - // .attr('class', 'spin-control'); - - // spin - // .append('button') - // .datum(-1) - // .attr('class', 'decrement') - // .attr('tabindex', -1); - - // spin - // .append('button') - // .datum(1) - // .attr('class', 'increment') - // .attr('tabindex', -1); - - // layerItem = layerItem - // .merge(layerEnter); - - // layerInput = layerItem.selectAll('.structure-input-layer') - // .on('change', changeLayer) - // .on('blur', changeLayer); - - // layerItem.selectAll('button') - // .on('click', function(d) { - // d3.event.preventDefault(); - // var num = parseInt(layerInput.node().value || 0, 10); - // if (!isNaN(num)) layerInput.node().value = num + d; - // changeLayer(); - // }); - } @@ -292,8 +245,6 @@ export function uiFieldRadio(field, context) { function changeLayer(t, onInput) { - // note: don't use utilGetSetValue here because we want 0 to be falsy. - // var t = { layer: layerInput.node().value || undefined }; if (t.layer === '0') { t.layer = undefined; } diff --git a/modules/ui/preset_editor.js b/modules/ui/preset_editor.js index 5b129651a..beeb67cc5 100644 --- a/modules/ui/preset_editor.js +++ b/modules/ui/preset_editor.js @@ -47,21 +47,21 @@ export function uiPresetEditor(context) { preset.fields.forEach(function(field) { if (field.matchGeometry(geometry)) { fieldsArr.push( - uiField(context, field, entity, true) + uiField(context, field, entity) ); } }); if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) { fieldsArr.push( - uiField(context, presets.field('restrictions'), entity, true) + uiField(context, presets.field('restrictions'), entity) ); } presets.universal().forEach(function(field) { if (preset.fields.indexOf(field) === -1) { fieldsArr.push( - uiField(context, field, entity, false) + uiField(context, field, entity, { show: false }) ); } }); From 077ee6d4b56e193794ea770672dac463d8c63483 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 5 Aug 2017 23:30:34 -0400 Subject: [PATCH 12/16] refactor structure type field to use uiField --- data/presets.yaml | 25 ++++ data/presets/fields.json | 32 +++- data/presets/fields/bridge.json | 6 + data/presets/fields/cutting.json | 6 + data/presets/fields/embankment.json | 6 + data/presets/fields/ford.json | 6 + data/presets/fields/tunnel.json | 5 +- data/presets/fields/tunnel_waterway.json | 5 + data/presets/presets.json | 8 +- data/presets/presets/waterway/ditch.json | 2 +- data/presets/presets/waterway/drain.json | 2 +- data/presets/presets/waterway/river.json | 2 +- data/presets/presets/waterway/stream.json | 2 +- dist/locales/en.json | 22 ++- modules/ui/fields/radio.js | 174 ++++++++-------------- 15 files changed, 179 insertions(+), 124 deletions(-) create mode 100644 data/presets/fields/bridge.json create mode 100644 data/presets/fields/cutting.json create mode 100644 data/presets/fields/embankment.json create mode 100644 data/presets/fields/ford.json create mode 100644 data/presets/fields/tunnel_waterway.json diff --git a/data/presets.yaml b/data/presets.yaml index 8ad29bdbf..385e72555 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -246,6 +246,11 @@ en: brand: # brand=* label: Brand + bridge: + # bridge=* + label: Type + # bridge field placeholder + placeholder: Default building: # building=* label: Building @@ -369,6 +374,11 @@ en: currency_multi: # 'currency:=*' label: Currency Types + cutting: + # cutting=* + label: Type + # cutting field placeholder + placeholder: Default cycle_network: # cycle_network=* label: Network @@ -458,6 +468,11 @@ en: label: Email # email field placeholder placeholder: example@example.com + embankment: + # embankment=* + label: Type + # embankment field placeholder + placeholder: Default emergency: # emergency=* label: Emergency @@ -505,6 +520,11 @@ en: fixme: # fixme=* label: Fix Me + ford: + # ford=* + label: Type + # ford field placeholder + placeholder: Default fuel: # fuel=* label: Fuel @@ -1353,6 +1373,11 @@ en: # trees=* label: Trees tunnel: + # tunnel=* + label: Type + # tunnel field placeholder + placeholder: Default + tunnel_waterway: # tunnel=* label: Tunnel vending: diff --git a/data/presets/fields.json b/data/presets/fields.json index 2f6ce6767..3325ca17c 100644 --- a/data/presets/fields.json +++ b/data/presets/fields.json @@ -329,6 +329,12 @@ "type": "text", "label": "Brand" }, + "bridge": { + "key": "bridge", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" + }, "building_area": { "key": "building", "type": "combo", @@ -488,6 +494,12 @@ "type": "multiCombo", "label": "Currency Types" }, + "cutting": { + "key": "cutting", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" + }, "cycle_network": { "key": "cycle_network", "type": "networkCombo", @@ -631,6 +643,12 @@ "universal": true, "label": "Email" }, + "embankment": { + "key": "embankment", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" + }, "emergency": { "key": "emergency", "type": "check", @@ -695,6 +713,12 @@ "label": "Fix Me", "universal": true }, + "ford": { + "key": "ford", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" + }, "fuel_multi": { "key": "fuel:", "type": "multiCombo", @@ -1831,11 +1855,17 @@ "type": "semiCombo", "label": "Trees" }, - "tunnel": { + "tunnel_waterway": { "key": "tunnel", "type": "combo", "label": "Tunnel" }, + "tunnel": { + "key": "tunnel", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" + }, "vending": { "key": "vending", "type": "combo", diff --git a/data/presets/fields/bridge.json b/data/presets/fields/bridge.json new file mode 100644 index 000000000..bf0e98a04 --- /dev/null +++ b/data/presets/fields/bridge.json @@ -0,0 +1,6 @@ +{ + "key": "bridge", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" +} diff --git a/data/presets/fields/cutting.json b/data/presets/fields/cutting.json new file mode 100644 index 000000000..72314c8ff --- /dev/null +++ b/data/presets/fields/cutting.json @@ -0,0 +1,6 @@ +{ + "key": "cutting", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" +} diff --git a/data/presets/fields/embankment.json b/data/presets/fields/embankment.json new file mode 100644 index 000000000..a9818c5ba --- /dev/null +++ b/data/presets/fields/embankment.json @@ -0,0 +1,6 @@ +{ + "key": "embankment", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" +} diff --git a/data/presets/fields/ford.json b/data/presets/fields/ford.json new file mode 100644 index 000000000..3755f5925 --- /dev/null +++ b/data/presets/fields/ford.json @@ -0,0 +1,6 @@ +{ + "key": "ford", + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" +} diff --git a/data/presets/fields/tunnel.json b/data/presets/fields/tunnel.json index 2c4f7751f..e349219b4 100644 --- a/data/presets/fields/tunnel.json +++ b/data/presets/fields/tunnel.json @@ -1,5 +1,6 @@ { "key": "tunnel", - "type": "combo", - "label": "Tunnel" + "type": "typeCombo", + "label": "Type", + "placeholder": "Default" } diff --git a/data/presets/fields/tunnel_waterway.json b/data/presets/fields/tunnel_waterway.json new file mode 100644 index 000000000..2c4f7751f --- /dev/null +++ b/data/presets/fields/tunnel_waterway.json @@ -0,0 +1,5 @@ +{ + "key": "tunnel", + "type": "combo", + "label": "Tunnel" +} diff --git a/data/presets/presets.json b/data/presets/presets.json index 02896931a..d24ade186 100644 --- a/data/presets/presets.json +++ b/data/presets/presets.json @@ -14144,7 +14144,7 @@ "waterway/ditch": { "icon": "waterway-ditch", "fields": [ - "tunnel" + "tunnel_waterway" ], "geometry": [ "line" @@ -14179,7 +14179,7 @@ "waterway/drain": { "icon": "waterway-stream", "fields": [ - "tunnel" + "tunnel_waterway" ], "geometry": [ "line" @@ -14215,7 +14215,7 @@ "waterway/river": { "icon": "waterway-river", "fields": [ - "tunnel", + "tunnel_waterway", "width" ], "geometry": [ @@ -14284,7 +14284,7 @@ "waterway/stream": { "icon": "waterway-stream", "fields": [ - "tunnel", + "tunnel_waterway", "width" ], "geometry": [ diff --git a/data/presets/presets/waterway/ditch.json b/data/presets/presets/waterway/ditch.json index 0f61421df..9373764b1 100644 --- a/data/presets/presets/waterway/ditch.json +++ b/data/presets/presets/waterway/ditch.json @@ -1,7 +1,7 @@ { "icon": "waterway-ditch", "fields": [ - "tunnel" + "tunnel_waterway" ], "geometry": [ "line" diff --git a/data/presets/presets/waterway/drain.json b/data/presets/presets/waterway/drain.json index c0b72fdac..71f63d634 100644 --- a/data/presets/presets/waterway/drain.json +++ b/data/presets/presets/waterway/drain.json @@ -1,7 +1,7 @@ { "icon": "waterway-stream", "fields": [ - "tunnel" + "tunnel_waterway" ], "geometry": [ "line" diff --git a/data/presets/presets/waterway/river.json b/data/presets/presets/waterway/river.json index b9d1e8b3e..346196cf6 100644 --- a/data/presets/presets/waterway/river.json +++ b/data/presets/presets/waterway/river.json @@ -1,7 +1,7 @@ { "icon": "waterway-river", "fields": [ - "tunnel", + "tunnel_waterway", "width" ], "geometry": [ diff --git a/data/presets/presets/waterway/stream.json b/data/presets/presets/waterway/stream.json index 1a6a5f68c..b9ad16d1b 100644 --- a/data/presets/presets/waterway/stream.json +++ b/data/presets/presets/waterway/stream.json @@ -1,7 +1,7 @@ { "icon": "waterway-stream", "fields": [ - "tunnel", + "tunnel_waterway", "width" ], "geometry": [ diff --git a/dist/locales/en.json b/dist/locales/en.json index 18d65d682..1e9660185 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -1282,6 +1282,10 @@ "brand": { "label": "Brand" }, + "bridge": { + "label": "Type", + "placeholder": "Default" + }, "building_area": { "label": "Building" }, @@ -1384,6 +1388,10 @@ "currency_multi": { "label": "Currency Types" }, + "cutting": { + "label": "Type", + "placeholder": "Default" + }, "cycle_network": { "label": "Network" }, @@ -1469,6 +1477,10 @@ "label": "Email", "placeholder": "example@example.com" }, + "embankment": { + "label": "Type", + "placeholder": "Default" + }, "emergency": { "label": "Emergency" }, @@ -1509,6 +1521,10 @@ "fixme": { "label": "Fix Me" }, + "ford": { + "label": "Type", + "placeholder": "Default" + }, "fuel_multi": { "label": "Fuel Types" }, @@ -2209,9 +2225,13 @@ "trees": { "label": "Trees" }, - "tunnel": { + "tunnel_waterway": { "label": "Tunnel" }, + "tunnel": { + "label": "Type", + "placeholder": "Default" + }, "vending": { "label": "Type of Goods" }, diff --git a/modules/ui/fields/radio.js b/modules/ui/fields/radio.js index f11b98736..fa4fc4090 100644 --- a/modules/ui/fields/radio.js +++ b/modules/ui/fields/radio.js @@ -1,14 +1,7 @@ import * as d3 from 'd3'; import { t } from '../../util/locale'; -// import { d3combobox } from '../../lib/d3.combobox.js'; -// import { services } from '../../services'; import { uiField } from '../field'; - -import { - utilGetSetValue, - // utilNoAuto, - utilRebind -} from '../../util'; +import { utilRebind } from '../../util'; export { uiFieldRadio as uiFieldStructureRadio }; @@ -16,13 +9,11 @@ export { uiFieldRadio as uiFieldStructureRadio }; export function uiFieldRadio(field, context) { var dispatch = d3.dispatch('change'), - // taginfo = services.taginfo, placeholder = d3.select(null), wrap = d3.select(null), labels = d3.select(null), radios = d3.select(null), - // typeInput = d3.select(null), - // layerInput = d3.select(null), + typeField, layerField, oldType = {}, entity; @@ -34,32 +25,6 @@ export function uiFieldRadio(field, context) { return !node.empty() && node.datum(); } - // // returns the tag value for a display value - // function tagValue(dispVal) { - // dispVal = snake(clean(dispVal || '')); - // return dispVal.toLowerCase() || 'yes'; - // } - - // // returns the display value for a tag value - // function displayValue(tagVal) { - // tagVal = tagVal || ''; - // return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal); - // } - - // function snake(s) { - // return s.replace(/\s+/g, '_'); - // } - - // function unsnake(s) { - // return s.replace(/_+/g, ' '); - // } - - // function clean(s) { - // return s.split(';') - // .map(function(s) { return s.trim(); }) - // .join(';'); - // } - function radio(selection) { selection.classed('preset-radio', true); @@ -108,7 +73,11 @@ export function uiFieldRadio(field, context) { function structureExtras(selection, tags) { - var selected = selectedKey(); + var selected = selectedKey(), + type = context.presets().field(selected), + layer = context.presets().field('layer'), + showLayer = (selected === 'bridge' || selected === 'tunnel'); + var extrasWrap = selection.selectAll('.structure-extras-wrap') .data(selected ? [0] : []); @@ -129,60 +98,62 @@ export function uiFieldRadio(field, context) { .merge(list); - // // Type - // var typeItem = list.selectAll('.structure-type-item') - // .data([0]); + // Type + if (type) { + if (!typeField || typeField.id !== selected) { + typeField = uiField(context, type, entity, { wrap: false }) + .on('change', changeType); + } + typeField.tags(tags); + } else { + typeField = null; + } - // var typeEnter = typeItem.enter() - // .append('li') - // .attr('class', 'cf structure-type-item'); + var typeItem = list.selectAll('.structure-type-item') + .data(typeField ? [typeField] : [], function(d) { return d.id; }); - // typeEnter - // .append('span') - // .attr('class', 'col6 label structure-label-type') - // .attr('for', 'structure-input-type') - // .text(t('inspector.radio.structure.type')); + // Exit + typeItem.exit() + .remove(); - // typeEnter - // .append('div') - // .attr('class', 'col6 structure-input-type-wrap') - // .append('input') - // .attr('type', 'text') - // .attr('class', 'structure-input-type') - // .attr('placeholder', t('inspector.radio.structure.default')) - // .call(utilNoAuto); + // Enter + var typeEnter = typeItem.enter() + .insert('li', ':first-child') + .attr('class', 'cf structure-type-item'); - // typeItem = typeItem - // .merge(typeEnter); + typeEnter + .append('span') + .attr('class', 'col6 label structure-label-type') + .attr('for', 'preset-input-' + selected) + .text(t('inspector.radio.structure.type')); - // typeInput = typeItem.selectAll('.structure-input-type'); + typeEnter + .append('div') + .attr('class', 'col6 structure-input-type-wrap'); - // if (taginfo) { - // typeInput - // .call(d3combobox() - // .container(context.container()) - // .fetcher(typeFetcher) - // ); - // } + // Update + typeItem = typeItem + .merge(typeEnter); - // typeInput - // .on('change', changeType) - // .on('blur', changeType); + if (typeField) { + typeItem.selectAll('.structure-input-type-wrap') + .call(typeField.render); + } // Layer - var showLayer = (selected === 'bridge' || selected === 'tunnel'); - if (!layerField) { - var field = context.presets().field('layer'); - layerField = uiField(context, field, entity, { wrap: false }) - .on('change', changeLayer); + if (layer && showLayer) { + if (!layerField) { + layerField = uiField(context, layer, entity, { wrap: false }) + .on('change', changeLayer); + } + layerField.tags(tags); + } else { + layerField = null; } - layerField.tags(tags); - - var layerItem = list.selectAll('.structure-layer-item') - .data(layerField && showLayer ? [0] : []); + .data(layerField ? [layerField] : []); // Exit layerItem.exit() @@ -207,41 +178,21 @@ export function uiFieldRadio(field, context) { layerItem = layerItem .merge(layerEnter); - layerItem.selectAll('.structure-input-layer-wrap') - .call(layerField.render); - + if (layerField) { + layerItem.selectAll('.structure-input-layer-wrap') + .call(layerField.render); + } } - // function typeFetcher(q, callback) { - // taginfo.values({ - // debounce: true, - // key: selectedKey(), - // query: q - // }, function(err, data) { - // if (err) return; - // var comboData = data.map(function(d) { - // return { - // key: d.value, - // value: unsnake(d.value), - // title: d.title - // }; - // }); - // if (callback) callback(comboData); - // }); - // } + function changeType(t, onInput) { + var key = selectedKey(); + if (!key) return; - - // function changeType() { - // var key = selectedKey(), - // t = {}; - - // if (!key) return; - // var val = tagValue(utilGetSetValue(typeInput)); - // t[key] = val; - // if (val !== 'no') oldType[key] = val; - // dispatch.call('change', this, t); - // } + var val = t[key]; + if (val !== 'no') oldType[key] = val; + dispatch.call('change', this, t, onInput); + } function changeLayer(t, onInput) { @@ -299,13 +250,12 @@ export function uiFieldRadio(field, context) { radios.property('checked', checked); var selection = radios.filter(function() { return this.checked; }); - var typeVal = ''; if (selection.empty()) { placeholder.text(t('inspector.none')); } else { placeholder.text(selection.attr('value')); - typeVal = oldType[selection.datum()] = tags[selection.datum()]; + oldType[selection.datum()] = tags[selection.datum()]; } if (field.type === 'structureRadio') { From 839a23f113699c0313cf3c085f2e4357f065ea67 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sun, 6 Aug 2017 16:59:30 -0400 Subject: [PATCH 13/16] Fix rounded corners on the structure field list items --- css/80_app.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/css/80_app.css b/css/80_app.css index dad03b124..82c5f10ed 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1337,6 +1337,18 @@ button.save.has-count .count::before { border: 1px solid #ccc; border-radius: 4px; } +.structure-extras-wrap li:first-child span { + border-top-left-radius: 4px; +} +.structure-extras-wrap li:first-child input { + border-top-right-radius: 4px; +} +.structure-extras-wrap li:last-child span { + border-bottom-left-radius: 4px; +} +.structure-extras-wrap li:last-child input { + border-bottom-right-radius: 4px; +} /* preset form multicombo */ From 27113f7599f0b1fabd908b4769765b34a511db91 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sun, 6 Aug 2017 17:40:33 -0400 Subject: [PATCH 14/16] Fix RTL for spin control and form buttons --- css/80_app.css | 51 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 82c5f10ed..73f8652b0 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1107,6 +1107,7 @@ button.save.has-count .count::before { border-left: none; border-right: 1px solid #CCC; border-radius: 4px 0 0 0; + width: 31px; } .form-label button:hover { background: #f1f1f1; @@ -1298,6 +1299,7 @@ button.save.has-count .count::before { /* preset form access */ /* preset form cycleway */ +/* preset form structure extras */ .form-field-structure .structure-extras-wrap li, .form-field-cycleway .preset-input-wrap li, @@ -1349,6 +1351,22 @@ button.save.has-count .count::before { .structure-extras-wrap li:last-child input { border-bottom-right-radius: 4px; } +[dir='rtl'] .structure-extras-wrap li:first-child span { + border-top-left-radius: 0; + border-top-right-radius: 4px; +} +[dir='rtl'] .structure-extras-wrap li:first-child input { + border-top-right-radius: 0; + border-top-left-radius: 4px; +} +[dir='rtl'] .structure-extras-wrap li:last-child span { + border-bottom-left-radius: 0; + border-bottom-right-radius: 4px; +} +[dir='rtl'] .structure-extras-wrap li:last-child input { + border-bottom-right-radius: 0; + border-bottom-left-radius: 4px; +} /* preset form multicombo */ @@ -1424,6 +1442,10 @@ input[type=number] { margin-bottom: -11px; position: relative; } +[dir='rtl'] .spin-control{ + margin-left: 0; + margin-right: -64px; +} .spin-control button { right: 1px; @@ -1435,10 +1457,21 @@ input[type=number] { border-radius: 0; background: rgba(0, 0, 0, 0); } +[dir='rtl'] .spin-control button{ + border-left: 0; + border-right: 1px solid #CCC; +} .spin-control button.decrement { border-bottom-right-radius: 3px; } +[dir='rtl'] .spin-control button.decrement{ + border-bottom-right-radius: 0; + right: 0; +} +[dir='rtl'] .spin-control button.increment{ + border-bottom-left-radius: 3px; +} .spin-control button.decrement::after, .spin-control button.increment::after { @@ -1461,6 +1494,7 @@ input[type=number] { border-right: 5px solid transparent; } + /* preset form checkbox */ .checkselect label:last-of-type { @@ -4179,23 +4213,6 @@ li.hide + li.version .badge .tooltip .tooltip-arrow { border-radius: 4px 0 0 4px; } - -/* increment / decrement control - code by Naoufel Razouane */ - -[dir='rtl'] .spin-control{ - margin-left: 0; - margin-right: -20%; -} -[dir='rtl'] .spin-control button{ - border-left: 0; - border-right: 1px solid #CCC; -} -[dir='rtl'] .spin-control button.decrement{ - border-bottom-right-radius: 0; -} -[dir='rtl'] .spin-control button.increment{ - border-bottom-left-radius: 3px; -} /* modal */ [dir='rtl'] .modal > button { position: absolute; From 3e168935d1e265b57495bedd75aaaa453f9e4083 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sun, 6 Aug 2017 22:00:30 -0400 Subject: [PATCH 15/16] Swap increment/decrement spin buttons when RTL --- css/80_app.css | 6 +++--- modules/ui/fields/input.js | 16 +++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 73f8652b0..7a576702b 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1465,12 +1465,12 @@ input[type=number] { .spin-control button.decrement { border-bottom-right-radius: 3px; } -[dir='rtl'] .spin-control button.decrement{ +[dir='rtl'] .spin-control button.decrement { border-bottom-right-radius: 0; - right: 0; } -[dir='rtl'] .spin-control button.increment{ +[dir='rtl'] .spin-control button.increment { border-bottom-left-radius: 3px; + right: 0; } .spin-control button.decrement::after, diff --git a/modules/ui/fields/input.js b/modules/ui/fields/input.js index 4cbed223a..c60f9361e 100644 --- a/modules/ui/fields/input.js +++ b/modules/ui/fields/input.js @@ -1,7 +1,7 @@ import * as d3 from 'd3'; -import { t } from '../../util/locale'; -import { dataPhoneFormats } from '../../../data/index'; -import { services } from '../../services/index'; +import { t, textDirection } from '../../util/locale'; +import { dataPhoneFormats } from '../../../data'; +import { services } from '../../services'; import { utilGetSetValue, utilNoAuto, @@ -52,6 +52,8 @@ export function uiFieldText(field, context) { }); } else if (field.type === 'number') { + var rtl = (textDirection === 'rtl'); + input.attr('type', 'text'); var spinControl = selection.selectAll('.spin-control') @@ -63,14 +65,14 @@ export function uiFieldText(field, context) { enter .append('button') - .datum(-1) - .attr('class', 'decrement') + .datum(rtl ? 1 : -1) + .attr('class', rtl ? 'increment' : 'decrement') .attr('tabindex', -1); enter .append('button') - .datum(1) - .attr('class', 'increment') + .datum(rtl ? -1 : 1) + .attr('class', rtl ? 'decrement' : 'increment') .attr('tabindex', -1); spinControl = spinControl From f95d6298f2ba24fbecfed9be9c7ad8c177539e61 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sun, 6 Aug 2017 22:06:30 -0400 Subject: [PATCH 16/16] Fix RTL for panel close buttons --- css/80_app.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/css/80_app.css b/css/80_app.css index 7a576702b..fc334eaa1 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -2756,6 +2756,9 @@ img.tile-removing { background: none; color: #ddd; } +[dir='rtl'] .panel-title button.close { + float: left; +} .panel-title button.close:hover { color: #fff;