From e8d154a52915cae60d5d1715c2623598eff46e32 Mon Sep 17 00:00:00 2001 From: Quincy Morgan Date: Wed, 18 Dec 2019 11:25:31 -0500 Subject: [PATCH] Remove old, unused implementations of favorite, recent, and search-to-add preset toolbar items --- css/80_app.css | 217 ---------- modules/ui/tools/add_favorite.js | 295 -------------- modules/ui/tools/add_recent.js | 336 ---------------- modules/ui/tools/index.js | 3 - modules/ui/tools/search_add.js | 655 ------------------------------- modules/ui/top_toolbar.js | 14 +- 6 files changed, 1 insertion(+), 1519 deletions(-) delete mode 100644 modules/ui/tools/add_favorite.js delete mode 100644 modules/ui/tools/add_recent.js delete mode 100644 modules/ui/tools/search_add.js diff --git a/css/80_app.css b/css/80_app.css index 4a5430e1d..e6ad9ff49 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -607,223 +607,6 @@ button.add-note svg.icon { margin-left: 1px; } -/* Add a feature search bar -------------------------------------------------------- */ - -.search-add { - width: 200%; - justify-content: center; - position: relative; - min-width: 150px; - max-width: 325px; -} -.search-add .search-wrap { - position: relative; - width: 100%; -} -[dir='ltr'] .search-add .search-wrap { - border-radius: 20px 4px 4px 20px; -} -[dir='rtl'] .search-add .search-wrap { - border-radius: 4px 20px 20px 4px; -} -.search-add .search-wrap.focused .tooltip { - display: none; -} -.search-add .search-wrap:last-child { - border-radius: 20px; -} -.search-add input[type='search'] { - position: relative; - width: 100%; - height: 100%; - border: none; - font-size: 14px; - text-indent: 25px; - padding: 5px 10px; - border-radius: inherit; -} -.search-add input[type='search'][disabled] { - opacity: 0.25; - cursor: not-allowed; -} -.search-add .search-icon { - color: #333; - display: block; - position: absolute; - left: 10px; - top: 10px; - pointer-events: none; -} -[dir='rtl'] .search-add .search-icon { - left: auto; - right: 10px; -} -.search-add .popover { - border: none; - border-radius: 6px; - position: absolute; - max-height: 600px; - top: 44px; - width: 200%; - max-width: 325px; - margin: auto; - left: auto; - right: auto; - z-index: 300; -} -.search-add .popover .popover-content { - overflow-y: auto; - height: 100%; - max-height: 60vh; -} -.search-add .popover, -.search-add .popover .popover-content { - /* ensure corners are rounded in Chrome */ - -webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC); -} -.search-add .popover .popover-footer { - padding: 5px 10px 5px 10px; - background: #f6f6f6; - border-top: 1px solid #DCDCDC; - display: flex; -} -.search-add .popover .popover-footer .message { - color: #666666; - flex-grow: 1; -} -.search-add .popover .popover-footer button.filter { - height: 20px; - background: transparent; - color: #666; -} -.search-add .popover .popover-footer button.filter.active { - color: #7092ff; -} -.search-add .popover .popover-footer button.filter:hover { - color: #333; -} -.search-add .popover .popover-footer button.filter.active:hover { - color: #597be7; -} -.search-add .popover::-webkit-scrollbar { - /* don't overlap rounded corners */ - background: transparent; -} -.search-add .popover .list { - height: 100%; -} -.search-add .list-item > .row { - display: flex; - position: relative; - padding: 2px; -} -.search-add .list-item:not(:last-of-type) .row, -.search-add .subsection.subitems .list-item .row, -.search-add .subsection > .tag-reference-body { - border-bottom: 1px solid #DCDCDC; -} -.search-add .list-item .label { - font-weight: bold; - font-size: 12px; - padding-left: 2px; - top: 0; - bottom: 0; - position: relative; - display: flex; - align-items: center; - line-height: 1.3em; - width: 100%; -} -.search-add .list-item .label .namepart:nth-child(2) { - font-weight: normal; -} -.search-add .list-item.disabled .preset-icon-container, -.search-add .list-item.disabled .label { - opacity: 0.55; -} -[dir='ltr'] .search-add .list-item .label .icon.inline { - margin-left: 0; -} -[dir='rtl'] .search-add .list-item .label .icon.inline { - margin-right: 0; -} -.search-add .list-item .row > *:not(button) { - pointer-events: none; -} -.search-add .list-item button.choose { - position: absolute; - border-radius: 0; - height: 100%; - width: 100%; - top: 0; - left: 0; -} -.search-add .list-item button.choose:hover, -.search-add .list-item button.choose:focus { - background: #fff; -} -.search-add .list-item.focused:not(.disabled) button.choose { - background: #e8ebff; -} -.search-add .list-item button.choose.disabled { - background-color: #ececec; -} -.search-add .subsection .list-item button.choose { - opacity: 0.85; -} -.search-add .subsection .tag-reference-body { - background: rgba(255, 255, 255, 0.85); - padding: 10px; -} -.search-add .list-item button.accessory { - position: relative; - flex: 0 0 auto; - color: #808080; - background: transparent; - padding-right: 3px; - padding-left: 3px; -} -.search-add .list-item button.accessory:hover { - color: #666; -} -.search-add .list-item button.tag-reference-open path { - fill: #000; -} -.search-add .subsection { - background-color: #CBCBCB; -} -[dir='ltr'] .search-add .subitems { - padding-left: 6px; -} -[dir='rtl'] .search-add .subitems { - padding-right: 6px; -} - -/* Add a preset mode buttons -------------------------------------------------------- */ - -button.bar-button.add-preset { - border-radius: 4px; -} -[dir='ltr'] button.bar-button.add-preset { - margin-left: 1px; -} -[dir='rtl'] button.bar-button.add-preset { - margin-right: 1px; -} -[dir='ltr'] button.bar-button.add-preset.first-recent { - margin-left: 10px; -} -[dir='rtl'] button.bar-button.add-preset.first-recent { - margin-right: 10px; -} -button.bar-button.add-preset { - padding: 0; -} -button.add-preset.disabled .preset-icon-container { - opacity: 0.5; -} /* Header for modals / panes ------------------------------------------------------- */ .header { diff --git a/modules/ui/tools/add_favorite.js b/modules/ui/tools/add_favorite.js deleted file mode 100644 index 3d4d042cf..000000000 --- a/modules/ui/tools/add_favorite.js +++ /dev/null @@ -1,295 +0,0 @@ -import _debounce from 'lodash-es/debounce'; - -import { drag as d3_drag } from 'd3-drag'; -import { event as d3_event, select as d3_select } from 'd3-selection'; - -import { modeAddArea, modeAddLine, modeAddPoint, modeBrowse } from '../../modes'; -import { t, textDirection } from '../../util/locale'; -import { tooltip } from '../../util/tooltip'; -import { uiPresetIcon } from '../preset_icon'; -import { uiTooltipHtml } from '../tooltipHtml'; - - -export function uiToolAddFavorite(context) { - - var tool = { - id: 'add_favorite', - klass: 'modes', - label: t('toolbar.favorites') - }; - - function enabled() { - return osmEditable(); - } - - function osmEditable() { - return context.editable(); - } - - function toggleMode(d) { - if (!enabled(d)) return; - - if (d.button === context.mode().button) { - context.enter(modeBrowse(context)); - } else { - if (d.preset) { - context.presets().setMostRecent(d.preset, d.geometry); - } - context.enter(d); - } - } - - - tool.render = function(selection) { - context - .on('enter.editor.favorite', function(entered) { - selection.selectAll('button.add-button') - .classed('active', function(mode) { return entered.button === mode.button; }); - context.container() - .classed('mode-' + entered.id, true); - }); - - context - .on('exit.editor.favorite', function(exited) { - context.container() - .classed('mode-' + exited.id, false); - }); - - var debouncedUpdate = _debounce(update, 500, { leading: true, trailing: true }); - - context.map() - .on('move.favorite', debouncedUpdate) - .on('drawn.favorite', debouncedUpdate); - - context - .on('enter.favorite', update) - .presets() - .on('favoritePreset.favorite', update) - .on('recentsChange.favorite', update); - - update(); - - - function update() { - - for (var i = 0; i <= 9; i++) { - context.keybinding().off(i.toString()); - } - - var items = context.presets().getFavorites(); - - var modes = items.map(function(d, index) { - var presetName = d.preset.name().split(' – ')[0]; - var markerClass = 'add-preset add-' + d.geometry + ' add-preset-' + presetName.replace(/\s+/g, '_') - + '-' + d.geometry + ' add-' + d.source; // replace spaces with underscores to avoid css interpretation - if (d.preset.isFallback()) { - markerClass += ' add-generic-preset'; - } - - var supportedGeometry = d.preset.geometry.filter(function(geometry) { - return ['vertex', 'point', 'line', 'area'].indexOf(geometry) !== -1; - }); - var vertexIndex = supportedGeometry.indexOf('vertex'); - if (vertexIndex !== -1 && supportedGeometry.indexOf('point') !== -1) { - // both point and vertex allowed, just combine them - supportedGeometry.splice(vertexIndex, 1); - } - var tooltipTitleID = 'modes.add_preset.title'; - if (supportedGeometry.length !== 1) { - if (d.preset.setTags({}, d.geometry).building) { - tooltipTitleID = 'modes.add_preset.building.title'; - } else { - tooltipTitleID = 'modes.add_preset.' + context.presets().fallback(d.geometry).id + '.title'; - } - } - var protoMode = Object.assign({}, d); // shallow copy - protoMode.button = markerClass; - protoMode.title = presetName; - protoMode.description = t(tooltipTitleID, { feature: '' + presetName + '' }); - - var keyCode; - // use number row order: 1 2 3 4 5 6 7 8 9 0 - // use the same for RTL even though the layout is backward: #6107 - if (index === 9) { - keyCode = 0; - } else if (index < 10) { - keyCode = index + 1; - } - if (keyCode !== undefined) { - protoMode.key = keyCode.toString(); - } - - var mode; - switch (d.geometry) { - case 'point': - case 'vertex': - mode = modeAddPoint(context, protoMode); - break; - case 'line': - mode = modeAddLine(context, protoMode); - break; - case 'area': - mode = modeAddArea(context, protoMode); - } - - if (mode.key) { - context.keybinding().off(mode.key); - context.keybinding().on(mode.key, function() { - toggleMode(mode); - }); - } - - return mode; - }); - - var buttons = selection.selectAll('button.add-button') - .data(modes, function(d, index) { return d.button + index; }); - - // exit - buttons.exit() - .remove(); - - // enter - var buttonsEnter = buttons.enter() - .append('button') - .attr('tabindex', -1) - .attr('class', function(d) { - return d.button + ' add-button bar-button'; - }) - .on('click.mode-buttons', function(d) { - - // When drawing, ignore accidental clicks on mode buttons - #4042 - if (/^draw/.test(context.mode().id)) return; - - toggleMode(d); - }) - .call(tooltip() - .placement('bottom') - .html(true) - .title(function(d) { return uiTooltipHtml(d.description, d.key); }) - .scrollContainer(d3_select('#bar')) - ); - - buttonsEnter - .each(function(d) { - d3_select(this) - .call(uiPresetIcon(context) - .geometry((d.geometry === 'point' && !d.preset.matchGeometry(d.geometry)) ? 'vertex' : d.geometry) - .preset(d.preset) - .sizeClass('small') - ); - }); - - var dragOrigin, dragMoved, targetIndex; - - buttonsEnter.call(d3_drag() - .on('start', function() { - dragOrigin = { - x: d3_event.x, - y: d3_event.y - }; - targetIndex = null; - dragMoved = false; - }) - .on('drag', function(d, index) { - dragMoved = true; - var x = d3_event.x - dragOrigin.x, - y = d3_event.y - dragOrigin.y; - - if (!d3_select(this).classed('dragging') && - // don't display drag until dragging beyond a distance threshold - Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return; - - d3_select(this) - .classed('dragging', true) - .classed('removing', y > 50); - - targetIndex = null; - - selection.selectAll('button.add-preset') - .style('transform', function(d2, index2) { - var node = d3_select(this).node(); - if (index === index2) { - return 'translate(' + x + 'px, ' + y + 'px)'; - } else if (y > 50) { - if (index2 > index) { - return 'translateX(' + (textDirection === 'rtl' ? '' : '-') + '100%)'; - } - } else if (d.source === d2.source) { - if (index2 > index && ( - (d3_event.x > node.offsetLeft && textDirection === 'ltr') || - (d3_event.x < node.offsetLeft + node.offsetWidth && textDirection === 'rtl') - )) { - if (targetIndex === null || index2 > targetIndex) { - targetIndex = index2; - } - return 'translateX(' + (textDirection === 'rtl' ? '' : '-') + '100%)'; - } else if (index2 < index && ( - (d3_event.x < node.offsetLeft + node.offsetWidth && textDirection === 'ltr') || - (d3_event.x > node.offsetLeft && textDirection === 'rtl') - )) { - if (targetIndex === null || index2 < targetIndex) { - targetIndex = index2; - } - return 'translateX(' + (textDirection === 'rtl' ? '-' : '') + '100%)'; - } - } - return null; - }); - }) - .on('end', function(d, index) { - - if (dragMoved && !d3_select(this).classed('dragging')) { - toggleMode(d); - return; - } - - d3_select(this) - .classed('dragging', false) - .classed('removing', false); - - selection.selectAll('button.add-preset') - .style('transform', null); - - var y = d3_event.y - dragOrigin.y; - if (y > 50) { - // dragged out of the top bar, remove - if (d.isFavorite()) { - context.presets().removeFavorite(d.preset, d.geometry); - // also remove this as a recent so it doesn't still appear - context.presets().removeRecent(d.preset, d.geometry); - } - } else if (targetIndex !== null) { - // dragged to a new position, reorder - if (d.isFavorite()) { - context.presets().moveFavorite(index, targetIndex); - } - } - }) - ); - - // update - buttons = buttons - .merge(buttonsEnter) - .classed('disabled', function(d) { return !enabled(d); }); - } - }; - - tool.uninstall = function() { - - context - .on('enter.editor.favorite', null) - .on('exit.editor.favorite', null) - .on('enter.favorite', null); - - context.presets() - .on('favoritePreset.favorite', null) - .on('recentsChange.favorite', null); - - context.map() - .on('move.favorite', null) - .on('drawn.favorite', null); - }; - - return tool; -} diff --git a/modules/ui/tools/add_recent.js b/modules/ui/tools/add_recent.js deleted file mode 100644 index addc707e2..000000000 --- a/modules/ui/tools/add_recent.js +++ /dev/null @@ -1,336 +0,0 @@ -import _debounce from 'lodash-es/debounce'; - -import { drag as d3_drag } from 'd3-drag'; -import { event as d3_event, select as d3_select } from 'd3-selection'; - -import { modeAddArea, modeAddLine, modeAddPoint, modeBrowse } from '../../modes'; -import { t, textDirection } from '../../util/locale'; -import { tooltip } from '../../util/tooltip'; -import { uiPresetIcon } from '../preset_icon'; -import { uiTooltipHtml } from '../tooltipHtml'; - - -export function uiToolAddRecent(context) { - - var tool = { - id: 'add_recent', - klass: 'modes', - label: t('toolbar.recent') - }; - - function enabled() { - return osmEditable(); - } - - function osmEditable() { - return context.editable(); - } - - function toggleMode(d) { - if (!enabled(d)) return; - - if (d.button === context.mode().button) { - context.enter(modeBrowse(context)); - } else { - if (d.preset && - // don't set a recent as most recent to avoid reordering buttons - !d.isRecent()) { - context.presets().setMostRecent(d.preset, d.geometry); - } - context.enter(d); - } - } - - function recentsToDraw() { - var maxShown = 10; - var maxRecents = 5; - - var favorites = context.presets().getFavorites().slice(0, maxShown); - - function isAFavorite(recent) { - return favorites.some(function(favorite) { - return favorite.matches(recent.preset, recent.geometry); - }); - } - - var favoritesCount = favorites.length; - maxRecents = Math.min(maxRecents, maxShown - favoritesCount); - var items = []; - if (maxRecents > 0) { - var recents = context.presets().getRecents().filter(function(recent) { - return recent.geometry !== 'relation'; - }); - for (var i in recents) { - var recent = recents[i]; - if (!isAFavorite(recent)) { - items.push(recent); - if (items.length === maxRecents) { - break; - } - } - } - } - - return items; - } - - tool.shouldShow = function() { - return recentsToDraw().length > 0; - }; - - - tool.render = function(selection) { - context - .on('enter.editor.recent', function(entered) { - selection.selectAll('button.add-button') - .classed('active', function(mode) { return entered.button === mode.button; }); - context.container() - .classed('mode-' + entered.id, true); - }); - - context - .on('exit.editor.recent', function(exited) { - context.container() - .classed('mode-' + exited.id, false); - }); - - var debouncedUpdate = _debounce(update, 500, { leading: true, trailing: true }); - - context.map() - .on('move.recent', debouncedUpdate) - .on('drawn.recent', debouncedUpdate); - - context - .on('enter.recent', update) - .presets() - .on('favoritePreset.recent', update) - .on('recentsChange.recent', update); - - update(); - - - function update() { - - var items = recentsToDraw(); - var favoritesCount = context.presets().getFavorites().length; - - var modes = items.map(function(d, index) { - var presetName = d.preset.name().split(' – ')[0]; - var markerClass = 'add-preset add-' + d.geometry + ' add-preset-' + presetName.replace(/\s+/g, '_') - + '-' + d.geometry + ' add-' + d.source; // replace spaces with underscores to avoid css interpretation - if (d.preset.isFallback()) { - markerClass += ' add-generic-preset'; - } - - var supportedGeometry = d.preset.geometry.filter(function(geometry) { - return ['vertex', 'point', 'line', 'area'].indexOf(geometry) !== -1; - }); - var vertexIndex = supportedGeometry.indexOf('vertex'); - if (vertexIndex !== -1 && supportedGeometry.indexOf('point') !== -1) { - // both point and vertex allowed, just combine them - supportedGeometry.splice(vertexIndex, 1); - } - var tooltipTitleID = 'modes.add_preset.title'; - if (supportedGeometry.length !== 1) { - if (d.preset.setTags({}, d.geometry).building) { - tooltipTitleID = 'modes.add_preset.building.title'; - } else { - tooltipTitleID = 'modes.add_preset.' + context.presets().fallback(d.geometry).id + '.title'; - } - } - var protoMode = Object.assign({}, d); // shallow copy - protoMode.button = markerClass; - protoMode.title = presetName; - protoMode.description = t(tooltipTitleID, { feature: '' + presetName + '' }); - - var totalIndex = favoritesCount + index; - var keyCode; - // use number row order: 1 2 3 4 5 6 7 8 9 0 - // use the same for RTL even though the layout is backward: #6107 - if (totalIndex === 9) { - keyCode = 0; - } else if (totalIndex < 10) { - keyCode = totalIndex + 1; - } - if (keyCode !== undefined) { - protoMode.key = keyCode.toString(); - } - - var mode; - switch (d.geometry) { - case 'point': - case 'vertex': - mode = modeAddPoint(context, protoMode); - break; - case 'line': - mode = modeAddLine(context, protoMode); - break; - case 'area': - mode = modeAddArea(context, protoMode); - } - - if (mode.key) { - context.keybinding().off(mode.key); - context.keybinding().on(mode.key, function() { - toggleMode(mode); - }); - } - - return mode; - }); - - var buttons = selection.selectAll('button.add-button') - .data(modes, function(d, index) { return d.button + index; }); - - // exit - buttons.exit() - .remove(); - - // enter - var buttonsEnter = buttons.enter() - .append('button') - .attr('tabindex', -1) - .attr('class', function(d) { - return d.button + ' add-button bar-button'; - }) - .on('click.mode-buttons', function(d) { - - // When drawing, ignore accidental clicks on mode buttons - #4042 - if (/^draw/.test(context.mode().id)) return; - - toggleMode(d); - }) - .call(tooltip() - .placement('bottom') - .html(true) - .title(function(d) { return uiTooltipHtml(d.description, d.key); }) - .scrollContainer(d3_select('#bar')) - ); - - buttonsEnter - .each(function(d) { - d3_select(this) - .call(uiPresetIcon(context) - .geometry((d.geometry === 'point' && !d.preset.matchGeometry(d.geometry)) ? 'vertex' : d.geometry) - .preset(d.preset) - .sizeClass('small') - ); - }); - - var dragOrigin, dragMoved, targetIndex, targetData; - - buttonsEnter.call(d3_drag() - .on('start', function() { - dragOrigin = { - x: d3_event.x, - y: d3_event.y - }; - targetIndex = null; - targetData = null; - dragMoved = false; - }) - .on('drag', function(d, index) { - dragMoved = true; - var x = d3_event.x - dragOrigin.x, - y = d3_event.y - dragOrigin.y; - - if (!d3_select(this).classed('dragging') && - // don't display drag until dragging beyond a distance threshold - Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return; - - d3_select(this) - .classed('dragging', true) - .classed('removing', y > 50); - - targetIndex = null; - targetData = null; - - selection.selectAll('button.add-preset') - .style('transform', function(d2, index2) { - var node = d3_select(this).node(); - if (index === index2) { - return 'translate(' + x + 'px, ' + y + 'px)'; - } else if (y > 50) { - if (index2 > index) { - return 'translateX(' + (textDirection === 'rtl' ? '' : '-') + '100%)'; - } - } else if (d.source === d2.source) { - if (index2 > index && ( - (d3_event.x > node.offsetLeft && textDirection === 'ltr') || - (d3_event.x < node.offsetLeft + node.offsetWidth && textDirection === 'rtl') - )) { - if (targetIndex === null || index2 > targetIndex) { - targetIndex = index2; - targetData = d2; - } - return 'translateX(' + (textDirection === 'rtl' ? '' : '-') + '100%)'; - } else if (index2 < index && ( - (d3_event.x < node.offsetLeft + node.offsetWidth && textDirection === 'ltr') || - (d3_event.x > node.offsetLeft && textDirection === 'rtl') - )) { - if (targetIndex === null || index2 < targetIndex) { - targetIndex = index2; - targetData = d2; - } - return 'translateX(' + (textDirection === 'rtl' ? '-' : '') + '100%)'; - } - } - return null; - }); - }) - .on('end', function(d) { - - if (dragMoved && !d3_select(this).classed('dragging')) { - toggleMode(d); - return; - } - - d3_select(this) - .classed('dragging', false) - .classed('removing', false); - - selection.selectAll('button.add-preset') - .style('transform', null); - - var y = d3_event.y - dragOrigin.y; - if (y > 50) { - // dragged out of the top bar, remove - if (d.isRecent()) { - context.presets().removeRecent(d.preset, d.geometry); - } - } else if (targetIndex !== null) { - // dragged to a new position, reorder - if (d.isRecent()) { - var item = context.presets().recentMatching(d.preset, d.geometry); - var beforeItem = context.presets().recentMatching(targetData.preset, targetData.geometry); - context.presets().moveRecent(item, beforeItem); - } - } - }) - ); - - // update - buttons = buttons - .merge(buttonsEnter) - .classed('disabled', function(d) { return !enabled(d); }); - } - }; - - tool.uninstall = function() { - - context - .on('enter.editor.recent', null) - .on('exit.editor.recent', null) - .on('enter.recent', null); - - context.presets() - .on('favoritePreset.recent', null) - .on('recentsChange.recent', null); - - context.map() - .on('move.recent', null) - .on('drawn.recent', null); - }; - - return tool; -} diff --git a/modules/ui/tools/index.js b/modules/ui/tools/index.js index b8ff9aaa5..023bed85e 100644 --- a/modules/ui/tools/index.js +++ b/modules/ui/tools/index.js @@ -1,8 +1,5 @@ -export * from './add_favorite'; -export * from './add_recent'; export * from './modes'; export * from './notes'; export * from './save'; -export * from './search_add'; export * from './sidebar_toggle'; export * from './undo_redo'; diff --git a/modules/ui/tools/search_add.js b/modules/ui/tools/search_add.js deleted file mode 100644 index 1271ac616..000000000 --- a/modules/ui/tools/search_add.js +++ /dev/null @@ -1,655 +0,0 @@ -import _debounce from 'lodash-es/debounce'; - -import { dispatch as d3_dispatch } from 'd3-dispatch'; -import { - event as d3_event, - select as d3_select, - selectAll as d3_selectAll -} from 'd3-selection'; - -import { modeAddArea, modeAddLine, modeAddPoint } from '../../modes'; -import { t, textDirection } from '../../util/locale'; -import { svgIcon } from '../../svg/index'; -import { tooltip } from '../../util/tooltip'; -import { uiTagReference } from '../tag_reference'; -import { uiTooltipHtml } from '../tooltipHtml'; -import { uiPresetFavoriteButton } from '../preset_favorite_button'; -import { uiPresetIcon } from '../preset_icon'; -import { utilKeybinding, utilNoAuto, utilRebind } from '../../util'; - - -export function uiToolSearchAdd(context) { - - var tool = { - id: 'search_add', - label: t('inspector.search') - }; - - var dispatch = d3_dispatch('choose'); - var presets; - var searchWrap = d3_select(null), - search = d3_select(null), - popover = d3_select(null), - popoverContent = d3_select(null), - list = d3_select(null), - footer = d3_select(null), - message = d3_select(null); - - var allowedGeometry = ['area', 'line', 'point', 'vertex']; - var shownGeometry = []; - var key = t('modes.add_feature.key'); - - function updateShownGeometry(geom) { - shownGeometry = geom.sort(); - presets = context.presets().matchAnyGeometry(shownGeometry); - } - - function toggleShownGeometry(d) { - var geom = shownGeometry; - var index = geom.indexOf(d); - if (index === -1) { - geom.push(d); - if (d === 'point') geom.push('vertex'); - } else { - geom.splice(index, 1); - if (d === 'point') geom.splice(geom.indexOf('vertex'), 1); - } - updateShownGeometry(geom); - } - - function updateFilterButtonsStates() { - footer.selectAll('button.filter') - .classed('active', function(d) { - return shownGeometry.indexOf(d) !== -1; - }); - } - - - tool.render = function(selection) { - updateShownGeometry(allowedGeometry.slice()); // shallow copy - - searchWrap = selection - .append('div') - .attr('class', 'search-wrap') - .call(tooltip() - .placement('bottom') - .html(true) - .title(function() { return uiTooltipHtml(t('modes.add_feature.description'), key); }) - .scrollContainer(d3_select('#bar')) - ); - - search = searchWrap - .append('input') - .attr('class', 'search-input') - .attr('placeholder', t('modes.add_feature.title')) - .attr('type', 'search') - .call(utilNoAuto) - .on('mousedown', function() { - search.attr('clicking', true); - }) - .on('mouseup', function() { - search.attr('clicking', null); - }) - .on('focus', function() { - searchWrap.classed('focused', true); - if (search.attr('clicking')) { - search.attr('focusing', true); - search.attr('clicking', null); - } else { - search.node().setSelectionRange(0, search.property('value').length); - } - popover.classed('hide', false); - }) - .on('blur', function() { - searchWrap.classed('focused', false); - popover.classed('hide', true); - }) - .on('click', function() { - if (search.attr('focusing')) { - search.node().setSelectionRange(0, search.property('value').length); - search.attr('focusing', null); - } - }) - .on('keypress', keypress) - .on('keydown', keydown) - .on('input', updateResultsList); - - searchWrap - .call(svgIcon('#iD-icon-search', 'search-icon pre-text')); - - popover = searchWrap - .append('div') - .attr('class', 'popover fillL hide') - .on('mousedown', function() { - // don't blur the search input (and thus close results) - d3_event.preventDefault(); - d3_event.stopPropagation(); - }); - - popoverContent = popover - .append('div') - .attr('class', 'popover-content'); - - list = popoverContent.append('div') - .attr('class', 'list'); - - footer = popover - .append('div') - .attr('class', 'popover-footer'); - - message = footer.append('div') - .attr('class', 'message'); - - footer.append('div') - .attr('class', 'filter-wrap') - .selectAll('button.filter') - .data(['point', 'line', 'area']) - .enter() - .append('button') - .attr('class', 'filter active') - .attr('title', function(d) { - return t('modes.add_' + d + '.filter_tooltip'); - }) - .each(function(d) { - d3_select(this).call(svgIcon('#iD-icon-' + d)); - }) - .on('click', function(d) { - toggleShownGeometry(d); - if (shownGeometry.length === 0) { - updateShownGeometry(allowedGeometry.slice()); // shallow copy - toggleShownGeometry(d); - } - updateFilterButtonsStates(); - updateResultsList(); - }); - - context.features() - .on('change.search-add', updateForFeatureHiddenState); - - context.keybinding().on(key, function() { - search.node().focus(); - d3_event.preventDefault(); - d3_event.stopPropagation(); - }); - - var debouncedUpdate = _debounce(updateEnabledState, 500, { leading: true, trailing: true }); - - context.map() - .on('move.search-add', debouncedUpdate) - .on('drawn.search-add', debouncedUpdate); - - updateEnabledState(); - - updateResultsList(); - }; - - tool.uninstall = function() { - context.keybinding().off(key); - - context.features() - .on('change.search-add', null); - - context.map() - .on('move.search-add', null) - .on('drawn.search-add', null); - }; - - function osmEditable() { - return context.editable(); - } - - function updateEnabledState() { - var isEnabled = osmEditable(); - searchWrap.classed('disabled', !isEnabled); - if (!isEnabled) { - search.node().blur(); - } - search.attr('disabled', isEnabled ? null : true); - } - - function keypress() { - if (d3_event.keyCode === utilKeybinding.keyCodes.enter) { - popover.selectAll('.list .list-item.focused button.choose') - .each(function(d) { d.choose.call(this); }); - d3_event.preventDefault(); - d3_event.stopPropagation(); - } - } - - function keydown() { - - var nextFocus, - priorFocus, - parentSubsection; - if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] || - d3_event.keyCode === utilKeybinding.keyCodes.tab && !d3_event.shiftKey) { - d3_event.preventDefault(); - d3_event.stopPropagation(); - - priorFocus = popover.selectAll('.list .list-item.focused'); - if (priorFocus.empty()) { - nextFocus = popover.selectAll('.list > .list-item:first-child'); - } else { - nextFocus = d3_select(priorFocus.nodes()[0].nextElementSibling); - if (!nextFocus.empty() && !nextFocus.classed('list-item')) { - nextFocus = nextFocus.selectAll('.list-item:first-child'); - } - if (nextFocus.empty()) { - parentSubsection = priorFocus.nodes()[0].closest('.list .subsection'); - if (parentSubsection && parentSubsection.nextElementSibling) { - nextFocus = d3_select(parentSubsection.nextElementSibling); - } - } - } - if (!nextFocus.empty()) { - focusListItem(nextFocus, true); - priorFocus.classed('focused', false); - } - - } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑'] || - d3_event.keyCode === utilKeybinding.keyCodes.tab && d3_event.shiftKey) { - d3_event.preventDefault(); - d3_event.stopPropagation(); - - priorFocus = popover.selectAll('.list .list-item.focused'); - if (!priorFocus.empty()) { - - nextFocus = d3_select(priorFocus.nodes()[0].previousElementSibling); - if (!nextFocus.empty() && !nextFocus.classed('list-item')) { - nextFocus = nextFocus.selectAll('.list-item:last-child'); - } - if (nextFocus.empty()) { - parentSubsection = priorFocus.nodes()[0].closest('.list .subsection'); - if (parentSubsection && parentSubsection.previousElementSibling) { - nextFocus = d3_select(parentSubsection.previousElementSibling); - } - } - if (!nextFocus.empty()) { - focusListItem(nextFocus, true); - priorFocus.classed('focused', false); - } - } - } else if (d3_event.keyCode === utilKeybinding.keyCodes.esc) { - search.node().blur(); - d3_event.preventDefault(); - d3_event.stopPropagation(); - } - } - - function updateResultsList() { - - var value = search.property('value'); - var results; - if (value.length) { - results = presets.search(value, shownGeometry).collection; - } else { - var recents = context.presets().getRecents(); - recents = recents.filter(function(d) { - return shownGeometry.indexOf(d.geometry) !== -1; - }); - results = recents.slice(0, 35); - } - - list.call(drawList, results); - - popover.selectAll('.list .list-item.focused') - .classed('focused', false); - focusListItem(popover.selectAll('.list > .list-item:first-child'), false); - - popoverContent.node().scrollTop = 0; - - var resultCount = results.length; - message.text(t('modes.add_feature.' + (resultCount === 1 ? 'result' : 'results'), { count: resultCount })); - } - - function focusListItem(selection, scrollingToShow) { - if (!selection.empty()) { - selection.classed('focused', true); - if (scrollingToShow) { - // scroll to keep the focused item visible - scrollPopoverToShow(selection); - } - } - } - - function scrollPopoverToShow(selection) { - if (selection.empty()) return; - - var node = selection.nodes()[0]; - var scrollableNode = popoverContent.node(); - - if (node.offsetTop < scrollableNode.scrollTop) { - scrollableNode.scrollTop = node.offsetTop; - - } else if (node.offsetTop + node.offsetHeight > scrollableNode.scrollTop + scrollableNode.offsetHeight && - node.offsetHeight < scrollableNode.offsetHeight) { - scrollableNode.scrollTop = node.offsetTop + node.offsetHeight - scrollableNode.offsetHeight; - } - } - - function itemForPreset(preset) { - if (preset.members) { - return CategoryItem(preset); - } - if (preset.preset && preset.geometry) { - return AddablePresetItem(preset.preset, preset.geometry); - } - var supportedGeometry = preset.geometry.filter(function(geometry) { - return shownGeometry.indexOf(geometry) !== -1; - }).sort(); - var vertexIndex = supportedGeometry.indexOf('vertex'); - if (vertexIndex !== -1 && supportedGeometry.indexOf('point') !== -1) { - // both point and vertex allowed, just show point - supportedGeometry.splice(vertexIndex, 1); - } - if (supportedGeometry.length === 1) { - return AddablePresetItem(preset, supportedGeometry[0]); - } - return MultiGeometryPresetItem(preset, supportedGeometry); - } - - function drawList(list, data) { - - list.selectAll('.subsection.subitems').remove(); - - var dataItems = []; - for (var i = 0; i < data.length; i++) { - var preset = data[i]; - if (i < data.length - 1) { - var nextPreset = data[i+1]; - // group neighboring presets with the same name - if (preset.name && nextPreset.name && preset.name() === nextPreset.name()) { - var groupedPresets = [preset, nextPreset].sort(function(p1, p2) { - return (p1.geometry[0] < p2.geometry[0]) ? -1 : 1; - }); - dataItems.push(MultiPresetItem(groupedPresets)); - i++; // skip the next preset since we accounted for it - continue; - } - } - dataItems.push(itemForPreset(preset)); - } - - var items = list.selectAll('.list-item') - .data(dataItems, function(d) { return d.id(); }); - - items.order(); - - items.exit() - .remove(); - - drawItems(items.enter()); - - list.selectAll('.list-item.expanded') - .classed('expanded', false) - .selectAll('.label svg.icon use') - .attr('href', textDirection === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'); - - updateForFeatureHiddenState(); - } - - function drawItems(selection) { - - var item = selection - .append('div') - .attr('class', 'list-item') - .attr('id', function(d) { - return 'search-add-list-item-preset-' + d.id().replace(/[^a-zA-Z\d:]/g, '-'); - }) - .on('mouseover', function() { - list.selectAll('.list-item.focused') - .classed('focused', false); - d3_select(this) - .classed('focused', true); - }) - .on('mouseout', function() { - d3_select(this) - .classed('focused', false); - }); - - var row = item.append('div') - .attr('class', 'row'); - - row.append('button') - .attr('class', 'choose') - .on('click', function(d) { - d.choose.call(this); - }); - - row.each(function(d) { - d3_select(this).call( - uiPresetIcon(context) - .geometry(d.geometry) - .preset(d.preset || d.presets[0]) - .sizeClass('small') - ); - }); - var label = row.append('div') - .attr('class', 'label'); - - label.each(function(d) { - if (d.subitems) { - d3_select(this) - .call(svgIcon((textDirection === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'), 'inline')); - } - }); - - label.each(function(d) { - // NOTE: split/join on en-dash, not a hypen (to avoid conflict with fr - nl names in Brussels etc) - d3_select(this) - .append('div') - .attr('class', 'label-inner') - .selectAll('.namepart') - .data(d.name().split(' – ')) - .enter() - .append('div') - .attr('class', 'namepart') - .text(function(d) { return d; }); - }); - - row.each(function(d) { - if (d.geometry) { - var presetFavorite = uiPresetFavoriteButton(d.preset, d.geometry, context, 'accessory'); - d3_select(this).call(presetFavorite.button); - } - }); - item.each(function(d) { - if ((d.geometry && (!d.isSubitem || d.isInNameGroup)) || d.geometries) { - - var reference = uiTagReference(d.preset.reference(d.geometry || d.geometries[0]), context); - - var thisItem = d3_select(this); - thisItem.selectAll('.row').call(reference.button, 'accessory', 'info'); - - var subsection = thisItem - .append('div') - .attr('class', 'subsection reference'); - subsection.call(reference.body); - } - }); - } - - function updateForFeatureHiddenState() { - - var listItem = d3_selectAll('.search-add .popover .list-item'); - - // remove existing tooltips - listItem.selectAll('button.choose').call(tooltip().destroyAny); - - listItem.each(function(item, index) { - if (!item.geometry) return; - - var hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, item.geometry); - var isHiddenPreset = !!hiddenPresetFeaturesId; - - var button = d3_select(this).selectAll('button.choose'); - - d3_select(this).classed('disabled', isHiddenPreset); - button.classed('disabled', isHiddenPreset); - - if (isHiddenPreset) { - var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId); - var tooltipIdSuffix = isAutoHidden ? 'zoom' : 'manual'; - var tooltipObj = { features: t('feature.' + hiddenPresetFeaturesId + '.description') }; - button.call(tooltip('dark') - .html(true) - .title(t('inspector.hidden_preset.' + tooltipIdSuffix, tooltipObj)) - .placement(index < 2 ? 'bottom' : 'top') - ); - } - }); - } - - function chooseExpandable(item, itemSelection) { - - var shouldExpand = !itemSelection.classed('expanded'); - - itemSelection.classed('expanded', shouldExpand); - - var iconName = shouldExpand ? - '#iD-icon-down' : (textDirection === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'); - itemSelection.selectAll('.label svg.icon use') - .attr('href', iconName); - - if (shouldExpand) { - var subitems = item.subitems(); - var selector = '#' + itemSelection.node().id + ' + *'; - item.subsection = d3_select(itemSelection.node().parentNode).insert('div', selector) - .attr('class', 'subsection subitems'); - var subitemsEnter = item.subsection.selectAll('.list-item') - .data(subitems) - .enter(); - drawItems(subitemsEnter); - updateForFeatureHiddenState(); - scrollPopoverToShow(item.subsection); - } else { - item.subsection.remove(); - } - } - - function CategoryItem(preset) { - var item = {}; - item.id = function() { - return preset.id; - }; - item.name = function() { - return preset.name(); - }; - item.subsection = d3_select(null); - item.preset = preset; - item.choose = function() { - var selection = d3_select(this); - if (selection.classed('disabled')) return; - chooseExpandable(item, d3_select(selection.node().closest('.list-item'))); - }; - item.subitems = function() { - return preset.members.matchAnyGeometry(shownGeometry).collection.map(function(preset) { - return itemForPreset(preset); - }); - }; - return item; - } - - function MultiPresetItem(presets) { - var item = {}; - item.id = function() { - return presets.map(function(preset) { return preset.id; }).join(); - }; - item.name = function() { - return presets[0].name(); - }; - item.subsection = d3_select(null); - item.presets = presets; - item.choose = function() { - var selection = d3_select(this); - if (selection.classed('disabled')) return; - chooseExpandable(item, d3_select(selection.node().closest('.list-item'))); - }; - item.subitems = function() { - var items = []; - presets.forEach(function(preset) { - preset.geometry.filter(function(geometry) { - return shownGeometry.indexOf(geometry) !== -1; - }).forEach(function(geometry) { - items.push(AddablePresetItem(preset, geometry, true, true)); - }); - }); - return items; - }; - return item; - } - - function MultiGeometryPresetItem(preset, geometries) { - - var item = {}; - item.id = function() { - return preset.id + geometries; - }; - item.name = function() { - return preset.name(); - }; - item.subsection = d3_select(null); - item.preset = preset; - item.geometries = geometries; - item.choose = function() { - var selection = d3_select(this); - if (selection.classed('disabled')) return; - chooseExpandable(item, d3_select(selection.node().closest('.list-item'))); - }; - item.subitems = function() { - return geometries.map(function(geometry) { - return AddablePresetItem(preset, geometry, true); - }); - }; - return item; - } - - function AddablePresetItem(preset, geometry, isSubitem, isInNameGroup) { - var item = {}; - item.id = function() { - return preset.id + geometry + isSubitem; - }; - item.name = function() { - if (isSubitem) { - if (preset.setTags({}, geometry).building) { - return t('presets.presets.building.name'); - } - return t('modes.add_' + context.presets().fallback(geometry).id + '.title'); - } - return preset.name(); - }; - item.isInNameGroup = isInNameGroup; - item.isSubitem = isSubitem; - item.preset = preset; - item.geometry = geometry; - item.choose = function() { - if (d3_select(this).classed('disabled')) return; - - var markerClass = 'add-preset add-' + geometry + - ' add-preset-' + preset.name().replace(/\s+/g, '_') + '-' + geometry; - var modeInfo = { - button: markerClass, - preset: preset, - geometry: geometry - }; - var mode; - switch (geometry) { - case 'point': - case 'vertex': - mode = modeAddPoint(context, modeInfo); - break; - case 'line': - mode = modeAddLine(context, modeInfo); - break; - case 'area': - mode = modeAddArea(context, modeInfo); - } - search.node().blur(); - context.presets().setMostRecent(preset, geometry); - context.enter(mode); - }; - return item; - } - - return utilRebind(tool, dispatch, 'on'); -} diff --git a/modules/ui/top_toolbar.js b/modules/ui/top_toolbar.js index 514d3d095..ce16fe658 100644 --- a/modules/ui/top_toolbar.js +++ b/modules/ui/top_toolbar.js @@ -5,16 +5,13 @@ import { } from 'd3-selection'; import _debounce from 'lodash-es/debounce'; -import { /*uiToolAddFavorite, uiToolAddRecent, uiToolSearchAdd, */ uiToolOldDrawModes, uiToolNotes, uiToolSave, uiToolSidebarToggle, uiToolUndoRedo } from './tools'; +import { uiToolOldDrawModes, uiToolNotes, uiToolSave, uiToolSidebarToggle, uiToolUndoRedo } from './tools'; export function uiTopToolbar(context) { var sidebarToggle = uiToolSidebarToggle(context), modes = uiToolOldDrawModes(context), - //searchAdd = uiToolSearchAdd(context), - //addFavorite = uiToolAddFavorite(context), - //addRecent = uiToolAddRecent(context), notes = uiToolNotes(context), undoRedo = uiToolUndoRedo(context), save = uiToolSave(context); @@ -50,16 +47,7 @@ export function uiTopToolbar(context) { sidebarToggle, 'spacer', modes - // searchAdd ]; - /* - if (context.presets().getFavorites().length > 0) { - tools.push(addFavorite); - } - - if (addRecent.shouldShow()) { - tools.push(addRecent); - }*/ tools.push('spacer');