2 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
21 #include "qwebelement.h"
23 #include "qwebelement_p.h"
24 #include "CSSComputedStyleDeclaration.h"
25 #include "CSSMutableStyleDeclaration.h"
26 #include "CSSParser.h"
28 #include "CSSRuleList.h"
29 #include "CSSStyleRule.h"
30 #include "CSSStyleSelector.h"
32 #include "DocumentFragment.h"
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "HTMLElement.h"
37 #include "Completion.h"
38 #include "JSGlobalObject.h"
39 #include "JSHTMLElement.h"
41 #include "PropertyNameArray.h"
42 #include <parser/SourceCode.h>
43 #include "qt_runtime.h"
45 #include "V8DOMWindow.h"
46 #include "V8Binding.h"
47 #include "NotImplemented.h"
50 #include "RenderImage.h"
51 #include "ScriptState.h"
52 #include "StaticNodeList.h"
53 #include "qwebframe.h"
54 #include "qwebframe_p.h"
56 #include "runtime_root.h"
57 #include <JSDocument.h>
59 #include <wtf/Vector.h>
60 #include <wtf/text/CString.h>
64 using namespace WebCore;
66 class QWebElementPrivate {
73 \brief The QWebElement class provides convenient access to DOM elements in
77 A QWebElement object allows easy access to the document model, represented
78 by a tree-like structure of DOM elements. The root of the tree is called
79 the document element and can be accessed using
80 QWebFrame::documentElement().
82 Specific elements can be accessed using findAll() and findFirst(). These
83 elements are identified using CSS selectors. The code snippet below
84 demonstrates the use of findAll().
86 \snippet webkitsnippets/webelement/main.cpp FindAll
88 The first list contains all \c span elements in the document. The second
89 list contains \c span elements that are children of \c p, classified with
92 Using findFirst() is more efficient than calling findAll(), and extracting
93 the first element only in the list returned.
95 Alternatively you can traverse the document manually using firstChild() and
98 \snippet webkitsnippets/webelement/main.cpp Traversing with QWebElement
100 Individual elements can be inspected or changed using methods such as attribute()
101 or setAttribute(). For examle, to capture the user's input in a text field for later
102 use (auto-completion), a browser could do something like this:
104 \snippet webkitsnippets/webelement/main.cpp autocomplete1
106 When the same page is later revisited, the browser can fill in the text field automatically
107 by modifying the value attribute of the input element:
109 \snippet webkitsnippets/webelement/main.cpp autocomplete2
111 Another use case is to emulate a click event on an element. The following
112 code snippet demonstrates how to call the JavaScript DOM method click() of
115 \snippet webkitsnippets/webelement/main.cpp Calling a DOM element method
117 The underlying content of QWebElement is explicitly shared. Creating a copy
118 of a QWebElement does not create a copy of the content. Instead, both
119 instances point to the same element.
121 The contents of child elements can be converted to plain text with
122 toPlainText(); to XHTML using toInnerXml(). To include the element's tag in
123 the output, use toOuterXml().
125 It is possible to replace the contents of child elements using
126 setPlainText() and setInnerXml(). To replace the element itself and its
127 contents, use setOuterXml().
131 The \l{DOM Traversal Example} shows one way to traverse documents in a running
134 The \l{Simple Selector Example} can be used to experiment with the searching
135 features of this class and provides sample code you can start working with.
139 Constructs a null web element.
141 QWebElement::QWebElement()
150 QWebElement::QWebElement(WebCore::Element* domElement)
152 , m_element(domElement)
161 QWebElement::QWebElement(WebCore::Node* node)
165 if (node && node->isHTMLElement()) {
166 m_element = static_cast<HTMLElement*>(node);
172 Constructs a copy of \a other.
174 QWebElement::QWebElement(const QWebElement &other)
176 , m_element(other.m_element)
183 Assigns \a other to this element and returns a reference to this element.
185 QWebElement &QWebElement::operator=(const QWebElement &other)
187 // ### handle "d" assignment
188 if (this != &other) {
189 Element *otherElement = other.m_element;
194 m_element = otherElement;
200 Destroys the element. However, the underlying DOM element is not destroyed.
202 QWebElement::~QWebElement()
209 bool QWebElement::operator==(const QWebElement& o) const
211 return m_element == o.m_element;
214 bool QWebElement::operator!=(const QWebElement& o) const
216 return m_element != o.m_element;
220 Returns true if the element is a null element; otherwise returns false.
222 bool QWebElement::isNull() const
228 Returns a new list of child elements matching the given CSS selector
229 \a selectorQuery. If there are no matching elements, an empty list is
232 \l{Standard CSS2 selector} syntax is used for the query.
234 \note This search is performed recursively.
238 QWebElementCollection QWebElement::findAll(const QString &selectorQuery) const
240 return QWebElementCollection(*this, selectorQuery);
244 Returns the first child element that matches the given CSS selector
247 \l{Standard CSS2 selector} syntax is used for the query.
249 \note This search is performed recursively.
253 QWebElement QWebElement::findFirst(const QString &selectorQuery) const
256 return QWebElement();
257 ExceptionCode exception = 0; // ###
258 return QWebElement(m_element->querySelector(selectorQuery, exception).get());
262 Replaces the existing content of this element with \a text.
264 This is equivalent to setting the HTML innerText property.
268 void QWebElement::setPlainText(const QString &text)
270 if (!m_element || !m_element->isHTMLElement())
272 ExceptionCode exception = 0;
273 static_cast<HTMLElement*>(m_element)->setInnerText(text, exception);
277 Returns the text between the start and the end tag of this
280 This is equivalent to reading the HTML innerText property.
284 QString QWebElement::toPlainText() const
286 if (!m_element || !m_element->isHTMLElement())
288 return static_cast<HTMLElement*>(m_element)->innerText();
292 Replaces the contents of this element as well as its own tag with
293 \a markup. The string may contain HTML or XML tags, which is parsed and
294 formatted before insertion into the document.
296 \note This is currently only implemented for (X)HTML elements.
298 \sa toOuterXml(), toInnerXml(), setInnerXml()
300 void QWebElement::setOuterXml(const QString &markup)
302 if (!m_element || !m_element->isHTMLElement())
305 ExceptionCode exception = 0;
307 static_cast<HTMLElement*>(m_element)->setOuterHTML(markup, exception);
311 Returns this element converted to XML, including the start and the end
312 tags as well as its attributes.
314 \note This is currently implemented for (X)HTML elements only.
316 \note The format of the markup returned will obey the namespace of the
317 document containing the element. This means the return value will obey XML
318 formatting rules, such as self-closing tags, only if the document is
321 \sa setOuterXml(), setInnerXml(), toInnerXml()
323 QString QWebElement::toOuterXml() const
325 if (!m_element || !m_element->isHTMLElement())
328 return static_cast<HTMLElement*>(m_element)->outerHTML();
332 Replaces the contents of this element with \a markup. The string may
333 contain HTML or XML tags, which is parsed and formatted before insertion
336 \note This is currently implemented for (X)HTML elements only.
338 \sa toInnerXml(), toOuterXml(), setOuterXml()
340 void QWebElement::setInnerXml(const QString &markup)
342 if (!m_element || !m_element->isHTMLElement())
345 ExceptionCode exception = 0;
347 static_cast<HTMLElement*>(m_element)->setInnerHTML(markup, exception);
351 Returns the XML content between the element's start and end tags.
353 \note This is currently implemented for (X)HTML elements only.
355 \note The format of the markup returned will obey the namespace of the
356 document containing the element. This means the return value will obey XML
357 formatting rules, such as self-closing tags, only if the document is
360 \sa setInnerXml(), setOuterXml(), toOuterXml()
362 QString QWebElement::toInnerXml() const
364 if (!m_element || !m_element->isHTMLElement())
367 return static_cast<HTMLElement*>(m_element)->innerHTML();
371 Adds an attribute with the given \a name and \a value. If an attribute with
372 the same name exists, its value is replaced by \a value.
374 \sa attribute(), attributeNS(), setAttributeNS()
376 void QWebElement::setAttribute(const QString &name, const QString &value)
380 ExceptionCode exception = 0;
381 m_element->setAttribute(name, value, exception);
385 Adds an attribute with the given \a name in \a namespaceUri with \a value.
386 If an attribute with the same name exists, its value is replaced by
389 \sa attributeNS(), attribute(), setAttribute()
391 void QWebElement::setAttributeNS(const QString &namespaceUri, const QString &name, const QString &value)
395 WebCore::ExceptionCode exception = 0;
396 m_element->setAttributeNS(namespaceUri, name, value, exception);
400 Returns the attribute with the given \a name. If the attribute does not
401 exist, \a defaultValue is returned.
403 \sa setAttribute(), setAttributeNS(), attributeNS()
405 QString QWebElement::attribute(const QString &name, const QString &defaultValue) const
409 if (m_element->hasAttribute(name))
410 return m_element->getAttribute(name);
416 Returns the attribute with the given \a name in \a namespaceUri. If the
417 attribute does not exist, \a defaultValue is returned.
419 \sa setAttributeNS(), setAttribute(), attribute()
421 QString QWebElement::attributeNS(const QString &namespaceUri, const QString &name, const QString &defaultValue) const
425 if (m_element->hasAttributeNS(namespaceUri, name))
426 return m_element->getAttributeNS(namespaceUri, name);
432 Returns true if this element has an attribute with the given \a name;
433 otherwise returns false.
435 \sa attribute(), setAttribute()
437 bool QWebElement::hasAttribute(const QString &name) const
441 return m_element->hasAttribute(name);
445 Returns true if this element has an attribute with the given \a name, in
446 \a namespaceUri; otherwise returns false.
448 \sa attributeNS(), setAttributeNS()
450 bool QWebElement::hasAttributeNS(const QString &namespaceUri, const QString &name) const
454 return m_element->hasAttributeNS(namespaceUri, name);
458 Removes the attribute with the given \a name from this element.
460 \sa attribute(), setAttribute(), hasAttribute()
462 void QWebElement::removeAttribute(const QString &name)
466 ExceptionCode exception = 0;
467 m_element->removeAttribute(name, exception);
471 Removes the attribute with the given \a name, in \a namespaceUri, from this
474 \sa attributeNS(), setAttributeNS(), hasAttributeNS()
476 void QWebElement::removeAttributeNS(const QString &namespaceUri, const QString &name)
480 WebCore::ExceptionCode exception = 0;
481 m_element->removeAttributeNS(namespaceUri, name, exception);
485 Returns true if the element has any attributes defined; otherwise returns
488 \sa attribute(), setAttribute()
490 bool QWebElement::hasAttributes() const
494 return m_element->hasAttributes();
498 Return the list of attributes for the namespace given as \a namespaceUri.
500 \sa attribute(), setAttribute()
502 QStringList QWebElement::attributeNames(const QString& namespaceUri) const
505 return QStringList();
507 QStringList attributeNameList;
508 const NamedNodeMap* const attrs = m_element->attributes(/* read only = */ true);
510 const String namespaceUriString(namespaceUri); // convert QString -> String once
511 const unsigned attrsCount = attrs->length();
512 for (unsigned i = 0; i < attrsCount; ++i) {
513 const Attribute* const attribute = attrs->attributeItem(i);
514 if (namespaceUriString == attribute->namespaceURI())
515 attributeNameList.append(attribute->localName());
518 return attributeNameList;
522 Returns true if the element has keyboard input focus; otherwise, returns false
526 bool QWebElement::hasFocus() const
530 if (m_element->document())
531 return m_element == m_element->document()->focusedNode();
536 Gives keyboard input focus to this element
540 void QWebElement::setFocus()
544 if (m_element->document() && m_element->isFocusable())
545 m_element->document()->setFocusedNode(m_element);
549 Returns the geometry of this element, relative to its containing frame.
553 QRect QWebElement::geometry() const
557 return m_element->getRect();
561 Returns the tag name of this element.
565 QString QWebElement::tagName() const
569 return m_element->tagName();
573 Returns the namespace prefix of the element. If the element has no\
574 namespace prefix, empty string is returned.
576 QString QWebElement::prefix() const
580 return m_element->prefix();
584 Returns the local name of the element. If the element does not use
585 namespaces, an empty string is returned.
587 QString QWebElement::localName() const
591 return m_element->localName();
595 Returns the namespace URI of this element. If the element has no namespace
596 URI, an empty string is returned.
598 QString QWebElement::namespaceUri() const
602 return m_element->namespaceURI();
606 Returns the parent element of this elemen. If this element is the root
607 document element, a null element is returned.
609 QWebElement QWebElement::parent() const
612 return QWebElement(m_element->parentElement());
613 return QWebElement();
617 Returns the element's first child.
619 \sa lastChild(), previousSibling(), nextSibling()
621 QWebElement QWebElement::firstChild() const
624 return QWebElement();
625 for (Node* child = m_element->firstChild(); child; child = child->nextSibling()) {
626 if (!child->isElementNode())
628 Element* e = static_cast<Element*>(child);
629 return QWebElement(e);
631 return QWebElement();
635 Returns the element's last child.
637 \sa firstChild(), previousSibling(), nextSibling()
639 QWebElement QWebElement::lastChild() const
642 return QWebElement();
643 for (Node* child = m_element->lastChild(); child; child = child->previousSibling()) {
644 if (!child->isElementNode())
646 Element* e = static_cast<Element*>(child);
647 return QWebElement(e);
649 return QWebElement();
653 Returns the element's next sibling.
655 \sa firstChild(), previousSibling(), lastChild()
657 QWebElement QWebElement::nextSibling() const
660 return QWebElement();
661 for (Node* sib = m_element->nextSibling(); sib; sib = sib->nextSibling()) {
662 if (!sib->isElementNode())
664 Element* e = static_cast<Element*>(sib);
665 return QWebElement(e);
667 return QWebElement();
671 Returns the element's previous sibling.
673 \sa firstChild(), nextSibling(), lastChild()
675 QWebElement QWebElement::previousSibling() const
678 return QWebElement();
679 for (Node* sib = m_element->previousSibling(); sib; sib = sib->previousSibling()) {
680 if (!sib->isElementNode())
682 Element* e = static_cast<Element*>(sib);
683 return QWebElement(e);
685 return QWebElement();
689 Returns the document which this element belongs to.
691 QWebElement QWebElement::document() const
694 return QWebElement();
695 Document* document = m_element->document();
697 return QWebElement();
698 return QWebElement(document->documentElement());
702 Returns the web frame which this element is a part of. If the element is a
703 null element, null is returned.
705 QWebFrame *QWebElement::webFrame() const
710 Document* document = m_element->document();
714 Frame* frame = document->frame();
717 return QWebFramePrivate::kit(frame);
721 static bool setupScriptContext(WebCore::Element* element, JSC::JSValue& thisValue, ScriptState*& state, ScriptController*& scriptController)
726 Document* document = element->document();
730 Frame* frame = document->frame();
734 scriptController = frame->script();
735 if (!scriptController)
738 state = scriptController->globalObject(mainThreadNormalWorld())->globalExec();
742 thisValue = toJS(state, deprecatedGlobalObjectForPrototype(state), element);
749 static bool setupScriptContext(WebCore::Element* element, v8::Handle<v8::Value>& thisValue, ScriptState*& state, ScriptController*& scriptController)
754 Document* document = element->document();
758 Frame* frame = document->frame();
762 state = mainWorldScriptState(frame);
763 // Get V8 wrapper for DOM element
764 thisValue = toV8(frame->domWindow());
771 Executes \a scriptSource with this element as \c this object.
773 QVariant QWebElement::evaluateJavaScript(const QString& scriptSource)
775 if (scriptSource.isEmpty())
778 ScriptState* state = 0;
780 JSC::JSValue thisValue;
782 v8::Handle<v8::Value> thisValue;
784 ScriptController* scriptController = 0;
786 if (!setupScriptContext(m_element, thisValue, state, scriptController))
789 JSC::ScopeChainNode* scopeChain = state->dynamicGlobalObject()->globalScopeChain();
790 JSC::UString script(reinterpret_cast_ptr<const UChar*>(scriptSource.data()), scriptSource.length());
792 JSC::JSValue evaluationException;
793 JSC::JSValue evaluationResult = JSC::evaluate(state, scopeChain, JSC::makeSource(script), thisValue, &evaluationException);
794 if (evaluationException)
798 return JSC::Bindings::convertValueToQVariant(state, evaluationResult, QMetaType::Void, &distance);
806 \enum QWebElement::StyleResolveStrategy
808 This enum describes how QWebElement's styleProperty resolves the given
811 \value InlineStyle Return the property value as it is defined in
812 the element, without respecting style inheritance and other CSS
814 \value CascadedStyle The property's value is determined using the
815 inheritance and importance rules defined in the document's
817 \value ComputedStyle The property's value is the absolute value
818 of the style property resolved from the environment.
822 Returns the value of the style with the given \a name using the specified
823 \a strategy. If a style with \a name does not exist, an empty string is
826 In CSS, the cascading part depends on which CSS rule has priority and is
827 thus applied. Generally, the last defined rule has priority. Thus, an
828 inline style rule has priority over an embedded block style rule, which
829 in return has priority over an external style rule.
831 If the "!important" declaration is set on one of those, the declaration
832 receives highest priority, unless other declarations also use the
833 "!important" declaration. Then, the last "!important" declaration takes
836 \sa setStyleProperty()
839 QString QWebElement::styleProperty(const QString &name, StyleResolveStrategy strategy) const
841 if (!m_element || !m_element->isStyledElement())
844 int propID = cssPropertyID(name);
849 CSSStyleDeclaration* style = static_cast<StyledElement*>(m_element)->style();
851 if (strategy == InlineStyle)
852 return style->getPropertyValue(propID);
854 if (strategy == CascadedStyle) {
855 if (style->getPropertyPriority(propID))
856 return style->getPropertyValue(propID);
858 // We are going to resolve the style property by walking through the
859 // list of non-inline matched CSS rules for the element, looking for
860 // the highest priority definition.
862 // Get an array of matched CSS rules for the given element sorted
863 // by importance and inheritance order. This include external CSS
864 // declarations, as well as embedded and inline style declarations.
866 Document* doc = m_element->document();
867 if (RefPtr<CSSRuleList> rules = doc->styleSelector()->styleRulesForElement(m_element, /*authorOnly*/ true)) {
868 for (int i = rules->length(); i > 0; --i) {
869 CSSStyleRule* rule = static_cast<CSSStyleRule*>(rules->item(i - 1));
871 if (rule->style()->getPropertyPriority(propID))
872 return rule->style()->getPropertyValue(propID);
874 if (style->getPropertyValue(propID).isEmpty())
875 style = rule->style();
879 return style->getPropertyValue(propID);
882 if (strategy == ComputedStyle) {
883 if (!m_element || !m_element->isStyledElement())
886 int propID = cssPropertyID(name);
888 RefPtr<CSSComputedStyleDeclaration> style = computedStyle(m_element, true);
889 if (!propID || !style)
892 return style->getPropertyValue(propID);
899 Sets the value of the inline style with the given \a name to \a value.
901 Setting a value, does not necessarily mean that it will become the applied
902 value, due to the fact that the style property's value might have been set
903 earlier with a higher priority in external or embedded style declarations.
905 In order to ensure that the value will be applied, you may have to append
906 "!important" to the value.
908 void QWebElement::setStyleProperty(const QString &name, const QString &value)
910 if (!m_element || !m_element->isStyledElement())
913 int propID = cssPropertyID(name);
914 CSSStyleDeclaration* style = static_cast<StyledElement*>(m_element)->style();
915 if (!propID || !style)
918 ExceptionCode exception = 0;
919 style->setProperty(name, value, exception);
923 Returns the list of classes of this element.
925 QStringList QWebElement::classes() const
927 if (!hasAttribute(QLatin1String("class")))
928 return QStringList();
930 QStringList classes = attribute(QLatin1String("class")).simplified().split(QLatin1Char(' '), QString::SkipEmptyParts);
931 classes.removeDuplicates();
936 Returns true if this element has a class with the given \a name; otherwise
939 bool QWebElement::hasClass(const QString &name) const
941 QStringList list = classes();
942 return list.contains(name);
946 Adds the specified class with the given \a name to the element.
948 void QWebElement::addClass(const QString &name)
950 QStringList list = classes();
951 if (!list.contains(name)) {
953 QString value = list.join(QLatin1String(" "));
954 setAttribute(QLatin1String("class"), value);
959 Removes the specified class with the given \a name from the element.
961 void QWebElement::removeClass(const QString &name)
963 QStringList list = classes();
964 if (list.contains(name)) {
965 list.removeAll(name);
966 QString value = list.join(QLatin1String(" "));
967 setAttribute(QLatin1String("class"), value);
972 Adds the specified class with the given \a name if it is not present. If
973 the class is already present, it will be removed.
975 void QWebElement::toggleClass(const QString &name)
977 QStringList list = classes();
978 if (list.contains(name))
979 list.removeAll(name);
983 QString value = list.join(QLatin1String(" "));
984 setAttribute(QLatin1String("class"), value);
988 Appends the given \a element as the element's last child.
990 If \a element is the child of another element, it is re-parented to this
991 element. If \a element is a child of this element, then its position in
992 the list of children is changed.
994 Calling this function on a null element does nothing.
996 \sa prependInside(), prependOutside(), appendOutside()
998 void QWebElement::appendInside(const QWebElement &element)
1000 if (!m_element || element.isNull())
1003 ExceptionCode exception = 0;
1004 m_element->appendChild(element.m_element, exception);
1008 Appends the result of parsing \a markup as the element's last child.
1010 Calling this function on a null element does nothing.
1012 \sa prependInside(), prependOutside(), appendOutside()
1014 void QWebElement::appendInside(const QString &markup)
1019 if (!m_element->isHTMLElement())
1022 RefPtr<DocumentFragment> fragment = Range::createDocumentFragmentForElement(markup, toHTMLElement(m_element));
1024 ExceptionCode exception = 0;
1025 m_element->appendChild(fragment, exception);
1029 Prepends \a element as the element's first child.
1031 If \a element is the child of another element, it is re-parented to this
1032 element. If \a element is a child of this element, then its position in
1033 the list of children is changed.
1035 Calling this function on a null element does nothing.
1037 \sa appendInside(), prependOutside(), appendOutside()
1039 void QWebElement::prependInside(const QWebElement &element)
1041 if (!m_element || element.isNull())
1044 ExceptionCode exception = 0;
1046 if (m_element->hasChildNodes())
1047 m_element->insertBefore(element.m_element, m_element->firstChild(), exception);
1049 m_element->appendChild(element.m_element, exception);
1053 Prepends the result of parsing \a markup as the element's first child.
1055 Calling this function on a null element does nothing.
1057 \sa appendInside(), prependOutside(), appendOutside()
1059 void QWebElement::prependInside(const QString &markup)
1064 if (!m_element->isHTMLElement())
1067 RefPtr<DocumentFragment> fragment = Range::createDocumentFragmentForElement(markup, toHTMLElement(m_element));
1069 ExceptionCode exception = 0;
1071 if (m_element->hasChildNodes())
1072 m_element->insertBefore(fragment, m_element->firstChild(), exception);
1074 m_element->appendChild(fragment, exception);
1079 Inserts the given \a element before this element.
1081 If \a element is the child of another element, it is re-parented to the
1082 parent of this element.
1084 Calling this function on a null element does nothing.
1086 \sa appendInside(), prependInside(), appendOutside()
1088 void QWebElement::prependOutside(const QWebElement &element)
1090 if (!m_element || element.isNull())
1093 if (!m_element->parentNode())
1096 ExceptionCode exception = 0;
1097 m_element->parentNode()->insertBefore(element.m_element, m_element, exception);
1101 Inserts the result of parsing \a markup before this element.
1103 Calling this function on a null element does nothing.
1105 \sa appendInside(), prependInside(), appendOutside()
1107 void QWebElement::prependOutside(const QString &markup)
1112 Node* parent = m_element->parentNode();
1116 if (!parent->isHTMLElement())
1119 RefPtr<DocumentFragment> fragment = Range::createDocumentFragmentForElement(markup, toHTMLElement(parent));
1121 ExceptionCode exception = 0;
1122 parent->insertBefore(fragment, m_element, exception);
1126 Inserts the given \a element after this element.
1128 If \a element is the child of another element, it is re-parented to the
1129 parent of this element.
1131 Calling this function on a null element does nothing.
1133 \sa appendInside(), prependInside(), prependOutside()
1135 void QWebElement::appendOutside(const QWebElement &element)
1137 if (!m_element || element.isNull())
1140 if (!m_element->parentNode())
1143 ExceptionCode exception = 0;
1144 if (!m_element->nextSibling())
1145 m_element->parentNode()->appendChild(element.m_element, exception);
1147 m_element->parentNode()->insertBefore(element.m_element, m_element->nextSibling(), exception);
1151 Inserts the result of parsing \a markup after this element.
1153 Calling this function on a null element does nothing.
1155 \sa appendInside(), prependInside(), prependOutside()
1157 void QWebElement::appendOutside(const QString &markup)
1162 Node* parent = m_element->parentNode();
1166 if (!parent->isHTMLElement())
1169 RefPtr<DocumentFragment> fragment = Range::createDocumentFragmentForElement(markup, toHTMLElement(parent));
1171 ExceptionCode exception = 0;
1172 if (!m_element->nextSibling())
1173 parent->appendChild(fragment, exception);
1175 parent->insertBefore(fragment, m_element->nextSibling(), exception);
1179 Returns a clone of this element.
1181 The clone may be inserted at any point in the document.
1183 \sa appendInside(), prependInside(), prependOutside(), appendOutside()
1185 QWebElement QWebElement::clone() const
1188 return QWebElement();
1190 return QWebElement(m_element->cloneElementWithChildren().get());
1194 Removes this element from the document and returns a reference to it.
1196 The element is still valid after removal, and can be inserted into other
1197 parts of the document.
1199 \sa removeAllChildren(), removeFromDocument()
1201 QWebElement &QWebElement::takeFromDocument()
1206 ExceptionCode exception = 0;
1207 m_element->remove(exception);
1213 Removes this element from the document and makes it a null element.
1215 \sa removeAllChildren(), takeFromDocument()
1217 void QWebElement::removeFromDocument()
1222 ExceptionCode exception = 0;
1223 m_element->remove(exception);
1229 Removes all children from this element.
1231 \sa removeFromDocument(), takeFromDocument()
1233 void QWebElement::removeAllChildren()
1238 m_element->removeAllChildren();
1241 // FIXME: This code, and all callers are wrong, and have no place in a
1242 // WebKit implementation. These should be replaced with WebCore implementations.
1243 static RefPtr<Node> findInsertionPoint(PassRefPtr<Node> root)
1245 RefPtr<Node> node = root;
1247 // Go as far down the tree as possible.
1248 while (node->hasChildNodes() && node->firstChild()->isElementNode())
1249 node = node->firstChild();
1251 // TODO: Implement SVG support
1252 if (node->isHTMLElement()) {
1253 HTMLElement* element = static_cast<HTMLElement*>(node.get());
1255 // The insert point could be a non-enclosable tag and it can thus
1256 // never have children, so go one up. Get the parent element, and not
1257 // note as a root note will always exist.
1258 if (element->ieForbidsInsertHTML())
1259 node = node->parentElement();
1266 Encloses the contents of this element with \a element. This element becomes
1267 the child of the deepest descendant within \a element.
1273 void QWebElement::encloseContentsWith(const QWebElement &element)
1275 if (!m_element || element.isNull())
1278 RefPtr<Node> insertionPoint = findInsertionPoint(element.m_element);
1280 if (!insertionPoint)
1283 ExceptionCode exception = 0;
1285 // reparent children
1286 for (RefPtr<Node> child = m_element->firstChild(); child;) {
1287 RefPtr<Node> next = child->nextSibling();
1288 insertionPoint->appendChild(child, exception);
1292 if (m_element->hasChildNodes())
1293 m_element->insertBefore(element.m_element, m_element->firstChild(), exception);
1295 m_element->appendChild(element.m_element, exception);
1299 Encloses the contents of this element with the result of parsing \a markup.
1300 This element becomes the child of the deepest descendant within \a markup.
1304 void QWebElement::encloseContentsWith(const QString &markup)
1309 if (!m_element->parentNode())
1312 if (!m_element->isHTMLElement())
1315 RefPtr<DocumentFragment> fragment = Range::createDocumentFragmentForElement(markup, toHTMLElement(m_element));
1317 if (!fragment || !fragment->firstChild())
1320 RefPtr<Node> insertionPoint = findInsertionPoint(fragment->firstChild());
1322 if (!insertionPoint)
1325 ExceptionCode exception = 0;
1327 // reparent children
1328 for (RefPtr<Node> child = m_element->firstChild(); child;) {
1329 RefPtr<Node> next = child->nextSibling();
1330 insertionPoint->appendChild(child, exception);
1334 if (m_element->hasChildNodes())
1335 m_element->insertBefore(fragment, m_element->firstChild(), exception);
1337 m_element->appendChild(fragment, exception);
1341 Encloses this element with \a element. This element becomes the child of
1342 the deepest descendant within \a element.
1346 void QWebElement::encloseWith(const QWebElement &element)
1348 if (!m_element || element.isNull())
1351 RefPtr<Node> insertionPoint = findInsertionPoint(element.m_element);
1353 if (!insertionPoint)
1356 // Keep reference to these two nodes before pulling out this element and
1357 // wrapping it in the fragment. The reason for doing it in this order is
1358 // that once the fragment has been added to the document it is empty, so
1359 // we no longer have access to the nodes it contained.
1360 Node* parent = m_element->parentNode();
1361 Node* siblingNode = m_element->nextSibling();
1363 ExceptionCode exception = 0;
1364 insertionPoint->appendChild(m_element, exception);
1367 parent->appendChild(element.m_element, exception);
1369 parent->insertBefore(element.m_element, siblingNode, exception);
1373 Encloses this element with the result of parsing \a markup. This element
1374 becomes the child of the deepest descendant within \a markup.
1378 void QWebElement::encloseWith(const QString &markup)
1383 Node* parent = m_element->parentNode();
1387 if (!parent->isHTMLElement())
1390 RefPtr<DocumentFragment> fragment = Range::createDocumentFragmentForElement(markup, toHTMLElement(parent));
1392 if (!fragment || !fragment->firstChild())
1395 RefPtr<Node> insertionPoint = findInsertionPoint(fragment->firstChild());
1397 if (!insertionPoint)
1400 // Keep reference to parent & siblingNode before pulling out this element and
1401 // wrapping it in the fragment. The reason for doing it in this order is
1402 // that once the fragment has been added to the document it is empty, so
1403 // we no longer have access to the nodes it contained.
1404 Node* siblingNode = m_element->nextSibling();
1406 ExceptionCode exception = 0;
1407 insertionPoint->appendChild(m_element, exception);
1410 parent->appendChild(fragment, exception);
1412 parent->insertBefore(fragment, siblingNode, exception);
1416 Replaces this element with \a element.
1418 This method will not replace the <html>, <head> or <body> elements.
1422 void QWebElement::replace(const QWebElement &element)
1424 if (!m_element || element.isNull())
1427 appendOutside(element);
1432 Replaces this element with the result of parsing \a markup.
1434 This method will not replace the <html>, <head> or <body> elements.
1438 void QWebElement::replace(const QString &markup)
1443 appendOutside(markup);
1449 Walk \a node's parents until a valid QWebElement is found.
1450 For example, a WebCore::Text node is not a valid Html QWebElement, but its
1453 QWebElement QWebElement::enclosingElement(WebCore::Node* node)
1455 QWebElement element(node);
1457 while (element.isNull() && node) {
1458 node = node->parentNode();
1459 element = QWebElement(node);
1465 \fn inline bool QWebElement::operator==(const QWebElement& o) const;
1467 Returns true if this element points to the same underlying DOM object as
1468 \a o; otherwise returns false.
1472 \fn inline bool QWebElement::operator!=(const QWebElement& o) const;
1474 Returns true if this element points to a different underlying DOM object
1475 than \a o; otherwise returns false.
1480 Render the element into \a painter .
1482 void QWebElement::render(QPainter* painter)
1484 render(painter, QRect());
1488 Render the element into \a painter clipping to \a clip.
1490 void QWebElement::render(QPainter* painter, const QRect& clip)
1492 WebCore::Element* e = m_element;
1493 Document* doc = e ? e->document() : 0;
1497 Frame* frame = doc->frame();
1498 if (!frame || !frame->view() || !frame->contentRenderer())
1501 FrameView* view = frame->view();
1503 view->updateLayoutAndStyleIfNeededRecursive();
1505 IntRect rect = e->getRect();
1507 if (rect.size().isEmpty())
1510 QRect finalClipRect = rect;
1511 if (!clip.isEmpty())
1512 rect.intersect(clip.translated(rect.location()));
1514 GraphicsContext context(painter);
1517 context.translate(-rect.x(), -rect.y());
1518 painter->setClipRect(finalClipRect, Qt::IntersectClip);
1519 view->setNodeToDraw(e);
1520 view->paintContents(&context, finalClipRect);
1521 view->setNodeToDraw(0);
1525 class QWebElementCollectionPrivate : public QSharedData
1528 static QWebElementCollectionPrivate* create(const PassRefPtr<Node> &context, const QString &query);
1530 RefPtr<NodeList> m_result;
1533 inline QWebElementCollectionPrivate() {}
1536 QWebElementCollectionPrivate* QWebElementCollectionPrivate::create(const PassRefPtr<Node> &context, const QString &query)
1541 // Let WebKit do the hard work hehehe
1542 ExceptionCode exception = 0; // ###
1543 RefPtr<NodeList> nodes = context->querySelectorAll(query, exception);
1547 QWebElementCollectionPrivate* priv = new QWebElementCollectionPrivate;
1548 priv->m_result = nodes;
1553 \class QWebElementCollection
1555 \brief The QWebElementCollection class represents a collection of web elements.
1558 Elements in a document can be selected using QWebElement::findAll() or using the
1559 QWebElement constructor. The collection is composed by choosing all elements in the
1560 document that match a specified CSS selector expression.
1562 The number of selected elements is provided through the count() property. Individual
1563 elements can be retrieved by index using at().
1565 It is also possible to iterate through all elements in the collection using Qt's foreach
1569 QWebElementCollection collection = document.findAll("p");
1570 foreach (QWebElement paraElement, collection) {
1577 Constructs an empty collection.
1579 QWebElementCollection::QWebElementCollection()
1584 Constructs a copy of \a other.
1586 QWebElementCollection::QWebElementCollection(const QWebElementCollection &other)
1592 Constructs a collection of elements from the list of child elements of \a contextElement that
1593 match the specified CSS selector \a query.
1595 QWebElementCollection::QWebElementCollection(const QWebElement &contextElement, const QString &query)
1597 d = QExplicitlySharedDataPointer<QWebElementCollectionPrivate>(QWebElementCollectionPrivate::create(contextElement.m_element, query));
1601 Assigns \a other to this collection and returns a reference to this collection.
1603 QWebElementCollection &QWebElementCollection::operator=(const QWebElementCollection &other)
1610 Destroys the collection.
1612 QWebElementCollection::~QWebElementCollection()
1616 /*! \fn QWebElementCollection &QWebElementCollection::operator+=(const QWebElementCollection &other)
1618 Appends the items of the \a other list to this list and returns a
1619 reference to this list.
1621 \sa operator+(), append()
1625 Returns a collection that contains all the elements of this collection followed
1626 by all the elements in the \a other collection. Duplicates may occur in the result.
1630 QWebElementCollection QWebElementCollection::operator+(const QWebElementCollection &other) const
1632 QWebElementCollection n = *this; n.d.detach(); n += other; return n;
1636 Extends the collection by appending all items of \a other.
1638 The resulting collection may include duplicate elements.
1642 void QWebElementCollection::append(const QWebElementCollection &other)
1650 Vector<RefPtr<Node> > nodes;
1651 RefPtr<NodeList> results[] = { d->m_result, other.d->m_result };
1652 nodes.reserveInitialCapacity(results[0]->length() + results[1]->length());
1654 for (int i = 0; i < 2; ++i) {
1656 Node* n = results[i]->item(j);
1659 n = results[i]->item(++j);
1663 d->m_result = StaticNodeList::adopt(nodes);
1667 Returns the number of elements in the collection.
1669 int QWebElementCollection::count() const
1673 return d->m_result->length();
1677 Returns the element at index position \a i in the collection.
1679 QWebElement QWebElementCollection::at(int i) const
1682 return QWebElement();
1683 Node* n = d->m_result->item(i);
1684 return QWebElement(static_cast<Element*>(n));
1688 \fn const QWebElement QWebElementCollection::operator[](int position) const
1690 Returns the element at the specified \a position in the collection.
1693 /*! \fn QWebElement QWebElementCollection::first() const
1695 Returns the first element in the collection.
1697 \sa last(), operator[](), at(), count()
1700 /*! \fn QWebElement QWebElementCollection::last() const
1702 Returns the last element in the collection.
1704 \sa first(), operator[](), at(), count()
1708 Returns a QList object with the elements contained in this collection.
1710 QList<QWebElement> QWebElementCollection::toList() const
1713 return QList<QWebElement>();
1714 QList<QWebElement> elements;
1716 Node* n = d->m_result->item(i);
1718 if (n->isElementNode())
1719 elements.append(QWebElement(static_cast<Element*>(n)));
1720 n = d->m_result->item(++i);
1726 \fn QWebElementCollection::const_iterator QWebElementCollection::begin() const
1728 Returns an STL-style iterator pointing to the first element in the collection.
1734 \fn QWebElementCollection::const_iterator QWebElementCollection::end() const
1736 Returns an STL-style iterator pointing to the imaginary element after the
1737 last element in the list.
1743 \class QWebElementCollection::const_iterator
1745 \brief The QWebElementCollection::const_iterator class provides an STL-style const iterator for QWebElementCollection.
1747 QWebElementCollection provides STL style const iterators for fast low-level access to the elements.
1749 QWebElementCollection::const_iterator allows you to iterate over a QWebElementCollection.
1753 \fn QWebElementCollection::const_iterator::const_iterator(const const_iterator &other)
1755 Constructs a copy of \a other.
1759 \fn QWebElementCollection::const_iterator::const_iterator(const QWebElementCollection *collection, int index)
1764 \fn const QWebElement QWebElementCollection::const_iterator::operator*() const
1766 Returns the current element.
1770 \fn bool QWebElementCollection::const_iterator::operator==(const const_iterator &other) const
1772 Returns true if \a other points to the same item as this iterator;
1773 otherwise returns false.
1779 \fn bool QWebElementCollection::const_iterator::operator!=(const const_iterator &other) const
1781 Returns true if \a other points to a different element than this;
1782 iterator; otherwise returns false.
1788 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator++()
1790 The prefix ++ operator (\c{++it}) advances the iterator to the next element in the collection
1791 and returns an iterator to the new current element.
1793 Calling this function on QWebElementCollection::end() leads to undefined results.
1799 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator++(int)
1803 The postfix ++ operator (\c{it++}) advances the iterator to the next element in the collection
1804 and returns an iterator to the previously current element.
1806 Calling this function on QWebElementCollection::end() leads to undefined results.
1810 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator--()
1812 The prefix -- operator (\c{--it}) makes the preceding element current and returns an
1813 iterator to the new current element.
1815 Calling this function on QWebElementCollection::begin() leads to undefined results.
1821 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator--(int)
1825 The postfix -- operator (\c{it--}) makes the preceding element current and returns
1826 an iterator to the previously current element.
1830 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator+=(int j)
1832 Advances the iterator by \a j elements. If \a j is negative, the iterator goes backward.
1834 \sa operator-=(), operator+()
1838 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator-=(int j)
1840 Makes the iterator go back by \a j elements. If \a j is negative, the iterator goes forward.
1842 \sa operator+=(), operator-()
1846 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator+(int j) const
1848 Returns an iterator to the element at \a j positions forward from this iterator. If \a j
1849 is negative, the iterator goes backward.
1851 \sa operator-(), operator+=()
1855 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator-(int j) const
1857 Returns an iterator to the element at \a j positiosn backward from this iterator.
1858 If \a j is negative, the iterator goes forward.
1860 \sa operator+(), operator-=()
1864 \fn int QWebElementCollection::const_iterator::operator-(const_iterator other) const
1866 Returns the number of elements between the item point to by \a other
1867 and the element pointed to by this iterator.
1871 \fn bool QWebElementCollection::const_iterator::operator<(const const_iterator &other) const
1873 Returns true if the element pointed to by this iterator is less than the element pointed to
1874 by the \a other iterator.
1878 \fn bool QWebElementCollection::const_iterator::operator<=(const const_iterator &other) const
1880 Returns true if the element pointed to by this iterator is less than or equal to the
1881 element pointed to by the \a other iterator.
1885 \fn bool QWebElementCollection::const_iterator::operator>(const const_iterator &other) const
1887 Returns true if the element pointed to by this iterator is greater than the element pointed to
1888 by the \a other iterator.
1892 \fn bool QWebElementCollection::const_iterator::operator>=(const const_iterator &other) const
1894 Returns true if the element pointed to by this iterator is greater than or equal to the
1895 element pointed to by the \a other iterator.
1899 \fn QWebElementCollection::iterator QWebElementCollection::begin()
1901 Returns an STL-style iterator pointing to the first element in the collection.
1907 \fn QWebElementCollection::iterator QWebElementCollection::end()
1909 Returns an STL-style iterator pointing to the imaginary element after the
1910 last element in the list.
1916 \fn QWebElementCollection::const_iterator QWebElementCollection::constBegin() const
1918 Returns an STL-style iterator pointing to the first element in the collection.
1924 \fn QWebElementCollection::const_iterator QWebElementCollection::constEnd() const
1926 Returns an STL-style iterator pointing to the imaginary element after the
1927 last element in the list.
1933 \class QWebElementCollection::iterator
1935 \brief The QWebElementCollection::iterator class provides an STL-style iterator for QWebElementCollection.
1937 QWebElementCollection provides STL style iterators for fast low-level access to the elements.
1939 QWebElementCollection::iterator allows you to iterate over a QWebElementCollection.
1943 \fn QWebElementCollection::iterator::iterator(const iterator &other)
1945 Constructs a copy of \a other.
1949 \fn QWebElementCollection::iterator::iterator(const QWebElementCollection *collection, int index)
1954 \fn const QWebElement QWebElementCollection::iterator::operator*() const
1956 Returns the current element.
1960 \fn bool QWebElementCollection::iterator::operator==(const iterator &other) const
1962 Returns true if \a other points to the same item as this iterator;
1963 otherwise returns false.
1969 \fn bool QWebElementCollection::iterator::operator!=(const iterator &other) const
1971 Returns true if \a other points to a different element than this;
1972 iterator; otherwise returns false.
1978 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator++()
1980 The prefix ++ operator (\c{++it}) advances the iterator to the next element in the collection
1981 and returns an iterator to the new current element.
1983 Calling this function on QWebElementCollection::end() leads to undefined results.
1989 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator++(int)
1993 The postfix ++ operator (\c{it++}) advances the iterator to the next element in the collection
1994 and returns an iterator to the previously current element.
1996 Calling this function on QWebElementCollection::end() leads to undefined results.
2000 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator--()
2002 The prefix -- operator (\c{--it}) makes the preceding element current and returns an
2003 iterator to the new current element.
2005 Calling this function on QWebElementCollection::begin() leads to undefined results.
2011 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator--(int)
2015 The postfix -- operator (\c{it--}) makes the preceding element current and returns
2016 an iterator to the previously current element.
2020 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator+=(int j)
2022 Advances the iterator by \a j elements. If \a j is negative, the iterator goes backward.
2024 \sa operator-=(), operator+()
2028 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator-=(int j)
2030 Makes the iterator go back by \a j elements. If \a j is negative, the iterator goes forward.
2032 \sa operator+=(), operator-()
2036 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator+(int j) const
2038 Returns an iterator to the element at \a j positions forward from this iterator. If \a j
2039 is negative, the iterator goes backward.
2041 \sa operator-(), operator+=()
2045 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator-(int j) const
2047 Returns an iterator to the element at \a j positiosn backward from this iterator.
2048 If \a j is negative, the iterator goes forward.
2050 \sa operator+(), operator-=()
2054 \fn int QWebElementCollection::iterator::operator-(iterator other) const
2056 Returns the number of elements between the item point to by \a other
2057 and the element pointed to by this iterator.
2061 \fn bool QWebElementCollection::iterator::operator<(const iterator &other) const
2063 Returns true if the element pointed to by this iterator is less than the element pointed to
2064 by the \a other iterator.
2068 \fn bool QWebElementCollection::iterator::operator<=(const iterator &other) const
2070 Returns true if the element pointed to by this iterator is less than or equal to the
2071 element pointed to by the \a other iterator.
2075 \fn bool QWebElementCollection::iterator::operator>(const iterator &other) const
2077 Returns true if the element pointed to by this iterator is greater than the element pointed to
2078 by the \a other iterator.
2082 \fn bool QWebElementCollection::iterator::operator>=(const iterator &other) const
2084 Returns true if the element pointed to by this iterator is greater than or equal to the
2085 element pointed to by the \a other iterator.
2089 QWebElement QtWebElementRuntime::create(Element* element)
2091 return QWebElement(element);
2094 Element* QtWebElementRuntime::get(const QWebElement& element)
2096 return element.m_element;
2099 static QVariant convertJSValueToWebElementVariant(JSC::JSObject* object, int *distance, HashSet<JSC::JSObject*>* visitedObjects)
2101 Element* element = 0;
2103 if (object && object->inherits(&JSElement::s_info)) {
2104 element =(static_cast<JSElement*>(object))->impl();
2106 // Allow other objects to reach this one. This won't cause our algorithm to
2107 // loop since when we find an Element we do not recurse.
2108 visitedObjects->remove(object);
2109 } else if (object && object->inherits(&JSDocument::s_info)) {
2110 // To support LayoutTestControllerQt::nodesFromRect(), used in DRT, we do an implicit
2111 // conversion from 'document' to the QWebElement representing the 'document.documentElement'.
2112 // We can't simply use a QVariantMap in nodesFromRect() because it currently times out
2113 // when serializing DOMMimeType and DOMPlugin, even if we limit the recursion.
2114 element =(static_cast<JSDocument*>(object))->impl()->documentElement();
2117 return QVariant::fromValue<QWebElement>(QtWebElementRuntime::create(element));
2120 static JSC::JSValue convertWebElementVariantToJSValue(JSC::ExecState* exec, WebCore::JSDOMGlobalObject* globalObject, const QVariant& variant)
2122 return WebCore::toJS(exec, globalObject, QtWebElementRuntime::get(variant.value<QWebElement>()));
2126 void QtWebElementRuntime::initialize()
2128 static bool initialized = false;
2133 int id = qRegisterMetaType<QWebElement>();
2134 JSC::Bindings::registerCustomType(id, convertJSValueToWebElementVariant, convertWebElementVariantToJSValue);