{"id":133,"date":"2002-12-07T19:21:46","date_gmt":"2002-12-08T00:21:46","guid":{"rendered":"http:\/\/sovogo.com\/2002\/12\/07\/dom-2-range-with-javascript\/"},"modified":"2006-12-07T19:31:11","modified_gmt":"2006-12-08T00:31:11","slug":"dom-2-range-with-javascript","status":"publish","type":"post","link":"https:\/\/dylanschiemann.com\/?p=133","title":{"rendered":"DOM 2 Range with JavaScript"},"content":{"rendered":"<p>This article describes using the DOM 2 Range with JavaScript and describes its support in mozilla.  I put this together rather quickly and it isn&#8217;t very robust, but it is better than nothing.  Send bugs and comments to mail[@]dylans.org (without the brackets)<\/p>\n<h3>Overview:<\/h3>\n<p>A Range selects all content between a pair of boundary points, and the Range interface provides methods for accessing and manipulating the document tree at a higher level than similar methods in the Node interface.  Each of the methods in the Range interface maps directly to a series of DOM Core Methods, so the Range interface is actually just a set of convenience methods to make such manipulations tolerable.<\/p>\n<p>Currently, all of the examples here will only work in Mozilla-based browsers, as it is not supported in IE 5, 5.5, or 6.0.<\/p>\n<p><a href=\"\/articles\/dom2Range\/dom2RangeExamples.html\">Examples<\/a><\/p>\n<h3>hasFeature:<\/h3>\n<p>This Core DOM method returns a boolean for whether the feature is supported or not.<\/p>\n<p>document.implementation.hasFeature(&#8220;Range&#8221;,&#8221;2.0&#8243;);<\/p>\n<h3>Creating a Range:<\/h3>\n<p>Method:<br \/>\n\tcreateRange()<\/p>\n<p>Supported in Mozilla<\/p>\n<p>This creates a Range with offset 0 and container is the Document node.<\/p>\n<p>Example:<br \/>\n\tdocument.createRange();<\/p>\n<h3>Position:<\/h3>\n<p>A Range is defined by the position of its two boundary points, the start and end of a range.  The position in a Document or DocumentFragment tree is represented by a node and an offset.  The boundary points must have a common ancestor container which is either a Document, DocumentFragment, or Attr node.  This common ancestor is the root container of the Range, and contains the Range&#8217;s context tree.<\/p>\n<p>The boundary point contains a reference to a node, and the offset, which is different for nodes which inherit from the Character Data interface (Text, Comment and CDATASection nodes) and those which do not.  For the Character Data interface inheriting nodes, the offset is the 16-bit unit position.  For example, an offset of four for a text node that has standard English text would mean that the selection was after the fourth letter.  For the other node types, the offset is an integer that describes where it is in the childNodes hierarchy.  For example, an offset of 2 would be between the second and third child nodes.<\/p>\n<p>To read the position for the offset and container node, use the following methods:<\/p>\n<p>\tstartContainer, startOffset, endContainer, endOffset<\/p>\n<p>This is currently supported in Mozilla.  The valid syntax to retrieve the startContainer for a valid Range testRange is<\/p>\n<p>\ttestRange.startContainer;<\/p>\n<p>This requires our Range to have a start and end position.  This will be tested to show that the setting of start and end works correctly.<\/p>\n<h3>Selection:<\/h3>\n<p>A node or CDATA unit is selected if it is between the two boundary points of a Range.  A node is partially selected by a Range if it is an ancestor container to exactly one of the boundary points.<\/p>\n<p>Changing a Range&#8217;s Position:<\/p>\n<p>Methods:<br \/>\n\tsetStart(parent,offset)<br \/>\n\tsetEnd(parent,offset)<\/p>\n<p>\twhere parent is the container node and offset is an integer\n<\/p>\n<p>Supported in Mozilla<\/p>\n<p>Example:<br \/>\n\ttestRange.setStart(document.getElementsByTagName(&#8220;div&#8221;).item(0),0);<br \/>\n\ttestRange.setEnd(document.getElementsByTagName(&#8220;div&#8221;).item(0),1);\n<\/p>\n<p>This is one way to select where a Range starts and ends.  You can also set a Range&#8217;s position relative to nodes in the tree:<\/p>\n<p>\nMethods:<br \/>\n\tsetStartBefore(node);<br \/>\n\tsetStartAfter(node);<br \/>\n\tsetEndBefore(node);<br \/>\n\tsetEndAfter(node);\n<\/p>\n<p>Implemented correctly in Mozilla<\/p>\n<p>Example:<br \/>\n\ttestRange.setStartBefore(document.getElementsByTagName(&#8220;div&#8221;).item(0));<br \/>\n\ttestRange.setEndAfter(document.getElementsByTagName(&#8220;div&#8221;).item(0));<\/p>\n<p>You can also collapse a Range to one of its boundary points.<\/p>\n<p>Methods:<br \/>\n\tcollapse(bool)<br \/>\n\twhere bool is &#8220;TRUE&#8221; to collapse to the start boudnary point, and &#8220;FALSE&#8221; to collapse to the end boundary point\n<\/p>\n<p>Attributes:<br \/>\n\t.collapsed\n<\/p>\n<p>Supported in Mozilla<\/p>\n<p>Examples:<br \/>\n\ttestRange.collapse(&#8220;TRUE&#8221;);<br \/>\n\talert(testRange.collapsed); \/\/ should return true\n<\/p>\n<p>You can also have a Range directly that will directly select a Node or its contents<\/p>\n<p>Methods:<br \/>\n\tselectNode(node)<br \/>\n\tselectNodeContents(node)\n<\/p>\n<p>supported in Mozilla<\/p>\n<p>Example:<br \/>\n\ttestRange.selectNode(document.getElementsByTagName(&#8220;div&#8221;).item(0));\n<\/p>\n<h3>Comparing two Ranges by their Boundary Points<\/h3>\n<p>Method:<br \/>\n\tcompareBoundaryPoints(how,sourceRange)\n<\/p>\n<p>\thow is one of four values, START_TO_START,START_TO_END,END_TO_END,and END_TO_START, which equal the constants 0,1,2,3<br \/>\n\tthe sourceRange is the Range which you are comparing to.\n<\/p>\n<p>\tIt returns either -1,0,1 dpending on whether the corresponding boundary point is before, equal to, or after the boundary point of sourceRange.\n<\/p>\n<p>Fixed in Mozilla implementations after December, 2000. (see <a href=\"http:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=58028\">bug #58028<\/a>).. returns -1 instead of 1 and vice versa<\/p>\n<p>Example:<br \/>\n\ttestRange.selectNode(document.getElementsByTagName(&#8220;div&#8221;).item(0));<br \/>\n\ttestRange2.selectNode(document.getElementsByTagName(&#8220;div&#8221;).item(1));<br \/>\n\talert(testRange.compareBoundaryPoints(0,testRange2)); \/\/ should return -1\n<\/p>\n<h3>Deleting Content in a Range:<\/h3>\n<p>Method:<br \/>\n\tdeleteContents()\n<\/p>\n<p>The Range is collapsed upon deletion<\/p>\n<p>This is supported in Mozilla, but there are reported bugs such as <a href=\"http:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=43535\">#43535<\/a> which says sometimes too much is deleted<\/p>\n<p>Example:<br \/>\n\ttestRange.deleteContents();\n<\/p>\n<h3>Extracting Contents (like Cut) from a Range:<\/h3>\n<p>Method:<br \/>\n\textractContents()\n<\/p>\n<p>The Range is deleted from the document and is placed and returned in a new DocumentFragment.  Partially Selected Nodes are cloned.\n<\/p>\n<p>Fixed in Mozilla in May, 2001.  Refer to bug <a href=\"http:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=58969\">#58969<\/a>\n<\/p>\n<p>Example:<br \/>\n\ttestFragment = testRange.extractContents();\n<\/p>\n<h3>Cloning Content (like Copy) in a Range<\/h3>\n<p>Method:<br \/>\n\tcloneContents()\n<\/p>\n<p>Clones the contents of a Range into a new DocumentFragment with boundaryPoints equal to those in the existing Range<\/p>\n<p>Fixed in Mozilla in May, 2001.  Refer to bug Refer to bug <a href=\"http:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=58969\">#58969<\/a>.\n<\/p>\n<p>Example:<br \/>\n\tclonedFragment = testRange.cloneContents();\n<\/p>\n<h3>Inserting Content in a Range<\/h3>\n<p>Method:<br \/>\n\tinsertNode(node)\n<\/p>\n<p>Inserts a node into the Range at the starting boundary point, following rules similiar to DOM Core method insertBefore().  If the start of the Range is in a text node, that node will be split, even if the new inserted node is all text.\n<\/p>\n<p>Fixed in Mozilla in May, 2001.  Refer to bug Refer to bug <a href=\"http:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=58972\">#58972<\/a>\n<\/p>\n<p>Example:<br \/>\n\ttestRange.insertNode(document.createTextNode(&#8220;Insert This Text &#8220;));\n<\/p>\n<p>Subsuming Content Selected by a Range (Wrapping the Range inside its own node)<\/p>\n<p>Method:<br \/>\n\tsurroundContents(newParent)\n<\/p>\n<p>Fixed in Mozilla in May, 2001.  Refer to bug Refer to bug <a href=\"http:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=58974\">#58974<\/a>\n<\/p>\n<p>Example:<\/p>\n<p>\ttestRange.surroundContents(document.createElement(&#8220;div&#8221;));\n<\/p>\n<ol>It is equivalent to the following series of steps:<\/p>\n<li>extractContents()<\/li>\n<li>insert newParent where the Range is collapsed (after extraction) with insertNode()<\/li>\n<li>insert contents of extracted DocumentFragment into newParent using newParent.appendChild()<\/li>\n<li>select newParent and all of its content using newParent.selectNode()<\/li>\n<\/ol>\n<p>An exception is raised if Range partially selects a non-text node<\/p>\n<p>If newParent has any children, they are removed before its insertion, and if it has a parent, it is removed from its parent&#8217;s childNodes list.<\/p>\n<h3>Cloning a Range:<\/h3>\n<p>Method:<br \/>\n\tcloneRange()\n<\/p>\n<p>Clones the Range itself.<\/p>\n<p>This is supported in Mozilla<\/p>\n<p>Example:<br \/>\n\ttestRange2 = testRange.cloneRange();\n<\/p>\n<h3>Getting an ancestor container:<\/h3>\n<p>Attribute<br \/>\n\tcommonAncestorContainer\n<\/p>\n<p>This gives the ancestor for the boundary points of a Range that is furthest down from the root<\/p>\n<p>This is supported in Mozilla\n<\/p>\n<p>Example:<br \/>\n\ttestRange.commonAncestorContainer;\n<\/p>\n<p>Get a copy of all character data in a Range:\n<\/p>\n<p>Method:<br \/>\n\ttoString()\n<\/p>\n<p>This returns the CDATA in a Range\n<\/p>\n<p>This is supported in Mozilla\n<\/p>\n<p>Example:<br \/>\n\ttestRange.toString();\n<\/p>\n<p>Implementation can remove a Range from resources\n<\/p>\n<p>Method:<br \/>\n\tdetach()\n<\/p>\n<p>I do not think JavaScript developers need to worry about this unless they are worried about performance with a lot of Ranges\n<\/p>\n<p>This is supported in Mozilla\n<\/p>\n<p>Example:<br \/>\n\ttestRange.detach();<br \/>\n\talert(testRange); \/\/should alert &#8220;&#8221;\n<\/p>\n<h3>Normalization (part of DOM CORE)<\/h3>\n<p>Method:<br \/>\n\tnormalize()\n<\/p>\n<p>Used to combine adjacent text nodes and removed empty text nodes from a node\n<\/p>\n<p>This is supported in Mozilla\n<\/p>\n<p>Example:<br \/>\n\tdocument.getElementByTagName(&#8220;div&#8221;).item(0).normalize();\n<\/p>\n<h3>Document Mutations:<\/h3>\n<p>This section simply describes what happens to a Range when a document is mutated by insertion or deletion<\/p>\n<p>All Ranges remain valid after an mutation operation, and they select the same portion of the docuemtn after mutation.\n<\/p>\n<p>Insertion occurs at a single insertion point.  The boundary point of the Range changes upon insertion if they have the same container and the offset of the insertion point is less than the offset of the range boundary point.  This will change the end boundary point by increasing its offset.  The boundary point will be placed at the start of the newly inserted content if the boundary point and insertion point are equivalent.\n<\/p>\n<p>Deletion will affect the Range is the boundary point of the original Range is within the content being deleted.  After deletion, it will be a thte same position as the resulting boundary point of the now collapsed Range used to delete the contents.\n<\/p>\n<p>This behavior is supported in Mozilla, though it is highly probable that there are some quirks.\n<\/p>\n<p><a href=\"\/articles\/dom2Range\/dom2RangeExamples.html\">Examples<\/a><\/p>\n<p><a href=\"http:\/\/bugzilla.mozilla.org\/buglist.cgi?bug_status=UNCONFIRMED&#038;bug_status=NEW&#038;bug_status=ASSIGNED&#038;bug_status=REOPENED&#038;bug_status=RESOLVED&#038;bug_status=VERIFIED&#038;bug_status=CLOSED&#038;email1=&#038;emailtype1=substring&#038;emailassigned_to1=1&#038;email2=&#038;emailtype2=substring&#038;emailreporter2=1&#038;bugidtype=include&#038;bug_id=&#038;changedin=&#038;votes=&#038;chfieldfrom=&#038;chfieldto=Now&#038;chfieldvalue=&#038;component=DOM+Traversal-Range&#038;short_desc=&#038;short_desc_type=allwordssubstr&#038;long_desc=&#038;long_desc_type=allwordssubstr&#038;bug_file_loc=&#038;bug_file_loc_type=allwordssubstr&#038;status_whiteboard=&#038;status_whiteboard_type=allwordssubstr&#038;keywords=&#038;keywords_type=anywords&#038;field0-0-0=noop&#038;type0-0-0=noop&#038;value0-0-0=&#038;cmdtype=doit&#038;order=Reuse+same+sort+as+last+time\">All Reported DOM Range and Traversal bugs in mozilla<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article describes using the DOM 2 Range with JavaScript and describes its support in mozilla. I put this together rather quickly and it isn&#8217;t very robust, but it is better than nothing. Send bugs and comments to mail[@]dylans.org (without the brackets) Overview: A Range selects all content between a pair of boundary points, and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6,1,9],"tags":[],"_links":{"self":[{"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=\/wp\/v2\/posts\/133"}],"collection":[{"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=133"}],"version-history":[{"count":0,"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=\/wp\/v2\/posts\/133\/revisions"}],"wp:attachment":[{"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dylanschiemann.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}