rangeimpl.java
来自「JAVA 所有包」· Java 代码 · 共 1,729 行 · 第 1/5 页
JAVA
1,729 行
{ 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. * This method is invoked by * the generic <code>traverse</code> method. * * @param startAncestor * Given a common ancestor of the start and end containers, * this parameter is the ancestor (or self) of the start * container that is a direct child of the common ancestor. * * @param endAncestor * Given a common ancestor of the start and end containers, * this parameter is the ancestor (or self) of the end * container that is a direct child of the common ancestor. * * @param how Specifies what type of traversal is being * requested (extract, clone, or delete). * Legal values for this argument are: * * <ol> * <li><code>EXTRACT_CONTENTS</code> - will produce * a document fragment containing the range's content. * Partially selected nodes are copied, but fully * selected nodes are moved. * * <li><code>CLONE_CONTENTS</code> - will leave the * context tree of the range undisturbed, but sill * produced cloned content in a document fragment * * <li><code>DELETE_CONTENTS</code> - will delete from * the context tree of the range, all fully selected * nodes. * </ol> * * @return Returns a document fragment containing any * copied or extracted nodes. If the <code>how</code> * parameter was <code>DELETE_CONTENTS</code>, the * return value is null. */ private DocumentFragment traverseCommonAncestors( Node startAncestor, Node endAncestor, int how ) { DocumentFragment frag = null; if ( how!=DELETE_CONTENTS) frag = fDocument.createDocumentFragment(); Node n = traverseLeftBoundary( startAncestor, how ); if ( frag!=null ) frag.appendChild( n ); Node commonParent = startAncestor.getParentNode(); int startOffset = indexOf( startAncestor, commonParent ); int endOffset = indexOf( endAncestor, commonParent ); ++startOffset; int cnt = endOffset - startOffset; Node sibling = startAncestor.getNextSibling(); while( cnt > 0 ) { 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 * <code>how</code> parameter. It is a-priori assumed * by this method that the right boundary does * not contain the range's start container. * <p> * A "right boundary" is best visualized by thinking * of a sample tree:<pre> * A * /|\ * / | \ * / | \ * B C D * /|\ /|\ * E F G H I J * </pre> * 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: * <p> * Partially Selected Nodes: B, D<br> * Fully Selected Nodes: F, G, C, H, I * <p> * The "right boundary" is the highest subtree node * that contains the ending container. The root of * this subtree is always partially selected. * <p> * In this example, the nodes that are traversed * as "right boundary" nodes are: H, I, and D. * * @param root The node that is the root of the "right boundary" subtree. * * @param how Specifies what type of traversal is being * requested (extract, clone, or delete). * Legal values for this argument are: * * <ol> * <li><code>EXTRACT_CONTENTS</code> - will produce * a node containing the boundaries content. * Partially selected nodes are copied, but fully * selected nodes are moved. * * <li><code>CLONE_CONTENTS</code> - will leave the * context tree of the range undisturbed, but will * produced cloned content. * * <li><code>DELETE_CONTENTS</code> - will delete from * the context tree of the range, all fully selected * nodes within the boundary. * </ol> * * @return Returns a node that is the result of visiting nodes. * If the traversal operation is * <code>DELETE_CONTENTS</code> the return value is null. */ private Node traverseRightBoundary( Node root, int how ) { Node next = getSelectedNode( fEndContainer, fEndOffset-1 ); boolean isFullySelected = ( next!=fEndContainer ); if ( next==root ) return traverseNode( next, isFullySelected, false, how ); Node parent = next.getParentNode(); Node clonedParent = traverseNode( parent, false, false, how ); while( parent!=null ) { while( next!=null ) { Node prevSibling = next.getPreviousSibling(); 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(); 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 * <code>how</code> parameter. It is a-priori assumed * by this method that the left boundary does * not contain the range's end container. * <p> * A "left boundary" is best visualized by thinking * of a sample tree:<pre> * * A * /|\ * / | \ * / | \ * B C D * /|\ /|\ * E F G H I J * </pre> * 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: * <p> * Partially Selected Nodes: B, D<br> * Fully Selected Nodes: F, G, C, H, I * <p> * The "left boundary" is the highest subtree node * that contains the starting container. The root of * this subtree is always partially selected. * <p> * In this example, the nodes that are traversed * as "left boundary" nodes are: F, G, and B. * * @param root The node that is the root of the "left boundary" subtree. * * @param how Specifies what type of traversal is being * requested (extract, clone, or delete). * Legal values for this argument are: * * <ol> * <li><code>EXTRACT_CONTENTS</code> - will produce * a node containing the boundaries content. * Partially selected nodes are copied, but fully * selected nodes are moved. * * <li><code>CLONE_CONTENTS</code> - will leave the * context tree of the range undisturbed, but will * produced cloned content. * * <li><code>DELETE_CONTENTS</code> - will delete from * the context tree of the range, all fully selected * nodes within the boundary. * </ol> * * @return Returns a node that is the result of visiting nodes. * If the traversal operation is * <code>DELETE_CONTENTS</code> the return value is null. */ private Node traverseLeftBoundary( Node root, int how ) { Node next = getSelectedNode( getStartContainer(), getStartOffset() ); boolean isFullySelected = ( next!=getStartContainer() ); if ( next==root ) return traverseNode( next, isFullySelected, true, how ); Node parent = next.getParentNode(); Node clonedParent = traverseNode( parent, false, true, how ); while( parent!=null ) { while( next!=null ) { Node nextSibling = next.getNextSibling(); 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(); 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. * * @param n The node to be traversed. * * @param isFullySelected * Set to true if the node is fully selected. Should be * false otherwise. * Note that although the DOM 2 specification says that a * text node that is boththe start and end container is not * selected, we treat it here as if it were partially * selected. * * @param isLeft Is true if we are traversing the node as part of navigating * the "left boundary" of the range. If this value is false, * it implies we are navigating the "right boundary" of the * range. * * @param how Specifies what type of traversal is being * requested (extract, clone, or delete). * Legal values for this argument are: * * <ol> * <li><code>EXTRACT_CONTENTS</code> - will simply * return the original node. * * <li><code>CLONE_CONTENTS</code> - will leave the * context tree of the range undisturbed, but will * return a cloned node. * * <li><code>DELETE_CONTENTS</code> - will delete the * node from it's parent, but will return null. * </ol> * * @return Returns a node that is the result of visiting the node. * If the traversal operation is * <code>DELETE_CONTENTS</code> the return value is null. */ private Node traverseNode( Node n, boolean isFullySelected, boolean isLeft, int how ) { if ( isFullySelected ) return traverseFullySelected( n, how ); if ( n.getNodeType()==Node.TEXT_NODE ) return traverseTextNode( n, isLeft, how ); return traversePartiallySelected( n, how ); } /** * Utility method for traversing a single node when * we know a-priori
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?