Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Use Selection.prototype.containsNode for better caret tracking #1442

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

tuespetre
Copy link

There are a lot of open issues so I am not sure what issues if any this would close, but here is what I've got:

Chrome
Always fires focus before selectionchange
Edge
Always fires focus before selectionchange
IE
Always fires focus after selectionchange
Firefox
Fires focus after selectionchange when focus was not in the document
Fires focus after selectionchange when the caret is placed after all nodes in the editor
Fires focus before selectionchange otherwise

The SelectionObserver was checking whether or not the editor was focused and using that to decide whether or not it could skip firing the selectionChange event for the Document. But thanks to the last two browsers on that list, we cannot actually be sure if the selectionchange DOM event is irrelevant just by checking whether we have focus. This pull request instead checks whether the resulting DOM selection includes all or part of the editor element, resulting in a better experience in Firefox and IE. Otherwise, every time you click back into the editor, your caret jumps back to where it was the last time the editor had focus. 👎

@coveralls
Copy link

Coverage Status

Coverage remained the same at 100.0% when pulling 87d4678 on tuespetre:master into ec70448 on ckeditor:master.

@Reinmar
Copy link
Member

Reinmar commented Jun 25, 2018

Hi! Thanks for the PR! And congratulations for digging this up cause I think it's the first time I've seen a contribution touching such a system :)

I think that this issue sums it up: ckeditor/ckeditor5#734

I've been reading the current implementation of the SelectionObserver and I don't understand why we abort when the editable has no focus. This seems unnecessary. Or rather – imprecise.

I'd try to decouple these two pieces of state (focus and selection) as much as possible. So, it seems that you chose the right direction.

Why do we need a check at all? It's because we listen to selectionchange on the entire document. Which means that selections made outside the editor will trigger the SelectionObserver. We need to filter them out.

I'm not sure, though, if your proposal is correct:

if ( !domSelection.containsNode( domElement, true ) ) {
    return;
}

Demo: https://jsfiddle.net/1948yv6j/5/

Fails when:

image

I'd rather check whether selection.anchorNode and selection.focusNode are both inside the editable element. So sth like:

domElement.contains( selection.anchorNode ) && domElement.contains( selection.focusNode ) 

It should check fine whether the entire selection is contained within the editor. Demo: https://jsfiddle.net/1948yv6j/8/

I'd check both selection ends because I'm afraid that some browsers may allow making a selection which starts outside and ends inside a contentEditable element. Especially that we need to consider the read-only mode.

WDYT about this?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants