5. Ranges

5.1. Introduction to "DOM Ranges"

StaticRange and Range objects (ranges) represent a sequence of content within a node tree. Each range has a start and an end which are boundary points. A boundary point is a tuple consisting of a node and an offset. So in other words, a range represents a piece of content within a node tree between two boundary points.

Ranges are frequently used in editing for selecting and copying content.

In the node tree above, a range can be used to represent the sequence “syndata is awes”. Assuming p is assigned to the p element, and em to the em element, this would be done as follows:

var range = new Range(),
       firstText = p.childNodes[1],
       secondText = em.firstChild
   range.setStart(firstText, 9) // do not forget the leading space
   range.setEnd(secondText, 4)
   // range now stringifies to the aforementioned quote
   

Attributes such as src and alt in the node tree above cannot be represented by a range. Ranges are only useful for nodes.

Range objects, unlike StaticRange objects, are affected by mutations to the node tree. Therefore they are also known as live ranges. Such mutations will not invalidate them and will try to ensure that it still represents the same piece of content. Necessarily, a live range might itself be modified as part of the mutation to the node tree when, e.g., part of the content it represents is mutated.

See the insert and remove algorithms, the normalize() method, and the replace data and split algorithms for details.

Updating live ranges in response to node tree mutations can be expensive. For every node tree change, all affected Range objects need to be updated. Even if the application is uninterested in some live ranges, it still has to pay the cost of keeping them up-to-date when a mutation occurs.

A StaticRange object is a lightweight range that does not update when the node tree mutates. It is therefore not subject to the same maintenance cost as live ranges.

5.2. Boundary points

A boundary point is a tuple consisting of a node (a node) and an offset (a non-negative integer).

A correct boundary point’s offset will be between 0 and the boundary point’s node’s length, inclusive.

The position of a boundary point (nodeA, offsetA) relative to a boundary point (nodeB, offsetB) is before, equal, or after, as returned by these steps:

  1. Assert: nodeA and nodeB have the same root.

  2. If nodeA is nodeB, then return equal if offsetA is offsetB, before if offsetA is less than offsetB, and after if offsetA is greater than offsetB.
  3. If nodeA is following nodeB, then if the position of (nodeB, offsetB) relative to (nodeA, offsetA) is before, return after, and if it is after, return before.

  4. If nodeA is an ancestor of nodeB:

    1. Let child be nodeB.

    2. While child is not a child of nodeA, set child to its parent.

    3. If child’s index is less than offsetA, then return after.

  5. Return before.

5.3. Interface AbstractRange

AbstractRange

In all current engines.

Firefox69+Safari14.1+Chrome90+
Opera?Edge90+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
[Exposed=Window]
   interface AbstractRange {
     readonly attribute Node startContainer;
     readonly attribute unsigned long startOffset;
     readonly attribute Node endContainer;
     readonly attribute unsigned long endOffset;
     readonly attribute boolean collapsed;
   };
   

Objects implementing the AbstractRange interface are known as ranges.

A range has two associated boundary points — a start and end.

For convenience, a range’s start node is its start’s node, its start offset is its start’s offset, its end node is its end’s node, and its end offset is its end’s offset.

A range is collapsed if its start node is its end node and its start offset is its end offset.

AbstractRange/startContainer

In all current engines.

Firefox69+Safari14.1+Chrome90+
Opera?Edge90+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

Range/startContainer

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

StaticRange/startContainer

In all current engines.

Firefox69+Safari10.1+Chrome60+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
node = range . startContainer
Returns range’s start node.

AbstractRange/startOffset

In all current engines.

Firefox69+Safari14.1+Chrome90+
Opera?Edge90+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

Range/startOffset

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

StaticRange/startOffset

In all current engines.

Firefox69+Safari10.1+Chrome60+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
offset = range . startOffset
Returns range’s start offset.

AbstractRange/endContainer

In all current engines.

Firefox69+Safari14.1+Chrome90+
Opera?Edge90+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

Range/endContainer

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

StaticRange/endContainer

In all current engines.

Firefox69+Safari10.1+Chrome60+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
node = range . endContainer
Returns range’s end node.

AbstractRange/endOffset

In all current engines.

Firefox69+Safari14.1+Chrome90+
Opera?Edge90+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

Range/endOffset

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

StaticRange/endOffset

In all current engines.

Firefox69+Safari10.1+Chrome60+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
offset = range . endOffset
Returns range’s end offset.

AbstractRange/collapsed

In all current engines.

Firefox69+Safari14.1+Chrome90+
Opera?Edge90+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

Range/collapsed

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

StaticRange/collapsed

In all current engines.

Firefox69+Safari10.1+Chrome60+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
collapsed = range . collapsed
Returns true if range is collapsed; otherwise false.

The startContainer getter steps are to return this’s start node.

The startOffset getter steps are to return this’s start offset.

The endContainer getter steps are to return this’s end node.

The endOffset getter steps are to return this’s end offset.

The collapsed getter steps are to return true if this is collapsed; otherwise false.

5.4. Interface StaticRange

StaticRange

In all current engines.

Firefox69+Safari10.1+Chrome60+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android79+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
dictionary StaticRangeInit {
     required Node startContainer;
     required unsigned long startOffset;
     required Node endContainer;
     required unsigned long endOffset;
   };
   
   [Exposed=Window]
   interface StaticRange : AbstractRange {
     constructor(StaticRangeInit init);
   };
   

StaticRange/StaticRange

In all current engines.

Firefox71+Safari13.1+Chrome90+
Opera?Edge90+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
staticRange = new StaticRange(init)

Returns a new range object that does not update when the node tree mutates.

The new StaticRange(init) constructor steps are:

  1. If init["startContainer"] or init["endContainer"] is a DocumentType or Attr node, then throw an "InvalidNodeTypeError" DOMException.

  2. Set this’s start to (init["startContainer"], init["startOffset"]) and end to (init["endContainer"], init["endOffset"]).

A StaticRange is valid if all of the following are true:

5.5. Interface Range

Range

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+
[Exposed=Window]
   interface Range : AbstractRange {
     constructor();
   
     readonly attribute Node commonAncestorContainer;
   
     undefined setStart(Node node, unsigned long offset);
     undefined setEnd(Node node, unsigned long offset);
     undefined setStartBefore(Node node);
     undefined setStartAfter(Node node);
     undefined setEndBefore(Node node);
     undefined setEndAfter(Node node);
     undefined collapse(optional boolean toStart = false);
     undefined selectNode(Node node);
     undefined selectNodeContents(Node node);
   
     const unsigned short START_TO_START = 0;
     const unsigned short START_TO_END = 1;
     const unsigned short END_TO_END = 2;
     const unsigned short END_TO_START = 3;
     short compareBoundaryPoints(unsigned short how, Range sourceRange);
   
     [CEReactions] undefined deleteContents();
     [CEReactions, NewObject] DocumentFragment extractContents();
     [CEReactions, NewObject] DocumentFragment cloneContents();
     [CEReactions] undefined insertNode(Node node);
     [CEReactions] undefined surroundContents(Node newParent);
   
     [NewObject] Range cloneRange();
     undefined detach();
   
     boolean isPointInRange(Node node, unsigned long offset);
     short comparePoint(Node node, unsigned long offset);
   
     boolean intersectsNode(Node node);
   
     stringifier;
   };
   

Objects implementing the Range interface are known as live ranges.

Algorithms that modify a tree (in particular the insert, remove, replace data, and split algorithms) modify live ranges associated with that tree.

The root of a live range is the root of its start node.

A node node is contained in a live range range if node’s root is range’s root, and (node, 0) is after range’s start, and (node, node’s length) is before range’s end.

A node is partially contained in a live range if it’s an inclusive ancestor of the live range’s start node but not its end node, or vice versa.

Some facts to better understand these definitions:


Range/Range

In all current engines.

Firefox24+Safari8+Chrome29+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
range = new Range()
Returns a new live range.

The new Range() constructor steps are to set this’s start and end to (current global object’s associated Document, 0).


Range/commonAncestorContainer

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+
container = range . commonAncestorContainer
Returns the node, furthest away from the document, that is an ancestor of both range’s start node and end node.

The commonAncestorContainer getter steps are:

  1. Let container be start node.
  2. While container is not an inclusive ancestor of end node, let container be container’s parent.
  3. Return container.

To set the start or end of a range to a boundary point (node, offset), run these steps:

  1. If node is a doctype, then throw an "InvalidNodeTypeError" DOMException.
  2. If offset is greater than node’s length, then throw an "IndexSizeError" DOMException.
  3. Let bp be the boundary point (node, offset).
  4. If these steps were invoked as "set the start"
    1. If range’s root is not equal to node’s root, or if bp is after the range’s end, set range’s end to bp.
    2. Set range’s start to bp.
    If these steps were invoked as "set the end"
    1. If range’s root is not equal to node’s root, or if bp is before the range’s start, set range’s start to bp.
    2. Set range’s end to bp.

Range/setStart

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The setStart(node, offset) method steps are to set the start of this to boundary point (node, offset).

Range/setEnd

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The setEnd(node, offset) method steps are to set the end of this to boundary point (node, offset).

Range/setStartBefore

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The setStartBefore(node) method steps are:

  1. Let parent be node’s parent.
  2. If parent is null, then throw an "InvalidNodeTypeError" DOMException.
  3. Set the start of this to boundary point (parent, node’s index).

Range/setStartAfter

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The setStartAfter(node) method steps are:

  1. Let parent be node’s parent.

  2. If parent is null, then throw an "InvalidNodeTypeError" DOMException.

  3. Set the start of this to boundary point (parent, node’s index plus 1).

Range/setEndBefore

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The setEndBefore(node) method steps are:

  1. Let parent be node’s parent.
  2. If parent is null, then throw an "InvalidNodeTypeError" DOMException.
  3. Set the end of this to boundary point (parent, node’s index).

Range/setEndAfter

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The setEndAfter(node) method steps are:

  1. Let parent be node’s parent.

  2. If parent is null, then throw an "InvalidNodeTypeError" DOMException.

  3. Set the end of this to boundary point (parent, node’s index plus 1).

Range/collapse

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The collapse(toStart) method steps are to, if toStart is true, set end to start; otherwise set start to end.

To select a node node within a range range, run these steps:

  1. Let parent be node’s parent.

  2. If parent is null, then throw an "InvalidNodeTypeError" DOMException.

  3. Let index be node’s index.

  4. Set range’s start to boundary point (parent, index).

  5. Set range’s end to boundary point (parent, index plus 1).

Range/selectNode

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The selectNode(node) method steps are to select node within this.

Range/selectNodeContents

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The selectNodeContents(node) method steps are:

  1. If node is a doctype, throw an "InvalidNodeTypeError" DOMException.
  2. Let length be the length of node.
  3. Set start to the boundary point (node, 0).
  4. Set end to the boundary point (node, length).

Range/compareBoundaryPoints

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The compareBoundaryPoints(how, sourceRange) method steps are:

  1. If how is not one of

    then throw a "NotSupportedError" DOMException.

  2. If this’s root is not the same as sourceRange’s root, then throw a "WrongDocumentError" DOMException.
  3. If how is:
    START_TO_START:
    Let this point be this’s start. Let other point be sourceRange’s start.
    START_TO_END:
    Let this point be this’s end. Let other point be sourceRange’s start.
    END_TO_END:
    Let this point be this’s end. Let other point be sourceRange’s end.
    END_TO_START:
    Let this point be this’s start. Let other point be sourceRange’s end.
  4. If the position of this point relative to other point is

    before
    Return −1.
    equal
    Return 0.
    after
    Return 1.

Range/deleteContents

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The deleteContents() method steps are:

  1. If this is collapsed, then return.

  2. Let original start node, original start offset, original end node, and original end offset be this’s start node, start offset, end node, and end offset, respectively.
  3. If original start node is original end node and it is a CharacterData node, then replace data with node original start node, offset original start offset, count original end offset minus original start offset, and data the empty string, and then return.

  4. Let nodes to remove be a list of all the nodes that are contained in this, in tree order, omitting any node whose parent is also contained in this.
  5. If original start node is an inclusive ancestor of original end node, set new node to original start node and new offset to original start offset.
  6. Otherwise:
    1. Let reference node equal original start node.
    2. While reference node’s parent is not null and is not an inclusive ancestor of original end node, set reference node to its parent.
    3. Set new node to the parent of reference node, and new offset to one plus the index of reference node.

      If reference node’s parent were null, it would be the root of this, so would be an inclusive ancestor of original end node, and we could not reach this point.

  7. If original start node is a CharacterData node, then replace data with node original start node, offset original start offset, count original start node’s length minus original start offset, data the empty string.

  8. For each node in nodes to remove, in tree order, remove node.

  9. If original end node is a CharacterData node, then replace data with node original end node, offset 0, count original end offset and data the empty string.

  10. Set start and end to (new node, new offset).

To extract a live range range, run these steps:

  1. Let fragment be a new DocumentFragment node whose node document is range’s start node’s node document.

  2. If range is collapsed, then return fragment.

  3. Let original start node, original start offset, original end node, and original end offset be range’s start node, start offset, end node, and end offset, respectively.
  4. If original start node is original end node and it is a CharacterData node, then:

    1. Let clone be a clone of original start node.
    2. Set the data of clone to the result of substringing data with node original start node, offset original start offset, and count original end offset minus original start offset.
    3. Append clone to fragment.
    4. Replace data with node original start node, offset original start offset, count original end offset minus original start offset, and data the empty string.
    5. Return fragment.
  5. Let common ancestor be original start node.
  6. While common ancestor is not an inclusive ancestor of original end node, set common ancestor to its own parent.
  7. Let first partially contained child be null.
  8. If original start node is not an inclusive ancestor of original end node, set first partially contained child to the first child of common ancestor that is partially contained in range.
  9. Let last partially contained child be null.
  10. If original end node is not an inclusive ancestor of original start node, set last partially contained child to the last child of common ancestor that is partially contained in range.

    These variable assignments do actually always make sense. For instance, if original start node is not an inclusive ancestor of original end node, original start node is itself partially contained in range, and so are all its ancestors up until a child of common ancestor. common ancestor cannot be original start node, because it has to be an inclusive ancestor of original end node. The other case is similar. Also, notice that the two children will never be equal if both are defined.

  11. Let contained children be a list of all children of common ancestor that are contained in range, in tree order.
  12. If any member of contained children is a doctype, then throw a "HierarchyRequestError" DOMException.

    We do not have to worry about the first or last partially contained node, because a doctype can never be partially contained. It cannot be a boundary point of a range, and it cannot be the ancestor of anything.

  13. If original start node is an inclusive ancestor of original end node, set new node to original start node and new offset to original start offset.
  14. Otherwise:
    1. Let reference node equal original start node.
    2. While reference node’s parent is not null and is not an inclusive ancestor of original end node, set reference node to its parent.
    3. Set new node to the parent of reference node, and new offset to one plus reference node’s index.

      If reference node’s parent is null, it would be the root of range, so would be an inclusive ancestor of original end node, and we could not reach this point.

  15. If first partially contained child is a CharacterData node, then:

    In this case, first partially contained child is original start node.

    1. Let clone be a clone of original start node.
    2. Set the data of clone to the result of substringing data with node original start node, offset original start offset, and count original start node’s length minus original start offset.
    3. Append clone to fragment.
    4. Replace data with node original start node, offset original start offset, count original start node’s length minus original start offset, and data the empty string.
  16. Otherwise, if first partially contained child is not null:
    1. Let clone be a clone of first partially contained child.
    2. Append clone to fragment.
    3. Let subrange be a new live range whose start is (original start node, original start offset) and whose end is (first partially contained child, first partially contained child’s length).
    4. Let subfragment be the result of extracting subrange.

    5. Append subfragment to clone.
  17. For each contained child in contained children, append contained child to fragment.
  18. If last partially contained child is a CharacterData node, then:

    In this case, last partially contained child is original end node.

    1. Let clone be a clone of original end node.
    2. Set the data of clone to the result of substringing data with node original end node, offset 0, and count original end offset.
    3. Append clone to fragment.
    4. Replace data with node original end node, offset 0, count original end offset, and data the empty string.
  19. Otherwise, if last partially contained child is not null:
    1. Let clone be a clone of last partially contained child.
    2. Append clone to fragment.
    3. Let subrange be a new live range whose start is (last partially contained child, 0) and whose end is (original end node, original end offset).
    4. Let subfragment be the result of extracting subrange.

    5. Append subfragment to clone.
  20. Set range’s start and end to (new node, new offset).
  21. Return fragment.

Range/extractContents

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The extractContents() method steps are to return the result of extracting this.

To clone the contents of a live range range, run these steps:

  1. Let fragment be a new DocumentFragment node whose node document is range’s start node’s node document.

  2. If range is collapsed, then return fragment.

  3. Let original start node, original start offset, original end node, and original end offset be range’s start node, start offset, end node, and end offset, respectively.
  4. If original start node is original end node and it is a CharacterData node, then:

    1. Let clone be a clone of original start node.
    2. Set the data of clone to the result of substringing data with node original start node, offset original start offset, and count original end offset minus original start offset.
    3. Append clone to fragment.
    4. Return fragment.
  5. Let common ancestor be original start node.
  6. While common ancestor is not an inclusive ancestor of original end node, set common ancestor to its own parent.
  7. Let first partially contained child be null.
  8. If original start node is not an inclusive ancestor of original end node, set first partially contained child to the first child of common ancestor that is partially contained in range.
  9. Let last partially contained child be null.
  10. If original end node is not an inclusive ancestor of original start node, set last partially contained child to the last child of common ancestor that is partially contained in range.

    These variable assignments do actually always make sense. For instance, if original start node is not an inclusive ancestor of original end node, original start node is itself partially contained in range, and so are all its ancestors up until a child of common ancestor. common ancestor cannot be original start node, because it has to be an inclusive ancestor of original end node. The other case is similar. Also, notice that the two children will never be equal if both are defined.

  11. Let contained children be a list of all children of common ancestor that are contained in range, in tree order.
  12. If any member of contained children is a doctype, then throw a "HierarchyRequestError" DOMException.

    We do not have to worry about the first or last partially contained node, because a doctype can never be partially contained. It cannot be a boundary point of a range, and it cannot be the ancestor of anything.

  13. If first partially contained child is a CharacterData node, then:

    In this case, first partially contained child is original start node.

    1. Let clone be a clone of original start node.
    2. Set the data of clone to the result of substringing data with node original start node, offset original start offset, and count original start node’s length minus original start offset.
    3. Append clone to fragment.
  14. Otherwise, if first partially contained child is not null:
    1. Let clone be a clone of first partially contained child.
    2. Append clone to fragment.
    3. Let subrange be a new live range whose start is (original start node, original start offset) and whose end is (first partially contained child, first partially contained child’s length).
    4. Let subfragment be the result of cloning the contents of subrange.

    5. Append subfragment to clone.
  15. For each contained child in contained children:
    1. Let clone be a clone of contained child with the clone children flag set.
    2. Append clone to fragment.
  16. If last partially contained child is a CharacterData node, then:

    In this case, last partially contained child is original end node.

    1. Let clone be a clone of original end node.
    2. Set the data of clone to the result of substringing data with node original end node, offset 0, and count original end offset.
    3. Append clone to fragment.
  17. Otherwise, if last partially contained child is not null:
    1. Let clone be a clone of last partially contained child.
    2. Append clone to fragment.
    3. Let subrange be a new live range whose start is (last partially contained child, 0) and whose end is (original end node, original end offset).
    4. Let subfragment be the result of cloning the contents of subrange.

    5. Append subfragment to clone.
  18. Return fragment.

Range/cloneContents

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The cloneContents() method steps are to return the result of cloning the contents of this.

To insert a node node into a live range range, run these steps:

  1. If range’s start node is a ProcessingInstruction or Comment node, is a Text node whose parent is null, or is node, then throw a "HierarchyRequestError" DOMException.
  2. Let referenceNode be null.
  3. If range’s start node is a Text node, set referenceNode to that Text node.
  4. Otherwise, set referenceNode to the child of start node whose index is start offset, and null if there is no such child.
  5. Let parent be range’s start node if referenceNode is null, and referenceNode’s parent otherwise.
  6. Ensure pre-insertion validity of node into parent before referenceNode.
  7. If range’s start node is a Text node, set referenceNode to the result of splitting it with offset range’s start offset.
  8. If node is referenceNode, set referenceNode to its next sibling.
  9. If node’s parent is non-null, then remove node.

  10. Let newOffset be parent’s length if referenceNode is null, and referenceNode’s index otherwise.
  11. Increase newOffset by node’s length if node is a DocumentFragment node, and one otherwise.
  12. Pre-insert node into parent before referenceNode.
  13. If range is collapsed, then set range’s end to (parent, newOffset).

Range/insertNode

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The insertNode(node) method steps are to insert node into this.

Range/surroundContents

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The surroundContents(newParent) method steps are:

  1. If a non-Text node is partially contained in this, then throw an "InvalidStateError" DOMException.

  2. If newParent is a Document, DocumentType, or DocumentFragment node, then throw an "InvalidNodeTypeError" DOMException.

    For historical reasons CharacterData nodes are not checked here and end up throwing later on as a side effect.

  3. Let fragment be the result of extracting this.

  4. If newParent has children, then replace all with null within newParent.

  5. Insert newParent into this.

  6. Append fragment to newParent.

  7. Select newParent within this.

Range/cloneRange

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The cloneRange() method steps are to return a new live range with the same start and end as this.

Range/detach

Firefox1–15Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The detach() method steps are to do nothing. Its functionality (disabling a Range object) was removed, but the method itself is preserved for compatibility.


Range/comparePoint

In all current engines.

Firefox1+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)17+IENone
Firefox for Android?iOS Safari1+Chrome for Android?Android WebView?Samsung Internet?Opera Mobile12.1+
position = range . comparePoint(node, offset)
Returns −1 if the point is before the range, 0 if the point is in the range, and 1 if the point is after the range.

Range/intersectsNode

In all current engines.

Firefox17+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)17+IENone
Firefox for Android19+iOS Safari1+Chrome for Android?Android WebView?Samsung Internet?Opera Mobile12.1+
intersects = range . intersectsNode(node)
Returns whether range intersects node.

Range/isPointInRange

In all current engines.

Firefox1+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari1+Chrome for Android?Android WebView?Samsung Internet?Opera Mobile12.1+

The isPointInRange(node, offset) method steps are:

  1. If node’s root is different from this’s root, return false.
  2. If node is a doctype, then throw an "InvalidNodeTypeError" DOMException.
  3. If offset is greater than node’s length, then throw an "IndexSizeError" DOMException.
  4. If (node, offset) is before start or after end, return false.
  5. Return true.

The comparePoint(node, offset) method steps are:

  1. If node’s root is different from this’s root, then throw a "WrongDocumentError" DOMException.
  2. If node is a doctype, then throw an "InvalidNodeTypeError" DOMException.
  3. If offset is greater than node’s length, then throw an "IndexSizeError" DOMException.
  4. If (node, offset) is before start, return −1.
  5. If (node, offset) is after end, return 1.
  6. Return 0.

The intersectsNode(node) method steps are:

  1. If node’s root is different from this’s root, return false.
  2. Let parent be node’s parent.
  3. If parent is null, return true.
  4. Let offset be node’s index.
  5. If (parent, offset) is before end and (parent, offset plus 1) is after start, return true.
  6. Return false.

Range/toString

In all current engines.

Firefox1+Safari1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+IE9+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile10.1+

The stringification behavior must run these steps:

  1. Let s be the empty string.

  2. If this’s start node is this’s end node and it is a Text node, then return the substring of that Text node’s data beginning at this’s start offset and ending at this’s end offset.

  3. If this’s start node is a Text node, then append the substring of that node’s data from this’s start offset until the end to s.

  4. Append the concatenation of the data of all Text nodes that are contained in this, in tree order, to s.

  5. If this’s end node is a Text node, then append the substring of that node’s data from its start until this’s end offset to s.

  6. Return s.


The createContextualFragment(), getClientRects(), and getBoundingClientRect() methods are defined in other specifications. [DOM-Parsing] [CSSOM-VIEW]