📄 dom2_rangeimpl.cpp
字号:
* * The simplest is the start and endContainer is a text node. The start and end offset is the * number of characters into the text to remove/truncate. * * The next case is the start and endContainer is, well, a container, such a P tag or DIV tag. * In this case the start and end offset is the number of children into the container to start * from and end at. * * The other cases are different arrangements of the first two. * * psuedo code: * * if start container is not text: * count through the children to find where we start (m_startOffset children) * * loop from the start position: * if the current node is text, add the text to our variable 'text', truncating/removing if at the end/start. * * if the node has children, step to the first child. * if the node has no children but does have siblings, step to the next sibling * until we find a sibling, go to next the parent but: * make sure this sibling isn't past the end of where we are supposed to go. (position > endOffset and the parent is the endContainer) * */ if( m_startContainer == m_endContainer && m_startOffset >= m_endOffset) return text; if(n->firstChild()) { n = n->firstChild(); int current_offset = m_startOffset; while(current_offset-- && n) { n = n->nextSibling(); } } while(n) { if(n->nodeType() == DOM::Node::TEXT_NODE || n->nodeType() == DOM::Node::CDATA_SECTION_NODE) { DOMString str; str = static_cast<TextImpl *>(n)->string(); if( n == m_endContainer || n == m_startContainer) str = str.copy(); //copy if we are going to modify. if (n == m_endContainer) str.truncate(m_endOffset); if (n == m_startContainer) str.remove(0,m_startOffset); text += str; if (n == m_endContainer) break; } NodeImpl *next = n->firstChild(); if(!next) next = n->nextSibling(); while( !next && n->parentNode() ) { if (n == m_endContainer) return text; n = n->parentNode(); if (n == m_endContainer) return text; next = n->nextSibling(); } if(n->parentNode() == m_endContainer) { if(!next) break; unsigned long current_offset = 0; NodeImpl *it = n; while((it = it->previousSibling())) ++current_offset; if(current_offset >= m_endOffset) { break; } } n = next; } return text;}DOMString RangeImpl::toHTML( int &exceptioncode ){ bool hasHtmlTag = false; bool hasBodyTag = false; //FIXME: What is this section of code below exactly? Do I want it here? if (m_detached) { exceptioncode = DOMException::INVALID_STATE_ERR; return DOMString(); } DOMString text = ""; NodeImpl *n = m_startContainer; int num_tables=0; bool in_li = false; //whether we have an li in the text, without an ol/ul int depth_difference = 0; int lowest_depth_difference = 0; if( m_startContainer == m_endContainer && m_startOffset >= m_endOffset) return text; while(n) { /* First, we could have an tag <tagname key=value>otherstuff</tagname> */ if(n->nodeType() == DOM::Node::ELEMENT_NODE) { int elementId = static_cast<ElementImpl *>(n)->id(); if(elementId == ID_TABLE) num_tables++; if(elementId == ID_BODY) hasBodyTag = true; if(elementId == ID_HTML) hasHtmlTag = true; if(elementId == ID_LI) in_li=true; if(num_tables==0 && ( elementId == ID_TD || elementId == ID_TR || elementId == ID_TH || elementId == ID_TBODY || elementId == ID_TFOOT || elementId == ID_THEAD)) num_tables++; if(!( !n->hasChildNodes() && (elementId == ID_H1 || elementId == ID_H2 || elementId == ID_H3 || elementId == ID_H4 || elementId ==ID_H5))) { //Don't add <h1/> etc. Just skip these nodes just to make the output html a bit nicer. text += static_cast<ElementImpl *>(n)->openTagStartToString(true /*safely expand img urls*/); // adds "<tagname key=value" if(n->hasChildNodes()) { depth_difference++; text += ">"; } else { text += "/>"; } } } else if(n->nodeType() == DOM::Node::TEXT_NODE || n->nodeType() == DOM::Node::CDATA_SECTION_NODE) { if(n->nodeType() == DOM::Node::CDATA_SECTION_NODE) text += "<![CDATA[ "; long long startOffset = (n == m_startContainer)?(long long)m_startOffset:-1; long long endOffset = (n == m_endContainer)?(long long) m_endOffset:-1; text += static_cast<TextImpl *>(n)->toString(startOffset, endOffset); //Note this should always work since CDataImpl inherits TextImpl if(n->nodeType() == DOM::Node::CDATA_SECTION_NODE) text += " ]]>"; if(n == m_endContainer) { break; } } if(n->parentNode() == m_endContainer && !n->nextSibling()) { break; } //if (n == m_endContainer) break; NodeImpl *next = n->firstChild(); if(next) { if(n == m_startContainer) { //This is the start of our selection, so we have to move to where we have started selecting. //For example, if 'n' is "hello <img src='hello.png'> how are you? <img src='goodbye.png'>" //then this has four children. If our selection started on the image, then we need to start from there. unsigned long current_offset = 0; while(current_offset < m_startOffset && next) { next = next->nextSibling(); ++current_offset; } } } else { next = n->nextSibling(); if(n->parentNode() == m_endContainer) { unsigned long current_offset = 1; NodeImpl *it = n; while((it = it->previousSibling())) ++current_offset; if(current_offset >= m_endOffset) { break; } } } while( !next && n->parentNode() ) { n = n->parentNode(); if(n->nodeType() == DOM::Node::ELEMENT_NODE) { text += "</"; text += static_cast<ElementImpl *>(n)->tagName(); int elementId = static_cast<ElementImpl *>(n)->id(); if(elementId == ID_TABLE) num_tables--; depth_difference--; if(lowest_depth_difference > depth_difference) lowest_depth_difference=depth_difference; if(num_tables==0 && ( elementId == ID_TD || elementId == ID_TR || elementId == ID_TH || elementId == ID_TBODY || elementId == ID_TFOOT || elementId == ID_THEAD)) num_tables--; if(elementId == ID_OL || elementId == ID_UL) in_li=false; text += ">"; } next = n->nextSibling(); } n = next; } //We have the html in the selection. But now we need to properly add the opening and closing tags. //For example say we have: "Hello <b>Mr. John</b> How are you?" and we select "John" or even //"John</b> How" and copy. We want to return "<b>John</b>" and "<b>John</b> How" respectively //To do this, we need to go up the tree from the start, and prepend those tags. //Imagine our selection was this: // // hello</b></p><p>there // // The difference in depths between the start and end is -1, and the lowest depth // difference from the starting point is -2 // // So from the start of the selection, we want to go down to the lowest_depth_difference // and prepend those tags. (<p><b>) // // From the end of the selection, we want to also go down to the lowest_depth_difference. // We know the depth of the end of the selection - i.e. depth_difference. // // n = m_startContainer; int startdepth = 0; //by definition - we are counting from zero. while((n = n->parentNode()) && startdepth>lowest_depth_difference) { if(n->nodeType() == DOM::Node::ELEMENT_NODE) { //This should always be true.. right? switch (static_cast<ElementImpl *>(n)->id()) { case ID_TABLE: num_tables--; break; case ID_BODY: hasBodyTag = true; break; case ID_HTML: hasHtmlTag = true; break; case ID_LI: in_li = true; break; } text = static_cast<ElementImpl *>(n)->openTagStartToString(true /*expand img urls*/)+">" +text; // prepends "<tagname key=value>" } startdepth--; } n = m_endContainer; while( depth_difference>lowest_depth_difference && (n = n->parentNode())) { if(n->nodeType() == DOM::Node::ELEMENT_NODE) { //This should always be true.. right? switch (static_cast<ElementImpl *>(n)->id()) { case ID_TABLE: num_tables++; break; case ID_OL: case ID_UL: in_li=false; break; } text += "</"; text += static_cast<ElementImpl *>(n)->tagName(); text += ">"; } depth_difference--; } // Now our text string is the same depth on both sides, with nothing lower (in other words all the // tags in it match up.) This also means that the end value for n in the first loop is a sibling of the // end value for n in the second loop. // // We now need to go down the tree, and for certain tags, add them in on both ends of the text. // For example, if have: "<b>hello</b>" and we select "ll", then we want to go down the tree and // add "<b>" and "</b>" to it, to produce "<b>ll</b>". // // I just guessed at which tags you'd want to keep (bold, italic etc) and which you wouldn't (tables etc). // It's just wild guessing. feel free to change. // // Note we can carry on with the value of n if(n) { while((n = n->parentNode())) { if(n->nodeType() == DOM::Node::ELEMENT_NODE) { //This should always be true.. right? int elementId = static_cast<ElementImpl *>(n)->id(); switch (elementId) { case ID_TABLE: case ID_TD: case ID_TR: case ID_TH: case ID_TBODY: case ID_TFOOT: case ID_THEAD: if(num_tables>0) { if(elementId == ID_TABLE) num_tables--; text = static_cast<ElementImpl *>(n)->openTagStartToString(true /*expand img urls*/)+">" +text; text += "</"; text += static_cast<ElementImpl *>(n)->tagName(); text += ">"; } break; case ID_LI: if(!in_li) break; text = static_cast<ElementImpl *>(n)->openTagStartToString(true /*expand img urls*/)+">" +text; text += "</"; text += static_cast<ElementImpl *>(n)->tagName(); text += ">"; break; case ID_UL: case ID_OL: if(!in_li) break; in_li = false; case ID_B: case ID_I: case ID_U: case ID_FONT: case ID_S: case ID_STRONG: case ID_STRIKE: case ID_DEL: case ID_A: case ID_H1: case ID_H2: case ID_H3: case ID_H4: case ID_H5: //should small, etc be here? so hard to decide. this is such a hack :( //There's probably tons of others you'd want here. text = static_cast<ElementImpl *>(n)->openTagStartToString(true /*expand img urls*/)+">" +text; text += "</"; text += static_cast<ElementImpl *>(n)->tagName(); text += ">"; break; } } } } if(!hasBodyTag) text = DOMString("<body>") + text + "</body>"; else if(!hasHtmlTag) { text = DOMString("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" "<head>\n" "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" "<meta name=\"Generator\" content=\"KHTML, the KDE Web Page Viewer\" />\n" "</head>\n") + text + "</html>"; } text = DOMString("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n") + text; return text;}DocumentFragment RangeImpl::createContextualFragment ( const DOMString &html, int &exceptioncode ){ if (m_detached) { exceptioncode = DOMException::INVALID_STATE_ERR; return DocumentFragment(); } if (! m_startContainer->isHTMLElement()) { exceptioncode = DOMException::NOT_SUPPORTED_ERR; return DocumentFragment(); } HTMLElementImpl *e = static_cast<HTMLElementImpl *>(m_startContainer); DocumentFragment fragment = e->createContextualFragment(html); if (fragment.isNull()) { exceptioncode = DOMException::NOT_SUPPORTED_ERR; return DocumentFragment(); } return fragment;}void RangeImpl::detach( int &exceptioncode ){ if (m_detached) { exceptioncode = DOMException::INVALID_STATE_ERR; return; } if (m_startContainer) m_startContainer->deref(); m_startContainer = 0; if (m_endContainer) m_endContainer->deref(); m_endContainer = 0; m_detached = true;}bool RangeImpl::isDetached() const{ return m_detached;}void RangeImpl::checkNodeWOffset( NodeImpl *n, int offset, int &exceptioncode) const{ if( offset < 0 ) { exceptioncode = DOMException::INDEX_SIZE_ERR; } switch (n->nodeType()) { case Node::ENTITY_NODE: case Node::NOTATION_NODE: case Node::DOCUMENT_TYPE_NODE: exceptioncode = RangeException::INVALID_NODE_TYPE_ERR + RangeException::_EXCEPTION_OFFSET; break; case Node::TEXT_NODE: case Node::COMMENT_NODE: case Node::CDATA_SECTION_NODE: if ( (unsigned long)offset > static_cast<CharacterDataImpl*>(n)->length() ) exceptioncode = DOMException::INDEX_SIZE_ERR; break; case Node::PROCESSING_INSTRUCTION_NODE: // ### are we supposed to check with just data or the whole contents? if ( (unsigned long)offset > static_cast<ProcessingInstructionImpl*>(n)->data().length() ) exceptioncode = DOMException::INDEX_SIZE_ERR; break; default: if ( (unsigned long)offset > n->childNodeCount() ) exceptioncode = DOMException::INDEX_SIZE_ERR; break; }}void RangeImpl::checkNodeBA( NodeImpl *n, int &exceptioncode ) const{ // INVALID_NODE_TYPE_ERR: Raised if the root container of refNode is not an // Attr, Document or DocumentFragment node or if refNode is a Document, // DocumentFragment, Attr, Entity, or Notation node. NodeImpl *root = n; while (root->parentNode())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -