diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 493c4d8f7..1eac002a4 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -460,7 +460,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too self._save_current_note() elif cmd in self._links: - self._links[cmd](self) + return self._links[cmd](self) else: print("uncaught cmd", cmd) @@ -703,16 +703,21 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too filter=filter, key="media", ) + self.parentWindow.activateWindow() def addMedia(self, path: str, canDelete: bool = False) -> None: """canDelete is a legacy arg and is ignored.""" + try: html = self._addMedia(path) except Exception as e: showWarning(str(e)) return - self.web.eval(f"setFormat('inserthtml', {json.dumps(html)});") + + self.web.eval( + f'require("anki/TemplateButtons").mediaResolve({json.dumps(html)})' + ) def _addMedia(self, path: str, canDelete: bool = False) -> str: """Add to media folder and return local img or sound tag.""" diff --git a/qt/bundle/mac/icon/Assets.xcassets/AppIcon.appiconset/Contents.json b/qt/bundle/mac/icon/Assets.xcassets/AppIcon.appiconset/Contents.json index d0600b28d..6d1e95f9c 100644 --- a/qt/bundle/mac/icon/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/qt/bundle/mac/icon/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,59 +1,59 @@ { - "images" : [ - { - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "filename" : "round-1024-512.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" + "images": [ + { + "idiom": "mac", + "scale": "1x", + "size": "16x16" + }, + { + "idiom": "mac", + "scale": "2x", + "size": "16x16" + }, + { + "idiom": "mac", + "scale": "1x", + "size": "32x32" + }, + { + "idiom": "mac", + "scale": "2x", + "size": "32x32" + }, + { + "idiom": "mac", + "scale": "1x", + "size": "128x128" + }, + { + "idiom": "mac", + "scale": "2x", + "size": "128x128" + }, + { + "idiom": "mac", + "scale": "1x", + "size": "256x256" + }, + { + "idiom": "mac", + "scale": "2x", + "size": "256x256" + }, + { + "filename": "round-1024-512.png", + "idiom": "mac", + "scale": "1x", + "size": "512x512" + }, + { + "idiom": "mac", + "scale": "2x", + "size": "512x512" + } + ], + "info": { + "author": "xcode", + "version": 1 } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } } diff --git a/qt/bundle/mac/icon/Assets.xcassets/Contents.json b/qt/bundle/mac/icon/Assets.xcassets/Contents.json index 73c00596a..dd65c04e8 100644 --- a/qt/bundle/mac/icon/Assets.xcassets/Contents.json +++ b/qt/bundle/mac/icon/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { - "info" : { - "author" : "xcode", - "version" : 1 - } + "info": { + "author": "xcode", + "version": 1 + } } diff --git a/ts/editable/ContentEditable.svelte b/ts/editable/ContentEditable.svelte index a3bd7ba57..dd0a9bdad 100644 --- a/ts/editable/ContentEditable.svelte +++ b/ts/editable/ContentEditable.svelte @@ -11,10 +11,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import { updateAllState } from "../components/WithState.svelte"; import actionList from "../sveltelib/action-list"; - import type { InputManagerAction } from "../sveltelib/input-manager"; - import type { MirrorAction } from "../sveltelib/mirror-dom"; + import type { MirrorAction } from "../sveltelib/dom-mirror"; + import type { SetupInputHandlerAction } from "../sveltelib/input-handler"; import type { ContentEditableAPI } from "./content-editable"; - import { customFocusHandling, preventBuiltinShortcuts } from "./content-editable"; + import { preventBuiltinShortcuts, useFocusHandler } from "./content-editable"; export let resolve: (editable: HTMLElement) => void; @@ -24,15 +24,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const mirrorAction = actionList(mirrors); const mirrorOptions = { store: nodes }; - export let managers: InputManagerAction[]; + export let inputHandlers: SetupInputHandlerAction[]; - const managerAction = actionList(managers); + const inputHandlerAction = actionList(inputHandlers); export let api: Partial; - const { setupFocusHandling, flushCaret } = customFocusHandling(); + const [focusHandler, setupFocusHandling] = useFocusHandler(); - Object.assign(api, { flushCaret }); + Object.assign(api, { focusHandler }); void { - return function (this: HTMLElement): void { - if (!location) { - safePlaceCaretAfterContent(this); - return; - } - - try { - restoreSelection(this, location); - } catch { - safePlaceCaretAfterContent(this); - } - }; -} - -interface CustomFocusHandlingAPI { - setupFocusHandling(element: HTMLElement): { destroy(): void }; - flushCaret(): void; -} - -export function customFocusHandling(): CustomFocusHandlingAPI { - const focusHandlingEvents: (() => void)[] = []; - - function flushEvents(): void { - let removeEvent: (() => void) | undefined; - - while ((removeEvent = focusHandlingEvents.pop())) { - removeEvent(); - } +function restoreCaret(element: HTMLElement, location: SelectionLocation | null): void { + if (!location) { + return safePlaceCaretAfterContent(element); } + try { + restoreSelection(element, location); + } catch { + safePlaceCaretAfterContent(element); + } +} + +type SetupFocusHandlerAction = (element: HTMLElement) => { destroy(): void }; + +export interface FocusHandlerAPI { + /** + * Prevent the automatic caret restoration, that happens upon field focus + */ + flushCaret(): void; + /** + * Executed upon focus event of editable. + */ + focus: HandlerList<{ event: FocusEvent }>; +} + +export function useFocusHandler(): [FocusHandlerAPI, SetupFocusHandlerAction] { + let latestLocation: SelectionLocation | null = null; + let offFocus: Callback | null; + let offPointerDown: Callback | null; + let flush = false; + + function flushCaret(): void { + flush = true; + } + + const focus = new HandlerList<{ event: FocusEvent }>(); + function prepareFocusHandling( editable: HTMLElement, - latestLocation: SelectionLocation | null = null, + location: SelectionLocation | null = null, ): void { - const off = on(editable, "focus", onFocus(latestLocation), { once: true }); + latestLocation = location; - focusHandlingEvents.push(off, on(editable, "pointerdown", off, { once: true })); + offFocus?.(); + offFocus = on( + editable, + "focus", + (event: FocusEvent): void => { + if (flush) { + flush = false; + } else { + restoreCaret(event.currentTarget as HTMLElement, latestLocation); + } + + focus.dispatch({ event }); + }, + { once: true }, + ); + offPointerDown?.(); + offPointerDown = on( + editable, + "pointerdown", + () => { + offFocus?.(); + offFocus = null; + }, + { once: true }, + ); } /** @@ -66,22 +98,26 @@ export function customFocusHandling(): CustomFocusHandlingAPI { prepareFocusHandling(this, saveSelection(this)); } - function setupFocusHandling(editable: HTMLElement): { destroy(): void } { + function setupFocusHandler(editable: HTMLElement): { destroy(): void } { prepareFocusHandling(editable); const off = on(editable, "blur", onBlur); return { destroy() { - flushEvents(); off(); + offFocus?.(); + offPointerDown?.(); }, }; } - return { - setupFocusHandling, - flushCaret: flushEvents, - }; + return [ + { + flushCaret, + focus, + }, + setupFocusHandler, + ]; } if (isApplePlatform()) { @@ -102,5 +138,5 @@ export interface ContentEditableAPI { * the ContentEditable. Can be used when you want to set the caret * yourself. */ - flushCaret(): void; + focusHandler: FocusHandlerAPI; } diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte index 19e7b1ba2..929cce275 100644 --- a/ts/editor/NoteEditor.svelte +++ b/ts/editor/NoteEditor.svelte @@ -326,12 +326,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html