Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested contenteditables + comment markers make page jumps #4412

Closed
ma2ciek opened this issue Sep 6, 2018 · 9 comments · Fixed by ckeditor/ckeditor5-engine#1535
Closed

Nested contenteditables + comment markers make page jumps #4412

ma2ciek opened this issue Sep 6, 2018 · 9 comments · Fixed by ckeditor/ckeditor5-engine#1535
Labels
package:engine type:bug This issue reports a buggy (incorrect) behavior.
Milestone

Comments

@ma2ciek
Copy link
Contributor

ma2ciek commented Sep 6, 2018

How to reproduce?

  1. Create an image
  2. Write some text in its caption
  3. Create a comment to the caption
  4. Scroll down the page.
  5. Select text in the caption
  6. Select text in the main content editable element

Current behavior:
Scroll jumps to the top.

Additional info
Reproducible on Chrome, Safari
The same happens with table cells.

I've tried to debug it with @oskarwrobel and here are our thoughts:

Clicking the marker makes the comment's contenteditable active and triggers its rendering. Then Clicking outside of it, makes it inactive, rerenders the comment and rerenders the main content editable element. It triggers two times https://github.com/ckeditor/ckeditor5-engine/blob/5c0a34d6f277fed063d8ed40af5b8ebda4690e14/src/view/renderer.js#L756
which probably doesn't find the selection in the editor for the second time, thus it creates a selection for a while at the top of the editor and scrolls to it.

Possible solutions:

WDYT?
cc @pjasiun @Reinmar

@oskarwrobel
Copy link
Contributor

Clicking the marker makes the comment's contenteditable active and triggers its rendering. Then Clicking outside of it, makes it inactive, rerenders the comment and rerenders the main content editable element.

I think It has nothing to do with comment contenteditable. When clicking the marker inside nested contenteditable then 3 things happen at the same time:

  • selection update
  • focus update
  • marker re-render (from inactive to active)

I guess something is happening (selection or focus update) while marker's span update and the target element is not present in the DOM.

@oskarwrobel
Copy link
Contributor

Switch these two lines by @oskarwrobel. Not sure if it doesn't break something else.

It's just a quick shoot. I haven't debugged it deeply.

@jodator
Copy link
Contributor

jodator commented Sep 6, 2018

Hi guys... I had similar problem while creating a custom selection for tables (block selection). I set selection in model and I neeed to stop selection rendering then to not make selection flicker.

I've added simple switch:

// TODO: Add temporary solution to pausing selection rendering.
if ( this.renderSelection ) {
	this._updateSelection();
	this._updateFocus();
}

and I use it to pause selection rendering during block selection.

Without pausing something (the DOM?) was interferring with model selection and the whole thing doesn't worked well.

@jodator
Copy link
Contributor

jodator commented Sep 6, 2018

Compare:

  1. as on mater

tebel_sel_without

  1. with "off" switch

tebel_sel_with

ps.: The table feature pauses selection rendering while in block mode.

@pjasiun
Copy link

pjasiun commented Sep 6, 2018

I think that the guilty line is: https://github.com/ckeditor/ckeditor5-engine/blob/5c0a34d6f277fed063d8ed40af5b8ebda4690e14/src/view/renderer.js#L756 (as you mentioned before). It updates focus on the "selection update" part of the rendering in a very naive way (note that we update focus in the "focus update" part in a much more complex way, including checking isFocused and saving the scroll position). If you remove this line, everything works well. But, of course, since it is some FF hack we cannot remove it just like this.

When I started logging renderer.isFocused and domRoot (used in the code linked above) I get interesting results:

screen shot 2018-09-06 at 18 15 05

When I click on the comment in table editor, lose focus for a while and use global contenteditable a the domRoot and focus it. This is when the editor jump. So the real question here is: why editor lose focus?

@pjasiun
Copy link

pjasiun commented Sep 6, 2018

Also, I think that @jodator case in not related to this issue. But as long as we will not solve both I will not be sure.

@pjasiun
Copy link

pjasiun commented Sep 7, 2018

So, with @Reinmar we were able to debug this problem. The flow is like this:

  • user changes the selection in the DOM,
  • new selection (in the marker) is converted to the model,
  • comments markers plugin test if the selection is in a comment, changes the active marker and ask for rendering this change (note that we downcast changes first and the selection later, so at this point model selection is not yet converted back to the view),
  • renderer render change.

At this point:

  • DOM selection is already moved to the nested editable,
  • model selection is in the comment in the nested editable,
  • view selection is still in the main editable.

Then this code is executed: https://github.com/ckeditor/ckeditor5-engine/blob/5c0a34d6f277fed063d8ed40af5b8ebda4690e14/src/view/renderer.js#L739-L756

It takes the selection from view, asks for the corresponding DOM element and tries to focus it. However, because the view has an old selection it returns wrong editable element (main one) in which there is no DOM selection (because the selection is already in the nested editable). Focusing element with no selection cases page jump. TADAM!

@ma2ciek ma2ciek changed the title Nested contenteditables + comment markers make scroll jumps Nested contenteditables + comment markers make page jumps Sep 7, 2018
@pjasiun
Copy link

pjasiun commented Sep 7, 2018

I pushed the proposal of the fix to t/1528.

If prevent rendering when the user is in the model change block.

On the one hand, this is something I was thinking about for a long time. On the other, there is a reason we delayed this change for that long. It is ugly and makes "big look" logic even more complex.

@Reinmar
Copy link
Member

Reinmar commented Sep 7, 2018

I'm ok with that change. Maybe not the code itself (that flag should be protected (for now), there's a code style issue and fire() is called with unnecessary param), but the idea is good. We need a way to wrap multiple view.change() blocks in one "transaction" to avoid intermediate rendering. Right now we can have a protected API for that and only we'll use it, so we can revert it at any time. But if we'll prove that it's the right direction we can open it.

Reinmar referenced this issue in ckeditor/ckeditor5-engine Sep 10, 2018
Internal: Prevent rendering when in the `model.change()` or `model.enqueueChange()` block. Closes #1528.
Reinmar referenced this issue in ckeditor/ckeditor5-engine Sep 10, 2018
@mlewand mlewand transferred this issue from ckeditor/ckeditor5-engine Oct 9, 2019
@mlewand mlewand added this to the iteration 20 milestone Oct 9, 2019
@mlewand mlewand added status:confirmed type:bug This issue reports a buggy (incorrect) behavior. package:engine labels Oct 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package:engine type:bug This issue reports a buggy (incorrect) behavior.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants