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
Chrome 61+ unreliable cursor position after replaceWith() #710
Comments
This doesn't appear to be happening on Chrome 61 Linux. But maybe I have a different version (61 is currently unstable on Linux). Which platform did you test on? |
Osx. Tried version 61 and 62, Safari and latest public FF.
|
Reproduced on Chromium Version 61.0.3163.100 (Build de développement) built on Debian buster/sid, running on Debian buster/sid (64 bits). |
I can reproduce this now. When it happens, the cursor position that the browser is displaying does not correspond to the cursor position that it is reporting—it claims that the cursor is at offset 2 in the paragraph node, but the cursor is blinking (and typing happens) directly after the custom node (which would be offset 1). So this seems to be a browser bug. Then the question is whether we can work around it. That test you show, which prevents DOM selection updates when the DOM selection is already where it should be, isn't just an optimization—it is critical to avoid disrupting spell checking, horizontal position during vertical motion, and other pieces of hidden selection state. So we can't just turn it off. |
I've reproduced this outside of ProseMirror with the following code: <!doctype html><meta charset="utf-8">
<div contentEditable=true style="white-space: pre-wrap"><p>a</p></div>
<button onmousedown="runTest(); return false">Click</button>
<script>
let p = document.querySelector("p")
// Set the selection to the last index in the paragraph
let s = getSelection(), r = document.createRange()
r.setEnd(p, 1)
r.setStart(p, 1)
s.removeAllRanges()
s.addRange(r)
function runTest() {
p.insertBefore(document.createTextNode("x"), p.firstChild)
console.log("Selection is now supposedly at:", getSelection().anchorNode, getSelection().anchorOffset)
}
</script> |
Reported as https://bugs.chromium.org/p/chromium/issues/detail?id=775939 Found that it doesn't happen when the selection is inside of a text node, rather than at the top of the paragraph, but there's no way to ensure that without causing the aforementioned selection reset issues. |
Thanks for looking into that. I understand the limitations... |
If you have specific code that's typically running when the problem happens, you could, until the Chrome bug is fixed, add a kludge that resets the DOM selection—moving it into a nearby text node should prevent the issue from occurring. |
I've tested a few approaches, but decided on one of the simplest: // prepare transaction with the content insertion
const tr = state.tr.replaceWith(start, end, nodes);
// do this right before we dispatch PM transaction
if (isChromeWithSelectionBug) {
document.getSelection().empty();
}
// now viewdesc will have to re-apply selection putting it in the right spot
view.dispatch(tr); I do it conservatively for the identified use-cases when we inject inline block nodes into document, so that we don't interfere with spellcheckers in all other cases. |
Interesting is that comment here is saying that workaround should not work. |
FIX: Work around a Chrome bug where programmatic changes near the cursor sometimes cause the visible and reported selection to disagree. Issue ProseMirror/prosemirror#710
Attached patch tries to kludge around this. It's super-ugly, but covers this case and hopefully most other related ones. In case anyone wants to test it, I'm going to hold off releasing it a few more days. |
Issue details
With Chrome v 61 and up, there's a new glitch with cursor positions.
tr.replaceWith()
transaction on a document with 1 node.[ customInlineNode, text(" ") ]
state.selection.$anchor.pos === 3
which is correct.Steps to reproduce
https://chrome-selection-offsets-glitch.glitch.me
Please specify which version of ProseMirror you're running
ProseMirror v[ 0.24 ]
Affected platforms
Screenshots / Screencast (Optional)
Investigation
The critical part is in
prosemirror-view/src/viewdesc.js
:The value of
domSel
in the same moment in time is:{anchorNode: <p>, anchorOffset: 1, focusNode: <p>, focusOffset: 1, isCollapsed: true, …}
{anchorNode: p, anchorOffset: 2, focusNode: p, focusOffset: 2, isCollapsed: true, ...}
Chrome will return early at the
isEquivalentPosition()
condition, while other browsers will continue to line 371 where this happens:The text was updated successfully, but these errors were encountered: