You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by tn...@locus.apache.org on 2000/12/06 20:42:50 UTC
cvs commit: xml-xerces/c/tests/DOM/RangeTest RangeTest.cpp
tng 00/12/06 11:42:49
Modified: c/src/dom RangeImpl.cpp RangeImpl.hpp
c/tests/DOM/RangeTest RangeTest.cpp
Log:
further fixes to Range, and update RangeTest.cpp with more test coverage
Revision Changes Path
1.8 +616 -506 xml-xerces/c/src/dom/RangeImpl.cpp
Index: RangeImpl.cpp
===================================================================
RCS file: /home/cvs/xml-xerces/c/src/dom/RangeImpl.cpp,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- RangeImpl.cpp 2000/11/30 20:06:22 1.7
+++ RangeImpl.cpp 2000/12/06 19:42:45 1.8
@@ -55,12 +55,13 @@
*/
/*
- * $Id: RangeImpl.cpp,v 1.7 2000/11/30 20:06:22 andyh Exp $
+ * $Id: RangeImpl.cpp,v 1.8 2000/12/06 19:42:45 tng Exp $
*/
#include <util/RefVectorOf.hpp>
#include "NodeImpl.hpp"
#include "RangeImpl.hpp"
+#include "TextImpl.hpp"
#include "DocumentImpl.hpp"
#include "DOM_DOMException.hpp"
#include "DOM_Document.hpp"
@@ -164,27 +165,52 @@
void RangeImpl::setStartContainer(const DOM_Node& node)
{
+ if (fDetached)
+ {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+
fStartContainer = node;
}
void RangeImpl::setStartOffset(unsigned int offset)
{
+ if (fDetached)
+ {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+
fStartOffset = offset;
}
void RangeImpl::setEndContainer(const DOM_Node& node)
{
+ if (fDetached)
+ {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+
fEndContainer = node;
}
void RangeImpl::setEndOffset(unsigned int offset)
{
+ if (fDetached)
+ {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+
fEndOffset = offset;
}
void RangeImpl::setStart(const DOM_Node& refNode, unsigned int offset)
{
+ validateNode(refNode);
checkIndex(refNode, offset);
fStartContainer = refNode;
@@ -207,6 +233,7 @@
void RangeImpl::setEnd(const DOM_Node& refNode, unsigned int offset)
{
+ validateNode(refNode);
checkIndex(refNode, offset);
fEndContainer = refNode;
@@ -229,7 +256,14 @@
void RangeImpl::setStartBefore(const DOM_Node& refNode)
{
- validateNode(refNode);
+ if( fDetached) {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+ if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
+ throw DOM_RangeException(
+ DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
+ }
fStartContainer = refNode.getParentNode();
unsigned int i = 0;
@@ -258,7 +292,14 @@
void RangeImpl::setStartAfter(const DOM_Node& refNode)
{
- validateNode(refNode);
+ if( fDetached) {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+ if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
+ throw DOM_RangeException(
+ DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
+ }
fStartContainer = refNode.getParentNode();
unsigned int i = 0;
@@ -285,7 +326,14 @@
void RangeImpl::setEndBefore(const DOM_Node& refNode)
{
- validateNode(refNode);
+ if( fDetached) {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+ if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
+ throw DOM_RangeException(
+ DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
+ }
fEndContainer = refNode.getParentNode();
unsigned int i = 0;
@@ -313,7 +361,14 @@
void RangeImpl::setEndAfter(const DOM_Node& refNode)
{
- validateNode(refNode);
+ if( fDetached) {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+ if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
+ throw DOM_RangeException(
+ DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
+ }
fEndContainer = refNode.getParentNode();
unsigned int i = 0;
@@ -343,6 +398,11 @@
//-------------------------------
void RangeImpl::detach()
{
+ if( fDetached) {
+ throw DOM_DOMException(
+ DOM_DOMException::INVALID_STATE_ERR, null);
+ }
+
fDetached = true;
//nullify nodes
@@ -375,18 +435,12 @@
void RangeImpl::selectNode(const DOM_Node& refNode)
{
validateNode(refNode);
- short type = refNode.getNodeType();
- if (type == DOM_Node::ATTRIBUTE_NODE
- || type == DOM_Node::ENTITY_NODE
- || type == DOM_Node::NOTATION_NODE
- || type == DOM_Node::DOCUMENT_TYPE_NODE
- || type == DOM_Node::DOCUMENT_FRAGMENT_NODE) {
-
+ if ( !isLegalContainedNode(refNode)) {
throw DOM_RangeException(
DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
}
//First check for the text type node
- if (type == DOM_Node::TEXT_NODE)
+ if (refNode.getNodeType() == DOM_Node::TEXT_NODE)
{
//The node itself is the container.
fStartContainer = refNode;
@@ -417,14 +471,6 @@
void RangeImpl::selectNodeContents(const DOM_Node& node)
{
validateNode(node);
- short type = node.getNodeType();
- if (type == DOM_Node::ENTITY_NODE
- || type == DOM_Node::NOTATION_NODE
- || type == DOM_Node::DOCUMENT_TYPE_NODE) {
-
- throw DOM_RangeException(
- DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
- }
fStartContainer = node;
fEndContainer = node;
@@ -463,12 +509,8 @@
}
int type = newParent.getNodeType();
- if (type == DOM_Node::ATTRIBUTE_NODE
- || type == DOM_Node::ENTITY_NODE
- || type == DOM_Node::NOTATION_NODE
- || type == DOM_Node::DOCUMENT_TYPE_NODE
- || type == DOM_Node::DOCUMENT_NODE
- || type == DOM_Node::DOCUMENT_FRAGMENT_NODE)
+ if ( !isLegalContainedNode(newParent)
+ || type == DOM_Node::DOCUMENT_TYPE_NODE)
{
throw DOM_RangeException(
DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
@@ -580,190 +622,12 @@
void RangeImpl:: deleteContents()
{
- if ((fStartContainer == null) || (fEndContainer == null) ) return;
- checkReadOnly(fStartContainer, fEndContainer, fStartOffset, fEndOffset);
-
- if( fDetached) {
- throw DOM_DOMException(
- DOM_DOMException::INVALID_STATE_ERR, null);
- }
-
- DOM_Node current = fStartContainer;
-
- // if same container, simplify case
- if (fStartContainer == fEndContainer) {
- if (fStartOffset == fEndOffset) { // already collapsed
- return;
- }
- if (fStartOffset > fEndOffset)
- throw DOM_RangeException(DOM_RangeException::BAD_BOUNDARYPOINTS_ERR, null);
-
- if (fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) {
- DOMString value = fStartContainer.getNodeValue();
- unsigned int realStart = fStartOffset;
- unsigned int realEnd = fEndOffset;
-
- if (fStartOffset > value.length()) realStart = value.length()-1;
- if (fEndOffset > value.length()) realEnd = value.length()-1;
-
- ((DOM_Text &)fStartContainer).deleteData(realStart, realEnd-realStart);
-
- } else {
- current = fStartContainer.getFirstChild();
- unsigned int i = 0;
- //move till the start offset
- for(i = 0; i < fStartOffset && current != null; i++) {
- current=current.getNextSibling();
- }
-
- //delete all children after the start offset to end offset
- for(i = 0; i < (fEndOffset-fStartOffset) && (current != null); i++) {
- DOM_Node newCurrent = current.getNextSibling();
- removeChild(fStartContainer, current);
- current = newCurrent;
- }
- }
- collapse(true);
- return;
- }
-
- //The case of partial selections and when start container is not the same as end one
- bool deleteCurrent = false;
-
- // initialize current for startContainer.
- if (current.getNodeType() == DOM_Node::TEXT_NODE) {
- ((DOM_Text &)current).deleteData(fStartOffset, current.getNodeValue().length()-fStartOffset);
- } else {
- current = current.getFirstChild();
- for (unsigned int i = 0 ; i < fStartOffset && current != null; i++){
- current = current.getNextSibling();
- }
- if (current == null) {
- current = fStartContainer;
- } else if (current != fStartContainer)
- deleteCurrent = true;
- }
-
- DOM_Node parent = null;
- DOM_Node next;
- DOM_Node partialNode = null;
- int partialInt = START;
- DOM_Node startRoot = null;
-
- DOM_Node root = getCommonAncestorContainer();
- // traverse up from the startContainer...
- // current starts as the node to delete;
- while (current != root && current != null) {
-
- parent = current.getParentNode();
- if (parent == root) {
- if (startRoot == null)
- startRoot = current;
- } else {
- if (partialNode == null) {
- partialNode = parent;
- partialInt = AFTER;
- }
- }
-
- if (parent != root) {
- next = current.getNextSibling();
- DOM_Node nextnext;
- while (next != null) {
- nextnext = next.getNextSibling();
- removeChild(parent, next);
- next = nextnext;
- }
- }
-
- if (deleteCurrent) {
- removeChild(parent, current);
- deleteCurrent = false;
- }
- current = parent;
- }
-
- DOM_Node endRoot = null;
- // initialize current for endContainer.
- current = fEndContainer;
- if (current.getNodeType() == DOM_Node::TEXT_NODE) {
- ((DOM_Text &)current).deleteData(0, fEndOffset);
- } else {
-
- if (fEndOffset == 0) { // "before"
- current = fEndContainer;
- }
- else {
- current = current.getFirstChild();
- for(unsigned int i = 1; i < fEndOffset && current != null; i++) {
- current=current.getNextSibling();
- }
- if (current==null) { // REVIST: index-out-of-range what to do?
- current = fEndContainer.getLastChild();
- } else
- if (current != fStartContainer) {
- deleteCurrent = true;
- }
-
- }
- }
-
- // traverse up from the endContainer...
- while (current != root && current != null) {
-
- parent = current.getParentNode();
- if (parent == root) {
- if (endRoot == null)
- endRoot = current;
- } else {
- if (partialNode==null) {
- partialNode = parent;
- partialInt = BEFORE;
- }
- }
-
- if (parent != root && parent != null) {
- next = current.getPreviousSibling();
- DOM_Node nextnext;
- while (next != null) {
- nextnext = next.getPreviousSibling();
- removeChild(parent, next);
- next = nextnext;
- }
- }
-
- if (deleteCurrent) {
- removeChild(parent, current);
- deleteCurrent = false;
- }
- current = parent;
- }
-
- //if (endRoot == null || startRoot == null) return; //REVIST
- current = endRoot.getPreviousSibling();
- DOM_Node prev = null;
- while (current != null && current != startRoot ) {
- prev = current.getPreviousSibling();
- parent = current.getParentNode();
- if (parent != null) {
- removeChild(parent, current);
- }
- current = prev;
- }
-
- if (partialNode == null) {
- collapse(true);
- } else if (partialInt == AFTER) {
- setStartAfter(partialNode);
- setEndAfter(partialNode);
- } else if (partialInt == BEFORE) {
- setStartBefore(partialNode);
- setEndBefore(partialNode);
- }
+ traverseContents(DELETE_CONTENTS);
}
DOM_DocumentFragment RangeImpl::extractContents()
{
+ checkReadOnly(fStartContainer, fEndContainer, fStartOffset, fEndOffset);
return traverseContents(EXTRACT_CONTENTS);
}
@@ -778,10 +642,12 @@
{
if (newNode == null) return; //don't have to do anything
- if (fStartContainer.getParentNode().fImpl->isReadOnly()) {
+ for (DOM_Node aNode = fStartContainer; aNode!=null; aNode = aNode.getParentNode()) {
+ if (aNode.fImpl->isReadOnly()) {
throw DOM_DOMException(
DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
}
+ }
if (fDocument != newNode.getOwnerDocument()) {
throw DOM_DOMException(
@@ -804,8 +670,7 @@
if (type == DOM_Node::ATTRIBUTE_NODE
|| type == DOM_Node::ENTITY_NODE
|| type == DOM_Node::NOTATION_NODE
- || type == DOM_Node::DOCUMENT_NODE
- || type == DOM_Node::DOCUMENT_FRAGMENT_NODE)
+ || type == DOM_Node::DOCUMENT_NODE)
{
throw DOM_RangeException(
DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
@@ -870,43 +735,52 @@
}
DOM_Node node = fStartContainer;
+ DOM_Node stopNode = fEndContainer;
DOMString tempString;
if ( (fStartContainer.getNodeType() == DOM_Node::TEXT_NODE)
|| (fStartContainer.getNodeType() == DOM_Node::CDATA_SECTION_NODE) ) {
if (fStartContainer == fEndContainer) {
- //the substringData returns a substring from start to end all inclusive
- //we want a substring begins at fStartOffset inclusive, but ends at fEndOffset exclusive
- tempString.appendData(fStartContainer.getNodeValue().substringData(fStartOffset, fEndOffset-1));
+ tempString.appendData(fStartContainer.getNodeValue().substringData(fStartOffset, fEndOffset-fStartOffset));
return tempString;
} else {
int length = fStartContainer.getNodeValue().length();
tempString.appendData(fStartContainer.getNodeValue().substringData(fStartOffset, length - fStartOffset));
+ node = nextNode(node, true);
}
- }else if (node == fEndContainer){
- DOM_Node anode = node.getFirstChild();
- unsigned int i = 0;
- for ( ;i<fStartOffset; i++)
- anode = anode.getNextSibling();
- for( ; ( i<fEndOffset || anode!=null); anode = anode.getNextSibling(), i++) {
- if( (anode.getNodeType() == DOM_Node::TEXT_NODE)
- || (anode.getNodeType() == DOM_Node::CDATA_SECTION_NODE)) {
- tempString.appendData(anode.getNodeValue());
+ }else { //fStartContainer is not a TextNode
+ node=node.getFirstChild();
+ if (fStartOffset>0) { //find a first node within a range, specified by fStartOffset
+ unsigned int counter = 0;
+ while (counter<fStartOffset && node!=null) {
+ node=node.getNextSibling();
+ counter++;
}
+ }
+ if (node == null) {
+ node = nextNode(fStartContainer,false);
}
- return tempString;
}
- DOM_Node root = getCommonAncestorContainer();
- while (node != fEndContainer) {
- node = nextNode(node, true);
- if ((node == null) || (node == fEndContainer)) break;
+ if ( fEndContainer.getNodeType()!= DOM_Node.TEXT_NODE &&
+ fEndContainer.getNodeType()!= DOM_Node.CDATA_SECTION_NODE ){
+ int i=fEndOffset;
+ stopNode = fEndContainer.getFirstChild();
+ while( i>0 && stopNode!=null ){
+ --i;
+ stopNode = stopNode.getNextSibling();
+ }
+ if ( stopNode == null )
+ stopNode = nextNode( fEndContainer, false );
+ }
- if (node.getNodeType() == DOM_Node::TEXT_NODE
- || node.getNodeType() == DOM_Node::CDATA_SECTION_NODE
- ) {
+ while (node != stopNode) { //look into all kids of the Range
+ if (node == null) break;
+ if (node.getNodeType() == DOM_Node.TEXT_NODE
+ || node.getNodeType() == DOM_Node.CDATA_SECTION_NODE) {
tempString.appendData(node.getNodeValue());
}
+ node = nextNode(node, true);
}
if (fEndContainer.getNodeType() == DOM_Node::TEXT_NODE
@@ -950,6 +824,36 @@
return false;
}
+bool RangeImpl::hasLegalRootContainer(const DOM_Node& node) const {
+ if ( node==null )
+ return false;
+
+ DOM_Node rootContainer = node;
+ for (; rootContainer.getParentNode()!=null; rootContainer = rootContainer.getParentNode());
+ switch( rootContainer.getNodeType() ) {
+ case DOM_Node::ATTRIBUTE_NODE:
+ case DOM_Node::DOCUMENT_NODE:
+ case DOM_Node::DOCUMENT_FRAGMENT_NODE:
+ return true;
+ }
+ return false;
+}
+
+bool RangeImpl::isLegalContainedNode(const DOM_Node& node ) const {
+ if ( node==null )
+ return false;
+ switch( node.getNodeType() )
+ {
+ case DOM_Node::DOCUMENT_NODE:
+ case DOM_Node::DOCUMENT_FRAGMENT_NODE:
+ case DOM_Node::ATTRIBUTE_NODE:
+ case DOM_Node::ENTITY_NODE:
+ case DOM_Node::NOTATION_NODE:
+ return false;
+ }
+ return true;
+}
+
unsigned short RangeImpl::indexOf(const DOM_Node& child, const DOM_Node& parent) const
{
unsigned short i = 0;
@@ -1022,8 +926,6 @@
void RangeImpl::checkIndex(const DOM_Node& node, unsigned int offset) const
{
- validateNode(node);
-
if (offset < 0) {
throw DOM_DOMException( DOM_DOMException::INDEX_SIZE_ERR, null );
}
@@ -1091,12 +993,12 @@
}
-/** This is the master traversal function which is used by
-* both extractContents and cloneContents().
+/** This is the master routine invoked to visit the nodes
+* selected by this range. For each such node, different
+* actions are taken depending on the value of the TraversalType argument.
*/
-DOM_DocumentFragment RangeImpl::traverseContents(TraversalType trvType)
+DOM_DocumentFragment RangeImpl::traverseContents(TraversalType how)
{
-
if (fDetached)
throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
@@ -1104,285 +1006,500 @@
return DOM_DocumentFragment(); // REVIST: Throw exception?
}
- DOM_DocumentFragment frag = fDocument.createDocumentFragment() ;
+ /* Traversal is accomplished by first determining the
+ relationship between the endpoints of the range.
+ For each of four significant relationships, we will
+ delegate the traversal call to a method that
+ can make appropriate assumptions.
+ */
- DOM_Node current = fStartContainer;
- DOM_Node cloneCurrent = null;
- DOM_Node cloneParent = null;
- DOM_Node partialNode = null;
- int partialInt = START;
-
- // if same container, simplify case
- if (fStartContainer == fEndContainer) {
- if (fStartOffset == fEndOffset) { // eg collapsed
- return frag; // REVIST: what is correct re spec?
- }
- if (fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) {
- cloneCurrent = fStartContainer.cloneNode(false);
- cloneCurrent.setNodeValue(
- cloneCurrent.getNodeValue().substringData(fStartOffset, fEndOffset));
- if (trvType == EXTRACT_CONTENTS) {
- ((DOM_Text &)current).deleteData(fStartOffset, fEndOffset-fStartOffset);
- }
- frag.appendChild(cloneCurrent);
- } else {
- current = current.getFirstChild();
- unsigned int i = 0;
- for(i = 0; i < fStartOffset && current != null; i++) {
- current=current.getNextSibling();
- }
- unsigned int n = fEndOffset-fStartOffset;
- for(i = 0; i < n && current != null ;i++) {
- DOM_Node newCurrent=current.getNextSibling();
+ // case 1: same container
+ if ( fStartContainer == fEndContainer )
+ return traverseSameContainer( how );
- if (trvType == CLONE_CONTENTS) {
- cloneCurrent = current.cloneNode(true);
- frag.appendChild(cloneCurrent);
- } else
- if (trvType == EXTRACT_CONTENTS) {
- frag.appendChild(current);
- }
- current = newCurrent;
- }
- }
- if (trvType == EXTRACT_CONTENTS ) {
- collapse(true);
- }
- return frag;
+ // case 2: Child C of start container is ancestor of end container
+ for (DOM_Node node = fStartContainer.getFirstChild(); node != null; node=node.getNextSibling()) {
+ if (isAncestorOf(node, fEndContainer))
+ return traverseCommonStartContainer( node, how );
}
- //***** END SIMPLE CASE ****
-
-
- DOM_Node root = getCommonAncestorContainer();
- DOM_Node parent = null;
- // go up the start tree...
- current = fStartContainer;
-
- bool endAtRoot = false;
-
- //REVIST: Always clone TEXT_NODE's?
- if (current.getNodeType() == DOM_Node::TEXT_NODE) {
- cloneCurrent = current.cloneNode(false);
- cloneCurrent.setNodeValue(
- ((DOM_Text&)cloneCurrent).getNodeValue().substringData(fStartOffset, current.getNodeValue().length() - fStartOffset));
- if (trvType == EXTRACT_CONTENTS) {
- ((DOM_Text&)current).deleteData(fStartOffset, current.getNodeValue().length()-fStartOffset);
- }
- } else {
- current = current.getFirstChild();
- for(unsigned int i = 0; i < fStartOffset && current != null; i++) {
- current=current.getNextSibling();
- }
- // current is now at the offset.
- if (current==null) { //"after"
- current = fStartContainer;
+ // case 3: Child C of end container is ancestor of start container
+ for (DOM_Node nd = fEndContainer.getFirstChild(); nd != null; nd=nd.getNextSibling()) {
+ if (isAncestorOf(nd, fStartContainer))
+ return traverseCommonEndContainer( nd, how );
}
- if (trvType == CLONE_CONTENTS) {
- cloneCurrent = current.cloneNode(true);
- } else if (trvType == EXTRACT_CONTENTS ) {
- cloneCurrent = current;
- }
+ // case 4: preorder traversal of context tree.
+ // There is a common ancestor container. Find the
+ // ancestor siblings that are children of that container.
+ DOM_Node ancestor = commonAncestorOf(fStartContainer, fEndContainer);
+ return traverseCommonAncestors( ancestor, ancestor, how );
}
-
- DOM_Node startRoot = null;
- DOM_Node endRoot = null;
- parent = null;
-
- if (root == fEndContainer) {
- if (fStartContainer.getParentNode() == fEndContainer) {
- //a unique situation when start and end are partial under the same pass
- DOM_Node endNode = fEndContainer.getFirstChild();
- for (unsigned int i = 0;
- i <= fEndOffset-2;
- i++, endNode = endNode.getNextSibling()) ;
-
- if (cloneParent == null)
- cloneParent = root.cloneNode(false);
-
- cloneParent.appendChild(cloneCurrent); //clone the node from above
+/**
+ * Visits the nodes selected by this range when we know
+ * a-priori that the start and end containers are the same.
+ *
+ */
+DOM_DocumentFragment RangeImpl::traverseSameContainer( int how )
+{
+ DOM_DocumentFragment frag = null;
+ if ( how!=DELETE_CONTENTS)
+ frag = fDocument.createDocumentFragment();
- for (current= current.getNextSibling();
- current != null, current != endNode.getNextSibling();
- current=current.getNextSibling()) {
- if (trvType == CLONE_CONTENTS) {
- cloneCurrent = current.cloneNode(true);
- cloneParent.appendChild(cloneCurrent);
- } else if (trvType == EXTRACT_CONTENTS) {
- cloneParent.appendChild(current);
- }
- }
- if (trvType == EXTRACT_CONTENTS) {
- collapse(true);
- }
- frag.appendChild(cloneParent);
+ // If selection is empty, just return the fragment
+ if ( fStartOffset==fEndOffset )
return frag;
- }
- }
-
- // going up in a direct line from boundary point
- // through parents to the common ancestor,
- // all these nodes are partially selected, and must
- // be cloned.
- while (current != root) {
- parent = current.getParentNode();
-
- if (parent == root) {
- cloneParent = frag;
- startRoot = current;
- } else {
- //check if (parent == null) case too
- cloneParent = parent.cloneNode(false);
- if (partialNode==null && parent != root) {
- partialNode = parent;
- partialInt = AFTER;
- }
-
- }
-
- // The children to the "right" of the "ancestor hierarchy"
- // are "fully-selected".
- DOM_Node next = null;
-
- //increment to the next sibling BEFORE doing the appendChild
- current = current.getNextSibling();
- //do this appendChild after the increment above.
- cloneParent.appendChild(cloneCurrent);
-
- while (current != null) {
- next = current.getNextSibling();
- if (current != null && parent != root) {
- if (trvType == CLONE_CONTENTS) {
- cloneCurrent = current.cloneNode(true);
- cloneParent.appendChild(cloneCurrent);
- } else
- if (trvType == EXTRACT_CONTENTS) {
- cloneParent.appendChild(current);
- }
- }
- current = next;
- }
-
- current = parent;
- cloneCurrent = cloneParent;
- }
-
- // go up the end tree...
- current = fEndContainer;
+ DOM_Node current = fStartContainer;
+ DOM_Node cloneCurrent = null;
- if (current.getNodeType() == DOM_Node::TEXT_NODE) {
- cloneCurrent = current.cloneNode(false);
+ // Text node needs special case handling
+ if ( fStartContainer.getNodeType()== DOM_Node::TEXT_NODE )
+ {
+ cloneCurrent = fStartContainer.cloneNode(false);
cloneCurrent.setNodeValue(
- (cloneCurrent.getNodeValue()).substringData(0,fEndOffset));
- if (trvType == EXTRACT_CONTENTS) {
- ((DOM_Text&)current).deleteData(0, fEndOffset);
- }
- } else {
- if (fEndOffset == 0) { // "before"
- current = fEndContainer;
- }
- else {
- current = current.getFirstChild();
- for(unsigned int i = 1; i < fEndOffset && current != null; i++) {
- current=current.getNextSibling();
- }
- if (current==null) { // REVIST: index-out-of-range what to do?
- current = fEndContainer.getLastChild();
- }
- }
- if (trvType == CLONE_CONTENTS) {
- cloneCurrent = current.cloneNode(true);
- } else
- if (trvType == EXTRACT_CONTENTS ) {
- cloneCurrent = current;
- }
- }
-
- while (current != root && current != null) {
- parent = current.getParentNode();
- if (parent == root) {
- cloneParent = frag;
- endRoot = current;
- } else {
- cloneParent = parent.cloneNode(false);
- if (partialNode==null && parent != root) {
- partialNode = parent;
- partialInt = BEFORE;
- }
- }
-
- DOM_Node holdCurrent = current;
-
- current = parent.getFirstChild();
-
- cloneParent.appendChild(cloneCurrent);
+ cloneCurrent.getNodeValue().substringData(fStartOffset, fEndOffset));
- DOM_Node next = null;
- while (current != holdCurrent && current != null) {
- next = current.getNextSibling();
- // The leftmost children are fully-selected
- // and are removed, and appended, not cloned.
- if (current != null && parent != root) {
- if (trvType == CLONE_CONTENTS) {
- cloneCurrent = current.cloneNode(true);
- cloneParent.appendChild(cloneCurrent);
- } else
- if (trvType == EXTRACT_CONTENTS) {
- //cloneCurrent = current;
- cloneParent.appendChild(current);
- }
- }
- current = next;
- }
-
- current = parent;
- cloneCurrent = cloneParent;
-
+ // set the original text node to its new value
+ if ( how != CLONE_CONTENTS )
+ ((DOM_Text &)fStartContainer).deleteData(fStartOffset, fEndOffset-fStartOffset);
+ if ( how != DELETE_CONTENTS)
+ frag.appendChild(cloneCurrent);
}
-
- // traverse the "fully-selected" middle...
- DOM_Node clonedPrevious = frag.getLastChild();
- current = endRoot.getPreviousSibling();
- DOM_Node prev = null;
- while (current != startRoot && current != null) {
- prev = current.getPreviousSibling();
-
- if (trvType == CLONE_CONTENTS) {
- cloneCurrent = current.cloneNode(true);
- } else
- if (trvType == EXTRACT_CONTENTS) {
- cloneCurrent = current;
+ else {
+ // Copy nodes between the start/end offsets.
+ DOM_Node n = getSelectedNode( fStartContainer, fStartOffset );
+ int cnt = fEndOffset - fStartOffset;
+ while( cnt > 0 )
+ {
+ DOM_Node sibling = n.getNextSibling();
+ DOM_Node xferNode = traverseFullySelected( n, how );
+ if ( frag!=null )
+ frag.appendChild( xferNode );
+ --cnt;
+ n = sibling;
}
-
- frag.insertBefore(cloneCurrent, clonedPrevious);
-
- current = prev;
- clonedPrevious = cloneCurrent;
}
- // collapse the range...
- if (trvType == EXTRACT_CONTENTS ) {
- if (partialNode == null) {
+ // Nothing is partially selected, so collapse to start point
+ if ( how != CLONE_CONTENTS )
collapse(true);
- } else
- if (partialInt == AFTER) {
- setStartAfter(partialNode);
- setEndAfter(partialNode);
- }
- else if (partialInt == BEFORE) {
- setStartBefore(partialNode);
- setEndBefore(partialNode);
- }
+ return frag;
+}
+
+/**
+ * Visits the nodes selected by this range when we know
+ * a-priori that the start and end containers are not the
+ * same, but the start container is an ancestor of the end container
+ *
+ */
+DOM_DocumentFragment RangeImpl::traverseCommonStartContainer( DOM_Node endAncestor, int how )
+{
+ DOM_DocumentFragment frag = null;
+ if ( how!=DELETE_CONTENTS)
+ frag = fDocument.createDocumentFragment();
+ DOM_Node n = traverseRightBoundary( endAncestor, how );
+ if ( frag!=null )
+ frag.appendChild( n );
+
+ int endIdx = indexOf( endAncestor, fStartContainer );
+ int cnt = endIdx - fStartOffset;
+ if ( cnt <=0 )
+ {
+ // Collapse to just before the endAncestor, which
+ // is partially selected.
+ if ( how != CLONE_CONTENTS )
+ {
+ setEndBefore( endAncestor );
+ collapse( false );
+ }
+ return frag;
}
-
+ n = endAncestor.getPreviousSibling();
+ while( cnt > 0 )
+ {
+ DOM_Node sibling = n.getPreviousSibling();
+ DOM_Node xferNode = traverseFullySelected( n, how );
+ if ( frag!=null )
+ frag.insertBefore( xferNode, frag.getFirstChild() );
+ --cnt;
+ n = sibling;
+ }
+ // Collapse to just before the endAncestor, which
+ // is partially selected.
+ if ( how != CLONE_CONTENTS )
+ {
+ setEndBefore( endAncestor );
+ collapse( false );
+ }
return frag;
}
-void RangeImpl::checkReadOnly(DOM_Node& start, DOM_Node& end,
+/**
+ * Visits the nodes selected by this range when we know
+ * a-priori that the start and end containers are not the
+ * same, but the end container is an ancestor of the start container
+ *
+ */
+DOM_DocumentFragment RangeImpl::traverseCommonEndContainer( DOM_Node startAncestor, int how )
+{
+ DOM_DocumentFragment frag = null;
+ if ( how!=DELETE_CONTENTS)
+ frag = fDocument.createDocumentFragment();
+ DOM_Node n = traverseLeftBoundary( startAncestor, how );
+ if ( frag!=null )
+ frag.appendChild( n );
+ int startIdx = indexOf( startAncestor, fEndContainer );
+ ++startIdx; // Because we already traversed it....
+
+ int cnt = fEndOffset - startIdx;
+ n = startAncestor.getNextSibling();
+ while( cnt > 0 )
+ {
+ DOM_Node sibling = n.getNextSibling();
+ DOM_Node xferNode = traverseFullySelected( n, how );
+ if ( frag!=null )
+ frag.appendChild( xferNode );
+ --cnt;
+ n = sibling;
+ }
+
+ if ( how != CLONE_CONTENTS )
+ {
+ setStartAfter( startAncestor );
+ collapse( true );
+ }
+
+ return frag;
+}
+
+/**
+ * Visits the nodes selected by this range when we know
+ * a-priori that the start and end containers are not
+ * the same, and we also know that neither the start
+ * nor end container is an ancestor of the other.
+ */
+DOM_DocumentFragment RangeImpl::traverseCommonAncestors( DOM_Node startAncestor, DOM_Node endAncestor, int how )
+{
+ DOM_DocumentFragment frag = null;
+ if ( how!=DELETE_CONTENTS)
+ frag = fDocument.createDocumentFragment();
+
+ DOM_Node n = traverseLeftBoundary( startAncestor, how );
+ if ( frag!=null )
+ frag.appendChild( n );
+
+ DOM_Node commonParent = startAncestor.getParentNode();
+ int startOffset = indexOf( startAncestor, commonParent );
+ int endOffset = indexOf( endAncestor, commonParent );
+ ++startOffset;
+
+ int cnt = endOffset - startOffset;
+ DOM_Node sibling = startAncestor.getNextSibling();
+
+ while( cnt > 0 )
+ {
+ DOM_Node nextSibling = sibling.getNextSibling();
+ n = traverseFullySelected( sibling, how );
+ if ( frag!=null )
+ frag.appendChild( n );
+ sibling = nextSibling;
+ --cnt;
+ }
+
+ n = traverseRightBoundary( endAncestor, how );
+ if ( frag!=null )
+ frag.appendChild( n );
+
+ if ( how != CLONE_CONTENTS )
+ {
+ setStartAfter( startAncestor );
+ collapse( true );
+ }
+ return frag;
+}
+
+/**
+ * Traverses the "right boundary" of this range and
+ * operates on each "boundary node" according to the
+ * how parameter. It is a-priori assumed
+ * by this method that the right boundary does
+ * not contain the range's start container.
+ *
+ * A "right boundary" is best visualized by thinking
+ * of a sample tree:
+ * A
+ * /|\
+ * / | \
+ * / | \
+ * B C D
+ * /|\ /|\
+ * E F G H I J
+ *
+ * Imagine first a range that begins between the
+ * "E" and "F" nodes and ends between the
+ * "I" and "J" nodes. The start container is
+ * "B" and the end container is "D". Given this setup,
+ * the following applies:
+ *
+ * Partially Selected Nodes: B, D<br>
+ * Fully Selected Nodes: F, G, C, H, I
+ *
+ * The "right boundary" is the highest subtree node
+ * that contains the ending container. The root of
+ * this subtree is always partially selected.
+ *
+ * In this example, the nodes that are traversed
+ * as "right boundary" nodes are: H, I, and D.
+ *
+ */
+DOM_Node RangeImpl::traverseRightBoundary( DOM_Node root, int how )
+{
+ DOM_Node next = getSelectedNode( fEndContainer, fEndOffset-1 );
+ bool isFullySelected = ( next!=fEndContainer );
+
+ if ( next==root )
+ return traverseNode( next, isFullySelected, false, how );
+
+ DOM_Node parent = next.getParentNode();
+ DOM_Node clonedParent = traverseNode( parent, false, false, how );
+
+ while( parent!=null )
+ {
+ while( next!=null )
+ {
+ DOM_Node prevSibling = next.getPreviousSibling();
+ DOM_Node clonedChild =
+ traverseNode( next, isFullySelected, false, how );
+ if ( how!=DELETE_CONTENTS )
+ {
+ clonedParent.insertBefore(
+ clonedChild,
+ clonedParent.getFirstChild()
+ );
+ }
+ isFullySelected = true;
+ next = prevSibling;
+ }
+ if ( parent==root )
+ return clonedParent;
+
+ next = parent.getPreviousSibling();
+ parent = parent.getParentNode();
+ DOM_Node clonedGrandParent = traverseNode( parent, false, false, how );
+ if ( how!=DELETE_CONTENTS )
+ clonedGrandParent.appendChild( clonedParent );
+ clonedParent = clonedGrandParent;
+
+ }
+
+ // should never occur
+ return null;
+}
+
+/**
+ * Traverses the "left boundary" of this range and
+ * operates on each "boundary node" according to the
+ * how parameter. It is a-priori assumed
+ * by this method that the left boundary does
+ * not contain the range's end container.
+ *
+ * A "left boundary" is best visualized by thinking
+ * of a sample tree:
+ *
+ * A
+ * /|\
+ * / | \
+ * / | \
+ * B C D
+ * /|\ /|\
+ * E F G H I J
+ *
+ * Imagine first a range that begins between the
+ * "E" and "F" nodes and ends between the
+ * "I" and "J" nodes. The start container is
+ * "B" and the end container is "D". Given this setup,
+ * the following applies:
+ *
+ * Partially Selected Nodes: B, D<br>
+ * Fully Selected Nodes: F, G, C, H, I
+ *
+ * The "left boundary" is the highest subtree node
+ * that contains the starting container. The root of
+ * this subtree is always partially selected.
+ *
+ * In this example, the nodes that are traversed
+ * as "left boundary" nodes are: F, G, and B.
+ *
+ */
+DOM_Node RangeImpl::traverseLeftBoundary( DOM_Node root, int how )
+{
+ DOM_Node next = getSelectedNode( getStartContainer(), getStartOffset() );
+ bool isFullySelected = ( next!=getStartContainer() );
+
+ if ( next==root )
+ return traverseNode( next, isFullySelected, true, how );
+
+ DOM_Node parent = next.getParentNode();
+ DOM_Node clonedParent = traverseNode( parent, false, true, how );
+
+ while( parent!=null )
+ {
+ while( next!=null )
+ {
+ DOM_Node nextSibling = next.getNextSibling();
+ DOM_Node clonedChild =
+ traverseNode( next, isFullySelected, true, how );
+ if ( how!=DELETE_CONTENTS )
+ clonedParent.appendChild(clonedChild);
+ isFullySelected = true;
+ next = nextSibling;
+ }
+ if ( parent==root )
+ return clonedParent;
+
+ next = parent.getNextSibling();
+ parent = parent.getParentNode();
+ DOM_Node clonedGrandParent = traverseNode( parent, false, true, how );
+ if ( how!=DELETE_CONTENTS )
+ clonedGrandParent.appendChild( clonedParent );
+ clonedParent = clonedGrandParent;
+
+ }
+
+ // should never occur
+ return null;
+
+}
+
+/**
+ * Utility method for traversing a single node.
+ * Does not properly handle a text node containing both the
+ * start and end offsets. Such nodes should
+ * have been previously detected and been routed to traverseTextNode.
+ *
+ */
+DOM_Node RangeImpl::traverseNode( DOM_Node n, bool isFullySelected, bool isLeft, int how )
+{
+ if ( isFullySelected )
+ return traverseFullySelected( n, how );
+ if ( n.getNodeType()== DOM_Node::TEXT_NODE )
+ return traverseTextNode( n, isLeft, how );
+ return traversePartiallySelected( n, how );
+}
+
+/**
+ * Utility method for traversing a single node when
+ * we know a-priori that the node if fully
+ * selected.
+ *
+ */
+DOM_Node RangeImpl::traverseFullySelected( DOM_Node n, int how )
+{
+ switch( how )
+ {
+ case CLONE_CONTENTS:
+ return n.cloneNode( true );
+ case EXTRACT_CONTENTS:
+ if ( n.getNodeType()== DOM_Node::DOCUMENT_TYPE_NODE )
+ {
+ throw DOM_DOMException(
+ DOM_DOMException::HIERARCHY_REQUEST_ERR, null);
+ }
+ return n;
+ case DELETE_CONTENTS:
+ n.getParentNode().removeChild(n);
+ return null;
+ }
+ return null;
+}
+
+/**
+ * Utility method for traversing a single node when
+ * we know a-priori that the node if partially
+ * selected and is not a text node.
+ *
+ */
+DOM_Node RangeImpl::traversePartiallySelected( DOM_Node n, int how )
+{
+ switch( how )
+ {
+ case DELETE_CONTENTS:
+ return null;
+ case CLONE_CONTENTS:
+ case EXTRACT_CONTENTS:
+ return n.cloneNode( false );
+ }
+ return null;
+}
+
+/**
+ * Utility method for traversing a text node that we know
+ * a-priori to be on a left or right boundary of the range.
+ * This method does not properly handle text nodes that contain
+ * both the start and end points of the range.
+ *
+ */
+DOM_Node RangeImpl::traverseTextNode( DOM_Node n, bool isLeft, int how )
+{
+ DOMString txtValue = n.getNodeValue();
+ DOMString newNodeValue;
+ DOMString oldNodeValue;
+
+ if ( isLeft )
+ {
+ int offset = getStartOffset();
+ newNodeValue = txtValue.substringData( offset , fStartContainer.getNodeValue().length());
+ oldNodeValue = txtValue.substringData( 0, offset );
+ }
+ else
+ {
+ int offset = getEndOffset();
+ newNodeValue = txtValue.substringData( 0, offset );
+ oldNodeValue = txtValue.substringData( offset , fEndContainer.getNodeValue().length() );
+ }
+
+ if ( how != CLONE_CONTENTS )
+ n.setNodeValue( oldNodeValue );
+ if ( how==DELETE_CONTENTS )
+ return null;
+ DOM_Node newNode = n.cloneNode( false );
+ newNode.setNodeValue( newNodeValue );
+ return newNode;
+}
+
+/**
+ * Utility method to retrieve a child node by index. This method
+ * assumes the caller is trying to find out which node is
+ * selected by the given index. Note that if the index is
+ * greater than the number of children, this implies that the
+ * first node selected is the parent node itself.
+ *
+ */
+DOM_Node RangeImpl::getSelectedNode( DOM_Node container, int offset )
+{
+ if ( container.getNodeType() == DOM_Node::TEXT_NODE )
+ return container;
+
+ // This case is an important convenience for
+ // traverseRightBoundary()
+ if ( offset<0 )
+ return container;
+
+ DOM_Node child = container.getFirstChild();
+ while( child!=null && offset > 0 )
+ {
+ --offset;
+ child = child.getNextSibling();
+ }
+ if ( child!=null )
+ return child;
+ return container;
+}
+
+void RangeImpl::checkReadOnly(DOM_Node& start, DOM_Node& end,
unsigned int startOffset, unsigned int endOffset)
{
if ((start == null) || (end == null) ) return;
@@ -1399,7 +1516,7 @@
DOM_Node sNode = start.getFirstChild();
for(unsigned int i = 0; i<startOffset; i++)
sNode = sNode.getNextSibling();
-
+
DOM_Node eNode;
if (end.getNodeType() == DOM_Node::TEXT_NODE) {
eNode = end; //need to check only till this node
@@ -1415,7 +1532,7 @@
void RangeImpl::recurseTreeAndCheck(DOM_Node& start, DOM_Node& end)
{
- for(DOM_Node node=start; node != null, node !=end; node=node.getNextSibling())
+ for(DOM_Node node=start; node != null && node !=end; node=node.getNextSibling())
{
if (node.fImpl->isReadOnly()) {
throw DOM_DOMException(
@@ -1512,26 +1629,22 @@
if (node->getParentNode() == fEndContainer.fImpl) {
unsigned short index = indexOf(tNode, fEndContainer);
- if ( fEndOffset < index) {
+ if ( fEndOffset > index) {
fEndOffset--;
}
}
if (node->getParentNode() != fStartContainer.fImpl
- && node->getParentNode() != fEndContainer.fImpl) {
+ || node->getParentNode() != fEndContainer.fImpl) {
if (isAncestorOf(node, fStartContainer)) {
- if (( node->getParentNode()->getNodeType() == DOM_Node::DOCUMENT_FRAGMENT_NODE) )
- return; //if the node's up in the heirarchy and its parent is doc-frag ignore
DOM_Node tpNode(node->getParentNode());
setStartContainer( tpNode );
- fStartOffset = indexOf( tNode, tpNode)-1;
+ fStartOffset = indexOf( tNode, tpNode);
}
if (isAncestorOf(node, fEndContainer)) {
- if (( node->getParentNode()->getNodeType() == DOM_Node::DOCUMENT_FRAGMENT_NODE))
- return;
DOM_Node tpNode(node->getParentNode());
setEndContainer( tpNode );
- fEndOffset = indexOf( tNode, tpNode)-1;
+ fEndOffset = indexOf( tNode, tpNode);
}
}
@@ -1541,7 +1654,7 @@
if (node == null) return;
if (node->getParentNode() == fStartContainer.fImpl) {
- unsigned int index = indexOf(DOM_Node(node), fStartContainer) -1;
+ unsigned int index = indexOf(DOM_Node(node), fStartContainer);
if (index < fStartOffset) {
fStartOffset++;
}
@@ -1549,10 +1662,7 @@
if (node->getParentNode() == fEndContainer.fImpl) {
unsigned int index = indexOf(DOM_Node(node), fEndContainer);
- //if index is equal then the text is inserted before the end of
- //range so should get included in the range
-
- if (index <= fEndOffset) {
+ if (index < fEndOffset) {
fEndOffset++;
}
}
1.4 +17 -2 xml-xerces/c/src/dom/RangeImpl.hpp
Index: RangeImpl.hpp
===================================================================
RCS file: /home/cvs/xml-xerces/c/src/dom/RangeImpl.hpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- RangeImpl.hpp 2000/11/30 20:06:23 1.3
+++ RangeImpl.hpp 2000/12/06 19:42:46 1.4
@@ -57,7 +57,7 @@
*/
/*
- * $Id: RangeImpl.hpp,v 1.3 2000/11/30 20:06:23 andyh Exp $
+ * $Id: RangeImpl.hpp,v 1.4 2000/12/06 19:42:46 tng Exp $
*/
@@ -133,7 +133,8 @@
private:
enum TraversalType {
EXTRACT_CONTENTS = 1,
- CLONE_CONTENTS = 2
+ CLONE_CONTENTS = 2,
+ DELETE_CONTENTS = 3
};
enum TraversePoint {
@@ -151,6 +152,8 @@
//misc functions
void validateNode(const DOM_Node& node) const;
bool isValidAncestorType(const DOM_Node& node) const;
+ bool hasLegalRootContainer(const DOM_Node& node) const;
+ bool isLegalContainedNode(const DOM_Node& node ) const;
void checkIndex(const DOM_Node& node, unsigned int offset) const;
static bool isAncestorOf(const DOM_Node& a, const DOM_Node& b);
@@ -163,6 +166,18 @@
unsigned int starOffset, unsigned int endOffset);
void recurseTreeAndCheck(DOM_Node& start, DOM_Node& end);
DOM_Node removeChild(DOM_Node& parent, DOM_Node& child);
+
+ DOM_DocumentFragment traverseSameContainer( int how );
+ DOM_DocumentFragment traverseCommonStartContainer( DOM_Node endAncestor, int how );
+ DOM_DocumentFragment traverseCommonEndContainer( DOM_Node startAncestor, int how );
+ DOM_DocumentFragment traverseCommonAncestors( DOM_Node startAncestor, DOM_Node endAncestor, int how );
+ DOM_Node traverseRightBoundary( DOM_Node root, int how );
+ DOM_Node traverseLeftBoundary( DOM_Node root, int how );
+ DOM_Node traverseNode( DOM_Node n, bool isFullySelected, bool isLeft, int how );
+ DOM_Node traverseFullySelected( DOM_Node n, int how );
+ DOM_Node traversePartiallySelected( DOM_Node n, int how );
+ DOM_Node traverseTextNode( DOM_Node n, bool isLeft, int how );
+ DOM_Node getSelectedNode( DOM_Node container, int offset );
//private data
1.2 +512 -38 xml-xerces/c/tests/DOM/RangeTest/RangeTest.cpp
Index: RangeTest.cpp
===================================================================
RCS file: /home/cvs/xml-xerces/c/tests/DOM/RangeTest/RangeTest.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- RangeTest.cpp 2000/07/28 01:33:39 1.1
+++ RangeTest.cpp 2000/12/06 19:42:48 1.2
@@ -57,7 +57,7 @@
/**
- * $Id: RangeTest.cpp,v 1.1 2000/07/28 01:33:39 aruna1 Exp $
+ * $Id: RangeTest.cpp,v 1.2 2000/12/06 19:42:48 tng Exp $
*/
@@ -151,6 +151,7 @@
extractContents
toString
detach
+ removeChild
*/
{
@@ -223,13 +224,13 @@
//Tests start here
// Initial dom tree looks like :
- // <Body><H1>Title</H1><P>Blah xyz</P>
- //i.e., Body
- // _____________|______________
+ // <Body><H1>TitleAnother Text</H1><P>Blah xyz</P></Body>
+ //i.e., Body(rt)
+ // _____________|________________
// | |
- // H1 P
- // | |
- // "Title" "Blah xyz"
+ // ___H1(E11)___ P(E12)
+ // | | |
+ // "Title" "Another Text" "Blah xyz"
//test for start and end settings of a range
@@ -275,6 +276,17 @@
TASSERT(range.getEndContainer() == rt);
TASSERT(range.getEndOffset() == 5);
+ //After above operations, now the tree looks like:
+ // <Body><Element3/><H1>TitleAnother Text</H1><Element2/><Element1/><P>Blah xyz</P></Body>
+ //i.e., Body(rt)
+ // _____________|_______________________________________________________________
+ // | | | | |
+ // Element3(E122) ___H1(E11)___ Element2(E121) Element1(E120) P(E12)
+ // | | |
+ // "Title" "Another Text" "Blah xyz"
+ //
+ // range has rt as start and end container, and 2 as start offset, 5 as end offset
+
//changing selection
range.selectNode(rt.getLastChild().getPreviousSibling());
TASSERT(range.getStartContainer() == rt);
@@ -288,42 +300,86 @@
range.setStart(rt.getFirstChild().getNextSibling().getFirstChild(), 2);
TASSERT(range.getStartContainer() == rt.getFirstChild().getNextSibling().getFirstChild());
+ TASSERT(range.getStartContainer().getNodeValue().equals("Title"));
TASSERT(range.getStartOffset() == 2);
range.setEnd(rt.getFirstChild().getNextSibling().getFirstChild(), 4);
TASSERT(range.getEndContainer() == rt.getFirstChild().getNextSibling().getFirstChild());
+ TASSERT(range.getEndContainer().getNodeValue().equals("Title"));
TASSERT(range.getEndOffset() == 4);
+ TASSERT(range.toString().equals("tl"));
//inserting text between a text node
range.insertNode(E210);
//only end offset moves and new node gets into range as being inserted at boundary point
- TASSERT(range.getStartContainer() == rt.getFirstChild().getNextSibling().getLastChild().getPreviousSibling());
- TASSERT(range.getStartOffset() == 0);
+ TASSERT(range.getStartContainer() == rt.getFirstChild().getNextSibling().getFirstChild());
+ TASSERT(range.getStartOffset() == 2);
TASSERT(range.getEndContainer() == rt.getFirstChild().getNextSibling().getLastChild().getPreviousSibling());
TASSERT(range.getEndOffset() == 2);
- //inserting element node before the selcted text node
+ //inserting element node before the selected text node
range.insertNode(E120);
//only end offset moves and new node gets into range as being inserted at boundary point
- TASSERT(range.getStartContainer() == rt.getFirstChild().getNextSibling().getLastChild().getPreviousSibling());
- TASSERT(range.getStartOffset() == 0);
+ TASSERT(range.getStartContainer() == rt.getFirstChild().getNextSibling().getFirstChild());
+ TASSERT(range.getStartContainer().getNodeValue().equals("Ti"));
+ TASSERT(range.getStartOffset() == 2);
TASSERT(range.getEndContainer() == rt.getFirstChild().getNextSibling().getLastChild().getPreviousSibling());
+ TASSERT(range.getEndContainer().getNodeValue().equals("tle"));
TASSERT(range.getEndOffset() == 2);
+ TASSERT(E11.getChildNodes().getLength()==6);
//checking the text replacment
range.getStartContainer().setNodeValue("ReplacedText");
- //collapsed
- TASSERT(range.getCollapsed() == true);
-
- //the offsets are set to 0
+ //only the start offset is impact
+ TASSERT(range.getStartContainer() == rt.getFirstChild().getNextSibling().getFirstChild());
+ TASSERT(range.getStartContainer().getNodeValue().equals("ReplacedText"));
TASSERT(range.getStartOffset() == 0);
- TASSERT(range.getEndOffset() == 0);
+ TASSERT(range.getEndContainer() == rt.getFirstChild().getNextSibling().getLastChild().getPreviousSibling());
+ TASSERT(range.getEndContainer().getNodeValue().equals("tle"));
+ TASSERT(range.getEndOffset() == 2);
+
+ //After above operations, now the tree looks like:
+ // <Body><Element3/><H1>ReplacedText<Element1/>insertedTexttleAnother Text</H1><Element2/><P>Blah xyz</P></Body>
+ //i.e., Body(rt)
+ // _____________|_______________________________________________________________________________________________
+ // | | | |
+ // Element3(E122) ___H1(E11)___________________________________________________________ Element2(E121) P(E12)
+ // | | | | | | |
+ // "ReplacedText" "" Element1(E120) "insertedText"(E210) "tle" "Another Text" "Blah xyz"
+ //
+ // range has "ReplacedText" as start container and "tle" as end container
+ // and 0 as start offset, 2 as end offset
//changing the selection. Preparing for 'surround'
range.setStart(range.getStartContainer().getParentNode(), 2);
range.setEnd(range.getStartContainer(), 5);
+ TASSERT(range.getStartContainer().getNodeName().equals("H1"));
+ TASSERT(range.getEndContainer().getNodeName().equals("H1"));
+ TASSERT(range.toString().equals("insertedTexttle"));
+
range.surroundContents(E311);
+ TASSERT(range.getStartContainer().getNodeName().equals("H1"));
+ TASSERT(range.getStartOffset() == 2);
+ TASSERT(range.getEndContainer().getNodeName().equals("H1"));
+ TASSERT(range.getEndOffset() == 3);
+ TASSERT(E11.getChildNodes().getLength()==4);
+ TASSERT(E311.getChildNodes().getLength()==3);
+ TASSERT(range.toString().equals("insertedTexttle"));
+
+ //After above operations, now the tree looks like:
+ // <Body><Element3/><H1>ReplacedText<SurroundNode1><Element1/>insertedTexttle</SurroundNode1>Another Text</H1><Element2/><P>Blah xyz</P></Body>
+ //i.e., Body(rt)
+ // _____________|_________________________________________________________________________
+ // | | | |
+ // Element3(E122) ___H1(E11)___________________________________ Element2(E121) P(E12)
+ // | | | | |
+ // "ReplacedText" "" SurroundNode1(E311) "Another Text" "Blah xyz"
+ // ____________ |_____________________________
+ // | | |
+ // Element1(E120) "insertedText"(E210) "tle"
+ //
+ // range has H1 as start and end container and 2 as start offset, 3 as end offset
//testing cloning
DOM_Range aRange = range.cloneRange();
@@ -339,11 +395,11 @@
short compVal = range.compareBoundaryPoints(DOM_Range::END_TO_END, aRange);
TASSERT(compVal == 0);
compVal = range.compareBoundaryPoints(DOM_Range::START_TO_START, aRange);
- TASSERT(compVal == -1);
+ TASSERT(compVal == 1);
compVal = range.compareBoundaryPoints(DOM_Range::START_TO_END, aRange);
- TASSERT(compVal == -1);
- compVal = range.compareBoundaryPoints(DOM_Range::END_TO_START, aRange);
TASSERT(compVal == 1);
+ compVal = range.compareBoundaryPoints(DOM_Range::END_TO_START, aRange);
+ TASSERT(compVal == -1);
//testing collapse
//not collapsed
@@ -351,46 +407,50 @@
TASSERT(range.getStartOffset() == 2);
TASSERT(range.getEndOffset() == 3);
-
//selectNodeContents
range.selectNodeContents(rt.getLastChild().getFirstChild());
TASSERT(range.getStartContainer() == rt.getLastChild().getFirstChild());
TASSERT(range.getEndContainer() == rt.getLastChild().getFirstChild());
TASSERT(range.getStartOffset() == 0);
TASSERT(range.getEndOffset() == 8);
+ TASSERT(range.toString().equals("Blah xyz"));
//testing collapse
range.collapse(true); //collapse to start
TASSERT(range.getCollapsed() == true);
TASSERT(range.getStartOffset() == 0);
TASSERT(range.getEndOffset() == 0);
+ TASSERT(range.toString().equals(""));
TASSERT(aRange.getEndOffset() == 3); //other range is unaffected
+ TASSERT(aRange.toString().equals("eplacedTextinsertedTexttle"));
-
- // DOM Tree now looks like this
- // <Body>
- // |---------|----------|--------------|
- // Element3 H1 Element2 P
- // | |
- // |------|-----------| "Blah xyz"
- // "Ti" "insertedText" SurroundNode
- // |
- // |--------|---------------|
- // Element1 "ReplacedText "AnotherText"
-
- // range has H1 as start and end container and 2 as start and end offset. in collapsed state
- // aRange has "Ti" as start with 1 as start offset, H1 as end and 3 as end offset
-
-
+ //After above operations, now the tree looks like:
+ // <Body><Element3/><H1>ReplacedText<SurroundNode1><Element1/>insertedTexttle</SurroundNode1>Another Text</H1><Element2/><P>Blah xyz</P></Body>
+ //i.e., Body(rt)
+ // _____________|_________________________________________________________________________
+ // | | | |
+ // Element3(E122) ___H1(E11)___________________________________ Element2(E121) P(E12)
+ // | | | | |
+ // "ReplacedText" "" SurroundNode1(E311) "Another Text" "Blah xyz"
+ // ____________ |_____________________________
+ // | | |
+ // Element1(E120) "insertedText"(E210) "tle"
+ //
+ // range has "Blah xyz" as start and end container and 0 as start and end offset (collapsed)
+ // aRange has "ReplacedText" as start container and H1 as end container
+ // and 1 as start offset and 3 as end offset
DOM_DocumentFragment docFrag = aRange.cloneContents();
TASSERT( docFrag != 0);
range.selectNode(rt.getFirstChild());
TASSERT(range.getStartContainer() == rt);
+ TASSERT(range.getEndContainer() == rt);
+ TASSERT(range.getStartOffset() == 0);
+ TASSERT(range.getEndOffset() == 1);
//Testing toString()
const char* str = aRange.toString().transcode();
- char* str2 = "iinsertedTextReplacedTextAnotherText";
+ char* str2 = "eplacedTextinsertedTexttle";
TASSERT(*str == *str2);
//start and end before and after tests
@@ -413,10 +473,424 @@
//testing extract()
DOM_DocumentFragment frag2 = range.extractContents();
TASSERT( frag2 != 0);
+
+ //After above operations, now the tree looks like:
+ // <Body><Element3/></Body>
+ //i.e., Body(rt)
+ // |
+ // Element3(E122)
+ //
+ // aRange has rt as start and end container, and 1 as start and end offset (collapsed)
+ // range has rt as start and end container, and 1 as start and end offset (collapsed)
+ //
+ //and frag2 looks:
+ // <Body>ReplacedText<SurroundNode1><Element1/>insertedTexttle</SurroundNode1>Another Text</H1><Element2/><P>Blah xyz</P></Body>
+ //i.e., Body(rt)
+ // ______________|________________________________________________________
+ // | | |
+ // ___H1(E11)___________________________________ Element2(E121) P(E12)
+ // | | | | |
+ //"ReplacedText" "" SurroundNode1(E311) "Another Text" "Blah xyz"
+ // ____________ |_____________________________
+ // | | |
+ // Element1(E120) "insertedText"(E210) "tle"
+ //
+
+ //the tree do not have those node anymore after extract
+ //only Element3 left
+ TASSERT(rt.getChildNodes().getLength()==1);
+
+ //aRange is collapsed
+ TASSERT(aRange.getCollapsed() == true);
+ TASSERT(aRange.getStartContainer() == rt);
+ TASSERT(aRange.getStartOffset() == 1);
+ TASSERT(aRange.getEndContainer() == rt);
+ TASSERT(aRange.getEndOffset() == 1);
+
+ //range is collapsed as well
+ TASSERT(range.getCollapsed() == true);
+ TASSERT(range.getStartContainer() == rt);
+ TASSERT(range.getStartOffset() == 1);
+ TASSERT(range.getEndContainer() == rt);
+ TASSERT(range.getEndOffset() == 1);
+
+ //test the document fragment frag2
+ TASSERT(frag2.getChildNodes().getLength()==3);
+
//detaching the other range
aRange.detach();
range.detach();
+ //***************************************************************
+ //another set of test
+ //TEST createRange, setStart and setEnd, insertnode
+ //***************************************************************
+ DOM_Document doc2 = DOM_Document::createDocument();
+ DOM_Element root2 = doc2.createElement("root2");
+ doc2.appendChild(root2);
+ //case 1: simple text node, start==end
+ // <body>text1</body>
+ DOM_Element body = doc2.createElement("body");
+ DOM_Text text1 = doc2.createTextNode("text1");
+ body.appendChild(text1);
+ root2.appendChild(body);
+
+ //set range
+ DOM_Range range1 = doc2.createRange();
+ range1.setStart(text1,1);
+ range1.setEnd(text1,3);
+
+ TASSERT(range1.toString().equals("ex"));
+ TASSERT(range1.getStartOffset()==1);
+ TASSERT(range1.getStartContainer().getNodeValue().equals("text1"));
+ TASSERT(range1.getEndOffset()==3);
+ TASSERT(range1.getEndContainer().getNodeValue().equals("text1"));
+
+ //now insert a text node
+ //<body>ttext2ext1</body>
+ DOM_Text text2 = doc2.createTextNode("text2");
+ range1.insertNode(text2);
+
+ TASSERT(range1.toString().equals("text2ex"));
+ TASSERT(range1.getStartOffset()==1);
+ TASSERT(range1.getStartContainer().getNodeValue().equals("t"));
+ TASSERT(range1.getEndOffset()==2);
+ TASSERT(range1.getEndContainer().getNodeValue().equals("ext1"));
+
+ //now insert a non-text node
+ //<body>t<p1/>text2ext1</body>
+ DOM_Element p1 = doc2.createElement("p1");
+ range1.insertNode(p1);
+
+ TASSERT(range1.toString().equals("text2ex"));
+ TASSERT(range1.getStartOffset()==1);
+ TASSERT(range1.getStartContainer().getNodeValue().equals("t"));
+ TASSERT(range1.getEndOffset()==2);
+ TASSERT(range1.getEndContainer().getNodeValue().equals("ext1"));
+
+ //case 2: non-text node, start==end
+ // <head><h1/></head>
+ DOM_Element head = doc2.createElement("head");
+ DOM_Element h1 = doc2.createElement("h1");
+ head.appendChild(h1);
+ root2.appendChild(head);
+
+ //set range
+ DOM_Range range2 = doc2.createRange();
+ range2.setStart(head,0);
+ range2.setEnd(head,1);
+
+ TASSERT(range2.toString().equals(""));
+ TASSERT(range2.getStartOffset()==0);
+ TASSERT(range2.getStartContainer().getNodeName().equals("head"));
+ TASSERT(range2.getEndOffset()==1);
+ TASSERT(range2.getEndContainer().getNodeName().equals("head"));
+
+ //now insert a non-text node
+ //<head><h2/><h1/></head>
+ DOM_Element h2 = doc2.createElement("h2");
+ range2.insertNode(h2);
+
+ TASSERT(range2.toString().equals(""));
+ TASSERT(range2.getStartOffset()==0);
+ TASSERT(range2.getStartContainer().getNodeName().equals("head"));
+ TASSERT(range2.getEndOffset()==2);
+ TASSERT(range2.getEndContainer().getNodeName().equals("head"));
+
+ //now insert a text node
+ //<head>text5<h2/><h1/></head>
+ DOM_Text text5 = doc2.createTextNode("text5");
+ range2.insertNode(text5);
+
+ TASSERT(range2.toString().equals("text5"));
+ TASSERT(range2.getStartOffset()==0);
+ TASSERT(range2.getStartContainer().getNodeName().equals("head"));
+ TASSERT(range2.getEndOffset()==3);
+ TASSERT(range2.getEndContainer().getNodeName().equals("head"));
+
+ //case 3: simple text node, start!=end
+ // <body2>text3</body2>
+ DOM_Element body2 = doc2.createElement("body2");
+ DOM_Text text3 = doc2.createTextNode("text3");
+ body2.appendChild(text3);
+ root2.appendChild(body2);
+
+ //set range
+ DOM_Range range3 = doc2.createRange();
+ range3.setStart(text3,1);
+ range3.setEnd(body2,1);
+
+ TASSERT(range3.toString().equals("ext3"));
+ TASSERT(range3.getStartOffset()==1);
+ TASSERT(range3.getStartContainer().getNodeValue().equals("text3"));
+ TASSERT(range3.getEndOffset()==1);
+ TASSERT(range3.getEndContainer().getNodeName().equals("body2"));
+
+ //now insert a textnode
+ //<body2>ttext4ext3</body2>
+ DOM_Text text4 = doc2.createTextNode("text4");
+ range3.insertNode(text4);
+
+ TASSERT(range3.toString().equals(""));
+ TASSERT(range3.getStartOffset()==1);
+ TASSERT(range3.getStartContainer().getNodeValue().equals("t"));
+ TASSERT(range3.getEndOffset()==1);
+ TASSERT(range3.getEndContainer().getNodeName().equals("body2"));
+
+ //now insert a non-text node
+ //<body2>t<p2/>text4ext3</body2>
+ DOM_Element p2 = doc2.createElement("p2");
+ range3.insertNode(p2);
+
+ //extra empty node caused by splitting 't'
+ TASSERT(range3.toString().equals(""));
+ TASSERT(range3.getStartOffset()==1);
+ TASSERT(range3.getStartContainer().getNodeValue().equals("t"));
+ TASSERT(range3.getEndOffset()==1);
+ TASSERT(range3.getEndContainer().getNodeName().equals("body2"));
+
+ //test toString a bit
+ range3.setStart(body2,1);
+ range3.setEnd(body2,5);
+
+ TASSERT(range3.toString().equals("text4ext3"));
+
+ range3.setStart(body2,0);
+ range3.setEnd(body2,5);
+
+ TASSERT(range3.toString().equals("ttext4ext3"));
+
+ //case 4: non-text node, start!=end
+ // <head2><h3/></head2>
+ DOM_Element head2 = doc2.createElement("head2");
+ DOM_Element h3 = doc2.createElement("h3");
+ head2.appendChild(h3);
+ root2.appendChild(head2);
+
+ //set range
+ DOM_Range range4 = doc2.createRange();
+ range4.setStart(head2,0);
+ range4.setEnd(h3,0);
+
+ TASSERT(range4.toString().equals(""));
+ TASSERT(range4.getStartOffset()==0);
+ TASSERT(range4.getStartContainer().getNodeName().equals("head2"));
+ TASSERT(range4.getEndOffset()==0);
+ TASSERT(range4.getEndContainer().getNodeName().equals("h3"));
+
+ //now insert a non-text node
+ //<head2><h4/><h3/></head2>
+ DOM_Element h4 = doc2.createElement("h4");
+ range4.insertNode(h4);
+
+ TASSERT(range4.toString().equals(""));
+ TASSERT(range4.getStartOffset()==0);
+ TASSERT(range4.getStartContainer().getNodeName().equals("head2"));
+ TASSERT(range4.getEndOffset()==0);
+ TASSERT(range4.getEndContainer().getNodeName().equals("h3"));
+
+ //now insert a text node
+ //<head2>text6<h4/><h3/></head2>
+ DOM_Text text6 = doc2.createTextNode("text6");
+ range4.insertNode(text6);
+
+ TASSERT(range4.toString().equals("text6"));
+ TASSERT(range4.getStartOffset()==0);
+ TASSERT(range4.getStartContainer().getNodeName().equals("head2"));
+ TASSERT(range4.getEndOffset()==0);
+ TASSERT(range4.getEndContainer().getNodeName().equals("h3"));
+
+ //***************************************************************
+ // quick test of updating
+ //***************************************************************
+ // <upbody>text1</upbody>
+ DOM_Element upbody = doc2.createElement("upbody");
+ DOM_Text uptext1 = doc2.createTextNode("uptext1");
+ upbody.appendChild(uptext1);
+ root2.appendChild(upbody);
+
+ DOM_Range uprange = doc2.createRange();
+ uprange.setStart(upbody,0);
+ uprange.setEnd(upbody,1);
+
+ TASSERT(uprange.toString().equals("uptext1"));
+ TASSERT(uprange.getStartOffset()==0);
+ TASSERT(uprange.getStartContainer().getNodeName().equals("upbody"));
+ TASSERT(uprange.getEndOffset()==1);
+ TASSERT(uprange.getEndContainer().getNodeName().equals("upbody"));
+
+ // split text
+ uptext1.splitText(1);
+
+ TASSERT(uprange.toString().equals("u"));
+ TASSERT(uprange.getStartOffset()==0);
+ TASSERT(uprange.getStartContainer().getNodeName().equals("upbody"));
+ TASSERT(uprange.getEndOffset()==1);
+ TASSERT(uprange.getEndContainer().getNodeName().equals("upbody"));
+
+ //insert node
+ DOM_Element upbody2 = doc2.createElement("upbody2");
+ DOM_Text uptext2 = doc2.createTextNode("uptext2");
+ upbody2.appendChild(uptext2);
+ root2.appendChild(upbody2);
+
+ DOM_Range uprange2 = doc2.createRange();
+ uprange2.setStart(uptext2,1);
+ uprange2.setEnd(upbody2,1);
+
+ DOM_Range uprange3 = doc2.createRange();
+ uprange3.setStart(uptext2,1);
+ uprange3.setEnd(upbody2,1);
+
+ TASSERT(uprange2.toString().equals("ptext2"));
+ TASSERT(uprange2.getStartOffset()==1);
+ TASSERT(uprange2.getStartContainer().getNodeValue().equals("uptext2"));
+ TASSERT(uprange2.getEndOffset()==1);
+ TASSERT(uprange2.getEndContainer().getNodeName().equals("upbody2"));
+
+ TASSERT(uprange3.toString().equals("ptext2"));
+ TASSERT(uprange3.getStartOffset()==1);
+ TASSERT(uprange3.getStartContainer().getNodeValue().equals("uptext2"));
+ TASSERT(uprange3.getEndOffset()==1);
+ TASSERT(uprange3.getEndContainer().getNodeName().equals("upbody2"));
+
+ DOM_Element upp1 = doc2.createElement("upp1");
+ uprange2.insertNode(upp1);
+
+ TASSERT(uprange2.toString().equals(""));
+ TASSERT(uprange2.getStartOffset()==1);
+ TASSERT(uprange2.getStartContainer().getNodeValue().equals("u"));
+ TASSERT(uprange2.getEndOffset()==1);
+ TASSERT(uprange2.getEndContainer().getNodeName().equals("upbody2"));
+
+ TASSERT(uprange3.toString().equals(""));
+ TASSERT(uprange3.getStartOffset()==1);
+ TASSERT(uprange3.getStartContainer().getNodeValue().equals("u"));
+ TASSERT(uprange3.getEndOffset()==1);
+ TASSERT(uprange3.getEndContainer().getNodeName().equals("upbody2"));
+
+ //***************************************************************
+ //another set of test
+ //<foo><c/><moo><b/></moo>ab<a>Hello cd</a><cool>ef</cool></foo>
+ //
+ // ______________________foo_____________________
+ // | | | | |
+ // c moo "ab" a cool
+ // | | |
+ // b "Hello cd" "ef"
+ //
+ DOM_Document doc3 = DOM_Document::createDocument();
+ DOM_Element root3 = doc3.createElement("root");
+ doc3.appendChild(root3);
+
+ DOM_Element foo = doc3.createElement("foo");
+ DOM_Element moo = doc3.createElement("moo");
+ DOM_Element cool = doc3.createElement("cool");
+ DOM_Text ab = doc3.createTextNode("ab");
+ DOM_Text cd = doc3.createTextNode("Hello cd");
+ DOM_Text ef = doc3.createTextNode("ef");
+
+ DOM_Element a = doc3.createElement("a");
+ DOM_Element b = doc3.createElement("b");
+ DOM_Element c = doc3.createElement("c");
+
+ root3.appendChild(foo);
+ foo.appendChild(c);
+ foo.appendChild(moo);
+ foo.appendChild(ab);
+ foo.appendChild(a);
+ foo.appendChild(cool);
+ moo.appendChild(b);
+ a.appendChild(cd);
+ cool.appendChild(ef);
+
+ //***************************************************************
+ //TEST toString
+ //***************************************************************
+ DOM_Range newtestrange = doc3.createRange();
+ //case 1:
+ //start container is text node
+ // i) end container is also text node
+ // a) start==end
+ // b) start!=end
+ // ii) end container is not text node
+ // a) start==end => impossible
+ // b) start!=end
+ //
+ //case 2:
+ //start container is not text node
+ // i) end container is text node
+ // a) start==end => impossible
+ // b) start!=end
+ // ii) end container is not text node
+ // a) start==end
+ // b) start!=end
+
+ //case 1, i, a
+ newtestrange.setStart( cd, 1 );
+ newtestrange.setEnd( cd, 4 );
+
+ TASSERT(newtestrange.toString().equals("ell"));
+
+ //case 1, i, b
+ newtestrange.setStart( cd, 1 );
+ newtestrange.setEnd( ef, 2 );
+
+ TASSERT(newtestrange.toString().equals("ello cdef"));
+
+ //case 1, ii, b
+ newtestrange.setStart( cd, 1 );
+ newtestrange.setEnd( foo, 4 );
+
+ TASSERT(newtestrange.toString().equals("ello cd"));
+
+ //case 2, i, b
+ newtestrange.setStart( foo, 1 );
+ newtestrange.setEnd( cd, 5 );
+
+ TASSERT(newtestrange.toString().equals("abHello"));
+
+ //case 2, ii, a
+ newtestrange.setStart( foo, 1 );
+ newtestrange.setEnd( foo, 4 );
+
+ TASSERT(newtestrange.toString().equals("abHello cd"));
+
+ //case 2, ii, b
+ newtestrange.setStart( moo, 1 );
+ newtestrange.setEnd( foo, 4 );
+
+ TASSERT(newtestrange.toString().equals("abHello cd"));
+
+ //***************************************************************
+ //test removeChild
+ //***************************************************************
+ DOM_Range newrange = doc3.createRange();
+ newrange.setStart( moo, 0 );
+ newrange.setEnd( foo, 4 );
+
+ TASSERT(newrange.getStartOffset()==0);
+ TASSERT(newrange.getStartContainer().getNodeName().equals("moo"));
+ TASSERT(newrange.getEndOffset()==4);
+ TASSERT(newrange.getEndContainer().getNodeName().equals("foo"));
+ TASSERT(newrange.toString().equals("abHello cd"));
+
+ DOM_Node n = newrange.cloneContents();
+ DOM_NodeList nol = foo.getChildNodes();
+
+ //removing moo
+ foo.removeChild(nol.item(1));
+ TASSERT(newrange.getStartOffset()==1);
+ TASSERT(newrange.getStartContainer().getNodeName().equals("foo"));
+ TASSERT(newrange.getEndOffset()==3);
+ TASSERT(newrange.getEndContainer().getNodeName().equals("foo"));
+ TASSERT(newrange.toString().equals("abHello cd"));
+
+ TASSERT(newtestrange.getStartOffset()==1);
+ TASSERT(newtestrange.getStartContainer().getNodeName().equals("foo"));
+ TASSERT(newtestrange.getEndOffset()==3);
+ TASSERT(newtestrange.getEndContainer().getNodeName().equals("foo"));
+ TASSERT(newtestrange.toString().equals("abHello cd"));
}
TESTEPILOG;