Cannot exit links in contenteditable elements, i.e. no way to place caret cursor outside `<a href>` element when there is no editable/navigable content before or after <a href>
Categories
(Core :: DOM: Editor, defect, P3)
Tracking
()
Tracking | Status | |
---|---|---|
firefox86 | --- | fixed |
People
(Reporter: j.swiderski, Assigned: masayuki)
References
(Blocks 1 open bug, )
Details
(Whiteboard: [h2review-noted][Thunderbird painpoint], [wptsync upstream])
Attachments
(10 files)
331 bytes,
text/html
|
Details | |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
48 bytes,
text/x-phabricator-request
|
Details | Review |
User Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0 Build ID: 20170323105023 Steps to reproduce: 1. Use below code on your HTML page and open it in a browser: <div style="margin:20px; border:1px solid black; width:500px;" contenteditable="true"> <p><a href="http://test">http://test</a></p> </div> 2. Click right behind letter "t" and once cursor is blinking, press Space, Right Arrow or Enter or do all of that and then start typing. Actual results: Newly typed text is a link and it seems there is no way of getting out of it. Even if I press enter, new link is created and text is still linked. Expected results: Newly typed text should be a plain text.
Updated•7 years ago
|
Updated•7 years ago
|
Comment 1•7 years ago
|
||
Chrome seems to always position the cursor outside the link when you put it at the border of the link, but inside when it comes to bold (I didn't test other markup). But if you have other text on the line, like abc<b>def</b>ghi, it will position the cursor outside the <b> if you place it before, and inside for after, like abc|<b>def</b>ghi abc<b>def</b>|ghi I vaguely remember testing this a long time ago and finding this was how Word behaved, but I could be wrong. It seems reasonable to match Word's behavior here.
Assignee | ||
Comment 2•6 years ago
|
||
After landing bug 1422234, pressing Enter at end of link stops creating another <a> element in new paragraph. However, we still don't have a way to put caret outside the <a> element.
Assignee | ||
Comment 3•4 years ago
|
||
After landing bug 1496320, if caret is moved from outside of <a href>
, typing new character at edge of the element is treated as typing outside it. I guess that the remaining issue is, the case when there is no content before or after <a href>
in the block or line.
Updated•4 years ago
|
Comment 5•4 years ago
|
||
I wonder this could be related to bug 1667129. Could we create an empty frame on a line edge so that reaching the line end could:
- Put the caret in a non-anchor plain text frame
- Make sure the caret is always in visual edges of lines, even in mixed bidi context
I'm sharing my random thought before actual investigation, though.
Comment 6•4 years ago
|
||
Emilio, does comment #5 make sense to you? It could also remove a workaround in nsCaret.
Comment 7•4 years ago
|
||
So when you have an element in <div><a>bcd</a></div>
you don't have any text frame, but I think moving past the d
should set the caret association mode to CARET_ASSOCIATE_AFTER
... I'm not sure you really need more DOM for that.
I'm not sure what you mean with (2) though, can you elaborate?
Comment 8•4 years ago
|
||
(any text frame outside of the link I mean)
Assignee | ||
Comment 9•4 years ago
|
||
Well, I don't know selection handling with pointing device events though, cannot put selection after the <a>
element and in the <div>
? I.e., div - 1
in this case. If it's reasonable, editor could handle TypeInState
specifically.
Comment 10•4 years ago
|
||
I'm not sure what you mean with (2) though, can you elaborate?
https://bug1667129.bmoattachments.org/attachment.cgi?id=9177660
If you select the first line from right to left by mouse, it's hard to fully select the RTL word because the logical end of the line is visually at the middle of the line. (Dragging to outside of the window should fully select the line but it does not.) I was wondering if adding an empty LTR frame at the end of the line could help here.
Updated•3 years ago
|
Assignee | ||
Comment 20•3 years ago
|
||
Well, today, I have much time for this. I'll post a patch.
Assignee | ||
Comment 21•3 years ago
|
||
Perhaps, the reasonable solution is, we should take almost same behavior. However, for better UX and keeping traditional better behavior,
- Basically, we should unlink when selection is changed and it's not in an
<a href>
element. - But don't unlink when selection is collapsed to start or end of an
<a href>
with clicking first or last content. - And also don't unlink when caret is moved to start or end of an
<a href>
with a key press and the previous caret position is in the link
So, I think that we should unlink if selection change occurred by JS for making exactly same behavior as the other browsers from the point of view of Selection API.
Comment 22•3 years ago
•
|
||
(Midair-collision with comment 21, will look at that in my next comment)
Hi Masayuki, thank you very much for picking this up, that'll be a nice Christmas present!!! As the duplicates testify, this has been an everlasting painpoint especially for Thunderbird.
Let's try to elaborate a bit what we really want here.
Please let me know what you think.
Sorry if I sound clumsy.
I think the remaining problem isn't exactly about clicking outside <a href>
, that actually works pretty well when there's any editable content after the link: If you click on the left leg of the W, you can type regular text, but if you click on the right rounding of the D, you'll continue the link. Same for cursoring, coming from link will extend the link, coming from text will extend text:
<a href="...">linktextEND</a>Whatever
So per your own comment 3, the real problem here (as seen in attachment 8859119 [details]) occurs only when there's no editable (cursor-navigable) content before or after the link, regardless if you mouse-click or navigate with navigation keys: That is when there's no way to place the input cursor before or after the link, as indicated below:
Desired input positions for adding unlinked text outside the link:
<p>|<a href="http://test">http://test</a>|</p>
(In reply to Masayuki Nakano [:masayuki] (he/him)(JST, +0900)(Got a cold, working slower) from comment #3)
After landing bug 1496320, if caret is moved from outside of
<a href>
, typing new character at edge of the element is treated as typing outside it. I guess that the remaining issue is the case when there is no content before or after<a href>
in the block or line.
So I think we want to fix two problems here:
- Mouse click before and after link: Add a condition that if there's no editable/cursor-navigable content before/after
<a href>
, clicking before or after the link(text) (or even on the very edges of linktext) must place the input cursor outside the link (for entering plain vanilla text). - Cursor navigation: We must provide a way to reach the cursor position outside the link when there's no other editable/cursor-navigable content around it.
For cursor navigation, here's my proposal:
- Let's remain consistent with the behaviour recently implemented in bug 1496320: Navigating from inside the link exactly to its edge (i.e. from linktext character pos 1 to pos 0, or link.length-1 to link.length) extends the link.
- However, when the input cursor is already on the edge of the link text (pos 0, or link.length), and user deliberately presses any navigation keys again trying to move "more" outwards, that's when we should place the input cursor outside the link for entering plain text. Iow, while the visible cursor won't change its position, the internal editing position changes on the edges if you continue navigating (note that selections with Ctrl or Shift should not have that behaviour, but always immediately include the link edges).
Keyboard navigation from inside the link:
<p><a href="http://test">http://tes|t</a></p>
Keyboard navigation from inside (e.g. Arrow-right, or END), now on edge (extend link style):
<p><a href="http://test">http://test|</a></p>
Keyboard navigation from edge (e.g. Arrow-right or END again or held down), now outside link (plain text):
<p><a href="http://test">http://test</a>|</p>
I think we once had this behaviour even for ongoing text, but it was removed because a cursor which doesn't move after pressing a navigation key is irritating. However, this case is different as it is an edge case, and no further cursor movement is expected as we've already reached the edge. However, still doing the "internal" cursor movement from inside to outside the anchor tag will be tremendously helpful, and I can't think of any other keyboard way consistent with the current behaviour to solve this.
Comment 23•3 years ago
•
|
||
(In reply to Masayuki Nakano [:masayuki] (he/him)(JST, +0900)(Got a cold, working slower) from comment #21)
Perhaps, the reasonable solution is, we should take almost same behavior. However, for better UX and keeping traditional better behavior,
- Basically, we should unlink when selection is changed and it's not in an
<a href>
element.
I don't understand - can you elaborate? Is this mouse or keyboard? Or programmatically?
Is this new or existing behaviour?
- But don't unlink when selection is collapsed to start or end of an
<a href>
with clicking first or last content.
Ok, let's take this example:
<p><a href="...">STARTlinktextEND</a></p>
Do you mean this?
- don't unlink when clicking on outer edges of S or D (existing behaviour)
- (New:) Unlink when clicking "outside" S or D (is that even possible? What if there's no editable whitespace to click on, as on the left side of testcase attachment 8859119 [details]?)
- And also don't unlink when caret is moved to start or end of an
<a href>
with a key press and the previous caret position is in the link
Yes. That's existing behaviour. The interesting part is just after that:
- Unlink when navigation key is pressed with current internal cursor position still "inside" the link, but already on the edge.
So, I think that we should unlink if selection change occurred by JS for making exactly same behavior as the other browsers from the point of view of Selection API.
What's the behaviour in other browsers?
Comment 24•3 years ago
|
||
Btw, my older version of Word (2003) has a very simple, non-sticky behaviour:
Cursor at the edge of linktext will always create plain text (unlinked). That feels much better because there's no tricky sticky link stuff going on. So it becomes a bit harder when you want to change linktext on the edges, but you can always double-click to explicitly edit link text in a dialog, or to navigate one character to the inside of linktext, add what you want, and delete the outmost linktext character.
Assignee | ||
Comment 25•3 years ago
|
||
(In reply to Thomas D. (:thomas8) - [PTO 18 Dec - 03 Jan] from comment #22)
(Midair-collision with comment 21, will look at that in my next comment)
I think the remaining problem isn't exactly about clicking outside<a href>
,
Exactly.
that actually works pretty well when there's any editable content after the link: If you click on the left leg of the W, you can type regular text, but if you click on the right rounding of the D, you'll continue the link. Same for cursoring, coming from link will extend the link, coming from text will extend text:
<a href="...">linktextEND</a>Whatever
Yes, I agree with that it's not an expected behavior for any users. So, only when clicking on the right half of the "D", editor should unlink temporarily for coming input.
So per your own comment 3, the real problem here (as seen in attachment 8859119 [details]) occurs only when there's no editable (cursor-navigable) content before or after the link, regardless if you mouse-click or navigate with navigation keys: That is when there's no way to place the input cursor before or after the link, as indicated below:
Desired input positions for adding unlinked text outside the link:
<p>|<a href="http://test">http://test</a>|</p>
Well, but it's hard to change caret position. So, I just change editor's temporary style (called "type-in-state" by its original author) in the mouse cases. For key navigation, I need another approach.
(In reply to Masayuki Nakano [:masayuki] (he/him)(JST, +0900)(Got a cold, working slower) from comment #3)
For cursor navigation, here's my proposal:
- Let's remain consistent with the behaviour recently implemented in bug 1496320: Navigating from inside the link exactly to its edge (i.e. from linktext character pos 1 to pos 0, or link.length-1 to link.length) extends the link.
Yeah, I think that it's reasonable, but I think that we should consider it with the command instead because it's hard to count the code points of first or last grapheme cluster. So, perhaps, editor should keep current behavior only when character-move command is ordered by a key press (typically, left/right arrow key without any modifiers).
- However, when the input cursor is already on the edge of the link text (pos 0, or link.length), and user deliberately presses any navigation keys again trying to move "more" outwards, that's when we should place the input cursor outside the link for entering plain text. Iow, while the visible cursor won't change its position, the internal editing position changes on the edges if you continue navigating (note that selections with Ctrl or Shift should not have that behaviour, but always immediately include the link edges).
I don't think that editor should change "type-in-state" without any visual feedback. But anyway, this is not possible change with simple code under current design.
Assignee | ||
Comment 28•3 years ago
|
||
Currently, the test checks the result only in contenteditable
, but I'd be
better to do same tests in designMode
editor too.
Additionally, for detecting regressions of the following patches, it should
check the result of 2nd typing too because inserting text into end of a link
element may cause unlink it.
Assignee | ||
Comment 29•3 years ago
|
||
This patch adds WPTs whose expected result is based on Chrome's behavior.
Depends on D100997
Assignee | ||
Comment 30•3 years ago
|
||
They were designed for object resizer and grabber to move absolutely positioned
element. Therefore, they should have better name to explain what they do.
Then, we can create event listener methods for generic cases.
Depends on D100998
Assignee | ||
Comment 31•3 years ago
|
||
When mouse button is clicked outside a link element but caret is positioned
start or end of the link, our traditional behavior keeps inserting new content
into the link. But this is different from the other browsers, and it does
not make sense to treat such selection change is intended to keep typing in
the link element.
Therefore, this patch makes TypeInState::OnSelectionChange()
handle
selection change reason is mousedown
and mouseup
cases. However,
it cannot know whether the event was fired in the parent link element or
not. Therefore, this patch makes HTMLEditorEventListener
notifies
TypeInState
of mouse events via HTMLEditor
.
Depends on D100999
Assignee | ||
Comment 32•3 years ago
|
||
Although different from the other browsers' behavior, our traditional behavior
might be better than them because the behavior on the other browser does not
allow users to insert new content at start nor end of a link.
However, we can relax more about keeping traditional behavior for web-compat.
Perhaps, only when caret is moved from the other side of first or last character
in the link and moves caret to the edge of the link with arrow key, we should
allow users to modify the link text.
Otherwise, e.g., Home
and End
key press should make it stop keeping the
link style. This helps advanced users who are familiar with keyboard navigatin
in editor.
Note that this patch also changes the condition which checks
aReason & nsISelectionListener::KEYPRESS_REASON
to check also
nsISelectionListener::COLLAPSETO_START_REASON
and
nsISelectionListener::COLLAPSETO_END_REASON
because all of them are
set by nsFrameSelection::MoveCaret
exclusively.
https://searchfox.org/mozilla-central/rev/a0ccd492719b1ad2106f6456549be62a76f45acb/layout/generic/nsFrameSelection.cpp#738,741,745
Therefore, they should be treated as same as a key press.
Note that they are also set by Selection::CollapseToStart
and
Selection::CollapseToEnd
too. But a following patch will add a new
reason to notify selection listeners of caused by JS. So, the problem
will be fixed by the following patch.
Depends on D101001
Assignee | ||
Comment 33•3 years ago
|
||
When caret is not moved but selection change command is fired, it means that
the caret is already set to start or end of editing host. In this case, we
should stop keeping link style for new inserting content because otherwise,
user cannot exit from the first or last link with arrow keys.
Depends on D101002
Assignee | ||
Comment 34•3 years ago
|
||
This is the most important situation. If selection is collapsed to a edge of a
link, the other browsers does not insert new content into the link. So, from
the point of view of web developers, this cause should work exactly same as
the other browsers.
Note that the new failures in editing/run/inserttext.html
are passed only
on Gecko. So, the test should be updated after fixing this bug.
Depends on D101003
Assignee | ||
Comment 35•3 years ago
|
||
When selection is not collapsed and is across link element boundary, we can
assume that user does not try to modify the link text because the other
browsers behave so. Therefore, we should take the same behavior in this case.
Note that all the new failures of editing/run/inserttext.html
are passed
only on Gecko. So, it should be updated in another bug.
Depends on D101004
Assignee | ||
Comment 36•3 years ago
|
||
This is same behavior as the other browsers. When selection is collapsed to
a edge of a link after deletion, we should stop applying link style to new
inserted content.
Depends on D101005
Comment 37•3 years ago
|
||
Pushed by masayuki@d-toybox.com: https://hg.mozilla.org/integration/autoland/rev/d81ab08e02b6 part 0-1: Make `test_typing_at_edge_of_anchor.html` test both on `contenteditable` and `designMode` r=m_kato https://hg.mozilla.org/integration/autoland/rev/32f63c6fa98e part 0-2: Add WPT for testing whether typing text is inserted into or outside of a link in various cases r=m_kato https://hg.mozilla.org/integration/autoland/rev/ef37ec496436 part 1: Rename `HTMLEditor::OnMouseDown()`, `HTMLEditor::OnMouseUp()` and `HTMLEditor::OnMouseMove()` r=m_kato https://hg.mozilla.org/integration/autoland/rev/8728fb04a7ef part 2: Make `TypeInState::OnSelectionChange()` stop inserting new content into the link if clicked outside it r=m_kato https://hg.mozilla.org/integration/autoland/rev/89469f0a9145 part 3: Make `TypeInState::OnSelectionChange()` stop keeping link style if caret is positioned at edge of a link element and not moved in the link r=m_kato,edgar https://hg.mozilla.org/integration/autoland/rev/642a9425089b part 4: Make `TypeInState` stop keeping link style when selection change command is performed, but it didn't change selection r=m_kato,edgar https://hg.mozilla.org/integration/autoland/rev/065517dd03b6 part 5: Make `TypeInState::OnSelectionChange` stop keeping link style for new inserting content when selection is changed by JS r=m_kato,edgar https://hg.mozilla.org/integration/autoland/rev/49ab7c774b1e part 6: Make `TypeInState::OnSelectionChange()` stop keeping link style when selection is not collapsed and the range is not entirely in a link r=m_kato https://hg.mozilla.org/integration/autoland/rev/c5fb8455ae1a part 7: Make `TypeInState::OnSelectionChange` stop keeping link style for new inserting content after content around a link edge is deleted r=m_kato
Comment 38•3 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/d81ab08e02b6
https://hg.mozilla.org/mozilla-central/rev/32f63c6fa98e
https://hg.mozilla.org/mozilla-central/rev/ef37ec496436
https://hg.mozilla.org/mozilla-central/rev/8728fb04a7ef
https://hg.mozilla.org/mozilla-central/rev/89469f0a9145
https://hg.mozilla.org/mozilla-central/rev/642a9425089b
https://hg.mozilla.org/mozilla-central/rev/065517dd03b6
https://hg.mozilla.org/mozilla-central/rev/49ab7c774b1e
https://hg.mozilla.org/mozilla-central/rev/c5fb8455ae1a
Created web-platform-tests PR https://github.com/web-platform-tests/wpt/pull/27170 for changes under testing/web-platform/tests
Upstream PR merged by moz-wptsync-bot
Comment 41•3 years ago
|
||
Awesome, thank you so much Masayuki for tackling this!!! :-))
I'll be looking forward to trying this out in action...
Description
•