ckeditor / ckeditor5

Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing.
https://ckeditor.com/ckeditor-5
Other
9.45k stars 3.7k forks source link

Change the order/flow of events fired by the DowncastDispatcher #10376

Closed niegowski closed 3 years ago

niegowski commented 3 years ago

Provide a description of the task

Currently DowncastDispatcher is firing events for the inserted range by walking on the range with TreeWalker so for the provided structure:

<x foo="bar">
    <y bar="123" baz="abc">
        foobar
    </y>
</x>

It fires events like a flat sequence:

insert:x
attribute:foo:x
insert:y
attribute:bar:y
attribute:baz:y
insert:$text

but if any of the elements' converter uses slots (and with this triggers conversion of nested element) the flow becomes mixed:

insert:x
    insert:y
    attribute:bar:y
    attribute:baz:y
    insert:$text
attribute:foo:x

The x element is triggering its children's conversion by using slots. This makes the order of events different, the flow becomes partly recursive (for the insert:x). This could be a complication hard to understand for developers. Also with a flat sequence of events, there is no way to listen on the whole element with children got converted (that could be useful for side effects that could listen on a low priority to notice when that conversion is completed).

In the UpcastDispatcher the flow is different, it's always recursive - there is the lowest priority listener that triggers nested nodes conversion (and also many converters can trigger it if appropriate).

I propose to align the DowncastDispatcher to the same recursive flow as it's used in the UpcastDispatcher so the sequence of events would look like this:

insert:x
    insert:y
        insert:$text
    attribute:bar:y
    attribute:baz:y
attribute:foo:x

or maybe even to:

insert:x
    attribute:foo:x
    insert:y
        attribute:bar:y
        attribute:baz:y
        insert:$text

by introducing nested trigger for attributes conversion (sth similar to conversionApi.convertInsert()). This way the order of events will be exactly the same but conversion of attributes and child nodes would be nested (on the call stack) inside the parent insert event handler.

Reinmar commented 3 years ago

Notes from a f2f meeting:

Existing features (also 3rd-party) that hook in downcast events on different priorities could break if we touch anything.

Approach A: Some features may assume that parent's (x) attributes have been converted before converting a child (y). If we go with the following order, this will break:

insert:x
    insert:y
        insert:$text
    attribute:bar:y
    attribute:baz:y
attribute:foo:x

Approach B: The following looks safer than 👆 because conversion for y will know about attributes of x. There's some downside to this: listeners on low priority for x may break because children would be converted before they get a chance to act.

insert:x
    attribute:foo:x
    insert:y
        attribute:bar:y
        attribute:baz:y
        insert:$text