mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Split/Merge editor.py for its three use cases (#1581)
* Forbid inserting object and iframe tags via PlainTextInput * Add optional browserMode parameter to Editor * Create new ts modules for three editor instances - note-creator for AddCards - browser-editor for the editor in the Browser - reviewer-editor for the EditCurrent * Revert "Forbid inserting object and iframe tags via PlainTextInput" This reverts commit ab90ae8194494d883a1863126496e2d8f332509e. * Refactor browserMode to editorMode * Move new editor variants inside /ts/editor directory * Fix typo
This commit is contained in:
parent
489eadb352
commit
3beea5e1e4
18 changed files with 286 additions and 100 deletions
|
@ -71,7 +71,12 @@ class AddCards(QMainWindow):
|
|||
self.setAndFocusNote(new_note)
|
||||
|
||||
def setupEditor(self) -> None:
|
||||
self.editor = aqt.editor.Editor(self.mw, self.form.fieldsArea, self, True)
|
||||
self.editor = aqt.editor.Editor(
|
||||
self.mw,
|
||||
self.form.fieldsArea,
|
||||
self,
|
||||
editorMode=aqt.editor.EditorMode.ADD_CARDS,
|
||||
)
|
||||
self.editor.web.eval("noteEditorPromise.then(() => activateStickyShortcuts());")
|
||||
|
||||
def setup_choosers(self) -> None:
|
||||
|
|
|
@ -418,7 +418,12 @@ class Browser(QMainWindow):
|
|||
)
|
||||
|
||||
gui_hooks.editor_did_init.append(add_preview_button)
|
||||
self.editor = aqt.editor.Editor(self.mw, self.form.fieldsArea, self)
|
||||
self.editor = aqt.editor.Editor(
|
||||
self.mw,
|
||||
self.form.fieldsArea,
|
||||
self,
|
||||
editorMode=aqt.editor.EditorMode.BROWSER,
|
||||
)
|
||||
gui_hooks.editor_did_init.remove(add_preview_button)
|
||||
|
||||
@ensure_editor_saved
|
||||
|
|
|
@ -15,14 +15,6 @@ compile_sass(
|
|||
],
|
||||
)
|
||||
|
||||
copy_files_into_group(
|
||||
name = "editor",
|
||||
srcs = [
|
||||
"editor.css",
|
||||
],
|
||||
package = "//ts/editor",
|
||||
)
|
||||
|
||||
copy_files_into_group(
|
||||
name = "editable",
|
||||
srcs = [
|
||||
|
@ -31,6 +23,16 @@ copy_files_into_group(
|
|||
package = "//ts/editable",
|
||||
)
|
||||
|
||||
copy_files_into_group(
|
||||
name = "editor",
|
||||
srcs = [
|
||||
"browser_editor.css",
|
||||
"reviewer_editor.css",
|
||||
"note_creator.css",
|
||||
],
|
||||
package = "//ts/editor",
|
||||
)
|
||||
|
||||
copy_files_into_group(
|
||||
name = "reviewer",
|
||||
srcs = [
|
||||
|
|
|
@ -26,7 +26,9 @@ typescript(
|
|||
copy_files_into_group(
|
||||
name = "editor",
|
||||
srcs = [
|
||||
"editor.js",
|
||||
"browser_editor.js",
|
||||
"reviewer_editor.js",
|
||||
"note_creator.js",
|
||||
],
|
||||
package = "//ts/editor",
|
||||
)
|
||||
|
@ -43,9 +45,9 @@ filegroup(
|
|||
name = "js",
|
||||
srcs = [
|
||||
"aqt",
|
||||
"editor",
|
||||
"mathjax.js",
|
||||
"reviewer",
|
||||
"editor",
|
||||
"//qt/aqt/data/web/js/vendor",
|
||||
],
|
||||
visibility = ["//qt:__subpackages__"],
|
||||
|
|
|
@ -24,7 +24,12 @@ class EditCurrent(QDialog):
|
|||
self.form.buttonBox.button(QDialogButtonBox.StandardButton.Close).setShortcut(
|
||||
QKeySequence("Ctrl+Return")
|
||||
)
|
||||
self.editor = aqt.editor.Editor(self.mw, self.form.fieldsArea, self)
|
||||
self.editor = aqt.editor.Editor(
|
||||
self.mw,
|
||||
self.form.fieldsArea,
|
||||
self,
|
||||
editorMode=aqt.editor.EditorMode.EDIT_CURRENT,
|
||||
)
|
||||
self.editor.card = self.mw.reviewer.card
|
||||
self.editor.set_note(self.mw.reviewer.card.note(), focusTo=0)
|
||||
restoreGeom(self, "editcurrent")
|
||||
|
|
|
@ -13,6 +13,7 @@ import urllib.error
|
|||
import urllib.parse
|
||||
import urllib.request
|
||||
import warnings
|
||||
from enum import Enum
|
||||
from random import randrange
|
||||
from typing import Any, Callable, Match, cast
|
||||
|
||||
|
@ -80,6 +81,12 @@ audio = (
|
|||
)
|
||||
|
||||
|
||||
class EditorMode(Enum):
|
||||
ADD_CARDS = 0
|
||||
EDIT_CURRENT = 1
|
||||
BROWSER = 2
|
||||
|
||||
|
||||
class Editor:
|
||||
"""The screen that embeds an editing widget should listen for changes via
|
||||
the `operation_did_execute` hook, and call set_note() when the editor needs
|
||||
|
@ -91,13 +98,23 @@ class Editor:
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, mw: AnkiQt, widget: QWidget, parentWindow: QWidget, addMode: bool = False
|
||||
self,
|
||||
mw: AnkiQt,
|
||||
widget: QWidget,
|
||||
parentWindow: QWidget,
|
||||
addMode: bool | None = None,
|
||||
*,
|
||||
editorMode: EditorMode = EditorMode.EDIT_CURRENT,
|
||||
) -> None:
|
||||
self.mw = mw
|
||||
self.widget = widget
|
||||
self.parentWindow = parentWindow
|
||||
self.note: Note | None = None
|
||||
self.addMode = addMode
|
||||
# legacy argument provided?
|
||||
if addMode is not None:
|
||||
editorMode = EditorMode.ADD_CARDS if addMode else EditorMode.EDIT_CURRENT
|
||||
self.addMode = editorMode is EditorMode.ADD_CARDS
|
||||
self.editorMode = editorMode
|
||||
self.currentField: int | None = None
|
||||
# Similar to currentField, but not set to None on a blur. May be
|
||||
# outside the bounds of the current notetype.
|
||||
|
@ -124,11 +141,18 @@ class Editor:
|
|||
self.web.set_bridge_command(self.onBridgeCmd, self)
|
||||
self.outerLayout.addWidget(self.web, 1)
|
||||
|
||||
if self.editorMode == EditorMode.ADD_CARDS:
|
||||
file = "note_creator"
|
||||
elif self.editorMode == EditorMode.BROWSER:
|
||||
file = "browser_editor"
|
||||
else:
|
||||
file = "reviewer_editor"
|
||||
|
||||
# then load page
|
||||
self.web.stdHtml(
|
||||
"",
|
||||
css=["css/editor.css"],
|
||||
js=["js/editor.js"],
|
||||
css=[f"css/{file}.css"],
|
||||
js=[f"js/{file}.js"],
|
||||
context=self,
|
||||
default_css=False,
|
||||
)
|
||||
|
@ -137,7 +161,7 @@ class Editor:
|
|||
gui_hooks.editor_did_init_left_buttons(lefttopbtns, self)
|
||||
|
||||
lefttopbtns_defs = [
|
||||
f"noteEditorPromise.then((noteEditor) => noteEditor.toolbar.notetypeButtons.appendButton({{ component: editorToolbar.Raw, props: {{ html: {json.dumps(button)} }} }}, -1));"
|
||||
f"uiPromise.then((noteEditor) => noteEditor.toolbar.notetypeButtons.appendButton({{ component: editorToolbar.Raw, props: {{ html: {json.dumps(button)} }} }}, -1));"
|
||||
for button in lefttopbtns
|
||||
]
|
||||
lefttopbtns_js = "\n".join(lefttopbtns_defs)
|
||||
|
@ -150,7 +174,7 @@ class Editor:
|
|||
righttopbtns_defs = ", ".join([json.dumps(button) for button in righttopbtns])
|
||||
righttopbtns_js = (
|
||||
f"""
|
||||
noteEditorPromise.then(noteEditor => noteEditor.toolbar.toolbar.appendGroup({{
|
||||
uiPromise.then(noteEditor => noteEditor.toolbar.toolbar.appendGroup({{
|
||||
component: editorToolbar.AddonButtons,
|
||||
id: "addons",
|
||||
props: {{ buttons: [ {righttopbtns_defs} ] }},
|
||||
|
@ -501,9 +525,7 @@ noteEditorPromise.then(noteEditor => noteEditor.toolbar.toolbar.appendGroup({{
|
|||
js += " setSticky(%s);" % json.dumps(sticky)
|
||||
|
||||
js = gui_hooks.editor_will_load_note(js, self.note, self)
|
||||
self.web.evalWithCallback(
|
||||
f"noteEditorPromise.then(() => {{ {js} }})", oncallback
|
||||
)
|
||||
self.web.evalWithCallback(f"uiPromise.then(() => {{ {js} }})", oncallback)
|
||||
|
||||
def _save_current_note(self) -> None:
|
||||
"Call after note is updated with data from webview."
|
||||
|
@ -557,8 +579,8 @@ noteEditorPromise.then(noteEditor => noteEditor.toolbar.toolbar.appendGroup({{
|
|||
elif result == NoteFieldsCheckResult.FIELD_NOT_CLOZE:
|
||||
cloze_hint = tr.adding_cloze_outside_cloze_field()
|
||||
|
||||
self.web.eval(f"setBackgrounds({json.dumps(cols)});")
|
||||
self.web.eval(f"setClozeHint({json.dumps(cloze_hint)});")
|
||||
self.web.eval(f"uiPromise.then(() => setBackgrounds({json.dumps(cols)}));")
|
||||
self.web.eval(f"uiPromise.then(() => setClozeHint({json.dumps(cloze_hint)}));")
|
||||
|
||||
def showDupes(self) -> None:
|
||||
aqt.dialogs.open(
|
||||
|
@ -1333,11 +1355,11 @@ gui_hooks.editor_will_munge_html.append(reverse_url_quoting)
|
|||
def set_cloze_button(editor: Editor) -> None:
|
||||
if editor.note.note_type()["type"] == MODEL_CLOZE:
|
||||
editor.web.eval(
|
||||
'noteEditorPromise.then((noteEditor) => noteEditor.toolbar.templateButtons.showButton("cloze")); '
|
||||
'uiPromise.then((noteEditor) => noteEditor.toolbar.templateButtons.showButton("cloze")); '
|
||||
)
|
||||
else:
|
||||
editor.web.eval(
|
||||
'noteEditorPromise.then((noteEditor) => noteEditor.toolbar.templateButtons.hideButton("cloze")); '
|
||||
'uiPromise.then((noteEditor) => noteEditor.toolbar.templateButtons.hideButton("cloze")); '
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -35,28 +35,52 @@ _ts_deps = [
|
|||
compile_svelte(deps = _ts_deps)
|
||||
|
||||
typescript(
|
||||
name = "editor_ts",
|
||||
name = "editor",
|
||||
deps = _ts_deps + [
|
||||
":svelte",
|
||||
],
|
||||
)
|
||||
|
||||
_esbuild_deps = [
|
||||
":editor",
|
||||
":editor_css",
|
||||
"//sass:button_mixins_lib",
|
||||
"@npm//@mdi",
|
||||
"@npm//bootstrap-icons",
|
||||
"@npm//protobufjs",
|
||||
]
|
||||
|
||||
esbuild(
|
||||
name = "editor",
|
||||
name = "browser_editor",
|
||||
args = {
|
||||
"loader": {".svg": "text"},
|
||||
},
|
||||
entry_point = "index_wrapper.ts",
|
||||
output_css = "editor.css",
|
||||
entry_point = "index_browser.ts",
|
||||
output_css = "browser_editor.css",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":editor_css",
|
||||
":editor_ts",
|
||||
"//sass:button_mixins_lib",
|
||||
"@npm//@mdi",
|
||||
"@npm//bootstrap-icons",
|
||||
"@npm//protobufjs",
|
||||
],
|
||||
deps = _esbuild_deps,
|
||||
)
|
||||
|
||||
esbuild(
|
||||
name = "reviewer_editor",
|
||||
args = {
|
||||
"loader": {".svg": "text"},
|
||||
},
|
||||
entry_point = "index_reviewer.ts",
|
||||
output_css = "reviewer_editor.css",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = _esbuild_deps,
|
||||
)
|
||||
|
||||
esbuild(
|
||||
name = "note_creator",
|
||||
args = {
|
||||
"loader": {".svg": "text"},
|
||||
},
|
||||
entry_point = "index_creator.ts",
|
||||
output_css = "note_creator.css",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = _esbuild_deps,
|
||||
)
|
||||
|
||||
# Tests
|
||||
|
|
19
ts/editor/BrowserEditor.svelte
Normal file
19
ts/editor/BrowserEditor.svelte
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!--
|
||||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="ts">
|
||||
import OldEditorAdapter from "../editor/OldEditorAdapter.svelte";
|
||||
import type { NoteEditorAPI } from "../editor/OldEditorAdapter.svelte";
|
||||
|
||||
const api: Partial<NoteEditorAPI> = {};
|
||||
let noteEditor: OldEditorAdapter;
|
||||
|
||||
export let uiResolve: (api: NoteEditorAPI) => void;
|
||||
|
||||
$: if (noteEditor) {
|
||||
uiResolve(api as NoteEditorAPI);
|
||||
}
|
||||
</script>
|
||||
|
||||
<OldEditorAdapter bind:this={noteEditor} {api} />
|
19
ts/editor/NoteCreator.svelte
Normal file
19
ts/editor/NoteCreator.svelte
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!--
|
||||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="ts">
|
||||
import OldEditorAdapter from "../editor/OldEditorAdapter.svelte";
|
||||
import type { NoteEditorAPI } from "../editor/OldEditorAdapter.svelte";
|
||||
|
||||
const api: Partial<NoteEditorAPI> = {};
|
||||
let noteEditor: OldEditorAdapter;
|
||||
|
||||
export let uiResolve: (api: NoteEditorAPI) => void;
|
||||
|
||||
$: if (noteEditor) {
|
||||
uiResolve(api as NoteEditorAPI);
|
||||
}
|
||||
</script>
|
||||
|
||||
<OldEditorAdapter bind:this={noteEditor} {api} />
|
|
@ -248,7 +248,38 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
}),
|
||||
);
|
||||
|
||||
import { wrapInternal } from "../lib/wrap";
|
||||
|
||||
onMount(() => {
|
||||
function wrap(before: string, after: string): void {
|
||||
if (!get(focusInRichText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const input = get(activeInput!) as RichTextInputAPI;
|
||||
|
||||
input.element.then((element) => {
|
||||
wrapInternal(element, before, after, false);
|
||||
});
|
||||
}
|
||||
|
||||
Object.assign(globalThis, {
|
||||
setFields,
|
||||
setDescriptions,
|
||||
setFonts,
|
||||
focusField,
|
||||
setColorButtons,
|
||||
setTags,
|
||||
setSticky,
|
||||
setBackgrounds,
|
||||
setClozeHint,
|
||||
saveNow: saveFieldNow,
|
||||
activateStickyShortcuts,
|
||||
focusIfField,
|
||||
setNoteId,
|
||||
wrap,
|
||||
});
|
||||
|
||||
document.addEventListener("visibilitychange", saveOnPageHide);
|
||||
return () => document.removeEventListener("visibilitychange", saveOnPageHide);
|
||||
});
|
||||
|
|
|
@ -4,13 +4,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
-->
|
||||
<script context="module" lang="ts">
|
||||
import type { EditingInputAPI } from "./EditingArea.svelte";
|
||||
import type { CodeMirror as CodeMirrorType } from "./code-mirror";
|
||||
import CodeMirror from "./CodeMirror.svelte";
|
||||
|
||||
export interface PlainTextInputAPI extends EditingInputAPI {
|
||||
name: "plain-text";
|
||||
moveCaretToEnd(): void;
|
||||
toggle(): boolean;
|
||||
getEditor(): CodeMirror.Editor;
|
||||
getEditor(): CodeMirrorType.Editor;
|
||||
}
|
||||
|
||||
export const parsingInstructions: string[] = [];
|
||||
|
@ -95,7 +96,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
return hidden;
|
||||
}
|
||||
|
||||
function getEditor(): CodeMirror.Editor {
|
||||
function getEditor(): CodeMirrorType.Editor {
|
||||
return codeMirror?.editor;
|
||||
}
|
||||
|
||||
|
|
19
ts/editor/ReviewerEditor.svelte
Normal file
19
ts/editor/ReviewerEditor.svelte
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!--
|
||||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="ts">
|
||||
import OldEditorAdapter from "../editor/OldEditorAdapter.svelte";
|
||||
import type { NoteEditorAPI } from "../editor/OldEditorAdapter.svelte";
|
||||
|
||||
const api: Partial<NoteEditorAPI> = {};
|
||||
let noteEditor: OldEditorAdapter;
|
||||
|
||||
export let uiResolve: (api: NoteEditorAPI) => void;
|
||||
|
||||
$: if (noteEditor) {
|
||||
uiResolve(api as NoteEditorAPI);
|
||||
}
|
||||
</script>
|
||||
|
||||
<OldEditorAdapter bind:this={noteEditor} {api} />
|
|
@ -60,53 +60,4 @@ export const i18n = setupI18n({
|
|||
],
|
||||
});
|
||||
|
||||
import OldEditorAdapter from "./OldEditorAdapter.svelte";
|
||||
import type { NoteEditorAPI } from "./OldEditorAdapter.svelte";
|
||||
|
||||
async function setupNoteEditor(): Promise<NoteEditorAPI> {
|
||||
await i18n;
|
||||
|
||||
const api: Partial<NoteEditorAPI> = {};
|
||||
|
||||
const noteEditor = new OldEditorAdapter({
|
||||
target: document.body,
|
||||
props: { api: api as NoteEditorAPI },
|
||||
});
|
||||
|
||||
Object.assign(globalThis, {
|
||||
setFields: noteEditor.setFields,
|
||||
setDescriptions: noteEditor.setDescriptions,
|
||||
setFonts: noteEditor.setFonts,
|
||||
focusField: noteEditor.focusField,
|
||||
setColorButtons: noteEditor.setColorButtons,
|
||||
setTags: noteEditor.setTags,
|
||||
setSticky: noteEditor.setSticky,
|
||||
setBackgrounds: noteEditor.setBackgrounds,
|
||||
setClozeHint: noteEditor.setClozeHint,
|
||||
saveNow: noteEditor.saveFieldNow,
|
||||
activateStickyShortcuts: noteEditor.activateStickyShortcuts,
|
||||
focusIfField: noteEditor.focusIfField,
|
||||
setNoteId: noteEditor.setNoteId,
|
||||
});
|
||||
|
||||
return api as NoteEditorAPI;
|
||||
}
|
||||
|
||||
import { get } from "svelte/store";
|
||||
import { wrapInternal } from "../lib/wrap";
|
||||
import type { RichTextInputAPI } from "./RichTextInput.svelte";
|
||||
|
||||
export async function wrap(before: string, after: string): Promise<void> {
|
||||
const noteEditor = await noteEditorPromise;
|
||||
|
||||
if (!get(noteEditor.focusInRichText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeInput = get(noteEditor.activeInput) as RichTextInputAPI;
|
||||
const element = await activeInput.element;
|
||||
wrapInternal(element, before, after, false);
|
||||
}
|
||||
|
||||
export const noteEditorPromise = setupNoteEditor();
|
||||
export { editorToolbar } from "./EditorToolbar.svelte";
|
||||
|
|
27
ts/editor/index_browser.ts
Normal file
27
ts/editor/index_browser.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
import { i18n } from ".";
|
||||
import BrowserEditor from "./BrowserEditor.svelte";
|
||||
import { promiseWithResolver } from "../lib/promise";
|
||||
import { globalExport } from "../lib/globals";
|
||||
|
||||
const [uiPromise, uiResolve] = promiseWithResolver();
|
||||
|
||||
async function setupBrowserEditor(): Promise<void> {
|
||||
await i18n;
|
||||
|
||||
new BrowserEditor({
|
||||
target: document.body,
|
||||
props: { uiResolve },
|
||||
});
|
||||
}
|
||||
|
||||
setupBrowserEditor();
|
||||
|
||||
import * as editor from ".";
|
||||
|
||||
globalExport({
|
||||
...editor,
|
||||
uiPromise,
|
||||
noteEditorPromise: uiPromise,
|
||||
});
|
27
ts/editor/index_creator.ts
Normal file
27
ts/editor/index_creator.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
import { i18n } from ".";
|
||||
import NoteCreator from "./NoteCreator.svelte";
|
||||
import { promiseWithResolver } from "../lib/promise";
|
||||
import { globalExport } from "../lib/globals";
|
||||
|
||||
const [uiPromise, uiResolve] = promiseWithResolver();
|
||||
|
||||
async function setupNoteCreator(): Promise<void> {
|
||||
await i18n;
|
||||
|
||||
new NoteCreator({
|
||||
target: document.body,
|
||||
props: { uiResolve },
|
||||
});
|
||||
}
|
||||
|
||||
setupNoteCreator();
|
||||
|
||||
import * as editor from ".";
|
||||
|
||||
globalExport({
|
||||
...editor,
|
||||
uiPromise,
|
||||
noteEditorPromise: uiPromise,
|
||||
});
|
27
ts/editor/index_reviewer.ts
Normal file
27
ts/editor/index_reviewer.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
import { i18n } from "../editor";
|
||||
import ReviewerEditor from "./ReviewerEditor.svelte";
|
||||
import { promiseWithResolver } from "../lib/promise";
|
||||
import { globalExport } from "../lib/globals";
|
||||
|
||||
const [uiPromise, uiResolve] = promiseWithResolver();
|
||||
|
||||
async function setupReviewerEditor(): Promise<void> {
|
||||
await i18n;
|
||||
|
||||
new ReviewerEditor({
|
||||
target: document.body,
|
||||
props: { uiResolve },
|
||||
});
|
||||
}
|
||||
|
||||
setupReviewerEditor();
|
||||
|
||||
import * as editor from "../editor";
|
||||
|
||||
globalExport({
|
||||
...editor,
|
||||
uiPromise,
|
||||
noteEditorPromise: uiPromise,
|
||||
});
|
|
@ -1,11 +0,0 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
// extend the global namespace with our exports - not sure if there's a better way with esbuild
|
||||
import * as globals from "./index";
|
||||
for (const key in globals) {
|
||||
window[key] = globals[key];
|
||||
}
|
||||
|
||||
// but also export as window.anki
|
||||
window["anki"] = globals;
|
11
ts/lib/globals.ts
Normal file
11
ts/lib/globals.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
export function globalExport(globals: Record<string, unknown>): void {
|
||||
for (const key in globals) {
|
||||
window[key] = globals[key];
|
||||
}
|
||||
|
||||
// but also export as window.anki
|
||||
window["anki"] = globals;
|
||||
}
|
Loading…
Reference in a new issue