mobiledoc-kit
mobiledoc-kit copied to clipboard
Input on android and IME has a bug when typing first char
Android:
When inserting text in the editor, after the first char the cursor moves back to start of editor area (instead than remaining after the inserted char), and after inserting another char the first char is duplicated.
the cursor is shown like '|' the area delimiter is '<<' and '>>'
bug :
- text area: <<>>
- action: <press char 'a'>
- text area: <<|A>>
- action: <press char 'b'>
- text area: <<Ab|A>> .. and so on
Hint: tracking the event 'cursorDidChange' I have seen that on Android this happen once more than on PC browser when the editor area is empty and you type the first charkey.
I've observed the same bug pointing my android chrome or android firefox browser to http://bustle.github.io/mobiledoc-kit/demo/ as well as in our app. Its severe enough to make it borderline unusable. Any ideas on how to fix?
@raycohen Thanks for the reproduction.
@raycohen and @part145pro Thanks for raising this issue. Does this screengrab from an emulator accurately show what you are seeing? I notice a few issues related to selection, and it seems that after the first character that I type, the remaining characters seems to function ok. I agree that this should be fixed, though. (The text I typed is "a" then "b" then "c").
@bantic Yes, that screengrab matches the behavior I get in Chrome on a Pixel 2.
Firefox on android is definitely less important to us, but it has an additional quirk - the first keypress 'a' - gets swallowed and nothing appears. So if you type a b c d
you'd end up seeing cd[cursor]b
, and the cursor would only initially appear after pressing a
.
I've been looking at this a bit. What I've dug up so far:
- First off Chrome for Android does not trigger
keypress
: https://bugs.chromium.org/p/chromium/issues/detail?id=118639 This is intentional. There is no key being pressed, I believe is the logic.keyCode
values are also not present onkeyup
andkeydown
. Key codes pertain to keys pressed on a physical keyboard, and again there is no physical keyboard. - Mobiledoc-kit uses
keypress
to recognize general input: https://github.com/bustle/mobiledoc-kit/blob/master/src/js/editor/event-manager.js#L138 If a key press event has a "printable" key code, one that would result in a character being added, we skip the prevent the default handler and add the character to the editor at the current cursor position. Then the event for the keypress is cancelled. - However Mobiledoc also has a fallback mechanism for recognizing input that doesn't use the keyboard. The most common example might be right clicking on a misspelled word and choosing a new spelling. This replaces content without a keypress. To recognize this, we use a mutation observer to re-parse any parts of the document HTML that has possibly changed. This is less efficient than adding the single character directly.
- Chrome for Android is following this second "reparse" code path for all inputs. We have some issue in this re-parsing code that is causing the bad behavior when starting with an empty wrapper element.
- A note: We're not using the
input
event instead ofkeyPress
because it does not trigger for contenteditable divs on IE11. I'd be open to the idea of dropping IE11 support, but after a 1.0 release.
I'll continue diving in here. One debugging approach I've found useful is simply to stop listening for the keyPress
event entirely. That makes reproducing a variant of the issue without an emulator straightforward. Desktop Chrome's built-in device emulation is not sufficient for emulating the unique event behaviors in Chrome for Android.
We've had a user report a similar sounding problem when typing Korean but this is on desktop rather than Android. I'm assuming this is related to this issue?
We have some issue in this re-parsing code that is causing the bad behavior when starting with an empty wrapper element.
Demo:
@mixonic
I'll continue diving in here. One debugging approach I've found useful is simply to stop listening for the keyPress event entirely.
I try to stop listening for the keyPress
event entirely, and add preventDefault()
to keyup/keydown
listener, but the editor still can input if using a IME.
Could you explain more detail about how the editor handle user input? I'm trying to find the root of IME input issue.
According to this: http://blog.evanyou.me/2014/01/03/composition-event/
The way IME composition works is that it buffers the user’s keystrokes until a character/word selection has been made, finalizing the input. The buffered keystrokes are temporarily displayed, but not actually inserted into the DOM. However, when I change the input field’s value during a composition, the composition gets terminated early and these buffered keystrokes get inserted into the input field.
I think the paragraph's value is changed during a composition, so only got first letter.
any progress on this bug?
I raised a pull request https://github.com/TryGhost/mobiledoc-kit/pull/11 which fixed this problem, works quite well on my Chrome on Mac OS, but on Safari, there is still a problem, I have no time to fix for it.
I'm experiencing this in Chrome for Android (Pixel 7, US English), so unfortunately this is still a problem in 2023. I love love love mobiledoc-kit but this is unfortunately a showstopper for my app :-(
In the discussion above, @mixonic stated this:
A note: We're not using the input event instead of keyPress because it does not trigger for contenteditable divs on IE11. I'd be open to the idea of dropping IE11 support, but after a 1.0 release.
At this point, I would suggest that it's quite safe to drop IE11 support, and that supporting Chrome for Android is far more important. How much work is involved in switching the code to use input events?