2

Assume the following DOM tree:

<div id="edit" contenteditable="true">
  this content <a id="link" href="http://www.google.com/">contains</a> a link
</div>

Then create a range right after the anchor:

var r = document.createRange();
var link = document.getElementById('link');
r.setStartAfter(link);
r.setEndAfter(link);

As expected, its commonAncestorContainer is the element with id edit:

console.log(r.commonAncestorContainer);  /* => <div id="edit" contenteditable="true">…</div> */

Set the selection to this range:

var s = window.getSelection();
s.removeAllRanges();
s.addRange(r);

Now query the window for the current selection range and check its commonAncestorContainer:

var r2 = s.getRangeAt(0);
console.log(r2.commonAncestorContainer);

You will find that in Firefox the result is as expected; the same element with id edit.

In WebKit browsers though, the selection range ancestor container suddenly is the text node inside the anchor; "contains", yet when you start typing you will find that you really are not inside the anchor. WTF!?

Click here for a live demo.

Is there any potential rationale behind this behavior? Any reason to assume that it is not a WebKit bug??

Thanks for your $.02.

Tim Molendijk
  • 1,016
  • 1
  • 10
  • 14
  • ohh so you're saying that the property is returning the incorrect element for the element you would then be editing? – ars265 Sep 03 '13 at 14:20
  • I'm saying that the range as returned by WebKit is inconsistent with the range that we just assigned it to, with Firefox's behavior, and with how the browser behaves towards the user. – Tim Molendijk Sep 03 '13 at 14:25
  • I see what you are saying now, I've been reviewing the Range documentation here:https://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range, I think you may have found a bug that may need reported. – ars265 Sep 03 '13 at 14:39
  • @ars265: It's not a bug. – Tim Down Sep 03 '13 at 14:40
  • @TimDown, No? If the Range object originally contained the node why would it not keep the inherited endpoints, or is this described by the following in the documentation: `The content that one would think of as being within the range consists of all contained nodes, plus possibly some of the contents of the start node and end node if those are Text or Comment nodes.` and since the begin and endpoint are not text nodes, they are dropped? – ars265 Sep 03 '13 at 14:44
  • http://stackoverflow.com/a/14104166/96100 – Tim Down Sep 03 '13 at 14:45
  • @ars265: When you select a range using the selection's `addRange()` method in WebKit, the range it stores in the selection is modified if the end points are not ones that the browser allows. – Tim Down Sep 03 '13 at 14:48
  • Yeah, that would make logical sense. – ars265 Sep 03 '13 at 14:49

1 Answers1

1

WebKit only allows certain positions within the DOM to be used as selection boundaries or caret positions. It therefore modifies a range that is selected using the selection's addRange() method to conform to this. See also https://stackoverflow.com/a/14104166/96100.

There is another issue at play, which is that WebKit has a special case for a caret position at the end of a link which places text typed at that position after the link rather than inside it. This is undeniably a bit of a nasty hack, given that the browser reports the selection as being inside the link. However, this does not happen for other inline elements, as you can see this in this modified version of your demo:

http://jsbin.com/EYoWuWe/7/edit

Community
  • 1
  • 1
Tim Down
  • 318,141
  • 75
  • 454
  • 536