login/register

Snip!t from collection of Alan Dix

see all channels for Alan Dix

Snip
summary

Anyone who’s dealt with browsers’ implementations of...
Background for anyone who’s not familiar with it. Ther ...
Now, from JavaScript, let’s look at how to get those t ...
var selection = window.getSelection();
... implementation of selection

Versionate Blog » Getting range objects from DOM selection
http://blog.versionate.com/2007/04/25/getting-range-objects-from-dom-selection/

Categories

/Channels/techie/browser

[ go to category ]

/Channels/techie/web development

[ go to category ]

For Snip

loading snip actions ...

For Page

loading url actions ...

Anyone who’s dealt with browsers’ implementations of DOM Selection would know what a pain it is. This is probably the one area where every browser implements it differently, with Firefox and Opera being the closest to the standard.

Background for anyone who’s not familiar with it. There are two main concepts in DOM relating to selections: Selection and Range. A selection is the highlighted portion of the DOM structure. The end user typically create a selection by dragging across text nodes with the mouse. Selection defines the area that has been selected, and may be composed of one or more ranges. A range is defined as a continuous area within the DOM with four attributes: startNode, startOffset, endNode, and endOffset.

Now, from JavaScript, let’s look at how to get those two objects. Getting the selection object is pretty standard across all browsers. You do it with:
var selection = window.getSelection();
for Non-IE browsers, and for IE:
var selection = document.selection;

It’s worth to note that IE’s selection and range objects do not conform to the W3C standard at all. Even though it’s a selection object, it doesn’t provide a way for you to obtain the DOM nodes of the selection.

To get a range object from the selection, it’s simple for Mozilla and Opera:
var range = selection.getRangeAt(0);

Safari, on the other hand, chose not to implement getRangeAt. That makes it a bit harder to obtain a range from a selection: you can’t get it directly. Fortunately, Safari implements these four properties on the selection object: baseNode, baseOffset, extentNode, and extentOffset. With those four properties, you can recreate the Range object:

var range = document.createRange();
var selection = window.getSelection();
range.setStart( selection.baseNode, selection.baseOffset );
range.setEnd( selection.extentNode, selection.extentOffset );

That works fine for half of the cases. In a selection object, the base(Node/Offset) and extent do not imply ordering. However, the range object does: start must be before end in the DOM tree. If you created the selection by dragging your mouse from end to start, this will fail. Using the trick below would get around that problem:

if( range.collapsed != selection.isCollapsed )
{
range.setStart( selection.extentNode, selection.extentOffset );
range.setEnd( selection.baseNode, selection.baseOffset );
}

Both the range and selection object will tell you if they are collapsed(start and end at the same position). If we messed up the range’s start and end, the range will remain at the start point, in a collapsed state. Flipping the start and end should fix that.

Now you have a method of getting the range object for all major browsers except for IE. To implement a javascript wysiwyg editor, the selection and range are the of most critical pieces of the puzzle. We’ll cover how we worked around IE’s implementation of selection and range in a future post.

HTML

<p>Anyone who&#x2019;s dealt with browsers&#x2019; implementations of DOM Selection would know what a pain it is. This is probably the one area where every browser implements it differently, with Firefox and Opera being the closest to the standard.</p> <p>Background for anyone who&#x2019;s not familiar with it. There are two main concepts in DOM relating to selections: Selection and Range. A <a href="http://developer.mozilla.org/en/docs/DOM:Selection">selection</a> is the highlighted portion of the DOM structure. The end user typically create a selection by dragging across text nodes with the mouse. Selection defines the area that has been selected, and may be composed of one or more ranges. A <a href="http://developer.mozilla.org/en/docs/DOM:range">range</a> is defined as a continuous area within the DOM with four attributes: startNode, startOffset, endNode, and endOffset.</p> <p>Now, from JavaScript, let&#x2019;s look at how to get those two objects. Getting the selection object is pretty standard across all browsers. You do it with:<br> <code>var selection = window.getSelection();</code><br> for Non-IE browsers, and for IE:<br> <code>var selection = document.selection;</code></p> <p>It&#x2019;s worth to note that IE&#x2019;s selection and range objects do not conform to the W3C standard at all. Even though it&#x2019;s a selection object, it doesn&#x2019;t provide a way for you to obtain the DOM nodes of the selection.</p> <p>To get a range object from the selection, it&#x2019;s simple for Mozilla and Opera:<br> <code>var range = selection.getRangeAt(0);</code></p> <p>Safari, on the other hand, chose not to implement getRangeAt. That makes it a bit harder to obtain a range from a selection: you can&#x2019;t get it directly. Fortunately, Safari implements these four properties on the selection object: baseNode, baseOffset, extentNode, and extentOffset. With those four properties, you can recreate the Range object:<br> <code><br> var range = document.createRange();<br> var selection = window.getSelection();<br> range.setStart( selection.baseNode, selection.baseOffset );<br> range.setEnd( selection.extentNode, selection.extentOffset );<br> </code></p> <p>That works fine for half of the cases. In a selection object, the base(Node/Offset) and extent do not imply ordering. However, the range object does: start must be before end in the DOM tree. If you created the selection by dragging your mouse from end to start, this will fail. Using the trick below would get around that problem:<br> <code><br> if( range.collapsed != selection.isCollapsed )<br> {<br> range.setStart( selection.extentNode, selection.extentOffset );<br> range.setEnd( selection.baseNode, selection.baseOffset );<br> }<br> </code><br> Both the range and selection object will tell you if they are collapsed(start and end at the same position). If we messed up the range&#x2019;s start and end, the range will remain at the start point, in a collapsed state. Flipping the start and end should fix that.</p> <p>Now you have a method of getting the range object for all major browsers except for IE. To implement a javascript wysiwyg editor, the selection and range are the of most critical pieces of the puzzle. We&#x2019;ll cover how we worked around IE&#x2019;s implementation of selection and range in a future post.</p>