mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Utilize enableButtons disableButtons from Svelte component
This commit is contained in:
parent
9340d20c20
commit
a820059b8f
13 changed files with 71 additions and 95 deletions
|
@ -82,7 +82,7 @@ _html = """
|
|||
}
|
||||
</style>
|
||||
<div>
|
||||
<anki-editor-toolbar></anki-editor-toolbar>
|
||||
<anki-editor-toolbar id="editorToolbar"></anki-editor-toolbar>
|
||||
<div id="fields">
|
||||
</div>
|
||||
<div id="dupes" class="is-inactive">
|
||||
|
@ -1113,6 +1113,7 @@ class Editor:
|
|||
dupes=showDupes,
|
||||
paste=onPaste,
|
||||
cutOrCopy=onCutOrCopy,
|
||||
htmlEdit=onHtmlEdit,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ esbuild(
|
|||
"//ts:protobuf-shim.js",
|
||||
],
|
||||
args = [
|
||||
"--global-name=anki",
|
||||
"--global-name=editorToolbar",
|
||||
"--inject:ts/protobuf-shim.js",
|
||||
"--loader:.svg=text",
|
||||
],
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
export const commandMap = writable(new Map<string, boolean>());
|
||||
|
||||
function updateButton(key: string): void {
|
||||
function initializeButton(key: string): void {
|
||||
commandMap.update(
|
||||
(map: Map<string, boolean>): Map<string, boolean> =>
|
||||
new Map([...map, [key, document.queryCommandState(key)]])
|
||||
|
@ -24,11 +24,11 @@
|
|||
);
|
||||
}
|
||||
|
||||
export function updateButtonActive() {
|
||||
export function updateActiveButtons() {
|
||||
updateButtons((key: string): boolean => document.queryCommandState(key));
|
||||
}
|
||||
|
||||
export function clearButtonActive() {
|
||||
export function clearActiveButtons() {
|
||||
updateButtons((): boolean => false);
|
||||
}
|
||||
</script>
|
||||
|
@ -44,7 +44,7 @@
|
|||
let active = false;
|
||||
|
||||
if (activatable) {
|
||||
updateButton(command);
|
||||
initializeButton(command);
|
||||
|
||||
commandMap.subscribe((map: Record<string, boolean>): void => {
|
||||
active = map.get(command);
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
<script lang="typescript">
|
||||
import type { Readable } from "svelte/store";
|
||||
import { setContext } from "svelte";
|
||||
import { disabledKey, nightModeKey } from "./contextKeys";
|
||||
|
||||
import ButtonGroup from "./ButtonGroup.svelte";
|
||||
import type { Buttons } from "./ButtonGroup.svelte";
|
||||
|
||||
export let buttons: Buttons = [];
|
||||
export let nightMode: boolean;
|
||||
export let disabled: Readable<boolean> = false;
|
||||
|
||||
console.log(nightMode);
|
||||
setContext(disabledKey, disabled);
|
||||
setContext(nightModeKey, nightMode);
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
<script lang="typescript">
|
||||
import { getContext } from "svelte";
|
||||
import type { Readable } from "svelte/store";
|
||||
import { disabledKey } from "./contextKeys";
|
||||
|
||||
export let className: string = "";
|
||||
export let onClick: (event: ClickEvent) => void;
|
||||
export let active = false;
|
||||
export let disabled = false;
|
||||
|
||||
const disabledStore = getContext(disabledKey)
|
||||
$: disabled = $disabledStore;
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -16,6 +22,7 @@
|
|||
|
||||
& > :global(svg),
|
||||
& > :global(img) {
|
||||
fill: currentColor;
|
||||
vertical-align: unset;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -38,6 +45,7 @@
|
|||
|
||||
&[disabled] {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
|
||||
&:hover {
|
||||
background-color: white;
|
||||
|
|
2
ts/editor-toolbar/contextKeys.ts
Normal file
2
ts/editor-toolbar/contextKeys.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export let nightModeKey = Symbol("nightMode");
|
||||
export let disabledKey = Symbol("disabled");
|
|
@ -1,5 +1,5 @@
|
|||
// @ts-ignore
|
||||
import CommandIconButton, { updateButtonActive } from "./CommandIconButton.svelte";
|
||||
import CommandIconButton from "./CommandIconButton.svelte";
|
||||
import boldIcon from "./type-bold.svg";
|
||||
import italicIcon from "./type-italic.svg";
|
||||
import underlineIcon from "./type-underline.svg";
|
||||
|
@ -43,6 +43,3 @@ export const eraserButton = {
|
|||
command: "removeFormat",
|
||||
highlightable: false,
|
||||
};
|
||||
|
||||
// TODO
|
||||
setInterval(updateButtonActive, 2000);
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
import type { SvelteComponent } from "svelte";
|
||||
|
||||
import { checkNightMode } from "anki/nightmode";
|
||||
import { setupI18n, ModuleName } from "anki/i18n";
|
||||
|
||||
import EditorToolbarSvelte from "./EditorToolbar.svelte";
|
||||
|
||||
import LabelButton from "./LabelButton.svelte";
|
||||
|
||||
// @ts-ignore
|
||||
export { updateActiveButtons, clearActiveButtons } from "./CommandIconButton.svelte";
|
||||
import { Writable, writable } from "svelte/store";
|
||||
|
||||
import {
|
||||
boldButton,
|
||||
italicButton,
|
||||
|
@ -42,17 +49,29 @@ const defaultButtons = [
|
|||
|
||||
class EditorToolbar extends HTMLElement {
|
||||
component?: SvelteComponent;
|
||||
disabled?: Writable<boolean>;
|
||||
|
||||
connectedCallback(): void {
|
||||
const nightMode = checkNightMode();
|
||||
this.disabled = writable(false);
|
||||
|
||||
this.component = new EditorToolbarSvelte({
|
||||
target: this,
|
||||
props: {
|
||||
nightMode,
|
||||
buttons: defaultButtons,
|
||||
},
|
||||
});
|
||||
setupI18n({ modules: [ModuleName.STATISTICS, ModuleName.SCHEDULING] }).then(() => {
|
||||
this.component = new EditorToolbarSvelte({
|
||||
target: this,
|
||||
props: {
|
||||
buttons: defaultButtons,
|
||||
nightMode: checkNightMode(),
|
||||
disabled: this.disabled,
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
enableButtons(): void {
|
||||
this.disabled?.set(false);
|
||||
}
|
||||
|
||||
disableButtons(): void {
|
||||
this.disabled?.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import type { Editable } from "./editable";
|
|||
import { bridgeCommand } from "./lib";
|
||||
import { onInput, onKey, onKeyUp } from "./inputHandlers";
|
||||
import { onFocus, onBlur } from "./focusHandlers";
|
||||
import { updateButtonState } from "./toolbar";
|
||||
|
||||
function onPaste(evt: ClipboardEvent): void {
|
||||
bridgeCommand("paste");
|
||||
|
@ -60,7 +59,8 @@ export class EditingArea extends HTMLDivElement {
|
|||
this.addEventListener("paste", onPaste);
|
||||
this.addEventListener("copy", onCutOrCopy);
|
||||
this.addEventListener("oncut", onCutOrCopy);
|
||||
this.addEventListener("mouseup", updateButtonState);
|
||||
// @ts-ignore
|
||||
this.addEventListener("mouseup", editorToolbar.updateActiveButtons);
|
||||
|
||||
const baseStyleSheet = this.baseStyle.sheet as CSSStyleSheet;
|
||||
baseStyleSheet.insertRule("anki-editable {}", 0);
|
||||
|
@ -75,7 +75,8 @@ export class EditingArea extends HTMLDivElement {
|
|||
this.removeEventListener("paste", onPaste);
|
||||
this.removeEventListener("copy", onCutOrCopy);
|
||||
this.removeEventListener("oncut", onCutOrCopy);
|
||||
this.removeEventListener("mouseup", updateButtonState);
|
||||
// @ts-ignore
|
||||
this.removeEventListener("mouseup", editorToolbar.updateActiveButtons);
|
||||
}
|
||||
|
||||
initialize(color: string, content: string): void {
|
||||
|
|
|
@ -5,13 +5,13 @@ import type { EditingArea } from "./editingArea";
|
|||
|
||||
import { saveField } from "./changeTimer";
|
||||
import { bridgeCommand } from "./lib";
|
||||
import { enableButtons, disableButtons } from "./toolbar";
|
||||
|
||||
export function onFocus(evt: FocusEvent): void {
|
||||
const currentField = evt.currentTarget as EditingArea;
|
||||
currentField.focusEditable();
|
||||
bridgeCommand(`focus:${currentField.ord}`);
|
||||
enableButtons();
|
||||
// @ts-ignore
|
||||
document.getElementById("editorToolbar").enableButtons();
|
||||
}
|
||||
|
||||
export function onBlur(evt: FocusEvent): void {
|
||||
|
@ -19,5 +19,6 @@ export function onBlur(evt: FocusEvent): void {
|
|||
const currentFieldUnchanged = previousFocus === document.activeElement;
|
||||
|
||||
saveField(previousFocus, currentFieldUnchanged ? "key" : "blur");
|
||||
disableButtons();
|
||||
// @ts-ignore
|
||||
document.getElementById("editorToolbar").disableButtons();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import { filterHTML } from "html-filter";
|
|||
|
||||
import { caretToEnd } from "./helpers";
|
||||
import { saveField } from "./changeTimer";
|
||||
import { updateButtonState, disableButtons } from "./toolbar";
|
||||
|
||||
import { EditorField } from "./editorField";
|
||||
import { LabelContainer } from "./labelContainer";
|
||||
|
@ -13,7 +12,6 @@ import { EditingArea } from "./editingArea";
|
|||
import { Editable } from "./editable";
|
||||
|
||||
export { setNoteId, getNoteId } from "./noteId";
|
||||
export { preventButtonFocus, toggleEditorButton, setFGButton } from "./toolbar";
|
||||
export { saveNow } from "./changeTimer";
|
||||
export { wrap, wrapIntoText } from "./wrap";
|
||||
|
||||
|
@ -43,7 +41,8 @@ export function focusField(n: number): void {
|
|||
if (field) {
|
||||
field.editingArea.focusEditable();
|
||||
caretToEnd(field.editingArea);
|
||||
updateButtonState();
|
||||
// @ts-ignore
|
||||
editorToolbar.updateActiveButtons();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +122,8 @@ export function setFields(fields: [string, string][]): void {
|
|||
|
||||
if (!getCurrentField()) {
|
||||
// when initial focus of the window is not on editor (e.g. browser)
|
||||
disableButtons();
|
||||
// @ts-ignore
|
||||
document.getElementById("editorToolbar").disableButtons();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,6 +158,7 @@ export function setFormat(cmd: string, arg?: any, nosave: boolean = false): void
|
|||
document.execCommand(cmd, false, arg);
|
||||
if (!nosave) {
|
||||
saveField(getCurrentField() as EditingArea, "key");
|
||||
updateButtonState();
|
||||
// @ts-ignore
|
||||
editorToolbar.updateActiveButtons();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
import { EditingArea } from "./editingArea";
|
||||
import { caretToEnd, nodeIsElement } from "./helpers";
|
||||
import { triggerChangeTimer } from "./changeTimer";
|
||||
import { updateButtonState } from "./toolbar";
|
||||
|
||||
function inListItem(currentField: EditingArea): boolean {
|
||||
const anchor = currentField.getSelection()!.anchorNode!;
|
||||
|
@ -22,7 +21,8 @@ function inListItem(currentField: EditingArea): boolean {
|
|||
export function onInput(event: Event): void {
|
||||
// make sure IME changes get saved
|
||||
triggerChangeTimer(event.currentTarget as EditingArea);
|
||||
updateButtonState();
|
||||
// @ts-ignore
|
||||
editorToolbar.updateActiveButtons();
|
||||
}
|
||||
|
||||
export function onKey(evt: KeyboardEvent): void {
|
||||
|
@ -69,7 +69,8 @@ globalThis.addEventListener("keydown", (evt: KeyboardEvent) => {
|
|||
const newFocusTarget = evt.target;
|
||||
if (newFocusTarget instanceof EditingArea) {
|
||||
caretToEnd(newFocusTarget);
|
||||
updateButtonState();
|
||||
// @ts-ignore
|
||||
editorToolbar.updateActiveButtons();
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
const highlightButtons = ["bold", "italic", "underline", "superscript", "subscript"];
|
||||
|
||||
export function updateButtonState(): void {
|
||||
for (const name of highlightButtons) {
|
||||
const elem = document.querySelector(`#${name}`) as HTMLElement;
|
||||
elem.classList.toggle("highlighted", document.queryCommandState(name));
|
||||
}
|
||||
|
||||
// fixme: forecolor
|
||||
// 'col': document.queryCommandValue("forecolor")
|
||||
}
|
||||
|
||||
function clearButtonHighlight(): void {
|
||||
for (const name of highlightButtons) {
|
||||
const elem = document.querySelector(`#${name}`) as HTMLElement;
|
||||
elem.classList.remove("highlighted");
|
||||
}
|
||||
}
|
||||
|
||||
export function preventButtonFocus(): void {
|
||||
for (const element of document.querySelectorAll("button.linkb")) {
|
||||
element.addEventListener("mousedown", (evt: Event) => {
|
||||
evt.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function enableButtons(): void {
|
||||
const buttons = document.querySelectorAll(
|
||||
"button.linkb"
|
||||
) as NodeListOf<HTMLButtonElement>;
|
||||
buttons.forEach((elem: HTMLButtonElement): void => {
|
||||
elem.disabled = false;
|
||||
});
|
||||
updateButtonState();
|
||||
}
|
||||
|
||||
export function disableButtons(): void {
|
||||
const buttons = document.querySelectorAll(
|
||||
"button.linkb:not(.perm)"
|
||||
) as NodeListOf<HTMLButtonElement>;
|
||||
buttons.forEach((elem: HTMLButtonElement): void => {
|
||||
elem.disabled = true;
|
||||
});
|
||||
clearButtonHighlight();
|
||||
}
|
||||
|
||||
export function setFGButton(col: string): void {
|
||||
document.getElementById("forecolor")!.style.backgroundColor = col;
|
||||
}
|
||||
|
||||
export function toggleEditorButton(buttonOrId: string | HTMLElement): void {
|
||||
const button =
|
||||
typeof buttonOrId === "string"
|
||||
? (document.getElementById(buttonOrId) as HTMLElement)
|
||||
: buttonOrId;
|
||||
button.classList.toggle("highlighted");
|
||||
}
|
Loading…
Reference in a new issue