From 0d83581ab08e1a92c5c55c99965e9f054b3f43e6 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 25 Feb 2022 01:59:06 +0100 Subject: [PATCH] Fix insert media always insert at the start (on Windows) (#1684) * Move Trigger into its own file * Try implement HandlerList * Implement new input handler and handler-list * Use new refocus HandlerList in TextColorButton * Fix TextColorButton on windows * Move ColorPicker to editor-toolbar * Change trigger behavior of overwriteSurround * Fix mathjax-overlay flushCaret * Insert image via bridgeCommand return value * Fix invoking color picker with F8 * Have remove format work even when collapsed * Satisfy formatter * Insert media via callback resolved from python * Replace print with web.eval * Fix python formatting * remove unused function (dae) --- qt/aqt/editor.py | 9 +- .../AppIcon.appiconset/Contents.json | 112 +++++------ .../mac/icon/Assets.xcassets/Contents.json | 8 +- ts/editable/ContentEditable.svelte | 16 +- ts/editable/content-editable.ts | 124 +++++++----- ts/editor/NoteEditor.svelte | 10 +- .../editor-toolbar}/ColorPicker.svelte | 13 +- .../HighlightColorButton.svelte | 8 +- .../editor-toolbar/TemplateButtons.svelte | 49 ++++- .../editor-toolbar/TextColorButton.svelte | 15 +- .../editor-toolbar/WithColorHelper.svelte | 3 +- .../mathjax-overlay/MathjaxHandle.svelte | 4 +- .../plain-text-input/PlainTextInput.svelte | 6 +- .../rich-text-input/RichTextInput.svelte | 49 ++--- ts/editor/surround.ts | 59 +++++- ts/lib/runtime-require.ts | 1 + ts/lib/typing.ts | 2 + ts/sveltelib/{mirror-dom.ts => dom-mirror.ts} | 4 +- ts/sveltelib/export-runtime.ts | 2 + ts/sveltelib/handler-list.ts | 165 ++++++++++++++++ ts/sveltelib/input-handler.ts | 112 +++++++++++ ts/sveltelib/input-manager.ts | 176 ------------------ 22 files changed, 574 insertions(+), 373 deletions(-) rename ts/{components => editor/editor-toolbar}/ColorPicker.svelte (56%) rename ts/sveltelib/{mirror-dom.ts => dom-mirror.ts} (98%) create mode 100644 ts/sveltelib/handler-list.ts create mode 100644 ts/sveltelib/input-handler.ts delete mode 100644 ts/sveltelib/input-manager.ts 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