src/pyams_skin/resources/js/ext/tinymce/dev/classes/dom/Range.js
changeset 566 a1707c607eec
parent 565 318533413200
child 567 bca1726b1d85
equal deleted inserted replaced
565:318533413200 566:a1707c607eec
     1 /**
       
     2  * Range.js
       
     3  *
       
     4  * Copyright, Moxiecode Systems AB
       
     5  * Released under LGPL License.
       
     6  *
       
     7  * License: http://www.tinymce.com/license
       
     8  * Contributing: http://www.tinymce.com/contributing
       
     9  */
       
    10 
       
    11 define("tinymce/dom/Range", [
       
    12 	"tinymce/util/Tools"
       
    13 ], function(Tools) {
       
    14 	// Range constructor
       
    15 	function Range(dom) {
       
    16 		var self = this,
       
    17 			doc = dom.doc,
       
    18 			EXTRACT = 0,
       
    19 			CLONE = 1,
       
    20 			DELETE = 2,
       
    21 			TRUE = true,
       
    22 			FALSE = false,
       
    23 			START_OFFSET = 'startOffset',
       
    24 			START_CONTAINER = 'startContainer',
       
    25 			END_CONTAINER = 'endContainer',
       
    26 			END_OFFSET = 'endOffset',
       
    27 			extend = Tools.extend,
       
    28 			nodeIndex = dom.nodeIndex;
       
    29 
       
    30 		function createDocumentFragment() {
       
    31 			return doc.createDocumentFragment();
       
    32 		}
       
    33 
       
    34 		function setStart(n, o) {
       
    35 			_setEndPoint(TRUE, n, o);
       
    36 		}
       
    37 
       
    38 		function setEnd(n, o) {
       
    39 			_setEndPoint(FALSE, n, o);
       
    40 		}
       
    41 
       
    42 		function setStartBefore(n) {
       
    43 			setStart(n.parentNode, nodeIndex(n));
       
    44 		}
       
    45 
       
    46 		function setStartAfter(n) {
       
    47 			setStart(n.parentNode, nodeIndex(n) + 1);
       
    48 		}
       
    49 
       
    50 		function setEndBefore(n) {
       
    51 			setEnd(n.parentNode, nodeIndex(n));
       
    52 		}
       
    53 
       
    54 		function setEndAfter(n) {
       
    55 			setEnd(n.parentNode, nodeIndex(n) + 1);
       
    56 		}
       
    57 
       
    58 		function collapse(ts) {
       
    59 			if (ts) {
       
    60 				self[END_CONTAINER] = self[START_CONTAINER];
       
    61 				self[END_OFFSET] = self[START_OFFSET];
       
    62 			} else {
       
    63 				self[START_CONTAINER] = self[END_CONTAINER];
       
    64 				self[START_OFFSET] = self[END_OFFSET];
       
    65 			}
       
    66 
       
    67 			self.collapsed = TRUE;
       
    68 		}
       
    69 
       
    70 		function selectNode(n) {
       
    71 			setStartBefore(n);
       
    72 			setEndAfter(n);
       
    73 		}
       
    74 
       
    75 		function selectNodeContents(n) {
       
    76 			setStart(n, 0);
       
    77 			setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length);
       
    78 		}
       
    79 
       
    80 		function compareBoundaryPoints(h, r) {
       
    81 			var sc = self[START_CONTAINER], so = self[START_OFFSET], ec = self[END_CONTAINER], eo = self[END_OFFSET],
       
    82 			rsc = r.startContainer, rso = r.startOffset, rec = r.endContainer, reo = r.endOffset;
       
    83 
       
    84 			// Check START_TO_START
       
    85 			if (h === 0) {
       
    86 				return _compareBoundaryPoints(sc, so, rsc, rso);
       
    87 			}
       
    88 
       
    89 			// Check START_TO_END
       
    90 			if (h === 1) {
       
    91 				return _compareBoundaryPoints(ec, eo, rsc, rso);
       
    92 			}
       
    93 
       
    94 			// Check END_TO_END
       
    95 			if (h === 2) {
       
    96 				return _compareBoundaryPoints(ec, eo, rec, reo);
       
    97 			}
       
    98 
       
    99 			// Check END_TO_START
       
   100 			if (h === 3) {
       
   101 				return _compareBoundaryPoints(sc, so, rec, reo);
       
   102 			}
       
   103 		}
       
   104 
       
   105 		function deleteContents() {
       
   106 			_traverse(DELETE);
       
   107 		}
       
   108 
       
   109 		function extractContents() {
       
   110 			return _traverse(EXTRACT);
       
   111 		}
       
   112 
       
   113 		function cloneContents() {
       
   114 			return _traverse(CLONE);
       
   115 		}
       
   116 
       
   117 		function insertNode(n) {
       
   118 			var startContainer = this[START_CONTAINER],
       
   119 				startOffset = this[START_OFFSET], nn, o;
       
   120 
       
   121 			// Node is TEXT_NODE or CDATA
       
   122 			if ((startContainer.nodeType === 3 || startContainer.nodeType === 4) && startContainer.nodeValue) {
       
   123 				if (!startOffset) {
       
   124 					// At the start of text
       
   125 					startContainer.parentNode.insertBefore(n, startContainer);
       
   126 				} else if (startOffset >= startContainer.nodeValue.length) {
       
   127 					// At the end of text
       
   128 					dom.insertAfter(n, startContainer);
       
   129 				} else {
       
   130 					// Middle, need to split
       
   131 					nn = startContainer.splitText(startOffset);
       
   132 					startContainer.parentNode.insertBefore(n, nn);
       
   133 				}
       
   134 			} else {
       
   135 				// Insert element node
       
   136 				if (startContainer.childNodes.length > 0) {
       
   137 					o = startContainer.childNodes[startOffset];
       
   138 				}
       
   139 
       
   140 				if (o) {
       
   141 					startContainer.insertBefore(n, o);
       
   142 				} else {
       
   143 					if (startContainer.nodeType == 3) {
       
   144 						dom.insertAfter(n, startContainer);
       
   145 					} else {
       
   146 						startContainer.appendChild(n);
       
   147 					}
       
   148 				}
       
   149 			}
       
   150 		}
       
   151 
       
   152 		function surroundContents(n) {
       
   153 			var f = self.extractContents();
       
   154 
       
   155 			self.insertNode(n);
       
   156 			n.appendChild(f);
       
   157 			self.selectNode(n);
       
   158 		}
       
   159 
       
   160 		function cloneRange() {
       
   161 			return extend(new Range(dom), {
       
   162 				startContainer: self[START_CONTAINER],
       
   163 				startOffset: self[START_OFFSET],
       
   164 				endContainer: self[END_CONTAINER],
       
   165 				endOffset: self[END_OFFSET],
       
   166 				collapsed: self.collapsed,
       
   167 				commonAncestorContainer: self.commonAncestorContainer
       
   168 			});
       
   169 		}
       
   170 
       
   171 		// Private methods
       
   172 
       
   173 		function _getSelectedNode(container, offset) {
       
   174 			var child;
       
   175 
       
   176 			if (container.nodeType == 3 /* TEXT_NODE */) {
       
   177 				return container;
       
   178 			}
       
   179 
       
   180 			if (offset < 0) {
       
   181 				return container;
       
   182 			}
       
   183 
       
   184 			child = container.firstChild;
       
   185 			while (child && offset > 0) {
       
   186 				--offset;
       
   187 				child = child.nextSibling;
       
   188 			}
       
   189 
       
   190 			if (child) {
       
   191 				return child;
       
   192 			}
       
   193 
       
   194 			return container;
       
   195 		}
       
   196 
       
   197 		function _isCollapsed() {
       
   198 			return (self[START_CONTAINER] == self[END_CONTAINER] && self[START_OFFSET] == self[END_OFFSET]);
       
   199 		}
       
   200 
       
   201 		function _compareBoundaryPoints(containerA, offsetA, containerB, offsetB) {
       
   202 			var c, offsetC, n, cmnRoot, childA, childB;
       
   203 
       
   204 			// In the first case the boundary-points have the same container. A is before B
       
   205 			// if its offset is less than the offset of B, A is equal to B if its offset is
       
   206 			// equal to the offset of B, and A is after B if its offset is greater than the
       
   207 			// offset of B.
       
   208 			if (containerA == containerB) {
       
   209 				if (offsetA == offsetB) {
       
   210 					return 0; // equal
       
   211 				}
       
   212 
       
   213 				if (offsetA < offsetB) {
       
   214 					return -1; // before
       
   215 				}
       
   216 
       
   217 				return 1; // after
       
   218 			}
       
   219 
       
   220 			// In the second case a child node C of the container of A is an ancestor
       
   221 			// container of B. In this case, A is before B if the offset of A is less than or
       
   222 			// equal to the index of the child node C and A is after B otherwise.
       
   223 			c = containerB;
       
   224 			while (c && c.parentNode != containerA) {
       
   225 				c = c.parentNode;
       
   226 			}
       
   227 
       
   228 			if (c) {
       
   229 				offsetC = 0;
       
   230 				n = containerA.firstChild;
       
   231 
       
   232 				while (n != c && offsetC < offsetA) {
       
   233 					offsetC++;
       
   234 					n = n.nextSibling;
       
   235 				}
       
   236 
       
   237 				if (offsetA <= offsetC) {
       
   238 					return -1; // before
       
   239 				}
       
   240 
       
   241 				return 1; // after
       
   242 			}
       
   243 
       
   244 			// In the third case a child node C of the container of B is an ancestor container
       
   245 			// of A. In this case, A is before B if the index of the child node C is less than
       
   246 			// the offset of B and A is after B otherwise.
       
   247 			c = containerA;
       
   248 			while (c && c.parentNode != containerB) {
       
   249 				c = c.parentNode;
       
   250 			}
       
   251 
       
   252 			if (c) {
       
   253 				offsetC = 0;
       
   254 				n = containerB.firstChild;
       
   255 
       
   256 				while (n != c && offsetC < offsetB) {
       
   257 					offsetC++;
       
   258 					n = n.nextSibling;
       
   259 				}
       
   260 
       
   261 				if (offsetC < offsetB) {
       
   262 					return -1; // before
       
   263 				}
       
   264 
       
   265 				return 1; // after
       
   266 			}
       
   267 
       
   268 			// In the fourth case, none of three other cases hold: the containers of A and B
       
   269 			// are siblings or descendants of sibling nodes. In this case, A is before B if
       
   270 			// the container of A is before the container of B in a pre-order traversal of the
       
   271 			// Ranges' context tree and A is after B otherwise.
       
   272 			cmnRoot = dom.findCommonAncestor(containerA, containerB);
       
   273 			childA = containerA;
       
   274 
       
   275 			while (childA && childA.parentNode != cmnRoot) {
       
   276 				childA = childA.parentNode;
       
   277 			}
       
   278 
       
   279 			if (!childA) {
       
   280 				childA = cmnRoot;
       
   281 			}
       
   282 
       
   283 			childB = containerB;
       
   284 			while (childB && childB.parentNode != cmnRoot) {
       
   285 				childB = childB.parentNode;
       
   286 			}
       
   287 
       
   288 			if (!childB) {
       
   289 				childB = cmnRoot;
       
   290 			}
       
   291 
       
   292 			if (childA == childB) {
       
   293 				return 0; // equal
       
   294 			}
       
   295 
       
   296 			n = cmnRoot.firstChild;
       
   297 			while (n) {
       
   298 				if (n == childA) {
       
   299 					return -1; // before
       
   300 				}
       
   301 
       
   302 				if (n == childB) {
       
   303 					return 1; // after
       
   304 				}
       
   305 
       
   306 				n = n.nextSibling;
       
   307 			}
       
   308 		}
       
   309 
       
   310 		function _setEndPoint(st, n, o) {
       
   311 			var ec, sc;
       
   312 
       
   313 			if (st) {
       
   314 				self[START_CONTAINER] = n;
       
   315 				self[START_OFFSET] = o;
       
   316 			} else {
       
   317 				self[END_CONTAINER] = n;
       
   318 				self[END_OFFSET] = o;
       
   319 			}
       
   320 
       
   321 			// If one boundary-point of a Range is set to have a root container
       
   322 			// other than the current one for the Range, the Range is collapsed to
       
   323 			// the new position. This enforces the restriction that both boundary-
       
   324 			// points of a Range must have the same root container.
       
   325 			ec = self[END_CONTAINER];
       
   326 			while (ec.parentNode) {
       
   327 				ec = ec.parentNode;
       
   328 			}
       
   329 
       
   330 			sc = self[START_CONTAINER];
       
   331 			while (sc.parentNode) {
       
   332 				sc = sc.parentNode;
       
   333 			}
       
   334 
       
   335 			if (sc == ec) {
       
   336 				// The start position of a Range is guaranteed to never be after the
       
   337 				// end position. To enforce this restriction, if the start is set to
       
   338 				// be at a position after the end, the Range is collapsed to that
       
   339 				// position.
       
   340 				if (_compareBoundaryPoints(self[START_CONTAINER], self[START_OFFSET], self[END_CONTAINER], self[END_OFFSET]) > 0) {
       
   341 					self.collapse(st);
       
   342 				}
       
   343 			} else {
       
   344 				self.collapse(st);
       
   345 			}
       
   346 
       
   347 			self.collapsed = _isCollapsed();
       
   348 			self.commonAncestorContainer = dom.findCommonAncestor(self[START_CONTAINER], self[END_CONTAINER]);
       
   349 		}
       
   350 
       
   351 		function _traverse(how) {
       
   352 			var c, endContainerDepth = 0, startContainerDepth = 0, p, depthDiff, startNode, endNode, sp, ep;
       
   353 
       
   354 			if (self[START_CONTAINER] == self[END_CONTAINER]) {
       
   355 				return _traverseSameContainer(how);
       
   356 			}
       
   357 
       
   358 			for (c = self[END_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) {
       
   359 				if (p == self[START_CONTAINER]) {
       
   360 					return _traverseCommonStartContainer(c, how);
       
   361 				}
       
   362 
       
   363 				++endContainerDepth;
       
   364 			}
       
   365 
       
   366 			for (c = self[START_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) {
       
   367 				if (p == self[END_CONTAINER]) {
       
   368 					return _traverseCommonEndContainer(c, how);
       
   369 				}
       
   370 
       
   371 				++startContainerDepth;
       
   372 			}
       
   373 
       
   374 			depthDiff = startContainerDepth - endContainerDepth;
       
   375 
       
   376 			startNode = self[START_CONTAINER];
       
   377 			while (depthDiff > 0) {
       
   378 				startNode = startNode.parentNode;
       
   379 				depthDiff--;
       
   380 			}
       
   381 
       
   382 			endNode = self[END_CONTAINER];
       
   383 			while (depthDiff < 0) {
       
   384 				endNode = endNode.parentNode;
       
   385 				depthDiff++;
       
   386 			}
       
   387 
       
   388 			// ascend the ancestor hierarchy until we have a common parent.
       
   389 			for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) {
       
   390 				startNode = sp;
       
   391 				endNode = ep;
       
   392 			}
       
   393 
       
   394 			return _traverseCommonAncestors(startNode, endNode, how);
       
   395 		}
       
   396 
       
   397 		function _traverseSameContainer(how) {
       
   398 			var frag, s, sub, n, cnt, sibling, xferNode, start, len;
       
   399 
       
   400 			if (how != DELETE) {
       
   401 				frag = createDocumentFragment();
       
   402 			}
       
   403 
       
   404 			// If selection is empty, just return the fragment
       
   405 			if (self[START_OFFSET] == self[END_OFFSET]) {
       
   406 				return frag;
       
   407 			}
       
   408 
       
   409 			// Text node needs special case handling
       
   410 			if (self[START_CONTAINER].nodeType == 3 /* TEXT_NODE */) {
       
   411 				// get the substring
       
   412 				s = self[START_CONTAINER].nodeValue;
       
   413 				sub = s.substring(self[START_OFFSET], self[END_OFFSET]);
       
   414 
       
   415 				// set the original text node to its new value
       
   416 				if (how != CLONE) {
       
   417 					n = self[START_CONTAINER];
       
   418 					start = self[START_OFFSET];
       
   419 					len = self[END_OFFSET] - self[START_OFFSET];
       
   420 
       
   421 					if (start === 0 && len >= n.nodeValue.length - 1) {
       
   422 						n.parentNode.removeChild(n);
       
   423 					} else {
       
   424 						n.deleteData(start, len);
       
   425 					}
       
   426 
       
   427 					// Nothing is partially selected, so collapse to start point
       
   428 					self.collapse(TRUE);
       
   429 				}
       
   430 
       
   431 				if (how == DELETE) {
       
   432 					return;
       
   433 				}
       
   434 
       
   435 				if (sub.length > 0) {
       
   436 					frag.appendChild(doc.createTextNode(sub));
       
   437 				}
       
   438 
       
   439 				return frag;
       
   440 			}
       
   441 
       
   442 			// Copy nodes between the start/end offsets.
       
   443 			n = _getSelectedNode(self[START_CONTAINER], self[START_OFFSET]);
       
   444 			cnt = self[END_OFFSET] - self[START_OFFSET];
       
   445 
       
   446 			while (n && cnt > 0) {
       
   447 				sibling = n.nextSibling;
       
   448 				xferNode = _traverseFullySelected(n, how);
       
   449 
       
   450 				if (frag) {
       
   451 					frag.appendChild(xferNode);
       
   452 				}
       
   453 
       
   454 				--cnt;
       
   455 				n = sibling;
       
   456 			}
       
   457 
       
   458 			// Nothing is partially selected, so collapse to start point
       
   459 			if (how != CLONE) {
       
   460 				self.collapse(TRUE);
       
   461 			}
       
   462 
       
   463 			return frag;
       
   464 		}
       
   465 
       
   466 		function _traverseCommonStartContainer(endAncestor, how) {
       
   467 			var frag, n, endIdx, cnt, sibling, xferNode;
       
   468 
       
   469 			if (how != DELETE) {
       
   470 				frag = createDocumentFragment();
       
   471 			}
       
   472 
       
   473 			n = _traverseRightBoundary(endAncestor, how);
       
   474 
       
   475 			if (frag) {
       
   476 				frag.appendChild(n);
       
   477 			}
       
   478 
       
   479 			endIdx = nodeIndex(endAncestor);
       
   480 			cnt = endIdx - self[START_OFFSET];
       
   481 
       
   482 			if (cnt <= 0) {
       
   483 				// Collapse to just before the endAncestor, which
       
   484 				// is partially selected.
       
   485 				if (how != CLONE) {
       
   486 					self.setEndBefore(endAncestor);
       
   487 					self.collapse(FALSE);
       
   488 				}
       
   489 
       
   490 				return frag;
       
   491 			}
       
   492 
       
   493 			n = endAncestor.previousSibling;
       
   494 			while (cnt > 0) {
       
   495 				sibling = n.previousSibling;
       
   496 				xferNode = _traverseFullySelected(n, how);
       
   497 
       
   498 				if (frag) {
       
   499 					frag.insertBefore(xferNode, frag.firstChild);
       
   500 				}
       
   501 
       
   502 				--cnt;
       
   503 				n = sibling;
       
   504 			}
       
   505 
       
   506 			// Collapse to just before the endAncestor, which
       
   507 			// is partially selected.
       
   508 			if (how != CLONE) {
       
   509 				self.setEndBefore(endAncestor);
       
   510 				self.collapse(FALSE);
       
   511 			}
       
   512 
       
   513 			return frag;
       
   514 		}
       
   515 
       
   516 		function _traverseCommonEndContainer(startAncestor, how) {
       
   517 			var frag, startIdx, n, cnt, sibling, xferNode;
       
   518 
       
   519 			if (how != DELETE) {
       
   520 				frag = createDocumentFragment();
       
   521 			}
       
   522 
       
   523 			n = _traverseLeftBoundary(startAncestor, how);
       
   524 			if (frag) {
       
   525 				frag.appendChild(n);
       
   526 			}
       
   527 
       
   528 			startIdx = nodeIndex(startAncestor);
       
   529 			++startIdx; // Because we already traversed it
       
   530 
       
   531 			cnt = self[END_OFFSET] - startIdx;
       
   532 			n = startAncestor.nextSibling;
       
   533 			while (n && cnt > 0) {
       
   534 				sibling = n.nextSibling;
       
   535 				xferNode = _traverseFullySelected(n, how);
       
   536 
       
   537 				if (frag) {
       
   538 					frag.appendChild(xferNode);
       
   539 				}
       
   540 
       
   541 				--cnt;
       
   542 				n = sibling;
       
   543 			}
       
   544 
       
   545 			if (how != CLONE) {
       
   546 				self.setStartAfter(startAncestor);
       
   547 				self.collapse(TRUE);
       
   548 			}
       
   549 
       
   550 			return frag;
       
   551 		}
       
   552 
       
   553 		function _traverseCommonAncestors(startAncestor, endAncestor, how) {
       
   554 			var n, frag, startOffset, endOffset, cnt, sibling, nextSibling;
       
   555 
       
   556 			if (how != DELETE) {
       
   557 				frag = createDocumentFragment();
       
   558 			}
       
   559 
       
   560 			n = _traverseLeftBoundary(startAncestor, how);
       
   561 			if (frag) {
       
   562 				frag.appendChild(n);
       
   563 			}
       
   564 
       
   565 			startOffset = nodeIndex(startAncestor);
       
   566 			endOffset = nodeIndex(endAncestor);
       
   567 			++startOffset;
       
   568 
       
   569 			cnt = endOffset - startOffset;
       
   570 			sibling = startAncestor.nextSibling;
       
   571 
       
   572 			while (cnt > 0) {
       
   573 				nextSibling = sibling.nextSibling;
       
   574 				n = _traverseFullySelected(sibling, how);
       
   575 
       
   576 				if (frag) {
       
   577 					frag.appendChild(n);
       
   578 				}
       
   579 
       
   580 				sibling = nextSibling;
       
   581 				--cnt;
       
   582 			}
       
   583 
       
   584 			n = _traverseRightBoundary(endAncestor, how);
       
   585 
       
   586 			if (frag) {
       
   587 				frag.appendChild(n);
       
   588 			}
       
   589 
       
   590 			if (how != CLONE) {
       
   591 				self.setStartAfter(startAncestor);
       
   592 				self.collapse(TRUE);
       
   593 			}
       
   594 
       
   595 			return frag;
       
   596 		}
       
   597 
       
   598 		function _traverseRightBoundary(root, how) {
       
   599 			var next = _getSelectedNode(self[END_CONTAINER], self[END_OFFSET] - 1), parent, clonedParent;
       
   600 			var prevSibling, clonedChild, clonedGrandParent, isFullySelected = next != self[END_CONTAINER];
       
   601 
       
   602 			if (next == root) {
       
   603 				return _traverseNode(next, isFullySelected, FALSE, how);
       
   604 			}
       
   605 
       
   606 			parent = next.parentNode;
       
   607 			clonedParent = _traverseNode(parent, FALSE, FALSE, how);
       
   608 
       
   609 			while (parent) {
       
   610 				while (next) {
       
   611 					prevSibling = next.previousSibling;
       
   612 					clonedChild = _traverseNode(next, isFullySelected, FALSE, how);
       
   613 
       
   614 					if (how != DELETE) {
       
   615 						clonedParent.insertBefore(clonedChild, clonedParent.firstChild);
       
   616 					}
       
   617 
       
   618 					isFullySelected = TRUE;
       
   619 					next = prevSibling;
       
   620 				}
       
   621 
       
   622 				if (parent == root) {
       
   623 					return clonedParent;
       
   624 				}
       
   625 
       
   626 				next = parent.previousSibling;
       
   627 				parent = parent.parentNode;
       
   628 
       
   629 				clonedGrandParent = _traverseNode(parent, FALSE, FALSE, how);
       
   630 
       
   631 				if (how != DELETE) {
       
   632 					clonedGrandParent.appendChild(clonedParent);
       
   633 				}
       
   634 
       
   635 				clonedParent = clonedGrandParent;
       
   636 			}
       
   637 		}
       
   638 
       
   639 		function _traverseLeftBoundary(root, how) {
       
   640 			var next = _getSelectedNode(self[START_CONTAINER], self[START_OFFSET]), isFullySelected = next != self[START_CONTAINER];
       
   641 			var parent, clonedParent, nextSibling, clonedChild, clonedGrandParent;
       
   642 
       
   643 			if (next == root) {
       
   644 				return _traverseNode(next, isFullySelected, TRUE, how);
       
   645 			}
       
   646 
       
   647 			parent = next.parentNode;
       
   648 			clonedParent = _traverseNode(parent, FALSE, TRUE, how);
       
   649 
       
   650 			while (parent) {
       
   651 				while (next) {
       
   652 					nextSibling = next.nextSibling;
       
   653 					clonedChild = _traverseNode(next, isFullySelected, TRUE, how);
       
   654 
       
   655 					if (how != DELETE) {
       
   656 						clonedParent.appendChild(clonedChild);
       
   657 					}
       
   658 
       
   659 					isFullySelected = TRUE;
       
   660 					next = nextSibling;
       
   661 				}
       
   662 
       
   663 				if (parent == root) {
       
   664 					return clonedParent;
       
   665 				}
       
   666 
       
   667 				next = parent.nextSibling;
       
   668 				parent = parent.parentNode;
       
   669 
       
   670 				clonedGrandParent = _traverseNode(parent, FALSE, TRUE, how);
       
   671 
       
   672 				if (how != DELETE) {
       
   673 					clonedGrandParent.appendChild(clonedParent);
       
   674 				}
       
   675 
       
   676 				clonedParent = clonedGrandParent;
       
   677 			}
       
   678 		}
       
   679 
       
   680 		function _traverseNode(n, isFullySelected, isLeft, how) {
       
   681 			var txtValue, newNodeValue, oldNodeValue, offset, newNode;
       
   682 
       
   683 			if (isFullySelected) {
       
   684 				return _traverseFullySelected(n, how);
       
   685 			}
       
   686 
       
   687 			if (n.nodeType == 3 /* TEXT_NODE */) {
       
   688 				txtValue = n.nodeValue;
       
   689 
       
   690 				if (isLeft) {
       
   691 					offset = self[START_OFFSET];
       
   692 					newNodeValue = txtValue.substring(offset);
       
   693 					oldNodeValue = txtValue.substring(0, offset);
       
   694 				} else {
       
   695 					offset = self[END_OFFSET];
       
   696 					newNodeValue = txtValue.substring(0, offset);
       
   697 					oldNodeValue = txtValue.substring(offset);
       
   698 				}
       
   699 
       
   700 				if (how != CLONE) {
       
   701 					n.nodeValue = oldNodeValue;
       
   702 				}
       
   703 
       
   704 				if (how == DELETE) {
       
   705 					return;
       
   706 				}
       
   707 
       
   708 				newNode = dom.clone(n, FALSE);
       
   709 				newNode.nodeValue = newNodeValue;
       
   710 
       
   711 				return newNode;
       
   712 			}
       
   713 
       
   714 			if (how == DELETE) {
       
   715 				return;
       
   716 			}
       
   717 
       
   718 			return dom.clone(n, FALSE);
       
   719 		}
       
   720 
       
   721 		function _traverseFullySelected(n, how) {
       
   722 			if (how != DELETE) {
       
   723 				return how == CLONE ? dom.clone(n, TRUE) : n;
       
   724 			}
       
   725 
       
   726 			n.parentNode.removeChild(n);
       
   727 		}
       
   728 
       
   729 		function toStringIE() {
       
   730 			return dom.create('body', null, cloneContents()).outerText;
       
   731 		}
       
   732 
       
   733 		extend(self, {
       
   734 			// Inital states
       
   735 			startContainer: doc,
       
   736 			startOffset: 0,
       
   737 			endContainer: doc,
       
   738 			endOffset: 0,
       
   739 			collapsed: TRUE,
       
   740 			commonAncestorContainer: doc,
       
   741 
       
   742 			// Range constants
       
   743 			START_TO_START: 0,
       
   744 			START_TO_END: 1,
       
   745 			END_TO_END: 2,
       
   746 			END_TO_START: 3,
       
   747 
       
   748 			// Public methods
       
   749 			setStart: setStart,
       
   750 			setEnd: setEnd,
       
   751 			setStartBefore: setStartBefore,
       
   752 			setStartAfter: setStartAfter,
       
   753 			setEndBefore: setEndBefore,
       
   754 			setEndAfter: setEndAfter,
       
   755 			collapse: collapse,
       
   756 			selectNode: selectNode,
       
   757 			selectNodeContents: selectNodeContents,
       
   758 			compareBoundaryPoints: compareBoundaryPoints,
       
   759 			deleteContents: deleteContents,
       
   760 			extractContents: extractContents,
       
   761 			cloneContents: cloneContents,
       
   762 			insertNode: insertNode,
       
   763 			surroundContents: surroundContents,
       
   764 			cloneRange: cloneRange,
       
   765 			toStringIE: toStringIE
       
   766 		});
       
   767 
       
   768 		return self;
       
   769 	}
       
   770 
       
   771 	// Older IE versions doesn't let you override toString by it's constructor so we have to stick it in the prototype
       
   772 	Range.prototype.toString = function() {
       
   773 		return this.toStringIE();
       
   774 	};
       
   775 
       
   776 	return Range;
       
   777 });