Приглашаем посетить
CSS (css.find-info.ru)

Programming the TextRange Object

Programming the TextRange Object

This section introduces the properties and methods available for manipulating the TextRange object. The methods allow scripts to manipulate the underlying text in much the same way as a person could edit it with a text editor, selecting text and typing or pasting new text into the document. Viewing the methods this way will help you understand how they work.

Creating a TextRange Object

As mentioned, a TextRange object is created by calling the createTextRange method on an element that is a text edit owner. Like the dynamic contents properties, the TextRange object is not available until after the entire document is parsed. During the parsing of the document, any attempt to create a TextRange object using the createTextRange method fails. Therefore, ensure that the document is entirely loaded before using any method that returns a TextRange object.

The TextRange object returned by the createTextRange method should almost always be assigned to a variable. Otherwise, the TextRange object created in memory is immediately destroyed. Here is the right way to create a TextRange object:

var tr = document.body.createTextRange();

And here is the wrong way:

document.body.createTextRange(); // This does nothing.

The only circumstance in which you don't have to assign a new TextRange object to a variable occurs when a sequence of operations can be performed in a single step—for example, when you replace the HTML that the TextRange object represents:

// Replace the entire body's HTML.
document.body.createTextRange().pasteHTML("<H1>New Document</H1>");

The parentTextEdit Property

Every element has a property named parentTextEdit that references the text edit owner responsible for the element's contents. Using this property can give your code compatibility with future versions of the object model. Currently the parentTextEdit properties for most elements in a document reference the Body element. Elements contained within a Button element are the only exceptions; their text edit owner is the Button element. However, future versions of the object model might support more elements as text edit owners. When you create a TextRange object for an element, use its parentTextEdit property to identify its text edit owner, and your code should still work if the text edit owner changes. The following code illustrates this technique:

// el represents an element object in the document.
var tr;
if (!el.isTextEdit)
   tr = el.parentTextEdit.createTextRange();
else
   tr = el.createTextRange();

Every element in the body of a document exposes the isTextEdit property, which indicates whether the element is a text edit owner. The preceding code uses the element el to create a TextRange object if el is a text edit owner; otherwise, the code uses the parent text edit owner of el. The following simple line of code demonstrates that the Body element is a text edit owner:

alert(document.body.isTextEdit);  // true; the Body element is a
                                  // text edit owner.

Representing the Document's Contents

The TextRange object has two properties, text and htmlText, that provide access to the document's unformatted and formatted text.

The text property represents the document's text without any of the HTML markup. This property is read/write and can be used to replace the unformatted contents. The text property is similar to the outerText property on the element objects in the way it exposes the document's contents and in the types of values that can be assigned to it.

The htmlText property represents the text together with the HTML markup. This property represents the HTML the same way the outerHTML property represents it, but unlike the outerHTML property, the htmlText property is read-only. To assign new HTML to the TextRange object, you must use the pasteHTML method instead. Assigning new HTML is handled by a separate method because it is not symmetric with reading the current HTML. A value you insert into a text range using the pasteHTML method might not match the value that is subsequently returned by the htmlText property; the TextRange object might modify or clean up the HTML you insert, and the HTML might even influence contents beyond the boundaries of the TextRange object.

The pasteHTML method is designed to insert valid HTML. When you call the pasteHTML method on a particular element, the fragment you paste will be within the span of that element, and it should be valid HTML within that span as defined by the DTD (document type definition). The browser will attempt to clean up any HTML that doesn't conform, and it can extend HTML beyond the boundaries originally spanned by the TextRange object. When the pasteHTML method returns, the TextRange object is updated to span the newly inserted text.

text vs. htmlText

The primary advantage of using the text property over htmlText and pasteHTML involves the handling of entities representing angle brackets. When you assign a value to a text property, the value is parsed as unformatted HTML, so any angle brackets are automatically replaced by the corresponding entities; for example, < is replaced by &lt;. When you read a text property, entities are returned as their literal values.

When you insert new text in a text range using the pasteHTML method, the text is parsed as HTML, so any angle brackets are interpreted as parts of HTML tags. If you want to embed an angle bracket in the text, you must substitute the appropriate entity yourself. When you use the htmlText property to retrieve a text range, any angle brackets in the text appear as entities; for example, < is returned as &lt;.

White Space

The text property of the TextRange object represents white space as it is rendered on the screen, not as it is represented in the underlying document. In most cases in HTML, extra white space is ignored. For example, if an HTML document uses three spaces between each word, the text will be displayed with only a single space between each word. In addition, carriage returns inside an HTML document are ignored; block tags determine line breaks.

The exception to these rules is in PRE and XMP elements. In these elements, the existing white space is preserved and any white space later inserted is maintained.

Floating End Tags

You cannot force an existing element in the document to end earlier by inserting a new end tag. For example, suppose a document has this Bold element:

<B>This is bold text.</B>

If you use a TextRange object to insert a new </B> end tag between the words bold and text, the new tag will not become the end tag for the Bold element. The pasteHTML method does not insert a fragment literally into the tree. Instead, the fragment is validated against the DTD, which specifies that any extra end tags are ignored. So inserting the </B> tag will have no effect on the text or on the document tree.

Invalid Scope

Some HTML elements can validly appear only within the scope of other elements. For example, a TD element is supposed to be contained in a TR element inside a Table element. Chapter 7, "Document Element Collections," describes the parser's rules for handling elements in the source document that are not within their valid scope. Many of the same rules also apply to HTML that is inserted using a TextRange object. For example, the following code attempts to replace the document's body with a single TD element:

var tr = document.body.createTextRange();
tr.pasteHTML("<TD>Cell outside any table or row</TD>");

In this example, the contents are inserted into the document, but the surrounding <TD> tags are ignored because a valid table is not defined. This error handling is not guaranteed to be maintained from version to version of Dynamic HTML; therefore, to ensure predictable results, be careful to supply a proper HTML fragment.

Relating the TextRange Object to the Document's Structure

The TextRange object has a parentElement method that reports the relationship between the text range and the document's structure. This method returns the lowest element in the parsing tree that influences the entire range of text. As illustrated in Figure 14-1, every character in the text range is influenced by a leaf node (a node with no children). When a TextRange object represents a character, its parentElement method returns the leaf node influencing the character. When a TextRange object represents a range of characters, its parentElement is the node that influences the entire range. When a TextRange object is first created on the Body element, it represents all of the text, so its parentElement is usually the Body element itself.

Positioning the TextRange Object

When a TextRange object is first created, it encompasses all of the text influenced by the text edit owner on which it was created. For example, calling the createTextRange method on the Body element returns a text range that contains all the contents of the body.

A set of TextRange object methods repositions the TextRange object to span different text. The underlying architecture for the TextRange object is not tied to the ordinal indexes of the characters it spans in the text buffer. You cannot directly manipulate the endpoints of a text range, assigning them new character indexes. Instead, the TextRange object move methods reposition the object in ways to facilitate operations on the text. They can position the TextRange object to span any character, word, sentence, text edit owner, element, or point on the screen. These methods do not cause any text to be moved around the document. The following list enumerates the methods available for positioning a TextRange object:

Two additional methods are available for repositioning the TextRange object: setEndPoint and moveToBookmark. The setEndPoint method complements the compareEndPoints method. These methods are discussed in the sections "Managing TextRange Objects" and "Manipulating Bookmarks" later in this chapter.

The expand and collapse Methods

The expand method expands a TextRange object to fully encompass a character, a word, a sentence, or the entire text of the text edit owner on which it was created. For example, if the TextRange object spans a portion of a word, calling its expand method with the parameter word causes it to span the entire word. The expand method returns a Boolean value indicating whether the method succeeded.

The collapse method performs the reverse operation, placing the TextRange object's begin and end markers together as an insertion point. An optional parameter determines whether the insertion point is placed at the beginning or end of the current range; the default value is true, which places the insertion point at the beginning.

The moveToElementText Method

The moveToElementText method positions the TextRange object to span the text influenced by an element. Consistent with the behavior of the TextRange object, there is no guarantee that assigning a value to the TextRange object positioned using moveToElementText will change only the element's contents. Instead, if you need to change the contents of an element directly, you should use the inner and outer properties, introduced in Chapter 13, "Dynamic Contents."

The moveToElementText method is useful for navigating through the document to perform subsequent manipulations such as analyzing the first word of each header. The TextRange object can be easily moved to an element and then repositioned to span just the first word of text in that element without having to parse any strings. The next section focuses on the move methods that can do this.

The move, moveStart, and moveEnd Methods

The move, moveStart, and moveEnd methods reposition the TextRange object by a specified amount. The moveStart and moveEnd methods reposition the begin and end markers of the TextRange object. The move method repositions the TextRange object's begin marker by the specified amount and collapses the object to an insertion point.

Each of the three methods takes the same two parameters. The first parameter specifies whether to move by word, character, or sentence or to the end of the text stream. The second parameter specifies how many units to move. The second parameter can be either a positive or a negative value, which indicates whether to move forward or backward. The first parameter can be any of the following string values:


Unit Definition
character Moves by the specified number of characters
word Moves by the specified number of words
sentence Moves by the specified number of sentences
textedit Moves by the specified number of text edit elements

The move, moveStart, and moveEnd methods return the actual number of units that were moved. For example, if you were trying to move 200 words in a 100-word document, the move method would reposition the TextRange object to the last word in the document and return the number of words moved. To check whether an operation was successful, compare the return value with the number of units moved:

if (200 == tr.move("word", 200)) {
   // Success!
}
else { 
   // Failed to move 200 words.
}

The move method positions the TextRange object as an insertion point between two characters. For example, calling the move method to move forward three words positions the TextRange object between the third and fourth words. In this case, the text property would return an empty string. Assigning a value to the text property or calling the pasteHTML method would insert the text into the document at that point.

The moveStart and moveEnd methods move the start and end character positions. For example, this technique can be used to expand a selection of four words to five words either by moving the start position backward or by moving the end position forward. The following code demonstrates how to obtain the first word of an element in the document:

function firstWord(myElement) {
   // Obtain a TextRange object.
   var tr = document.body.createTextRange();
   // Move the TextRange object.
   // myElement represents an element in the document.
   tr.moveToElementText(myElement);
   // Collapse the TextRange object to the beginning of the element.
   tr.collapse();
   if (tr.moveEnd("word", 1))
      return tr.text;
   else
      return "";
}

The following example demonstrates how to count the number of words in a document. This code can be easily changed to count other units by changing the first parameter in the move method.

function countWords() {
   var tr = document.body.createTextRange();
   var intCount = 0;
   // Collapse the TextRange object to the beginning of the document.
   tr.collapse(true);
   while (tr.move("word", 1)) 
      intCount++;
   return intCount;
}

When moving by word or character units, all elements that represent an object, including images, intrinsic controls, and so on, represent a single unit.


NOTE: The ways these methods reposition the TextRange object can be compared with the ways certain keystrokes move the cursor or change text selection in popular word processors such as Microsoft Word. For example, the move method repositions the TextRange object as an insertion point the same way that the Right and Left arrow keys reposition the cursor in a word processor. Pressing an arrow key moves the cursor one character; holding down the Ctrl key and pressing an arrow key moves the cursor one word. The moveStart and moveEnd methods expand or contract the text spanned by a TextRange object the same way that keystrokes expand or contract selected text. Holding down the Shift key and pressing the Right or Left arrow key causes a selection to expand or contract one character in the specified direction. Holding down the Shift and Ctrl keys causes the selection to expand or contract a word at a time.

The moveToPoint Method

The moveToPoint method takes a point in the client area of the screen as an argument, determines what item in the document is rendered at that point on the screen, and places the TextRange object as an insertion point by that item. This method, when used in a mouse event handler to determine what text the mouse is on, offers finer granularity than the srcElement property, which returns the element the mouse pointer is in. The following mouse event handler code displays in the status bar the word the mouse is on:

function doMouseMove() {
   var tr = document.body.createTextRange();
   tr.moveToPoint(event.clientX, event.clientY);
   // Expand to the entire word under the mouse.
   tr.expand("word");
   window.status = tr.text;
}
document.onmousemove = doMouseMove;

The findText Method

The findText method locates a specified string in the document. The browser's Find dialog boxes use the findText method and can demonstrate the flexibility provided by this method.

The findText method takes three parameters. The first parameter is the string to locate in the document. The second parameter represents how many characters to search in the document; the value must be positive for a forward search and negative for a backward search. The third parameter specifies whether an entire word must match the string and whether a match must be case sensitive: pass 2 for full word matching, 4 for case-sensitive searching, and 6 for case-sensitive word matching.

Managing TextRange Objects

Methods are available to clone a TextRange object, to compare two TextRange objects, and to position one TextRange object relative to another one.

The duplicate Method

The duplicate method creates a copy of the TextRange object on which it is called. For example, the following code creates a copy of the TextRange object named tr:

var tr2 = tr.duplicate();

The inRange and isEqual Methods

The inRange method specifies whether the supplied text range is within the span of the TextRange object on which the method is called:

alert(tr2.inRange(tr)); // true; tr is within tr2.

The isEqual method compares two TextRange objects to see whether they span the same text. The method is necessary because two TextRange objects representing the same range of text can nonetheless be distinct objects, so comparing them directly as objects will not work. The following code demonstrates the right and wrong ways to see whether two objects span the same text:

// Set up example.
var tr = document.body.createTextRange();
var tr2 = tr.duplicate();
// Wrong way to compare text ranges:
alert(tr == tr2);       // false; these are two different objects.
// Right way to compare text ranges:
alert(tr.isEqual(tr2)); // true

The compareEndPoints and setEndPoint Methods

The compareEndPoints method compares two TextRange objects to see whether their start or end positions coincide. The setEndPoint method sets the start or end position of one TextRange object to the start or end position of another TextRange object. Both methods take two parameters. A start or end position of the TextRange object on which the method is called is compared with or set to a start or end position of the TextRange object specified by the second parameter. The first parameter can take any of the values in the following table, which specify what positions are to be used.


Value Description
StartToStart Sets or compares the start position of the current TextRange object to the start position of the TextRange object specified in the second parameter
StartToEnd Sets or compares the start position of the current TextRange object to the end position of the TextRange object specified in the second parameter
EndToEnd Sets or compares the end position of the current TextRange object to the end position of the TextRange object specified in the second parameter
EndToStart Sets or compares the end position of the current TextRange object to the start position of the TextRange object specified in the second parameter

For example, the following function determines whether the trDest object continues where the trSrc object leaves off:

function continues(trSrc, trDest) {
   return trSrc.compareEndPoints("EndToStart", trDest);
}

Scrolling the Range into View

TextRange objects are manipulated entirely in memory. Changing the text and htmlText properties on the TextRange object does not cause the document to scroll. To scroll the text spanned by a TextRange object into view, use the same scrollIntoView method that all elements support. This method takes a single optional parameter that specifies whether to scroll the text in the TextRange object to the top of the screen (true) or to the bottom of the screen (false).

Manipulating Bookmarks

A bookmark represents a TextRange object's position in the text, similar to an HTML bookmark representing a position in a document. You can use a TextRange object's getBookmark method to save a record of the object's current position as a bookmark and its moveToBookmark method to return to a saved position.

The getBookmark method returns a bookmark as a string value. Like TextRange, a bookmark does not record start and end positions as character indexes. Rather, the bookmark is a string that contains the position information in an encoded form. The string is not meant to be manipulated directly and should be used only with TextRange methods.

The moveToBookmark method takes a bookmark string as a parameter and positions the TextRange object according to the bookmark. This method returns a Boolean value that indicates whether the operation is successful.

You could make one TextRange object's position match a second TextRange object's position by calling the first object's moveToBookmark method and passing it the bookmark returned by the second object's getBookmark method. However, a more direct way to copy a bookmark is to use the duplicate method.

Embedded Objects

Embedded objects are the HTML elements that represent intrinsic controls, Object elements, images, and so on. Each embedded object is represented by a space in the TextRange object. To determine whether a space in a TextRange object actually represents an embedded object, obtain another TextRange object that spans just the space and check the parentElement method.

To add an embedded object to the TextRange object, insert the appropriate HTML into the document using the pasteHTML method. Once the assignment is made and the HTML is parsed, the text in the TextRange object is automatically updated with a space to represent the newly instantiated embedded object.

Selecting the Text Range

The TextRange object exposes a select method that makes the text spanned by the object the user's current selection. When a TextRange object is selected, the text it spans is selected on the screen. Subsequently extending the TextRange object does not extend the selection unless you call the select method again.

[Содержание]