Javascript is evaluated asynchronously, so if you need the result of a JS expression you can use ankiwebview’s evalWithCallback().
Although the communication between Python and JS works as intended, I’m clueless how to use the result of a JS call effectively within Python - not with another editor.web.eval(), but as a return value of the Python function.
Scenario
I would like to edit field content before it is saved by Anki (editor_will_munge_html) with a JavaScript function, because it is a lot easier to do with DOM-manipulation rather than raw text editing.
Basic idea (flawed)
def on_munge(txt, editor):
replacement = txt
def callback(value) -> None: # <- asynchronous
replacement = value
editor.web.evalWithCallback(f"SomeObject.munge('{txt}')", callback)
# is there a way to await evalWithCallback
# before returning?
return replacement
I reckon making on_munge async won’t work because it will not be awaited by Anki. Is there an API-solution for this kind of scenario, where you want to await the result of a JS call / assign it to a variable?
Or is there an altogether different way to solve my problem?
I’m also remember breaking my head on something like this.
I came to the conclusion that it’s not possible (which is due to the Qt implementation).
One hacky alternative that would probably work, is getting the prototype of an Editable object, and then overwrite the Editable.prototype.fieldHTML getter. But I think you might already have the better solution.
No big deal. I think doing it without async back- and forth is more performant anyway. In the end I’m glad my laziness didn’t win and I had to step out of my comfort zone.
Beautifulsoup is seriously impressive and covers all my needs. As a bonus, it can pretty-print the output, so it looks nice in the HTML editor (but I guess you’ll soon implement this natively with Prettier?).
It’s not really practical to implement async/await with Qt at the moment. You can’t mutate local function state with a callback, so that state either needs to be captured in a closure that you pass as the callback, or the state needs to be stored in an instance variable, with processing continuing in the callback (eg deckbrowser.py:_renderPage())