refactor(book_properties): list buttons are now declarative

This commit is contained in:
Elian Doran 2025-07-09 20:29:58 +03:00
parent 430ed78d85
commit 196bba9cda
No known key found for this signature in database
2 changed files with 78 additions and 59 deletions

View File

@ -45,31 +45,12 @@ const TPL = /*html*/`
<div class="book-properties-container"> <div class="book-properties-container">
</div> </div>
<button type="button"
class="collapse-all-button btn btn-sm"
title="${t("book_properties.collapse_all_notes")}">
<span class="bx bx-layer-minus"></span>
${t("book_properties.collapse")}
</button>
<button type="button"
class="expand-children-button btn btn-sm"
title="${t("book_properties.expand_all_children")}">
<span class="bx bx-move-vertical"></span>
${t("book_properties.expand")}
</button>
</div> </div>
`; `;
export default class BookPropertiesWidget extends NoteContextAwareWidget { export default class BookPropertiesWidget extends NoteContextAwareWidget {
private $viewTypeSelect!: JQuery<HTMLElement>; private $viewTypeSelect!: JQuery<HTMLElement>;
private $expandChildrenButton!: JQuery<HTMLElement>;
private $collapseAllButton!: JQuery<HTMLElement>;
private $propertiesContainer!: JQuery<HTMLElement>; private $propertiesContainer!: JQuery<HTMLElement>;
private labelsToWatch: string[] = []; private labelsToWatch: string[] = [];
@ -100,33 +81,6 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
this.$viewTypeSelect = this.$widget.find(".view-type-select"); this.$viewTypeSelect = this.$widget.find(".view-type-select");
this.$viewTypeSelect.on("change", () => this.toggleViewType(String(this.$viewTypeSelect.val()))); this.$viewTypeSelect.on("change", () => this.toggleViewType(String(this.$viewTypeSelect.val())));
this.$expandChildrenButton = this.$widget.find(".expand-children-button");
this.$expandChildrenButton.on("click", async () => {
if (!this.noteId || !this.note) {
return;
}
if (!this.note?.isLabelTruthy("expanded")) {
await attributeService.addLabel(this.noteId, "expanded");
}
this.triggerCommand("refreshNoteList", { noteId: this.noteId });
});
this.$collapseAllButton = this.$widget.find(".collapse-all-button");
this.$collapseAllButton.on("click", async () => {
if (!this.noteId || !this.note) {
return;
}
// owned is important - we shouldn't remove inherited expanded labels
for (const expandedAttr of this.note.getOwnedLabels("expanded")) {
await attributeService.removeAttributeById(this.noteId, expandedAttr.attributeId);
}
this.triggerCommand("refreshNoteList", { noteId: this.noteId });
});
this.$propertiesContainer = this.$widget.find(".book-properties-container"); this.$propertiesContainer = this.$widget.find(".book-properties-container");
} }
@ -139,15 +93,15 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
this.$viewTypeSelect.val(viewType); this.$viewTypeSelect.val(viewType);
this.$expandChildrenButton.toggle(viewType === "list");
this.$collapseAllButton.toggle(viewType === "list");
this.$propertiesContainer.empty(); this.$propertiesContainer.empty();
const bookPropertiesData = bookPropertiesConfig[viewType]; const bookPropertiesData = bookPropertiesConfig[viewType];
if (bookPropertiesData) { if (bookPropertiesData) {
for (const property of bookPropertiesData.properties) { for (const property of bookPropertiesData.properties) {
this.$propertiesContainer.append(renderBookProperty(property, note)); this.$propertiesContainer.append(renderBookProperty(property, {
note: this.note,
triggerCommand: this.triggerCommand.bind(this)
}));
this.labelsToWatch.push(property.bindToLabel); this.labelsToWatch.push(property.bindToLabel);
} }
} }

View File

@ -1,17 +1,34 @@
import { t } from "i18next";
import FNote from "../../entities/fnote"; import FNote from "../../entities/fnote";
import attributes from "../../services/attributes"; import attributes from "../../services/attributes";
import { ViewTypeOptions } from "../../services/note_list_renderer" import { ViewTypeOptions } from "../../services/note_list_renderer"
import NoteContextAwareWidget from "../note_context_aware_widget";
type BookProperty = CheckBoxProperty | ButtonProperty;
interface BookConfig { interface BookConfig {
properties: BookProperty[] properties: BookProperty[];
} }
interface BookProperty { interface CheckBoxProperty {
label: string;
type: "checkbox", type: "checkbox",
label: string;
bindToLabel: string bindToLabel: string
} }
interface ButtonProperty {
type: "button",
label: string;
title?: string;
icon?: string;
onClick: (context: BookContext) => void;
}
interface BookContext {
note: FNote;
triggerCommand: NoteContextAwareWidget["triggerCommand"];
}
export const bookPropertiesConfig: Record<ViewTypeOptions, BookConfig> = { export const bookPropertiesConfig: Record<ViewTypeOptions, BookConfig> = {
calendar: { calendar: {
properties: [ properties: [
@ -26,16 +43,49 @@ export const bookPropertiesConfig: Record<ViewTypeOptions, BookConfig> = {
bindToLabel: "calendar:weekNumbers" bindToLabel: "calendar:weekNumbers"
} }
] ]
},
list: {
properties: [
{
label: t("book_properties.collapse"),
title: t("book_properties.collapse_all_notes"),
type: "button",
icon: "bx bx-layer-minus",
async onClick({ note, triggerCommand }) {
const { noteId } = note;
// owned is important - we shouldn't remove inherited expanded labels
for (const expandedAttr of note.getOwnedLabels("expanded")) {
await attributes.removeAttributeById(noteId, expandedAttr.attributeId);
}
triggerCommand("refreshNoteList", { noteId: noteId });
},
},
{
label: t("book_properties.expand"),
title: t("book_properties.expand_all_children"),
type: "button",
icon: "bx bx-move-vertical",
async onClick({ note, triggerCommand }) {
const { noteId } = note;
if (!note.isLabelTruthy("expanded")) {
await attributes.addLabel(noteId, "expanded");
}
triggerCommand("refreshNoteList", { noteId });
},
}
]
} }
}; };
export function renderBookProperty(property: BookProperty, note: FNote) { export function renderBookProperty(property: BookProperty, context: BookContext) {
const $container = $("<div>"); const $container = $("<div>");
const $label = $("<label>").text(property.label); const { note } = context;
$container.append($label);
switch (property.type) { switch (property.type) {
case "checkbox": case "checkbox":
const $label = $("<label>").text(property.label);
const $checkbox = $("<input>", { const $checkbox = $("<input>", {
type: "checkbox", type: "checkbox",
class: "form-check-input", class: "form-check-input",
@ -49,9 +99,24 @@ export function renderBookProperty(property: BookProperty, note: FNote) {
}); });
$checkbox.prop("checked", note.hasOwnedLabel(property.bindToLabel)); $checkbox.prop("checked", note.hasOwnedLabel(property.bindToLabel));
$label.prepend($checkbox); $label.prepend($checkbox);
$container.append($label);
break;
case "button":
const $button = $("<button>", {
type: "button",
class: "btn btn-sm"
}).text(property.label);
if (property.title) {
$button.attr("title", property.title);
}
if (property.icon) {
$button.prepend($("<span>", { class: property.icon }));
}
$button.on("click", () => {
property.onClick(context);
});
$container.append($button);
break; break;
default:
throw new Error(`Unknown property type: ${property.type}`);
} }
return $container; return $container;