Merge pull request #1356 from tatsumoto-ren/editor_will_process_mime

Add a hook for modifiying pasted MIME data
This commit is contained in:
Damien Elmes 2021-09-06 21:03:37 +10:00 committed by GitHub
commit c9574ec133
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 21 deletions

View file

@ -84,6 +84,7 @@ cherryblossom <github.com/cherryblossom000>
Hikaru Yoshiga <github.com/hikaru-y>
Thore Tyborski <github.com/ThoreBor>
Alexander Giorev <alex.giorev@gmail.com>
Ren Tatsumoto <tatsu@autistici.org>
********************

View file

@ -863,13 +863,16 @@ $editorToolbar.then(({{ toolbar }}) => toolbar.appendGroup({{
self.web.eval(f"pasteHTML({json.dumps(html)}, {json.dumps(internal)}, {ext});")
gui_hooks.editor_did_paste(self, html, internal, extended)
def doDrop(self, html: str, internal: bool, extended: bool = False) -> None:
def doDrop(
self, html: str, internal: bool, extended: bool, cursor_pos: QPoint
) -> None:
def pasteIfField(ret: bool) -> None:
if ret:
self.doPaste(html, internal, extended)
p = self.web.mapFromGlobal(QCursor.pos())
self.web.evalWithCallback(f"focusIfField({p.x()}, {p.y()});", pasteIfField)
self.web.evalWithCallback(
f"focusIfField({cursor_pos.x()}, {cursor_pos.y()});", pasteIfField
)
def onPaste(self) -> None:
self.web.onPaste()
@ -1138,30 +1141,39 @@ class EditorWebView(AnkiWebView):
def dropEvent(self, evt: QDropEvent) -> None:
extended = self._wantsExtendedPaste()
mime = evt.mimeData()
cursor_pos = self.mapFromGlobal(QCursor.pos())
if evt.source() and mime.hasHtml():
# don't filter html from other fields
html, internal = mime.html(), True
else:
html, internal = self._processMime(mime, extended)
html, internal = self._processMime(mime, extended, drop_event=True)
if not html:
return
self.editor.doDrop(html, internal, extended)
self.editor.doDrop(html, internal, extended, cursor_pos)
# returns (html, isInternal)
def _processMime(self, mime: QMimeData, extended: bool = False) -> Tuple[str, bool]:
def _processMime(
self, mime: QMimeData, extended: bool = False, drop_event: bool = False
) -> Tuple[str, bool]:
# print("html=%s image=%s urls=%s txt=%s" % (
# mime.hasHtml(), mime.hasImage(), mime.hasUrls(), mime.hasText()))
# print("html", mime.html())
# print("urls", mime.urls())
# print("text", mime.text())
internal = mime.html().startswith("<!--anki-->")
mime = gui_hooks.editor_will_process_mime(
mime, self, internal, extended, drop_event
)
# try various content types in turn
html, internal = self._processHtml(mime)
if html:
return html, internal
if mime.hasHtml():
html_content = mime.html()[11:] if internal else mime.html()
return html_content, internal
# favour url if it's a local link
if mime.hasUrls() and mime.urls()[0].toString().startswith("file://"):
@ -1227,17 +1239,6 @@ class EditorWebView(AnkiWebView):
processed.pop()
return "".join(processed)
def _processHtml(self, mime: QMimeData) -> Tuple[Optional[str], bool]:
if not mime.hasHtml():
return None, False
html = mime.html()
# no filtering required for internal pastes
if html.startswith("<!--anki-->"):
return html[11:], True
return html, False
def _processImage(self, mime: QMimeData, extended: bool = False) -> Optional[str]:
if not mime.hasImage():
return None

View file

@ -29,7 +29,7 @@ from anki.decks import DeckDict, DeckConfigDict
from anki.hooks import runFilter, runHook
from anki.models import NotetypeDict
from anki.collection import OpChangesAfterUndo
from aqt.qt import QDialog, QEvent, QMenu, QModelIndex, QWidget
from aqt.qt import QDialog, QEvent, QMenu, QModelIndex, QWidget, QMimeData
from aqt.tagedit import TagEdit
from aqt.undo import UndoActionsInfo
"""
@ -864,6 +864,31 @@ gui_hooks.webview_did_inject_style_into_page.append(mytest)
],
doc="""Called after some data is pasted by python into an editor field.""",
),
Hook(
name="editor_will_process_mime",
args=[
"mime: QMimeData",
"editor_web_view: aqt.editor.EditorWebView",
"internal: bool",
"extended: bool",
"drop_event: bool",
],
return_type="QMimeData",
doc="""
Used to modify MIME data stored in the clipboard after a drop or a paste.
Called after the user pastes or drag-and-drops something to Anki
before Anki processes the data.
The function should return a new or existing QMimeData object.
"mime" contains the corresponding QMimeData object.
"internal" indicates whether the drop or paste is performed between Anki fields.
Most likely you want to skip processing if "internal" was set to True.
"extended" indicates whether the user requested an extended paste.
"drop_event" indicates whether the event was triggered by a drag-and-drop
or by a right-click paste.
""",
),
# Tag
###################
Hook(name="tag_editor_did_process_key", args=["tag_edit: TagEdit", "evt: QEvent"]),