moved tab management to app context

This commit is contained in:
zadam 2020-01-12 12:30:30 +01:00
parent 61474defff
commit 5e11840137
19 changed files with 235 additions and 231 deletions

View File

@ -61,7 +61,7 @@ window.glob.noteChanged = noteDetailService.noteChanged;
window.glob.refreshTree = treeService.reload; window.glob.refreshTree = treeService.reload;
// required for ESLint plugin // required for ESLint plugin
window.glob.getActiveTabNote = noteDetailService.getActiveTabNote; window.glob.getActiveTabNote = appContext.getActiveTabNote;
window.glob.requireLibrary = libraryLoader.requireLibrary; window.glob.requireLibrary = libraryLoader.requireLibrary;
window.glob.ESLINT = libraryLoader.ESLINT; window.glob.ESLINT = libraryLoader.ESLINT;
@ -145,7 +145,7 @@ async function printActiveNote() {
return; return;
} }
const $tabContext = noteDetailService.getActiveTabContext(); const $tabContext = appContext.getActiveTabContext();
if (!$tabContext) { if (!$tabContext) {
return; return;
} }

View File

@ -93,7 +93,7 @@ function AttributesModel() {
} }
this.loadAttributes = async function() { this.loadAttributes = async function() {
const noteId = noteDetailService.getActiveTabNoteId(); const noteId = appContext.getActiveTabNoteId();
const attributes = await server.get('notes/' + noteId + '/attributes'); const attributes = await server.get('notes/' + noteId + '/attributes');
@ -139,7 +139,7 @@ function AttributesModel() {
self.updateAttributePositions(); self.updateAttributePositions();
const noteId = noteDetailService.getActiveTabNoteId(); const noteId = appContext.getActiveTabNoteId();
const attributesToSave = self.ownedAttributes() const attributesToSave = self.ownedAttributes()
.map(attribute => attribute()) .map(attribute => attribute())
@ -171,7 +171,7 @@ function AttributesModel() {
toastService.showMessage("Attributes have been saved."); toastService.showMessage("Attributes have been saved.");
const ctx = noteDetailService.getActiveTabContext(); const ctx = appContext.getActiveTabContext();
ctx.attributes.refreshAttributes(); ctx.attributes.refreshAttributes();

View File

@ -31,7 +31,7 @@ export async function showDialog() {
} }
$dialog.on('shown.bs.modal', () => { $dialog.on('shown.bs.modal', () => {
const note = noteDetailService.getActiveTabNote(); const note = appContext.getActiveTabNote();
linkMapService = new LinkMapService(note, $linkMapContainer, getOptions()); linkMapService = new LinkMapService(note, $linkMapContainer, getOptions());
linkMapService.render(); linkMapService.render();

View File

@ -26,7 +26,7 @@ async function convertMarkdownToHtml(text) {
} }
export async function importMarkdownInline() { export async function importMarkdownInline() {
if (noteDetailService.getActiveTabNoteType() !== 'text') { if (appContext.getActiveTabNoteType() !== 'text') {
return; return;
} }

View File

@ -16,7 +16,7 @@ export function showDialog() {
$dialog.modal(); $dialog.modal();
const activeNote = noteDetailService.getActiveTabNote(); const activeNote = appContext.getActiveTabNote();
$noteId.text(activeNote.noteId); $noteId.text(activeNote.noteId);
$dateCreated.text(activeNote.dateCreated); $dateCreated.text(activeNote.dateCreated);

View File

@ -25,7 +25,7 @@ let note;
let noteRevisionId; let noteRevisionId;
export async function showCurrentNoteRevisions() { export async function showCurrentNoteRevisions() {
await showNoteRevisionsDialog(noteDetailService.getActiveTabNoteId()); await showNoteRevisionsDialog(appContext.getActiveTabNoteId());
} }
export async function showNoteRevisionsDialog(noteId, noteRevisionId) { export async function showNoteRevisionsDialog(noteId, noteRevisionId) {
@ -42,7 +42,7 @@ async function loadNoteRevisions(noteId, noteRevId) {
$list.empty(); $list.empty();
$content.empty(); $content.empty();
note = noteDetailService.getActiveTabNote(); note = appContext.getActiveTabNote();
revisionItems = await server.get(`notes/${noteId}/revisions`); revisionItems = await server.get(`notes/${noteId}/revisions`);
for (const item of revisionItems) { for (const item of revisionItems) {

View File

@ -11,7 +11,7 @@ export function showDialog() {
$dialog.modal(); $dialog.modal();
const noteText = noteDetailService.getActiveTabNote().content; const noteText = appContext.getActiveTabNote().content;
$noteSource.text(formatHtml(noteText)); $noteSource.text(formatHtml(noteText));
} }

View File

@ -2,10 +2,16 @@ import GlobalButtonsWidget from "../widgets/global_buttons.js";
import SearchBoxWidget from "../widgets/search_box.js"; import SearchBoxWidget from "../widgets/search_box.js";
import SearchResultsWidget from "../widgets/search_results.js"; import SearchResultsWidget from "../widgets/search_results.js";
import NoteTreeWidget from "../widgets/note_tree.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 { class AppContext {
constructor() { constructor() {
this.widgets = []; this.widgets = [];
/** @type {TabContext[]} */
this.tabContexts = [];
} }
trigger(name, data) { 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() { showWidgets() {
const $leftPane = $("#left-pane"); const $leftPane = $("#left-pane");
@ -39,8 +136,68 @@ class AppContext {
getMainNoteTree() { getMainNoteTree() {
return this.noteTreeWidget; 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(); 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; export default appContext;

View File

@ -284,6 +284,8 @@ function registerEntrypoints() {
searchNotesService.searchInSubtree(node.data.noteId); searchNotesService.searchInSubtree(node.data.noteId);
}); });
keyboardActionService.setGlobalActionHandler('CollapseTree', () => appContext.getMainNoteTree().collapseTree());
} }
export default { export default {

View File

@ -286,7 +286,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
* @method * @method
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
this.refreshAllTabs = noteDetailService.reloadAllTabs; this.refreshAllTabs = appContext.reloadAllTabs;
/** /**
* Create note link (jQuery object) for given note. * Create note link (jQuery object) for given note.
@ -309,7 +309,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
* @method * @method
* @returns {NoteFull} active note (loaded into right pane) * @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. * 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 * @method
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note * @returns {Promise<string|null>} 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. * This method checks whether user navigated away from the note from which the scripts has been started.

View File

@ -30,7 +30,7 @@ async function setHoistedNoteId(noteId) {
await tree.reload(); await tree.reload();
const activeTabContext = noteDetailService.getActiveTabContext(); const activeTabContext = appContext.getActiveTabContext();
if (activeTabContext) { if (activeTabContext) {
await tree.activateNote(activeTabContext.notePath); await tree.activateNote(activeTabContext.notePath);

View File

@ -8,7 +8,7 @@ const SELECTED_PATH_KEY = "data-note-path";
async function autocompleteSource(term, cb) { async function autocompleteSource(term, cb) {
const result = await server.get('autocomplete' const result = await server.get('autocomplete'
+ '?query=' + encodeURIComponent(term) + '?query=' + encodeURIComponent(term)
+ '&activeNoteId=' + noteDetailService.getActiveTabNoteId()); + '&activeNoteId=' + appContext.getActiveTabNoteId());
if (result.length === 0) { if (result.length === 0) {
result.push({ result.push({

View File

@ -4,7 +4,6 @@ import server from './server.js';
import ws from "./ws.js"; import ws from "./ws.js";
import treeCache from "./tree_cache.js"; import treeCache from "./tree_cache.js";
import NoteFull from "../entities/note_full.js"; import NoteFull from "../entities/note_full.js";
import utils from "./utils.js";
import contextMenuService from "./context_menu.js"; import contextMenuService from "./context_menu.js";
import treeUtils from "./tree_utils.js"; import treeUtils from "./tree_utils.js";
import tabRow from "./tab_row.js"; import tabRow from "./tab_row.js";
@ -19,21 +18,13 @@ let detailLoadedListeners = [];
async function reload() { async function reload() {
// no saving here // no saving here
await loadNoteDetail(getActiveTabContext().notePath); await loadNoteDetail(appContext.getActiveTabNotePath());
} }
async function reloadTab(tabContext) { async function reloadNote(tabContext) {
if (tabContext.note) { const note = await loadNote(tabContext.note.noteId);
const note = await loadNote(tabContext.note.noteId);
await loadNoteDetailToContext(tabContext, note, tabContext.notePath); await loadNoteDetailToContext(tabContext, note, tabContext.notePath);
}
}
async function reloadAllTabs() {
for (const tabContext of tabContexts) {
await reloadTab(tabContext);
}
} }
async function openInTab(notePath, activate) { async function openInTab(notePath, activate) {
@ -53,7 +44,7 @@ function onNoteChange(func) {
} }
async function saveNotesIfChanged() { async function saveNotesIfChanged() {
for (const ctx of tabContexts) { for (const ctx of appContext.getTabContexts()) {
await ctx.saveNoteIfChanged(); await ctx.saveNoteIfChanged();
} }
@ -61,9 +52,6 @@ async function saveNotesIfChanged() {
$savedIndicator.fadeIn(); $savedIndicator.fadeIn();
} }
/** @type {TabContext[]} */
let tabContexts = [];
function getActiveEditor() { function getActiveEditor() {
const activeTabContext = getActiveTabContext(); 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 {TabContext} ctx
* @param {NoteFull} note * @param {NoteFull} note
@ -211,16 +107,7 @@ async function loadNoteDetail(origNotePath, options = {}) {
const noteId = treeUtils.getNoteIdFromNotePath(notePath); const noteId = treeUtils.getNoteIdFromNotePath(notePath);
const loadedNote = await loadNote(noteId); const loadedNote = await loadNote(noteId);
let ctx; const ctx = appContext.getTab(newTab, options.state);
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();
}
// we will try to render the new note only if it's still the active one in the tree // 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 // 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() { function focusOnTitle() {
getActiveTabContext().$noteTitle.trigger('focus'); getActiveTabContext().$noteTitle.trigger('focus');
} }
@ -337,12 +216,12 @@ ws.subscribeToOutsideSyncMessages(syncData => {
.forEach(sync => noteIdsToRefresh.add(sync.noteId)); .forEach(sync => noteIdsToRefresh.add(sync.noteId));
for (const noteId of noteIdsToRefresh) { for (const noteId of noteIdsToRefresh) {
refreshTabs(null, noteId); appContext.refreshTabs(null, noteId);
} }
}); });
ws.subscribeToAllSyncMessages(syncData => { ws.subscribeToAllSyncMessages(syncData => {
for (const tc of tabContexts) { for (const tc of appContext.tabContexts) {
tc.eventReceived('syncData', syncData); 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 => { $(tabRow.el).on('contextmenu', '.note-tab', e => {
e.preventDefault(); e.preventDefault();
@ -473,7 +324,7 @@ async function saveOpenTabs() {
for (const tabEl of tabRow.tabEls) { for (const tabEl of tabRow.tabEls) {
const tabId = tabEl.getAttribute('data-tab-id'); 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) { if (tabContext) {
const tabState = tabContext.getTabState(); const tabState = tabContext.getTabState();
@ -505,7 +356,6 @@ setInterval(saveNotesIfChanged, 3000);
export default { export default {
reload, reload,
reloadAllTabs,
openInTab, openInTab,
switchToNote, switchToNote,
loadNote, loadNote,
@ -515,20 +365,12 @@ export default {
saveNotesIfChanged, saveNotesIfChanged,
onNoteChange, onNoteChange,
addDetailLoadedListener, addDetailLoadedListener,
switchToTab,
getTabContexts,
getActiveTabContext,
getActiveTabNotePath,
getActiveTabNote,
getActiveTabNoteType,
getActiveTabNoteId,
getActiveEditor, getActiveEditor,
activateOrOpenNote, activateOrOpenNote,
clearOpenTabsTask, clearOpenTabsTask,
filterTabs, filterTabs,
openEmptyTab,
noteDeleted, noteDeleted,
refreshTabs,
noteChanged, noteChanged,
openTabsChanged openTabsChanged,
reloadNote
}; };

View File

@ -5,6 +5,7 @@ import server from './server.js';
import protectedSessionHolder from './protected_session_holder.js'; import protectedSessionHolder from './protected_session_holder.js';
import toastService from "./toast.js"; import toastService from "./toast.js";
import ws from "./ws.js"; import ws from "./ws.js";
import appContext from "./app_context.js";
const $enterProtectedSessionButton = $("#enter-protected-session-button"); const $enterProtectedSessionButton = $("#enter-protected-session-button");
const $leaveProtectedSessionButton = $("#leave-protected-session-button"); const $leaveProtectedSessionButton = $("#leave-protected-session-button");
@ -50,7 +51,7 @@ async function setupProtectedSession(password) {
await treeService.reload(); await treeService.reload();
// it's important that tree has been already reloaded at this point since detail also uses tree cache (for book) // 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) { if (protectedSessionDeferred !== null) {
import("../dialogs/protected_session.js").then(dialog => dialog.close()); import("../dialogs/protected_session.js").then(dialog => dialog.close());
@ -72,16 +73,16 @@ async function enterProtectedSessionOnServer(password) {
} }
async function protectNoteAndSendToServer() { async function protectNoteAndSendToServer() {
if (!noteDetailService.getActiveTabNote() || noteDetailService.getActiveTabNote().isProtected) { if (!appContext.getActiveTabNote() || appContext.getActiveTabNote().isProtected) {
return; return;
} }
await enterProtectedSession(); await enterProtectedSession();
const note = noteDetailService.getActiveTabNote(); const note = appContext.getActiveTabNote();
note.isProtected = true; note.isProtected = true;
await noteDetailService.getActiveTabContext().saveNote(); await appContext.getActiveTabContext().saveNote();
treeService.setProtected(note.noteId, note.isProtected); treeService.setProtected(note.noteId, note.isProtected);
@ -89,7 +90,7 @@ async function protectNoteAndSendToServer() {
} }
async function unprotectNoteAndSendToServer() { async function unprotectNoteAndSendToServer() {
const activeNote = noteDetailService.getActiveTabNote(); const activeNote = appContext.getActiveTabNote();
if (!activeNote.isProtected) { if (!activeNote.isProtected) {
toastService.showAndLogError(`Note ${activeNote.noteId} is not protected`); toastService.showAndLogError(`Note ${activeNote.noteId} is not protected`);
@ -108,7 +109,7 @@ async function unprotectNoteAndSendToServer() {
activeNote.isProtected = false; activeNote.isProtected = false;
await noteDetailService.getActiveTabContext().saveNote(); await appContext.getActiveTabContext().saveNote();
treeService.setProtected(activeNote.noteId, activeNote.isProtected); treeService.setProtected(activeNote.noteId, activeNote.isProtected);

View File

@ -38,7 +38,7 @@ $showSidebarButton.on('click', async () => {
await server.put('options/rightPaneVisible/true'); await server.put('options/rightPaneVisible/true');
const {sidebar} = noteDetailService.getActiveTabContext(); const {sidebar} = appContext.getActiveTabContext();
await sidebar.noteLoaded(); await sidebar.noteLoaded();
sidebar.show(); sidebar.show();
}); });

View File

@ -11,6 +11,7 @@ import protectedSessionService from "./protected_session.js";
import optionsService from "./options.js"; import optionsService from "./options.js";
import linkService from "./link.js"; import linkService from "./link.js";
import Sidebar from "./sidebar.js"; import Sidebar from "./sidebar.js";
import appContext from "./app_context.js";
const $tabContentsContainer = $("#note-tab-container"); const $tabContentsContainer = $("#note-tab-container");
@ -360,7 +361,7 @@ class TabContext {
if (this.isNoteChanged) { if (this.isNoteChanged) {
await this.saveNote(); await this.saveNote();
noteDetailService.refreshTabs(this.tabId, this.note.noteId); appContext.refreshTabs(this.tabId, this.note.noteId);
} }
} }

View File

@ -215,7 +215,7 @@ function getSelectedNodes(stopOnParents = false) {
} }
async function treeInitialized() { async function treeInitialized() {
if (noteDetailService.getTabContexts().length > 0) { if (appContext.getTabContexts().length > 0) {
// this is just tree reload - tabs are already in place // this is just tree reload - tabs are already in place
return; return;
} }
@ -369,7 +369,7 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
extraOptions.isProtected = false; extraOptions.isProtected = false;
} }
if (noteDetailService.getActiveTabNoteType() !== 'text') { if (appContext.getActiveTabNoteType() !== 'text') {
extraOptions.saveSelection = false; extraOptions.saveSelection = false;
} }
@ -560,31 +560,10 @@ async function reloadNotes(noteIds, activateNotePath = null) {
await treeCache.reloadNotes(noteIds); await treeCache.reloadNotes(noteIds);
if (!activateNotePath) { if (!activateNotePath) {
activateNotePath = noteDetailService.getActiveTabNotePath(); activateNotePath = appContext.getActiveTabNotePath();
} }
for (const noteId of noteIds) { appContext.trigger('notesReloaded', { noteIds, activateNotePath });
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);
}
}
} }
window.glob.cutIntoNote = () => createNoteInto(true); window.glob.cutIntoNote = () => createNoteInto(true);
@ -599,7 +578,7 @@ $(window).bind('hashchange', async function() {
if (isNotePathInAddress()) { if (isNotePathInAddress()) {
const [notePath, tabId] = getHashValueFromAddress(); const [notePath, tabId] = getHashValueFromAddress();
noteDetailService.switchToTab(tabId, notePath); appContext.switchToTab(tabId, notePath);
} }
}); });

View File

@ -1,7 +1,6 @@
import BasicWidget from "./basic_widget.js"; import BasicWidget from "./basic_widget.js";
import hoistedNoteService from "../services/hoisted_note.js"; import hoistedNoteService from "../services/hoisted_note.js";
import searchNotesService from "../services/search_notes.js"; import searchNotesService from "../services/search_notes.js";
import keyboardActionService from "../services/keyboard_actions.js";
import treeService from "../services/tree.js"; import treeService from "../services/tree.js";
import treeUtils from "../services/tree_utils.js"; import treeUtils from "../services/tree_utils.js";
import noteDetailService from "../services/note_detail.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 TreeContextMenu from "../services/tree_context_menu.js";
import treeChangesService from "../services/branches.js"; import treeChangesService from "../services/branches.js";
import ws from "../services/ws.js"; import ws from "../services/ws.js";
import appContext from "../services/app_context.js";
const TPL = ` const TPL = `
<style> <style>
#tree { .tree {
overflow: auto; overflow: auto;
flex-grow: 1; flex-grow: 1;
flex-shrink: 1; flex-shrink: 1;
@ -26,7 +26,7 @@ const TPL = `
} }
</style> </style>
<div id="tree"></div> <div class="tree"></div>
`; `;
export default class NoteTreeWidget extends BasicWidget { export default class NoteTreeWidget extends BasicWidget {
@ -39,7 +39,7 @@ export default class NoteTreeWidget extends BasicWidget {
async doRender($widget) { async doRender($widget) {
$widget.append($(TPL)); $widget.append($(TPL));
const $tree = $widget.find('#tree'); const $tree = $widget.find('.tree');
const treeData = await treeService.loadTreeData(); 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", ".unhoist-button", hoistedNoteService.unhoist);
$tree.on("click", ".refresh-search-button", searchNotesService.refreshSearch); $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 // fancytree doesn't support middle click so this is a way to support it
$widget.on('mousedown', '.fancytree-title', e => { $widget.on('mousedown', '.fancytree-title', e => {
if (e.which === 2) { if (e.which === 2) {
@ -154,7 +151,7 @@ export default class NoteTreeWidget extends BasicWidget {
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) { if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation 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, { importService.uploadFiles(node.data.noteId, files, {
safeImport: true, safeImport: true,
@ -231,7 +228,7 @@ export default class NoteTreeWidget extends BasicWidget {
return false; // blocks default browser right click menu return false; // blocks default browser right click menu
}); });
this.tree = $.ui.fancytree.getTree("#tree"); this.tree = $.ui.fancytree.getTree($tree);
} }
/** @return {FancytreeNode[]} */ /** @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 // FIXME since this operates on note details tab context it seems it does not really belong here
async scrollToActiveNote() { async scrollToActiveNote() {
const activeContext = noteDetailService.getActiveTabContext(); const activeContext = appContext.getActiveTabContext();
if (activeContext && activeContext.notePath) { if (activeContext && activeContext.notePath) {
this.tree.setFocus(); this.tree.setFocus();
@ -405,4 +402,29 @@ export default class NoteTreeWidget extends BasicWidget {
createTopLevelNoteListener() { treeService.createNewTopLevelNote(); } createTopLevelNoteListener() { treeService.createNewTopLevelNote(); }
collapseTreeListener() { this.collapseTree(); } 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);
}
}
}
} }

View File

@ -23,12 +23,12 @@ html, body {
margin: 0 10px 0 16px; margin: 0 10px 0 16px;
} }
#tree { .tree {
width: 100%; width: 100%;
overflow: auto; overflow: auto;
} }
#tree .action-button { .tree .action-button {
position: relative; position: relative;
top: -5px; top: -5px;
margin-left: 10px; margin-left: 10px;