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))}`, tooltip: `{tr.browsing_preview_selected_card(val=shortcut(preview_shortcut))}`,
onClick: () => bridgeCommand("preview"), onClick: () => bridgeCommand("preview"),
disables: false, disables: false,
}}), "notetype"); }}), "notetype", -1);
""" """
) )

View file

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

View file

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

View file

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

View file

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