Many JavaScript developers have had to deal with the objects listed in the header, for example, when solving the following tasks:
- creation of visual editors (wysiwyg),
- search in the browser window,
- setting BB-code
etc.
In this article, the author attempts to collect the translation of documentation about these objects in one place + to write small accompanying examples. The translation is free, not literal, so if you find inaccuracy or clumsy wording - write in the comments.
In general, the post is for reference only, and I hope that someone will simplify the development.
')
1. Range
Range is an object corresponding to a document fragment, which may include nodes and sections of text from this document. Most details about Range-objects are set out in the
DOM Range .
In order to understand what this is about, let us turn to the simplest case of Range-objects, which will be discussed in detail below, - to selections. In the example below, highlight a few words in a sentence. This will create objects similar to Range. In our example, we will get the text content of the area that you select.
Example linkBut such areas can be created not only with the help of a custom selection, but also from a JavaScript script, performing certain manipulations with them. However, to write a simple illustrating code will not work right away, since there is one BUT - Internet Explorer. Micsosoft created its own implementation,
a TextRange object . Let's sort each implementation separately.
1.1 DOM implementation of a Range 



Range consists of two boundary points (boundary-points) corresponding to the beginning and end of the region. The position of any boundary point is defined in the document using two properties: node (node) and offset (offset). A container is a node that contains a boundary point. The container itself and all its ancestors are called the parent containers (ancestor containers) for the boundary point. A parent container that includes both boundary points is called a root container.

In the image above, the selection boundary points lie in text nodes (# text1 and # text2), which are containers. For the left border, the parent containers are # text1, H1, BODY, for the right border - # text2, P, BODY. The common parent for both boundary points is BODY, this element is a root container.
If the container is a text node, the offset is defined in characters from the beginning of the node. If the container is an element (Document, DocumentFragment, Element ...), then the offset is determined in the child nodes.
We look at the illustration (
source ):

The boundary points of the Range-object
s1 lie in the text nodes, so the offset is specified in characters from the beginning of the node. For
s2, the boundary points are arranged so that they include the entire <p> Blah xyz </ p> paragraph, so the container is the BODY element, and the offset is considered at the positions of the child nodes.
Range objects are created using the creareRange method, which is called in the context of a root container or document. The object is created empty, and the boundary points are set by the setStart and setEnd methods of the object. See an example:
< div id ="ex2" >
< h2 > | Range- </ h2 >
< p > | . </ p >
</ div >
$domRange = {
create : function () {
// root-
var root = document .getElementById( 'ex2' );
// ( )
var start = root.getElementsByTagName( 'h2' )[0].firstChild;
var end = root.getElementsByTagName( 'p' )[0].firstChild;
if ( root.createRange ) {
// Range
var rng = root.createRange();
// ,
rng.setStart( start, 3 );
//
rng.setEnd( end, 10 );
// ,
return rng.toString();
} else
return ', Internet Explorer, TextRange ' ;
}
}
An example in action .
Consider briefly the
properties and methods of the Range :
- The commonAncestorContainer property returns a link to the most embedded root container.
- The startContainer ( endContainer ) property returns a reference to the container of the upper (lower) boundary point.
- The startOffset ( endOffset ) property returns the offset for the upper (lower) boundary point.
- The collapsed property returns true if the boundary points have the same containers and offset (false otherwise).
- The setStart ( setEnd ) method sets the container (link to the node) and the offset (integer value) for the corresponding boundary points. The example above.
- The setStartBefore , setStartAfter , setEndBefore , setEndAfter methods take as a single argument a reference to a node and set boundary points according to the natural border of the passed node. For example:
< span id ="s1" > First </ span >
< span id ="s2" > Second </ span >
var rng = document .createRange();
// #s1
rng.setStartBefore( document .getElementById( 's1' ) );
// #s2
rng.setEndAfter( document .getElementById( 's2' ) );
- The selectNode and selectNodeContents methods allow you to create a Range object on the boundaries of the node, the link to which they take as the only argument. When using selectNode, the passed node will also go into Range, while selectNodeContents will create an object only from the contents of the node:

- The collapse method combines the boundary points of a Range object. As a single argument, it takes a boolean value (true & mdash to combine at the top point, false & mdash at the bottom). By default, true.
- The toString method returns the text content of the Range object.
- The cloneContents method will return a copy of the contents of the Range object as a fragment of a document.
- The cloneRange method will return a copy of the Range object itself.
- The deleteContents method deletes the entire contents of the Range object.
- The detach method retrieves the current object from the DOM, so it can no longer be referenced.
- The insertNode method takes as a single argument a reference to a node (or a fragment of a document) and inserts it into the contents of the Range object at the starting point.
- The extractContents method cuts the contents of the Range object and returns a reference to the received document fragment.
- The method surroundContents places the entire contents of the current Range object into a new parent element, the link to which is taken as the only argument.
- The compareBoundaryPoints method is used to compare boundary points.
To distract and consolidate knowledge, we will solve a small puzzle. Find the phrase in the text node and highlight it with a blue background.
< div id ="ex3" >
""
</ div >
$domRange.highlight = function ( text ) {
//
var root = document .getElementById( 'ex3' ).firstChild;
//
var content = root.nodeValue;
//
if ( content.indexOf( text ) != -1 ) {
if ( document .createRange ) {
// , Range,
var rng = document .createRange();
// ,
rng.setStart( root, content.indexOf( text ) );
// +
rng.setEnd( root, content.indexOf( text ) + text.length );
//
var highlightDiv = document .createElement( 'span' );
highlightDiv.style.backgroundColor = 'blue' ;
// Range
rng.surroundContents( highlightDiv );
} else
alert( ', Internet Explorer, TextRange ' );
} else
alert( ' ' );
}
An example in action .
Experiment yourself with the rest of the properties and methods.
Let us turn to the implementation of range in MSIE.
1.2. Textrange 
The
TextRange object in the MSIE implementation is a text range of zero or more length. This range also has its own borders, which can be “moved” by an integer number of text units: character (character), word (word), sentence (sentence). That is, you can take and move the border by 2 (5, 8, etc.) words (symbol, sentence) to the right (left). At the same time, the object stores data about the HTML content of the range and has methods for interacting with the DOM.
A TextRange object is created using the
createTextRange method, which can be called in the context of the following DOM elements:
BODY, BUTTON, INPUT type=button, INPUT type=hidden, INPUT type=password, INPUT type=reset, INPUT type=submit, INPUT type=text, TEXTAREA
A simple example with a button:
< input id ="buttonId" type ="button" value ="Test button" />
$ieTextRange = {
create : function () {
//
var button = document .getElementById( 'buttonId' );
//
if ( button.createTextRange && button.createTextRange() != undefined ) {
// TextRange
var rng = button.createTextRange();
//
return rng.text;
} else
return ', IE (!), Range ' ;
}
}
An example in action .
Consider the
properties and methods of the TextRange object (not all, only the most necessary):
- The property boundingWidth (boundingHeight) returns the width (height) that the TextRange object occupies in pixels.
- The property boundingTop ( boundingLeft ) returns the Y (X) -coordinate of the upper left corner of the test area relative to the document window.
- The htmlText property returns the HTML content of the object.
- The text property returns the textual content of the object (see the example above).
- The offsetTop ( offsetLeft ) property returns the Y (X) -coordinate of the upper left corner of the test area relative to the ancestor.
- The collapse method combines the boundary points of a range. As a single argument, it takes a boolean value (true & mdash to combine at the top point, false & mdash at the bottom). By default, true.
- The duplicate method clones the existing text range, returning a new one, exactly the same.
- The expand method expands the current text range to a single text passed as the only text argument:
'character' —
'word' —
'sentence' —
'textedit' — .
Returns true (false) on success (failure).
- The findText method searches for a range of matches with the text string passed as the first argument (case insensitive). If a match is found, the boundaries of the range are collapsed to it. As a second (optional) argument, you can pass an integer indicating the number of characters from the top point to be searched. Further, as arguments, you can list INT-flags that you are unlikely to need .
- The getBookmark method returns in case of a successful call a string that can be used to restore the current state of the text range using the moveToBookmark method.
- The inRange method takes another TextRange object as an argument and checks whether its text range is in the range of the context object. Returns a boolean value.
- The isEqual method checks whether the current TextRange object is identical to the one passed as an argument. Returns a boolean value.
- The move (sUnit [, iCount]) method collapses the current range to zero length and moves a unit of text passed as the first argument (character | word | sentence | textedit). As a second (optional) argument, you can pass the number of units to which the range should be moved.
- The moveEnd ( moveStart ) method, similarly to the move method, moves the upper (lower) limit of the range by a unit of text, the number of which can also be specified by the optional second parameter.
- The moveToElementText method takes as its argument a link to the DOM element and sets the bounds of the range of the TextRange object along the bounds of the received element.
- The moveToPoint method takes as its two required arguments X and Y-coordinates (in pixels) relative to the upper left corner of the document and transfers the boundaries of the range there.
- The parentElement method returns a reference to an element that completely contains the range of a TextRange object (or null).
- The pasteHTML method replaces the HTML content of the current text range with the string passed as the only argument.
- The select method generates a selection based on the contents of the TextRange object, which we will discuss in more detail below.
- The setEndPoint method takes a text pointer and a link to another TextRange object as required arguments, setting it depending on the value of the pointer of the range border. Pointers can be the following: 'StartToEnd', 'StartToStart', 'EndToStart', 'EndToEnd'.
Also applied to the TextRange objects are commands of
the execCommand method .
To fix it, we will solve a puzzle for searching text content, similar to the one above:
< div id ="ex4" >
""
</ div >
$ieTextRange.highlight = function ( text ) {
// ,
var root = document .getElementById( 'ex4' );
//
var content = root.firstChild.nodeValue;
//
if ( content.indexOf( text ) != -1 ) {
// MSIE
if ( document .body.createTextRange ) {
// TextRange
var rng = document .body.createTextRange();
// root
rng.moveToElementText( root );
//
if ( rng.findText( text ) )
// span
rng.pasteHTML( '<span style="background:blue;">' + text + '</span>' );
} else
alert( ', IE (!), Range ' );
} else
alert( ' ' );
}
An example in action .
Experiment yourself with the rest of the properties and methods.
2. Selection
Everyone knows the selection of elements on the page, when, holding the left mouse button and moving the cursor, we select the desired fragment. Or hold Shift and click on the arrow keys. Or somehow, it does not matter. In this part of the article, we will cross-browser learn how to solve two problems: get a user selection and set your own.
2.1. Get custom highlighting
We have already solved this problem at the very beginning of the article
in the mix example . Now consider the code:
$selection = {
getText : function () {
var txt = '' ;
if (txt = window.getSelection) // Not IE, getSelection
txt = window.getSelection().toString();
else // IE, selection
txt = document .selection.createRange().text;
return txt;
}
}
All browsers, except Internet Explorer, support the
getSelection method in the context of a window, which returns an object similar to
the previously discussed Range . This object has a selection start point (anchor) and a focus end point (focus). Points may coincide. Consider the properties and methods of the Selection object:




- The anchorNode property returns the container in which the selection starts. I note that the beginning of the selection is the border from which you started the selection. That is, if you select from right to left, then the beginning will be exactly the right border. This rule works everywhere except for the Opera browser, in which anchorNode returns a link to the node of the left edge of the selection.
- The anchorOffset property returns the offset to start the selection within the anchorNode container.
- The focusNode and focusOffset properties work similarly for focal points, that is, the end points of the selection. Opera has also distinguished itself here, instead of a focal point, it returns the node of the right edge of the selection.
- The rangeCount property returns the number of Range-objects that are included in the resulting selection. This property is useful when using the addRange method.
- The getRangeAt method takes as an argument the index of the Range object and returns the object itself. If rangeCount == 1, then only getRangeAt (0) will work. Thus, we can get a Range-object that fully corresponds to the current selection.
- The collapse method collapses the selection to a point (caret). The method can be passed as the first argument of the node in which to place the carriage.
- The extend method takes as arguments the reference to the container and the offset (parentNode, offset), and moves the focal point to this position.
- The collapseToStart ( collapseToEnd ) method moves the focal (initial) border to the initial (focal) border, thereby folding the selection into the caret.
- The selectAllChildren method accepts a reference to the node as the only argument and adds all its descendants to the selection.
- The addRange method takes a Range object as an argument and adds it to the selection. Thus, you can increase the number of Range-objects, the number of which will be prompted to us by the rangeCount property.
- The removeRange ( removeAllRanges ) method removes the transferred (all) Range object from the selection.
- The toString method returns the textual content of the selection.
Internet Explorer provides its own interface for interacting with selections - the
selection object in the context of the document. The following methods are used to work with this object.

- The clear method removes the selection along with its contents.
- The createRange method (IMPORTANT! Not to be confused with the createRange DOM method for creating Range objects!) Creates a TextRange object from the selection content.
- The empty method removes the selection, but leaves the contents.
I hope, now, after becoming acquainted with both implementations of selections, the code above has become more understandable.
2.1. Setting your own selection
Suppose you want a text fragment on a page to be selected as a user selection. This is necessary for the client implementation of the search page and some other tasks. The easiest way to solve this problem is as follows:
- Create a Range object (TextRange for IE).
- Translate the resulting object to the selection.
We look implementation:
< div id ="ex5" >
< span > </ span > , .
</ div >
$selection.set = function () {
var target = document .getElementById( 'ex5' ).getElementsByTagName( 'span' )[0];
var rng, sel;
if ( document .createRange ) {
rng = document .createRange();
rng.selectNode( target )
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange( rng );
} else {
var rng = document .body.createTextRange();
rng.moveToElementText( target );
rng.select();
}
}
An example in action .
3. Afterword
Reflecting on the API provided by the article, the idea arose of creating a small library that would teach IE the DOM-implementation of Range and Selection. Perhaps it even exists, then the author will be grateful to you for the link and saving your own time.
Description API does not claim to be complete and accurate translation, but the author of this is enough for comfortable JavaScript development. The originals in English can be found at the links below.
Crosspost articles
Range, TextRange and Selection with
fastcoder.org .
4. References