Anki Forums

Access to Dom element in EditorField

Hi,

I’m extremely confused and lost. I’m trying to port “Resize image in editor” for the new editor, as @AnKingMed keep asking for, and I’m totally at lost about what’s going on. As he suggested, I’m asking for @hengiesel help or anybody who understand what’s going on here.

I need to access the images in the actual dom element. I know how to access the fields in the note, but that’s the back-end data, what I really need is the representation of the images, so that I can ensure they get resizable with jquery-ui.
However, when I do:

var setFieldsInit = setFields;    
setFields = function(fields) {
    setFieldsInit(fields);
    const fieldsId = document.getElementById("fields");
    console.log(`fieldsId: ${fieldsId.outerHTML}`);
}

the result show empty html, there is not the fields content anymore.
However,

console.log(fieldsId.children[0].editingArea.editable.fieldHTML) 

i correctly see the content of the field. I would have expected it to be the dom element (since fieldHtml actually change innerHTML), but it seems like even if I can manipulate this as dom, with jquery, changing it have no impact. So I feel like I missed something and really would love help to understand what

The fields content is in a shadow root. The shadow root helps with isolating the user’s content from the web view. This way, styles defined for editor elements do not trickle through to the content. You can see this with AnkiWebInspector:

There is no way to access all fields under one descriptor / one element. I’m also not sure jQuery has good support for shadow DOM. However you can also pass raw elements to jquery.

However I’m not sure it’s going to work even then.

EDIT: Does you add-on change the actual size of the image, or does it only resize the picture for the editor window?

2 Likes

It changed the width and height element of omg tag

I had to work with the fields too, and support both, the old and the new implementation.
I did it like that:

cacheFields: function() {

        this._fields = [];
        if (!$('#fields [contenteditable]').length) {
            // 2.1.41+
            let fields = document.querySelectorAll('.field');
            for (let f of fields) {
                this._fields.push(f.shadowRoot.querySelector('anki-editable'));
            }
        } else {
            // - 2.1.40
            this._fields = document.querySelectorAll('.field');
        }
    }
3 Likes

And when you edit the content of this._fields in 2.1.41+, you actually get some dom you can edit, whose change is reflected on screen ? That seems it would answer my question, thank so much

Yes, these are then normal Element objects. I used that function so I don’t have to query the elements everytime I need them (function is called on note loading). If you just need the fields, it can be even shorter I think:

function getFields() {
    if (!$('#fields [contenteditable]').length) {
          return [...document.querySelectorAll('.field')].map((x) => x.shadowRoot.querySelector('anki-editable'));
    } else {
          return document.querySelectorAll('.field')
    }
}

What would be the simplest way to alter the shadow-root styles defined in editable.css? Do I need to write an add-on for that / hack it into an existing one?

To be more specific: I want to edit or override the <u> and <i> styles, which I am now using for Closet pre-template markup instead of classes, because these default tags are more forgiving in the editor (undo, shortcuts etc.).

Example with Image

Here I overwrote the styles within editable.css through the webview inspector (<u> in salmon, <i> in lime and underlined):

@glutanimate’s add-on Customize Editor Stylesheet won’t work for that use case.

@kleinerpirat
There’s this PR which would certainly help you out.

Besides that, you can only access it with add-ons. A somewhat minimal example for the Python part would be load_collapsible_icon_js in Collapsible Fields. Of course, you’d only need the CSS file.

A minimal example for the JS/CSS would be the load function here in load. You’d need to adjust textContent (or load it through a link element with href).

2 Likes

Thanks for taking the time, Henrik! :rocket:
I achieved what I wanted with that load function.

PR looks interesting too :+1: