Set caret inside chemical expression in Mathjax (#1763)

This commit is contained in:
Henrik Giesel 2022-03-31 15:39:49 +02:00 committed by GitHub
parent 6718e67883
commit 67c1f7368e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 86 additions and 51 deletions

View file

@ -41,11 +41,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let image: HTMLImageElement;
export function moveCaretAfter(): void {
export function moveCaretAfter(position?: [number, number]): void {
// This should trigger a focusing of the Mathjax Handle
image.dispatchEvent(
new CustomEvent("movecaretafter", {
detail: image,
detail: { image, position },
bubbles: true,
composed: true,
}),

View file

@ -121,7 +121,15 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax
});
if (this.hasAttribute("focusonmount")) {
this.component.moveCaretAfter();
let position: [number, number] | undefined = undefined;
if (this.getAttribute("focusonmount")!.length > 0) {
position = this.getAttribute("focusonmount")!
.split(",")
.map(Number) as [number, number];
}
this.component.moveCaretAfter(position);
}
this.setAttribute("contentEditable", "false");

View file

@ -52,9 +52,12 @@ export const gutterOptions: CodeMirror.EditorConfiguration = {
foldGutter: true,
};
export function focusAndCaretAfter(editor: CodeMirror.Editor): void {
export function focusAndSetCaret(
editor: CodeMirror.Editor,
position: CodeMirror.Position = { line: editor.lineCount(), ch: 0 },
): void {
editor.focus();
editor.setCursor(editor.lineCount(), 0);
editor.setCursor(position);
}
interface OpenCodeMirrorOptions {

View file

@ -35,7 +35,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
function onMathjaxChemistry(): void {
surround("<anki-mathjax focusonmount>\\ce{", "}</anki-mathjax>");
surround('<anki-mathjax focusonmount="0,4">\\ce{', "}</anki-mathjax>");
}
function onLatex(): void {

View file

@ -10,7 +10,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import * as tr from "../../lib/ftl";
import { noop } from "../../lib/functional";
import { getPlatformString } from "../../lib/shortcuts";
import { baseOptions, focusAndCaretAfter, latex } from "../code-mirror";
import { baseOptions, focusAndSetCaret, latex } from "../code-mirror";
import type { CodeMirrorAPI } from "../CodeMirror.svelte";
import CodeMirror from "../CodeMirror.svelte";
@ -33,15 +33,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
mode: latex,
};
/* These are not reactive, but only operate on initialization */
export let position: CodeMirrorLib.Position | undefined = undefined;
export let selectAll: boolean;
const dispatch = createEventDispatcher();
let codeMirror = {} as CodeMirrorAPI;
onMount(() =>
codeMirror.editor.then((editor) => {
focusAndCaretAfter(editor);
onMount(async () => {
const editor = await codeMirror.editor;
focusAndSetCaret(editor, position);
if (selectAll) {
editor.execCommand("selectAll");
@ -83,8 +86,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
direction = undefined;
},
);
}),
);
});
/**
* Escape characters which are technically legal in Mathjax, but confuse HTML.

View file

@ -3,6 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import type CodeMirrorLib from "codemirror";
import { onDestroy, onMount, tick } from "svelte";
import { writable } from "svelte/store";
@ -26,9 +27,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let allow = noop;
let unsubscribe = noop;
function showHandle(image: HTMLImageElement): void {
allow = preventResubscription();
let selectAll = false;
let position: CodeMirrorLib.Position | undefined = undefined;
function showHandle(image: HTMLImageElement, pos?: CodeMirrorLib.Position): void {
allow = preventResubscription();
position = pos;
/* Setting the activeImage and mathjaxElement to a non-nullish value is
* what triggers the Mathjax editor to show */
activeImage = image;
mathjaxElement = activeImage.closest(Mathjax.tagName)!;
@ -38,8 +45,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
});
}
let selectAll = false;
function placeHandle(after: boolean): void {
editable.focusHandler.flushCaret();
@ -52,6 +57,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
async function resetHandle(): Promise<void> {
selectAll = false;
position = undefined;
if (activeImage && mathjaxElement) {
unsubscribe();
@ -72,9 +78,20 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
async function showAutofocusHandle({
detail,
}: CustomEvent<HTMLImageElement>): Promise<void> {
}: CustomEvent<{
image: HTMLImageElement;
position?: [number, number];
}>): Promise<void> {
let position: CodeMirrorLib.Position | undefined = undefined;
await resetHandle();
showHandle(detail);
if (detail.position) {
const [line, ch] = detail.position;
position = { line, ch };
}
showHandle(detail.image, position);
}
async function showSelectAll({
@ -138,6 +155,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
element={mathjaxElement}
{code}
{selectAll}
{position}
bind:updateSelection
on:reset={resetHandle}
on:moveoutstart={() => {

View file

@ -3,6 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import type CodeMirrorLib from "codemirror";
import { createEventDispatcher } from "svelte";
import type { Writable } from "svelte/store";
@ -15,7 +16,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let element: Element;
export let code: Writable<string>;
export let selectAll: boolean;
export let position: CodeMirrorLib.Position | undefined;
const acceptShortcut = "Enter";
const newlineShortcut = "Shift+Enter";
@ -40,6 +43,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{newlineShortcut}
{code}
{selectAll}
{position}
on:blur={() => dispatch("reset")}
on:moveoutstart
on:moveoutend