refactoring of note detail API

This commit is contained in:
zadam
2020-01-24 17:54:47 +01:00
parent 4b66765cc1
commit 606d5afcab
18 changed files with 107 additions and 219 deletions

View File

@@ -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
};