You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pastebin/nginx/public_html/index.js

103 lines
5.3 KiB
JavaScript

import api from './api.js';
import App from './App.js';
import nanoid from './nanoid.min.js';
import {initial_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
var root = document.body;
/* Ruthlessly taken from [https://gist.github.com/kitze/fb65f527803a93fb2803ce79a792fff8]: */
const handleActions = (actionsMap, defaultState) =>
(state=defaultState, {type, payload}) =>
produce(state, draft => {
const action = actionsMap[type];
action && action(draft, payload);
});
// get bin id from URL, and load notes from that bin; if a bin id isn't specified in the URL, create a new one and update the URL
let bin_id = window.location.hash.substring(1); // extract the leading '#'
if(bin_id === ''){
bin_id = nanoid();
window.history.replaceState(null,'', '#'+bin_id);
}
// the actual loading from server is done later, after store and dispatch are defined
function addToBinListIfLoggedIn(state){
const s = state;
// if user is logged in:
if(s.login.is_logged_in){
// if bin is not already in the list:
if(s.login.bins.filter(b=>b.id===s.bin.id).length===0){
s.login.bins.push({id: s.bin.id, name: s.bin.name});
}
}
}
const reducer = handleActions({
'new-bin': (s, bin) => { s.bin=bin; s.notes=[]; s.temp_bin_name=bin.id; },
'bin-requested': (s, bin_id) => { s.bin={id:bin_id}; s.notes = []; },
'bin-loaded': (s, bin) => { s.bin=bin; s.temp_bin_name=bin.name; },
'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}}); },
'notes-loaded': (s, _notes) => { s.notes = _notes.map(n=>({is_editing: false, temp_text: n.text, bin_id: s.bin.id, note:n})); },
'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-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.is_logged_in=true; s.login.showing=true; s.login.password=''; s.login.user=user; s.login.session_id=session_id; },
'login-failed': (s) => { s.login.showing=true; s.login.password=''; },
'logout-requested': (s) => { s.login.is_logged_in=false; s.login.showing=true; s.login.username=''; s.login.password=''; s.login.session_id=''; s.login.bins=[]; },
'user-bin-list-loaded': (s, bins) => { s.login.bins=bins; },
'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; addToBinListIfLoggedIn(s); }
}, {
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',
login: {
showing: true,
username: '', // value of textbox
password: '', // value of textbox
is_logged_in: false,
user: null /*{
id: '',
username: ''
}*/,
session_id: '',
bins: []
}
//search_result_notes: []
});
// create Redux store, with Redux DevTools enabled:
const store = Redux.createStore(reducer, /* preloadedState, */
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
const dispatch = function(action_type, payload){ store.dispatch({type:action_type, payload}); };
store.subscribe(()=>{
const state = store.getState();
m.render(root, m(App, {state, dispatch}));
});
api.setStore(store);
window.addEventListener("hashchange", (e)=>hash_change_handler(store.getState(), dispatch, e), false);
let state = store.getState();
initial_load_bin_handler(state, dispatch, bin_id);
// we don't want Mithril auto-redraw system in place, since Redux will manually re-render when necessary with store.subscribe():
// m.mount(root, App);
m.render(root, m(App, {state, dispatch}))