Merge pull request #1376 from hgiesel/mathjaxcleanupv2

Mathjax Cleanup
This commit is contained in:
Damien Elmes 2021-09-21 18:39:27 +10:00 committed by GitHub
commit 09cc55b0d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 84 additions and 36 deletions

View file

@ -3,7 +3,7 @@ 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
--> -->
<script lang="ts"> <script lang="ts">
import { onMount, getContext } from "svelte"; import { onMount, onDestroy, getContext, tick } from "svelte";
import { nightModeKey } from "components/context-keys"; import { nightModeKey } from "components/context-keys";
import { convertMathjax } from "./mathjax"; import { convertMathjax } from "./mathjax";
@ -22,18 +22,27 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let encoded: string; let encoded: string;
let imageHeight: number; let imageHeight: number;
$: { $: encoded = encodeURIComponent(converted);
encoded = encodeURIComponent(converted);
setTimeout(() => (imageHeight = image.getBoundingClientRect().height));
}
let image: HTMLImageElement; let image: HTMLImageElement;
const observer = new ResizeObserver(async () => {
imageHeight = image.getBoundingClientRect().height;
await tick();
setTimeout(() => image.dispatchEvent(new Event("resize")));
});
onMount(() => { onMount(() => {
observer.observe(image);
if (autofocus) { if (autofocus) {
image.click(); image.click();
} }
}); });
onDestroy(() => {
observer.unobserve(image);
observer.disconnect();
});
</script> </script>
<img <img

View file

@ -1,6 +1,10 @@
// 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
/* eslint
@typescript-eslint/no-explicit-any: "off",
*/
import { mathIcon } from "./icons"; import { mathIcon } from "./icons";
const parser = new DOMParser(); const parser = new DOMParser();
@ -36,19 +40,25 @@ export function convertMathjax(
return getEmptyIcon(style); return getEmptyIcon(style);
} }
const output = globalThis.MathJax.tex2svg(input); let output: Element;
const svg = output.children[0]; try {
output = globalThis.MathJax.tex2svg(input);
} catch (e) {
return ["Mathjax Error", String(e)];
}
if (svg.viewBox.baseVal.height === 16) { const svg = output.children[0] as SVGElement;
if ((svg as any).viewBox.baseVal.height === 16) {
return getEmptyIcon(style); return getEmptyIcon(style);
} }
let title = ""; let title = "";
if (svg.innerHTML.includes("data-mjx-error")) { if (svg.innerHTML.includes("data-mjx-error")) {
svg.querySelector("rect").setAttribute("fill", "yellow"); svg.querySelector("rect")?.setAttribute("fill", "yellow");
svg.querySelector("text").setAttribute("color", "red"); svg.querySelector("text")?.setAttribute("color", "red");
title = svg.querySelector("title").innerHTML; title = svg.querySelector("title")?.innerHTML ?? "";
} else { } else {
svg.insertBefore(style, svg.children[0]); svg.insertBefore(style, svg.children[0]);
} }

View file

@ -20,6 +20,27 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let dropdownApi: any; let dropdownApi: any;
let removeEventListener: () => void = () => {
/* noop */
};
function onImageResize(): void {
if (activeImage) {
errorMessage = activeImage.title;
updateSelection().then(() => dropdownApi.update());
}
}
$: if (activeImage) {
activeImage.addEventListener("resize", onImageResize);
const lastImage = activeImage;
removeEventListener = () =>
lastImage.removeEventListener("resize", onImageResize);
} else {
removeEventListener();
}
const resizeObserver = new ResizeObserver(async () => { const resizeObserver = new ResizeObserver(async () => {
if (activeImage) { if (activeImage) {
await updateSelection(); await updateSelection();
@ -36,21 +57,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
return image.closest("anki-mathjax")! as HTMLElement; return image.closest("anki-mathjax")! as HTMLElement;
} }
function onEditorUpdate(event: CustomEvent) { function onEditorUpdate(event: CustomEvent): void {
/* this updates the image in Mathjax.svelte */
getComponent(activeImage!).dataset.mathjax = event.detail.mathjax; getComponent(activeImage!).dataset.mathjax = event.detail.mathjax;
let selectionResolve: (value: void) => void;
const afterSelectionUpdate = new Promise((resolve) => {
selectionResolve = resolve;
});
setTimeout(async () => {
errorMessage = activeImage!.title;
await updateSelection();
selectionResolve();
});
return afterSelectionUpdate;
} }
</script> </script>
@ -60,7 +69,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
autoClose={false} autoClose={false}
distance={4} distance={4}
let:createDropdown let:createDropdown
let:dropdownObject
> >
{#if activeImage} {#if activeImage}
<HandleSelection <HandleSelection
@ -77,10 +85,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<DropdownMenu> <DropdownMenu>
<MathjaxHandleEditor <MathjaxHandleEditor
initialValue={getComponent(activeImage).dataset.mathjax ?? ""} initialValue={getComponent(activeImage).dataset.mathjax ?? ""}
on:update={async (event) => { on:update={onEditorUpdate}
await onEditorUpdate(event);
dropdownObject.update();
}}
/> />
<div class="margin-x"> <div class="margin-x">
<ButtonToolbar> <ButtonToolbar>

View file

@ -16,6 +16,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let codeMirror: CodeMirror.EditorFromTextArea; let codeMirror: CodeMirror.EditorFromTextArea;
const changeTimer = new ChangeTimer(); const changeTimer = new ChangeTimer();
const dispatch = createEventDispatcher();
function onInput() { function onInput() {
changeTimer.schedule( changeTimer.schedule(
@ -24,12 +25,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
); );
} }
function onBlur() {
changeTimer.fireImmediately();
}
function openCodemirror(textarea: HTMLTextAreaElement): void { function openCodemirror(textarea: HTMLTextAreaElement): void {
codeMirror = CodeMirror.fromTextArea(textarea, codeMirrorOptions); codeMirror = CodeMirror.fromTextArea(textarea, codeMirrorOptions);
codeMirror.on("change", onInput); codeMirror.on("change", onInput);
codeMirror.on("blur", onBlur);
} }
const dispatch = createEventDispatcher();
let textarea: HTMLTextAreaElement; let textarea: HTMLTextAreaElement;
onMount(() => { onMount(() => {

View file

@ -3,10 +3,16 @@
export class ChangeTimer { export class ChangeTimer {
private value: number | null = null; private value: number | null = null;
private action: (() => void) | null = null;
constructor() {
this.fireImmediately = this.fireImmediately.bind(this);
}
schedule(action: () => void, delay: number): void { schedule(action: () => void, delay: number): void {
this.clear(); this.clear();
this.value = setTimeout(action, delay); this.action = action;
this.value = setTimeout(this.fireImmediately, delay);
} }
clear(): void { clear(): void {
@ -15,4 +21,13 @@ export class ChangeTimer {
this.value = null; this.value = null;
} }
} }
fireImmediately(): void {
if (this.action) {
this.action();
this.action = null;
}
this.clear();
}
} }

View file

@ -29,12 +29,11 @@ export function saveNow(keepFocus: boolean): void {
return; return;
} }
saveFieldTimer.clear();
if (keepFocus) { if (keepFocus) {
saveField(currentField, "key"); saveFieldTimer.fireImmediately();
} else { } else {
// triggers onBlur, which saves // triggers onBlur, which saves
saveFieldTimer.clear();
currentField.blur(); currentField.blur();
} }
} }

View file

@ -38,7 +38,12 @@ export function wrapInternal(
document.execCommand("inserthtml", false, new_); document.execCommand("inserthtml", false, new_);
} }
if (!span.innerHTML) { if (
!span.innerHTML &&
/* ugly solution: treat <anki-mathjax> differently than other wraps */ !front.includes(
"<anki-mathjax"
)
) {
moveCursorPastPostfix(selection, back); moveCursorPastPostfix(selection, back);
} }
} }