diff --git a/nginx/public_html/App.js b/nginx/public_html/App.js index 2b7721e..95f26d8 100644 --- a/nginx/public_html/App.js +++ b/nginx/public_html/App.js @@ -1,9 +1,10 @@ import Note from './Note.js'; -import {new_note_handler, search_term_change_handler, sorting_change_handler, load_notes, new_bin_handler} from './handlers/App.js'; +import {new_note_handler, search_term_change_handler, sorting_change_handler, load_notes, new_bin_handler, bin_name_change_handler, bin_name_editing_toggle_button_handler, bin_name_commit_handler} from './handlers/App.js'; function App(vnode_init){ const {state, dispatch} = vnode_init.attrs; + const o = function(handler){ return handler.bind(null, state, dispatch); } //load_notes(state, dispatch); return { view: function(vnode){ @@ -11,16 +12,23 @@ function App(vnode_init){ return m('.app', {key: 'app'}, [ m('.top', {key: 'top'}, [ m('.top-left', {key: 'top-left'}, [ - m('button', {key: 'button', onclick: new_note_handler.bind(null, s, dispatch)}, 'New Note...'), - m('input.search', {key: 'search', value: s.search_term, onkeyup: search_term_change_handler.bind(null, s, dispatch)}), - m('select.sorting', {key: 'sorting', value: s.sorting, onchange: sorting_change_handler.bind(null, s, dispatch)}, [ + m('button', {key: 'button', onclick: o(new_note_handler)}, 'New Note...'), + m('input.search', {key: 'search', value: s.search_term, onkeyup: o(search_term_change_handler)}), + m('select.sorting', {key: 'sorting', value: s.sorting, onchange: o(sorting_change_handler)}, [ m('option', {key: 'new->old', value: 'new->old'}, 'Newest -> Oldest'), m('option', {key: 'old->new', value: 'old->new'}, 'Oldest -> Newest') ]) ]), m('.top-right', {key: 'top-right'}, [ - m('.bin-id', {key: 'bin-id'}, s.bin.id), - m('button', {key: 'new-bin-button', onclick: new_bin_handler.bind(null, s, dispatch)}, 'New Bin...') + (s.is_editing_bin_name + ? m('input.bin-name-textbox', {key: 'bin-name-textbox', value: s.temp_bin_name, onchange: o(bin_name_change_handler)}) + : m('.bin-name', {key: 'bin-name'}, s.bin.name) + ), + m('button', {key: 'new-bin-button', onclick: o(new_bin_handler)}, 'New Bin...'), + (s.is_editing_bin_name + ? m('button', {key:'save-bin-name-button', onclick: o(bin_name_commit_handler)}, 'Save') + : m('button', {key:'rename-bin-button', onclick: o(bin_name_editing_toggle_button_handler)}, 'Rename') + ) ]) ]), m('.main', {key: 'main'}, [ diff --git a/nginx/public_html/handlers/App.js b/nginx/public_html/handlers/App.js index 25002be..eed7bac 100644 --- a/nginx/public_html/handlers/App.js +++ b/nginx/public_html/handlers/App.js @@ -34,5 +34,43 @@ const new_bin_handler = function(state, dispatch){ window.history.pushState(null,'','#'+id); dispatch('new-bin', {id}); }; +const username_change_handler = function(state, dispatch, e){ + dispatch('update-username', e.target.value); + }; +const password_change_handler = function(state, dispatch, e){ + dispatch('update-password', e.target.value); + }; +const login_request_handler = function(state, dispatch, e){ + dispatch('login-requested'); + api.post('/login', {username: state.login.username, password: state.login.password}) + .then(res=>{ + if(res.success===true){ + dispatch('login-succeeded', res.user, res.session_id); + } + else{ + dispatch('login-failed'); + } + }); + }; +const bin_name_editing_toggle_button_handler = function(state, dispatch){ + dispatch('update-bin-name-editing', !state.is_editing_bin_name); + }; +const bin_name_change_handler = function(state, dispatch, e){ + dispatch('update-bin-name', e.target.value); + }; +const bin_name_commit_handler = function(state, dispatch){ + dispatch('commit-bin-name'); + }; -export {new_note_handler, search_term_change_handler, sorting_change_handler, load_notes, new_bin_handler}; \ No newline at end of file +export {new_note_handler, + search_term_change_handler, + sorting_change_handler, + load_notes, + new_bin_handler, + username_change_handler, + password_change_handler, + login_request_handler, + bin_name_editing_toggle_button_handler, + bin_name_change_handler, + bin_name_commit_handler + }; \ No newline at end of file diff --git a/nginx/public_html/index.js b/nginx/public_html/index.js index e02ae70..cf733fb 100644 --- a/nginx/public_html/index.js +++ b/nginx/public_html/index.js @@ -1,6 +1,7 @@ import App from './App.js'; import nanoid from './nanoid.min.js'; import {load_bin_handler, hash_change_handler} from './handlers/index.js'; +import {bin, note} from './models.js'; const produce = immer.produce; immer.setAutoFreeze(false); // needed for high-frequency updated values, like onkeyup->note.temp_text; only once 'save' is called will it produce a new immutable state tree @@ -25,7 +26,7 @@ if(bin_id === ''){ const reducer = handleActions({ 'new-bin': (s, bin) => { s.bin=bin; s.notes=[]; }, 'bin-requested': (s, bin_id) => { s.bin={id:bin_id}; s.notes = []; }, - 'bin-loaded': (s, {bin, _notes}) => { s.bin=bin; s.notes=_notes.map(n=>({is_editing: false, temp_text: n.text, bin_id: bin.id, note:n})); }, + 'bin-loaded': (s, {bin, _notes}) => { s.bin=bin; s.temp_bin_name=bin.name; s.notes=_notes.map(n=>({is_editing: false, temp_text: n.text, bin_id: bin.id, note:n})); }, 'update-search-term': (s, search_term) => { s.search_term=search_term; }, 'update-search-results': (s, _notes) => { s.notes =_notes.map(n=>({is_editing: false, temp_text: '', bin_id: s.bin.id, note:n})); }, 'add-note': (s, {id, date}) => { s.notes.unshift({is_editing: true, temp_text: '', bin_id: s.bin.id, is_focused:true, note: {id: id, text: '', modified: date}}); }, @@ -33,14 +34,35 @@ const reducer = handleActions({ 'update-note-text': (s, {id, text}) => { const note_s=s.notes.find(n=>n.note.id===id); note_s.note.text=text; }, // updates underlying note text (i.e. the "model", not the app note_state) "in the background" (e.g. from a server-pushed update), regardless of whether it's being edited; "save" is a separate action, below 'update-note-editing': (s, {id, is_editing}) => { const note_s=s.notes.find(n=>n.note.id===id); note_s.is_editing=is_editing; note_s.temp_text=note_s.note.text; }, 'save-note-edit': (s, {id, text}) => { const note_s=s.notes.find(n=>n.note.id===id); note_s.note.text=text; note_s.temp_text=text; note_s.is_editing=false; }, - 'update-sorting': (s, sorting) => { s.sorting=sorting; } + 'update-sorting': (s, sorting) => { s.sorting=sorting; }, + 'update-username': (s, username) => { s.login.username=username; }, + 'update-password': (s, password) => { s.login.password=password; }, + 'login-requested': (s) => { s.login.showing=false; }, + 'login-succeeded': (s, user, session_id) => { s.login.showing=false; s.login.password=''; s.login.user=user; s.login.session_id=session_id; }, + 'login-failed': (s) => { s.login.showing=true; s.login.password=''; }, + 'update-bin-name-editing': (s, is_editing) => { s.is_editing_bin_name=is_editing; }, + 'update-bin-name': (s, name) => { s.temp_bin_name=name; }, + 'commit-bin-name': (s) => { s.bin.name=s.temp_bin_name; s.is_editing_bin_name=false; } }, { - bin: {id: bin_id}, + bin: {id: bin_id, name: bin_id, user_id: ''}, + is_editing_bin_name: false, + temp_bin_name: bin_id, notes: [ //{is_editing: false, temp_text: '', bin_id: '', note: {id: nanoid(), text: 'Note one', modified: 1}}, ], search_term: '', - sorting: 'new->old' + sorting: 'new->old', + login: { + showing: true, + username: '', // value of textbox + password: '', // value of textbox + logged_in: false, + user: { + id: '', + username: '' + }, + session_id: '' + } //search_result_notes: [] }); diff --git a/nginx/public_html/models.js b/nginx/public_html/models.js new file mode 100644 index 0000000..078bca8 --- /dev/null +++ b/nginx/public_html/models.js @@ -0,0 +1,20 @@ +function bin(o){ + const b = {}; + b.id = o.id; + b.name = o.name || b.id; + b.user_id = o.user_id || ''; + return b; + } + +function note(o){ + const n = {}; + n.id = o.id; + n.text = o.text || ''; + n.modified = o.modified || 0; + return n; + } + +export { + bin, + note + } \ No newline at end of file