lazy loading of note list

This commit is contained in:
zadam 2020-12-27 22:19:27 +01:00
parent 95760f1d28
commit 1d64129572
12 changed files with 125 additions and 124 deletions

108
package-lock.json generated
View File

@ -54,6 +54,12 @@
} }
} }
}, },
"@discoveryjs/json-ext": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
"integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==",
"dev": true
},
"@electron/get": { "@electron/get": {
"version": "1.7.2", "version": "1.7.2",
"resolved": "https://registry.npmjs.org/@electron/get/-/get-1.7.2.tgz", "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.7.2.tgz",
@ -898,18 +904,18 @@
} }
}, },
"@webpack-cli/info": { "@webpack-cli/info": {
"version": "1.1.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.0.tgz",
"integrity": "sha512-uNWSdaYHc+f3LdIZNwhdhkjjLDDl3jP2+XBqAq9H8DjrJUvlOKdP8TNruy1yEaDfgpAIgbSAN7pye4FEHg9tYQ==", "integrity": "sha512-+wA8lBKopgKmN76BSGJVJby5ZXDlsrO6p/nm7fUBsHznRNWB/ozotJP7Yfcz8JPfqeG2LxwYlTH2u6D9a/0XAw==",
"dev": true, "dev": true,
"requires": { "requires": {
"envinfo": "^7.7.3" "envinfo": "^7.7.3"
} }
}, },
"@webpack-cli/serve": { "@webpack-cli/serve": {
"version": "1.1.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.0.tgz",
"integrity": "sha512-7RfnMXCpJ/NThrhq4gYQYILB18xWyoQcBey81oIyVbmgbc6m5ZHHyFK+DyH7pLHJf0p14MxL4mTsoPAgBSTpIg==", "integrity": "sha512-jI3P7jMp/AXDSPkM+ClwRcJZbxnlvNC8bVZBmyRr4scMMZ4p5WQcXkw3Q+Hc7RQekomJlBMN+UQGliT4hhG8Vw==",
"dev": true "dev": true
}, },
"@xtuc/ieee754": { "@xtuc/ieee754": {
@ -1145,12 +1151,6 @@
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
} }
}, },
"array-back": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz",
"integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==",
"dev": true
},
"array-flatten": { "array-flatten": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@ -2009,18 +2009,6 @@
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
} }
}, },
"command-line-usage": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz",
"integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==",
"dev": true,
"requires": {
"array-back": "^4.0.1",
"chalk": "^2.4.2",
"table-layout": "^1.0.1",
"typical": "^5.2.0"
}
},
"commander": { "commander": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
@ -2373,9 +2361,9 @@
} }
}, },
"dayjs": { "dayjs": {
"version": "1.9.7", "version": "1.9.8",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.9.7.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.9.8.tgz",
"integrity": "sha512-IC877KBdMhBrCfBfJXHQlo0G8keZ0Opy7YIIq5QKtUbCuHMzim8S4PyiVK4YmihI3iOF9lhfUBW4AQWHTR5WHA==" "integrity": "sha512-F42qBtJRa30FKF7XDnOQyNUTsaxDkuaZRj/i7BejSHC34LlLfPoIU4aeopvWfM+m1dJ6/DHKAWLg2ur+pLgq1w=="
}, },
"debug": { "debug": {
"version": "4.1.1", "version": "4.1.1",
@ -3661,6 +3649,12 @@
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
}, },
"fastest-levenshtein": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
"integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
"dev": true
},
"fd-slicer": { "fd-slicer": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
@ -4823,12 +4817,6 @@
"integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==",
"dev": true "dev": true
}, },
"leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
"integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
"dev": true
},
"levn": { "levn": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@ -6223,12 +6211,6 @@
"resolve": "^1.9.0" "resolve": "^1.9.0"
} }
}, },
"reduce-flatten": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz",
"integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==",
"dev": true
},
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.13.7", "version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
@ -7018,18 +7000,6 @@
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
}, },
"table-layout": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz",
"integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==",
"dev": true,
"requires": {
"array-back": "^4.0.1",
"deep-extend": "~0.6.0",
"typical": "^5.2.0",
"wordwrapjs": "^4.0.0"
}
},
"taffydb": { "taffydb": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
@ -7390,12 +7360,6 @@
"is-typedarray": "^1.0.0" "is-typedarray": "^1.0.0"
} }
}, },
"typical": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz",
"integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==",
"dev": true
},
"uc.micro": { "uc.micro": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
@ -7731,30 +7695,30 @@
} }
}, },
"webpack-cli": { "webpack-cli": {
"version": "4.2.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.2.0.tgz", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.0.tgz",
"integrity": "sha512-EIl3k88vaF4fSxWSgtAQR+VwicfLMTZ9amQtqS4o+TDPW9HGaEpbFBbAZ4A3ZOT5SOnMxNOzROsSTPiE8tBJPA==", "integrity": "sha512-gve+BBKrzMPTOYDjupzV8JchUznhVWMKtWM1hFIQWi6XoeLvGNoQwkrtMWVb+aJ437GgCKdta7sIn10v621pKA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@webpack-cli/info": "^1.1.0", "@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/serve": "^1.1.0", "@webpack-cli/info": "^1.2.0",
"@webpack-cli/serve": "^1.2.0",
"colorette": "^1.2.1", "colorette": "^1.2.1",
"command-line-usage": "^6.1.0",
"commander": "^6.2.0", "commander": "^6.2.0",
"enquirer": "^2.3.6", "enquirer": "^2.3.6",
"execa": "^4.1.0", "execa": "^4.1.0",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2", "import-local": "^3.0.2",
"interpret": "^2.2.0", "interpret": "^2.2.0",
"leven": "^3.1.0",
"rechoir": "^0.7.0", "rechoir": "^0.7.0",
"v8-compile-cache": "^2.2.0", "v8-compile-cache": "^2.2.0",
"webpack-merge": "^4.2.2" "webpack-merge": "^4.2.2"
}, },
"dependencies": { "dependencies": {
"commander": { "commander": {
"version": "6.2.0", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
"integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
"dev": true "dev": true
} }
} }
@ -7883,16 +7847,6 @@
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
}, },
"wordwrapjs": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz",
"integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==",
"dev": true,
"requires": {
"reduce-flatten": "^2.0.0",
"typical": "^5.0.0"
}
},
"wrap-ansi": { "wrap-ansi": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",

View File

@ -32,7 +32,7 @@
"commonmark": "0.29.3", "commonmark": "0.29.3",
"cookie-parser": "1.4.5", "cookie-parser": "1.4.5",
"csurf": "1.11.0", "csurf": "1.11.0",
"dayjs": "1.9.7", "dayjs": "1.9.8",
"ejs": "3.1.5", "ejs": "3.1.5",
"electron-debug": "3.2.0", "electron-debug": "3.2.0",
"electron-dl": "3.0.2", "electron-dl": "3.0.2",
@ -87,7 +87,7 @@
"lorem-ipsum": "2.0.3", "lorem-ipsum": "2.0.3",
"rcedit": "3.0.0", "rcedit": "3.0.0",
"webpack": "5.11.0", "webpack": "5.11.0",
"webpack-cli": "4.2.0" "webpack-cli": "4.3.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"electron-installer-debian": "2.0.1" "electron-installer-debian": "2.0.1"

View File

@ -26,6 +26,7 @@ import PromotedAttributesWidget from "../widgets/attribute_widgets/promoted_attr
import InheritedAttributesWidget from "../widgets/inherited_attribute_list.js"; import InheritedAttributesWidget from "../widgets/inherited_attribute_list.js";
import NoteListWidget from "../widgets/note_list.js"; import NoteListWidget from "../widgets/note_list.js";
import SearchDefinitionWidget from "../widgets/search_definition.js"; import SearchDefinitionWidget from "../widgets/search_definition.js";
import Container from "../widgets/container.js";
const RIGHT_PANE_CSS = ` const RIGHT_PANE_CSS = `
<style> <style>
@ -160,8 +161,11 @@ export default class DesktopMainWindowLayout {
.child(new InheritedAttributesWidget()) .child(new InheritedAttributesWidget())
) )
) )
.child(new Container()
.css('height: 100%; overflow: auto;')
.child(new TabCachingWidget(() => new NoteDetailWidget())) .child(new TabCachingWidget(() => new NoteDetailWidget()))
.child(new TabCachingWidget(() => new NoteListWidget())) .child(new TabCachingWidget(() => new NoteListWidget()))
)
.child(new TabCachingWidget(() => new SimilarNotesWidget())) .child(new TabCachingWidget(() => new SimilarNotesWidget()))
.child(...this.customWidgets.get('center-pane')) .child(...this.customWidgets.get('center-pane'))
) )

View File

@ -59,7 +59,7 @@ async function createNote(parentNoteId, options = {}) {
appContext.triggerCommand('focusAndSelectTitle'); appContext.triggerCommand('focusAndSelectTitle');
} }
else if (options.focus === 'content') { else if (options.focus === 'content') {
appContext.triggerCommand('focusOnDetail', {tabId: this.tabId}); appContext.triggerCommand('focusOnDetail', {tabId: activeTabContext.tabId});
} }
} }

View File

@ -148,8 +148,12 @@ class NoteListRenderer {
/* /*
* We're using noteIds so that it's not necessary to load all notes at once when paging * We're using noteIds so that it's not necessary to load all notes at once when paging
*/ */
constructor(parentNote, noteIds) { constructor($parent, parentNote, noteIds) {
this.$noteList = $(TPL); this.$noteList = $(TPL);
// note list must be added to the DOM immediatelly, otherwise some functionality scripting (canvas) won't work
$parent.empty().append(this.$noteList);
this.parentNote = parentNote; this.parentNote = parentNote;
this.noteIds = noteIds; this.noteIds = noteIds;
this.page = 1; this.page = 1;

View File

@ -0,0 +1,38 @@
import BasicWidget from "./basic_widget.js";
export default class Container extends BasicWidget {
constructor() {
super();
this.children = [];
this.positionCounter = 10;
}
child(...components) {
if (!components) {
return this;
}
super.child(...components);
for (const component of components) {
if (!component.position) {
component.position = this.positionCounter;
this.positionCounter += 10;
}
}
this.children.sort((a, b) => a.position - b.position < 0 ? -1 : 1);
return this;
}
doRender() {
this.$widget = $(`<div>`);
for (const widget of this.children) {
this.$widget.append(widget.render());
}
}
}

View File

@ -1,6 +1,6 @@
import BasicWidget from "./basic_widget.js"; import Container from "./container.js";
export default class FlexContainer extends BasicWidget { export default class FlexContainer extends Container {
constructor(direction) { constructor(direction) {
super(); super();
@ -9,36 +9,5 @@ export default class FlexContainer extends BasicWidget {
} }
this.attrs.style = `display: flex; flex-direction: ${direction};`; this.attrs.style = `display: flex; flex-direction: ${direction};`;
this.children = [];
this.positionCounter = 10;
}
child(...components) {
if (!components) {
return this;
}
super.child(...components);
for (const component of components) {
if (!component.position) {
component.position = this.positionCounter;
this.positionCounter += 10;
}
}
this.children.sort((a, b) => a.position - b.position < 0 ? -1 : 1);
return this;
}
doRender() {
this.$widget = $(`<div>`);
for (const widget of this.children) {
this.$widget.append(widget.render());
}
} }
} }

View File

@ -25,8 +25,6 @@ const TPL = `
<div class="note-detail"> <div class="note-detail">
<style> <style>
.note-detail { .note-detail {
min-height: 0;
flex-grow: 1;
font-family: var(--detail-font-family); font-family: var(--detail-font-family);
font-size: var(--detail-font-size); font-size: var(--detail-font-size);
} }

View File

@ -32,12 +32,46 @@ export default class NoteListWidget extends TabAwareWidget {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$content = this.$widget.find('.note-list-widget-content'); this.$content = this.$widget.find('.note-list-widget-content');
this.contentSized(); this.contentSized();
const observer = new IntersectionObserver(entries => {
this.isIntersecting = entries[0].isIntersecting;
this.checkRenderStatus();
}, {
rootMargin: '50px',
threshold: 0.1
});
observer.observe(this.$widget[0]);
} }
async refreshWithNote(note) { checkRenderStatus() {
const noteListRenderer = new NoteListRenderer(note, note.getChildNoteIds()); console.log("this.isIntersecting", this.isIntersecting);
console.log("this.noteIdRefreshed === this.noteId", this.noteIdRefreshed === this.noteId);
console.log("this.shownNoteId !== this.noteId", this.shownNoteId !== this.noteId);
this.$content.empty().append(await noteListRenderer.renderList()); if (this.isIntersecting
&& this.noteIdRefreshed === this.noteId
&& this.shownNoteId !== this.noteId) {
this.shownNoteId = this.noteId;
this.renderNoteList(this.note);
}
}
async renderNoteList(note) {
const noteListRenderer = new NoteListRenderer(this.$content, note, note.getChildNoteIds());
await noteListRenderer.renderList();
}
noteDetailRefreshedEvent({tabId}) {
if (!this.isTab(tabId)) {
return;
}
this.noteIdRefreshed = this.noteId;
setTimeout(() => this.checkRenderStatus(), 100);
} }
autoBookDisabledEvent({tabContext}) { autoBookDisabledEvent({tabContext}) {

View File

@ -124,7 +124,7 @@ export default class EditableCodeTypeWidget extends TypeWidget {
async doRefresh(note) { async doRefresh(note) {
const noteComplement = await this.tabContext.getNoteComplement(); const noteComplement = await this.tabContext.getNoteComplement();
this.spacedUpdate.allowUpdateWithoutChange(() => { await this.spacedUpdate.allowUpdateWithoutChange(() => {
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check) // CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
// we provide fallback // we provide fallback
this.codeEditor.setValue(noteComplement.content || ""); this.codeEditor.setValue(noteComplement.content || "");

View File

@ -54,8 +54,6 @@ const TPL = `
.note-detail-editable-text h6::before { content: "######\\00a0\\00a0"; color: var(--muted-text-color); } .note-detail-editable-text h6::before { content: "######\\00a0\\00a0"; color: var(--muted-text-color); }
.note-detail-editable-text { .note-detail-editable-text {
overflow: auto;
height: 100%;
font-family: var(--detail-text-font-family); font-family: var(--detail-text-font-family);
padding-left: 12px; padding-left: 12px;
} }

View File

@ -22,6 +22,8 @@ export default class TypeWidget extends TabAwareWidget {
this.toggleInt(true); this.toggleInt(true);
await this.doRefresh(this.note); await this.doRefresh(this.note);
this.triggerEvent('noteDetailRefreshed', {tabId: this.tabContext.tabId});
} }
} }