From a699210a298a64a571998083054bb44962504026 Mon Sep 17 00:00:00 2001 From: azivner Date: Sun, 25 Mar 2018 11:09:17 -0400 Subject: [PATCH] using ES6 modules for whole frontend SPA app --- src/public/javascripts/bootstrap.js | 35 +- src/public/javascripts/cloning.js | 46 +- src/public/javascripts/context_menu.js | 341 ++-- src/public/javascripts/dialogs/add_link.js | 226 +-- .../javascripts/dialogs/edit_tree_prefix.js | 76 +- src/public/javascripts/dialogs/event_log.js | 53 +- .../javascripts/dialogs/jump_to_note.js | 98 +- src/public/javascripts/dialogs/labels.js | 379 ++-- .../javascripts/dialogs/note_history.js | 125 +- src/public/javascripts/dialogs/note_source.js | 104 +- .../javascripts/dialogs/recent_changes.js | 139 +- .../javascripts/dialogs/recent_notes.js | 186 +- src/public/javascripts/dialogs/settings.js | 80 +- src/public/javascripts/dialogs/sql_console.js | 176 +- src/public/javascripts/drag_and_drop.js | 5 + src/public/javascripts/export.js | 58 +- src/public/javascripts/init.js | 404 ++-- src/public/javascripts/link.js | 162 +- src/public/javascripts/messaging.js | 215 +-- src/public/javascripts/note_editor.js | 662 +++---- src/public/javascripts/note_tree.js | 1630 +++++++++-------- src/public/javascripts/note_type.js | 262 +-- src/public/javascripts/protected_session.js | 329 ++-- src/public/javascripts/script_api.js | 6 +- src/public/javascripts/script_context.js | 9 +- src/public/javascripts/search_tree.js | 2 + src/public/javascripts/server.js | 161 +- src/public/javascripts/sync.js | 46 +- src/public/javascripts/tree_changes.js | 235 +-- src/public/javascripts/tree_utils.js | 54 +- src/public/javascripts/utils.js | 494 ++--- src/views/index.ejs | 37 - 32 files changed, 3452 insertions(+), 3383 deletions(-) diff --git a/src/public/javascripts/bootstrap.js b/src/public/javascripts/bootstrap.js index d858b0f12..9ddabb999 100644 --- a/src/public/javascripts/bootstrap.js +++ b/src/public/javascripts/bootstrap.js @@ -1,9 +1,38 @@ -import searchTree from './search_tree.js'; +import addLink from './dialogs/add_link.js'; +import editTreePrefix from './dialogs/edit_tree_prefix.js'; +import eventLog from './dialogs/event_log.js'; +import jumpToNote from './dialogs/jump_to_note.js'; +import labelsDialog from './dialogs/labels.js'; +import noteHistory from './dialogs/note_history.js'; +import noteSource from './dialogs/note_source.js'; +import recentChanges from './dialogs/recent_changes.js'; +import recentNotes from './dialogs/recent_notes.js'; +import settings from './dialogs/settings.js'; +import sqlConsole from './dialogs/sql_console.js'; +import cloning from './cloning.js'; +import contextMenu from './context_menu.js'; +import dragAndDropSetup from './drag_and_drop.js'; +import exportService from './export.js'; +import link from './link.js'; +import messaging from './messaging.js'; +import noteEditor from './note_editor.js'; +import noteType from './note_type.js'; +import protected_session from './protected_session.js'; +import ScriptApi from './script_api.js'; +import ScriptContext from './script_context.js'; +import sync from './sync.js'; +import treeChanges from './tree_changes.js'; +import treeUtils from './tree_utils.js'; +import utils from './utils.js'; + +import searchTreeService from './search_tree.js'; +import './init.js'; +import treeService from './note_tree.js'; const $toggleSearchButton = $("#toggle-search-button"); -$toggleSearchButton.click(searchTree.toggleSearch); -bindShortcut('ctrl+s', searchTree.toggleSearch); +$toggleSearchButton.click(searchTreeService.toggleSearch); +bindShortcut('ctrl+s', searchTreeService.toggleSearch); function bindShortcut(keyboardShortcut, handler) { $(document).bind('keydown', keyboardShortcut, e => { diff --git a/src/public/javascripts/cloning.js b/src/public/javascripts/cloning.js index 7dd7e395a..bb578a888 100644 --- a/src/public/javascripts/cloning.js +++ b/src/public/javascripts/cloning.js @@ -1,33 +1,33 @@ "use strict"; -const cloning = (function() { - async function cloneNoteTo(childNoteId, parentNoteId, prefix) { - const resp = await server.put('notes/' + childNoteId + '/clone-to/' + parentNoteId, { - prefix: prefix - }); +import treeService from './note_tree.js'; - if (!resp.success) { - alert(resp.message); - return; - } +async function cloneNoteTo(childNoteId, parentNoteId, prefix) { + const resp = await server.put('notes/' + childNoteId + '/clone-to/' + parentNoteId, { + prefix: prefix + }); - await treeService.reload(); + if (!resp.success) { + alert(resp.message); + return; } - // beware that first arg is noteId and second is branchId! - async function cloneNoteAfter(noteId, afterBranchId) { - const resp = await server.put('notes/' + noteId + '/clone-after/' + afterBranchId); + await treeService.reload(); +} - if (!resp.success) { - alert(resp.message); - return; - } +// beware that first arg is noteId and second is branchId! +async function cloneNoteAfter(noteId, afterBranchId) { + const resp = await server.put('notes/' + noteId + '/clone-after/' + afterBranchId); - await treeService.reload(); + if (!resp.success) { + alert(resp.message); + return; } - return { - cloneNoteAfter, - cloneNoteTo - }; -})(); \ No newline at end of file + await treeService.reload(); +} + +export default { + cloneNoteAfter, + cloneNoteTo +}; \ No newline at end of file diff --git a/src/public/javascripts/context_menu.js b/src/public/javascripts/context_menu.js index 55fe98edb..0631a104f 100644 --- a/src/public/javascripts/context_menu.js +++ b/src/public/javascripts/context_menu.js @@ -1,181 +1,188 @@ "use strict"; -const contextMenu = (function() { - const $tree = $("#tree"); +import treeService from './note_tree.js'; +import cloning from './cloning.js'; +import exportService from './export.js'; +import messaging from './messaging.js'; +import protected_session from './protected_session.js'; +import treeChanges from './tree_changes.js'; +import treeUtils from './tree_utils.js'; +import utils from './utils.js'; - let clipboardIds = []; - let clipboardMode = null; +const $tree = $("#tree"); - async function pasteAfter(node) { - if (clipboardMode === 'cut') { - const nodes = clipboardIds.map(nodeKey => treeUtils.getNodeByKey(nodeKey)); +let clipboardIds = []; +let clipboardMode = null; - await treeChanges.moveAfterNode(nodes, node); +async function pasteAfter(node) { + if (clipboardMode === 'cut') { + const nodes = clipboardIds.map(nodeKey => treeUtils.getNodeByKey(nodeKey)); - clipboardIds = []; - clipboardMode = null; + await treeChanges.moveAfterNode(nodes, node); + + clipboardIds = []; + clipboardMode = null; + } + else if (clipboardMode === 'copy') { + for (const noteId of clipboardIds) { + await cloning.cloneNoteAfter(noteId, node.data.branchId); } - else if (clipboardMode === 'copy') { - for (const noteId of clipboardIds) { - await cloning.cloneNoteAfter(noteId, node.data.branchId); - } - // copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places + // copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places + } + else if (clipboardIds.length === 0) { + // just do nothing + } + else { + utils.throwError("Unrecognized clipboard mode=" + clipboardMode); + } +} + +async function pasteInto(node) { + if (clipboardMode === 'cut') { + const nodes = clipboardIds.map(nodeKey => treeUtils.getNodeByKey(nodeKey)); + + await treeChanges.moveToNode(nodes, node); + + clipboardIds = []; + clipboardMode = null; + } + else if (clipboardMode === 'copy') { + for (const noteId of clipboardIds) { + await cloning.cloneNoteTo(noteId, node.data.noteId); } - else if (clipboardIds.length === 0) { - // just do nothing + // copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places + } + else if (clipboardIds.length === 0) { + // just do nothing + } + else { + utils.throwError("Unrecognized clipboard mode=" + mode); + } +} + +function copy(nodes) { + clipboardIds = nodes.map(node => node.data.noteId); + clipboardMode = 'copy'; + + utils.showMessage("Note(s) have been copied into clipboard."); +} + +function cut(nodes) { + clipboardIds = nodes.map(node => node.key); + clipboardMode = 'cut'; + + utils.showMessage("Note(s) have been cut into clipboard."); +} + +const contextMenuSettings = { + delegate: "span.fancytree-title", + autoFocus: true, + menu: [ + {title: "Insert note here Ctrl+O", cmd: "insertNoteHere", uiIcon: "ui-icon-plus"}, + {title: "Insert child note Ctrl+P", cmd: "insertChildNote", uiIcon: "ui-icon-plus"}, + {title: "Delete Ctrl+Del", cmd: "delete", uiIcon: "ui-icon-trash"}, + {title: "----"}, + {title: "Edit tree prefix F2", cmd: "editTreePrefix", uiIcon: "ui-icon-pencil"}, + {title: "----"}, + {title: "Protect sub-tree", cmd: "protectSubTree", uiIcon: "ui-icon-locked"}, + {title: "Unprotect sub-tree", cmd: "unprotectSubTree", uiIcon: "ui-icon-unlocked"}, + {title: "----"}, + {title: "Copy / clone Ctrl+C", cmd: "copy", uiIcon: "ui-icon-copy"}, + {title: "Cut Ctrl+X", cmd: "cut", uiIcon: "ui-icon-scissors"}, + {title: "Paste into Ctrl+V", cmd: "pasteInto", uiIcon: "ui-icon-clipboard"}, + {title: "Paste after", cmd: "pasteAfter", uiIcon: "ui-icon-clipboard"}, + {title: "----"}, + {title: "Export sub-tree", cmd: "exportSubTree", uiIcon: " ui-icon-arrowthick-1-ne"}, + {title: "Import sub-tree into", cmd: "importSubTree", uiIcon: "ui-icon-arrowthick-1-sw"}, + {title: "----"}, + {title: "Collapse sub-tree Alt+-", cmd: "collapseSubTree", uiIcon: "ui-icon-minus"}, + {title: "Force note sync", cmd: "forceNoteSync", uiIcon: "ui-icon-refresh"}, + {title: "Sort alphabetically Alt+S", cmd: "sortAlphabetically", uiIcon: " ui-icon-arrowthick-2-n-s"} + + ], + beforeOpen: (event, ui) => { + const node = $.ui.fancytree.getNode(ui.target); + const branch = treeService.getBranch(node.data.branchId); + const note = treeService.getNote(node.data.noteId); + const parentNote = treeService.getNote(branch.parentNoteId); + + // Modify menu entries depending on node status + $tree.contextmenu("enableEntry", "pasteAfter", clipboardIds.length > 0 && (!parentNote || parentNote.type !== 'search')); + $tree.contextmenu("enableEntry", "pasteInto", clipboardIds.length > 0 && note.type !== 'search'); + $tree.contextmenu("enableEntry", "insertNoteHere", !parentNote || parentNote.type !== 'search'); + $tree.contextmenu("enableEntry", "insertChildNote", note.type !== 'search'); + $tree.contextmenu("enableEntry", "importSubTree", note.type !== 'search'); + $tree.contextmenu("enableEntry", "exportSubTree", note.type !== 'search'); + + // Activate node on right-click + node.setActive(); + // Disable tree keyboard handling + ui.menu.prevKeyboard = node.tree.options.keyboard; + node.tree.options.keyboard = false; + }, + close: (event, ui) => {}, + select: (event, ui) => { + const node = $.ui.fancytree.getNode(ui.target); + + if (ui.cmd === "insertNoteHere") { + const parentNoteId = node.data.parentNoteId; + const isProtected = treeUtils.getParentProtectedStatus(node); + + treeService.createNote(node, parentNoteId, 'after', isProtected); + } + else if (ui.cmd === "insertChildNote") { + treeService.createNote(node, node.data.noteId, 'into'); + } + else if (ui.cmd === "editTreePrefix") { + editTreePrefix.showDialog(node); + } + else if (ui.cmd === "protectSubTree") { + protected_session.protectSubTree(node.data.noteId, true); + } + else if (ui.cmd === "unprotectSubTree") { + protected_session.protectSubTree(node.data.noteId, false); + } + else if (ui.cmd === "copy") { + copy(treeService.getSelectedNodes()); + } + else if (ui.cmd === "cut") { + cut(treeService.getSelectedNodes()); + } + else if (ui.cmd === "pasteAfter") { + pasteAfter(node); + } + else if (ui.cmd === "pasteInto") { + pasteInto(node); + } + else if (ui.cmd === "delete") { + treeChanges.deleteNodes(treeService.getSelectedNodes(true)); + } + else if (ui.cmd === "exportSubTree") { + exportService.exportSubTree(node.data.noteId); + } + else if (ui.cmd === "importSubTree") { + exportService.importSubTree(node.data.noteId); + } + else if (ui.cmd === "collapseSubTree") { + treeService.collapseTree(node); + } + else if (ui.cmd === "forceNoteSync") { + syncService.forceNoteSync(node.data.noteId); + } + else if (ui.cmd === "sortAlphabetically") { + treeService.sortAlphabetically(node.data.noteId); } else { - utils.throwError("Unrecognized clipboard mode=" + clipboardMode); + messaging.logError("Unknown command: " + ui.cmd); } } +}; - async function pasteInto(node) { - if (clipboardMode === 'cut') { - const nodes = clipboardIds.map(nodeKey => treeUtils.getNodeByKey(nodeKey)); - - await treeChanges.moveToNode(nodes, node); - - clipboardIds = []; - clipboardMode = null; - } - else if (clipboardMode === 'copy') { - for (const noteId of clipboardIds) { - await cloning.cloneNoteTo(noteId, node.data.noteId); - } - // copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places - } - else if (clipboardIds.length === 0) { - // just do nothing - } - else { - utils.throwError("Unrecognized clipboard mode=" + mode); - } - } - - function copy(nodes) { - clipboardIds = nodes.map(node => node.data.noteId); - clipboardMode = 'copy'; - - utils.showMessage("Note(s) have been copied into clipboard."); - } - - function cut(nodes) { - clipboardIds = nodes.map(node => node.key); - clipboardMode = 'cut'; - - utils.showMessage("Note(s) have been cut into clipboard."); - } - - const contextMenuSettings = { - delegate: "span.fancytree-title", - autoFocus: true, - menu: [ - {title: "Insert note here Ctrl+O", cmd: "insertNoteHere", uiIcon: "ui-icon-plus"}, - {title: "Insert child note Ctrl+P", cmd: "insertChildNote", uiIcon: "ui-icon-plus"}, - {title: "Delete Ctrl+Del", cmd: "delete", uiIcon: "ui-icon-trash"}, - {title: "----"}, - {title: "Edit tree prefix F2", cmd: "editTreePrefix", uiIcon: "ui-icon-pencil"}, - {title: "----"}, - {title: "Protect sub-tree", cmd: "protectSubTree", uiIcon: "ui-icon-locked"}, - {title: "Unprotect sub-tree", cmd: "unprotectSubTree", uiIcon: "ui-icon-unlocked"}, - {title: "----"}, - {title: "Copy / clone Ctrl+C", cmd: "copy", uiIcon: "ui-icon-copy"}, - {title: "Cut Ctrl+X", cmd: "cut", uiIcon: "ui-icon-scissors"}, - {title: "Paste into Ctrl+V", cmd: "pasteInto", uiIcon: "ui-icon-clipboard"}, - {title: "Paste after", cmd: "pasteAfter", uiIcon: "ui-icon-clipboard"}, - {title: "----"}, - {title: "Export sub-tree", cmd: "exportSubTree", uiIcon: " ui-icon-arrowthick-1-ne"}, - {title: "Import sub-tree into", cmd: "importSubTree", uiIcon: "ui-icon-arrowthick-1-sw"}, - {title: "----"}, - {title: "Collapse sub-tree Alt+-", cmd: "collapseSubTree", uiIcon: "ui-icon-minus"}, - {title: "Force note sync", cmd: "forceNoteSync", uiIcon: "ui-icon-refresh"}, - {title: "Sort alphabetically Alt+S", cmd: "sortAlphabetically", uiIcon: " ui-icon-arrowthick-2-n-s"} - - ], - beforeOpen: (event, ui) => { - const node = $.ui.fancytree.getNode(ui.target); - const branch = treeService.getBranch(node.data.branchId); - const note = treeService.getNote(node.data.noteId); - const parentNote = treeService.getNote(branch.parentNoteId); - - // Modify menu entries depending on node status - $tree.contextmenu("enableEntry", "pasteAfter", clipboardIds.length > 0 && (!parentNote || parentNote.type !== 'search')); - $tree.contextmenu("enableEntry", "pasteInto", clipboardIds.length > 0 && note.type !== 'search'); - $tree.contextmenu("enableEntry", "insertNoteHere", !parentNote || parentNote.type !== 'search'); - $tree.contextmenu("enableEntry", "insertChildNote", note.type !== 'search'); - $tree.contextmenu("enableEntry", "importSubTree", note.type !== 'search'); - $tree.contextmenu("enableEntry", "exportSubTree", note.type !== 'search'); - - // Activate node on right-click - node.setActive(); - // Disable tree keyboard handling - ui.menu.prevKeyboard = node.tree.options.keyboard; - node.tree.options.keyboard = false; - }, - close: (event, ui) => {}, - select: (event, ui) => { - const node = $.ui.fancytree.getNode(ui.target); - - if (ui.cmd === "insertNoteHere") { - const parentNoteId = node.data.parentNoteId; - const isProtected = treeUtils.getParentProtectedStatus(node); - - treeService.createNote(node, parentNoteId, 'after', isProtected); - } - else if (ui.cmd === "insertChildNote") { - treeService.createNote(node, node.data.noteId, 'into'); - } - else if (ui.cmd === "editTreePrefix") { - editTreePrefix.showDialog(node); - } - else if (ui.cmd === "protectSubTree") { - protected_session.protectSubTree(node.data.noteId, true); - } - else if (ui.cmd === "unprotectSubTree") { - protected_session.protectSubTree(node.data.noteId, false); - } - else if (ui.cmd === "copy") { - copy(treeService.getSelectedNodes()); - } - else if (ui.cmd === "cut") { - cut(treeService.getSelectedNodes()); - } - else if (ui.cmd === "pasteAfter") { - pasteAfter(node); - } - else if (ui.cmd === "pasteInto") { - pasteInto(node); - } - else if (ui.cmd === "delete") { - treeChanges.deleteNodes(treeService.getSelectedNodes(true)); - } - else if (ui.cmd === "exportSubTree") { - exportService.exportSubTree(node.data.noteId); - } - else if (ui.cmd === "importSubTree") { - exportService.importSubTree(node.data.noteId); - } - else if (ui.cmd === "collapseSubTree") { - treeService.collapseTree(node); - } - else if (ui.cmd === "forceNoteSync") { - syncService.forceNoteSync(node.data.noteId); - } - else if (ui.cmd === "sortAlphabetically") { - treeService.sortAlphabetically(node.data.noteId); - } - else { - messaging.logError("Unknown command: " + ui.cmd); - } - } - }; - - return { - pasteAfter, - pasteInto, - cut, - copy, - contextMenuSettings - } -})(); \ No newline at end of file +export default { + pasteAfter, + pasteInto, + cut, + copy, + contextMenuSettings +}; \ No newline at end of file diff --git a/src/public/javascripts/dialogs/add_link.js b/src/public/javascripts/dialogs/add_link.js index f0f06d7f2..e357471c2 100644 --- a/src/public/javascripts/dialogs/add_link.js +++ b/src/public/javascripts/dialogs/add_link.js @@ -1,137 +1,141 @@ "use strict"; -const addLink = (function() { - const $dialog = $("#add-link-dialog"); - const $form = $("#add-link-form"); - const $autoComplete = $("#note-autocomplete"); - const $linkTitle = $("#link-title"); - const $clonePrefix = $("#clone-prefix"); - const $linkTitleFormGroup = $("#add-link-title-form-group"); - const $prefixFormGroup = $("#add-link-prefix-form-group"); - const $linkTypes = $("input[name='add-link-type']"); - const $linkTypeHtml = $linkTypes.filter('input[value="html"]'); +import treeService from '../note_tree.js'; +import cloning from '../cloning.js'; +import link from '../link.js'; +import noteEditor from '../note_editor.js'; +import treeUtils from '../tree_utils.js'; - function setLinkType(linkType) { - $linkTypes.each(function () { - $(this).prop('checked', $(this).val() === linkType); - }); +const $dialog = $("#add-link-dialog"); +const $form = $("#add-link-form"); +const $autoComplete = $("#note-autocomplete"); +const $linkTitle = $("#link-title"); +const $clonePrefix = $("#clone-prefix"); +const $linkTitleFormGroup = $("#add-link-title-form-group"); +const $prefixFormGroup = $("#add-link-prefix-form-group"); +const $linkTypes = $("input[name='add-link-type']"); +const $linkTypeHtml = $linkTypes.filter('input[value="html"]'); - linkTypeChanged(); +function setLinkType(linkType) { + $linkTypes.each(function () { + $(this).prop('checked', $(this).val() === linkType); + }); + + linkTypeChanged(); +} + +async function showDialog() { + glob.activeDialog = $dialog; + + if (noteEditor.getCurrentNoteType() === 'text') { + $linkTypeHtml.prop('disabled', false); + + setLinkType('html'); + } + else { + $linkTypeHtml.prop('disabled', true); + + setLinkType('selected-to-current'); } - async function showDialog() { - glob.activeDialog = $dialog; + $dialog.dialog({ + modal: true, + width: 700 + }); - if (noteEditor.getCurrentNoteType() === 'text') { - $linkTypeHtml.prop('disabled', false); + $autoComplete.val('').focus(); + $clonePrefix.val(''); + $linkTitle.val(''); - setLinkType('html'); - } - else { - $linkTypeHtml.prop('disabled', true); + function setDefaultLinkTitle(noteId) { + const noteTitle = treeService.getNoteTitle(noteId); - setLinkType('selected-to-current'); - } + $linkTitle.val(noteTitle); + } - $dialog.dialog({ - modal: true, - width: 700 - }); + $autoComplete.autocomplete({ + source: await treeService.getAutocompleteItems(), + minLength: 0, + change: () => { + const val = $autoComplete.val(); + const notePath = link.getNodePathFromLabel(val); + if (!notePath) { + return; + } - $autoComplete.val('').focus(); - $clonePrefix.val(''); - $linkTitle.val(''); - - function setDefaultLinkTitle(noteId) { - const noteTitle = treeService.getNoteTitle(noteId); - - $linkTitle.val(noteTitle); - } - - $autoComplete.autocomplete({ - source: await treeService.getAutocompleteItems(), - minLength: 0, - change: () => { - const val = $autoComplete.val(); - const notePath = link.getNodePathFromLabel(val); - if (!notePath) { - return; - } - - const noteId = treeUtils.getNoteIdFromNotePath(notePath); - - if (noteId) { - setDefaultLinkTitle(noteId); - } - }, - // this is called when user goes through autocomplete list with keyboard - // at this point the item isn't selected yet so we use supplied ui.item to see WHERE the cursor is - focus: (event, ui) => { - const notePath = link.getNodePathFromLabel(ui.item.value); - const noteId = treeUtils.getNoteIdFromNotePath(notePath); + const noteId = treeUtils.getNoteIdFromNotePath(notePath); + if (noteId) { setDefaultLinkTitle(noteId); } - }); - } + }, + // this is called when user goes through autocomplete list with keyboard + // at this point the item isn't selected yet so we use supplied ui.item to see WHERE the cursor is + focus: (event, ui) => { + const notePath = link.getNodePathFromLabel(ui.item.value); + const noteId = treeUtils.getNoteIdFromNotePath(notePath); - $form.submit(() => { - const value = $autoComplete.val(); - - const notePath = link.getNodePathFromLabel(value); - const noteId = treeUtils.getNoteIdFromNotePath(notePath); - - if (notePath) { - const linkType = $("input[name='add-link-type']:checked").val(); - - if (linkType === 'html') { - const linkTitle = $linkTitle.val(); - - $dialog.dialog("close"); - - link.addLinkToEditor(linkTitle, '#' + notePath); - } - else if (linkType === 'selected-to-current') { - const prefix = $clonePrefix.val(); - - cloning.cloneNoteTo(noteId, noteEditor.getCurrentNoteId(), prefix); - - $dialog.dialog("close"); - } - else if (linkType === 'current-to-selected') { - const prefix = $clonePrefix.val(); - - cloning.cloneNoteTo(noteEditor.getCurrentNoteId(), noteId, prefix); - - $dialog.dialog("close"); - } + setDefaultLinkTitle(noteId); } - - return false; }); +} - function linkTypeChanged() { - const value = $linkTypes.filter(":checked").val(); +$form.submit(() => { + const value = $autoComplete.val(); - if (value === 'html') { - $linkTitleFormGroup.show(); - $prefixFormGroup.hide(); + const notePath = link.getNodePathFromLabel(value); + const noteId = treeUtils.getNoteIdFromNotePath(notePath); + + if (notePath) { + const linkType = $("input[name='add-link-type']:checked").val(); + + if (linkType === 'html') { + const linkTitle = $linkTitle.val(); + + $dialog.dialog("close"); + + link.addLinkToEditor(linkTitle, '#' + notePath); } - else { - $linkTitleFormGroup.hide(); - $prefixFormGroup.show(); + else if (linkType === 'selected-to-current') { + const prefix = $clonePrefix.val(); + + cloning.cloneNoteTo(noteId, noteEditor.getCurrentNoteId(), prefix); + + $dialog.dialog("close"); + } + else if (linkType === 'current-to-selected') { + const prefix = $clonePrefix.val(); + + cloning.cloneNoteTo(noteEditor.getCurrentNoteId(), noteId, prefix); + + $dialog.dialog("close"); } } - $linkTypes.change(linkTypeChanged); + return false; +}); - $(document).bind('keydown', 'ctrl+l', e => { - showDialog(); +function linkTypeChanged() { + const value = $linkTypes.filter(":checked").val(); - e.preventDefault(); - }); + if (value === 'html') { + $linkTitleFormGroup.show(); + $prefixFormGroup.hide(); + } + else { + $linkTitleFormGroup.hide(); + $prefixFormGroup.show(); + } +} - return { - showDialog - }; -})(); \ No newline at end of file +$linkTypes.change(linkTypeChanged); + +$(document).bind('keydown', 'ctrl+l', e => { + showDialog(); + + e.preventDefault(); +}); + +export default { + showDialog +}; \ No newline at end of file diff --git a/src/public/javascripts/dialogs/edit_tree_prefix.js b/src/public/javascripts/dialogs/edit_tree_prefix.js index bcc15ef44..45dbdcbee 100644 --- a/src/public/javascripts/dialogs/edit_tree_prefix.js +++ b/src/public/javascripts/dialogs/edit_tree_prefix.js @@ -1,46 +1,46 @@ "use strict"; -const editTreePrefix = (function() { - const $dialog = $("#edit-tree-prefix-dialog"); - const $form = $("#edit-tree-prefix-form"); - const $treePrefixInput = $("#tree-prefix-input"); - const $noteTitle = $('#tree-prefix-note-title'); +import treeService from '../note_tree.js'; - let branchId; +const $dialog = $("#edit-tree-prefix-dialog"); +const $form = $("#edit-tree-prefix-form"); +const $treePrefixInput = $("#tree-prefix-input"); +const $noteTitle = $('#tree-prefix-note-title'); - async function showDialog() { - glob.activeDialog = $dialog; +let branchId; - await $dialog.dialog({ - modal: true, - width: 500 - }); +async function showDialog() { + glob.activeDialog = $dialog; - const currentNode = treeService.getCurrentNode(); - - branchId = currentNode.data.branchId; - const nt = treeService.getBranch(branchId); - - $treePrefixInput.val(nt.prefix).focus(); - - const noteTitle = treeService.getNoteTitle(currentNode.data.noteId); - - $noteTitle.html(noteTitle); - } - - $form.submit(() => { - const prefix = $treePrefixInput.val(); - - server.put('tree/' + branchId + '/set-prefix', { - prefix: prefix - }).then(() => treeService.setPrefix(branchId, prefix)); - - $dialog.dialog("close"); - - return false; + await $dialog.dialog({ + modal: true, + width: 500 }); - return { - showDialog - }; -})(); \ No newline at end of file + const currentNode = treeService.getCurrentNode(); + + branchId = currentNode.data.branchId; + const nt = treeService.getBranch(branchId); + + $treePrefixInput.val(nt.prefix).focus(); + + const noteTitle = treeService.getNoteTitle(currentNode.data.noteId); + + $noteTitle.html(noteTitle); +} + +$form.submit(() => { + const prefix = $treePrefixInput.val(); + + server.put('tree/' + branchId + '/set-prefix', { + prefix: prefix + }).then(() => treeService.setPrefix(branchId, prefix)); + + $dialog.dialog("close"); + + return false; +}); + +export default { + showDialog +}; \ No newline at end of file diff --git a/src/public/javascripts/dialogs/event_log.js b/src/public/javascripts/dialogs/event_log.js index affa63dc7..b89cafe52 100644 --- a/src/public/javascripts/dialogs/event_log.js +++ b/src/public/javascripts/dialogs/event_log.js @@ -1,38 +1,39 @@ "use strict"; -const eventLog = (function() { - const $dialog = $("#event-log-dialog"); - const $list = $("#event-log-list"); +import link from '../link.js'; +import utils from '../utils.js'; - async function showDialog() { - glob.activeDialog = $dialog; +const $dialog = $("#event-log-dialog"); +const $list = $("#event-log-list"); - $dialog.dialog({ - modal: true, - width: 800, - height: 700 - }); +async function showDialog() { + glob.activeDialog = $dialog; - const result = await server.get('event-log'); + $dialog.dialog({ + modal: true, + width: 800, + height: 700 + }); - $list.html(''); + const result = await server.get('event-log'); - for (const event of result) { - const dateTime = utils.formatDateTime(utils.parseDate(event.dateAdded)); + $list.html(''); - if (event.noteId) { - const noteLink = link.createNoteLink(event.noteId).prop('outerHTML'); + for (const event of result) { + const dateTime = utils.formatDateTime(utils.parseDate(event.dateAdded)); - event.comment = event.comment.replace('', noteLink); - } + if (event.noteId) { + const noteLink = link.createNoteLink(event.noteId).prop('outerHTML'); - const eventEl = $('
  • ').html(dateTime + " - " + event.comment); - - $list.append(eventEl); + event.comment = event.comment.replace('', noteLink); } - } - return { - showDialog - }; -})(); \ No newline at end of file + const eventEl = $('
  • ').html(dateTime + " - " + event.comment); + + $list.append(eventEl); + } +} + +export default { + showDialog +}; diff --git a/src/public/javascripts/dialogs/jump_to_note.js b/src/public/javascripts/dialogs/jump_to_note.js index c6b33c01a..f1dae16cf 100644 --- a/src/public/javascripts/dialogs/jump_to_note.js +++ b/src/public/javascripts/dialogs/jump_to_note.js @@ -1,59 +1,61 @@ "use strict"; -const jumpToNote = (function() { - const $showDialogButton = $("#jump-to-note-button"); - const $dialog = $("#jump-to-note-dialog"); - const $autoComplete = $("#jump-to-note-autocomplete"); - const $form = $("#jump-to-note-form"); +import treeService from '../note_tree.js'; +import link from '../link.js'; +import utils from '../utils.js'; - async function showDialog() { - glob.activeDialog = $dialog; +const $showDialogButton = $("#jump-to-note-button"); +const $dialog = $("#jump-to-note-dialog"); +const $autoComplete = $("#jump-to-note-autocomplete"); +const $form = $("#jump-to-note-form"); - $autoComplete.val(''); +async function showDialog() { + glob.activeDialog = $dialog; - $dialog.dialog({ - modal: true, - width: 800 - }); + $autoComplete.val(''); - await $autoComplete.autocomplete({ - source: await utils.stopWatch("building autocomplete", treeService.getAutocompleteItems), - minLength: 0 - }); - } - - function getSelectedNotePath() { - const val = $autoComplete.val(); - return link.getNodePathFromLabel(val); - } - - function goToNote() { - const notePath = getSelectedNotePath(); - - if (notePath) { - treeService.activateNode(notePath); - - $dialog.dialog('close'); - } - } - - $(document).bind('keydown', 'ctrl+j', e => { - showDialog(); - - e.preventDefault(); + $dialog.dialog({ + modal: true, + width: 800 }); - $form.submit(() => { - const action = $dialog.find("button:focus").val(); - - goToNote(); - - return false; + await $autoComplete.autocomplete({ + source: await utils.stopWatch("building autocomplete", treeService.getAutocompleteItems), + minLength: 0 }); +} - $showDialogButton.click(showDialog); +function getSelectedNotePath() { + const val = $autoComplete.val(); + return link.getNodePathFromLabel(val); +} - return { - showDialog - }; -})(); \ No newline at end of file +function goToNote() { + const notePath = getSelectedNotePath(); + + if (notePath) { + treeService.activateNode(notePath); + + $dialog.dialog('close'); + } +} + +$(document).bind('keydown', 'ctrl+j', e => { + showDialog(); + + e.preventDefault(); +}); + +$form.submit(() => { + const action = $dialog.find("button:focus").val(); + + goToNote(); + + return false; +}); + +$showDialogButton.click(showDialog); + +export default { + showDialog +}; \ No newline at end of file diff --git a/src/public/javascripts/dialogs/labels.js b/src/public/javascripts/dialogs/labels.js index 1ffd9c91f..b63dd90fd 100644 --- a/src/public/javascripts/dialogs/labels.js +++ b/src/public/javascripts/dialogs/labels.js @@ -1,227 +1,228 @@ "use strict"; -const labelsDialog = (function() { - const $showDialogButton = $(".show-labels-button"); - const $dialog = $("#labels-dialog"); - const $saveLabelsButton = $("#save-labels-button"); - const $labelsBody = $('#labels-table tbody'); +import noteEditor from '../note_editor.js'; +import utils from '../utils.js'; - const labelsModel = new LabelsModel(); - let labelNames = []; +const $showDialogButton = $(".show-labels-button"); +const $dialog = $("#labels-dialog"); +const $saveLabelsButton = $("#save-labels-button"); +const $labelsBody = $('#labels-table tbody'); - function LabelsModel() { - const self = this; +const labelsModel = new LabelsModel(); +let labelNames = []; - this.labels = ko.observableArray(); +function LabelsModel() { + const self = this; - this.loadLabels = async function() { - const noteId = noteEditor.getCurrentNoteId(); + this.labels = ko.observableArray(); - const labels = await server.get('notes/' + noteId + '/labels'); + this.loadLabels = async function() { + const noteId = noteEditor.getCurrentNoteId(); - self.labels(labels.map(ko.observable)); + const labels = await server.get('notes/' + noteId + '/labels'); + + self.labels(labels.map(ko.observable)); + + addLastEmptyRow(); + + labelNames = await server.get('labels/names'); + + // label might not be rendered immediatelly so could not focus + setTimeout(() => $(".label-name:last").focus(), 100); + + $labelsBody.sortable({ + handle: '.handle', + containment: $labelsBody, + update: function() { + let position = 0; + + // we need to update positions by searching in the DOM, because order of the + // labels in the viewmodel (self.labels()) stays the same + $labelsBody.find('input[name="position"]').each(function() { + const attr = self.getTargetLabel(this); + + attr().position = position++; + }); + } + }); + }; + + this.deleteLabel = function(data, event) { + const attr = self.getTargetLabel(event.target); + const attrData = attr(); + + if (attrData) { + attrData.isDeleted = 1; + + attr(attrData); addLastEmptyRow(); - - labelNames = await server.get('labels/names'); - - // label might not be rendered immediatelly so could not focus - setTimeout(() => $(".label-name:last").focus(), 100); - - $labelsBody.sortable({ - handle: '.handle', - containment: $labelsBody, - update: function() { - let position = 0; - - // we need to update positions by searching in the DOM, because order of the - // labels in the viewmodel (self.labels()) stays the same - $labelsBody.find('input[name="position"]').each(function() { - const attr = self.getTargetLabel(this); - - attr().position = position++; - }); - } - }); - }; - - this.deleteLabel = function(data, event) { - const attr = self.getTargetLabel(event.target); - const attrData = attr(); - - if (attrData) { - attrData.isDeleted = 1; - - attr(attrData); - - addLastEmptyRow(); - } - }; - - function isValid() { - for (let attrs = self.labels(), i = 0; i < attrs.length; i++) { - if (self.isEmptyName(i)) { - return false; - } - } - - return true; } + }; - this.save = async function() { - // we need to defocus from input (in case of enter-triggered save) because value is updated - // on blur event (because of conflict with jQuery UI Autocomplete). Without this, input would - // stay in focus, blur wouldn't be triggered and change wouldn't be updated in the viewmodel. - $saveLabelsButton.focus(); - - if (!isValid()) { - alert("Please fix all validation errors and try saving again."); - return; - } - - const noteId = noteEditor.getCurrentNoteId(); - - const labelsToSave = self.labels() - .map(attr => attr()) - .filter(attr => attr.labelId !== "" || attr.name !== ""); - - const labels = await server.put('notes/' + noteId + '/labels', labelsToSave); - - self.labels(labels.map(ko.observable)); - - addLastEmptyRow(); - - utils.showMessage("Labels have been saved."); - - noteEditor.loadLabelList(); - }; - - function addLastEmptyRow() { - const attrs = self.labels().filter(attr => attr().isDeleted === 0); - const last = attrs.length === 0 ? null : attrs[attrs.length - 1](); - - if (!last || last.name.trim() !== "" || last.value !== "") { - self.labels.push(ko.observable({ - labelId: '', - name: '', - value: '', - isDeleted: 0, - position: 0 - })); - } - } - - this.labelChanged = function (data, event) { - addLastEmptyRow(); - - const attr = self.getTargetLabel(event.target); - - attr.valueHasMutated(); - }; - - this.isNotUnique = function(index) { - const cur = self.labels()[index](); - - if (cur.name.trim() === "") { + function isValid() { + for (let attrs = self.labels(), i = 0; i < attrs.length; i++) { + if (self.isEmptyName(i)) { return false; } + } - for (let attrs = self.labels(), i = 0; i < attrs.length; i++) { - const attr = attrs[i](); + return true; + } - if (index !== i && cur.name === attr.name) { - return true; - } - } + this.save = async function() { + // we need to defocus from input (in case of enter-triggered save) because value is updated + // on blur event (because of conflict with jQuery UI Autocomplete). Without this, input would + // stay in focus, blur wouldn't be triggered and change wouldn't be updated in the viewmodel. + $saveLabelsButton.focus(); - return false; - }; + if (!isValid()) { + alert("Please fix all validation errors and try saving again."); + return; + } - this.isEmptyName = function(index) { - const cur = self.labels()[index](); + const noteId = noteEditor.getCurrentNoteId(); - return cur.name.trim() === "" && (cur.labelId !== "" || cur.value !== ""); - }; + const labelsToSave = self.labels() + .map(attr => attr()) + .filter(attr => attr.labelId !== "" || attr.name !== ""); - this.getTargetLabel = function(target) { - const context = ko.contextFor(target); - const index = context.$index(); + const labels = await server.put('notes/' + noteId + '/labels', labelsToSave); - return self.labels()[index]; + self.labels(labels.map(ko.observable)); + + addLastEmptyRow(); + + utils.showMessage("Labels have been saved."); + + noteEditor.loadLabelList(); + }; + + function addLastEmptyRow() { + const attrs = self.labels().filter(attr => attr().isDeleted === 0); + const last = attrs.length === 0 ? null : attrs[attrs.length - 1](); + + if (!last || last.name.trim() !== "" || last.value !== "") { + self.labels.push(ko.observable({ + labelId: '', + name: '', + value: '', + isDeleted: 0, + position: 0 + })); } } - async function showDialog() { - glob.activeDialog = $dialog; + this.labelChanged = function (data, event) { + addLastEmptyRow(); - await labelsModel.loadLabels(); + const attr = self.getTargetLabel(event.target); - $dialog.dialog({ - modal: true, - width: 800, - height: 500 + attr.valueHasMutated(); + }; + + this.isNotUnique = function(index) { + const cur = self.labels()[index](); + + if (cur.name.trim() === "") { + return false; + } + + for (let attrs = self.labels(), i = 0; i < attrs.length; i++) { + const attr = attrs[i](); + + if (index !== i && cur.name === attr.name) { + return true; + } + } + + return false; + }; + + this.isEmptyName = function(index) { + const cur = self.labels()[index](); + + return cur.name.trim() === "" && (cur.labelId !== "" || cur.value !== ""); + }; + + this.getTargetLabel = function(target) { + const context = ko.contextFor(target); + const index = context.$index(); + + return self.labels()[index]; + } +} + +async function showDialog() { + glob.activeDialog = $dialog; + + await labelsModel.loadLabels(); + + $dialog.dialog({ + modal: true, + width: 800, + height: 500 + }); +} + +$(document).bind('keydown', 'alt+a', e => { + showDialog(); + + e.preventDefault(); +}); + +ko.applyBindings(labelsModel, document.getElementById('labels-dialog')); + +$(document).on('focus', '.label-name', function (e) { + if (!$(this).hasClass("ui-autocomplete-input")) { + $(this).autocomplete({ + // shouldn't be required and autocomplete should just accept array of strings, but that fails + // because we have overriden filter() function in init.js + source: labelNames.map(attr => { + return { + label: attr, + value: attr + } + }), + minLength: 0 }); } - $(document).bind('keydown', 'alt+a', e => { - showDialog(); + $(this).autocomplete("search", $(this).val()); +}); - e.preventDefault(); - }); +$(document).on('focus', '.label-value', async function (e) { + if (!$(this).hasClass("ui-autocomplete-input")) { + const labelName = $(this).parent().parent().find('.label-name').val(); - ko.applyBindings(labelsModel, document.getElementById('labels-dialog')); - - $(document).on('focus', '.label-name', function (e) { - if (!$(this).hasClass("ui-autocomplete-input")) { - $(this).autocomplete({ - // shouldn't be required and autocomplete should just accept array of strings, but that fails - // because we have overriden filter() function in init.js - source: labelNames.map(attr => { - return { - label: attr, - value: attr - } - }), - minLength: 0 - }); + if (labelName.trim() === "") { + return; } - $(this).autocomplete("search", $(this).val()); - }); + const labelValues = await server.get('labels/values/' + encodeURIComponent(labelName)); - $(document).on('focus', '.label-value', async function (e) { - if (!$(this).hasClass("ui-autocomplete-input")) { - const labelName = $(this).parent().parent().find('.label-name').val(); - - if (labelName.trim() === "") { - return; - } - - const labelValues = await server.get('labels/values/' + encodeURIComponent(labelName)); - - if (labelValues.length === 0) { - return; - } - - $(this).autocomplete({ - // shouldn't be required and autocomplete should just accept array of strings, but that fails - // because we have overriden filter() function in init.js - source: labelValues.map(attr => { - return { - label: attr, - value: attr - } - }), - minLength: 0 - }); + if (labelValues.length === 0) { + return; } - $(this).autocomplete("search", $(this).val()); - }); + $(this).autocomplete({ + // shouldn't be required and autocomplete should just accept array of strings, but that fails + // because we have overriden filter() function in init.js + source: labelValues.map(attr => { + return { + label: attr, + value: attr + } + }), + minLength: 0 + }); + } - $showDialogButton.click(showDialog); + $(this).autocomplete("search", $(this).val()); +}); - return { - showDialog - }; -})(); \ No newline at end of file +$showDialogButton.click(showDialog); + +export default { + showDialog +}; \ No newline at end of file diff --git a/src/public/javascripts/dialogs/note_history.js b/src/public/javascripts/dialogs/note_history.js index 3c04679aa..7819fd643 100644 --- a/src/public/javascripts/dialogs/note_history.js +++ b/src/public/javascripts/dialogs/note_history.js @@ -1,81 +1,82 @@ "use strict"; -const noteHistory = (function() { - const $showDialogButton = $("#show-history-button"); - const $dialog = $("#note-history-dialog"); - const $list = $("#note-history-list"); - const $content = $("#note-history-content"); - const $title = $("#note-history-title"); +import noteEditor from '../note_editor.js'; +import utils from '../utils.js'; - let historyItems = []; +const $showDialogButton = $("#show-history-button"); +const $dialog = $("#note-history-dialog"); +const $list = $("#note-history-list"); +const $content = $("#note-history-content"); +const $title = $("#note-history-title"); - async function showCurrentNoteHistory() { - await showNoteHistoryDialog(noteEditor.getCurrentNoteId()); +let historyItems = []; + +async function showCurrentNoteHistory() { + await showNoteHistoryDialog(noteEditor.getCurrentNoteId()); +} + +async function showNoteHistoryDialog(noteId, noteRevisionId) { + glob.activeDialog = $dialog; + + $dialog.dialog({ + modal: true, + width: 800, + height: 700 + }); + + $list.empty(); + $content.empty(); + + historyItems = await server.get('notes-history/' + noteId); + + for (const item of historyItems) { + const dateModified = utils.parseDate(item.dateModifiedFrom); + + $list.append($('