diff --git a/qt/aqt/browser/browser.py b/qt/aqt/browser/browser.py index 7624c6d44..9e42e70ec 100644 --- a/qt/aqt/browser/browser.py +++ b/qt/aqt/browser/browser.py @@ -391,7 +391,7 @@ $editorToolbar.addButton(editorToolbar.labelButton({{ tooltip: `{tr.browsing_preview_selected_card(val=shortcut(preview_shortcut))}`, onClick: () => bridgeCommand("preview"), disables: false, -}}), "notetype"); +}}), "notetype", -1); """ ) diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 2d7acb39a..1db017bb1 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -155,7 +155,7 @@ class Editor: gui_hooks.editor_did_init_left_buttons(lefttopbtns, self) lefttopbtns_defs = [ - f"$editorToolbar.addButton(editorToolbar.rawButton({{ html: `{button}` }}), 'notetype');" + f"$editorToolbar.addButton(editorToolbar.rawButton({{ html: `{button}` }}), 'notetype', -1);" for button in lefttopbtns ] lefttopbtns_js = "\n".join(lefttopbtns_defs) @@ -173,10 +173,10 @@ class Editor: ) righttopbtns_js = ( f""" -$editorToolbar.addButtonGroup(editorToolbar.buttonGroup({{ +$editorToolbar.addButton(editorToolbar.buttonGroup({{ id: "addons", items: [ {righttopbtns_defs} ] -}})); +}}), -1); """ if righttopbtns_defs else "" diff --git a/ts/editor-toolbar/hideable.ts b/ts/editor-toolbar/hideable.ts index a236278bd..4df9af725 100644 --- a/ts/editor-toolbar/hideable.ts +++ b/ts/editor-toolbar/hideable.ts @@ -4,14 +4,17 @@ interface Hideable { hidden?: boolean; } -export function showComponent(component: Hideable): void { +export function showComponent(component: T): T { component.hidden = false; + return component; } -export function hideComponent(component: Hideable): void { +export function hideComponent(component: T): T { component.hidden = true; + return component; } -export function toggleComponent(component: Hideable): void { +export function toggleComponent(component: T): T { component.hidden = !component.hidden; + return component; } diff --git a/ts/editor-toolbar/identifiable.ts b/ts/editor-toolbar/identifiable.ts index e4acb0b44..b9eff01f5 100644 --- a/ts/editor-toolbar/identifiable.ts +++ b/ts/editor-toolbar/identifiable.ts @@ -1,52 +1,98 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -interface Identifiable { +export interface Identifiable { id?: string; } +interface IterableIdentifiable extends Identifiable { + items: T[]; +} + +export type Identifier = string | number; + function normalize( - values: T[], - idOrIndex: string | number + iterable: IterableIdentifiable, + idOrIndex: Identifier ): number { let normalizedIndex: number; if (typeof idOrIndex === "string") { - normalizedIndex = values.findIndex((value) => value.id === idOrIndex); + normalizedIndex = iterable.items.findIndex((value) => value.id === idOrIndex); } else if (idOrIndex < 0) { - normalizedIndex = values.length + idOrIndex; + normalizedIndex = iterable.items.length + idOrIndex; } else { normalizedIndex = idOrIndex; } - return normalizedIndex >= values.length ? -1 : normalizedIndex; + return normalizedIndex >= iterable.items.length ? -1 : normalizedIndex; } -export function search( - values: T[], - idOrIndex: string | number -): T | null { - const index = normalize(values, idOrIndex); +function search(values: T[], index: number): T | null { return index >= 0 ? values[index] : null; } export function insert( - values: T[], + iterable: IterableIdentifiable & T, value: T, - idOrIndex: string | number -): T[] { - const index = normalize(values, idOrIndex); - return index >= 0 - ? [...values.slice(0, index), value, ...values.slice(index)] - : values; + idOrIndex: Identifier +): IterableIdentifiable & T { + const index = normalize(iterable, idOrIndex); + + if (index >= 0) { + iterable.items = [ + ...iterable.items.slice(0, index), + value, + ...iterable.items.slice(index), + ]; + } + + return iterable; } export function add( - values: T[], + iterable: IterableIdentifiable & T, value: T, - idOrIndex: string | number -): T[] { - const index = normalize(values, idOrIndex); - return index >= 0 - ? [...values.slice(0, index + 1), value, ...values.slice(index + 1)] - : values; + idOrIndex: Identifier +): IterableIdentifiable & T { + const index = normalize(iterable, idOrIndex); + + if (index >= 0) { + iterable.items = [ + ...iterable.items.slice(0, index + 1), + value, + ...iterable.items.slice(index + 1), + ]; + } + + return iterable; +} + +function isRecursive(component: Identifiable): component is IterableIdentifiable { + return Boolean(Object.prototype.hasOwnProperty.call(component, "items")); +} + +export function updateRecursive( + update: (component: T) => T, + component: T, + ...identifiers: Identifier[] +): T { + if (identifiers.length === 0) { + return update(component); + } else if (isRecursive(component)) { + const [identifier, ...restIdentifiers] = identifiers; + const normalizedIndex = normalize(component, identifier); + const foundComponent = search(component.items, normalizedIndex); + + if (foundComponent) { + component.items[normalizedIndex] = updateRecursive( + update, + foundComponent as T, + ...restIdentifiers + ); + } + + return component; + } + + return component; } diff --git a/ts/editor-toolbar/index.ts b/ts/editor-toolbar/index.ts index 2909a7a88..fc3e34b49 100644 --- a/ts/editor-toolbar/index.ts +++ b/ts/editor-toolbar/index.ts @@ -2,6 +2,7 @@ // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import type { SvelteComponentDev } from "svelte/internal"; import type { ToolbarItem, IterableToolbarItem } from "./types"; +import type { Identifier } from "./identifiable"; import { Writable, writable } from "svelte/store"; @@ -9,7 +10,7 @@ import EditorToolbarSvelte from "./EditorToolbar.svelte"; import "./bootstrap.css"; -import { search, add, insert } from "./identifiable"; +import { add, insert, updateRecursive } from "./identifiable"; import { showComponent, hideComponent, toggleComponent } from "./hideable"; let buttonsResolve: (value: Writable) => void; @@ -46,101 +47,59 @@ export class EditorToolbar extends HTMLElement { menusResolve(menus); } - updateButtonGroup( - update: (component: IterableToolbarItem) => void, - group: string | number - ): void { - this.buttonsPromise.then((buttons) => { - buttons.update((buttonGroups) => { - const foundGroup = search(buttonGroups, group); - - if (foundGroup) { - update(foundGroup as IterableToolbarItem); - } - - return buttonGroups; - }); - - return buttons; - }); - } - - showButtonGroup(group: string | number): void { - this.updateButtonGroup(showComponent, group); - } - - hideButtonGroup(group: string | number): void { - this.updateButtonGroup(hideComponent, group); - } - - toggleButtonGroup(group: string | number): void { - this.updateButtonGroup(toggleComponent, group); - } - - insertButtonGroup(newGroup: IterableToolbarItem, group: string | number = 0): void { - this.buttonsPromise.then((buttons) => { - buttons.update((buttonGroups) => { - return insert(buttonGroups, newGroup, group); - }); - - return buttons; - }); - } - - addButtonGroup(newGroup: IterableToolbarItem, group: string | number = -1): void { - this.buttonsPromise.then((buttons) => { - buttons.update((buttonGroups) => { - return add(buttonGroups, newGroup, group); - }); - - return buttons; - }); - } - updateButton( - update: (component: ToolbarItem) => void, - group: string | number, - button: string | number + update: (component: ToolbarItem) => ToolbarItem, + ...identifiers: Identifier[] ): void { - this.updateButtonGroup((foundGroup) => { - const foundButton = search(foundGroup.items, button); + this.buttonsPromise.then( + ( + buttons: Writable + ): Writable => { + buttons.update( + (items: IterableToolbarItem[]): IterableToolbarItem[] => + updateRecursive( + update, + { component: EditorToolbarSvelte, items }, + ...identifiers + ).items as IterableToolbarItem[] + ); - if (foundButton) { - update(foundButton); + return buttons; } - }, group); + ); } - showButton(group: string | number, button: string | number): void { - this.updateButton(showComponent, group, button); + showButton(...identifiers: Identifier[]): void { + this.updateButton(showComponent, ...identifiers); } - hideButton(group: string | number, button: string | number): void { - this.updateButton(hideComponent, group, button); + hideButton(...identifiers: Identifier[]): void { + this.updateButton(hideComponent, ...identifiers); } - toggleButton(group: string | number, button: string | number): void { - this.updateButton(toggleComponent, group, button); + toggleButton(...identifiers: Identifier[]): void { + this.updateButton(toggleComponent, ...identifiers); } - insertButton( - newButton: ToolbarItem, - group: string | number, - button: string | number = 0 - ): void { - this.updateButtonGroup((component: IterableToolbarItem) => { - component.items = insert(component.items, newButton, button); - }, group); + insertButton(newButton: ToolbarItem, ...identifiers: Identifier[]): void { + const initIdentifiers = identifiers.slice(0, -1); + const lastIdentifier = identifiers[identifiers.length - 1]; + this.updateButton( + (component: ToolbarItem) => + insert(component as IterableToolbarItem, newButton, lastIdentifier), + + ...initIdentifiers + ); } - addButton( - newButton: ToolbarItem, - group: string | number, - button: string | number = -1 - ): void { - this.updateButtonGroup((component: IterableToolbarItem) => { - component.items = add(component.items, newButton, button); - }, group); + addButton(newButton: ToolbarItem, ...identifiers: Identifier[]): void { + const initIdentifiers = identifiers.slice(0, -1); + const lastIdentifier = identifiers[identifiers.length - 1]; + this.updateButton( + (component: ToolbarItem) => + add(component as IterableToolbarItem, newButton, lastIdentifier), + ...initIdentifiers + ); } }