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
This commit is contained in:
parent
ee70006ec4
commit
2be1f4c56d
@ -23,13 +23,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
import { randomUUID } from "../lib/uuid";
|
import { randomUUID } from "../lib/uuid";
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
import { pageTheme } from "../sveltelib/theme";
|
||||||
import { convertMathjax } from "./mathjax";
|
import { convertMathjax, unescapeSomeEntities } from "./mathjax";
|
||||||
|
|
||||||
export let mathjax: string;
|
export let mathjax: string;
|
||||||
export let block: boolean;
|
export let block: boolean;
|
||||||
export let fontSize: number;
|
export let fontSize: number;
|
||||||
|
|
||||||
$: [converted, title] = convertMathjax(mathjax, $pageTheme.isDark, fontSize);
|
$: [converted, title] = convertMathjax(
|
||||||
|
unescapeSomeEntities(mathjax),
|
||||||
|
$pageTheme.isDark,
|
||||||
|
fontSize,
|
||||||
|
);
|
||||||
$: empty = title === "MathJax";
|
$: empty = title === "MathJax";
|
||||||
$: encoded = encodeURIComponent(converted);
|
$: encoded = encodeURIComponent(converted);
|
||||||
|
|
||||||
|
@ -15,14 +15,6 @@ const mathjaxTagPattern =
|
|||||||
const mathjaxBlockDelimiterPattern = /\\\[(.*?)\\\]/gsu;
|
const mathjaxBlockDelimiterPattern = /\\\[(.*?)\\\]/gsu;
|
||||||
const mathjaxInlineDelimiterPattern = /\\\((.*?)\\\)/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
|
export const Mathjax: DecoratedElementConstructor = class Mathjax
|
||||||
extends HTMLElement
|
extends HTMLElement
|
||||||
implements DecoratedElement
|
implements DecoratedElement
|
||||||
@ -45,12 +37,10 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax
|
|||||||
static toUndecorated(stored: string): string {
|
static toUndecorated(stored: string): string {
|
||||||
return stored
|
return stored
|
||||||
.replace(mathjaxBlockDelimiterPattern, (_match: string, text: string) => {
|
.replace(mathjaxBlockDelimiterPattern, (_match: string, text: string) => {
|
||||||
const escaped = translateEntitiesToMathjax(text);
|
return `<${Mathjax.tagName} block="true">${text}</${Mathjax.tagName}>`;
|
||||||
return `<${Mathjax.tagName} block="true">${escaped}</${Mathjax.tagName}>`;
|
|
||||||
})
|
})
|
||||||
.replace(mathjaxInlineDelimiterPattern, (_match: string, text: string) => {
|
.replace(mathjaxInlineDelimiterPattern, (_match: string, text: string) => {
|
||||||
const escaped = translateEntitiesToMathjax(text);
|
return `<${Mathjax.tagName}>${text}</${Mathjax.tagName}>`;
|
||||||
return `<${Mathjax.tagName}>${escaped}</${Mathjax.tagName}>`;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +97,7 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dataset.mathjax = this.innerText;
|
this.dataset.mathjax = this.innerHTML;
|
||||||
this.innerHTML = "";
|
this.innerHTML = "";
|
||||||
this.style.whiteSpace = "normal";
|
this.style.whiteSpace = "normal";
|
||||||
|
|
||||||
|
@ -65,3 +65,14 @@ export function convertMathjax(
|
|||||||
|
|
||||||
return [svg.outerHTML, title];
|
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, "<").replace(/>/g, ">");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unescapeSomeEntities(value: string): string {
|
||||||
|
return value.replace(/</g, "<").replace(/>/g, ">");
|
||||||
|
}
|
||||||
|
@ -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, "{\\lt}").replace(/>/g, "{\\gt}");
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="mathjax-editor">
|
<div class="mathjax-editor">
|
||||||
@ -101,7 +94,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
{code}
|
{code}
|
||||||
{configuration}
|
{configuration}
|
||||||
bind:api={codeMirror}
|
bind:api={codeMirror}
|
||||||
on:change={({ detail }) => code.set(escapeSomeEntities(detail))}
|
on:change={({ detail: mathjaxText }) => code.set(mathjaxText)}
|
||||||
on:blur
|
on:blur
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
import WithDropdown from "../../components/WithDropdown.svelte";
|
import WithDropdown from "../../components/WithDropdown.svelte";
|
||||||
|
import { escapeSomeEntities, unescapeSomeEntities } from "../../editable/mathjax";
|
||||||
import { Mathjax } from "../../editable/mathjax-element";
|
import { Mathjax } from "../../editable/mathjax-element";
|
||||||
import { on } from "../../lib/events";
|
import { on } from "../../lib/events";
|
||||||
import { noop } from "../../lib/functional";
|
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 { container, api } = context.get();
|
||||||
const { editable, preventResubscription } = api;
|
const { editable, preventResubscription } = api;
|
||||||
|
|
||||||
const code = writable("");
|
|
||||||
|
|
||||||
let activeImage: HTMLImageElement | null = null;
|
let activeImage: HTMLImageElement | null = null;
|
||||||
let mathjaxElement: HTMLElement | null = null;
|
let mathjaxElement: HTMLElement | null = null;
|
||||||
let allow = noop;
|
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 selectAll = false;
|
||||||
let position: CodeMirrorLib.Position | undefined = undefined;
|
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 {
|
function showHandle(image: HTMLImageElement, pos?: CodeMirrorLib.Position): void {
|
||||||
allow = preventResubscription();
|
allow = preventResubscription();
|
||||||
position = pos;
|
position = pos;
|
||||||
@ -39,9 +44,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
activeImage = image;
|
activeImage = image;
|
||||||
mathjaxElement = activeImage.closest(Mathjax.tagName)!;
|
mathjaxElement = activeImage.closest(Mathjax.tagName)!;
|
||||||
|
|
||||||
code.set(mathjaxElement.dataset.mathjax ?? "");
|
code.set(unescapeSomeEntities(mathjaxElement.dataset.mathjax ?? ""));
|
||||||
unsubscribe = code.subscribe((value: string) => {
|
unsubscribe = code.subscribe((value: string) => {
|
||||||
mathjaxElement!.dataset.mathjax = value;
|
mathjaxElement!.dataset.mathjax = escapeSomeEntities(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
/* We need .createContextualFragment so that customElements are initialized */
|
||||||
const fragment = document
|
const fragment = document
|
||||||
.createRange()
|
.createRange()
|
||||||
.createContextualFragment(createDummyDoc(adjustInputHTML(html)));
|
.createContextualFragment(createDummyDoc(adjustInputHTML(storedHTML)));
|
||||||
|
|
||||||
adjustInputFragment(fragment);
|
adjustInputFragment(fragment);
|
||||||
return fragment;
|
return fragment;
|
||||||
@ -56,5 +56,6 @@ export function fragmentToStored(fragment: DocumentFragment): string {
|
|||||||
const clone = document.importNode(fragment, true);
|
const clone = document.importNode(fragment, true);
|
||||||
adjustOutputFragment(clone);
|
adjustOutputFragment(clone);
|
||||||
|
|
||||||
return adjustOutputHTML(fragmentToString(clone));
|
const storedHTML = adjustOutputHTML(fragmentToString(clone));
|
||||||
|
return storedHTML;
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,9 @@ export function nodeContainsInlineContent(node: Node): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consumes the input fragment.
|
||||||
|
*/
|
||||||
export function fragmentToString(fragment: DocumentFragment): string {
|
export function fragmentToString(fragment: DocumentFragment): string {
|
||||||
const fragmentDiv = document.createElement("div");
|
const fragmentDiv = document.createElement("div");
|
||||||
fragmentDiv.appendChild(fragment);
|
fragmentDiv.appendChild(fragment);
|
||||||
|
Loading…
Reference in New Issue
Block a user