diff --git a/docs/frontend_api/Branch.html b/docs/frontend_api/Branch.html
index e4d6a52e8..f8a5d8573 100644
--- a/docs/frontend_api/Branch.html
+++ b/docs/frontend_api/Branch.html
@@ -879,7 +879,7 @@
- Classes
+ Classes Global
diff --git a/docs/frontend_api/FrontendScriptApi.html b/docs/frontend_api/FrontendScriptApi.html
index bf5e6142f..4be267270 100644
--- a/docs/frontend_api/FrontendScriptApi.html
+++ b/docs/frontend_api/FrontendScriptApi.html
@@ -5483,7 +5483,7 @@ Typical use case is when new note has been created, we should wait until it is s
- Classes
+ Classes Global
diff --git a/docs/frontend_api/NoteComplement.html b/docs/frontend_api/NoteComplement.html
index 02e7ea197..ae6edadd3 100644
--- a/docs/frontend_api/NoteComplement.html
+++ b/docs/frontend_api/NoteComplement.html
@@ -507,7 +507,7 @@
- Classes
+ Classes Global
diff --git a/docs/frontend_api/NoteShort.html b/docs/frontend_api/NoteShort.html
index d3c633784..df31231ed 100644
--- a/docs/frontend_api/NoteShort.html
+++ b/docs/frontend_api/NoteShort.html
@@ -6813,7 +6813,7 @@ Cache is note instance scoped.
- Classes
+ Classes Global
diff --git a/docs/frontend_api/entities_attribute.js.html b/docs/frontend_api/entities_attribute.js.html
index 6c73abfce..a74c256fb 100644
--- a/docs/frontend_api/entities_attribute.js.html
+++ b/docs/frontend_api/entities_attribute.js.html
@@ -79,7 +79,7 @@ export default Attribute;
- Classes
+ Classes Global
diff --git a/docs/frontend_api/entities_branch.js.html b/docs/frontend_api/entities_branch.js.html
index 1c60b1af3..f492aabbb 100644
--- a/docs/frontend_api/entities_branch.js.html
+++ b/docs/frontend_api/entities_branch.js.html
@@ -81,7 +81,7 @@ export default Branch;
- Classes
+ Classes Global
diff --git a/docs/frontend_api/entities_note_complement.js.html b/docs/frontend_api/entities_note_complement.js.html
index 5e85d7b9a..75b9636e8 100644
--- a/docs/frontend_api/entities_note_complement.js.html
+++ b/docs/frontend_api/entities_note_complement.js.html
@@ -61,7 +61,7 @@ export default NoteComplement;
- Classes
+ Classes Global
diff --git a/docs/frontend_api/entities_note_short.js.html b/docs/frontend_api/entities_note_short.js.html
index 34a9d0e20..4f56dd9ce 100644
--- a/docs/frontend_api/entities_note_short.js.html
+++ b/docs/frontend_api/entities_note_short.js.html
@@ -493,7 +493,7 @@ export default NoteShort;
- Classes
+ Classes Global
diff --git a/docs/frontend_api/global.html b/docs/frontend_api/global.html
index 1d2eca868..6525a2d09 100644
--- a/docs/frontend_api/global.html
+++ b/docs/frontend_api/global.html
@@ -95,6 +95,275 @@
+
+
Methods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ for overriding
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) doRenderBody()
+
+
+
+
+
+
+
+ for overriding
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This event is used to synchronize collapsed state of all the tab-cached widgets since they are all rendered
+separately but should behave uniformly for the user.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -333,7 +602,7 @@
- Classes
+ Classes Global
diff --git a/docs/frontend_api/index.html b/docs/frontend_api/index.html
index 73c03637b..978ebed4f 100644
--- a/docs/frontend_api/index.html
+++ b/docs/frontend_api/index.html
@@ -50,7 +50,7 @@
- Classes
+ Classes Global
diff --git a/docs/frontend_api/services_frontend_script_api.js.html b/docs/frontend_api/services_frontend_script_api.js.html
index 4dcfd43e9..0d32d82ba 100644
--- a/docs/frontend_api/services_frontend_script_api.js.html
+++ b/docs/frontend_api/services_frontend_script_api.js.html
@@ -443,7 +443,7 @@ export default FrontendScriptApi;
- Classes
+ Classes Global
diff --git a/docs/frontend_api/widgets_collapsible_widget.js.html b/docs/frontend_api/widgets_collapsible_widget.js.html
new file mode 100644
index 000000000..e5ec10b7b
--- /dev/null
+++ b/docs/frontend_api/widgets_collapsible_widget.js.html
@@ -0,0 +1,151 @@
+
+
+
+
+ JSDoc: Source: widgets/collapsible_widget.js
+
+
+
+
+
+
+
+
+
+
+
+
+
Source: widgets/collapsible_widget.js
+
+
+
+
+
+
+
+
+ import TabAwareWidget from "./tab_aware_widget.js";
+import options from "../services/options.js";
+
+const WIDGET_TPL = `
+<div class="card widget">
+ <div class="card-header">
+ <div>
+ <button class="btn btn-sm widget-title" data-toggle="collapse" data-target="#[to be set]">
+ Collapsible Group Item
+ </button>
+
+ <a class="widget-help external no-arrow bx bx-info-circle"></a>
+ </div>
+
+ <div class="widget-header-actions"></div>
+ </div>
+
+ <div id="[to be set]" class="collapse body-wrapper" style="transition: none; ">
+ <div class="card-body"></div>
+ </div>
+</div>`;
+
+export default class CollapsibleWidget extends TabAwareWidget {
+ get widgetTitle() { return "Untitled widget"; }
+
+ get headerActions() { return []; }
+
+ get help() { return {}; }
+
+ doRender() {
+ this.$widget = $(WIDGET_TPL);
+ this.$widget.find('[data-target]').attr('data-target', "#" + this.componentId);
+
+ this.$bodyWrapper = this.$widget.find('.body-wrapper');
+ this.$bodyWrapper.attr('id', this.componentId); // for toggle to work we need id
+
+ this.widgetName = this.constructor.name;
+
+ if (!options.is(this.widgetName + 'Collapsed')) {
+ this.$bodyWrapper.collapse("show");
+ }
+
+ // using immediate variants of the event so that the previous collapse is not caught
+ this.$bodyWrapper.on('hide.bs.collapse', () => this.saveCollapsed(true));
+ this.$bodyWrapper.on('show.bs.collapse', () => this.saveCollapsed(false));
+
+ this.$body = this.$bodyWrapper.find('.card-body');
+
+ this.$title = this.$widget.find('.widget-title');
+ this.$title.text(this.widgetTitle);
+
+ this.$help = this.$widget.find('.widget-help');
+
+ if (this.help.title) {
+ this.$help.attr("title", this.help.title);
+ this.$help.attr("href", this.help.url || "javascript:");
+
+ if (!this.help.url) {
+ this.$help.addClass('no-link');
+ }
+ }
+ else {
+ this.$help.hide();
+ }
+
+ this.$headerActions = this.$widget.find('.widget-header-actions');
+ this.$headerActions.append(...this.headerActions);
+
+ this.initialized = this.doRenderBody();
+
+ this.decorateWidget();
+
+ return this.$widget;
+ }
+
+ saveCollapsed(collapse) {
+ options.save(this.widgetName + 'Collapsed', collapse.toString());
+
+ this.triggerEvent(`widgetCollapsedStateChanged`, {widgetName: this.widgetName, collapse});
+ }
+
+ /**
+ * This event is used to synchronize collapsed state of all the tab-cached widgets since they are all rendered
+ * separately but should behave uniformly for the user.
+ */
+ widgetCollapsedStateChangedEvent({widgetName, collapse}) {
+ if (widgetName === this.widgetName) {
+ this.$bodyWrapper.toggleClass('show', !collapse);
+ }
+ }
+
+ /** for overriding */
+ decorateWidget() {}
+
+ /** for overriding */
+ async doRenderBody() {}
+
+ isExpanded() {
+ return this.$bodyWrapper.hasClass("show");
+ }
+}
+
+
+
+
+
+
+
+
+
+ Classes Global
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index ebb165f2e..ff3b9a9c5 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
"start-server": "TRILIUM_ENV=dev node ./src/www",
"start-electron": "TRILIUM_ENV=dev electron .",
"build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
- "build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js",
+ "build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/collapsible_widget.js",
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
"webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js"
},