diff --git a/.vscode/settings.json b/.vscode/settings.json index 5c8bfa763..b5762c411 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,9 @@ { "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": true + "[python]": { + "editor.codeActionsOnSave": { + "source.organizeImports": true + } }, "files.watcherExclude": { "**/.git/objects/**": true, diff --git a/ftl/core/editing.ftl b/ftl/core/editing.ftl index df5d391db..6e4d9086a 100644 --- a/ftl/core/editing.ftl +++ b/ftl/core/editing.ftl @@ -15,6 +15,7 @@ editing-customize-card-templates = Customize Card Templates editing-customize-fields = Customize Fields editing-cut = Cut editing-double-click-image = double-click image +editing-double-click-to-expand = (double-click to expand) editing-edit-current = Edit Current editing-edit-html = Edit HTML editing-fields = Fields @@ -38,6 +39,7 @@ editing-outdent = Decrease indent editing-paste = Paste editing-record-audio = Record audio editing-remove-formatting = Remove formatting +editing-restore-original-size = Restore original size editing-select-remove-formatting = Select formatting to remove editing-show-duplicates = Show Duplicates editing-subscript = Subscript diff --git a/package.json b/package.json index a717f362e..50fafcd1c 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,6 @@ "lodash-es": "^4.17.21", "marked": "^4.0.0", "mathjax": "^3.1.2", - "mathjax-full": "^3.2.0", "protobufjs": "^6.10.2" }, "resolutions": { diff --git a/qt/aqt/data/web/js/BUILD.bazel b/qt/aqt/data/web/js/BUILD.bazel index a28fb5562..78c7ada44 100644 --- a/qt/aqt/data/web/js/BUILD.bazel +++ b/qt/aqt/data/web/js/BUILD.bazel @@ -41,13 +41,21 @@ copy_files_into_group( package = "//ts/reviewer", ) +copy_files_into_group( + name = "mathjax", + srcs = [ + "mathjax.js", + ], + package = "//ts/mathjax", +) + filegroup( name = "js", srcs = [ "aqt", - "mathjax.js", "reviewer", "editor", + "mathjax", "//qt/aqt/data/web/js/vendor", ], visibility = ["//qt:__subpackages__"], @@ -68,6 +76,5 @@ eslint_test( ) exports_files([ - "mathjax.js", "tsconfig.json", ]) diff --git a/qt/aqt/data/web/js/mathjax.js b/qt/aqt/data/web/js/mathjax.js deleted file mode 100644 index 2d864715f..000000000 --- a/qt/aqt/data/web/js/mathjax.js +++ /dev/null @@ -1,28 +0,0 @@ -window.MathJax = { - tex: { - displayMath: [["\\[", "\\]"]], - processRefs: false, - processEnvironments: false, - processEscapes: false, - packages: { - "[+]": ["noerrors", "mhchem"], - }, - }, - startup: { - typeset: false, - pageReady: () => { - return MathJax.startup.defaultPageReady(); - }, - }, - options: { - renderActions: { - addMenu: [], - checkLoading: [], - }, - ignoreHtmlClass: "tex2jax_ignore", - processHtmlClass: "tex2jax_process", - }, - loader: { - load: ["[tex]/noerrors", "[tex]/mhchem"], - }, -}; diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 7d081cde4..6c8ce673e 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -155,7 +155,10 @@ class Editor: self.web.stdHtml( "", css=[f"css/{file}.css"], - js=[f"js/{file}.js"], + js=[ + "js/mathjax.js", + f"js/{file}.js", + ], context=self, default_css=False, ) diff --git a/qt/aqt/sound.py b/qt/aqt/sound.py index 14dfdf36d..a6bbb17f7 100644 --- a/qt/aqt/sound.py +++ b/qt/aqt/sound.py @@ -149,6 +149,14 @@ class AVPlayer: self._enqueued = tags[:] self._play_next_if_idle() + def append_tags(self, tags: list[AVTag]) -> None: + """Append provided tags to the queue, then start playing them if the current player is idle.""" + self._enqueued.extend(tags) + self._play_next_if_idle() + + def queue_is_empty(self) -> bool: + return bool(self._enqueued) + def stop_and_clear_queue(self) -> None: self._enqueued = [] self._stop_if_playing() diff --git a/ts/editable/BUILD.bazel b/ts/editable/BUILD.bazel index 953890ceb..b9aceca15 100644 --- a/ts/editable/BUILD.bazel +++ b/ts/editable/BUILD.bazel @@ -21,8 +21,8 @@ _ts_deps = [ "//ts/lib", "//ts/domlib", "//ts/sveltelib", + "//ts/mathjax:mathjax_ts", "@npm//mathjax", - "@npm//mathjax-full", "@npm//svelte", ] diff --git a/ts/editable/ResizableImage.svelte b/ts/editable/ResizableImage.svelte new file mode 100644 index 000000000..36b06871b --- /dev/null +++ b/ts/editable/ResizableImage.svelte @@ -0,0 +1,11 @@ + + diff --git a/ts/editable/index.ts b/ts/editable/index.ts index 8fa7331d7..f8fa11f71 100644 --- a/ts/editable/index.ts +++ b/ts/editable/index.ts @@ -5,3 +5,4 @@ import "./editable-base.css"; /* only imported for the CSS */ import "./ContentEditable.svelte"; import "./Mathjax.svelte"; +import "./ResizableImage.svelte"; diff --git a/ts/editable/mathjax-element.ts b/ts/editable/mathjax-element.ts index 1d7117cf5..247ccb458 100644 --- a/ts/editable/mathjax-element.ts +++ b/ts/editable/mathjax-element.ts @@ -1,8 +1,6 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import "mathjax/es5/tex-svg-full"; - import { placeCaretAfter, placeCaretBefore } from "../domlib/place-caret"; import { on } from "../lib/events"; import type { DecoratedElement, DecoratedElementConstructor } from "./decorated"; @@ -15,6 +13,13 @@ const mathjaxTagPattern = const mathjaxBlockDelimiterPattern = /\\\[(.*?)\\\]/gsu; const mathjaxInlineDelimiterPattern = /\\\((.*?)\\\)/gsu; +function trimBreaks(text: string): string { + return text + .replace(//gsu, "\n") + .replace(/^\n*/, "") + .replace(/\n*$/, ""); +} + export const Mathjax: DecoratedElementConstructor = class Mathjax extends HTMLElement implements DecoratedElement @@ -25,9 +30,10 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax const stored = undecorated.replace( mathjaxTagPattern, (_match: string, block: string | undefined, text: string) => { + const trimmed = trimBreaks(text); return typeof block === "string" && block !== "false" - ? `\\[${text}\\]` - : `\\(${text}\\)`; + ? `\\[${trimmed}\\]` + : `\\(${trimmed}\\)`; }, ); @@ -37,10 +43,12 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax static toUndecorated(stored: string): string { return stored .replace(mathjaxBlockDelimiterPattern, (_match: string, text: string) => { - return `<${Mathjax.tagName} block="true">${text}`; + const trimmed = trimBreaks(text); + return `<${Mathjax.tagName} block="true">${trimmed}`; }) .replace(mathjaxInlineDelimiterPattern, (_match: string, text: string) => { - return `<${Mathjax.tagName}>${text}`; + const trimmed = trimBreaks(text); + return `<${Mathjax.tagName}>${trimmed}`; }); } diff --git a/ts/editable/mathjax.ts b/ts/editable/mathjax.ts index bbc4b8006..00a6027d8 100644 --- a/ts/editable/mathjax.ts +++ b/ts/editable/mathjax.ts @@ -5,6 +5,8 @@ @typescript-eslint/no-explicit-any: "off", */ +import "mathjax/es5/tex-svg"; + import { mathIcon } from "./icons"; const parser = new DOMParser(); diff --git a/ts/editable/tsconfig.json b/ts/editable/tsconfig.json index 2a86c8fcc..e4dc590f1 100644 --- a/ts/editable/tsconfig.json +++ b/ts/editable/tsconfig.json @@ -5,6 +5,7 @@ { "path": "../components" }, { "path": "../lib" }, { "path": "../domlib" }, - { "path": "../sveltelib" } + { "path": "../sveltelib" }, + { "path": "../mathjax" } ] } diff --git a/ts/editor/editor-toolbar/ClozeButtons.svelte b/ts/editor/ClozeButtons.svelte similarity index 72% rename from ts/editor/editor-toolbar/ClozeButtons.svelte rename to ts/editor/ClozeButtons.svelte index 5dd391d2b..f53c969e8 100644 --- a/ts/editor/editor-toolbar/ClozeButtons.svelte +++ b/ts/editor/ClozeButtons.svelte @@ -3,19 +3,18 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html --> -
+
diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte index 754628b29..ff3fa0d42 100644 --- a/ts/editor/NoteEditor.svelte +++ b/ts/editor/NoteEditor.svelte @@ -324,8 +324,26 @@ the AddCards dialog) should be implemented in the user of this component. {#if cols[index] === "dupe"} {/if} - - + { + richTextsHidden[index] = !richTextsHidden[index]; + + if (!richTextsHidden[index]) { + richTextInputs[index].api.refocus(); + } + }} + /> + { + plainTextsHidden[index] = !plainTextsHidden[index]; + + if (!plainTextsHidden[index]) { + plainTextInputs[index].api.refocus(); + } + }} + /> @@ -339,7 +357,7 @@ the AddCards dialog) should be implemented in the user of this component. }} bind:this={richTextInputs[index]} > - + diff --git a/ts/editor/PlainTextBadge.svelte b/ts/editor/PlainTextBadge.svelte index 838d48ad1..9904150f1 100644 --- a/ts/editor/PlainTextBadge.svelte +++ b/ts/editor/PlainTextBadge.svelte @@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html --> + + diff --git a/ts/editor/editor-toolbar/SubscriptButton.svelte b/ts/editor/editor-toolbar/SubscriptButton.svelte index df1316a20..5fdb113b4 100644 --- a/ts/editor/editor-toolbar/SubscriptButton.svelte +++ b/ts/editor/editor-toolbar/SubscriptButton.svelte @@ -4,7 +4,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html --> - {#await sheetPromise then sheet} - { - updateSizesWithDimensions(); - dropdownObject.update(); - }} - let:toggleActualSize - let:active + image={activeImage} + on:mount={(event) => createDropdown(event.detail.selection)} > - {#if activeImage} - createDropdown(event.detail.selection)} - > - + { + if (shrinkingDisabled) { + return; + } + toggleActualSize(); + updateSizesWithDimensions(); + dropdownObject.update(); + }} + /> - - {actualWidth}×{actualHeight} - {#if customDimensions} - (Original: {naturalWidth}×{naturalHeight}) - {/if} - + + {#if isSizeConstrained} + {tr.editingDoubleClickToExpand()} + {:else} + {actualWidth}×{actualHeight} + {#if customDimensions} + (Original: {naturalWidth}×{naturalHeight}) + {/if} + {/if} + - { - if (active) { - setPointerCapture(event); - } - }} - on:pointermove={(event) => { - resize(event); - updateSizesWithDimensions(); - dropdownObject.update(); - }} - /> - - - - - - {/if} - - {/await} + { + if (!isSizeConstrained) { + setPointerCapture(event); + } + }} + on:pointermove={(event) => { + resize(event); + updateSizesWithDimensions(); + dropdownObject.update(); + }} + /> + + + + { + toggleActualSize(); + updateSizesWithDimensions(); + dropdownObject.update(); + }} + on:imageclear={() => { + clearActualSize(); + updateSizesWithDimensions(); + dropdownObject.update(); + }} + /> + + {/if} diff --git a/ts/editor/image-overlay/SizeSelect.svelte b/ts/editor/image-overlay/SizeSelect.svelte index 9afacc1ff..022b3aad5 100644 --- a/ts/editor/image-overlay/SizeSelect.svelte +++ b/ts/editor/image-overlay/SizeSelect.svelte @@ -3,29 +3,38 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html --> {@html icon} dispatch("imagetoggle")} + --border-left-radius="5px">{@html icon} + + dispatch("imageclear")} + --border-right-radius="5px">{@html sizeClear} diff --git a/ts/editor/image-overlay/WithImageConstrained.svelte b/ts/editor/image-overlay/WithImageConstrained.svelte deleted file mode 100644 index d0d6cb935..000000000 --- a/ts/editor/image-overlay/WithImageConstrained.svelte +++ /dev/null @@ -1,203 +0,0 @@ - - - -{#if activeImage} - -{/if} diff --git a/ts/editor/image-overlay/icons.ts b/ts/editor/image-overlay/icons.ts index 9fd979fe7..fa1019d56 100644 --- a/ts/editor/image-overlay/icons.ts +++ b/ts/editor/image-overlay/icons.ts @@ -4,5 +4,6 @@ export { default as floatLeftIcon } from "@mdi/svg/svg/format-float-left.svg"; export { default as floatNoneIcon } from "@mdi/svg/svg/format-float-none.svg"; export { default as floatRightIcon } from "@mdi/svg/svg/format-float-right.svg"; +export { default as sizeClear } from "@mdi/svg/svg/image-remove.svg"; export { default as sizeActual } from "@mdi/svg/svg/image-size-select-actual.svg"; export { default as sizeMinimized } from "@mdi/svg/svg/image-size-select-large.svg"; diff --git a/ts/editor/mathjax-overlay/MathjaxButtons.svelte b/ts/editor/mathjax-overlay/MathjaxButtons.svelte index 95cc8b2b6..a801572d2 100644 --- a/ts/editor/mathjax-overlay/MathjaxButtons.svelte +++ b/ts/editor/mathjax-overlay/MathjaxButtons.svelte @@ -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 { hasBlockAttribute } from "../../lib/dom"; import * as tr from "../../lib/ftl"; + import ClozeButtons from "../ClozeButtons.svelte"; import { blockIcon, deleteIcon, inlineIcon } from "./icons"; export let element: Element; @@ -48,6 +49,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html > + +
+ +