def insertNode(self, newNode): """Insert a node at the starting point""" if self.detached: raise InvalidStateErr() if newNode.nodeType in [ Node.ATTRIBUTE_NODE, Node.ENTITY_NODE, Node.NOTATION_NODE, Node.DOCUMENT_NODE, ]: raise InvalidNodeTypeErr() if self.startContainer.nodeType == Node.TEXT_NODE: #Split the text at the boundary. Insert the node after this otherText = self.startContainer.substringData( self.startOffset, len(self.startContainer.data)) self.startContainer.deleteData(self.startOffset, len(self.startContainer.data)) newText = self._ownerDocument.createTextNode(otherText) self.startContainer.parentNode.insertBefore( newText, self.startContainer.nextSibling) newText.parentNode.insertBefore(newNode, newText) elif self.startContainer.nodeType in [ Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: raise HierarchyRequestErr() else: curNode = self.startContainer.childNodes[self.startOffset] self.startContainer.insertBefore(newNode, curNode.nextSibling)
def cloneRange(self): if self.detached: raise InvalidStateErr() newRange = Range(self._ownerDocument) newRange.setStart(self.startContainer, self.startOffset) newRange.setEnd(self.endContainer, self.endOffset) return newRange
def previousNode(self): if self._detached: raise InvalidStateErr() prev_node = self._regress() while (prev_node and not ( self._checkWhatToShow(prev_node) and self._checkFilter(prev_node) == NodeFilter.FILTER_ACCEPT)): prev_node = self._regress() return prev_node
def nextNode(self): if self._detached: raise InvalidStateErr() next_node = self._advance() while (next_node and not ( self._checkWhatToShow(next_node) and self._checkFilter(next_node) == NodeFilter.FILTER_ACCEPT)): next_node = self._advance() return next_node
def toString(self): if self.detached: raise InvalidStateErr() df = self.cloneContents() res = self.__recurseToString(df) from pyxml.dom.ext import ReleaseNode ReleaseNode(df) return res
def collapse(self, toStart): """Collapse the range""" if self.detached: raise InvalidStateErr() if toStart: self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.startOffset else: self.__dict__['startContainer'] = self.endContainer self.__dict__['startOffset'] = self.endOffset self.__dict__['collapsed'] = 1 self.__dict__['commonAncestorContainer'] = self.startContainer
def selectNodeContents(self, refNode): """Select a node""" if self.detached: raise InvalidStateErr() self.__validateBoundary(refNode, 0) self.__dict__['startContainer'] = refNode self.__dict__['endContainer'] = refNode self.__dict__['startOffset'] = 0 self.__dict__['endOffset'] = len(refNode.childNodes) self.__dict__['collapsed'] = self.startOffset == self.endOffset self.__dict__['commonAncestorContainer'] = refNode
def selectNode(self, refNode): """Select a node""" if self.detached: raise InvalidStateErr() self.__validateRefNode(refNode) self.__dict__['startContainer'] = refNode.parentNode self.__dict__['endContainer'] = refNode.parentNode index = refNode.parentNode.childNodes.index(refNode) self.__dict__['startOffset'] = index self.__dict__['endOffset'] = index + 1 self.__dict__['collapsed'] = 0 self.__dict__['commonAncestorContainer'] = refNode.parentNode
def surroundContents(self, newParent): """Surround the range with this node""" if self.detached: raise InvalidStateErr() if newParent.nodeType in [ Node.ATTRIBUTE_NODE, Node.ENTITY_NODE, Node.DOCUMENT_TYPE_NODE, Node.NOTATION_NODE, Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE ]: raise InvalidNodeTypeErr() #See is we have element nodes that are partially selected if self.startContainer.nodeType not in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: if self.commonAncestorContainer not in [ self.startContainer, self.startContainer.parentNode ]: #This is partially selected because our parent is not the common ancestor raise BadBoundaryPointsErr() if self.endContainer.nodeType not in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: if self.commonAncestorContainer not in [ self.endContainer, self.endContainer.parentNode ]: #This is partially selected because our parent is not the common ancestor raise BadBoundaryPointsErr() #All good, do the insert #Remove children from newPArent for c in newParent.childNodes: newParent.removeChild(c) df = self.extractContents() self.insertNode(newParent) newParent.appendChild(df) self.selectNode(newParent)
def setStart(self, parent, offset): """Set the ranges start container and offset""" #Check for errors if self.detached: raise InvalidStateErr() self.__validateBoundary(parent, offset) self.__dict__['startContainer'] = parent self.__dict__['startOffset'] = offset pos = self.__comparePositions(parent, offset, self.endContainer, self.endOffset) self.__dict__['collapsed'] = (pos == self.POSITION_EQUAL) if pos == self.POSITION_GREATER_THAN: self.__dict__['endContainer'] = parent self.__dict__['endOffset'] = offset self.__dict__['collapsed'] = 1 self.__calculateCommonAncestor()
def compareBoundaryPoints(self, how, sourceRange): if self.detached: raise InvalidStateErr() if not hasattr( sourceRange, '_ownerDocument' ) or sourceRange._ownerDocument != self._ownerDocument or not isinstance( sourceRange, Range): raise WrongDocumentErr() if how == self.START_TO_START: ac = self.startContainer ao = self.startOffset bc = sourceRange.startContainer bo = sourceRange.startOffset elif how == self.START_TO_END: ac = self.startContainer ao = self.startOffset bc = sourceRange.endContainer bo = sourceRange.endOffset elif how == self.END_TO_END: ac = self.endContainer ao = self.endOffset bc = sourceRange.endContainer bo = sourceRange.endOffset elif how == self.END_TO_START: ac = self.endContainer ao = self.endOffset bc = sourceRange.startContainer bo = sourceRange.startOffset else: raise TypeError, how pos = self.__comparePositions(ac, ao, bc, bo) if pos == self.POSITION_EQUAL: return 0 elif pos == self.POSITION_LESS_THAN: return -1 return 1
def cloneContents(self): """Clone the contents defined by this range""" if self.detached: raise InvalidStateErr() df = self._ownerDocument.createDocumentFragment() if self.startContainer == self.endContainer: if self.startOffset == self.endOffset: return df if self.startContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data data = self.startContainer.substringData( self.startOffset, 1 + self.endOffset - self.startOffset) tx = self._ownerDocument.createTextNode(data) df.appendChild(tx) else: #Clone a set number of children numDel = self.endOffset - self.startOffset + 1 for ctr in range(numDel): c = self.startContainer.childNodes[self.startOffset + ctr].cloneNode(1) df.appendChild(c) elif self.startContainer == self.commonAncestorContainer: #Clone up the endContainer #From the start to the end lastKids = [] copyData = None if self.endContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data copyData = self.endContainer.substringData(0, self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): lastKids.append( self.endContainer.childNodes[ctr].cloneNode(1)) cur = self.endContainer while cur.parentNode != self.commonAncestorContainer: #Clone all of the way up newCur = cur.cloneNode(0) if copyData: newCur.data = copyData copyData = None for k in lastKids: newCur.appendChild(k) lastKids = [] index = cur.parentNode.childNodes.index(cur) for ctr in range(index): lastKids.append( cur.parentNode.childNodes[ctr].cloneNode(1)) lastKids.append(newCur) cur = cur.parentNode newEnd = cur.cloneNode(0) for k in lastKids: newEnd.appendChild(k) endAncestorChild = cur #Extract up to the ancestor of end for c in self.startContainer.childNodes: if c == endAncestorChild: break df.appendChild(c.cloneNode(1)) df.appendChild(newEnd) elif self.endContainer == self.commonAncestorContainer: lastKids = [] copyData = None if self.startContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data copyData = self.startContainer.substringData( self.startOffset, 1 + len(self.startContainer.data) - self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.childNodes[self.startOffset + ctr].cloneNode(1) lastKids.append(c) cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: #Clone all of the way up newCur = cur.cloneNode(0) if copyData: newCur.data = copyData copyData = None for k in lastKids: newCur.appendChild(k) lastKids = [newCur] index = cur.parentNode.childNodes.index(cur) for ctr in range(index + 1, len(cur.parentNode.childNodes)): lastKids.append( cur.parentNode.childNodes[ctr].cloneNode(1)) cur = cur.parentNode startAncestorChild = cur newStart = cur.cloneNode(0) for k in lastKids: newStart.appendChild(k) df.appendChild(newStart) #Extract up to the ancestor of start startAncestorChild = cur startIndex = self.endContainer.childNodes.index(cur) lastAdded = None for ctr in range(startIndex + 1, self.endOffset + 1): c = self.endContainer.childNodes[ctr].cloneNode(1) df.insertBefore(c, lastAdded) lastAdded = c else: #From the start to the end lastStartKids = [] startCopyData = None if self.startContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data startCopyData = self.startContainer.substringData( self.startOffset, 1 + len(self.startContainer.data) - self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.childNodes[self.startOffset + ctr].cloneNode(1) lastStartKids.append(c) cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: #Clone all of the way up newCur = cur.cloneNode(0) if startCopyData: newCur.data = startCopyData startCopyData = None for k in lastStartKids: newCur.appendChild(k) lastStartKids = [newCur] index = cur.parentNode.childNodes.index(cur) for ctr in range(index + 1, len(cur.parentNode.childNodes)): lastStartKids.append( cur.parentNode.childNodes[ctr].cloneNode(1)) cur = cur.parentNode startAncestorChild = cur newStart = cur.cloneNode(0) for k in lastStartKids: newStart.appendChild(k) df.appendChild(newStart) lastEndKids = [] endCopyData = None #Delete up the endContainer #From the start to the end if self.endContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data endCopyData = self.endContainer.substringData( 0, self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): c = self.endContainer.childNodes[ctr].cloneNode(1) lastEndKids.append(c) cur = self.endContainer while cur.parentNode != self.commonAncestorContainer: newCur = cur.cloneNode(0) if endCopyData: newCur.data = endCopyData endCopyData = None for k in lastEndKids: newCur.appendChild(k) lastEndKids = [] index = cur.parentNode.childNodes.index(cur) for ctr in range(index): lastEndKids.append( cur.parentNode.childNodes[ctr].cloneNode(1)) lastEndKids.append(newCur) cur = cur.parentNode endAncestorChild = cur newEnd = cur.cloneNode(0) for k in lastEndKids: newEnd.appendChild(k) cur = startAncestorChild #Extract everything between us startIndex = startAncestorChild.parentNode.childNodes.index( startAncestorChild) endIndex = endAncestorChild.parentNode.childNodes.index( endAncestorChild) for ctr in range(startIndex + 1, endIndex): c = startAncestorChild.parentNode.childNodes[ctr] df.appendChild(c.cloneNode(1)) df.appendChild(newEnd) #Adjust the containers #FIXME What the heck is the spec talking about?? self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.startContainer self.__dict__['commonAncestorContainer'] = self.startContainer self.__dict__['collapsed'] = 1 return df
def __getattr__(self, name): if name in self.readOnly: #Means we are detached raise InvalidStateErr() raise AttributeError, name
def deleteContents(self): """Delete the contents defined by this range""" #NOTE Use 4DOM ReleaseNode cause it is interface safe from pyxml.dom.ext import ReleaseNode if self.detached: raise InvalidStateErr() if self.startContainer == self.endContainer: if self.startOffset == self.endOffset: return if self.startContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data self.startContainer.deleteData( self.startOffset, 1 + self.endOffset - self.startOffset) else: #Delete a set number of children numDel = self.endOffset - self.startOffset + 1 for ctr in range(numDel): c = self.startContainer.removeChild( self.startContainer.childNodes[self.startOffset]) ReleaseNode(c) self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.endContainer self.__dict__['commonAncestorContainer'] = self.endContainer self.__dict__['collapsed'] = 1 elif self.startContainer == self.commonAncestorContainer: #Delete up the endContainer #From the start to the end if self.endContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data self.endContainer.deleteData(0, self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): c = self.endContainer.removeChild( self.endContainer.childNodes[0]) ReleaseNode(c) cur = self.endContainer while cur.parentNode != self.commonAncestorContainer: while cur.previousSibling: c = cur.parentNode.removeChild(cur.previousSibling) ReleaseNode(c) cur = cur.parentNode #Delete up to the ancestor of end endAncestorChild = cur while self.startContainer.firstChild != endAncestorChild: c = self.startContainer.removeChild( self.startContainer.firstChild) ReleaseNode(c) elif self.endContainer == self.commonAncestorContainer: if self.startContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data self.startContainer.deleteData( self.startOffset, 1 + len(self.startContainer.data) - self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.removeChild( self.startContainer.childNodes[self.startOffset]) ReleaseNode(c) cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: while cur.nextSibling: c = cur.parentNode.removeChild(cur.nextSibling) ReleaseNode(c) cur = cur.parentNode startAncestorChild = cur #Delete up to the ancestor of start startAncestorChild = cur startIndex = self.endContainer.childNodes.index(cur) numDel = self.endOffset - startIndex for ctr in range(numDel): c = self.endContainer.removeChild( startAncestorChild.nextSibling) ReleaseNode(c) else: #From the start to the end if self.startContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data self.startContainer.deleteData( self.startOffset, 1 + len(self.startContainer.data) - self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.removeChild( self.startContainer.childNodes[self.startOffset]) ReleaseNode(c) cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: while cur.nextSibling: c = cur.parentNode.removeChild(cur.nextSibling) ReleaseNode(c) cur = cur.parentNode startAncestorChild = cur #Delete up the endContainer #From the start to the end if self.endContainer.nodeType in [ Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE ]: #Adjust the character data self.endContainer.deleteData(0, self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): c = self.endContainer.removeChild( self.endContainer.childNodes[0]) ReleaseNode(c) cur = self.endContainer while cur.parentNode != self.commonAncestorContainer: while cur.previousSibling: c = cur.parentNode.removeChild(cur.previousSibling) ReleaseNode(c) cur = cur.parentNode endAncestorChild = cur cur = startAncestorChild #Delete everything between us while cur.nextSibling != endAncestorChild: c = cur.parentNode.removeChild(cur.nextSibling) ReleaseNode(c) #Adjust the containers #FIXME What the heck is the spec talking about?? self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.startContainer self.__dict__['commonAncestorContainer'] = self.startContainer self.__dict__['collapsed'] = 1 return None