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>
<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>
`;
export default class BookPropertiesWidget extends NoteContextAwareWidget {
private $viewTypeSelect!: JQuery<HTMLElement>;
private $expandChildrenButton!: JQuery<HTMLElement>;
private $collapseAllButton!: JQuery<HTMLElement>;
private $propertiesContainer!: JQuery<HTMLElement>;
private labelsToWatch: string[] = [];
@ -100,33 +81,6 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
this.$viewTypeSelect = this.$widget.find(".view-type-select");
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");
}
@ -139,15 +93,15 @@ export default class BookPropertiesWidget extends NoteContextAwareWidget {
this.$viewTypeSelect.val(viewType);
this.$expandChildrenButton.toggle(viewType === "list");
this.$collapseAllButton.toggle(viewType === "list");
this.$propertiesContainer.empty();
const bookPropertiesData = bookPropertiesConfig[viewType];
if (bookPropertiesData) {
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);
}
}

View File

@ -1,17 +1,34 @@
import { t } from "i18next";
import FNote from "../../entities/fnote";
import attributes from "../../services/attributes";
import { ViewTypeOptions } from "../../services/note_list_renderer"
import NoteContextAwareWidget from "../note_context_aware_widget";
type BookProperty = CheckBoxProperty | ButtonProperty;
interface BookConfig {
properties: BookProperty[]
properties: BookProperty[];
}
interface BookProperty {
label: string;
interface CheckBoxProperty {
type: "checkbox",
label: 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> = {
calendar: {
properties: [
@ -26,16 +43,49 @@ export const bookPropertiesConfig: Record<ViewTypeOptions, BookConfig> = {
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 $label = $("<label>").text(property.label);
$container.append($label);
const { note } = context;
switch (property.type) {
case "checkbox":
const $label = $("<label>").text(property.label);
const $checkbox = $("<input>", {
type: "checkbox",
class: "form-check-input",
@ -49,9 +99,24 @@ export function renderBookProperty(property: BookProperty, note: FNote) {
});
$checkbox.prop("checked", note.hasOwnedLabel(property.bindToLabel));
$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;
default:
throw new Error(`Unknown property type: ${property.type}`);
}
return $container;