I programmatically paste content into a note in the Editor (more specifically in the AddCard window).
How can I enable “undo paste” in the AddCard window please?
I use a checkpoint to enable undo’s when calling the addon from the browser window:
def pasteContentIntoBrowser(browser):
mw = browser.mw
mw.checkpoint("paste content into notes") # enables 'undo action'
mw.progress.start()
browser.model.beginReset()
for nid in browser.selectedNotes():
' paste something into note
browser.model.endReset()
mw.requireReset()
mw.progress.finish()
mw.reset()
What would be the equivalent for a call from the Editor / AddCard window?
Below my sample code that does not currently work:
def pasteContentIntoEditor(editor):
mw = editor.mw
mw.checkpoint("paste content into note")
mw.progress.start()
' paste something into note
mw.requireReset()
mw.progress.finish()
editor.parentWindow.onReset()
dae
February 4, 2021, 11:10am
2
Ctrl+z in a field will undo normal edits - no special checkpointing is required.
Hi Damien
Thanks for the reply.
The addon modifies the content of a field:
note[fld] = newvalue
Ctrl+z doesn’t work unfortunately to undo the addon’s action.
Is there another way to change the field’s content that is ”undoable”?
hkr
February 4, 2021, 8:03pm
4
I think there may be an easier way to do that, but you can try the following:
from dataclasses import dataclass
from typing import Optional
import anki
import aqt
FIELDS_HISTORY = "fields history"
@dataclass
class FieldsHistory:
note: Optional[anki.notes.Note] = None
fields: Optional[dict] = None
def clear(self):
self.note = None
self.fields = None
def modify_content(editor: aqt.editor.Editor, fields_history: FieldsHistory) -> None:
fields_history.note = editor.note
fields_history.fields = {k: v for k, v in editor.note.items()}
editor.note.fields[editor.currentField] = "New Value"
if not editor.addMode:
editor.note.flush()
editor.loadNote(focusTo=editor.currentField)
def restore_fields(editor: aqt.editor.Editor, fields_history: FieldsHistory) -> None:
for k, v in fields_history.fields.items():
editor.note[k] = v
if not editor.addMode:
editor.note.flush()
editor.loadNote(focusTo=editor.currentField)
fields_history.clear()
def on_editor_did_init(editor: aqt.editor.Editor) -> None:
fields_history = FieldsHistory()
setattr(editor, FIELDS_HISTORY, fields_history)
def on_editor_will_show_context_menu(
editor_webview: aqt.editor.EditorWebView, menu: aqt.qt.QMenu
) -> None:
editor = editor_webview.editor
fields_history: FieldsHistory = getattr(editor, FIELDS_HISTORY)
if editor.currentField is not None:
menu.addAction("Modify content", lambda: modify_content(editor, fields_history))
if fields_history.fields and (editor.note is fields_history.note):
menu.addAction(
"Undo add-on's action", lambda: restore_fields(editor, fields_history)
)
else:
fields_history.clear()
aqt.gui_hooks.editor_did_init.append(on_editor_did_init)
aqt.gui_hooks.editor_will_show_context_menu.append(on_editor_will_show_context_menu)
This should also work on “Edit Current” and “Browser”.
3 Likes
dae
February 6, 2021, 5:27am
5
If you’re just inserting HTML, you may want to consider inserting it like a paste does, as that should be undoable. A checkpoint won’t work in the add screen, as the note is not written until the user adds it.
1 Like
Thanks for the replies.
Damien’s response enables me to use the built-in “undo” function (ie Ctrl+Z).
So I implemented the following:
import json
def getOrd(note, fname):
return note._fieldOrd(fname)
def sortByFieldOrd(note, contentsByFieldName):
return sorted([(getOrd(note, fname), fcontent) for fname, fcontent in contentsByFieldName.items()])
def pasteFieldsIntoEditor(editor):
note = editor.note
currentFld = editor.currentField
fieldsToUpdate = {
"some field": "new HTML value 1",
"another field": "new HTML value 2"
}
contentsByOrd = sortByFieldOrd(note, fieldsToUpdate)
for ord, fcontent in contentsByOrd:
js = '''
focusField(%d);
document.execCommand("selectall");
setFormat("inserthtml", %s);
''' % (ord, json.dumps(fcontent))
editor.web.eval(js)
# restore focus
if currentFld:
editor.web.eval("focusField(%d)" % currentFld)