mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 06:52: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))}`,
|
tooltip: `{tr.browsing_preview_selected_card(val=shortcut(preview_shortcut))}`,
|
||||||
onClick: () => bridgeCommand("preview"),
|
onClick: () => bridgeCommand("preview"),
|
||||||
disables: false,
|
disables: false,
|
||||||
}}), "notetype");
|
}}), "notetype", -1);
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ class Editor:
|
||||||
gui_hooks.editor_did_init_left_buttons(lefttopbtns, self)
|
gui_hooks.editor_did_init_left_buttons(lefttopbtns, self)
|
||||||
|
|
||||||
lefttopbtns_defs = [
|
lefttopbtns_defs = [
|
||||||
f"$editorToolbar.addButton(editorToolbar.rawButton({{ html: `{button}` }}), 'notetype');"
|
f"$editorToolbar.addButton(editorToolbar.rawButton({{ html: `{button}` }}), 'notetype', -1);"
|
||||||
for button in lefttopbtns
|
for button in lefttopbtns
|
||||||
]
|
]
|
||||||
lefttopbtns_js = "\n".join(lefttopbtns_defs)
|
lefttopbtns_js = "\n".join(lefttopbtns_defs)
|
||||||
|
@ -173,10 +173,10 @@ class Editor:
|
||||||
)
|
)
|
||||||
righttopbtns_js = (
|
righttopbtns_js = (
|
||||||
f"""
|
f"""
|
||||||
$editorToolbar.addButtonGroup(editorToolbar.buttonGroup({{
|
$editorToolbar.addButton(editorToolbar.buttonGroup({{
|
||||||
id: "addons",
|
id: "addons",
|
||||||
items: [ {righttopbtns_defs} ]
|
items: [ {righttopbtns_defs} ]
|
||||||
}}));
|
}}), -1);
|
||||||
"""
|
"""
|
||||||
if righttopbtns_defs
|
if righttopbtns_defs
|
||||||
else ""
|
else ""
|
||||||
|
|
|
@ -4,14 +4,17 @@ interface Hideable {
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showComponent(component: Hideable): void {
|
export function showComponent<T extends Hideable>(component: T): T {
|
||||||
component.hidden = false;
|
component.hidden = false;
|
||||||
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hideComponent(component: Hideable): void {
|
export function hideComponent<T extends Hideable>(component: T): T {
|
||||||
component.hidden = true;
|
component.hidden = true;
|
||||||
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toggleComponent(component: Hideable): void {
|
export function toggleComponent<T extends Hideable>(component: T): T {
|
||||||
component.hidden = !component.hidden;
|
component.hidden = !component.hidden;
|
||||||
|
return component;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,98 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
interface Identifiable {
|
export interface Identifiable {
|
||||||
id?: string;
|
id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IterableIdentifiable<T extends Identifiable> extends Identifiable {
|
||||||
|
items: T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Identifier = string | number;
|
||||||
|
|
||||||
function normalize<T extends Identifiable>(
|
function normalize<T extends Identifiable>(
|
||||||
values: T[],
|
iterable: IterableIdentifiable<T>,
|
||||||
idOrIndex: string | number
|
idOrIndex: Identifier
|
||||||
): number {
|
): number {
|
||||||
let normalizedIndex: number;
|
let normalizedIndex: number;
|
||||||
|
|
||||||
if (typeof idOrIndex === "string") {
|
if (typeof idOrIndex === "string") {
|
||||||
normalizedIndex = values.findIndex((value) => value.id === idOrIndex);
|
normalizedIndex = iterable.items.findIndex((value) => value.id === idOrIndex);
|
||||||
} else if (idOrIndex < 0) {
|
} else if (idOrIndex < 0) {
|
||||||
normalizedIndex = values.length + idOrIndex;
|
normalizedIndex = iterable.items.length + idOrIndex;
|
||||||
} else {
|
} else {
|
||||||
normalizedIndex = idOrIndex;
|
normalizedIndex = idOrIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalizedIndex >= values.length ? -1 : normalizedIndex;
|
return normalizedIndex >= iterable.items.length ? -1 : normalizedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function search<T extends Identifiable>(
|
function search<T extends Identifiable>(values: T[], index: number): T | null {
|
||||||
values: T[],
|
|
||||||
idOrIndex: string | number
|
|
||||||
): T | null {
|
|
||||||
const index = normalize(values, idOrIndex);
|
|
||||||
return index >= 0 ? values[index] : null;
|
return index >= 0 ? values[index] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function insert<T extends Identifiable>(
|
export function insert<T extends Identifiable>(
|
||||||
values: T[],
|
iterable: IterableIdentifiable<T> & T,
|
||||||
value: T,
|
value: T,
|
||||||
idOrIndex: string | number
|
idOrIndex: Identifier
|
||||||
): T[] {
|
): IterableIdentifiable<T> & T {
|
||||||
const index = normalize(values, idOrIndex);
|
const index = normalize(iterable, idOrIndex);
|
||||||
return index >= 0
|
|
||||||
? [...values.slice(0, index), value, ...values.slice(index)]
|
if (index >= 0) {
|
||||||
: values;
|
iterable.items = [
|
||||||
|
...iterable.items.slice(0, index),
|
||||||
|
value,
|
||||||
|
...iterable.items.slice(index),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function add<T extends Identifiable>(
|
export function add<T extends Identifiable>(
|
||||||
values: T[],
|
iterable: IterableIdentifiable<T> & T,
|
||||||
value: T,
|
value: T,
|
||||||
idOrIndex: string | number
|
idOrIndex: Identifier
|
||||||
): T[] {
|
): IterableIdentifiable<T> & T {
|
||||||
const index = normalize(values, idOrIndex);
|
const index = normalize(iterable, idOrIndex);
|
||||||
return index >= 0
|
|
||||||
? [...values.slice(0, index + 1), value, ...values.slice(index + 1)]
|
if (index >= 0) {
|
||||||
: values;
|
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
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import type { SvelteComponentDev } from "svelte/internal";
|
import type { SvelteComponentDev } from "svelte/internal";
|
||||||
import type { ToolbarItem, IterableToolbarItem } from "./types";
|
import type { ToolbarItem, IterableToolbarItem } from "./types";
|
||||||
|
import type { Identifier } from "./identifiable";
|
||||||
|
|
||||||
import { Writable, writable } from "svelte/store";
|
import { Writable, writable } from "svelte/store";
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ import EditorToolbarSvelte from "./EditorToolbar.svelte";
|
||||||
|
|
||||||
import "./bootstrap.css";
|
import "./bootstrap.css";
|
||||||
|
|
||||||
import { search, add, insert } from "./identifiable";
|
import { add, insert, updateRecursive } from "./identifiable";
|
||||||
import { showComponent, hideComponent, toggleComponent } from "./hideable";
|
import { showComponent, hideComponent, toggleComponent } from "./hideable";
|
||||||
|
|
||||||
let buttonsResolve: (value: Writable<IterableToolbarItem[]>) => void;
|
let buttonsResolve: (value: Writable<IterableToolbarItem[]>) => void;
|
||||||
|
@ -46,101 +47,59 @@ export class EditorToolbar extends HTMLElement {
|
||||||
menusResolve(menus);
|
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(
|
updateButton(
|
||||||
update: (component: ToolbarItem) => void,
|
update: (component: ToolbarItem) => ToolbarItem,
|
||||||
group: string | number,
|
...identifiers: Identifier[]
|
||||||
button: string | number
|
|
||||||
): void {
|
): void {
|
||||||
this.updateButtonGroup((foundGroup) => {
|
this.buttonsPromise.then(
|
||||||
const foundButton = search(foundGroup.items, button);
|
(
|
||||||
|
buttons: Writable<IterableToolbarItem[]>
|
||||||
|
): Writable<IterableToolbarItem[]> => {
|
||||||
|
buttons.update(
|
||||||
|
(items: IterableToolbarItem[]): IterableToolbarItem[] =>
|
||||||
|
updateRecursive(
|
||||||
|
update,
|
||||||
|
{ component: EditorToolbarSvelte, items },
|
||||||
|
...identifiers
|
||||||
|
).items as IterableToolbarItem[]
|
||||||
|
);
|
||||||
|
|
||||||
if (foundButton) {
|
return buttons;
|
||||||
update(foundButton);
|
|
||||||
}
|
}
|
||||||
}, group);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
showButton(group: string | number, button: string | number): void {
|
showButton(...identifiers: Identifier[]): void {
|
||||||
this.updateButton(showComponent, group, button);
|
this.updateButton(showComponent, ...identifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
hideButton(group: string | number, button: string | number): void {
|
hideButton(...identifiers: Identifier[]): void {
|
||||||
this.updateButton(hideComponent, group, button);
|
this.updateButton(hideComponent, ...identifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleButton(group: string | number, button: string | number): void {
|
toggleButton(...identifiers: Identifier[]): void {
|
||||||
this.updateButton(toggleComponent, group, button);
|
this.updateButton(toggleComponent, ...identifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
insertButton(
|
insertButton(newButton: ToolbarItem, ...identifiers: Identifier[]): void {
|
||||||
newButton: ToolbarItem,
|
const initIdentifiers = identifiers.slice(0, -1);
|
||||||
group: string | number,
|
const lastIdentifier = identifiers[identifiers.length - 1];
|
||||||
button: string | number = 0
|
this.updateButton(
|
||||||
): void {
|
(component: ToolbarItem) =>
|
||||||
this.updateButtonGroup((component: IterableToolbarItem) => {
|
insert(component as IterableToolbarItem, newButton, lastIdentifier),
|
||||||
component.items = insert(component.items, newButton, button);
|
|
||||||
}, group);
|
...initIdentifiers
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
addButton(
|
addButton(newButton: ToolbarItem, ...identifiers: Identifier[]): void {
|
||||||
newButton: ToolbarItem,
|
const initIdentifiers = identifiers.slice(0, -1);
|
||||||
group: string | number,
|
const lastIdentifier = identifiers[identifiers.length - 1];
|
||||||
button: string | number = -1
|
this.updateButton(
|
||||||
): void {
|
(component: ToolbarItem) =>
|
||||||
this.updateButtonGroup((component: IterableToolbarItem) => {
|
add(component as IterableToolbarItem, newButton, lastIdentifier),
|
||||||
component.items = add(component.items, newButton, button);
|
...initIdentifiers
|
||||||
}, group);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue