Implement cloze buttons in Mathjax editor (#1860)

* Introduce RichTextClozeButtons

* Implement cloze buttons in Mathjax editor
This commit is contained in:
Henrik Giesel 2022-05-13 05:04:20 +02:00 committed by GitHub
parent 52438fe4c9
commit b6fb64fde1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 73 additions and 34 deletions

View File

@ -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);

View File

@ -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>

View 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} />

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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()}

View File

@ -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) {

View File

@ -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>