📜 ⬆️ ⬇️

Range, TextRange and Selection

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 link

But 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 Mozilla Firefox supportedChrome supportedOpera supportedSafari supported


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.

Range nodes

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 ):

Range Example

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 :



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 Internet Explorer supported


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):



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: Mozilla Firefox supportedChrome supportedOpera supportedSafari supported


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. Internet Explorer supported

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:
  1. Create a Range object (TextRange for IE).
  2. 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

Source: https://habr.com/ru/post/55922/


All Articles