📄 range.cpp
字号:
return 0; // A is equal to B if (offsetA < offsetB) return -1; // A is before B else return 1; // A is after B } // case 2: node C (container B or an ancestor) is a child node of A Node* c = containerB; while (c && c->parentNode() != containerA) c = c->parentNode(); if (c) { int offsetC = 0; Node* n = containerA->firstChild(); while (n != c && offsetC < offsetA) { offsetC++; n = n->nextSibling(); } if (offsetA <= offsetC) return -1; // A is before B else return 1; // A is after B } // case 3: node C (container A or an ancestor) is a child node of B c = containerA; while (c && c->parentNode() != containerB) c = c->parentNode(); if (c) { int offsetC = 0; Node* n = containerB->firstChild(); while (n != c && offsetC < offsetB) { offsetC++; n = n->nextSibling(); } if (offsetC < offsetB) return -1; // A is before B else return 1; // A is after B } // case 4: containers A & B are siblings, or children of siblings // ### we need to do a traversal here instead Node* commonAncestor = commonAncestorContainer(containerA, containerB); if (!commonAncestor) return 0; Node* childA = containerA; while (childA && childA->parentNode() != commonAncestor) childA = childA->parentNode(); if (!childA) childA = commonAncestor; Node* childB = containerB; while (childB && childB->parentNode() != commonAncestor) childB = childB->parentNode(); if (!childB) childB = commonAncestor; if (childA == childB) return 0; // A is equal to B Node* n = commonAncestor->firstChild(); while (n) { if (n == childA) return -1; // A is before B if (n == childB) return 1; // A is after B n = n->nextSibling(); } // Should never reach this point. ASSERT_NOT_REACHED(); return 0;}short Range::compareBoundaryPoints(const Position& a, const Position& b){ return compareBoundaryPoints(a.container.get(), a.posOffset, b.container.get(), b.posOffset);}bool Range::boundaryPointsValid() const{ return m_start.container() && compareBoundaryPoints(m_start.container(), m_start.offset(), m_end.container(), m_end.offset()) <= 0;}void Range::deleteContents(ExceptionCode& ec){ checkDeleteExtract(ec); if (ec) return; processContents(DELETE_CONTENTS, ec);}bool Range::intersectsNode(Node* refNode, ExceptionCode& ec){ // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode // Returns a bool if the node intersects the range. if (!refNode) { ec = NOT_FOUND_ERR; return false; } if (!m_start.container() && refNode->attached() || m_start.container() && !refNode->attached() || refNode->document() != m_ownerDocument) { // Firefox doesn't throw an exception for these cases; it returns false. return false; } Node* parentNode = refNode->parentNode(); int nodeIndex = refNode->nodeIndex(); if (!parentNode) { // if the node is the top document we should return NODE_BEFORE_AND_AFTER // but we throw to match firefox behavior ec = NOT_FOUND_ERR; return false; } if (comparePoint(parentNode, nodeIndex, ec) < 0 && // starts before start comparePoint(parentNode, nodeIndex + 1, ec) < 0) { // ends before start return false; } else if (comparePoint(parentNode, nodeIndex, ec) > 0 && // starts after end comparePoint(parentNode, nodeIndex + 1, ec) > 0) { // ends after end return false; } return true; // all other cases}PassRefPtr<DocumentFragment> Range::processContents(ActionType action, ExceptionCode& ec){ // FIXME: To work properly with mutation events, we will have to take into account // situations where the tree is being transformed while we work on it - ugh! RefPtr<DocumentFragment> fragment; if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) fragment = new DocumentFragment(m_ownerDocument.get()); ec = 0; if (collapsed(ec)) return fragment.release(); if (ec) return 0; Node* commonRoot = commonAncestorContainer(ec); if (ec) return 0; ASSERT(commonRoot); // what is the highest node that partially selects the start of the range? Node* partialStart = 0; if (m_start.container() != commonRoot) { partialStart = m_start.container(); while (partialStart->parentNode() != commonRoot) partialStart = partialStart->parentNode(); } // what is the highest node that partially selects the end of the range? Node* partialEnd = 0; if (m_end.container() != commonRoot) { partialEnd = m_end.container(); while (partialEnd->parentNode() != commonRoot) partialEnd = partialEnd->parentNode(); } // Simple case: the start and end containers are the same. We just grab // everything >= start offset and < end offset if (m_start.container() == m_end.container()) { Node::NodeType startNodeType = m_start.container()->nodeType(); if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true)); c->deleteData(m_end.offset(), c->length() - m_end.offset(), ec); c->deleteData(0, m_start.offset(), ec); fragment->appendChild(c.release(), ec); } if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) static_cast<CharacterData*>(m_start.container())->deleteData(m_start.offset(), m_end.offset() - m_start.offset(), ec); } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true)); c->setData(c->data().substring(m_start.offset(), m_end.offset() - m_start.offset()), ec); fragment->appendChild(c.release(), ec); } if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container()); String data(pi->data()); data.remove(m_start.offset(), m_end.offset() - m_start.offset()); pi->setData(data, ec); } } else { Node* n = m_start.container()->firstChild(); int i; for (i = 0; n && i < m_start.offset(); i++) // skip until start offset n = n->nextSibling(); int endOffset = m_end.offset(); while (n && i < endOffset) { // delete until end offset Node* next = n->nextSibling(); if (action == EXTRACT_CONTENTS) fragment->appendChild(n, ec); // will remove n from its parent else if (action == CLONE_CONTENTS) fragment->appendChild(n->cloneNode(true), ec); else m_start.container()->removeChild(n, ec); n = next; i++; } } return fragment.release(); } // Complex case: Start and end containers are different. // There are three possiblities here: // 1. Start container == commonRoot (End container must be a descendant) // 2. End container == commonRoot (Start container must be a descendant) // 3. Neither is commonRoot, they are both descendants // // In case 3, we grab everything after the start (up until a direct child // of commonRoot) into leftContents, and everything before the end (up until // a direct child of commonRoot) into rightContents. Then we process all // commonRoot children between leftContents and rightContents // // In case 1 or 2, we skip either processing of leftContents or rightContents, // in which case the last lot of nodes either goes from the first or last // child of commonRoot. // // These are deleted, cloned, or extracted (i.e. both) depending on action. RefPtr<Node> leftContents; if (m_start.container() != commonRoot) { // process the left-hand side of the range, up until the last ancestor of // start container before commonRoot Node::NodeType startNodeType = m_start.container()->nodeType(); if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true)); c->deleteData(0, m_start.offset(), ec); leftContents = c.release(); } if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) static_cast<CharacterData*>(m_start.container())->deleteData( m_start.offset(), static_cast<CharacterData*>(m_start.container())->length() - m_start.offset(), ec); } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true)); c->setData(c->data().substring(m_start.offset()), ec); leftContents = c.release(); } if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container()); String data(pi->data()); pi->setData(data.left(m_start.offset()), ec); } } else { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) leftContents = m_start.container()->cloneNode(false); Node* n = m_start.container()->firstChild(); for (int i = 0; n && i < m_start.offset(); i++) // skip until start offset n = n->nextSibling(); while (n) { // process until end Node* next = n->nextSibling(); if (action == EXTRACT_CONTENTS) leftContents->appendChild(n, ec); // will remove n from start container else if (action == CLONE_CONTENTS) leftContents->appendChild(n->cloneNode(true), ec); else m_start.container()->removeChild(n, ec); n = next; } } Node* leftParent = m_start.container()->parentNode(); Node* n = m_start.container()->nextSibling(); for (; leftParent != commonRoot; leftParent = leftParent->parentNode()) { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { RefPtr<Node> leftContentsParent = leftParent->cloneNode(false); leftContentsParent->appendChild(leftContents,ec); leftContents = leftContentsParent; } Node* next; for (; n; n = next) { next = n->nextSibling(); if (action == EXTRACT_CONTENTS) leftContents->appendChild(n,ec); // will remove n from leftParent else if (action == CLONE_CONTENTS) leftContents->appendChild(n->cloneNode(true),ec); else leftParent->removeChild(n,ec); } n = leftParent->nextSibling(); } } RefPtr<Node> rightContents; if (m_end.container() != commonRoot) { // delete the right-hand side of the range, up until the last ancestor of // end container before commonRoot Node::NodeType endNodeType = m_end.container()->nodeType(); if (endNodeType == Node::TEXT_NODE || endNodeType == Node::CDATA_SECTION_NODE || endNodeType == Node::COMMENT_NODE) { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_end.container()->cloneNode(true)); c->deleteData(m_end.offset(), static_cast<CharacterData*>(m_end.container())->length() - m_end.offset(), ec); rightContents = c; } if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) static_cast<CharacterData*>(m_end.container())->deleteData(0, m_end.offset(), ec); } else if (endNodeType == Node::PROCESSING_INSTRUCTION_NODE) { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_end.container()->cloneNode(true)); c->setData(c->data().left(m_end.offset()), ec); rightContents = c.release(); } if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_end.container()); pi->setData(pi->data().substring(m_end.offset()), ec); } } else { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) rightContents = m_end.container()->cloneNode(false); Node* n = m_end.container()->firstChild(); if (n && m_end.offset()) { for (int i = 0; i + 1 < m_end.offset(); i++) { // skip to end.offset() Node* next = n->nextSibling(); if (!next) break; n = next; } Node* prev; for (; n; n = prev) { prev = n->previousSibling(); if (action == EXTRACT_CONTENTS) rightContents->insertBefore(n, rightContents->firstChild(), ec); // will remove n from its parent else if (action == CLONE_CONTENTS) rightContents->insertBefore(n->cloneNode(true), rightContents->firstChild(), ec); else m_end.container()->removeChild(n, ec); } } } Node* rightParent = m_end.container()->parentNode(); Node* n = m_end.container()->previousSibling(); for (; rightParent != commonRoot; rightParent = rightParent->parentNode()) { if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { RefPtr<Node> rightContentsParent = rightParent->cloneNode(false); rightContentsParent->appendChild(rightContents,ec); rightContents = rightContentsParent; } Node* prev; for (; n; n = prev) { prev = n->previousSibling(); if (action == EXTRACT_CONTENTS) rightContents->insertBefore(n, rightContents->firstChild(), ec); // will remove n from its parent else if (action == CLONE_CONTENTS) rightContents->insertBefore(n->cloneNode(true), rightContents->firstChild(), ec); else rightParent->removeChild(n, ec); } n = rightParent->previousSibling(); } } // delete all children of commonRoot between the start and end container Node* processStart; // child of commonRoot if (m_start.container() == commonRoot) { processStart = m_start.container()->firstChild(); for (int i = 0; i < m_start.offset(); i++) processStart = processStart->nextSibling(); } else { processStart = m_start.container(); while (processStart->parentNode() != commonRoot) processStart = processStart->parentNode(); processStart = processStart->nextSibling(); } Node* processEnd; // child of commonRoot if (m_end.container() == commonRoot) { processEnd = m_end.container()->firstChild(); for (int i = 0; i < m_end.offset(); i++) processEnd = processEnd->nextSibling(); } else { processEnd = m_end.container(); while (processEnd->parentNode() != commonRoot) processEnd = processEnd->parentNode(); } // Now add leftContents, stuff in between, and rightContents to the fragment // (or just delete the stuff in between) if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && leftContents) fragment->appendChild(leftContents, ec); Node* next; Node* n; if (processStart) { for (n = processStart; n && n != processEnd; n = next) { next = n->nextSibling(); if (action == EXTRACT_CONTENTS) fragment->appendChild(n, ec); // will remove from commonRoot else if (action == CLONE_CONTENTS) fragment->appendChild(n->cloneNode(true), ec); else commonRoot->removeChild(n, ec); } } if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && rightContents) fragment->appendChild(rightContents, ec); return fragment.release();}PassRefPtr<DocumentFragment> Range::extractContents(ExceptionCode& ec){ checkDeleteExtract(ec); if (ec) return 0; return processContents(EXTRACT_CONTENTS, ec);}PassRefPtr<DocumentFragment> Range::cloneContents(ExceptionCode& ec){ if (!m_start.container()) { ec = INVALID_STATE_ERR; return 0; } return processContents(CLONE_CONTENTS, ec);}void Range::insertNode(PassRefPtr<Node> prpNewNode, ExceptionCode& ec){ RefPtr<Node> newNode = prpNewNode; ec = 0; if (!m_start.container()) { ec = INVALID_STATE_ERR; return; } if (!newNode) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -