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> Hikaru Yoshiga <github.com/hikaru-y>
Thore Tyborski <github.com/ThoreBor> Thore Tyborski <github.com/ThoreBor>
Alexander Giorev <alex.giorev@gmail.com> 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});") self.web.eval(f"pasteHTML({json.dumps(html)}, {json.dumps(internal)}, {ext});")
gui_hooks.editor_did_paste(self, html, internal, extended) 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: def pasteIfField(ret: bool) -> None:
if ret: if ret:
self.doPaste(html, internal, extended) self.doPaste(html, internal, extended)
p = self.web.mapFromGlobal(QCursor.pos()) self.web.evalWithCallback(
self.web.evalWithCallback(f"focusIfField({p.x()}, {p.y()});", pasteIfField) f"focusIfField({cursor_pos.x()}, {cursor_pos.y()});", pasteIfField
)
def onPaste(self) -> None: def onPaste(self) -> None:
self.web.onPaste() self.web.onPaste()
@ -1138,30 +1141,39 @@ class EditorWebView(AnkiWebView):
def dropEvent(self, evt: QDropEvent) -> None: def dropEvent(self, evt: QDropEvent) -> None:
extended = self._wantsExtendedPaste() extended = self._wantsExtendedPaste()
mime = evt.mimeData() mime = evt.mimeData()
cursor_pos = self.mapFromGlobal(QCursor.pos())
if evt.source() and mime.hasHtml(): if evt.source() and mime.hasHtml():
# don't filter html from other fields # don't filter html from other fields
html, internal = mime.html(), True html, internal = mime.html(), True
else: else:
html, internal = self._processMime(mime, extended) html, internal = self._processMime(mime, extended, drop_event=True)
if not html: if not html:
return return
self.editor.doDrop(html, internal, extended) self.editor.doDrop(html, internal, extended, cursor_pos)
# returns (html, isInternal) # 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" % ( # print("html=%s image=%s urls=%s txt=%s" % (
# mime.hasHtml(), mime.hasImage(), mime.hasUrls(), mime.hasText())) # mime.hasHtml(), mime.hasImage(), mime.hasUrls(), mime.hasText()))
# print("html", mime.html()) # print("html", mime.html())
# print("urls", mime.urls()) # print("urls", mime.urls())
# print("text", mime.text()) # 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 # try various content types in turn
html, internal = self._processHtml(mime) if mime.hasHtml():
if html: html_content = mime.html()[11:] if internal else mime.html()
return html, internal return html_content, internal
# favour url if it's a local link # favour url if it's a local link
if mime.hasUrls() and mime.urls()[0].toString().startswith("file://"): if mime.hasUrls() and mime.urls()[0].toString().startswith("file://"):
@ -1227,17 +1239,6 @@ class EditorWebView(AnkiWebView):
processed.pop() processed.pop()
return "".join(processed) 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]: def _processImage(self, mime: QMimeData, extended: bool = False) -> Optional[str]:
if not mime.hasImage(): if not mime.hasImage():
return None return None

View file

@ -29,7 +29,7 @@ from anki.decks import DeckDict, DeckConfigDict
from anki.hooks import runFilter, runHook from anki.hooks import runFilter, runHook
from anki.models import NotetypeDict from anki.models import NotetypeDict
from anki.collection import OpChangesAfterUndo 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.tagedit import TagEdit
from aqt.undo import UndoActionsInfo 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.""", 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 # Tag
################### ###################
Hook(name="tag_editor_did_process_key", args=["tag_edit: TagEdit", "evt: QEvent"]), Hook(name="tag_editor_did_process_key", args=["tag_edit: TagEdit", "evt: QEvent"]),