From fdc86bab50c456aecd91305f141d0f6d2886d861 Mon Sep 17 00:00:00 2001 From: zadam Date: Wed, 4 Sep 2019 21:30:11 +0200 Subject: [PATCH] lazy loading of opened tabs to speed up initial startup --- src/public/javascripts/services/link_map.js | 4 +- .../javascripts/services/note_detail.js | 60 +------------ .../javascripts/services/tab_context.js | 85 ++++++++++++++++++- 3 files changed, 85 insertions(+), 64 deletions(-) diff --git a/src/public/javascripts/services/link_map.js b/src/public/javascripts/services/link_map.js index 04b5af043..a09ee6bc6 100644 --- a/src/public/javascripts/services/link_map.js +++ b/src/public/javascripts/services/link_map.js @@ -97,8 +97,8 @@ export default class LinkMap { } $noteBox - .mouseover(() => $(".link-" + noteId).addClass("jsplumb-connection-hover")) - .mouseout(() => $(".link-" + noteId).removeClass("jsplumb-connection-hover")); + .mouseover(() => this.$linkMapContainer.find(".link-" + noteId).addClass("jsplumb-connection-hover")) + .mouseout(() => this.$linkMapContainer.find(".link-" + noteId).removeClass("jsplumb-connection-hover")); this.$linkMapContainer.append($noteBox); diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js index 708b49c7e..1cc5e6982 100644 --- a/src/public/javascripts/services/note_detail.js +++ b/src/public/javascripts/services/note_detail.js @@ -145,7 +145,7 @@ async function switchToTab(tabId, notePath) { async function showTab(tabId) { for (const ctx of tabContexts) { if (ctx.tabId === tabId) { - ctx.show(); + await ctx.show(); } else { ctx.hide(); @@ -171,23 +171,6 @@ async function showTab(tabId) { } } -async function renderComponent(ctx) { - for (const componentType in ctx.components) { - if (componentType !== ctx.note.type) { - ctx.components[componentType].cleanup(); - } - } - - ctx.$noteDetailComponents.hide(); - - ctx.$noteTitle.show(); // this can be hidden by empty detail - ctx.$noteTitle.removeAttr("readonly"); // this can be set by protected session service - - await ctx.initComponent(); - - await ctx.getComponent().render(); -} - /** * @param {TabContext} ctx * @param {NoteFull} note @@ -197,44 +180,9 @@ async function loadNoteDetailToContext(ctx, note, notePath) { openTabsChanged(); - if (utils.isDesktop()) { - // needs to happen after loading the note itself because it references active noteId - ctx.attributes.refreshAttributes(); - } else { - // mobile usually doesn't need attributes so we just invalidate - ctx.attributes.invalidateAttributes(); - } - - ctx.noteChangeDisabled = true; - - try { - ctx.$noteTitle.val(ctx.note.title); - - if (utils.isDesktop()) { - ctx.noteType.update(); - } - - await renderComponent(ctx); - } finally { - ctx.noteChangeDisabled = false; - } - treeService.setBranchBackgroundBasedOnProtectedStatus(note.noteId); - // after loading new note make sure editor is scrolled to the top - ctx.getComponent().scrollToTop(); - fireDetailLoaded(); - - ctx.$scriptArea.empty(); - - await bundleService.executeRelationBundles(ctx.note, 'runOnNoteView', ctx); - - if (utils.isDesktop()) { - await ctx.attributes.showAttributes(); - - await ctx.showChildrenOverview(); - } } async function loadNoteDetail(origNotePath, options = {}) { @@ -409,14 +357,10 @@ $tabContentsContainer.on("drop", async e => { }); }); -async function openEmptyTab(render = true) { +async function openEmptyTab() { const ctx = new TabContext(tabRow); tabContexts.push(ctx); - if (render) { - await renderComponent(ctx); - } - await tabRow.activateTab(ctx.$tab[0]); } diff --git a/src/public/javascripts/services/tab_context.js b/src/public/javascripts/services/tab_context.js index ddea635e1..d1f30f78b 100644 --- a/src/public/javascripts/services/tab_context.js +++ b/src/public/javascripts/services/tab_context.js @@ -41,6 +41,14 @@ class TabContext { this.tabRow = tabRow; this.tabId = state.tabId || utils.randomString(4); this.$tab = $(this.tabRow.addTab(this.tabId)); + this.initialized = false; + this.state = state; + } + + initTabContent() { + if (this.initialized) { + return; + } this.$tabContent = $(".note-tab-content-template").clone(); this.$tabContent.removeClass('note-tab-content-template'); @@ -62,7 +70,7 @@ class TabContext { this.attributes = new Attributes(this); if (utils.isDesktop()) { - const sidebarState = state.sidebar || { + const sidebarState = this.state.sidebar || { visible: showSidebarInNewTab }; @@ -101,6 +109,8 @@ class TabContext { this.$unprotectButton = this.$tabContent.find(".unprotect-button"); this.$unprotectButton.click(protectedSessionService.unprotectNoteAndSendToServer); + + this.initialized = true; } async setNote(note, notePath) { @@ -110,14 +120,43 @@ class TabContext { this.note = note; this.tabRow.updateTab(this.$tab[0], {title: note.title}); - this.attributes.invalidateAttributes(); + if (!this.initialized) { + return; + } await this.initComponent(); + // after loading new note make sure editor is scrolled to the top + this.getComponent().scrollToTop(); + + if (utils.isDesktop()) { + // needs to happen after loading the note itself because it references active noteId + this.attributes.refreshAttributes(); + + await this.showChildrenOverview(); + } else { + // mobile usually doesn't need attributes so we just invalidate + this.attributes.invalidateAttributes(); + } + this.setupClasses(); this.setCurrentNotePathToHash(); + this.noteChangeDisabled = true; + + try { + this.$noteTitle.val(this.note.title); + + if (utils.isDesktop()) { + this.noteType.update(); + } + + await this.renderComponent(); + } finally { + this.noteChangeDisabled = false; + } + this.setTitleBar(); this.closeAutocomplete(); // esp. on windows autocomplete is not getting closed automatically @@ -137,15 +176,45 @@ class TabContext { if (this.sidebar) { this.sidebar.noteLoaded(); // load async } + + await bundleService.executeRelationBundles(this.note, 'runOnNoteView', this); } - show() { + async show() { + if (!this.initialized) { + this.initTabContent(); + + await this.initComponent(); + + if (this.note) { + await this.setNote(this.note, this.notePath); + } + } + this.$tabContent.show(); this.setCurrentNotePathToHash(); this.setTitleBar(); this.getComponent().show(); } + async renderComponent() { + for (const componentType in this.components) { + if (componentType !== this.note.type) { + this.components[componentType].cleanup(); + } + } + + this.$noteDetailComponents.hide(); + + this.$noteTitle.show(); // this can be hidden by empty detail + this.$noteTitle.removeAttr("readonly"); // this can be set by protected session service + + await this.initComponent(); + + await this.getComponent().render(); + } + + setTitleBar() { if (!this.$tabContent.is(":visible")) { return; @@ -160,7 +229,9 @@ class TabContext { } hide() { - this.$tabContent.hide(); + if (this.initialized) { + this.$tabContent.hide(); + } } setCurrentNotePathToHash() { @@ -265,6 +336,8 @@ class TabContext { this.$savedIndicator.fadeIn(); + this.$scriptArea.empty(); + // run async bundleService.executeRelationBundles(this.note, 'runOnNoteChange', this); @@ -369,6 +442,10 @@ class TabContext { } eventReceived(name, data) { + if (!this.initialized) { + return; + } + this.attributes.eventReceived(name, data); if (this.sidebar) {