From de6268d86f4657ebee8a50524824c9fc789653be Mon Sep 17 00:00:00 2001 From: quenousimporte Date: Sun, 4 Feb 2024 22:43:24 +0100 Subject: [PATCH] refactor local serialization --- main.js | 302 ++++++++++++++++++++++---------------------------------- 1 file changed, 120 insertions(+), 182 deletions(-) diff --git a/main.js b/main.js index 0193d5d..23bf489 100644 --- a/main.js +++ b/main.js @@ -19,37 +19,18 @@ var defaultsettings = }; //builtin -var markerslist = ["* ", "- ", " * ", " - ", ">> ", "> ", "=> ", "— ", "[ ] ", " ", "• ", "- [ ]", "[x] ", "- [x]"]; -var codelanguages = ["xml", "js", "sql"]; -var tagmark = "+"; +const markerslist = ["* ", "- ", " * ", " - ", ">> ", "> ", "=> ", "— ", "[ ] ", " ", "• ", "- [ ]", "[x] ", "- [x]"]; +const codelanguages = ["xml", "js", "sql"]; +const tagmark = "+"; // globals +var previoustitle = ""; var metadata = null; var fileindex = 0; var workerid = null; -var backup = ""; -var saved = true; -var lastsaved = ""; -var pending = false; -var settings = null; +var backup = "";var settings = null; var tags = null; -var stat = -{ - ses: - { - q: 0, - t: timestamp(), - d: 0 - }, - cur: - { - q: 0, - t: timestamp(), - d: 0 - } -} - var commands = [ { hint: "Close menu" @@ -57,9 +38,7 @@ var commands = [ { shortcut: "ctrl+shift+P", hint: "Command palette", - allowunsaved: true, action: commandpalette, - excludepalette: true }, { shortcut: "ctrl+p", @@ -78,14 +57,12 @@ var commands = [ }, { hint: "Force save", - action: save, - shortcut: "ctrl+s", - allowunsaved: true + action: serialize, + shortcut: "ctrl+s" }, { hint: "Share note", - action: share, - allowunsaved: true + action: share }, { hint: "Share note (html)", @@ -99,20 +76,17 @@ var commands = [ { shortcut: "ctrl+i", hint: "Toggle title", - action: toggletitle, - allowunsaved: true + action: toggletitle }, { shortcut: "ctrl+m", hint: "Toggle preview", - action: togglepreview, - allowunsaved: true + action: togglepreview }, { shortcut: "ctrl+shift+M", hint: "Toggle preview with merged subnotes", - action: togglepreviewwithsubs, - allowunsaved: true + action: togglepreviewwithsubs }, { shortcut: "ctrl+d", @@ -125,8 +99,7 @@ var commands = [ }, { hint: "Insert markdown header", - action: insertheader, - allowunsaved: true + action: insertheader }, { hint: "Show help", @@ -166,8 +139,7 @@ var commands = [ { hint: "Note outline", action: showoutline, - shortcut: "ctrl+o", - allowunsaved: true + shortcut: "ctrl+o" }, { hint: "Show connected notes", @@ -177,13 +149,11 @@ var commands = [ { hint: "Show stats", action: showinfo, - shortcut: "ctrl+w", - allowunsaved: true + shortcut: "ctrl+w" }, { hint: "Toggle spell check", action: togglespellcheck, - allowunsaved: true, shortcut: "F7" }, { @@ -255,8 +225,7 @@ var commands = [ }, { hint: "Sort text", - action: sortselection, - allowunsaved: true + action: sortselection }, { hint: "Show backlinks", @@ -264,8 +233,7 @@ var commands = [ }, { hint: "Remove completed tasks", - action: purgetodo, - allowunsaved: true + action: purgetodo }]; var snippets = [ @@ -316,21 +284,19 @@ function genguid() return crypto.randomUUID(); } -function purgetodo() { +function purgetodo() +{ if (currentistodo() && confirm("Remove completed tasks?")) { seteditorcontent(currentnote.content.replace(/\nx .*/g, "")); } } -function seteditorcontent(content, silent) +function seteditorcontent(content) { md.value = content; applycolors(); - if (!silent) - { - datachanged(); - } + serialize(); resize(); } @@ -453,7 +419,7 @@ function includesub() if (confirm("Delete '" + title + "'?")) { - deletenote(subnote); + deletenote(title); } } } @@ -490,19 +456,12 @@ function showinfo() var tags = gettags(currentnote); showtemporaryinfo( [ - "saved: " + saved + (lastsaved? " (" + lastsaved + ")": ""), "sync: " + (settings.sync ? "en" : "dis") + "abled", "title: " + currentnote.title, "line count: " + md.value.split("\n").length, "word count: " + getwords(), "cursor position: " + md.selectionStart + " (" + pospercent() + "%)", (tags ? "tags: " + tags : ""), - "current note start: " + stat.cur.t, - "current note queries: " + stat.cur.q, - "current note data sent: " + formatsize(stat.cur.d), - "session start: " + stat.ses.t, - "session queries: " + stat.ses.q, - "session data sent: " + formatsize(stat.ses.d), "notes count: " + localdata.length, "spell check: " + (md.spellcheck ? "en" : "dis") + "abled" ].join("\n")); @@ -877,11 +836,7 @@ function restoresettings() function editsettings() { - bind( - { - title: "settings.json", - content: JSON.stringify(settings, null, " ") - }); + bind("settings.json", JSON.stringify(settings, null, " ")); } function editsetting(name) @@ -932,11 +887,7 @@ function decryptnote() function editpgpkeys() { - bind( - { - title: "pgpkeys", - content: localStorage.getItem("pgpkeys") || "" - }); + bind("pgpkeys", localStorage.getItem("pgpkeys") || ""); } function showtemporaryinfo(info) @@ -1101,14 +1052,24 @@ function headerandtext(content) function inserttodo(text) { - var todo = getorcreate("todo", ""); - var split = headerandtext(todo); - todo.content = split.header + text + "\n" + split.text; - if (todo == currentnote) + var guid = getguid("todo"); + if (!guid) { - seteditorcontent(todo.content, true); + guid = createnote("todo"); + } + var content = localStorage.getItem(guid); + var split = headerandtext(content); + content = split.header + text + "\n" + split.text; + if (title.value == "todo") + { + seteditorcontent(content); + } + else + { + localStorage.setItem(guid, content); + metadata[guid].lastchanged = Date.now(); + serialize(); } - return datachanged(); } function promptinserttodo() @@ -1228,7 +1189,8 @@ function loadstorage() msg.innerText = "Clipping..."; notepage.appendChild(msg); - inserttodo("@clip " + clip).then(window.close); + inserttodo("@clip " + clip) + window.close(); } // when multiple tabs or split? @@ -1249,8 +1211,7 @@ function loadstorage() if (window.title.value) { - var guid = getguid(window.title.value); - bind(guid); + bind(window.title.value); if (line) { gotoline(line); @@ -1354,14 +1315,14 @@ function migratelegacystorage() var legacy = localStorage.getItem("data"); if (legacy) { - // todo: use title as key and guid as property. or not. var legacy = JSON.parse(legacy); var index = {}; - legacy.forEach(note => + legacy.reverse().forEach(note => { var guid = genguid(); localStorage.setItem(guid, note.content); note.header = indexheader(note.content); + note.lastchanged = Date.now(); delete note.content; index[guid] = note; }); @@ -1448,9 +1409,6 @@ function queryremote(params) { return new Promise( (apply, failed) => { - stat.cur.q++; - stat.ses.q++; - params.password = settings.password; var paramlist = []; @@ -1459,9 +1417,6 @@ function queryremote(params) paramlist.push(i + "=" + encodeURIComponent(params[i])); } - stat.cur.d += paramlist.join("&").length; - stat.ses.d += paramlist.join("&").length; - var xhr = new XMLHttpRequest(); xhr.open("POST", "handler.php"); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); @@ -1661,11 +1616,7 @@ function showgrepresult(needle, grepresult) grepcontent.push("No result."); } - bind( - { - title: "Search result", - content: grepcontent.join("\n") - }); + bind("Search result", grepcontent.join("\n")); if (preview.hidden) { @@ -1877,12 +1828,6 @@ function resize() } } -function putontop() -{ - console.warn("todo: put on top"); - return; -} - function postpone() { return new Promise(function(resolve) @@ -1892,31 +1837,37 @@ function postpone() }); } -function setsaved() -{ - unsavedmark.hidden = true; - saved = true; - lastsaved = timestamp(); -} - function serialize() { - // serialize all gui stuff to local storage + clearTimeout(workerid); + workerid = null; + var guid = getguid(window.title.value); - var item = metadata[guid]; - item.title = title.value; - item.pos = md.selectionStart; - item.header = indexheader(md.value); - - // is it the right place? - putontop(); - - localStorage.setItem("index", JSON.stringify(metadata)); - localStorage.setItem(guid, md.value); + if (guid) + { + var item = metadata[guid]; + item.title = title.value; + item.pos = md.selectionStart; + item.header = indexheader(md.value); + item.lastchanged = Date.now(); + localStorage.setItem("index", JSON.stringify(metadata)); + localStorage.setItem(guid, md.value); + } + else if (title.value == "settings.json") + { + settings = JSON.parse(md.value); + savesettings(); + loadsettings(); + } + else if (title.value == "pgpkeys") + { + localStorage.setItem("pgpkeys", md.value); + } + console.log("data serialized"); } -function save() +/*function save() { return new Promise(function(resolve, reject) { @@ -2001,7 +1952,7 @@ function save() } } }); -} +}*/ function escapeHtml(unsafe) { return unsafe @@ -2263,19 +2214,10 @@ function editorinput() // criteria to improve. Or redraw only after? var multiline = md.value.substring(md.selectionStart, md.selectionEnd).includes("\n"); applycolors(!multiline && event.data && (event.inputType == "insertText" || event.inputType == "deleteContentBackward" || event.inputType == "deleteContentForward")); - datachanged(); + postpone().then(serialize); resize(); } -function datachanged() -{ - saved = false; - unsavedmark.hidden = !settings.sync; - - return postpone() - .then(save); -} - function timestamp() { var utc = new Date(); @@ -2286,17 +2228,17 @@ function timestamp() function quicknewnote() { + serialize(); loadnote(timestamp()); - datachanged(); } function startnewnote() { + serialize(); var title = prompt("Note title: ", timestamp()); if (title) { loadnote(title); - datachanged(); } } @@ -2334,11 +2276,7 @@ function showhelp() help.push("##Sources"); help.push("https://github.com/quenousimporte/notes"); - bind( - { - title: "Help", - content: help.join("\n") - }); + bind("Help", help.join("\n")); if (preview.hidden) { @@ -2362,6 +2300,7 @@ function toggletitle() function selectnote() { + // todo: sort by lastchanged return searchinlist( Object.values(metadata).map(item => { @@ -2491,6 +2430,7 @@ function renamereferences(newname) function restoredeleted() { + // todo: parse local storage starting with "deleted" and reindex with a new guid var trash = window.localStorage.getItem("trash"); if (trash) { @@ -2518,24 +2458,22 @@ function restoredeleted() } } -function deletenote(note) +function deletenote(title) { - var trash = JSON.parse(window.localStorage.getItem("trash") || "[]"); - note.deletiondate = timestamp(); - trash.push(note); - window.localStorage.setItem("trash", JSON.stringify(trash)); - - localdata = localdata.filter(n => n != note); - - renamereferences(note.title + " (deleted)"); - datachanged(); + var guid = getguid(title); + delete metadata[guid]; + renameinternallinks(title, title + " (deleted)"); + var content = localStorage.getItem(guid); + localStorage.removeItem(guid); + localStorage.setItem("deleted_" + title, content); + localStorage.setItem("index", JSON.stringify(metadata)); } function deletecurrentnote() { - if (confirm('delete "' + currentnote.title + '"?')) + if (confirm('delete "' + title.value + '"?')) { - deletenote(currentnote); + deletenote(title.value); loadlast(); } } @@ -2578,11 +2516,7 @@ function shortcutmatches(event, shortcut) function executecommand(command) { - if (!command.allowunsaved && !saved) - { - showtemporaryinfo("Cannot perform '" + command.hint + "' because current note is not saved."); - } - else if (command.remoteonly && !settings.sync) + if (command.remoteonly && !settings.sync) { showtemporaryinfo(command.hint + " is not available in local mode."); } @@ -2748,31 +2682,41 @@ function setwindowtitle() document.title = title.value; } +function renameinternallinks(from, to) +{ + foreachmetadata( (guid, item) => + { + var content = localStorage.getItem(guid); + var newcontent = content.replaceAll("[[" + from + "]]", "[[" + to + "]]"); + if (content != newcontent) + { + localStorage.setItem(guid, newcontent); + } + }); +} + function ontitlechange() { - if (localdata.find(n => n.title == title.value)) + var guid = getguid(title.value); + if (guid) { showtemporaryinfo(title.value + " alreday exists"); - title.value = currentnote.title; - return; + title.value = previoustitle; } - - // rename internal references - localdata - .filter(note => note != currentnote) - .forEach(note => + else { - note.content = note.content.replaceAll("[[" + currentnote.title + "]]", "[[" + title.value + "]]"); - }); + renameinternallinks(previoustitle, title.value); - currentnote.title = title.value; + guid = getguid(previoustitle); + previoustitle = title.value; + metadata[guid].title = title.value; + setwindowtitle(); + serialize(); - datachanged(); - setwindowtitle(); - - if (!settings.titlebydefault) - { - toggletitle(); + if (!settings.titlebydefault) + { + toggletitle(); + } } } @@ -2961,18 +2905,16 @@ function togglepreviewwithsubs() function bind(title, content, pos) { - var changed = title.value != title; - + previoustitle = title; backup = content; + window.title.value = title; setwindowtitle(); - seteditorcontent(content || "", true); + md.value = content || ""; + applycolors(); - if (changed) - { - md.style.height = "0px"; - } + md.style.height = "0px"; resize(); setpos(pos || 0); @@ -3027,10 +2969,6 @@ function loadnote(title) bind(item.title, content, item.pos); - stat.cur.q = 0; - stat.cur.d = 0; - stat.cur.t = timestamp(); - if (!preview.hidden || (preview.hidden && (gettags(md.value).indexOf("preview") !== -1))) { togglepreview();