Selection is moved after removing part of the text on 'compositionend' event in which composition takes place
Reported by
k.krz...@cksource.com,
Mar 8 2018
|
||||||
Issue descriptionUserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36 Steps to reproduce the problem: 1. Create contenteditable element with HTML like `<p>Foo<strong>Bar</strong></p>`. 2. Create a `compositionend` listener attached to editable, which will remove first few characters from `<strong>` text node on composition end. 3. Put caret like `<p>Foo<strong>Bar^</strong></p>`. 4. Start and end composition which will result in inserting some text. If this scenario is not obvious to understand check below codepen in which it can be easily reproduced: https://codepen.io/f1ames/pen/EEYjKg?editors=1010 What is the expected behavior? After removing some characters on `compositionend` event from text node in which selection is present, selection does not change. What went wrong? After removing some characters on `compositionend` event from text node in which selection is present, selection moves right (by the same amount of characters which was removed). Did this work before? N/A Does this work in other browsers? Yes Chrome version: 64.0.3282.167 Channel: stable OS Version: OS X 10.11.6 Flash Version: ## Observations When text data is removed via `CharacterData.replaceData` or `CharacterData.deleteData` it works in other browsers (FF, Safari) and selection is not moved, but fails, as described, in Chrome. When text is removed by replacing whole text node data like `textNode.data = textNode.data.substr( 7 );` it fails on Chrome as described above. In other browsers selection is moved to the beginning of the text node. Deferring (`setTimeout( ..., 0 )`) the text removal inside `compositionend` listener, results in Chrome behaving like other browsers using `textNode.data = textNode.data.substr( 7 );` - selection moves to the beginning of the text node. Selection movement looks async, manually setting selection after text removal has no effect. When instead of `compositionend`, listening to `keyup` (so just plain typing), Chrome moves selection to the beginning of text node when using `textNode.data = textNode.data.substr( 7 );` and works fine with `CharacterData.*` methods. The original issue is related to removing zero-width spaces from text node after composition ends, however it seems it also happens with printable characters.
,
Mar 9 2018
,
Mar 9 2018
Thanks for filing the issue! @Reporter: As per comment#1 could you please check the same issue on upcoming latest stable version where issue seems to be fixed and let us know it's behaviour. From crbug.com/737395 cc'ing "rlanday".
,
Mar 9 2018
That's great news! Checked on newest Chrome (Version 65.0.3325.146 (Official Build) (64-bit)) and yes, it is fixed (for cases mentioned in original description), but only partially. I still found 3 cases in which it can be reproduced, the set up is the same, but now listening and removing characters on `compositionstart/update` (check attached gifs showing how it behaves with Spanish accent and macOS accent panel) it is still reproducible. The above is, let's say, not that big issue, since with this events you know composition takes place so it is easier to determine if text node can be manipulated, still an issue IMHO. However, there is a serious issue with macOS accent panel. When listening to and manipulating text node on `keyup` (which in case of accent panel may be called before composition events so you are unable to determine that composition will take place), the caret looks like it is not moved, but character in composition is inserted in the wrong place (check out the 3rd attached gif and codepen - https://codepen.io/f1ames/pen/pLoyrM?editors=1010).
,
Mar 9 2018
Thank you for providing more feedback. Adding the requester to the cc list. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Mar 9 2018
compositionstart and compositionupdate are fired before we actually perform the DOM edit requested by the IME. So if you change the text in that time frame, you’re kind of asking for trouble since the IME’s about to perform an edit but you’ve just changed the text it’s expecting. Performing edits in response to input or compositionend should be safe as of M65. I’m having a hard time reproducing the behavior you’re describing on macOS. I think keyup is fired *after* compositionupdate in every scenario I’ve tested: https://w3c.github.io/uievents/tools/key-event-viewer.html Can you please provide more detail? What you’re describing though seems to be the result of an implementation detail with how composition edits are implemented. When an IME wants to change the text in the current composition, we first select the composition range, then let the IME overwrite it, then take this new selection range and convert it back to a composition range. I’m not sure it’s safe to change this since some developers apparently depend on this behavior to get the composition range (see discussion on https://crbug.com/812674 ).
,
Mar 9 2018
> compositionstart and compositionupdate are fired before we actually perform the DOM edit requested by the IME. So if you change the text in that time frame, you’re kind of asking for trouble since the IME’s about to perform an edit but you’ve just changed the text it’s expecting. I can agree to some extent, but in all cases in this issue the part of the text which is removed does not contain selection. Selection is placed in the part which is not touched so it should be safe. In different scenarios, when you have selection inside text, removing some part of the text before/after does not affect selection in any way I suppose, so why it happens in this case? Plus even for `compositionstart/update` it works fine in Firefox and Safari. As for the third case, te reproduce this scenario you have to press `a` first, then accent panel will appear, the release `a` (this will trigger `keyup`). And the pressing `left/right arrow` will trigger `compositionstart`. I attached two more gifs which shows this behaviour.
,
Mar 9 2018
> I can agree to some extent, but in all cases in this issue the part of the text which is removed does not contain selection. Selection is placed in the part which is not touched so it should be safe. In different scenarios, when you have selection inside text, removing some part of the text before/after does not affect selection in any way I suppose, so why it happens in this case? I told you why it works this way. We could potentially change the implementation, but I’m not sure what the point would really be, and it might break other web apps. You’re essentially moving the composition range when you move the selection. If you move the selection here, the IME is going to overwrite it anyway after it updates the composition, so there’s really no point. > As for the third case, te reproduce this scenario you have to press `a` first, then accent panel will appear, the release `a` (this will trigger `keyup`). And the pressing `left/right arrow` will trigger `compositionstart`. I attached two more gifs which shows this behaviour. It’s not interesting to me that it’s possible to have a keyup event, and then later, have an IME open a composition from a separate action. That’s a fairly trivial observation. From Chrome’s perspective, it should be perfectly safe to change the text in between those two operations. It might possibly confuse the accent panel, but we can’t really do anything about that. Your test case seems messed up in Safari too.
,
Mar 9 2018
When I say “the IME is going to overwrite [the selection] anyway after it updates the composition,” this is because our implementation is heavily influenced by the need to properly support text input on Android. Two of the methods used for inputting text on Android: setComposingText(): https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingText(java.lang.CharSequence,%20int) commitText(); https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#commitText(java.lang.CharSequence,%20int) provide a selection offset together with the new text. So from our perspective, there’s no good way to support changing the selection in the middle of an IME command. You should wait until either the input or compositionend events.
,
Mar 12 2018
Thank you for clarification. So (more or less) the the position where text during/after composition is inserted, is based on text/offset of the node before composition starts (or collected on `compositionstart` event). This makes sense and I agree that fiddling with text/selection in the text node in which composition takes place is asking for trouble. Thanks to `composition*` events is easy to distinguish such situations, so we may prevent any manipulation during composition. This is fine. However, I'm still worried about 3rd case with MacOS accent panel, where removing part of the text on `keyup` which takes place before `compositionstart` (as composition is fired on arrows navigation through panel) also affects the composition as explained in my previous comment. Do you have any thoughts on that? Is it the same case or the cause is different here?
,
Mar 12 2018
I agree it's not ideal, but I think this is between you and Apple. We can't predict in Chrome that the accent panel is going to open any more than you can. I think they're sort of persisting state in a way we can't keep track of.
,
Mar 12 2018
|
||||||
►
Sign in to add a comment |
||||||
Comment 1 by rlanday@chromium.org
, Mar 8 2018