Implement cloze buttons in Mathjax editor (#1860)
* Introduce RichTextClozeButtons * Implement cloze buttons in Mathjax editor
This commit is contained in:
parent
52438fe4c9
commit
b6fb64fde1
@ -3,19 +3,18 @@ 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 { createEventDispatcher } from "svelte";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
import ButtonGroup from "../../components/ButtonGroup.svelte";
|
import ButtonGroup from "../components/ButtonGroup.svelte";
|
||||||
import IconButton from "../../components/IconButton.svelte";
|
import IconButton from "../components/IconButton.svelte";
|
||||||
import Shortcut from "../../components/Shortcut.svelte";
|
import Shortcut from "../components/Shortcut.svelte";
|
||||||
import * as tr from "../../lib/ftl";
|
import * as tr from "../lib/ftl";
|
||||||
import { isApplePlatform } from "../../lib/platform";
|
import { isApplePlatform } from "../lib/platform";
|
||||||
import { getPlatformString } from "../../lib/shortcuts";
|
import { getPlatformString } from "../lib/shortcuts";
|
||||||
import { wrapInternal } from "../../lib/wrap";
|
|
||||||
import { context as noteEditorContext } from "../NoteEditor.svelte";
|
|
||||||
import type { RichTextInputAPI } from "../rich-text-input";
|
|
||||||
import { editingInputIsRichText } from "../rich-text-input";
|
|
||||||
import { clozeIcon, incrementClozeIcon } from "./icons";
|
import { clozeIcon, incrementClozeIcon } from "./icons";
|
||||||
|
import { context as noteEditorContext } from "./NoteEditor.svelte";
|
||||||
|
import { editingInputIsRichText } from "./rich-text-input";
|
||||||
|
|
||||||
const { focusedInput, fields } = noteEditorContext.get();
|
const { focusedInput, fields } = noteEditorContext.get();
|
||||||
|
|
||||||
@ -48,20 +47,24 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
return Math.max(1, highest);
|
return Math.max(1, highest);
|
||||||
}
|
}
|
||||||
|
|
||||||
$: richTextAPI = $focusedInput as RichTextInputAPI;
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
async function onIncrementCloze(): Promise<void> {
|
async function onIncrementCloze(): Promise<void> {
|
||||||
const richText = await richTextAPI.element;
|
|
||||||
|
|
||||||
const highestCloze = getCurrentHighestCloze(true);
|
const highestCloze = getCurrentHighestCloze(true);
|
||||||
wrapInternal(richText, `{{c${highestCloze}::`, "}}", false);
|
|
||||||
|
dispatch("surround", {
|
||||||
|
prefix: `{{c${highestCloze}::`,
|
||||||
|
suffix: "}}",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onSameCloze(): Promise<void> {
|
async function onSameCloze(): Promise<void> {
|
||||||
const richText = await richTextAPI.element;
|
|
||||||
|
|
||||||
const highestCloze = getCurrentHighestCloze(false);
|
const highestCloze = getCurrentHighestCloze(false);
|
||||||
wrapInternal(richText, `{{c${highestCloze}::`, "}}", false);
|
|
||||||
|
dispatch("surround", {
|
||||||
|
prefix: `{{c${highestCloze}::`,
|
||||||
|
suffix: "}}",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$: disabled = !editingInputIsRichText($focusedInput);
|
$: disabled = !editingInputIsRichText($focusedInput);
|
@ -56,9 +56,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
import Item from "../../components/Item.svelte";
|
import Item from "../../components/Item.svelte";
|
||||||
import StickyContainer from "../../components/StickyContainer.svelte";
|
import StickyContainer from "../../components/StickyContainer.svelte";
|
||||||
import BlockButtons from "./BlockButtons.svelte";
|
import BlockButtons from "./BlockButtons.svelte";
|
||||||
import ClozeButtons from "./ClozeButtons.svelte";
|
|
||||||
import InlineButtons from "./InlineButtons.svelte";
|
import InlineButtons from "./InlineButtons.svelte";
|
||||||
import NotetypeButtons from "./NotetypeButtons.svelte";
|
import NotetypeButtons from "./NotetypeButtons.svelte";
|
||||||
|
import RichTextClozeButtons from "./RichTextClozeButtons.svelte";
|
||||||
import TemplateButtons from "./TemplateButtons.svelte";
|
import TemplateButtons from "./TemplateButtons.svelte";
|
||||||
|
|
||||||
export let size: number;
|
export let size: number;
|
||||||
@ -108,7 +108,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
</Item>
|
</Item>
|
||||||
|
|
||||||
<Item id="cloze">
|
<Item id="cloze">
|
||||||
<ClozeButtons />
|
<RichTextClozeButtons />
|
||||||
</Item>
|
</Item>
|
||||||
</DynamicallySlottable>
|
</DynamicallySlottable>
|
||||||
</ButtonToolbar>
|
</ButtonToolbar>
|
||||||
|
23
ts/editor/editor-toolbar/RichTextClozeButtons.svelte
Normal file
23
ts/editor/editor-toolbar/RichTextClozeButtons.svelte
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!--
|
||||||
|
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 "../../lib/wrap";
|
||||||
|
import ClozeButtons from "../ClozeButtons.svelte";
|
||||||
|
import { context as noteEditorContext } from "../NoteEditor.svelte";
|
||||||
|
import type { RichTextInputAPI } from "../rich-text-input";
|
||||||
|
|
||||||
|
const { focusedInput } = noteEditorContext.get();
|
||||||
|
|
||||||
|
$: richTextAPI = $focusedInput as RichTextInputAPI;
|
||||||
|
|
||||||
|
async function onSurround({ detail }): Promise<void> {
|
||||||
|
const richText = await richTextAPI.element;
|
||||||
|
const { prefix, suffix } = detail;
|
||||||
|
|
||||||
|
wrapInternal(richText, prefix, suffix, false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ClozeButtons on:surround={onSurround} />
|
@ -24,8 +24,6 @@ export { default as underlineIcon } from "bootstrap-icons/icons/type-underline.s
|
|||||||
export const arrowIcon =
|
export const arrowIcon =
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="transparent" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2 5l6 6 6-6"/></svg>';
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="transparent" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2 5l6 6 6-6"/></svg>';
|
||||||
|
|
||||||
export { default as incrementClozeIcon } from "../../icons/contain-plus.svg";
|
|
||||||
export { default as clozeIcon } from "@mdi/svg/svg/contain.svg";
|
|
||||||
export { default as functionIcon } from "@mdi/svg/svg/function-variant.svg";
|
export { default as functionIcon } from "@mdi/svg/svg/function-variant.svg";
|
||||||
export { default as paperclipIcon } from "@mdi/svg/svg/paperclip.svg";
|
export { default as paperclipIcon } from "@mdi/svg/svg/paperclip.svg";
|
||||||
export { default as micIcon } from "bootstrap-icons/icons/mic.svg";
|
export { default as micIcon } from "bootstrap-icons/icons/mic.svg";
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
|
|
||||||
export type { EditorToolbarAPI } from "./EditorToolbar.svelte";
|
export type { EditorToolbarAPI } from "./EditorToolbar.svelte";
|
||||||
export { default as EditorToolbar, editorToolbar } from "./EditorToolbar.svelte";
|
export { default as EditorToolbar, editorToolbar } from "./EditorToolbar.svelte";
|
||||||
|
export { default as ClozeButtons } from "./EditorToolbar.svelte";
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
/// <reference types="../lib/image-import" />
|
/// <reference types="../lib/image-import" />
|
||||||
|
|
||||||
|
export { default as incrementClozeIcon } from "../icons/contain-plus.svg";
|
||||||
export { default as alertIcon } from "@mdi/svg/svg/alert.svg";
|
export { default as alertIcon } from "@mdi/svg/svg/alert.svg";
|
||||||
export { default as htmlOn } from "@mdi/svg/svg/code-tags.svg";
|
export { default as htmlOn } from "@mdi/svg/svg/code-tags.svg";
|
||||||
|
export { default as clozeIcon } from "@mdi/svg/svg/contain.svg";
|
||||||
export { default as richTextOff } from "@mdi/svg/svg/eye-off-outline.svg";
|
export { default as richTextOff } from "@mdi/svg/svg/eye-off-outline.svg";
|
||||||
export { default as richTextOn } from "@mdi/svg/svg/eye-outline.svg";
|
export { default as richTextOn } from "@mdi/svg/svg/eye-outline.svg";
|
||||||
export { default as stickyOff } from "@mdi/svg/svg/pin-off-outline.svg";
|
export { default as stickyOff } from "@mdi/svg/svg/pin-off-outline.svg";
|
||||||
|
@ -10,6 +10,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
import IconButton from "../../components/IconButton.svelte";
|
import IconButton from "../../components/IconButton.svelte";
|
||||||
import { hasBlockAttribute } from "../../lib/dom";
|
import { hasBlockAttribute } from "../../lib/dom";
|
||||||
import * as tr from "../../lib/ftl";
|
import * as tr from "../../lib/ftl";
|
||||||
|
import ClozeButtons from "../ClozeButtons.svelte";
|
||||||
import { blockIcon, deleteIcon, inlineIcon } from "./icons";
|
import { blockIcon, deleteIcon, inlineIcon } from "./icons";
|
||||||
|
|
||||||
export let element: Element;
|
export let element: Element;
|
||||||
@ -48,6 +49,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
>
|
>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
|
<ClozeButtons on:surround />
|
||||||
|
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<IconButton
|
<IconButton
|
||||||
tooltip={tr.actionsDelete()}
|
tooltip={tr.actionsDelete()}
|
||||||
|
@ -99,6 +99,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<slot editor={codeMirror} />
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.mathjax-editor {
|
.mathjax-editor {
|
||||||
:global(.CodeMirror) {
|
:global(.CodeMirror) {
|
||||||
|
@ -47,21 +47,28 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
on:blur={() => dispatch("reset")}
|
on:blur={() => dispatch("reset")}
|
||||||
on:moveoutstart
|
on:moveoutstart
|
||||||
on:moveoutend
|
on:moveoutend
|
||||||
/>
|
let:editor={mathjaxEditor}
|
||||||
|
>
|
||||||
|
<Shortcut
|
||||||
|
keyCombination={acceptShortcut}
|
||||||
|
on:action={() => dispatch("moveoutend")}
|
||||||
|
/>
|
||||||
|
|
||||||
<Shortcut
|
<MathjaxButtons
|
||||||
keyCombination={acceptShortcut}
|
{element}
|
||||||
on:action={() => dispatch("moveoutend")}
|
on:delete={() => {
|
||||||
/>
|
placeCaretAfter(element);
|
||||||
|
element.remove();
|
||||||
|
dispatch("reset");
|
||||||
|
}}
|
||||||
|
on:surround={async ({ detail }) => {
|
||||||
|
const editor = await mathjaxEditor.editor;
|
||||||
|
const { prefix, suffix } = detail;
|
||||||
|
|
||||||
<MathjaxButtons
|
editor.replaceSelection(prefix + editor.getSelection() + suffix);
|
||||||
{element}
|
}}
|
||||||
on:delete={() => {
|
/>
|
||||||
placeCaretAfter(element);
|
</MathjaxEditor>
|
||||||
element.remove();
|
|
||||||
dispatch("reset");
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user