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 @@
-
+
@@ -270,7 +270,7 @@
-
+