mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Revert "Revert "Preserve HTML formatting inside clozes (#3038)""
This reverts commit e911b4b69a
.
Trying again now that 24.04 is out.
This commit is contained in:
parent
9f55cf26fc
commit
9c733848b8
7 changed files with 95 additions and 19 deletions
|
@ -1246,7 +1246,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
|
|||
highest += 1
|
||||
# must start at 1
|
||||
highest = max(1, highest)
|
||||
self.web.eval("wrap('{{c%d::', '}}');" % highest)
|
||||
self.web.eval("wrapCloze(%d);" % highest)
|
||||
|
||||
def setupForegroundButton(self) -> None:
|
||||
self.fcolour = self.mw.pm.profile.get("lastColour", "#00f")
|
||||
|
|
|
@ -55,18 +55,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
async function onIncrementCloze(): Promise<void> {
|
||||
const highestCloze = getCurrentHighestCloze(true);
|
||||
|
||||
dispatch("surround", {
|
||||
prefix: `{{c${highestCloze}::`,
|
||||
suffix: "}}",
|
||||
dispatch("cloze", {
|
||||
n: highestCloze,
|
||||
});
|
||||
}
|
||||
|
||||
async function onSameCloze(): Promise<void> {
|
||||
const highestCloze = getCurrentHighestCloze(false);
|
||||
|
||||
dispatch("surround", {
|
||||
prefix: `{{c${highestCloze}::`,
|
||||
suffix: "}}",
|
||||
dispatch("cloze", {
|
||||
n: highestCloze,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
import { ImageOcclusionFieldIndexes } from "@generated/anki/image_occlusion_pb";
|
||||
import { getImageOcclusionFields } from "@generated/backend";
|
||||
import { wrapInternal } from "@tslib/wrap";
|
||||
import { wrapClozeInternal, wrapInternal } from "@tslib/wrap";
|
||||
|
||||
import Shortcut from "$lib/components/Shortcut.svelte";
|
||||
|
||||
|
@ -547,6 +547,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
});
|
||||
}
|
||||
|
||||
function wrapCloze(n: number): void {
|
||||
if (!$focusedInput || !editingInputIsRichText($focusedInput)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$focusedInput.element.then((element) => {
|
||||
wrapClozeInternal(element, n);
|
||||
});
|
||||
}
|
||||
|
||||
Object.assign(globalThis, {
|
||||
saveSession,
|
||||
setFields,
|
||||
|
@ -565,6 +575,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
setNoteId,
|
||||
setNotetypeMeta,
|
||||
wrap,
|
||||
wrapCloze,
|
||||
setMathjaxEnabled,
|
||||
setShrinkImages,
|
||||
setCloseHTMLTags,
|
||||
|
|
|
@ -3,7 +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 { wrapInternal } from "@tslib/wrap";
|
||||
import { wrapClozeInternal } from "@tslib/wrap";
|
||||
|
||||
import ClozeButtons from "../ClozeButtons.svelte";
|
||||
import { context as noteEditorContext } from "../NoteEditor.svelte";
|
||||
|
@ -13,12 +13,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
$: richTextAPI = $focusedInput as RichTextInputAPI;
|
||||
|
||||
async function onSurround({ detail }): Promise<void> {
|
||||
async function onCloze({ detail }): Promise<void> {
|
||||
const richText = await richTextAPI.element;
|
||||
const { prefix, suffix } = detail;
|
||||
|
||||
wrapInternal(richText, prefix, suffix, false);
|
||||
const { n } = detail;
|
||||
wrapClozeInternal(richText, n);
|
||||
}
|
||||
</script>
|
||||
|
||||
<ClozeButtons on:surround={onSurround} />
|
||||
<ClozeButtons on:cloze={onCloze} />
|
||||
|
|
|
@ -39,7 +39,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
</IconButton>
|
||||
</ButtonGroup>
|
||||
|
||||
<ClozeButtons on:surround alwaysEnabled={true} />
|
||||
<ClozeButtons on:cloze alwaysEnabled={true} />
|
||||
|
||||
<ButtonGroup>
|
||||
<IconButton
|
||||
|
|
|
@ -261,12 +261,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
clear();
|
||||
}
|
||||
}}
|
||||
on:surround={async ({ detail }) => {
|
||||
on:cloze={async ({ detail }) => {
|
||||
const editor = await mathjaxEditor.editor;
|
||||
const { prefix, suffix } = detail;
|
||||
|
||||
const { n } = detail;
|
||||
editor.replaceSelection(
|
||||
prefix + editor.getSelection() + suffix,
|
||||
`{{c${n}::` + editor.getSelection() + "}}",
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import { placeCaretAfter } from "../domlib/place-caret";
|
||||
import { getRange, getSelection } from "./cross-browser";
|
||||
import { nodeIsElement } from "./dom";
|
||||
|
||||
function wrappedExceptForWhitespace(text: string, front: string, back: string): string {
|
||||
const match = text.match(/^(\s*)([^]*?)(\s*)$/)!;
|
||||
|
@ -53,3 +55,70 @@ export function wrapInternal(
|
|||
moveCursorInside(selection, back);
|
||||
}
|
||||
}
|
||||
|
||||
export function wrapClozeInternal(base: Element, n: number): void {
|
||||
const selection = getSelection(base)!;
|
||||
const range = getRange(selection);
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand the range to include parent nodes whose children are already included.
|
||||
// This is to work around .extractContents() adding redundant empty elements
|
||||
let startParent: Node | null = range.startContainer.parentNode;
|
||||
if (
|
||||
startParent !== base
|
||||
&& startParent?.firstChild === range.startContainer && range.startOffset === 0
|
||||
) {
|
||||
range.setStartBefore(startParent);
|
||||
}
|
||||
let endParent: Node | null = range.endContainer.parentNode;
|
||||
if (
|
||||
endParent !== base
|
||||
&& endParent?.lastChild === range.endContainer && (
|
||||
(!nodeIsElement(range.endContainer)
|
||||
&& range.endOffset === range.endContainer.textContent?.length)
|
||||
|| (nodeIsElement(range.endContainer)
|
||||
&& range.endOffset === range.endContainer.childNodes.length)
|
||||
)
|
||||
) {
|
||||
range.setEndAfter(endParent);
|
||||
}
|
||||
let expand: boolean;
|
||||
do {
|
||||
expand = false;
|
||||
if (
|
||||
startParent
|
||||
&& startParent.parentNode !== base && startParent.parentNode?.firstChild === startParent
|
||||
&& range.isPointInRange(startParent.parentNode, startParent.parentNode?.childNodes.length)
|
||||
) {
|
||||
startParent = startParent.parentNode;
|
||||
range.setStartBefore(startParent);
|
||||
expand = true;
|
||||
}
|
||||
if (
|
||||
endParent && endParent.parentNode !== base && endParent.parentNode?.lastChild === endParent
|
||||
&& range.isPointInRange(endParent.parentNode, 0)
|
||||
) {
|
||||
endParent = endParent.parentNode;
|
||||
range.setEndAfter(endParent);
|
||||
expand = true;
|
||||
}
|
||||
if (range.endOffset === 0) {
|
||||
range.setEndBefore(range.endContainer);
|
||||
expand = true;
|
||||
}
|
||||
} while (expand);
|
||||
|
||||
const fragment = range.extractContents();
|
||||
if (fragment.childNodes.length === 0) {
|
||||
document.execCommand("inserthtml", false, `{{c${n}::}}`);
|
||||
} else {
|
||||
const startNode = document.createTextNode(`{{c${n}::`);
|
||||
const endNode = document.createTextNode("}}");
|
||||
range.insertNode(endNode);
|
||||
range.insertNode(fragment);
|
||||
range.insertNode(startNode);
|
||||
placeCaretAfter(endNode);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue