From 2be1f4c56da3cd4964f590dcfeded85340aa4d74 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Mon, 25 Apr 2022 05:42:54 +0200 Subject: [PATCH] Instead of transforming to {\lt}, transform to < (#1818) * Instead of transforming to {\lt}, transform to < - In Mathjax editor - This way you can also use Mathjax convenience shortcuts like <=> in chemistry mode: \ce{<=>} * Remove unused translateEntitiesToMathjax() (dae) https://github.com/ankitects/anki/pull/1818#discussion_r857238310 --- ts/editable/Mathjax.svelte | 8 ++++++-- ts/editable/mathjax-element.ts | 16 +++------------- ts/editable/mathjax.ts | 11 +++++++++++ ts/editor/mathjax-overlay/MathjaxEditor.svelte | 9 +-------- ts/editor/mathjax-overlay/MathjaxHandle.svelte | 13 +++++++++---- ts/editor/rich-text-input/transform.ts | 7 ++++--- ts/lib/dom.ts | 3 +++ 7 files changed, 37 insertions(+), 30 deletions(-) diff --git a/ts/editable/Mathjax.svelte b/ts/editable/Mathjax.svelte index cc56a1b2c..03687b73a 100644 --- a/ts/editable/Mathjax.svelte +++ b/ts/editable/Mathjax.svelte @@ -23,13 +23,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import { randomUUID } from "../lib/uuid"; import { pageTheme } from "../sveltelib/theme"; - import { convertMathjax } from "./mathjax"; + import { convertMathjax, unescapeSomeEntities } from "./mathjax"; export let mathjax: string; export let block: boolean; export let fontSize: number; - $: [converted, title] = convertMathjax(mathjax, $pageTheme.isDark, fontSize); + $: [converted, title] = convertMathjax( + unescapeSomeEntities(mathjax), + $pageTheme.isDark, + fontSize, + ); $: empty = title === "MathJax"; $: encoded = encodeURIComponent(converted); diff --git a/ts/editable/mathjax-element.ts b/ts/editable/mathjax-element.ts index f2b24e335..1d7117cf5 100644 --- a/ts/editable/mathjax-element.ts +++ b/ts/editable/mathjax-element.ts @@ -15,14 +15,6 @@ const mathjaxTagPattern = const mathjaxBlockDelimiterPattern = /\\\[(.*?)\\\]/gsu; const mathjaxInlineDelimiterPattern = /\\\((.*?)\\\)/gsu; -/** - * If the user enters the Mathjax with delimiters, "<" and ">" will - * be first translated to entities. - */ -function translateEntitiesToMathjax(value: string) { - return value.replace(/</g, "{\\lt}").replace(/>/g, "{\\gt}"); -} - export const Mathjax: DecoratedElementConstructor = class Mathjax extends HTMLElement implements DecoratedElement @@ -45,12 +37,10 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax static toUndecorated(stored: string): string { return stored .replace(mathjaxBlockDelimiterPattern, (_match: string, text: string) => { - const escaped = translateEntitiesToMathjax(text); - return `<${Mathjax.tagName} block="true">${escaped}`; + return `<${Mathjax.tagName} block="true">${text}`; }) .replace(mathjaxInlineDelimiterPattern, (_match: string, text: string) => { - const escaped = translateEntitiesToMathjax(text); - return `<${Mathjax.tagName}>${escaped}`; + return `<${Mathjax.tagName}>${text}`; }); } @@ -107,7 +97,7 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax return; } - this.dataset.mathjax = this.innerText; + this.dataset.mathjax = this.innerHTML; this.innerHTML = ""; this.style.whiteSpace = "normal"; diff --git a/ts/editable/mathjax.ts b/ts/editable/mathjax.ts index 6338b3f5d..825f9d7ed 100644 --- a/ts/editable/mathjax.ts +++ b/ts/editable/mathjax.ts @@ -65,3 +65,14 @@ export function convertMathjax( return [svg.outerHTML, title]; } + +/** + * Escape characters which are technically legal in Mathjax, but confuse HTML. + */ +export function escapeSomeEntities(value: string): string { + return value.replace(//g, ">"); +} + +export function unescapeSomeEntities(value: string): string { + return value.replace(/</g, "<").replace(/>/g, ">"); +} diff --git a/ts/editor/mathjax-overlay/MathjaxEditor.svelte b/ts/editor/mathjax-overlay/MathjaxEditor.svelte index dfd74f6a4..c9ac38e41 100644 --- a/ts/editor/mathjax-overlay/MathjaxEditor.svelte +++ b/ts/editor/mathjax-overlay/MathjaxEditor.svelte @@ -87,13 +87,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html }, ); }); - - /** - * Escape characters which are technically legal in Mathjax, but confuse HTML. - */ - export function escapeSomeEntities(value: string): string { - return value.replace(//g, "{\\gt}"); - }
@@ -101,7 +94,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html {code} {configuration} bind:api={codeMirror} - on:change={({ detail }) => code.set(escapeSomeEntities(detail))} + on:change={({ detail: mathjaxText }) => code.set(mathjaxText)} on:blur />
diff --git a/ts/editor/mathjax-overlay/MathjaxHandle.svelte b/ts/editor/mathjax-overlay/MathjaxHandle.svelte index 6f13d384d..4b58ef1f3 100644 --- a/ts/editor/mathjax-overlay/MathjaxHandle.svelte +++ b/ts/editor/mathjax-overlay/MathjaxHandle.svelte @@ -8,6 +8,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import { writable } from "svelte/store"; import WithDropdown from "../../components/WithDropdown.svelte"; + import { escapeSomeEntities, unescapeSomeEntities } from "../../editable/mathjax"; import { Mathjax } from "../../editable/mathjax-element"; import { on } from "../../lib/events"; import { noop } from "../../lib/functional"; @@ -20,8 +21,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const { container, api } = context.get(); const { editable, preventResubscription } = api; - const code = writable(""); - let activeImage: HTMLImageElement | null = null; let mathjaxElement: HTMLElement | null = null; let allow = noop; @@ -30,6 +29,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html let selectAll = false; let position: CodeMirrorLib.Position | undefined = undefined; + /** + * Will contain the Mathjax text with unescaped entities. + * This is the text displayed in the actual editor window. + */ + const code = writable(""); + function showHandle(image: HTMLImageElement, pos?: CodeMirrorLib.Position): void { allow = preventResubscription(); position = pos; @@ -39,9 +44,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html activeImage = image; mathjaxElement = activeImage.closest(Mathjax.tagName)!; - code.set(mathjaxElement.dataset.mathjax ?? ""); + code.set(unescapeSomeEntities(mathjaxElement.dataset.mathjax ?? "")); unsubscribe = code.subscribe((value: string) => { - mathjaxElement!.dataset.mathjax = value; + mathjaxElement!.dataset.mathjax = escapeSomeEntities(value); }); } diff --git a/ts/editor/rich-text-input/transform.ts b/ts/editor/rich-text-input/transform.ts index 185992834..33ce0afb8 100644 --- a/ts/editor/rich-text-input/transform.ts +++ b/ts/editor/rich-text-input/transform.ts @@ -23,11 +23,11 @@ function adjustInputFragment(fragment: DocumentFragment): void { } } -export function storedToFragment(html: string): DocumentFragment { +export function storedToFragment(storedHTML: string): DocumentFragment { /* We need .createContextualFragment so that customElements are initialized */ const fragment = document .createRange() - .createContextualFragment(createDummyDoc(adjustInputHTML(html))); + .createContextualFragment(createDummyDoc(adjustInputHTML(storedHTML))); adjustInputFragment(fragment); return fragment; @@ -56,5 +56,6 @@ export function fragmentToStored(fragment: DocumentFragment): string { const clone = document.importNode(fragment, true); adjustOutputFragment(clone); - return adjustOutputHTML(fragmentToString(clone)); + const storedHTML = adjustOutputHTML(fragmentToString(clone)); + return storedHTML; } diff --git a/ts/lib/dom.ts b/ts/lib/dom.ts index 1cf599050..60b79689a 100644 --- a/ts/lib/dom.ts +++ b/ts/lib/dom.ts @@ -110,6 +110,9 @@ export function nodeContainsInlineContent(node: Node): boolean { return true; } +/** + * Consumes the input fragment. + */ export function fragmentToString(fragment: DocumentFragment): string { const fragmentDiv = document.createElement("div"); fragmentDiv.appendChild(fragment);