mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	refactoring of note detail API
This commit is contained in:
		@@ -1,35 +1,9 @@
 | 
			
		||||
import treeService from './tree.js';
 | 
			
		||||
import TabContext from './tab_context.js';
 | 
			
		||||
import server from './server.js';
 | 
			
		||||
import ws from "./ws.js";
 | 
			
		||||
import treeCache from "./tree_cache.js";
 | 
			
		||||
import NoteFull from "../entities/note_full.js";
 | 
			
		||||
import treeUtils from "./tree_utils.js";
 | 
			
		||||
import tabRow from "../widgets/tab_row.js";
 | 
			
		||||
import appContext from "./app_context.js";
 | 
			
		||||
 | 
			
		||||
let detailLoadedListeners = [];
 | 
			
		||||
 | 
			
		||||
async function reload() {
 | 
			
		||||
    // no saving here
 | 
			
		||||
 | 
			
		||||
    await loadNoteDetail(appContext.getActiveTabNotePath());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function reloadNote(tabContext) {
 | 
			
		||||
    await loadNoteDetailToContext(tabContext, tabContext.notePath);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function openInTab(notePath, activate) {
 | 
			
		||||
    await loadNoteDetail(notePath, { newTab: true, activate });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function switchToNote(notePath) {
 | 
			
		||||
    await loadNoteDetail(notePath);
 | 
			
		||||
 | 
			
		||||
    appContext.openTabsChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getActiveEditor() {
 | 
			
		||||
    const activeTabContext = appContext.getActiveTabContext();
 | 
			
		||||
 | 
			
		||||
@@ -41,73 +15,6 @@ function getActiveEditor() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function activateOrOpenNote(noteId) {
 | 
			
		||||
    for (const tabContext of appContext.getTabContexts()) {
 | 
			
		||||
        if (tabContext.note && tabContext.note.noteId === noteId) {
 | 
			
		||||
            await tabContext.activate();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if no tab with this note has been found we'll create new tab
 | 
			
		||||
 | 
			
		||||
    await loadNoteDetail(noteId, {
 | 
			
		||||
        newTab: true,
 | 
			
		||||
        activate: true
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {TabContext} ctx
 | 
			
		||||
 * @param {string} notePath
 | 
			
		||||
 */
 | 
			
		||||
async function loadNoteDetailToContext(ctx, notePath) {
 | 
			
		||||
    await ctx.setNote(notePath);
 | 
			
		||||
 | 
			
		||||
    appContext.openTabsChanged();
 | 
			
		||||
 | 
			
		||||
    fireDetailLoaded();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function loadNoteDetail(origNotePath, options = {}) {
 | 
			
		||||
    const newTab = !!options.newTab;
 | 
			
		||||
    const activate = !!options.activate;
 | 
			
		||||
 | 
			
		||||
    let notePath = await treeService.resolveNotePath(origNotePath);
 | 
			
		||||
 | 
			
		||||
    if (!notePath) {
 | 
			
		||||
        console.error(`Cannot resolve note path ${origNotePath}`);
 | 
			
		||||
 | 
			
		||||
        // fallback to display something
 | 
			
		||||
        notePath = 'root';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const noteId = treeUtils.getNoteIdFromNotePath(notePath);
 | 
			
		||||
    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
 | 
			
		||||
    // try to render all those loaded notes one after each other. This only guarantees that correct note
 | 
			
		||||
    // will be displayed independent of timing
 | 
			
		||||
    const currentTreeNode = appContext.getMainNoteTree().getActiveNode();
 | 
			
		||||
    if (!newTab && currentTreeNode && currentTreeNode.data.noteId !== noteId) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const loadPromise = loadNoteDetailToContext(ctx, notePath).then(() => {
 | 
			
		||||
        if (activate) {
 | 
			
		||||
            return appContext.activateTab(ctx.tabId);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return Promise.resolve();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!options.async) {
 | 
			
		||||
        await loadPromise;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function loadNote(noteId) {
 | 
			
		||||
    const row = await server.get('notes/' + noteId);
 | 
			
		||||
 | 
			
		||||
@@ -116,49 +23,12 @@ async function loadNote(noteId) {
 | 
			
		||||
    return new NoteFull(treeCache, row, noteShort);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function noteDeleted(noteId) {
 | 
			
		||||
    for (const tc of appContext.getTabContexts()) {
 | 
			
		||||
        // not removing active even if it contains deleted note since that one will move to another note (handled by deletion logic)
 | 
			
		||||
        // and we would lose tab context state (e.g. sidebar visibility)
 | 
			
		||||
        if (!tc.isActive() && tc.notePath && tc.notePath.split("/").includes(noteId)) {
 | 
			
		||||
            tabRow.removeTab(tc.tabId);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function focusOnTitle() {
 | 
			
		||||
    appContext.getActiveTabContext().$noteTitle.trigger('focus');
 | 
			
		||||
    appContext.trigger('focusOnTitle');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function focusAndSelectTitle() {
 | 
			
		||||
    appContext.getActiveTabContext()
 | 
			
		||||
        .$noteTitle
 | 
			
		||||
            .trigger('focus')
 | 
			
		||||
            .trigger('select');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Since detail loading may take some time and user might just browse through the notes using UP-DOWN keys,
 | 
			
		||||
 * we intentionally decouple activation of the note in the tree and full load of the note so just avaiting on
 | 
			
		||||
 * fancytree's activate() won't wait for the full load.
 | 
			
		||||
 *
 | 
			
		||||
 * This causes an issue where in some cases you want to do some action after detail is loaded. For this reason
 | 
			
		||||
 * we provide the listeners here which will be triggered after the detail is loaded and if the loaded note
 | 
			
		||||
 * is the one registered in the listener.
 | 
			
		||||
 */
 | 
			
		||||
function addDetailLoadedListener(noteId, callback) {
 | 
			
		||||
    detailLoadedListeners.push({ noteId, callback });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function fireDetailLoaded() {
 | 
			
		||||
    for (const {noteId, callback} of detailLoadedListeners) {
 | 
			
		||||
        if (noteId === appContext.getActiveTabNoteId()) {
 | 
			
		||||
            callback();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // all the listeners are one time only
 | 
			
		||||
    detailLoadedListeners = [];
 | 
			
		||||
    appContext.trigger('focusAndSelectTitle');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ws.subscribeToOutsideSyncMessages(syncData => {
 | 
			
		||||
@@ -199,17 +69,9 @@ $(window).on('beforeunload', () => {
 | 
			
		||||
 });
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    reload,
 | 
			
		||||
    openInTab,
 | 
			
		||||
    switchToNote,
 | 
			
		||||
    loadNote,
 | 
			
		||||
    loadNoteDetail,
 | 
			
		||||
    focusOnTitle,
 | 
			
		||||
    focusAndSelectTitle,
 | 
			
		||||
    addDetailLoadedListener,
 | 
			
		||||
    getActiveEditor,
 | 
			
		||||
    activateOrOpenNote,
 | 
			
		||||
    noteDeleted,
 | 
			
		||||
    noteChanged,
 | 
			
		||||
    reloadNote
 | 
			
		||||
    noteChanged
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user