diff --git a/src/public/javascripts/desktop.js b/src/public/javascripts/desktop.js index 17a5c182d..ece9f9885 100644 --- a/src/public/javascripts/desktop.js +++ b/src/public/javascripts/desktop.js @@ -61,7 +61,7 @@ window.glob.noteChanged = noteDetailService.noteChanged; window.glob.refreshTree = treeService.reload; // required for ESLint plugin -window.glob.getActiveTabNote = noteDetailService.getActiveTabNote; +window.glob.getActiveTabNote = appContext.getActiveTabNote; window.glob.requireLibrary = libraryLoader.requireLibrary; window.glob.ESLINT = libraryLoader.ESLINT; @@ -145,7 +145,7 @@ async function printActiveNote() { return; } - const $tabContext = noteDetailService.getActiveTabContext(); + const $tabContext = appContext.getActiveTabContext(); if (!$tabContext) { return; } diff --git a/src/public/javascripts/dialogs/attributes.js b/src/public/javascripts/dialogs/attributes.js index 171c01a29..1c0068cf3 100644 --- a/src/public/javascripts/dialogs/attributes.js +++ b/src/public/javascripts/dialogs/attributes.js @@ -93,7 +93,7 @@ function AttributesModel() { } this.loadAttributes = async function() { - const noteId = noteDetailService.getActiveTabNoteId(); + const noteId = appContext.getActiveTabNoteId(); const attributes = await server.get('notes/' + noteId + '/attributes'); @@ -139,7 +139,7 @@ function AttributesModel() { self.updateAttributePositions(); - const noteId = noteDetailService.getActiveTabNoteId(); + const noteId = appContext.getActiveTabNoteId(); const attributesToSave = self.ownedAttributes() .map(attribute => attribute()) @@ -171,7 +171,7 @@ function AttributesModel() { toastService.showMessage("Attributes have been saved."); - const ctx = noteDetailService.getActiveTabContext(); + const ctx = appContext.getActiveTabContext(); ctx.attributes.refreshAttributes(); diff --git a/src/public/javascripts/dialogs/link_map.js b/src/public/javascripts/dialogs/link_map.js index 4a3937a53..e1fbd1b20 100644 --- a/src/public/javascripts/dialogs/link_map.js +++ b/src/public/javascripts/dialogs/link_map.js @@ -31,7 +31,7 @@ export async function showDialog() { } $dialog.on('shown.bs.modal', () => { - const note = noteDetailService.getActiveTabNote(); + const note = appContext.getActiveTabNote(); linkMapService = new LinkMapService(note, $linkMapContainer, getOptions()); linkMapService.render(); diff --git a/src/public/javascripts/dialogs/markdown_import.js b/src/public/javascripts/dialogs/markdown_import.js index 02465e34a..bd491ff4d 100644 --- a/src/public/javascripts/dialogs/markdown_import.js +++ b/src/public/javascripts/dialogs/markdown_import.js @@ -26,7 +26,7 @@ async function convertMarkdownToHtml(text) { } export async function importMarkdownInline() { - if (noteDetailService.getActiveTabNoteType() !== 'text') { + if (appContext.getActiveTabNoteType() !== 'text') { return; } diff --git a/src/public/javascripts/dialogs/note_info.js b/src/public/javascripts/dialogs/note_info.js index 0b300a3eb..9ec3781e2 100644 --- a/src/public/javascripts/dialogs/note_info.js +++ b/src/public/javascripts/dialogs/note_info.js @@ -16,7 +16,7 @@ export function showDialog() { $dialog.modal(); - const activeNote = noteDetailService.getActiveTabNote(); + const activeNote = appContext.getActiveTabNote(); $noteId.text(activeNote.noteId); $dateCreated.text(activeNote.dateCreated); diff --git a/src/public/javascripts/dialogs/note_revisions.js b/src/public/javascripts/dialogs/note_revisions.js index 8656bfe9b..06cfc926e 100644 --- a/src/public/javascripts/dialogs/note_revisions.js +++ b/src/public/javascripts/dialogs/note_revisions.js @@ -25,7 +25,7 @@ let note; let noteRevisionId; export async function showCurrentNoteRevisions() { - await showNoteRevisionsDialog(noteDetailService.getActiveTabNoteId()); + await showNoteRevisionsDialog(appContext.getActiveTabNoteId()); } export async function showNoteRevisionsDialog(noteId, noteRevisionId) { @@ -42,7 +42,7 @@ async function loadNoteRevisions(noteId, noteRevId) { $list.empty(); $content.empty(); - note = noteDetailService.getActiveTabNote(); + note = appContext.getActiveTabNote(); revisionItems = await server.get(`notes/${noteId}/revisions`); for (const item of revisionItems) { diff --git a/src/public/javascripts/dialogs/note_source.js b/src/public/javascripts/dialogs/note_source.js index 76ead802b..be710061c 100644 --- a/src/public/javascripts/dialogs/note_source.js +++ b/src/public/javascripts/dialogs/note_source.js @@ -11,7 +11,7 @@ export function showDialog() { $dialog.modal(); - const noteText = noteDetailService.getActiveTabNote().content; + const noteText = appContext.getActiveTabNote().content; $noteSource.text(formatHtml(noteText)); } diff --git a/src/public/javascripts/services/app_context.js b/src/public/javascripts/services/app_context.js index 2bc5f17cd..3c1bcadd7 100644 --- a/src/public/javascripts/services/app_context.js +++ b/src/public/javascripts/services/app_context.js @@ -2,10 +2,16 @@ import GlobalButtonsWidget from "../widgets/global_buttons.js"; import SearchBoxWidget from "../widgets/search_box.js"; import SearchResultsWidget from "../widgets/search_results.js"; import NoteTreeWidget from "../widgets/note_tree.js"; +import tabRow from "./tab_row.js"; +import treeService from "./tree.js"; +import noteDetailService from "./note_detail.js"; +import TabContext from "./tab_context.js"; class AppContext { constructor() { this.widgets = []; + /** @type {TabContext[]} */ + this.tabContexts = []; } trigger(name, data) { @@ -14,6 +20,97 @@ class AppContext { } } + /** @return {TabContext[]} */ + getTabContexts() { + return this.tabContexts; + } + + /** @returns {TabContext} */ + getActiveTabContext() { + const activeTabEl = tabRow.activeTabEl; + + if (!activeTabEl) { + return null; + } + + const tabId = activeTabEl.getAttribute('data-tab-id'); + + return this.tabContexts.find(tc => tc.tabId === tabId); + } + + /** @returns {string|null} */ + getActiveTabNotePath() { + const activeContext = this.getActiveTabContext(); + return activeContext ? activeContext.notePath : null; + } + + /** @return {NoteFull} */ + getActiveTabNote() { + const activeContext = this.getActiveTabContext(); + return activeContext ? activeContext.note : null; + } + + /** @return {string|null} */ + getActiveTabNoteId() { + const activeNote = this.getActiveTabNote(); + + return activeNote ? activeNote.noteId : null; + } + + /** @return {string|null} */ + getActiveTabNoteType() { + const activeNote = this.getActiveTabNote(); + + return activeNote ? activeNote.type : null; + } + + async switchToTab(tabId, notePath) { + const tabContext = this.tabContexts.find(tc => tc.tabId === tabId); + + if (!tabContext) { + await noteDetailService.loadNoteDetail(notePath, { + newTab: true, + activate: true + }); + } else { + await tabContext.activate(); + + if (notePath && tabContext.notePath !== notePath) { + await treeService.activateNote(notePath); + } + } + } + + async showTab(tabId) { + for (const ctx of this.tabContexts) { + if (ctx.tabId === tabId) { + await ctx.show(); + } else { + ctx.hide(); + } + } + + const oldActiveNode = this.getMainNoteTree().getActiveNode(); + + if (oldActiveNode) { + oldActiveNode.setActive(false); + } + + const newActiveTabContext = this.getActiveTabContext(); + + if (newActiveTabContext && newActiveTabContext.notePath) { + const newActiveNode = await this.getMainNoteTree().getNodeFromPath(newActiveTabContext.notePath); + + if (newActiveNode) { + if (!newActiveNode.isVisible()) { + await this.getMainNoteTree().expandToNote(newActiveTabContext.notePath); + } + + newActiveNode.setActive(true, {noEvents: true}); + } + } + } + showWidgets() { const $leftPane = $("#left-pane"); @@ -39,8 +136,68 @@ class AppContext { getMainNoteTree() { return this.noteTreeWidget; } + + getTab(newTab, state) { + if (!this.getActiveTabContext() || newTab) { + // if it's a new tab explicitly by user then it's in background + const ctx = new TabContext(tabRow, state); + this.tabContexts.push(ctx); + + return ctx; + } else { + return this.getActiveTabContext(); + } + } + + async reloadAllTabs() { + for (const tabContext of this.tabContexts) { + await this.reloadTab(tabContext); + } + } + + async refreshTabs(sourceTabId, noteId) { + for (const tc of this.tabContexts) { + if (tc.noteId === noteId && tc.tabId !== sourceTabId) { + await this.reloadTab(tc); + } + } + } + + async reloadTab(tc) { + if (tc.note) { + noteDetailService.reloadNote(tc); + } + } + + async openEmptyTab() { + const ctx = new TabContext(tabRow); + this.tabContexts.push(ctx); + + await tabRow.activateTab(ctx.$tab[0]); + } } const appContext = new AppContext(); +tabRow.addListener('newTab', () => appContext.openEmptyTab()); + +tabRow.addListener('activeTabChange', async ({ detail }) => { + const tabId = detail.tabEl.getAttribute('data-tab-id'); + + await appContext.showTab(tabId); +}); + +tabRow.addListener('tabRemove', async ({ detail }) => { + const tabId = detail.tabEl.getAttribute('data-tab-id'); + + appContext.tabContexts.filter(nc => nc.tabId === tabId) + .forEach(tc => tc.remove()); + + appContext.tabContexts = appContext.tabContexts.filter(nc => nc.tabId !== tabId); + + if (appContext.tabContexts.length === 0) { + appContext.openEmptyTab(); + } +}); + export default appContext; \ No newline at end of file diff --git a/src/public/javascripts/services/entrypoints.js b/src/public/javascripts/services/entrypoints.js index a34749ff7..49f2e7965 100644 --- a/src/public/javascripts/services/entrypoints.js +++ b/src/public/javascripts/services/entrypoints.js @@ -284,6 +284,8 @@ function registerEntrypoints() { searchNotesService.searchInSubtree(node.data.noteId); }); + + keyboardActionService.setGlobalActionHandler('CollapseTree', () => appContext.getMainNoteTree().collapseTree()); } export default { diff --git a/src/public/javascripts/services/frontend_script_api.js b/src/public/javascripts/services/frontend_script_api.js index 9f7ac3ea3..c7aa12839 100644 --- a/src/public/javascripts/services/frontend_script_api.js +++ b/src/public/javascripts/services/frontend_script_api.js @@ -286,7 +286,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte * @method * @returns {Promise} */ - this.refreshAllTabs = noteDetailService.reloadAllTabs; + this.refreshAllTabs = appContext.reloadAllTabs; /** * Create note link (jQuery object) for given note. @@ -309,7 +309,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte * @method * @returns {NoteFull} active note (loaded into right pane) */ - this.getActiveTabNote = noteDetailService.getActiveTabNote; + this.getActiveTabNote = appContext.getActiveTabNote; /** * See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance. @@ -323,7 +323,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte * @method * @returns {Promise} returns note path of active note or null if there isn't active note */ - this.getActiveTabNotePath = noteDetailService.getActiveTabNotePath; + this.getActiveTabNotePath = appContext.getActiveTabNotePath; /** * This method checks whether user navigated away from the note from which the scripts has been started. diff --git a/src/public/javascripts/services/hoisted_note.js b/src/public/javascripts/services/hoisted_note.js index ca5b218b1..7b5265459 100644 --- a/src/public/javascripts/services/hoisted_note.js +++ b/src/public/javascripts/services/hoisted_note.js @@ -30,7 +30,7 @@ async function setHoistedNoteId(noteId) { await tree.reload(); - const activeTabContext = noteDetailService.getActiveTabContext(); + const activeTabContext = appContext.getActiveTabContext(); if (activeTabContext) { await tree.activateNote(activeTabContext.notePath); diff --git a/src/public/javascripts/services/note_autocomplete.js b/src/public/javascripts/services/note_autocomplete.js index 3a2d4acd1..231300601 100644 --- a/src/public/javascripts/services/note_autocomplete.js +++ b/src/public/javascripts/services/note_autocomplete.js @@ -8,7 +8,7 @@ const SELECTED_PATH_KEY = "data-note-path"; async function autocompleteSource(term, cb) { const result = await server.get('autocomplete' + '?query=' + encodeURIComponent(term) - + '&activeNoteId=' + noteDetailService.getActiveTabNoteId()); + + '&activeNoteId=' + appContext.getActiveTabNoteId()); if (result.length === 0) { result.push({ diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js index 835c66880..2c48ef98d 100644 --- a/src/public/javascripts/services/note_detail.js +++ b/src/public/javascripts/services/note_detail.js @@ -4,7 +4,6 @@ import server from './server.js'; import ws from "./ws.js"; import treeCache from "./tree_cache.js"; import NoteFull from "../entities/note_full.js"; -import utils from "./utils.js"; import contextMenuService from "./context_menu.js"; import treeUtils from "./tree_utils.js"; import tabRow from "./tab_row.js"; @@ -19,21 +18,13 @@ let detailLoadedListeners = []; async function reload() { // no saving here - await loadNoteDetail(getActiveTabContext().notePath); + await loadNoteDetail(appContext.getActiveTabNotePath()); } -async function reloadTab(tabContext) { - if (tabContext.note) { - const note = await loadNote(tabContext.note.noteId); +async function reloadNote(tabContext) { + const note = await loadNote(tabContext.note.noteId); - await loadNoteDetailToContext(tabContext, note, tabContext.notePath); - } -} - -async function reloadAllTabs() { - for (const tabContext of tabContexts) { - await reloadTab(tabContext); - } + await loadNoteDetailToContext(tabContext, note, tabContext.notePath); } async function openInTab(notePath, activate) { @@ -53,7 +44,7 @@ function onNoteChange(func) { } async function saveNotesIfChanged() { - for (const ctx of tabContexts) { + for (const ctx of appContext.getTabContexts()) { await ctx.saveNoteIfChanged(); } @@ -61,9 +52,6 @@ async function saveNotesIfChanged() { $savedIndicator.fadeIn(); } -/** @type {TabContext[]} */ -let tabContexts = []; - function getActiveEditor() { const activeTabContext = getActiveTabContext(); @@ -91,98 +79,6 @@ async function activateOrOpenNote(noteId) { }); } -/** @return {TabContext[]} */ -function getTabContexts() { - return tabContexts; -} - -/** @returns {TabContext} */ -function getActiveTabContext() { - const activeTabEl = tabRow.activeTabEl; - - if (!activeTabEl) { - return null; - } - - const tabId = activeTabEl.getAttribute('data-tab-id'); - - return tabContexts.find(tc => tc.tabId === tabId); -} - -/** @returns {string|null} */ -function getActiveTabNotePath() { - const activeContext = getActiveTabContext(); - return activeContext ? activeContext.notePath : null; -} - -/** @return {NoteFull} */ -function getActiveTabNote() { - const activeContext = getActiveTabContext(); - return activeContext ? activeContext.note : null; -} - -/** @return {string|null} */ -function getActiveTabNoteId() { - const activeNote = getActiveTabNote(); - - return activeNote ? activeNote.noteId : null; -} - -/** @return {string|null} */ -function getActiveTabNoteType() { - const activeNote = getActiveTabNote(); - - return activeNote ? activeNote.type : null; -} - -async function switchToTab(tabId, notePath) { - const tabContext = tabContexts.find(tc => tc.tabId === tabId); - - if (!tabContext) { - await loadNoteDetail(notePath, { - newTab: true, - activate: true - }); - } else { - await tabContext.activate(); - - if (notePath && tabContext.notePath !== notePath) { - await treeService.activateNote(notePath); - } - } -} - -async function showTab(tabId) { - for (const ctx of tabContexts) { - if (ctx.tabId === tabId) { - await ctx.show(); - } - else { - ctx.hide(); - } - } - - const oldActiveNode = appContext.getMainNoteTree().getActiveNode(); - - if (oldActiveNode) { - oldActiveNode.setActive(false); - } - - const newActiveTabContext = getActiveTabContext(); - - if (newActiveTabContext && newActiveTabContext.notePath) { - const newActiveNode = await appContext.getMainNoteTree().getNodeFromPath(newActiveTabContext.notePath); - - if (newActiveNode) { - if (!newActiveNode.isVisible()) { - await appContext.getMainNoteTree().expandToNote(newActiveTabContext.notePath); - } - - newActiveNode.setActive(true, {noEvents: true}); - } - } -} - /** * @param {TabContext} ctx * @param {NoteFull} note @@ -211,16 +107,7 @@ async function loadNoteDetail(origNotePath, options = {}) { const noteId = treeUtils.getNoteIdFromNotePath(notePath); const loadedNote = await loadNote(noteId); - let ctx; - - if (!getActiveTabContext() || newTab) { - // if it's a new tab explicitly by user then it's in background - ctx = new TabContext(tabRow, options.state); - tabContexts.push(ctx); - } - else { - ctx = getActiveTabContext(); - } + const ctx = appContext.getTab(newTab, options.state); // we will try to render the new note only if it's still the active one in the tree // this is useful when user quickly switches notes (by e.g. holding down arrow) so that we don't @@ -281,14 +168,6 @@ async function noteDeleted(noteId) { } } -async function refreshTabs(sourceTabId, noteId) { - for (const tc of tabContexts) { - if (tc.noteId === noteId && tc.tabId !== sourceTabId) { - await reloadTab(tc); - } - } -} - function focusOnTitle() { getActiveTabContext().$noteTitle.trigger('focus'); } @@ -337,12 +216,12 @@ ws.subscribeToOutsideSyncMessages(syncData => { .forEach(sync => noteIdsToRefresh.add(sync.noteId)); for (const noteId of noteIdsToRefresh) { - refreshTabs(null, noteId); + appContext.refreshTabs(null, noteId); } }); ws.subscribeToAllSyncMessages(syncData => { - for (const tc of tabContexts) { + for (const tc of appContext.tabContexts) { tc.eventReceived('syncData', syncData); } }); @@ -371,34 +250,6 @@ $tabContentsContainer.on("drop", async e => { }); }); -async function openEmptyTab() { - const ctx = new TabContext(tabRow); - tabContexts.push(ctx); - - await tabRow.activateTab(ctx.$tab[0]); -} - -tabRow.addListener('newTab', openEmptyTab); - -tabRow.addListener('activeTabChange', async ({ detail }) => { - const tabId = detail.tabEl.getAttribute('data-tab-id'); - - await showTab(tabId); -}); - -tabRow.addListener('tabRemove', async ({ detail }) => { - const tabId = detail.tabEl.getAttribute('data-tab-id'); - - tabContexts.filter(nc => nc.tabId === tabId) - .forEach(tc => tc.remove()); - - tabContexts = tabContexts.filter(nc => nc.tabId !== tabId); - - if (tabContexts.length === 0) { - openEmptyTab(); - } -}); - $(tabRow.el).on('contextmenu', '.note-tab', e => { e.preventDefault(); @@ -473,7 +324,7 @@ async function saveOpenTabs() { for (const tabEl of tabRow.tabEls) { const tabId = tabEl.getAttribute('data-tab-id'); - const tabContext = tabContexts.find(tc => tc.tabId === tabId); + const tabContext = appContext.getTabContexts().find(tc => tc.tabId === tabId); if (tabContext) { const tabState = tabContext.getTabState(); @@ -505,7 +356,6 @@ setInterval(saveNotesIfChanged, 3000); export default { reload, - reloadAllTabs, openInTab, switchToNote, loadNote, @@ -515,20 +365,12 @@ export default { saveNotesIfChanged, onNoteChange, addDetailLoadedListener, - switchToTab, - getTabContexts, - getActiveTabContext, - getActiveTabNotePath, - getActiveTabNote, - getActiveTabNoteType, - getActiveTabNoteId, getActiveEditor, activateOrOpenNote, clearOpenTabsTask, filterTabs, - openEmptyTab, noteDeleted, - refreshTabs, noteChanged, - openTabsChanged + openTabsChanged, + reloadNote }; \ No newline at end of file diff --git a/src/public/javascripts/services/protected_session.js b/src/public/javascripts/services/protected_session.js index 168ff3b27..31d5db4e6 100644 --- a/src/public/javascripts/services/protected_session.js +++ b/src/public/javascripts/services/protected_session.js @@ -5,6 +5,7 @@ import server from './server.js'; import protectedSessionHolder from './protected_session_holder.js'; import toastService from "./toast.js"; import ws from "./ws.js"; +import appContext from "./app_context.js"; const $enterProtectedSessionButton = $("#enter-protected-session-button"); const $leaveProtectedSessionButton = $("#leave-protected-session-button"); @@ -50,7 +51,7 @@ async function setupProtectedSession(password) { await treeService.reload(); // it's important that tree has been already reloaded at this point since detail also uses tree cache (for book) - await noteDetailService.reloadAllTabs(); + await appContext.reloadAllTabs(); if (protectedSessionDeferred !== null) { import("../dialogs/protected_session.js").then(dialog => dialog.close()); @@ -72,16 +73,16 @@ async function enterProtectedSessionOnServer(password) { } async function protectNoteAndSendToServer() { - if (!noteDetailService.getActiveTabNote() || noteDetailService.getActiveTabNote().isProtected) { + if (!appContext.getActiveTabNote() || appContext.getActiveTabNote().isProtected) { return; } await enterProtectedSession(); - const note = noteDetailService.getActiveTabNote(); + const note = appContext.getActiveTabNote(); note.isProtected = true; - await noteDetailService.getActiveTabContext().saveNote(); + await appContext.getActiveTabContext().saveNote(); treeService.setProtected(note.noteId, note.isProtected); @@ -89,7 +90,7 @@ async function protectNoteAndSendToServer() { } async function unprotectNoteAndSendToServer() { - const activeNote = noteDetailService.getActiveTabNote(); + const activeNote = appContext.getActiveTabNote(); if (!activeNote.isProtected) { toastService.showAndLogError(`Note ${activeNote.noteId} is not protected`); @@ -108,7 +109,7 @@ async function unprotectNoteAndSendToServer() { activeNote.isProtected = false; - await noteDetailService.getActiveTabContext().saveNote(); + await appContext.getActiveTabContext().saveNote(); treeService.setProtected(activeNote.noteId, activeNote.isProtected); diff --git a/src/public/javascripts/services/sidebar.js b/src/public/javascripts/services/sidebar.js index 24bf629c4..d2639d7f7 100644 --- a/src/public/javascripts/services/sidebar.js +++ b/src/public/javascripts/services/sidebar.js @@ -38,7 +38,7 @@ $showSidebarButton.on('click', async () => { await server.put('options/rightPaneVisible/true'); - const {sidebar} = noteDetailService.getActiveTabContext(); + const {sidebar} = appContext.getActiveTabContext(); await sidebar.noteLoaded(); sidebar.show(); }); diff --git a/src/public/javascripts/services/tab_context.js b/src/public/javascripts/services/tab_context.js index 74c885c17..1c52f8d2b 100644 --- a/src/public/javascripts/services/tab_context.js +++ b/src/public/javascripts/services/tab_context.js @@ -11,6 +11,7 @@ import protectedSessionService from "./protected_session.js"; import optionsService from "./options.js"; import linkService from "./link.js"; import Sidebar from "./sidebar.js"; +import appContext from "./app_context.js"; const $tabContentsContainer = $("#note-tab-container"); @@ -360,7 +361,7 @@ class TabContext { if (this.isNoteChanged) { await this.saveNote(); - noteDetailService.refreshTabs(this.tabId, this.note.noteId); + appContext.refreshTabs(this.tabId, this.note.noteId); } } diff --git a/src/public/javascripts/services/tree.js b/src/public/javascripts/services/tree.js index e6ee1e466..2414ec6d7 100644 --- a/src/public/javascripts/services/tree.js +++ b/src/public/javascripts/services/tree.js @@ -215,7 +215,7 @@ function getSelectedNodes(stopOnParents = false) { } async function treeInitialized() { - if (noteDetailService.getTabContexts().length > 0) { + if (appContext.getTabContexts().length > 0) { // this is just tree reload - tabs are already in place return; } @@ -369,7 +369,7 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) { extraOptions.isProtected = false; } - if (noteDetailService.getActiveTabNoteType() !== 'text') { + if (appContext.getActiveTabNoteType() !== 'text') { extraOptions.saveSelection = false; } @@ -560,31 +560,10 @@ async function reloadNotes(noteIds, activateNotePath = null) { await treeCache.reloadNotes(noteIds); if (!activateNotePath) { - activateNotePath = noteDetailService.getActiveTabNotePath(); + activateNotePath = appContext.getActiveTabNotePath(); } - for (const noteId of noteIds) { - for (const node of appContext.getMainNoteTree().getNodesByNoteId(noteId)) { - const branch = treeCache.getBranch(node.data.branchId, true); - - if (!branch) { - node.remove(); - } - else { - await node.load(true); - - await appContext.getMainNoteTree().checkFolderStatus(node); - } - } - } - - if (activateNotePath) { - const node = await appContext.getMainNoteTree().getNodeFromPath(activateNotePath); - - if (node && !node.isActive()) { - await node.setActive(true); - } - } + appContext.trigger('notesReloaded', { noteIds, activateNotePath }); } window.glob.cutIntoNote = () => createNoteInto(true); @@ -599,7 +578,7 @@ $(window).bind('hashchange', async function() { if (isNotePathInAddress()) { const [notePath, tabId] = getHashValueFromAddress(); - noteDetailService.switchToTab(tabId, notePath); + appContext.switchToTab(tabId, notePath); } }); diff --git a/src/public/javascripts/widgets/note_tree.js b/src/public/javascripts/widgets/note_tree.js index 9eb8e6913..8f3129841 100644 --- a/src/public/javascripts/widgets/note_tree.js +++ b/src/public/javascripts/widgets/note_tree.js @@ -1,7 +1,6 @@ import BasicWidget from "./basic_widget.js"; import hoistedNoteService from "../services/hoisted_note.js"; import searchNotesService from "../services/search_notes.js"; -import keyboardActionService from "../services/keyboard_actions.js"; import treeService from "../services/tree.js"; import treeUtils from "../services/tree_utils.js"; import noteDetailService from "../services/note_detail.js"; @@ -13,10 +12,11 @@ import treeBuilder from "../services/tree_builder.js"; import TreeContextMenu from "../services/tree_context_menu.js"; import treeChangesService from "../services/branches.js"; import ws from "../services/ws.js"; +import appContext from "../services/app_context.js"; const TPL = ` -
+
`; export default class NoteTreeWidget extends BasicWidget { @@ -39,7 +39,7 @@ export default class NoteTreeWidget extends BasicWidget { async doRender($widget) { $widget.append($(TPL)); - const $tree = $widget.find('#tree'); + const $tree = $widget.find('.tree'); const treeData = await treeService.loadTreeData(); @@ -48,9 +48,6 @@ export default class NoteTreeWidget extends BasicWidget { $tree.on("click", ".unhoist-button", hoistedNoteService.unhoist); $tree.on("click", ".refresh-search-button", searchNotesService.refreshSearch); - // FIXME this does not belong here ... - keyboardActionService.setGlobalActionHandler('CollapseTree', () => this.collapseTree()); // don't use shortened form since collapseTree() accepts argument - // fancytree doesn't support middle click so this is a way to support it $widget.on('mousedown', '.fancytree-title', e => { if (e.which === 2) { @@ -154,7 +151,7 @@ export default class NoteTreeWidget extends BasicWidget { if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) { const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation - const importService = await import('./import.js'); + const importService = await import('../services/import.js'); importService.uploadFiles(node.data.noteId, files, { safeImport: true, @@ -231,7 +228,7 @@ export default class NoteTreeWidget extends BasicWidget { return false; // blocks default browser right click menu }); - this.tree = $.ui.fancytree.getTree("#tree"); + this.tree = $.ui.fancytree.getTree($tree); } /** @return {FancytreeNode[]} */ @@ -286,7 +283,7 @@ export default class NoteTreeWidget extends BasicWidget { // FIXME since this operates on note details tab context it seems it does not really belong here async scrollToActiveNote() { - const activeContext = noteDetailService.getActiveTabContext(); + const activeContext = appContext.getActiveTabContext(); if (activeContext && activeContext.notePath) { this.tree.setFocus(); @@ -405,4 +402,29 @@ export default class NoteTreeWidget extends BasicWidget { createTopLevelNoteListener() { treeService.createNewTopLevelNote(); } collapseTreeListener() { this.collapseTree(); } + + async notesReloadedListener({ noteIds, activateNotePath }) { + for (const noteId of noteIds) { + for (const node of this.getNodesByNoteId(noteId)) { + const branch = treeCache.getBranch(node.data.branchId, true); + + if (!branch) { + node.remove(); + } + else { + await node.load(true); + + await this.checkFolderStatus(node); + } + } + } + + if (activateNotePath) { + const node = await this.getNodeFromPath(activateNotePath); + + if (node && !node.isActive()) { + await node.setActive(true); + } + } + } } \ No newline at end of file diff --git a/src/public/stylesheets/mobile.css b/src/public/stylesheets/mobile.css index b97088011..b6f9a1c18 100644 --- a/src/public/stylesheets/mobile.css +++ b/src/public/stylesheets/mobile.css @@ -23,12 +23,12 @@ html, body { margin: 0 10px 0 16px; } -#tree { +.tree { width: 100%; overflow: auto; } -#tree .action-button { +.tree .action-button { position: relative; top: -5px; margin-left: 10px;