From b44c685f233acaa1fc84bc693000648ef0d6aec9 Mon Sep 17 00:00:00 2001 From: azivner Date: Sat, 4 Nov 2017 17:54:27 -0400 Subject: [PATCH] note converted to module --- public/javascripts/context_menu.js | 4 +- public/javascripts/dialogs/note_history.js | 2 +- public/javascripts/dialogs/recent_notes.js | 4 +- public/javascripts/encryption.js | 34 +-- public/javascripts/init.js | 6 +- public/javascripts/link.js | 1 + public/javascripts/note.js | 237 ------------------ public/javascripts/note_editor.js | 267 +++++++++++++++++++++ public/javascripts/status.js | 4 +- public/javascripts/tree.js | 8 +- views/index.ejs | 4 +- 11 files changed, 301 insertions(+), 270 deletions(-) delete mode 100644 public/javascripts/note.js create mode 100644 public/javascripts/note_editor.js diff --git a/public/javascripts/context_menu.js b/public/javascripts/context_menu.js index 8f5ad4523..99c066f60 100644 --- a/public/javascripts/context_menu.js +++ b/public/javascripts/context_menu.js @@ -54,10 +54,10 @@ const contextMenuSetup = { const parentKey = getParentKey(node); const encryption = getParentEncryption(node); - createNote(node, parentKey, 'after', encryption); + noteEditor.createNote(node, parentKey, 'after', encryption); } else if (ui.cmd === "insertChildNote") { - createNote(node, node.key, 'into'); + noteEditor.createNote(node, node.key, 'into'); } else if (ui.cmd === "encryptSubTree") { encryptSubTree(node.key); diff --git a/public/javascripts/dialogs/note_history.js b/public/javascripts/dialogs/note_history.js index 02b92e8c5..69d02b858 100644 --- a/public/javascripts/dialogs/note_history.js +++ b/public/javascripts/dialogs/note_history.js @@ -7,7 +7,7 @@ const noteHistory = (function() { let historyItems = []; async function showCurrentNoteHistory() { - await showNoteHistoryDialog(glob.currentNote.detail.note_id); + await showNoteHistoryDialog(noteEditor.getCurrentNoteId()); } async function showNoteHistoryDialog(noteId, noteHistoryId) { diff --git a/public/javascripts/dialogs/recent_notes.js b/public/javascripts/dialogs/recent_notes.js index b741f36b3..29f247454 100644 --- a/public/javascripts/dialogs/recent_notes.js +++ b/public/javascripts/dialogs/recent_notes.js @@ -9,7 +9,7 @@ const recentNotes = (function() { function addRecentNote(noteTreeId, noteContentId) { setTimeout(() => { // we include the note into recent list only if the user stayed on the note at least 5 seconds - if (noteTreeId === glob.currentNote.detail.note_id || noteContentId === glob.currentNote.detail.note_id) { + if (noteTreeId === noteEditor.getCurrentNoteId() || noteContentId === noteEditor.getCurrentNoteId()) { // if it's already there, remove the note list = list.filter(note => note !== noteTreeId); @@ -35,7 +35,7 @@ const recentNotes = (function() { selectBoxEl.find('option').remove(); // remove the current note - const recNotes = list.filter(note => note !== glob.currentNote.detail.note_id); + const recNotes = list.filter(note => note !== noteEditor.getCurrentNoteId()); $.each(recNotes, (key, valueNoteId) => { const noteTitle = getFullName(valueNoteId); diff --git a/public/javascripts/encryption.js b/public/javascripts/encryption.js index 47cdc38d2..b4c9567c0 100644 --- a/public/javascripts/encryption.js +++ b/public/javascripts/encryption.js @@ -12,7 +12,7 @@ function handleEncryption(requireEncryption, modal) { open: () => { if (!modal) { // dialog steals focus for itself, which is not what we want for non-modal (viewing) - getNodeByKey(glob.currentNote.detail.note_id).setFocus(); + getNodeByKey(noteEditor.getCurrentNoteId()).setFocus(); } } }); @@ -117,8 +117,8 @@ $("#encryption-password-form").submit(() => { function resetEncryptionSession() { glob.dataKey = null; - if (glob.currentNote.detail.encryption > 0) { - loadNoteToEditor(glob.currentNote.detail.note_id); + if (noteEditor.getCurrentNote().detail.encryption > 0) { + noteEditor.loadNoteToEditor(noteEditor.getCurrentNoteId()); for (const noteId of glob.allNoteIds) { const note = getNodeByKey(noteId); @@ -240,17 +240,17 @@ function encryptNote(note) { async function encryptNoteAndSendToServer() { await handleEncryption(true, true); - const note = glob.currentNote; + const note = noteEditor.getCurrentNote(); - updateNoteFromInputs(note); + noteEditor.updateNoteFromInputs(note); encryptNote(note); - await saveNoteToServer(note); + await noteEditor.saveNoteToServer(note); await changeEncryptionOnNoteHistory(note.detail.note_id, true); - setNoteBackgroundIfEncrypted(note); + noteEditor.setNoteBackgroundIfEncrypted(note); } async function changeEncryptionOnNoteHistory(noteId, encrypt) { @@ -287,17 +287,17 @@ async function changeEncryptionOnNoteHistory(noteId, encrypt) { async function decryptNoteAndSendToServer() { await handleEncryption(true, true); - const note = glob.currentNote; + const note = noteEditor.getCurrentNote(); - updateNoteFromInputs(note); + noteEditor.updateNoteFromInputs(note); note.detail.encryption = 0; - await saveNoteToServer(note); + await noteEditor.saveNoteToServer(note); await changeEncryptionOnNoteHistory(note.detail.note_id, false); - setNoteBackgroundIfEncrypted(note); + noteEditor.setNoteBackgroundIfEncrypted(note); } function decryptNoteIfNecessary(note) { @@ -327,11 +327,11 @@ async function encryptSubTree(noteId) { } }, note => { - if (note.detail.note_id === glob.currentNote.detail.note_id) { - loadNoteToEditor(note.detail.note_id); + if (note.detail.note_id === noteEditor.getCurrentNoteId()) { + noteEditor.loadNoteToEditor(note.detail.note_id); } else { - setTreeBasedOnEncryption(note); + noteEditor.setTreeBasedOnEncryption(note); } }); @@ -354,11 +354,11 @@ async function decryptSubTree(noteId) { } }, note => { - if (note.detail.note_id === glob.currentNote.detail.note_id) { - loadNoteToEditor(note.detail.note_id); + if (note.detail.note_id === noteEditor.getCurrentNoteId()) { + noteEditor.loadNoteToEditor(note.detail.note_id); } else { - setTreeBasedOnEncryption(note); + noteEditor.setTreeBasedOnEncryption(note); } }); diff --git a/public/javascripts/init.js b/public/javascripts/init.js index 61f96e8dd..94a22cfbc 100644 --- a/public/javascripts/init.js +++ b/public/javascripts/init.js @@ -24,7 +24,7 @@ $(document).bind('keydown', 'alt+t', () => { $(window).on('beforeunload', () => { // this makes sure that when user e.g. reloads the page or navigates away from the page, the note's content is saved // this sends the request asynchronously and doesn't wait for result - saveNoteIfChanged(); + noteEditor.saveNoteIfChanged(); }); // Overrides the default autocomplete filter function to search for matched on atleast 1 word in each of the input term's words @@ -62,10 +62,10 @@ $.ui.autocomplete.filter = (array, terms) => { $(document).tooltip({ items: ".note-editable a", content: function(callback) { - const noteId = getNoteIdFromLink($(this).attr("href")); + const noteId = link.getNoteIdFromLink($(this).attr("href")); if (noteId !== null) { - loadNote(noteId).then(note => callback(note.detail.note_text)); + noteEditor.loadNote(noteId).then(note => callback(note.detail.note_text)); } }, close: function(event, ui) diff --git a/public/javascripts/link.js b/public/javascripts/link.js index c8836bfef..cae4a5bcc 100644 --- a/public/javascripts/link.js +++ b/public/javascripts/link.js @@ -63,6 +63,7 @@ const link = (function() { return { getNodeIdFromLabel, + getNoteIdFromLink, createNoteLink }; })(); \ No newline at end of file diff --git a/public/javascripts/note.js b/public/javascripts/note.js deleted file mode 100644 index ec04dd13d..000000000 --- a/public/javascripts/note.js +++ /dev/null @@ -1,237 +0,0 @@ -const tags = { - 1: "", - 2: "", - 3: "", - 4: "", - 5: "", - 6: "", - 9: "", - 10: "" -}; - -let noteChangeDisabled = false; - -let isNoteChanged = false; - -function noteChanged() { - if (noteChangeDisabled) { - return; - } - - isNoteChanged = true; -} - -async function saveNoteIfChanged() { - if (!isNoteChanged) { - return; - } - - const note = glob.currentNote; - - updateNoteFromInputs(note); - - encryptNoteIfNecessary(note); - - await saveNoteToServer(note); -} - -setInterval(saveNoteIfChanged, 5000); - -$(document).ready(() => { - $("#note-title").on('input', () => { - noteChanged(); - }); - - $('#note-detail').summernote({ - airMode: true, - height: 300, - callbacks: { - onChange: noteChanged - } - }); - - // so that tab jumps from note title (which has tabindex 1) - $(".note-editable").attr("tabindex", 2); -}); - -function parseHtml(contents, note) { - note.links = []; - note.images = []; - - note.detail.note_text = contents; - - if (!note.detail.encryption) { - const linkRegexp = /]+?href="[^"]*kapp#([A-Za-z0-9]{22})"[^>]*?>[^<]+?<\/a>/g; - let match; - - while (match = linkRegexp.exec(contents)) { - console.log("adding link for " + match[1]); - - note.links.push({ - note_id: note.detail.note_id, - target_note_id: match[1] - }); - } - } -} - -function updateNoteFromInputs(note) { - let contents = $('#note-detail').summernote('code'); - - parseHtml(contents, note); - - let title = $('#note-title').val(); - - getNodeByKey(note.detail.note_id).setTitle(title); - - note.detail.note_title = title; -} - -async function saveNoteToServer(note) { - await $.ajax({ - url: baseApiUrl + 'notes/' + note.detail.note_id, - type: 'PUT', - data: JSON.stringify(note), - contentType: "application/json", - error: () => { - error("Error saving the note!"); - } - }); - - isNoteChanged = false; - - message("Saved!"); -} - -glob.currentNote = null; -glob.currentNoteLoadTime = null; - -function createNewTopLevelNote() { - let rootNode = glob.tree.fancytree("getRootNode"); - - createNote(rootNode, "root", "into"); -} - -let newNoteCreated = false; - -async function createNote(node, parentKey, target, encryption) { - // if encryption isn't available (user didn't enter password yet), then note is created as unencrypted - // but this is quite weird since user doesn't see where the note is being created so it shouldn't occur often - if (!encryption || !isEncryptionAvailable()) { - encryption = 0; - } - - const newNoteName = "new note"; - const newNoteNameEncryptedIfNecessary = encryption > 0 ? encryptString(newNoteName) : newNoteName; - - const result = await $.ajax({ - url: baseApiUrl + 'notes/' + parentKey + '/children' , - type: 'POST', - data: JSON.stringify({ - note_title: newNoteNameEncryptedIfNecessary, - target: target, - target_note_id: node.key, - encryption: encryption - }), - contentType: "application/json" - }); - - const newNode = { - title: newNoteName, - key: result.note_id, - note_id: result.note_id, - encryption: encryption, - extraClasses: encryption ? "encrypted" : "" - }; - - glob.allNoteIds.push(result.note_id); - - newNoteCreated = true; - - if (target === 'after') { - node.appendSibling(newNode).setActive(true); - } - else { - node.addChildren(newNode).setActive(true); - - node.folder = true; - node.renderTitle(); - } - - message("Created!"); -} - -function setTreeBasedOnEncryption(note) { - const node = getNodeByKey(note.detail.note_id); - node.toggleClass("encrypted", note.detail.encryption > 0); -} - -function setNoteBackgroundIfEncrypted(note) { - if (note.detail.encryption > 0) { - $(".note-editable").addClass("encrypted"); - $("#encrypt-button").hide(); - $("#decrypt-button").show(); - } - else { - $(".note-editable").removeClass("encrypted"); - $("#encrypt-button").show(); - $("#decrypt-button").hide(); - } - - setTreeBasedOnEncryption(note); -} - -async function loadNoteToEditor(noteId) { - const note = await $.get(baseApiUrl + 'notes/' + noteId); - glob.currentNote = note; - glob.currentNoteLoadTime = Math.floor(new Date().getTime() / 1000); - - if (newNoteCreated) { - newNoteCreated = false; - - $("#note-title").focus().select(); - } - - await handleEncryption(note.detail.encryption > 0, false); - - $("#note-detail-wrapper").show(); - - // this may fal if the dialog has not been previously opened - try { - $("#encryption-password-dialog").dialog('close'); - } - catch(e) {} - - $("#encryption-password").val(''); - - decryptNoteIfNecessary(note); - - $("#note-title").val(note.detail.note_title); - - noteChangeDisabled = true; - - // Clear contents and remove all stored history. This is to prevent undo from going across notes - $('#note-detail').summernote('reset'); - - $('#note-detail').summernote('code', note.detail.note_text); - - document.location.hash = noteId; - - recentNotes.addRecentNote(noteId, note.detail.note_id); - - noteChangeDisabled = false; - - setNoteBackgroundIfEncrypted(note); -} - -async function loadNote(noteId) { - const note = await $.get(baseApiUrl + 'notes/' + noteId); - - if (note.detail.encryption > 0 && !isEncryptionAvailable()) { - return; - } - - decryptNoteIfNecessary(note); - - return note; -} \ No newline at end of file diff --git a/public/javascripts/note_editor.js b/public/javascripts/note_editor.js new file mode 100644 index 000000000..ed55779d0 --- /dev/null +++ b/public/javascripts/note_editor.js @@ -0,0 +1,267 @@ +const noteEditor = (function() { + const noteTitleEl = $("#note-title"); + const noteDetailEl = $('#note-detail'); + const noteEditableEl = $(".note-editable"); + const encryptButton = $("#encrypt-button"); + const decryptButton = $("#decrypt-button"); + const noteDetailWrapperEl = $("#note-detail-wrapper"); + const encryptionPasswordDialogEl = $("#encryption-password-dialog"); + const encryptionPasswordEl = $("#encryption-password"); + + let currentNote = null; + let currentNoteLoadTime = null; + + let noteChangeDisabled = false; + + let isNoteChanged = false; + + function getCurrentNote() { + return currentNote; + } + + function getCurrentNoteId() { + return currentNote ? currentNote.detail.note_id : null; + } + + function getCurrentNoteLoadTime() { + return currentNoteLoadTime; + } + + function noteChanged() { + if (noteChangeDisabled) { + return; + } + + isNoteChanged = true; + } + + async function saveNoteIfChanged() { + if (!isNoteChanged) { + return; + } + + const note = noteEditor.getCurrentNote(); + + updateNoteFromInputs(note); + + encryptNoteIfNecessary(note); + + await saveNoteToServer(note); + } + + function parseHtml(contents, note) { + note.links = []; + note.images = []; + + note.detail.note_text = contents; + + if (!note.detail.encryption) { + const linkRegexp = /]+?href="[^"]*app#([A-Za-z0-9]{22})"[^>]*?>[^<]+?<\/a>/g; + let match; + + while (match = linkRegexp.exec(contents)) { + console.log("adding link for " + match[1]); + + note.links.push({ + note_id: note.detail.note_id, + target_note_id: match[1] + }); + } + } + } + + function updateNoteFromInputs(note) { + const contents = noteDetailEl.summernote('code'); + + parseHtml(contents, note); + + const title = noteTitleEl.val(); + + getNodeByKey(note.detail.note_id).setTitle(title); + + note.detail.note_title = title; + } + + async function saveNoteToServer(note) { + await $.ajax({ + url: baseApiUrl + 'notes/' + note.detail.note_id, + type: 'PUT', + data: JSON.stringify(note), + contentType: "application/json", + error: () => { + error("Error saving the note!"); + } + }); + + isNoteChanged = false; + + message("Saved!"); + } + + currentNote = null; + currentNoteLoadTime = null; + + function createNewTopLevelNote() { + let rootNode = glob.tree.fancytree("getRootNode"); + + createNote(rootNode, "root", "into"); + } + + let newNoteCreated = false; + + async function createNote(node, parentKey, target, encryption) { + // if encryption isn't available (user didn't enter password yet), then note is created as unencrypted + // but this is quite weird since user doesn't see where the note is being created so it shouldn't occur often + if (!encryption || !isEncryptionAvailable()) { + encryption = 0; + } + + const newNoteName = "new note"; + const newNoteNameEncryptedIfNecessary = encryption > 0 ? encryptString(newNoteName) : newNoteName; + + const result = await $.ajax({ + url: baseApiUrl + 'notes/' + parentKey + '/children' , + type: 'POST', + data: JSON.stringify({ + note_title: newNoteNameEncryptedIfNecessary, + target: target, + target_note_id: node.key, + encryption: encryption + }), + contentType: "application/json" + }); + + const newNode = { + title: newNoteName, + key: result.note_id, + note_id: result.note_id, + encryption: encryption, + extraClasses: encryption ? "encrypted" : "" + }; + + glob.allNoteIds.push(result.note_id); + + newNoteCreated = true; + + if (target === 'after') { + node.appendSibling(newNode).setActive(true); + } + else { + node.addChildren(newNode).setActive(true); + + node.folder = true; + node.renderTitle(); + } + + message("Created!"); + } + + function setTreeBasedOnEncryption(note) { + const node = getNodeByKey(note.detail.note_id); + node.toggleClass("encrypted", note.detail.encryption > 0); + } + + function setNoteBackgroundIfEncrypted(note) { + if (note.detail.encryption > 0) { + noteEditableEl.addClass("encrypted"); + encryptButton.hide(); + decryptButton.show(); + } + else { + noteEditableEl.removeClass("encrypted"); + encryptButton.show(); + decryptButton.hide(); + } + + setTreeBasedOnEncryption(note); + } + + async function loadNoteToEditor(noteId) { + const note = await $.get(baseApiUrl + 'notes/' + noteId); + currentNote = note; + currentNoteLoadTime = Math.floor(new Date().getTime() / 1000); + + if (newNoteCreated) { + newNoteCreated = false; + + noteTitleEl.focus().select(); + } + + await handleEncryption(note.detail.encryption > 0, false); + + noteDetailWrapperEl.show(); + + // this may fal if the dialog has not been previously opened + try { + encryptionPasswordDialogEl.dialog('close'); + } + catch(e) {} + + encryptionPasswordEl.val(''); + + decryptNoteIfNecessary(note); + + noteTitleEl.val(note.detail.note_title); + + noteChangeDisabled = true; + + // Clear contents and remove all stored history. This is to prevent undo from going across notes + noteDetailEl.summernote('reset'); + + noteDetailEl.summernote('code', note.detail.note_text); + + document.location.hash = noteId; + + recentNotes.addRecentNote(noteId, note.detail.note_id); + + noteChangeDisabled = false; + + setNoteBackgroundIfEncrypted(note); + } + + async function loadNote(noteId) { + const note = await $.get(baseApiUrl + 'notes/' + noteId); + + if (note.detail.encryption > 0 && !isEncryptionAvailable()) { + return; + } + + decryptNoteIfNecessary(note); + + return note; + } + + $(document).ready(() => { + noteTitleEl.on('input', () => { + noteChanged(); + }); + + noteDetailEl.summernote({ + airMode: true, + height: 300, + callbacks: { + onChange: noteChanged + } + }); + + // so that tab jumps from note title (which has tabindex 1) + noteEditableEl.attr("tabindex", 2); + }); + + setInterval(saveNoteIfChanged, 5000); + + return { + saveNoteIfChanged, + updateNoteFromInputs, + saveNoteToServer, + createNewTopLevelNote, + createNote, + setNoteBackgroundIfEncrypted, + setTreeBasedOnEncryption, + loadNoteToEditor, + loadNote, + getCurrentNote, + getCurrentNoteId, + getCurrentNoteLoadTime + }; +})(); \ No newline at end of file diff --git a/public/javascripts/status.js b/public/javascripts/status.js index 6e4a0b9c4..31eefb179 100644 --- a/public/javascripts/status.js +++ b/public/javascripts/status.js @@ -5,8 +5,8 @@ async function checkStatus() { contentType: "application/json", data: JSON.stringify({ treeLoadTime: glob.treeLoadTime, - currentNoteId: glob.currentNote ? glob.currentNote.detail.note_id : null, - currentNoteDateModified: glob.currentNoteLoadTime + currentNoteId: noteEditor.getCurrentNoteId(), + currentNoteDateModified: noteEditor.getCurrentNoteLoadTime() }), statusCode: { 401: () => { diff --git a/public/javascripts/tree.js b/public/javascripts/tree.js index e059d9420..59c240378 100644 --- a/public/javascripts/tree.js +++ b/public/javascripts/tree.js @@ -3,10 +3,10 @@ const keybindings = { const parentKey = getParentKey(node); const encryption = getParentEncryption(node); - createNote(node, parentKey, 'after', encryption); + noteEditor.createNote(node, parentKey, 'after', encryption); }, "ctrl+insert": node => { - createNote(node, node.key, 'into', node.data.encryption); + noteEditor.createNote(node, node.key, 'into', node.data.encryption); }, "del": node => { deleteNode(node); @@ -95,7 +95,7 @@ function initFancyTree(notes, startNoteId) { activate: (event, data) => { const node = data.node.data; - saveNoteIfChanged().then(() => loadNoteToEditor(node.note_id)); + noteEditor.saveNoteIfChanged().then(() => noteEditor.loadNoteToEditor(node.note_id)); }, expand: (event, data) => { setExpandedToServer(data.node.key, true); @@ -219,7 +219,7 @@ function collapseTree() { $(document).bind('keydown', 'alt+c', collapseTree); function scrollToCurrentNote() { - const node = getNodeByKey(glob.currentNote.detail.note_id); + const node = getNodeByKey(noteEditor.getCurrentNoteId()); if (node) { node.makeVisible({scrollIntoView: true}); diff --git a/views/index.ejs b/views/index.ejs index b91ad89d8..9b8629a0f 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -33,7 +33,7 @@
- + Create new top level note @@ -270,7 +270,7 @@ - +