If you ever tried to create a dynamic UI inside of <anki-editable>
with Anki’s new editor (2.1.50+), you probably realised that the editor will make quick work of your fancy interface by turning it into static HTML as soon as it detects HTML changes. Reason: The editable (RichTextInput
) bidirectionally syncs with the HTML editor (PlainTextInput
), refreshing the whole innerHTML
of the element and therefore removing any attached EventListeners
and other goodies in the process.
Example
I’ll take my add-on Tippy Tooltips as an example.
Altough it seems like the perfect match for a custom Svelte component, abovementioned restriction forced me to use a rather hacky method to live-update <anki-editable>
on input:
// The current tooltip anchor inside <anki-editable>
// is marked with the attribute [active],
// so I know which anchor to sync the changes to.
instance.input.addEventListener("input", (e) => {
editable.querySelector(
"a[data-tippy-content][active]",
).dataset.tippyContent = e.target.innerHTML;
});
Official API Solution
Today after a deliberate search, I have found @hengiesel has (like so many times) thought about this problem a long time ago and made it possible to decouple PlainTextInput
from RichTextInput
with the function preventResubscription
that’s exported with RichTextInputAPI
.
(Here @hkr described how to access that API: CSS Injector [Official Support] - #54 by hkr)
console.log(richTextInputApi.preventResubscription())
// output
// () => {
// allowResubscription.set(true);
// }
As you can see, the function returns another function that can be used to recouple PlainTextInput
with RichTextInput
again.
What are the implications?
This means you can build a dynamic UI (e.g. with a framework like Svelte) inside Anki’s fields and it will actually work.
I hope some of you will find this information useful and create wonderful things with it!