diff --git a/modules/ui/init.js b/modules/ui/init.js index 27fbf56f7..8845d6f40 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -26,6 +26,7 @@ import { uiLoading } from './loading'; import { uiMapData } from './map_data'; import { uiMapInMap } from './map_in_map'; import { uiModes } from './modes'; +import { uiNotes } from './notes'; import { uiNotice } from './notice'; import { uiPhotoviewer } from './photoviewer'; import { uiRestore } from './restore'; @@ -123,6 +124,10 @@ export function uiInit(context) { .attr('class', 'modes joined') .call(uiModes(context), bar); + centerArea.append('div') + .attr('class', 'notes') + .call(uiNotes(context), bar); + // Trailing area button group (Undo/Redo save buttons) var trailingArea = bar diff --git a/modules/ui/modes.js b/modules/ui/modes.js index 111b04578..e3a6b3b6c 100644 --- a/modules/ui/modes.js +++ b/modules/ui/modes.js @@ -6,7 +6,6 @@ import { modeAddArea, modeAddLine, modeAddPoint, - modeAddNote, modeBrowse } from '../modes'; @@ -20,17 +19,12 @@ export function uiModes(context) { var modes = [ modeAddPoint(context), modeAddLine(context), - modeAddArea(context), - modeAddNote(context) + modeAddArea(context) ]; - function enabled(d) { - if (d.id === 'add-note') { - return notesEnabled() && notesEditable(); - } else { - return osmEditable(); - } + function enabled() { + return osmEditable(); } function osmEditable() { @@ -38,16 +32,6 @@ export function uiModes(context) { return context.editable() && mode && mode.id !== 'save'; } - function notesEnabled() { - var noteLayer = context.layers().layer('notes'); - return noteLayer && noteLayer.enabled(); - } - - function notesEditable() { - var mode = context.mode(); - return context.map().notesEditable() && mode && mode.id !== 'save'; - } - return function(selection) { context @@ -91,8 +75,7 @@ export function uiModes(context) { function update() { - var showNotes = notesEnabled(); - var data = showNotes ? modes : modes.slice(0, 3); + var data = modes; // add favorite presets to modes var favoritePresets = context.getFavoritePresets(); diff --git a/modules/ui/notes.js b/modules/ui/notes.js new file mode 100644 index 000000000..45a2d62be --- /dev/null +++ b/modules/ui/notes.js @@ -0,0 +1,128 @@ +import _debounce from 'lodash-es/debounce'; + +import { select as d3_select } from 'd3-selection'; + +import { + modeAddNote, + modeBrowse +} from '../modes'; + +import { svgIcon } from '../svg'; +import { tooltip } from '../util/tooltip'; +import { uiTooltipHtml } from './tooltipHtml'; + +export function uiNotes(context) { + + var mode = modeAddNote(context); + + function enabled() { + return notesEnabled() && notesEditable(); + } + + function notesEnabled() { + var noteLayer = context.layers().layer('notes'); + return noteLayer && noteLayer.enabled(); + } + + function notesEditable() { + var mode = context.mode(); + return context.map().notesEditable() && mode && mode.id !== 'save'; + } + + + return function(selection) { + context + .on('enter.editor.notes', 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.notes', function(exited) { + context.container() + .classed('mode-' + exited.id, false); + }); + + context.keybinding().on(mode.key, function() { + if (!enabled(mode)) return; + + if (mode.id === context.mode().id) { + context.enter(modeBrowse(context)); + } else { + context.enter(mode); + } + }); + + + var debouncedUpdate = _debounce(update, 500, { leading: true, trailing: true }); + + context.map() + .on('move.notes', debouncedUpdate) + .on('drawn.notes', debouncedUpdate); + + context + .on('enter.notes', update); + + update(); + + + function update() { + var showNotes = notesEnabled(); + var data = showNotes ? [mode] : []; + + var buttons = selection.selectAll('button.add-button') + .data(data, function(d) { return d.id; }); + + // exit + buttons.exit() + .remove(); + + // enter + var buttonsEnter = buttons.enter() + .append('button') + .attr('tabindex', -1) + .attr('class', function(d) { return d.id + ' add-button bar-button'; }) + .on('click.notes', function(d) { + if (!enabled(d)) return; + + // When drawing, ignore accidental clicks on mode buttons - #4042 + var currMode = context.mode().id; + if (/^draw/.test(currMode)) return; + + if (d.id === currMode) { + context.enter(modeBrowse(context)); + } else { + context.enter(d); + } + }) + .call(tooltip() + .placement('bottom') + .html(true) + .title(function(d) { return uiTooltipHtml(d.description, d.key); }) + ); + + buttonsEnter + .each(function(d) { + d3_select(this) + .call(svgIcon(d.icon || '#iD-icon-' + d.button)); + }); + + buttonsEnter + .append('span') + .attr('class', 'label') + .text(function(mode) { return mode.title; }); + + // if we are adding/removing the buttons, check if toolbar has overflowed + if (buttons.enter().size() || buttons.exit().size()) { + context.ui().checkOverflow('#bar', true); + } + + // update + buttons = buttons + .merge(buttonsEnter) + .classed('disabled', function(d) { return !enabled(d); }); + } + }; +}