views:

23

answers:

1

Using JavaScript, I would like to create a collapsed range from a pixel position, in order to insert new nodes in the flow of the document, after the range identified by this position.

This can be done with the TextRange object in Internet Exporer (moveToPoint(x, y) method).

How can I do this in FireFox & Webkit?

I can get the container element from the position with document.elementFromPoint(x, y). But when the position happens to be inside a text node, how do I get more information about the text offset required to build a range?

A: 

Here is the result of my investigation for getting a character position inside a text node from a pixel position:

  • The standardized way: Get a range from a position with document.caretRangeFromPoint(x, y) See the spec at W3c. This is exactly what I was looking for. The problem is that Chrome is the only web browser that implements this method as of this writing (July 2010)
  • The MS IE way with the proprietary textRange.moveToPoint(x, y).
  • The Firefox way: If the pixel position (x, y) is retrieved from a mouse event, then Firefox will add two useful properties to the event object: rangParent and rangeOffset
  • For Safari & Opera (and actually the only cross-browser method) is to re-constitute the containing boxes for text nodes, and then use the pixel position inside the containing box to infer the character position. To do this you must:
    1. Wrap all text nodes into <span> elements (dimension information is only available for elements, not for text nodes)
    2. Call span.getClientRects() to get the containing boxes for each textNode (wrapped into a <span>). If the text node spans over several lines you'll get several boxes.
    3. Find the box which contains your (x, y) pixel position, and infer the character position with a simple "rule of three" based on the total pixel width and text length.
Yannick Deltroo
The method suggested for Safari works in Safari 4, except when a zoom factor is applied to the page: in this case coordinates returned by getClientRects() are incorrect. Additionally Safari 3 does not even implement getClientRects(), so if you wan to support this browser the only method I can think of is to wrap all words inside all text nodes into SPANs!
Yannick Deltroo