Make update algorithm in editor-toolbar/index.ts recursive

This commit is contained in:
Henrik Giesel 2021-04-23 20:50:09 +02:00
parent 6ae368ebac
commit 48b7cb49f9
5 changed files with 122 additions and 114 deletions

View file

@ -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);
"""
)

View file

@ -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 ""

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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
);
}
}