Typing in empty block element may cause inserting new text after the empty block on Android
Categories
(Core :: DOM: Editor, defect, P3)
Tracking
()
People
(Reporter: kbrosnan, Assigned: masayuki)
References
(Blocks 1 open bug, )
Details
Attachments
(1 file)
From github: https://github.com/mozilla-mobile/fenix/issues/27569.
Steps to reproduce
- Have the following HTML:
<div contenteditable="true"> <div style="width:20px; height: 20px; border: solid"></div> </div>
- Click/tap on the box
- Type a character
Expected behaviour
In Firefox desktop, Chrome desktop, and Chrome for Android, the typed character is inserted in the child div. This is the behaviour I would expect.
Actual behaviour
The typed character is inserted after the child div.
Device name
Fairphone 4
Android version
Android 11
Firefox release type
Firefox
Firefox version
106.1.0
Device logs
No logs are produced.
Additional information
I originally found this issue when testing a
contenteditablethat listens tobeforeinputevents to provide some custom behaviour. In other browsers (including Firefox for desktop)event.getTargetRanges()returns a range pointing at the child div, whereas Fenix returns a range that points at the parent div. I assume this inconsistency is related.┆Issue is synchronized with this Jira Task
Change performed by the Move to Bugzilla add-on.
Updated•3 years ago
|
Updated•3 years ago
|
Comment 2•3 years ago
|
||
Correcting the component from triage. I think this is a core bug.
I reproduced this locally as well in 111 nightly.
Updated•3 years ago
|
| Assignee | ||
Comment 3•3 years ago
|
||
It's a long-standing bug (I'm not sure whether there is an older bug report). And web apps can avoid this with putting <br> into the empty <div> etc, and that is required for making it visible because truly empty blocks are 0-height.
| Assignee | ||
Comment 4•3 years ago
|
||
Oh, but I cannot reproduce this bug in desktop, so this is different bug what I was thinking. I guess that IME on Android collapse Selection into the invisible text node and insert text there.
| Assignee | ||
Comment 5•3 years ago
|
||
I guess that invisible text node should be ignored in ContentEventHandler, i.e., IME won't see them and be able to put caret into it. On the other hand, I'm not sure why IME wants to put caret before a line break which is caused by open tag of the empty <div> element. I need to get the log of composition first.
| Assignee | ||
Updated•3 years ago
|
| Assignee | ||
Updated•3 years ago
|
| Assignee | ||
Comment 6•3 years ago
|
||
The log:
[Child 2304: Main Thread]: D/GeckoEditableSupport IME: IME_REPLACE_TEXT: text="M"
[Child 2304: Main Thread]: D/GeckoEditableSupport IME: Current selection: { mOffset=4, mData="" (Length()=0), Length()=0, EndOffset()=4 }
[Child 2304: Main Thread]: D/GeckoEditableSupport IME: NOTIFY_IME_OF_TEXT_CHANGE: TextChangeData={ mStartOffset=4, mRemoveEndOffset=5, mAddedEndOffset=5, mCausedOnlyByComposition=true, mIncludingChangesDuringComposition=false, mIncludingChangesWithoutComposition=false }
[Child 2304: Main Thread]: D/GeckoEditableSupport IME: NOTIFY_IME_OF_SELECTION_CHANGE: SelectionChangeData={ mOffset=5, mString="" (Length()=0), GetWritingMode()=h-ltr, mReversed=false, mCausedByComposition=true, mCausedBySelectionEvent=false, mOccurredDuringComposition=true }
[Child 2304: Main Thread]: D/GeckoEditableSupport IME: NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED
Odd, it's expected result, but indeed the character is inserted after the <div>. (there are one line break and 2 white-spaces (i.e., 3 characters) before the <div>, and a line break should be inserted after it. Therefore, mOffset=4 is correct. So, this is a bug in XP level code.
| Assignee | ||
Comment 7•3 years ago
|
||
At first beforeinput, getTargetRanges returns "adjusted" range.
beforeinput
target: <div contenteditable>, isComposing: true, inputType: "insertCompositionText", data: "m", dataTransfer: (null), getTargetRanges: [{ (<div id="editor">, 2) }]
However, Selection immediately before typing text is collapsed in the inner <div>...
| Assignee | ||
Comment 8•3 years ago
|
||
Hmm, before EditorBase::OnCompositionStart, Selection was "adjusted" to outside of the empty <div>.
TYLin: Do you have any ideas where updates Selection only in Android in this case?
| Assignee | ||
Comment 9•3 years ago
|
||
Ah, perhaps, I got it.
GeckoEditableSupport tries to set selection even if offset/length is not beeing changed. Then, if the selection is collapsed in an empty block, ContentEventHandler reaches here. Then, it's set to after the empty block. This matches with the symptom.
So I believe that ContentEventHandler should replace block element close tags with line breaks to make the eSetSelection event users possible to distinguish whether before or after a block element close tag.
However, this won't fix similar edge cases aound inline element boundaries, and it requires big changes. Therefore, I think that we should just make GeckoEditableSupport stop setting Selection if the range is same as current one.
| Assignee | ||
Updated•3 years ago
|
Comment 10•3 years ago
|
||
TYLin: Do you have any ideas where updates Selection only in Android in this case?
I'm not familiar with the relevant code you linked in comment 9, so I'm glad you figure it out :)
Comment 11•3 years ago
|
||
Thanks for looking into this, looking forward to seeing it fixed!
In the meantime (and for supporting older Firefox versions) is there a bit of JavaScript to detect whether this bug is in play? I have a JS-disabled fallback I'd like to use if this bug is in play, but I don't know if there is an easy way to detect it. I guess using the user agent would work, but maybe during your investigations you've found something else?
| Assignee | ||
Comment 12•3 years ago
|
||
ContentEventHandler may not replace open/close tags of inline elements and
close tags of block elements with a line break etc. Therefore, one offset may
mean multiple points in the DOM tree. From the DOM tree point of view, every
DOM point may have different meaning and styles. Therefore, if IME sets
Selection to current range, we should not update Selection with the log of
ContentEventHandler. Otherwise, new content will appear at different position
in the DOM tree and it may cause different style text, etc.
IMEContentObserver has cache of Selection while an editor has focus.
Therefore, for avoiding the query cost of Selection for each eSetSelection
event, ContentEventHandler should be used in IMEContentObserver instead if
an instance is available. Therefore, this patch makes TextComposition
delegate the handling to IMEContentObserver and check Selection range only
when IMEContentObserver is available. Note that eSetSelection is probably
used only when editable element has focus. Therefore, it must be fine to skip
selection range check in the other cases.
| Assignee | ||
Comment 13•3 years ago
|
||
(In reply to graham from comment #11)
In the meantime (and for supporting older Firefox versions) is there a bit of JavaScript to detect whether this bug is in play?
Unfortunately, this is a simple bug of IME handling in the case of that IME resets caret position by itself. Therefore, without UA checks, I guess that this could be detectable with checking Selection in compositionstart event listener or at first compositionupdate event. However, I'm not sure whether it works as you expected if you change Selection at these timings.
Comment 14•3 years ago
|
||
Comment 15•3 years ago
|
||
| bugherder | ||
Updated•3 years ago
|
Description
•