From 91add0c33e7b72e2027ac5c68e54f7d6037d55de Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 11 Jul 2018 23:10:01 -0400 Subject: [PATCH] WIP on buttons, simplify, remove some event dispatch - I made the buttons work like GitHub comment-on-issue buttons before typing: "Close Note" / "Comment" (disabled) after typing: "Close and Comment" / "Comment" (enabled) - I removed a bunch of the event dispatches. These are useful for sending events to listeners/observers outside of the module. In this case I think we can handle most of the things from within the uiNoteEditor. We can still dispatch an 'update' event so that modeSelectNote can reselect and redraw the note after some change happens to it. TODO - make the buttons work / check the OSM API stuff. --- css/65_data.css | 2 +- data/core.yaml | 10 +- dist/locales/en.json | 10 +- modules/modes/select_note.js | 2 +- modules/ui/note_comments.js | 6 +- modules/ui/note_editor.js | 349 +++++++++++++++-------------------- 6 files changed, 159 insertions(+), 220 deletions(-) diff --git a/css/65_data.css b/css/65_data.css index 0be1ab163..4491570d7 100644 --- a/css/65_data.css +++ b/css/65_data.css @@ -76,7 +76,7 @@ .note-header-label { background-color: #f6f6f6; - padding: 0 10px; + padding: 0 15px; flex: 1 1 100%; font-size: 14px; font-weight: bold; diff --git a/data/core.yaml b/data/core.yaml index ecb21897c..58993ea84 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -616,15 +616,13 @@ en: anonymous: anonymous closed: "(Closed)" commentTitle: Comments - close: Resolve - reopen: Reopen newComment: New Comment inputPlaceholder: Enter a comment to share with other users. + close: Close Note + open: Reopen Note comment: Comment - commentClose: Comment & Resolve - commentReopen: Comment & Reopen - save: Save comment - cancel: Cancel + close_comment: Close and Comment + open_comment: Reopen and Comment help: title: Help key: H diff --git a/dist/locales/en.json b/dist/locales/en.json index 7b6591fa1..7c28239bc 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -749,15 +749,13 @@ "anonymous": "anonymous", "closed": "(Closed)", "commentTitle": "Comments", - "close": "Resolve", - "reopen": "Reopen", "newComment": "New Comment", "inputPlaceholder": "Enter a comment to share with other users.", + "close": "Close Note", + "open": "Reopen Note", "comment": "Comment", - "commentClose": "Comment & Resolve", - "commentReopen": "Comment & Reopen", - "save": "Save comment", - "cancel": "Cancel" + "close_comment": "Close and Comment", + "open_comment": "Reopen and Comment" }, "help": { "title": "Help", diff --git a/modules/modes/select_note.js b/modules/modes/select_note.js index b9cf872d9..a35f087ac 100644 --- a/modules/modes/select_note.js +++ b/modules/modes/select_note.js @@ -25,7 +25,7 @@ export function modeSelectNote(context, selectedNoteID) { var osm = services.osm; var keybinding = d3_keybinding('select-note'); var noteEditor = uiNoteEditor(context) - .on('updateNote', function() { + .on('update', function() { // .call(drawNotes); // TODO: update and redraw notes var note = checkSelectedID(); if (!note) return; diff --git a/modules/ui/note_comments.js b/modules/ui/note_comments.js index 503f4a44d..4154f8941 100644 --- a/modules/ui/note_comments.js +++ b/modules/ui/note_comments.js @@ -1,7 +1,4 @@ -import { - event as d3_event, - select as d3_select -} from 'd3-selection'; +import { select as d3_select } from 'd3-selection'; import { t } from '../util/locale'; import { svgIcon } from '../svg'; @@ -10,7 +7,6 @@ import { utilDetect } from '../util/detect'; export function uiNoteComments() { - var commentLimit = 600; // add a "more" link to comments longer than this length var _note; diff --git a/modules/ui/note_editor.js b/modules/ui/note_editor.js index 7e68df82c..ce15d8832 100644 --- a/modules/ui/note_editor.js +++ b/modules/ui/note_editor.js @@ -6,7 +6,6 @@ import { } from 'd3-selection'; import { t } from '../util/locale'; -import { svgIcon } from '../svg'; import { services } from '../services'; import { uiNoteComments } from './note_comments'; @@ -17,213 +16,15 @@ import { utilRebind } from '../util'; -import { utilDetect } from '../util/detect'; -import { modeBrowse } from '../modes'; - export function uiNoteEditor(context) { - // TODO: use 'toggleNote' and 'saveNote' to add 'thank you' warning to the sidebar - var dispatch = d3_dispatch('change', 'cancel', 'save', 'modifiedInput', 'updateNote', 'toggleNote', 'saveNote'); + var dispatch = d3_dispatch('update'); var noteHeader = uiNoteHeader(); var noteComments = uiNoteComments(); - var _inputValue; - var _newComment; var _note; - var _modified; function noteEditor(selection) { - render(selection); - } - - function cancel() { - _newComment = false; - context.selectedNoteID(null); - context.enter(modeBrowse(context)); - } - - function save(updateFunction) { - var osm = context.connection(); - if (!osm) { - context.enter(modeBrowse(context)); - return; - } - - // If user somehow got logged out mid-save, try to reauthenticate.. - // This can happen if they were logged in from before, but the tokens are no longer valid. - if (!osm.authenticated()) { - - // TODO: dispatch 'notAuthenticated' to give warning - - osm.authenticate(function(err) { - if (err) { // quit save mode.. - context.enter(modeBrowse(context)); - return; - } else { - save(updateFunction); // continue where we left off.. - } - }); - return; - } - - function parseResults(results) { // TODO: simplify result parsing - dispatch.call('change', results); - - // call success - if (results) { - success(results); - } - // otherwise, call failure - else { - failure(results); - } - } - - function success(results) { - console.log('success!', results); // TODO: handle success - dispatch.apply('updateNote'); - } - - function failure(results) { // TODO: handle failure & errors - console.log('failure!', results); - } - - updateFunction(parseResults); - } - - - function toggleNoteStatus(parseResults) { - if (!_note || !_note.status || !context.selectedNoteID) return; - services.osm.toggleNoteStatus(_note, _inputValue, parseResults); - } - - - function addNoteComment(parseResults) { - if (!_note || !_note.status || !context.selectedNoteID) return; - services.osm.addNoteComment(_note, _inputValue, parseResults); - } - - - function newComment(selection) { - if (!context.selectedNoteID()) return; - // New Comment - var saveSection = selection.selectAll('.save-section') - .data([0]); - - saveSection = saveSection.enter() - .append('div') - .attr('class','save-section cf') - .merge(saveSection); - - saveSection - .call(saveHeader) - .call(input) - .call(buttons); - } - - - function saveHeader(selection) { - var header = selection.selectAll('.notesSaveHeader') - .data([0]); - - header.enter() - .append('h4') - .attr('class', '.notesSaveHeader') - .text(t('note.newComment')) - .merge(header); - } - - - function input(selection) { - var input = selection.selectAll('textarea') - .data([0]); - - input.enter() - .append('textarea') - .attr('id', 'new-comment-input') - .attr('placeholder', t('note.inputPlaceholder')) - .attr('maxlength', 1000) - .call(utilNoAuto) - .on('input', change) - .on('blur', change) - .merge(input); - - - function change() { - _inputValue = this.value; - console.log(_inputValue); - dispatch.apply('modifiedInput'); - } - } - - - function buttons(selection) { - // Buttons - var buttonSection = selection.selectAll('.buttons') - .data([0]); - - // enter - var buttonEnter = buttonSection.enter() - .append('div') - .attr('class', 'buttons cf'); - - buttonEnter - .append('button') - .attr('class', 'secondary-action button cancel-button') - .append('span') - .attr('class', 'label') - .text(t('note.cancel')); - - buttonEnter - .append('button') - .attr('class', 'action button save-button') - .append('span') - .attr('class', 'label') - .text(t('note.save')); - - var status; - if (_note.status) { - status = _note.status === 'open' ? t('note.close') : t('note.reopen'); - } - - buttonEnter - .append('button') - .attr('class', _note.status + '-button status-button action button') - .append('span') - .attr('class', 'label') - .text(status); - - - // update - buttonSection = buttonSection - .merge(buttonEnter); - - buttonSection.selectAll('.closed-button,.open-button') - .on('click', function() { - save(toggleNoteStatus); - dispatch.apply('toggleNote', this); // TODO: dispatch toggleNote event - }); - - buttonSection.selectAll('.cancel-button') - .on('click.cancel', cancel); - - buttonSection.selectAll('.save-button') - .attr('disabled', function() { - var n = d3_select('#new-comment-input').node(); - return (n && n.value.length) ? null : true; - }) - .on('modifiedInput', function() { - // TODO: determine how to toggle button on input via triggering 'modifiedInput' event - }) - .on('click.save', function() { - this.blur(); // avoid keeping focus on the button - #4641 - save(addNoteComment); - dispatch.apply('saveNote', this, _newComment); // TODO: dispatch saveNote event - }); - } - - - function render(selection) { var header = selection.selectAll('.header') .data([0]); @@ -249,7 +50,153 @@ export function uiNoteEditor(context) { .attr('class', 'modal-section note-editor') .call(noteHeader.note(_note)) .call(noteComments.note(_note)) - .call(newComment); + .call(noteSave); + } + + + function noteSave(selection) { + var isSelected = (_note && _note.id === context.selectedNoteID()); + var noteSave = selection.selectAll('.note-save-section') + .data((isSelected ? [_note] : []), function(d) { return d.id; }); + + // exit + noteSave.exit() + .remove(); + + // enter + var noteSaveEnter = noteSave.enter() + .append('div') + .attr('class', 'note-save-section save-section cf'); + + noteSaveEnter + .append('h4') + .attr('class', '.note-save-header') + .text(t('note.newComment')); + + noteSaveEnter + .append('textarea') + .attr('id', 'new-comment-input') + .attr('placeholder', t('note.inputPlaceholder')) + .attr('maxlength', 1000) + .call(utilNoAuto) + .on('input', change) + .on('blur', change); + + // update + noteSave = noteSaveEnter + .merge(noteSave); + + change(); + + function change() { + noteSave + .call(noteSaveButtons); + } + } + + + function noteSaveButtons(selection) { + var isSelected = (_note && _note.id === context.selectedNoteID()); + var buttonSection = selection.selectAll('.buttons') + .data((isSelected ? [_note] : []), function(d) { return d.id; }); + + // exit + buttonSection.exit() + .remove(); + + // enter + var buttonEnter = buttonSection.enter() + .append('div') + .attr('class', 'buttons'); + + buttonEnter + .append('button') + .attr('class', 'button status-button action') + .append('span') + .attr('class', 'label'); + + buttonEnter + .append('button') + .attr('class', 'button comment-button action') + .append('span') + .attr('class', 'label') + .text(t('note.comment')); + + // update + buttonSection = buttonSection + .merge(buttonEnter); + + buttonSection.selectAll('.status-button') + .text(function(d) { + var n = d3_select('#new-comment-input').node(); + var setStatus = (d.status === 'open' ? 'close' : 'open'); + var andComment = ((n && n.value.length) ? '_comment' : ''); + return t('note.' + setStatus + andComment); + }) + .on('click.status', function() { + this.blur(); // avoid keeping focus on the button - #4641 + // todo: the thing + }); + + buttonSection.selectAll('.comment-button') + .attr('disabled', function() { + var n = d3_select('#new-comment-input').node(); + return (n && n.value.length) ? null : true; + }) + .on('click.save', function() { + this.blur(); // avoid keeping focus on the button - #4641 + // todo: the thing + }); + } + + + function save() { + // var osm = context.connection(); + // if (!osm) { + // context.enter(modeBrowse(context)); + // return; + // } + + // // If user somehow got logged out mid-save, try to reauthenticate.. + // // This can happen if they were logged in from before, but the tokens are no longer valid. + // if (!osm.authenticated()) { + + // // TODO: dispatch 'notAuthenticated' to give warning + + // osm.authenticate(function(err) { + // if (err) { // quit save mode.. + // context.enter(modeBrowse(context)); + // return; + // } else { + // save(updateFunction); // continue where we left off.. + // } + // }); + // return; + // } + + // function parseResults(results) { // TODO: simplify result parsing + // dispatch.call('change', results); + + // // call success + // if (results) { + // success(results); + // } + // // otherwise, call failure + // else { + // failure(results); + // } + // } + + // function success(results) { + // console.log('success!', results); // TODO: handle success + // dispatch.apply('updateNote'); + // } + + // function failure(results) { // TODO: handle failure & errors + // console.log('failure!', results); + // } + + // updateFunction(parseResults); }