unsigned short RangeImpl::indexOf(const DOM_Node& child, const DOM_Node& parent) const { unsigned short i = 0; if (child.getParentNode() != parent) return (unsigned short)-1; for(DOM_Node node = child.getPreviousSibling(); node!= null; node=node.getPreviousSibling()) { i++; } return i; }
void RangeImpl::setEndAfter(const DOM_Node& 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; for (DOM_Node n = refNode; n!=null; n = n.getPreviousSibling(), i++) ; if (i ==0) fEndOffset = 0; else fEndOffset = i; if ((fDocument != refNode.getOwnerDocument() ) && (refNode.getOwnerDocument().fImpl != 0) ) { fDocument = refNode.getOwnerDocument(); collapse(true); } //compare the start and end boundary point //collapse if start point is after the end point if(compareBoundaryPoints(DOM_Range::END_TO_START, this) == 1) collapse(false); //collapse the range positions to end else fCollapsed = false; }
DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) { if (fDetached) throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null); DOM_Node result; // if we're at the root, return null. if (node == fRoot) return result; // get sibling result = node.getPreviousSibling(); if (result.isNull()) { //if 1st sibling, return parent result = node.getParentNode(); return result; } // if sibling has children, keep getting last child of child. if (result.hasChildNodes()) { while (result.hasChildNodes()) { result = result.getLastChild(); } } return result; }
/** * 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; }
/** * 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; }
DOM_Node TreeWalkerImpl::getPreviousSibling (DOM_Node node) { DOM_Node result; if (node.isNull() || node == fRoot) return result; DOM_Node newNode = node.getPreviousSibling(); if (newNode.isNull()) { newNode = node.getParentNode(); if (newNode.isNull() || node == fRoot) return result; short parentAccept = acceptNode(newNode); if (parentAccept == DOM_NodeFilter::FILTER_SKIP) { return getPreviousSibling(newNode); } return result; } short accept = acceptNode(newNode); if (accept == DOM_NodeFilter::FILTER_ACCEPT) return newNode; else if (accept == DOM_NodeFilter::FILTER_SKIP) { DOM_Node fChild = getLastChild(newNode); if (fChild.isNull()) { return getPreviousSibling(newNode); } return fChild; } return getPreviousSibling(newNode); }