mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
follow-up pr for io button in note editor (#2600)
* follow-up pr for io button in note editor * Expose change event in Svelte instead of relying on timeout (dae)
This commit is contained in:
parent
a35c1a058d
commit
b9da61f993
10 changed files with 186 additions and 56 deletions
|
@ -115,8 +115,8 @@ class AddCards(QMainWindow):
|
||||||
self.addButton.setToolTip(shortcut(tr.adding_add_shortcut_ctrlandenter()))
|
self.addButton.setToolTip(shortcut(tr.adding_add_shortcut_ctrlandenter()))
|
||||||
|
|
||||||
# add io button
|
# add io button
|
||||||
self.io_add_button = bb.addButton(f"{tr.actions_add()} {downArrow()}", ar)
|
self.io_add_button = bb.addButton(f"{tr.actions_add()}", ar)
|
||||||
qconnect(self.io_add_button.clicked, self.onAddIo)
|
qconnect(self.io_add_button.clicked, self.add_io_note)
|
||||||
self.io_add_button.setShortcut(QKeySequence("Ctrl+Shift+I"))
|
self.io_add_button.setShortcut(QKeySequence("Ctrl+Shift+I"))
|
||||||
|
|
||||||
# close
|
# close
|
||||||
|
@ -372,21 +372,8 @@ class AddCards(QMainWindow):
|
||||||
|
|
||||||
self.ifCanClose(doClose)
|
self.ifCanClose(doClose)
|
||||||
|
|
||||||
def onAddIo(self) -> None:
|
def add_io_note(self) -> None:
|
||||||
m = QMenu(self)
|
self.editor.web.eval("setOcclusionFieldInner()")
|
||||||
a = m.addAction(tr.notetypes_hide_all_guess_one())
|
|
||||||
qconnect(a.triggered, self.add_io_hide_all_note)
|
|
||||||
a = m.addAction(tr.notetypes_hide_one_guess_one())
|
|
||||||
qconnect(a.triggered, self.add_io_hide_one_note)
|
|
||||||
m.popup(QCursor.pos())
|
|
||||||
|
|
||||||
def add_io_hide_all_note(self) -> None:
|
|
||||||
self.editor.web.eval("setOcclusionField(true)")
|
|
||||||
self.add_current_note()
|
|
||||||
self.editor.web.eval("resetIOImageLoaded()")
|
|
||||||
|
|
||||||
def add_io_hide_one_note(self) -> None:
|
|
||||||
self.editor.web.eval("setOcclusionField(false)")
|
|
||||||
self.add_current_note()
|
self.add_current_note()
|
||||||
self.editor.web.eval("resetIOImageLoaded()")
|
self.editor.web.eval("resetIOImageLoaded()")
|
||||||
|
|
||||||
|
|
|
@ -562,8 +562,8 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
|
||||||
self.editorMode != EditorMode.ADD_CARDS
|
self.editorMode != EditorMode.ADD_CARDS
|
||||||
and self.current_notetype_is_image_occlusion()
|
and self.current_notetype_is_image_occlusion()
|
||||||
):
|
):
|
||||||
options = {"kind": "edit", "noteId": self.note.id}
|
mode = {"kind": "edit", "noteId": self.note.id}
|
||||||
options = {"mode": options}
|
options = {"mode": mode}
|
||||||
js += " setupMaskEditor(%s);" % json.dumps(options)
|
js += " setupMaskEditor(%s);" % json.dumps(options)
|
||||||
|
|
||||||
js = gui_hooks.editor_will_load_note(js, self.note, self)
|
js = gui_hooks.editor_will_load_note(js, self.note, self)
|
||||||
|
@ -1202,10 +1202,16 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
|
||||||
def accept(file: str) -> None:
|
def accept(file: str) -> None:
|
||||||
try:
|
try:
|
||||||
html = self._addMedia(file)
|
html = self._addMedia(file)
|
||||||
|
if self.editorMode == EditorMode.ADD_CARDS:
|
||||||
mode = {"kind": "add", "imagePath": file, "notetypeId": 0}
|
mode = {"kind": "add", "imagePath": file, "notetypeId": 0}
|
||||||
# pass both html and options
|
|
||||||
options = {"html": html, "mode": mode}
|
options = {"html": html, "mode": mode}
|
||||||
self.web.eval(f"setupMaskEditor({json.dumps(options)})")
|
self.web.eval(f"setupMaskEditor({json.dumps(options)})")
|
||||||
|
else:
|
||||||
|
mode = {"kind": "edit", "notetypeId": self.note.id}
|
||||||
|
options = {"html": html, "mode": mode}
|
||||||
|
self.web.eval(f"resetIOImage({json.dumps(file)})")
|
||||||
|
self.web.eval(f"setImageField({json.dumps(html)})")
|
||||||
|
self.web.eval(f"setupMaskEditor({json.dumps(options)})")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
showWarning(str(e))
|
showWarning(str(e))
|
||||||
return
|
return
|
||||||
|
|
|
@ -298,10 +298,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveNow(): void {
|
function saveNow(): void {
|
||||||
updateIONoteInEditMode();
|
|
||||||
closeMathjaxEditor?.();
|
closeMathjaxEditor?.();
|
||||||
$commitTagEdits();
|
$commitTagEdits();
|
||||||
saveFieldNow();
|
saveFieldNow();
|
||||||
|
imageOcclusionMode = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveOnPageHide() {
|
export function saveOnPageHide() {
|
||||||
|
@ -390,7 +390,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import ImageOcclusionPage from "image-occlusion/ImageOcclusionPage.svelte";
|
import ImageOcclusionPage from "image-occlusion/ImageOcclusionPage.svelte";
|
||||||
import type { IOMode } from "image-occlusion/lib";
|
import type { IOMode } from "image-occlusion/lib";
|
||||||
import { exportShapesToClozeDeletions } from "image-occlusion/shapes/to-cloze";
|
import { exportShapesToClozeDeletions } from "image-occlusion/shapes/to-cloze";
|
||||||
import { ioMaskEditorVisible } from "image-occlusion/store";
|
import { hideAllGuessOne, ioMaskEditorVisible } from "image-occlusion/store";
|
||||||
|
|
||||||
import { mathjaxConfig } from "../editable/mathjax-element";
|
import { mathjaxConfig } from "../editable/mathjax-element";
|
||||||
import CollapseLabel from "./CollapseLabel.svelte";
|
import CollapseLabel from "./CollapseLabel.svelte";
|
||||||
|
@ -402,10 +402,23 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
imageOcclusionMode = options.mode;
|
imageOcclusionMode = options.mode;
|
||||||
if (options.mode.kind === "add") {
|
if (options.mode.kind === "add") {
|
||||||
fieldStores[1].set(options.html);
|
fieldStores[1].set(options.html);
|
||||||
|
} else {
|
||||||
|
const clozeNote = get(fieldStores[0]);
|
||||||
|
if (clozeNote.includes("oi=1")) {
|
||||||
|
$hideAllGuessOne = true;
|
||||||
|
} else {
|
||||||
|
$hideAllGuessOne = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isIOImageLoaded = true;
|
isIOImageLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setImageField(html) {
|
||||||
|
fieldStores[1].set(html);
|
||||||
|
}
|
||||||
|
globalThis.setImageField = setImageField;
|
||||||
|
|
||||||
// update cloze deletions and set occlusion fields, it call in saveNow to update cloze deletions
|
// update cloze deletions and set occlusion fields, it call in saveNow to update cloze deletions
|
||||||
function updateIONoteInEditMode() {
|
function updateIONoteInEditMode() {
|
||||||
if (isEditMode) {
|
if (isEditMode) {
|
||||||
|
@ -418,6 +431,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setOcclusionFieldInner() {
|
||||||
|
if (isImageOcclusion) {
|
||||||
|
const occlusionsData = exportShapesToClozeDeletions($hideAllGuessOne);
|
||||||
|
fieldStores[0].set(occlusionsData.clozes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// global for calling this method in desktop note editor
|
||||||
|
globalThis.setOcclusionFieldInner = setOcclusionFieldInner;
|
||||||
|
|
||||||
// reset for new occlusion in add mode
|
// reset for new occlusion in add mode
|
||||||
function resetIOImageLoaded() {
|
function resetIOImageLoaded() {
|
||||||
isIOImageLoaded = false;
|
isIOImageLoaded = false;
|
||||||
|
@ -484,6 +506,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
setIsEditMode,
|
setIsEditMode,
|
||||||
setupMaskEditor,
|
setupMaskEditor,
|
||||||
setOcclusionField,
|
setOcclusionField,
|
||||||
|
setOcclusionFieldInner,
|
||||||
...oldEditorAdapter,
|
...oldEditorAdapter,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -539,7 +562,10 @@ the AddCards dialog) should be implemented in the user of this component.
|
||||||
|
|
||||||
{#if imageOcclusionMode}
|
{#if imageOcclusionMode}
|
||||||
<div style="display: {$ioMaskEditorVisible ? 'block' : 'none'}">
|
<div style="display: {$ioMaskEditorVisible ? 'block' : 'none'}">
|
||||||
<ImageOcclusionPage mode={imageOcclusionMode} />
|
<ImageOcclusionPage
|
||||||
|
mode={imageOcclusionMode}
|
||||||
|
on:change={updateIONoteInEditMode}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -11,15 +11,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import MasksEditor from "./MaskEditor.svelte";
|
import MasksEditor from "./MaskEditor.svelte";
|
||||||
import Notes from "./Notes.svelte";
|
import Notes from "./Notes.svelte";
|
||||||
import StickyFooter from "./StickyFooter.svelte";
|
import StickyFooter from "./StickyFooter.svelte";
|
||||||
|
import { hideAllGuessOne } from "./store";
|
||||||
|
|
||||||
export let mode: IOMode;
|
export let mode: IOMode;
|
||||||
|
|
||||||
async function hideAllGuessOne(): Promise<void> {
|
async function addNote(): Promise<void> {
|
||||||
addOrUpdateNote(mode, true);
|
addOrUpdateNote(mode, $hideAllGuessOne);
|
||||||
}
|
|
||||||
|
|
||||||
async function hideOneGuessOne(): Promise<void> {
|
|
||||||
addOrUpdateNote(mode, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
|
@ -45,14 +42,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div hidden={activeTabValue != 1}>
|
<div hidden={activeTabValue != 1}>
|
||||||
<MasksEditor {mode} />
|
<MasksEditor {mode} on:change />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div hidden={activeTabValue != 2}>
|
<div hidden={activeTabValue != 2}>
|
||||||
<Notes />
|
<Notes />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<StickyFooter {hideAllGuessOne} {hideOneGuessOne} />
|
<StickyFooter {addNote} />
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
@ -5,6 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PanZoom } from "panzoom";
|
import type { PanZoom } from "panzoom";
|
||||||
import panzoom from "panzoom";
|
import panzoom from "panzoom";
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
|
||||||
import type { IOMode } from "./lib";
|
import type { IOMode } from "./lib";
|
||||||
import { setupMaskEditor, setupMaskEditorForEdit } from "./mask-editor";
|
import { setupMaskEditor, setupMaskEditorForEdit } from "./mask-editor";
|
||||||
|
@ -17,6 +18,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
const startingTool = mode.kind === "add" ? "draw-rectangle" : "cursor";
|
const startingTool = mode.kind === "add" ? "draw-rectangle" : "cursor";
|
||||||
$: canvas = null;
|
$: canvas = null;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
function onChange() {
|
||||||
|
dispatch("change", { canvas });
|
||||||
|
}
|
||||||
|
|
||||||
function init(node) {
|
function init(node) {
|
||||||
instance = panzoom(node, {
|
instance = panzoom(node, {
|
||||||
bounds: true,
|
bounds: true,
|
||||||
|
@ -28,11 +35,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
instance.pause();
|
instance.pause();
|
||||||
|
|
||||||
if (mode.kind == "add") {
|
if (mode.kind == "add") {
|
||||||
setupMaskEditor(mode.imagePath, instance).then((canvas1) => {
|
setupMaskEditor(mode.imagePath, instance, onChange).then((canvas1) => {
|
||||||
canvas = canvas1;
|
canvas = canvas1;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setupMaskEditorForEdit(mode.noteId, instance).then((canvas1) => {
|
setupMaskEditorForEdit(mode.noteId, instance, onChange).then((canvas1) => {
|
||||||
canvas = canvas1;
|
canvas = canvas1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import ButtonGroup from "../components/ButtonGroup.svelte";
|
import ButtonGroup from "../components/ButtonGroup.svelte";
|
||||||
import LabelButton from "../components/LabelButton.svelte";
|
import LabelButton from "../components/LabelButton.svelte";
|
||||||
|
|
||||||
export let hideAllGuessOne: () => void;
|
export let addNote: () => void;
|
||||||
export let hideOneGuessOne: () => void;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div style:flex-grow="1" />
|
<div style:flex-grow="1" />
|
||||||
|
@ -18,18 +17,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<LabelButton
|
<LabelButton
|
||||||
--border-left-radius="5px"
|
--border-left-radius="5px"
|
||||||
--border-right-radius="5px"
|
--border-right-radius="5px"
|
||||||
on:click={hideAllGuessOne}
|
on:click={addNote}
|
||||||
class=" bottom-btn"
|
class=" bottom-btn"
|
||||||
>
|
>
|
||||||
{tr.notetypesHideAllGuessOne()}
|
{tr.actionsAdd()}
|
||||||
</LabelButton>
|
|
||||||
<LabelButton
|
|
||||||
--border-left-radius="5px"
|
|
||||||
--border-right-radius="5px"
|
|
||||||
on:click={hideOneGuessOne}
|
|
||||||
class=" bottom-btn"
|
|
||||||
>
|
|
||||||
{tr.notetypesHideOneGuessOne()}
|
|
||||||
</LabelButton>
|
</LabelButton>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,8 +3,23 @@ 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>
|
<script>
|
||||||
import IconButton from "../components/IconButton.svelte";
|
import { bridgeCommand } from "@tslib/bridgecommand";
|
||||||
import { mdiEye, mdiFormatAlignCenter } from "./icons";
|
import * as tr from "@tslib/ftl";
|
||||||
|
import DropdownItem from "components/DropdownItem.svelte";
|
||||||
|
import IconButton from "components/IconButton.svelte";
|
||||||
|
import Popover from "components/Popover.svelte";
|
||||||
|
import WithFloating from "components/WithFloating.svelte";
|
||||||
|
|
||||||
|
import {
|
||||||
|
mdiChevronDown,
|
||||||
|
mdiEye,
|
||||||
|
mdiFormatAlignCenter,
|
||||||
|
mdiRefresh,
|
||||||
|
mdiSquare,
|
||||||
|
mdiViewDashboard,
|
||||||
|
} from "./icons";
|
||||||
|
import { setupMaskEditor } from "./mask-editor";
|
||||||
|
import { hideAllGuessOne } from "./store";
|
||||||
import { drawEllipse, drawPolygon, drawRectangle } from "./tools/index";
|
import { drawEllipse, drawPolygon, drawRectangle } from "./tools/index";
|
||||||
import { makeMaskTransparent } from "./tools/lib";
|
import { makeMaskTransparent } from "./tools/lib";
|
||||||
import { enableSelectable, stopDraw } from "./tools/lib";
|
import { enableSelectable, stopDraw } from "./tools/lib";
|
||||||
|
@ -24,6 +39,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
let showAlignTools = false;
|
let showAlignTools = false;
|
||||||
let leftPos = 82;
|
let leftPos = 82;
|
||||||
let maksOpacity = false;
|
let maksOpacity = false;
|
||||||
|
let showFloating = false;
|
||||||
|
|
||||||
document.addEventListener("click", (event) => {
|
document.addEventListener("click", (event) => {
|
||||||
const upperCanvas = document.querySelector(".upper-canvas");
|
const upperCanvas = document.querySelector(".upper-canvas");
|
||||||
|
@ -61,6 +77,22 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
stopDraw(canvas);
|
stopDraw(canvas);
|
||||||
canvas.selectionColor = "rgba(100, 100, 255, 0.3)";
|
canvas.selectionColor = "rgba(100, 100, 255, 0.3)";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetIOImage = (path) => {
|
||||||
|
setupMaskEditor(path, instance);
|
||||||
|
};
|
||||||
|
globalThis.resetIOImage = resetIOImage;
|
||||||
|
|
||||||
|
const setOcclusionFieldForDesktop = () => {
|
||||||
|
const clist = document.body.classList;
|
||||||
|
if (
|
||||||
|
clist.contains("isLin") ||
|
||||||
|
clist.contains("isMac") ||
|
||||||
|
clist.contains("isWin")
|
||||||
|
) {
|
||||||
|
globalThis.setOcclusionFieldInner();
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="tool-bar-container">
|
<div class="tool-bar-container">
|
||||||
|
@ -79,6 +111,65 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="top-tool-bar-container">
|
<div class="top-tool-bar-container">
|
||||||
|
<div class="undo-redo-button" on:click={() => (showFloating = !showFloating)}>
|
||||||
|
{#if $hideAllGuessOne}
|
||||||
|
<IconButton class="top-tool-icon-button left-border-radius" {iconSize}>
|
||||||
|
{@html mdiViewDashboard}
|
||||||
|
</IconButton>
|
||||||
|
{:else}
|
||||||
|
<IconButton class="top-tool-icon-button left-border-radius" {iconSize}>
|
||||||
|
{@html mdiSquare}
|
||||||
|
</IconButton>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<WithFloating
|
||||||
|
show={showFloating}
|
||||||
|
closeOnInsideClick
|
||||||
|
inline
|
||||||
|
style="line-height: unset !important"
|
||||||
|
on:close={() => (showFloating = false)}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
class="top-tool-icon-button right-border-radius dropdown-tool-mode"
|
||||||
|
slot="reference"
|
||||||
|
>
|
||||||
|
{@html mdiChevronDown}
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Popover slot="floating" --popover-padding-inline="0">
|
||||||
|
<DropdownItem
|
||||||
|
on:click={() => {
|
||||||
|
$hideAllGuessOne = true;
|
||||||
|
setOcclusionFieldForDesktop();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>{tr.notetypesHideAllGuessOne()}</span>
|
||||||
|
</DropdownItem>
|
||||||
|
<DropdownItem
|
||||||
|
on:click={() => {
|
||||||
|
$hideAllGuessOne = false;
|
||||||
|
setOcclusionFieldForDesktop();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>{tr.notetypesHideOneGuessOne()}</span>
|
||||||
|
</DropdownItem>
|
||||||
|
</Popover>
|
||||||
|
</WithFloating>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- refresh for changing image -->
|
||||||
|
<div class="undo-redo-button">
|
||||||
|
<IconButton
|
||||||
|
class="top-tool-icon-button icon-border-radius"
|
||||||
|
{iconSize}
|
||||||
|
on:click={() => {
|
||||||
|
bridgeCommand("addImageForOcclusion");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{@html mdiRefresh}
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- undo & redo tools -->
|
<!-- undo & redo tools -->
|
||||||
<div class="undo-redo-button">
|
<div class="undo-redo-button">
|
||||||
{#each undoRedoTools as tool}
|
{#each undoRedoTools as tool}
|
||||||
|
@ -266,4 +357,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
color: white !important;
|
color: white !important;
|
||||||
background: var(--button-primary-bg) !important;
|
background: var(--button-primary-bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.icon-border-radius) {
|
||||||
|
border-radius: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dropdown-tool-mode) {
|
||||||
|
height: 38px !important;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -9,6 +9,7 @@ export { default as mdiAlignHorizontalRight } from "@mdi/svg/svg/align-horizonta
|
||||||
export { default as mdiAlignVerticalBottom } from "@mdi/svg/svg/align-vertical-bottom.svg";
|
export { default as mdiAlignVerticalBottom } from "@mdi/svg/svg/align-vertical-bottom.svg";
|
||||||
export { default as mdiAlignVerticalCenter } from "@mdi/svg/svg/align-vertical-center.svg";
|
export { default as mdiAlignVerticalCenter } from "@mdi/svg/svg/align-vertical-center.svg";
|
||||||
export { default as mdiAlignVerticalTop } from "@mdi/svg/svg/align-vertical-top.svg";
|
export { default as mdiAlignVerticalTop } from "@mdi/svg/svg/align-vertical-top.svg";
|
||||||
|
export { default as mdiChevronDown } from "@mdi/svg/svg/chevron-down.svg";
|
||||||
export { default as mdiClose } from "@mdi/svg/svg/close.svg";
|
export { default as mdiClose } from "@mdi/svg/svg/close.svg";
|
||||||
export { default as mdiCodeTags } from "@mdi/svg/svg/code-tags.svg";
|
export { default as mdiCodeTags } from "@mdi/svg/svg/code-tags.svg";
|
||||||
export { default as mdiCopy } from "@mdi/svg/svg/content-copy.svg";
|
export { default as mdiCopy } from "@mdi/svg/svg/content-copy.svg";
|
||||||
|
@ -27,7 +28,10 @@ export { default as mdiZoomIn } from "@mdi/svg/svg/magnify-plus-outline.svg";
|
||||||
export { default as mdiMagnifyScan } from "@mdi/svg/svg/magnify-scan.svg";
|
export { default as mdiMagnifyScan } from "@mdi/svg/svg/magnify-scan.svg";
|
||||||
export { default as mdiRectangleOutline } from "@mdi/svg/svg/rectangle-outline.svg";
|
export { default as mdiRectangleOutline } from "@mdi/svg/svg/rectangle-outline.svg";
|
||||||
export { default as mdiRedo } from "@mdi/svg/svg/redo.svg";
|
export { default as mdiRedo } from "@mdi/svg/svg/redo.svg";
|
||||||
|
export { default as mdiRefresh } from "@mdi/svg/svg/refresh.svg";
|
||||||
|
export { default as mdiSquare } from "@mdi/svg/svg/square.svg";
|
||||||
export { default as mdiUndo } from "@mdi/svg/svg/undo.svg";
|
export { default as mdiUndo } from "@mdi/svg/svg/undo.svg";
|
||||||
export { default as mdiUnfoldMoreHorizontal } from "@mdi/svg/svg/unfold-more-horizontal.svg";
|
export { default as mdiUnfoldMoreHorizontal } from "@mdi/svg/svg/unfold-more-horizontal.svg";
|
||||||
export { default as mdiUngroup } from "@mdi/svg/svg/ungroup.svg";
|
export { default as mdiUngroup } from "@mdi/svg/svg/ungroup.svg";
|
||||||
export { default as mdiVectorPolygonVariant } from "@mdi/svg/svg/vector-polygon-variant.svg";
|
export { default as mdiVectorPolygonVariant } from "@mdi/svg/svg/vector-polygon-variant.svg";
|
||||||
|
export { default as mdiViewDashboard } from "@mdi/svg/svg/view-dashboard.svg";
|
||||||
|
|
|
@ -16,9 +16,13 @@ import { enableSelectable, moveShapeToCanvasBoundaries } from "./tools/lib";
|
||||||
import { undoRedoInit } from "./tools/tool-undo-redo";
|
import { undoRedoInit } from "./tools/tool-undo-redo";
|
||||||
import type { Size } from "./types";
|
import type { Size } from "./types";
|
||||||
|
|
||||||
export const setupMaskEditor = async (path: string, instance: PanZoom): Promise<fabric.Canvas> => {
|
export const setupMaskEditor = async (
|
||||||
|
path: string,
|
||||||
|
instance: PanZoom,
|
||||||
|
onChange: () => void,
|
||||||
|
): Promise<fabric.Canvas> => {
|
||||||
const imageData = await getImageForOcclusion({ path });
|
const imageData = await getImageForOcclusion({ path });
|
||||||
const canvas = initCanvas();
|
const canvas = initCanvas(onChange);
|
||||||
|
|
||||||
// get image width and height
|
// get image width and height
|
||||||
const image = document.getElementById("image") as HTMLImageElement;
|
const image = document.getElementById("image") as HTMLImageElement;
|
||||||
|
@ -35,7 +39,11 @@ export const setupMaskEditor = async (path: string, instance: PanZoom): Promise<
|
||||||
return canvas;
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setupMaskEditorForEdit = async (noteId: number, instance: PanZoom): Promise<fabric.Canvas> => {
|
export const setupMaskEditorForEdit = async (
|
||||||
|
noteId: number,
|
||||||
|
instance: PanZoom,
|
||||||
|
onChange: () => void,
|
||||||
|
): Promise<fabric.Canvas> => {
|
||||||
const clozeNoteResponse = await getImageOcclusionNote({ noteId: BigInt(noteId) });
|
const clozeNoteResponse = await getImageOcclusionNote({ noteId: BigInt(noteId) });
|
||||||
const kind = clozeNoteResponse.value?.case;
|
const kind = clozeNoteResponse.value?.case;
|
||||||
if (!kind || kind === "error") {
|
if (!kind || kind === "error") {
|
||||||
|
@ -50,7 +58,7 @@ export const setupMaskEditorForEdit = async (noteId: number, instance: PanZoom):
|
||||||
}
|
}
|
||||||
|
|
||||||
const clozeNote = clozeNoteResponse.value.value;
|
const clozeNote = clozeNoteResponse.value.value;
|
||||||
const canvas = initCanvas();
|
const canvas = initCanvas(onChange);
|
||||||
|
|
||||||
// get image width and height
|
// get image width and height
|
||||||
const image = document.getElementById("image") as HTMLImageElement;
|
const image = document.getElementById("image") as HTMLImageElement;
|
||||||
|
@ -75,7 +83,7 @@ export const setupMaskEditorForEdit = async (noteId: number, instance: PanZoom):
|
||||||
return canvas;
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initCanvas = (): fabric.Canvas => {
|
function initCanvas(onChange: () => void): fabric.Canvas {
|
||||||
const canvas = new fabric.Canvas("canvas");
|
const canvas = new fabric.Canvas("canvas");
|
||||||
tagsWritable.set([]);
|
tagsWritable.set([]);
|
||||||
globalThis.canvas = canvas;
|
globalThis.canvas = canvas;
|
||||||
|
@ -84,8 +92,10 @@ const initCanvas = (): fabric.Canvas => {
|
||||||
canvas.uniScaleKey = "none";
|
canvas.uniScaleKey = "none";
|
||||||
moveShapeToCanvasBoundaries(canvas);
|
moveShapeToCanvasBoundaries(canvas);
|
||||||
undoRedoInit(canvas);
|
undoRedoInit(canvas);
|
||||||
|
canvas.on("object:modified", onChange);
|
||||||
|
canvas.on("object:removed", onChange);
|
||||||
return canvas;
|
return canvas;
|
||||||
};
|
}
|
||||||
|
|
||||||
const getImageData = (imageData): string => {
|
const getImageData = (imageData): string => {
|
||||||
const b64encoded = protoBase64.enc(imageData);
|
const b64encoded = protoBase64.enc(imageData);
|
||||||
|
|
|
@ -11,3 +11,5 @@ export const zoomResetValue = writable(1);
|
||||||
export const tagsWritable = writable([""]);
|
export const tagsWritable = writable([""]);
|
||||||
// it stores the visibility of mask editor
|
// it stores the visibility of mask editor
|
||||||
export const ioMaskEditorVisible = writable(true);
|
export const ioMaskEditorVisible = writable(true);
|
||||||
|
// it store hide all or hide one mode
|
||||||
|
export const hideAllGuessOne = writable(true);
|
||||||
|
|
Loading…
Reference in a new issue