mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Make update algorithm in editor-toolbar/index.ts recursive
This commit is contained in:
parent
6ae368ebac
commit
48b7cb49f9
5 changed files with 122 additions and 114 deletions
|
@ -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);
|
||||
"""
|
||||
)
|
||||
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -4,14 +4,17 @@ interface Hideable {
|
|||
hidden?: boolean;
|
||||
}
|
||||
|
||||
export function showComponent(component: Hideable): void {
|
||||
export function showComponent<T extends Hideable>(component: T): T {
|
||||
component.hidden = false;
|
||||
return component;
|
||||
}
|
||||
|
||||
export function hideComponent(component: Hideable): void {
|
||||
export function hideComponent<T extends Hideable>(component: T): T {
|
||||
component.hidden = true;
|
||||
return component;
|
||||
}
|
||||
|
||||
export function toggleComponent(component: Hideable): void {
|
||||
export function toggleComponent<T extends Hideable>(component: T): T {
|
||||
component.hidden = !component.hidden;
|
||||
return component;
|
||||
}
|
||||
|
|
|
@ -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<T extends Identifiable> extends Identifiable {
|
||||
items: T[];
|
||||
}
|
||||
|
||||
export type Identifier = string | number;
|
||||
|
||||
function normalize<T extends Identifiable>(
|
||||
values: T[],
|
||||
idOrIndex: string | number
|
||||
iterable: IterableIdentifiable<T>,
|
||||
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<T extends Identifiable>(
|
||||
values: T[],
|
||||
idOrIndex: string | number
|
||||
): T | null {
|
||||
const index = normalize(values, idOrIndex);
|
||||
function search<T extends Identifiable>(values: T[], index: number): T | null {
|
||||
return index >= 0 ? values[index] : null;
|
||||
}
|
||||
|
||||
export function insert<T extends Identifiable>(
|
||||
values: T[],
|
||||
iterable: IterableIdentifiable<T> & 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> & 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<T extends Identifiable>(
|
||||
values: T[],
|
||||
iterable: IterableIdentifiable<T> & 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> & 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<T>(component: Identifiable): component is IterableIdentifiable<T> {
|
||||
return Boolean(Object.prototype.hasOwnProperty.call(component, "items"));
|
||||
}
|
||||
|
||||
export function updateRecursive<T extends Identifiable>(
|
||||
update: (component: T) => T,
|
||||
component: T,
|
||||
...identifiers: Identifier[]
|
||||
): T {
|
||||
if (identifiers.length === 0) {
|
||||
return update(component);
|
||||
} else if (isRecursive<T>(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;
|
||||
}
|
||||
|
|
|
@ -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<IterableToolbarItem[]>) => 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<IterableToolbarItem[]>
|
||||
): Writable<IterableToolbarItem[]> => {
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue