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 "CSSParser.h"
27 #include "CSSRuleList.h"
28 #include "CSSStyleRule.h"
30 #include "DocumentFragment.h"
31 #include "FrameView.h"
32 #include "GraphicsContext.h"
33 #include "HTMLElement.h"
34 #include "StylePropertySet.h"
35 #include "StyleRule.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 "StyleResolver.h"
55 #include "qwebframe.h"
56 #include "qwebframe_p.h"
58 #include "runtime_root.h"
59 #include <JSDocument.h>
61 #include <wtf/Vector.h>
62 #include <wtf/text/CString.h>
66 using namespace WebCore;
68 class QWebElementPrivate {
75 \brief The QWebElement class provides convenient access to DOM elements in
79 A QWebElement object allows easy access to the document model, represented
80 by a tree-like structure of DOM elements. The root of the tree is called
81 the document element and can be accessed using
82 QWebFrame::documentElement().
84 Specific elements can be accessed using findAll() and findFirst(). These
85 elements are identified using CSS selectors. The code snippet below
86 demonstrates the use of findAll().
88 \snippet webkitsnippets/webelement/main.cpp FindAll
90 The first list contains all \c span elements in the document. The second
91 list contains \c span elements that are children of \c p, classified with
94 Using findFirst() is more efficient than calling findAll(), and extracting
95 the first element only in the list returned.
97 Alternatively you can traverse the document manually using firstChild() and
100 \snippet webkitsnippets/webelement/main.cpp Traversing with QWebElement
102 Individual elements can be inspected or changed using methods such as attribute()
103 or setAttribute(). For examle, to capture the user's input in a text field for later
104 use (auto-completion), a browser could do something like this:
106 \snippet webkitsnippets/webelement/main.cpp autocomplete1
108 When the same page is later revisited, the browser can fill in the text field automatically
109 by modifying the value attribute of the input element:
111 \snippet webkitsnippets/webelement/main.cpp autocomplete2
113 Another use case is to emulate a click event on an element. The following
114 code snippet demonstrates how to call the JavaScript DOM method click() of
117 \snippet webkitsnippets/webelement/main.cpp Calling a DOM element method
119 The underlying content of QWebElement is explicitly shared. Creating a copy
120 of a QWebElement does not create a copy of the content. Instead, both
121 instances point to the same element.
123 The contents of child elements can be converted to plain text with
124 toPlainText(); to XHTML using toInnerXml(). To include the element's tag in
125 the output, use toOuterXml().
127 It is possible to replace the contents of child elements using
128 setPlainText() and setInnerXml(). To replace the element itself and its
129 contents, use setOuterXml().
133 The \l{DOM Traversal Example} shows one way to traverse documents in a running
136 The \l{Simple Selector Example} can be used to experiment with the searching
137 features of this class and provides sample code you can start working with.
141 Constructs a null web element.
143 QWebElement::QWebElement()
152 QWebElement::QWebElement(WebCore::Element* domElement)
154 , m_element(domElement)
163 QWebElement::QWebElement(WebCore::Node* node)
167 if (node && node->isHTMLElement()) {
168 m_element = static_cast<HTMLElement*>(node);
174 Constructs a copy of \a other.
176 QWebElement::QWebElement(const QWebElement &other)
178 , m_element(other.m_element)
185 Assigns \a other to this element and returns a reference to this element.
187 QWebElement &QWebElement::operator=(const QWebElement &other)
189 // ### handle "d" assignment
190 if (this != &other) {
191 Element *otherElement = other.m_element;
196 m_element = otherElement;
202 Destroys the element. However, the underlying DOM element is not destroyed.
204 QWebElement::~QWebElement()
211 bool QWebElement::operator==(const QWebElement& o) const
213 return m_element == o.m_element;
216 bool QWebElement::operator!=(const QWebElement& o) const
218 return m_element != o.m_element;
222 Returns true if the element is a null element; otherwise returns false.
224 bool QWebElement::isNull() const
230 Returns a new list of child elements matching the given CSS selector
231 \a selectorQuery. If there are no matching elements, an empty list is
234 \l{Standard CSS2 selector} syntax is used for the query.
236 \note This search is performed recursively.
240 QWebElementCollection QWebElement::findAll(const QString &selectorQuery) const
242 return QWebElementCollection(*this, selectorQuery);
246 Returns the first child element that matches the given CSS selector
249 \l{Standard CSS2 selector} syntax is used for the query.
251 \note This search is performed recursively.
255 QWebElement QWebElement::findFirst(const QString &selectorQuery) const
258 return QWebElement();
259 ExceptionCode exception = 0; // ###
260 return QWebElement(m_element->querySelector(selectorQuery, exception).get());
264 Replaces the existing content of this element with \a text.
266 This is equivalent to setting the HTML innerText property.
270 void QWebElement::setPlainText(const QString &text)
272 if (!m_element || !m_element->isHTMLElement())
274 ExceptionCode exception = 0;
275 static_cast<HTMLElement*>(m_element)->setInnerText(text, exception);
279 Returns the text between the start and the end tag of this
282 This is equivalent to reading the HTML innerText property.
286 QString QWebElement::toPlainText() const
288 if (!m_element || !m_element->isHTMLElement())
290 return static_cast<HTMLElement*>(m_element)->innerText();
294 Replaces the contents of this element as well as its own tag with
295 \a markup. The string may contain HTML or XML tags, which is parsed and
296 formatted before insertion into the document.
298 \note This is currently only implemented for (X)HTML elements.
300 \sa toOuterXml(), toInnerXml(), setInnerXml()
302 void QWebElement::setOuterXml(const QString &markup)
304 if (!m_element || !m_element->isHTMLElement())
307 ExceptionCode exception = 0;
309 static_cast<HTMLElement*>(m_element)->setOuterHTML(markup, exception);
313 Returns this element converted to XML, including the start and the end
314 tags as well as its attributes.
316 \note This is currently implemented for (X)HTML elements only.
318 \note The format of the markup returned will obey the namespace of the
319 document containing the element. This means the return value will obey XML
320 formatting rules, such as self-closing tags, only if the document is
323 \sa setOuterXml(), setInnerXml(), toInnerXml()
325 QString QWebElement::toOuterXml() const
327 if (!m_element || !m_element->isHTMLElement())
330 return static_cast<HTMLElement*>(m_element)->outerHTML();
334 Replaces the contents of this element with \a markup. The string may
335 contain HTML or XML tags, which is parsed and formatted before insertion
338 \note This is currently implemented for (X)HTML elements only.
340 \sa toInnerXml(), toOuterXml(), setOuterXml()
342 void QWebElement::setInnerXml(const QString &markup)
344 if (!m_element || !m_element->isHTMLElement())
347 ExceptionCode exception = 0;
349 static_cast<HTMLElement*>(m_element)->setInnerHTML(markup, exception);
353 Returns the XML content between the element's start and end tags.
355 \note This is currently implemented for (X)HTML elements only.
357 \note The format of the markup returned will obey the namespace of the
358 document containing the element. This means the return value will obey XML
359 formatting rules, such as self-closing tags, only if the document is
362 \sa setInnerXml(), setOuterXml(), toOuterXml()
364 QString QWebElement::toInnerXml() const
366 if (!m_element || !m_element->isHTMLElement())
369 return static_cast<HTMLElement*>(m_element)->innerHTML();
373 Adds an attribute with the given \a name and \a value. If an attribute with
374 the same name exists, its value is replaced by \a value.
376 \sa attribute(), attributeNS(), setAttributeNS()
378 void QWebElement::setAttribute(const QString &name, const QString &value)
382 ExceptionCode exception = 0;
383 m_element->setAttribute(name, value, exception);
387 Adds an attribute with the given \a name in \a namespaceUri with \a value.
388 If an attribute with the same name exists, its value is replaced by
391 \sa attributeNS(), attribute(), setAttribute()
393 void QWebElement::setAttributeNS(const QString &namespaceUri, const QString &name, const QString &value)
397 WebCore::ExceptionCode exception = 0;
398 m_element->setAttributeNS(namespaceUri, name, value, exception);
402 Returns the attribute with the given \a name. If the attribute does not
403 exist, \a defaultValue is returned.
405 \sa setAttribute(), setAttributeNS(), attributeNS()
407 QString QWebElement::attribute(const QString &name, const QString &defaultValue) const
411 if (m_element->hasAttribute(name))
412 return m_element->getAttribute(name);
418 Returns the attribute with the given \a name in \a namespaceUri. If the
419 attribute does not exist, \a defaultValue is returned.
421 \sa setAttributeNS(), setAttribute(), attribute()
423 QString QWebElement::attributeNS(const QString &namespaceUri, const QString &name, const QString &defaultValue) const
427 if (m_element->hasAttributeNS(namespaceUri, name))
428 return m_element->getAttributeNS(namespaceUri, name);
434 Returns true if this element has an attribute with the given \a name;
435 otherwise returns false.
437 \sa attribute(), setAttribute()
439 bool QWebElement::hasAttribute(const QString &name) const
443 return m_element->hasAttribute(name);
447 Returns true if this element has an attribute with the given \a name, in
448 \a namespaceUri; otherwise returns false.
450 \sa attributeNS(), setAttributeNS()
452 bool QWebElement::hasAttributeNS(const QString &namespaceUri, const QString &name) const
456 return m_element->hasAttributeNS(namespaceUri, name);
460 Removes the attribute with the given \a name from this element.
462 \sa attribute(), setAttribute(), hasAttribute()
464 void QWebElement::removeAttribute(const QString &name)
468 m_element->removeAttribute(name);
472 Removes the attribute with the given \a name, in \a namespaceUri, from this
475 \sa attributeNS(), setAttributeNS(), hasAttributeNS()
477 void QWebElement::removeAttributeNS(const QString &namespaceUri, const QString &name)
481 m_element->removeAttributeNS(namespaceUri, name);
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 if (m_element->hasAttributes()) {
509 const String namespaceUriString(namespaceUri); // convert QString -> String once
510 const unsigned attrsCount = m_element->attributeCount();
511 for (unsigned i = 0; i < attrsCount; ++i) {
512 const Attribute* const attribute = m_element->attributeItem(i);
513 if (namespaceUriString == attribute->namespaceURI())
514 attributeNameList.append(attribute->localName());
517 return attributeNameList;
521 Returns true if the element has keyboard input focus; otherwise, returns false
525 bool QWebElement::hasFocus() const
529 if (m_element->document())
530 return m_element == m_element->document()->focusedNode();
535 Gives keyboard input focus to this element
539 void QWebElement::setFocus()
543 if (m_element->document() && m_element->isFocusable())
544 m_element->document()->setFocusedNode(m_element);
548 Returns the geometry of this element, relative to its containing frame.
552 QRect QWebElement::geometry() const
556 return m_element->getPixelSnappedRect();
560 Returns the tag name of this element.
564 QString QWebElement::tagName() const
568 return m_element->tagName();
572 Returns the namespace prefix of the element. If the element has no\
573 namespace prefix, empty string is returned.
575 QString QWebElement::prefix() const
579 return m_element->prefix();
583 Returns the local name of the element. If the element does not use
584 namespaces, an empty string is returned.
586 QString QWebElement::localName() const
590 return m_element->localName();
594 Returns the namespace URI of this element. If the element has no namespace
595 URI, an empty string is returned.
597 QString QWebElement::namespaceUri() const
601 return m_element->namespaceURI();
605 Returns the parent element of this elemen. If this element is the root
606 document element, a null element is returned.
608 QWebElement QWebElement::parent() const
611 return QWebElement(m_element->parentElement());
612 return QWebElement();
616 Returns the element's first child.
618 \sa lastChild(), previousSibling(), nextSibling()
620 QWebElement QWebElement::firstChild() const
623 return QWebElement();
624 for (Node* child = m_element->firstChild(); child; child = child->nextSibling()) {
625 if (!child->isElementNode())
627 Element* e = static_cast<Element*>(child);
628 return QWebElement(e);
630 return QWebElement();
634 Returns the element's last child.
636 \sa firstChild(), previousSibling(), nextSibling()
638 QWebElement QWebElement::lastChild() const
641 return QWebElement();
642 for (Node* child = m_element->lastChild(); child; child = child->previousSibling()) {
643 if (!child->isElementNode())
645 Element* e = static_cast<Element*>(child);
646 return QWebElement(e);
648 return QWebElement();
652 Returns the element's next sibling.
654 \sa firstChild(), previousSibling(), lastChild()
656 QWebElement QWebElement::nextSibling() const
659 return QWebElement();
660 for (Node* sib = m_element->nextSibling(); sib; sib = sib->nextSibling()) {
661 if (!sib->isElementNode())
663 Element* e = static_cast<Element*>(sib);
664 return QWebElement(e);
666 return QWebElement();
670 Returns the element's previous sibling.
672 \sa firstChild(), nextSibling(), lastChild()
674 QWebElement QWebElement::previousSibling() const
677 return QWebElement();
678 for (Node* sib = m_element->previousSibling(); sib; sib = sib->previousSibling()) {
679 if (!sib->isElementNode())
681 Element* e = static_cast<Element*>(sib);
682 return QWebElement(e);
684 return QWebElement();
688 Returns the document which this element belongs to.
690 QWebElement QWebElement::document() const
693 return QWebElement();
694 Document* document = m_element->document();
696 return QWebElement();
697 return QWebElement(document->documentElement());
701 Returns the web frame which this element is a part of. If the element is a
702 null element, null is returned.
704 QWebFrame *QWebElement::webFrame() const
709 Document* document = m_element->document();
713 Frame* frame = document->frame();
716 return QWebFramePrivate::kit(frame);
720 static bool setupScriptContext(WebCore::Element* element, JSC::JSValue& thisValue, ScriptState*& state, ScriptController*& scriptController)
725 Document* document = element->document();
729 Frame* frame = document->frame();
733 scriptController = frame->script();
734 if (!scriptController)
737 state = scriptController->globalObject(mainThreadNormalWorld())->globalExec();
741 thisValue = toJS(state, deprecatedGlobalObjectForPrototype(state), element);
748 static bool setupScriptContext(WebCore::Element* element, v8::Handle<v8::Value>& thisValue, ScriptState*& state, ScriptController*& scriptController)
753 Document* document = element->document();
757 Frame* frame = document->frame();
761 state = mainWorldScriptState(frame);
762 // Get V8 wrapper for DOM element
763 thisValue = toV8(frame->domWindow());
770 Executes \a scriptSource with this element as \c this object.
772 QVariant QWebElement::evaluateJavaScript(const QString& scriptSource)
774 if (scriptSource.isEmpty())
777 ScriptState* state = 0;
779 JSC::JSValue thisValue;
781 v8::Handle<v8::Value> thisValue;
783 ScriptController* scriptController = 0;
785 if (!setupScriptContext(m_element, thisValue, state, scriptController))
788 JSC::ScopeChainNode* scopeChain = state->dynamicGlobalObject()->globalScopeChain();
789 JSC::UString script(reinterpret_cast_ptr<const UChar*>(scriptSource.data()), scriptSource.length());
791 JSC::JSValue evaluationException;
792 JSC::JSValue evaluationResult = JSC::evaluate(state, scopeChain, JSC::makeSource(script), thisValue, &evaluationException);
793 if (evaluationException)
797 return JSC::Bindings::convertValueToQVariant(state, evaluationResult, QMetaType::Void, &distance);
805 \enum QWebElement::StyleResolveStrategy
807 This enum describes how QWebElement's styleProperty resolves the given
810 \value InlineStyle Return the property value as it is defined in
811 the element, without respecting style inheritance and other CSS
813 \value CascadedStyle The property's value is determined using the
814 inheritance and importance rules defined in the document's
816 \value ComputedStyle The property's value is the absolute value
817 of the style property resolved from the environment.
821 Returns the value of the style with the given \a name using the specified
822 \a strategy. If a style with \a name does not exist, an empty string is
825 In CSS, the cascading part depends on which CSS rule has priority and is
826 thus applied. Generally, the last defined rule has priority. Thus, an
827 inline style rule has priority over an embedded block style rule, which
828 in return has priority over an external style rule.
830 If the "!important" declaration is set on one of those, the declaration
831 receives highest priority, unless other declarations also use the
832 "!important" declaration. Then, the last "!important" declaration takes
835 \sa setStyleProperty()
838 QString QWebElement::styleProperty(const QString &name, StyleResolveStrategy strategy) const
840 if (!m_element || !m_element->isStyledElement())
843 CSSPropertyID propID = cssPropertyID(name);
848 const StylePropertySet* style = static_cast<StyledElement*>(m_element)->ensureInlineStyle();
850 if (strategy == InlineStyle)
851 return style->getPropertyValue(propID);
853 if (strategy == CascadedStyle) {
854 if (style->propertyIsImportant(propID))
855 return style->getPropertyValue(propID);
857 // We are going to resolve the style property by walking through the
858 // list of non-inline matched CSS rules for the element, looking for
859 // the highest priority definition.
861 // Get an array of matched CSS rules for the given element sorted
862 // by importance and inheritance order. This include external CSS
863 // declarations, as well as embedded and inline style declarations.
865 Document* doc = m_element->document();
866 if (RefPtr<CSSRuleList> rules = doc->styleResolver()->styleRulesForElement(m_element, /*authorOnly*/ true)) {
867 for (int i = rules->length(); i > 0; --i) {
868 CSSStyleRule* rule = static_cast<CSSStyleRule*>(rules->item(i - 1));
870 if (rule->styleRule()->properties()->propertyIsImportant(propID))
871 return rule->styleRule()->properties()->getPropertyValue(propID);
873 if (style->getPropertyValue(propID).isEmpty())
874 style = rule->styleRule()->properties();
878 return style->getPropertyValue(propID);
881 if (strategy == ComputedStyle) {
882 if (!m_element || !m_element->isStyledElement())
885 RefPtr<CSSComputedStyleDeclaration> style = CSSComputedStyleDeclaration::create(m_element, true);
886 if (!propID || !style)
889 return style->getPropertyValue(propID);
896 Sets the value of the inline style with the given \a name to \a value.
898 Setting a value, does not necessarily mean that it will become the applied
899 value, due to the fact that the style property's value might have been set
900 earlier with a higher priority in external or embedded style declarations.
902 In order to ensure that the value will be applied, you may have to append
903 "!important" to the value.
905 void QWebElement::setStyleProperty(const QString &name, const QString &value)
907 if (!m_element || !m_element->isStyledElement())
910 CSSPropertyID propID = cssPropertyID(name);
911 static_cast<StyledElement*>(m_element)->setInlineStyleProperty(propID, value);
915 Returns the list of classes of this element.
917 QStringList QWebElement::classes() const
919 if (!hasAttribute(QLatin1String("class")))
920 return QStringList();
922 QStringList classes = attribute(QLatin1String("class")).simplified().split(QLatin1Char(' '), QString::SkipEmptyParts);
923 classes.removeDuplicates();
928 Returns true if this element has a class with the given \a name; otherwise
931 bool QWebElement::hasClass(const QString &name) const
933 QStringList list = classes();
934 return list.contains(name);
938 Adds the specified class with the given \a name to the element.
940 void QWebElement::addClass(const QString &name)
942 QStringList list = classes();
943 if (!list.contains(name)) {
945 QString value = list.join(QLatin1String(" "));
946 setAttribute(QLatin1String("class"), value);
951 Removes the specified class with the given \a name from the element.
953 void QWebElement::removeClass(const QString &name)
955 QStringList list = classes();
956 if (list.contains(name)) {
957 list.removeAll(name);
958 QString value = list.join(QLatin1String(" "));
959 setAttribute(QLatin1String("class"), value);
964 Adds the specified class with the given \a name if it is not present. If
965 the class is already present, it will be removed.
967 void QWebElement::toggleClass(const QString &name)
969 QStringList list = classes();
970 if (list.contains(name))
971 list.removeAll(name);
975 QString value = list.join(QLatin1String(" "));
976 setAttribute(QLatin1String("class"), value);
980 Appends the given \a element as the element's last child.
982 If \a element is the child of another element, it is re-parented to this
983 element. If \a element is a child of this element, then its position in
984 the list of children is changed.
986 Calling this function on a null element does nothing.
988 \sa prependInside(), prependOutside(), appendOutside()
990 void QWebElement::appendInside(const QWebElement &element)
992 if (!m_element || element.isNull())
995 ExceptionCode exception = 0;
996 m_element->appendChild(element.m_element, exception);
1000 Appends the result of parsing \a markup as the element's last child.
1002 Calling this function on a null element does nothing.
1004 \sa prependInside(), prependOutside(), appendOutside()
1006 void QWebElement::appendInside(const QString &markup)
1011 if (!m_element->isHTMLElement())
1014 ExceptionCode exception = 0;
1015 RefPtr<DocumentFragment> fragment = createContextualFragment(markup, toHTMLElement(m_element), AllowScriptingContent, exception);
1017 m_element->appendChild(fragment, exception);
1021 Prepends \a element as the element's first child.
1023 If \a element is the child of another element, it is re-parented to this
1024 element. If \a element is a child of this element, then its position in
1025 the list of children is changed.
1027 Calling this function on a null element does nothing.
1029 \sa appendInside(), prependOutside(), appendOutside()
1031 void QWebElement::prependInside(const QWebElement &element)
1033 if (!m_element || element.isNull())
1036 ExceptionCode exception = 0;
1038 if (m_element->hasChildNodes())
1039 m_element->insertBefore(element.m_element, m_element->firstChild(), exception);
1041 m_element->appendChild(element.m_element, exception);
1045 Prepends the result of parsing \a markup as the element's first child.
1047 Calling this function on a null element does nothing.
1049 \sa appendInside(), prependOutside(), appendOutside()
1051 void QWebElement::prependInside(const QString &markup)
1056 if (!m_element->isHTMLElement())
1059 ExceptionCode exception = 0;
1060 RefPtr<DocumentFragment> fragment = createContextualFragment(markup, toHTMLElement(m_element), AllowScriptingContent, exception);
1062 if (m_element->hasChildNodes())
1063 m_element->insertBefore(fragment, m_element->firstChild(), exception);
1065 m_element->appendChild(fragment, exception);
1070 Inserts the given \a element before this element.
1072 If \a element is the child of another element, it is re-parented to the
1073 parent of this element.
1075 Calling this function on a null element does nothing.
1077 \sa appendInside(), prependInside(), appendOutside()
1079 void QWebElement::prependOutside(const QWebElement &element)
1081 if (!m_element || element.isNull())
1084 if (!m_element->parentNode())
1087 ExceptionCode exception = 0;
1088 m_element->parentNode()->insertBefore(element.m_element, m_element, exception);
1092 Inserts the result of parsing \a markup before this element.
1094 Calling this function on a null element does nothing.
1096 \sa appendInside(), prependInside(), appendOutside()
1098 void QWebElement::prependOutside(const QString &markup)
1103 Node* parent = m_element->parentNode();
1107 if (!parent->isHTMLElement())
1110 ExceptionCode exception = 0;
1111 RefPtr<DocumentFragment> fragment = createContextualFragment(markup, toHTMLElement(parent), AllowScriptingContent, exception);
1113 parent->insertBefore(fragment, m_element, exception);
1117 Inserts the given \a element after this element.
1119 If \a element is the child of another element, it is re-parented to the
1120 parent of this element.
1122 Calling this function on a null element does nothing.
1124 \sa appendInside(), prependInside(), prependOutside()
1126 void QWebElement::appendOutside(const QWebElement &element)
1128 if (!m_element || element.isNull())
1131 if (!m_element->parentNode())
1134 ExceptionCode exception = 0;
1135 if (!m_element->nextSibling())
1136 m_element->parentNode()->appendChild(element.m_element, exception);
1138 m_element->parentNode()->insertBefore(element.m_element, m_element->nextSibling(), exception);
1142 Inserts the result of parsing \a markup after this element.
1144 Calling this function on a null element does nothing.
1146 \sa appendInside(), prependInside(), prependOutside()
1148 void QWebElement::appendOutside(const QString &markup)
1153 Node* parent = m_element->parentNode();
1157 if (!parent->isHTMLElement())
1160 ExceptionCode exception = 0;
1161 RefPtr<DocumentFragment> fragment = createContextualFragment(markup, toHTMLElement(parent), AllowScriptingContent, exception);
1163 if (!m_element->nextSibling())
1164 parent->appendChild(fragment, exception);
1166 parent->insertBefore(fragment, m_element->nextSibling(), exception);
1170 Returns a clone of this element.
1172 The clone may be inserted at any point in the document.
1174 \sa appendInside(), prependInside(), prependOutside(), appendOutside()
1176 QWebElement QWebElement::clone() const
1179 return QWebElement();
1181 return QWebElement(m_element->cloneElementWithChildren().get());
1185 Removes this element from the document and returns a reference to it.
1187 The element is still valid after removal, and can be inserted into other
1188 parts of the document.
1190 \sa removeAllChildren(), removeFromDocument()
1192 QWebElement &QWebElement::takeFromDocument()
1197 ExceptionCode exception = 0;
1198 m_element->remove(exception);
1204 Removes this element from the document and makes it a null element.
1206 \sa removeAllChildren(), takeFromDocument()
1208 void QWebElement::removeFromDocument()
1213 ExceptionCode exception = 0;
1214 m_element->remove(exception);
1220 Removes all children from this element.
1222 \sa removeFromDocument(), takeFromDocument()
1224 void QWebElement::removeAllChildren()
1229 m_element->removeAllChildren();
1232 // FIXME: This code, and all callers are wrong, and have no place in a
1233 // WebKit implementation. These should be replaced with WebCore implementations.
1234 static RefPtr<Node> findInsertionPoint(PassRefPtr<Node> root)
1236 RefPtr<Node> node = root;
1238 // Go as far down the tree as possible.
1239 while (node->hasChildNodes() && node->firstChild()->isElementNode())
1240 node = node->firstChild();
1242 // TODO: Implement SVG support
1243 if (node->isHTMLElement()) {
1244 HTMLElement* element = static_cast<HTMLElement*>(node.get());
1246 // The insert point could be a non-enclosable tag and it can thus
1247 // never have children, so go one up. Get the parent element, and not
1248 // note as a root note will always exist.
1249 if (element->ieForbidsInsertHTML())
1250 node = node->parentElement();
1257 Encloses the contents of this element with \a element. This element becomes
1258 the child of the deepest descendant within \a element.
1264 void QWebElement::encloseContentsWith(const QWebElement &element)
1266 if (!m_element || element.isNull())
1269 RefPtr<Node> insertionPoint = findInsertionPoint(element.m_element);
1271 if (!insertionPoint)
1274 ExceptionCode exception = 0;
1276 // reparent children
1277 for (RefPtr<Node> child = m_element->firstChild(); child;) {
1278 RefPtr<Node> next = child->nextSibling();
1279 insertionPoint->appendChild(child, exception);
1283 if (m_element->hasChildNodes())
1284 m_element->insertBefore(element.m_element, m_element->firstChild(), exception);
1286 m_element->appendChild(element.m_element, exception);
1290 Encloses the contents of this element with the result of parsing \a markup.
1291 This element becomes the child of the deepest descendant within \a markup.
1295 void QWebElement::encloseContentsWith(const QString &markup)
1300 if (!m_element->parentNode())
1303 if (!m_element->isHTMLElement())
1306 ExceptionCode exception = 0;
1307 RefPtr<DocumentFragment> fragment = createContextualFragment(markup, toHTMLElement(m_element), AllowScriptingContent, exception);
1309 if (!fragment || !fragment->firstChild())
1312 RefPtr<Node> insertionPoint = findInsertionPoint(fragment->firstChild());
1314 if (!insertionPoint)
1317 // reparent children
1318 for (RefPtr<Node> child = m_element->firstChild(); child;) {
1319 RefPtr<Node> next = child->nextSibling();
1320 insertionPoint->appendChild(child, exception);
1324 if (m_element->hasChildNodes())
1325 m_element->insertBefore(fragment, m_element->firstChild(), exception);
1327 m_element->appendChild(fragment, exception);
1331 Encloses this element with \a element. This element becomes the child of
1332 the deepest descendant within \a element.
1336 void QWebElement::encloseWith(const QWebElement &element)
1338 if (!m_element || element.isNull())
1341 RefPtr<Node> insertionPoint = findInsertionPoint(element.m_element);
1343 if (!insertionPoint)
1346 // Keep reference to these two nodes before pulling out this element and
1347 // wrapping it in the fragment. The reason for doing it in this order is
1348 // that once the fragment has been added to the document it is empty, so
1349 // we no longer have access to the nodes it contained.
1350 Node* parent = m_element->parentNode();
1351 Node* siblingNode = m_element->nextSibling();
1353 ExceptionCode exception = 0;
1354 insertionPoint->appendChild(m_element, exception);
1357 parent->appendChild(element.m_element, exception);
1359 parent->insertBefore(element.m_element, siblingNode, exception);
1363 Encloses this element with the result of parsing \a markup. This element
1364 becomes the child of the deepest descendant within \a markup.
1368 void QWebElement::encloseWith(const QString &markup)
1373 Node* parent = m_element->parentNode();
1377 if (!parent->isHTMLElement())
1380 ExceptionCode exception = 0;
1381 RefPtr<DocumentFragment> fragment = createContextualFragment(markup, toHTMLElement(parent), AllowScriptingContent, exception);
1383 if (!fragment || !fragment->firstChild())
1386 RefPtr<Node> insertionPoint = findInsertionPoint(fragment->firstChild());
1388 if (!insertionPoint)
1391 // Keep reference to parent & siblingNode before pulling out this element and
1392 // wrapping it in the fragment. The reason for doing it in this order is
1393 // that once the fragment has been added to the document it is empty, so
1394 // we no longer have access to the nodes it contained.
1395 Node* siblingNode = m_element->nextSibling();
1397 insertionPoint->appendChild(m_element, exception);
1400 parent->appendChild(fragment, exception);
1402 parent->insertBefore(fragment, siblingNode, exception);
1406 Replaces this element with \a element.
1408 This method will not replace the <html>, <head> or <body> elements.
1412 void QWebElement::replace(const QWebElement &element)
1414 if (!m_element || element.isNull())
1417 appendOutside(element);
1422 Replaces this element with the result of parsing \a markup.
1424 This method will not replace the <html>, <head> or <body> elements.
1428 void QWebElement::replace(const QString &markup)
1433 appendOutside(markup);
1439 Walk \a node's parents until a valid QWebElement is found.
1440 For example, a WebCore::Text node is not a valid Html QWebElement, but its
1443 QWebElement QWebElement::enclosingElement(WebCore::Node* node)
1445 QWebElement element(node);
1447 while (element.isNull() && node) {
1448 node = node->parentNode();
1449 element = QWebElement(node);
1455 \fn inline bool QWebElement::operator==(const QWebElement& o) const;
1457 Returns true if this element points to the same underlying DOM object as
1458 \a o; otherwise returns false.
1462 \fn inline bool QWebElement::operator!=(const QWebElement& o) const;
1464 Returns true if this element points to a different underlying DOM object
1465 than \a o; otherwise returns false.
1470 Render the element into \a painter .
1472 void QWebElement::render(QPainter* painter)
1474 render(painter, QRect());
1478 Render the element into \a painter clipping to \a clip.
1480 void QWebElement::render(QPainter* painter, const QRect& clip)
1482 WebCore::Element* e = m_element;
1483 Document* doc = e ? e->document() : 0;
1487 Frame* frame = doc->frame();
1488 if (!frame || !frame->view() || !frame->contentRenderer())
1491 FrameView* view = frame->view();
1493 view->updateLayoutAndStyleIfNeededRecursive();
1495 IntRect rect = e->getPixelSnappedRect();
1497 if (rect.size().isEmpty())
1500 QRect finalClipRect = rect;
1501 if (!clip.isEmpty())
1502 rect.intersect(clip.translated(rect.location()));
1504 GraphicsContext context(painter);
1507 context.translate(-rect.x(), -rect.y());
1508 painter->setClipRect(finalClipRect, Qt::IntersectClip);
1509 view->setNodeToDraw(e);
1510 view->paintContents(&context, finalClipRect);
1511 view->setNodeToDraw(0);
1515 class QWebElementCollectionPrivate : public QSharedData
1518 static QWebElementCollectionPrivate* create(const PassRefPtr<Node> &context, const QString &query);
1520 RefPtr<NodeList> m_result;
1523 inline QWebElementCollectionPrivate() {}
1526 QWebElementCollectionPrivate* QWebElementCollectionPrivate::create(const PassRefPtr<Node> &context, const QString &query)
1531 // Let WebKit do the hard work hehehe
1532 ExceptionCode exception = 0; // ###
1533 RefPtr<NodeList> nodes = context->querySelectorAll(query, exception);
1537 QWebElementCollectionPrivate* priv = new QWebElementCollectionPrivate;
1538 priv->m_result = nodes;
1543 \class QWebElementCollection
1545 \brief The QWebElementCollection class represents a collection of web elements.
1548 Elements in a document can be selected using QWebElement::findAll() or using the
1549 QWebElement constructor. The collection is composed by choosing all elements in the
1550 document that match a specified CSS selector expression.
1552 The number of selected elements is provided through the count() property. Individual
1553 elements can be retrieved by index using at().
1555 It is also possible to iterate through all elements in the collection using Qt's foreach
1559 QWebElementCollection collection = document.findAll("p");
1560 foreach (QWebElement paraElement, collection) {
1567 Constructs an empty collection.
1569 QWebElementCollection::QWebElementCollection()
1574 Constructs a copy of \a other.
1576 QWebElementCollection::QWebElementCollection(const QWebElementCollection &other)
1582 Constructs a collection of elements from the list of child elements of \a contextElement that
1583 match the specified CSS selector \a query.
1585 QWebElementCollection::QWebElementCollection(const QWebElement &contextElement, const QString &query)
1587 d = QExplicitlySharedDataPointer<QWebElementCollectionPrivate>(QWebElementCollectionPrivate::create(contextElement.m_element, query));
1591 Assigns \a other to this collection and returns a reference to this collection.
1593 QWebElementCollection &QWebElementCollection::operator=(const QWebElementCollection &other)
1600 Destroys the collection.
1602 QWebElementCollection::~QWebElementCollection()
1606 /*! \fn QWebElementCollection &QWebElementCollection::operator+=(const QWebElementCollection &other)
1608 Appends the items of the \a other list to this list and returns a
1609 reference to this list.
1611 \sa operator+(), append()
1615 Returns a collection that contains all the elements of this collection followed
1616 by all the elements in the \a other collection. Duplicates may occur in the result.
1620 QWebElementCollection QWebElementCollection::operator+(const QWebElementCollection &other) const
1622 QWebElementCollection n = *this; n.d.detach(); n += other; return n;
1626 Extends the collection by appending all items of \a other.
1628 The resulting collection may include duplicate elements.
1632 void QWebElementCollection::append(const QWebElementCollection &other)
1640 Vector<RefPtr<Node> > nodes;
1641 RefPtr<NodeList> results[] = { d->m_result, other.d->m_result };
1642 nodes.reserveInitialCapacity(results[0]->length() + results[1]->length());
1644 for (int i = 0; i < 2; ++i) {
1646 Node* n = results[i]->item(j);
1649 n = results[i]->item(++j);
1653 d->m_result = StaticNodeList::adopt(nodes);
1657 Returns the number of elements in the collection.
1659 int QWebElementCollection::count() const
1663 return d->m_result->length();
1667 Returns the element at index position \a i in the collection.
1669 QWebElement QWebElementCollection::at(int i) const
1672 return QWebElement();
1673 Node* n = d->m_result->item(i);
1674 return QWebElement(static_cast<Element*>(n));
1678 \fn const QWebElement QWebElementCollection::operator[](int position) const
1680 Returns the element at the specified \a position in the collection.
1683 /*! \fn QWebElement QWebElementCollection::first() const
1685 Returns the first element in the collection.
1687 \sa last(), operator[](), at(), count()
1690 /*! \fn QWebElement QWebElementCollection::last() const
1692 Returns the last element in the collection.
1694 \sa first(), operator[](), at(), count()
1698 Returns a QList object with the elements contained in this collection.
1700 QList<QWebElement> QWebElementCollection::toList() const
1703 return QList<QWebElement>();
1704 QList<QWebElement> elements;
1706 Node* n = d->m_result->item(i);
1708 if (n->isElementNode())
1709 elements.append(QWebElement(static_cast<Element*>(n)));
1710 n = d->m_result->item(++i);
1716 \fn QWebElementCollection::const_iterator QWebElementCollection::begin() const
1718 Returns an STL-style iterator pointing to the first element in the collection.
1724 \fn QWebElementCollection::const_iterator QWebElementCollection::end() const
1726 Returns an STL-style iterator pointing to the imaginary element after the
1727 last element in the list.
1733 \class QWebElementCollection::const_iterator
1735 \brief The QWebElementCollection::const_iterator class provides an STL-style const iterator for QWebElementCollection.
1737 QWebElementCollection provides STL style const iterators for fast low-level access to the elements.
1739 QWebElementCollection::const_iterator allows you to iterate over a QWebElementCollection.
1743 \fn QWebElementCollection::const_iterator::const_iterator(const const_iterator &other)
1745 Constructs a copy of \a other.
1749 \fn QWebElementCollection::const_iterator::const_iterator(const QWebElementCollection *collection, int index)
1754 \fn const QWebElement QWebElementCollection::const_iterator::operator*() const
1756 Returns the current element.
1760 \fn bool QWebElementCollection::const_iterator::operator==(const const_iterator &other) const
1762 Returns true if \a other points to the same item as this iterator;
1763 otherwise returns false.
1769 \fn bool QWebElementCollection::const_iterator::operator!=(const const_iterator &other) const
1771 Returns true if \a other points to a different element than this;
1772 iterator; otherwise returns false.
1778 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator++()
1780 The prefix ++ operator (\c{++it}) advances the iterator to the next element in the collection
1781 and returns an iterator to the new current element.
1783 Calling this function on QWebElementCollection::end() leads to undefined results.
1789 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator++(int)
1793 The postfix ++ operator (\c{it++}) advances the iterator to the next element in the collection
1794 and returns an iterator to the previously current element.
1796 Calling this function on QWebElementCollection::end() leads to undefined results.
1800 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator--()
1802 The prefix -- operator (\c{--it}) makes the preceding element current and returns an
1803 iterator to the new current element.
1805 Calling this function on QWebElementCollection::begin() leads to undefined results.
1811 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator--(int)
1815 The postfix -- operator (\c{it--}) makes the preceding element current and returns
1816 an iterator to the previously current element.
1820 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator+=(int j)
1822 Advances the iterator by \a j elements. If \a j is negative, the iterator goes backward.
1824 \sa operator-=(), operator+()
1828 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator-=(int j)
1830 Makes the iterator go back by \a j elements. If \a j is negative, the iterator goes forward.
1832 \sa operator+=(), operator-()
1836 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator+(int j) const
1838 Returns an iterator to the element at \a j positions forward from this iterator. If \a j
1839 is negative, the iterator goes backward.
1841 \sa operator-(), operator+=()
1845 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator-(int j) const
1847 Returns an iterator to the element at \a j positiosn backward from this iterator.
1848 If \a j is negative, the iterator goes forward.
1850 \sa operator+(), operator-=()
1854 \fn int QWebElementCollection::const_iterator::operator-(const_iterator other) const
1856 Returns the number of elements between the item point to by \a other
1857 and the element pointed to by this iterator.
1861 \fn bool QWebElementCollection::const_iterator::operator<(const const_iterator &other) const
1863 Returns true if the element pointed to by this iterator is less than the element pointed to
1864 by the \a other iterator.
1868 \fn bool QWebElementCollection::const_iterator::operator<=(const const_iterator &other) const
1870 Returns true if the element pointed to by this iterator is less than or equal to the
1871 element pointed to by the \a other iterator.
1875 \fn bool QWebElementCollection::const_iterator::operator>(const const_iterator &other) const
1877 Returns true if the element pointed to by this iterator is greater than the element pointed to
1878 by the \a other iterator.
1882 \fn bool QWebElementCollection::const_iterator::operator>=(const const_iterator &other) const
1884 Returns true if the element pointed to by this iterator is greater than or equal to the
1885 element pointed to by the \a other iterator.
1889 \fn QWebElementCollection::iterator QWebElementCollection::begin()
1891 Returns an STL-style iterator pointing to the first element in the collection.
1897 \fn QWebElementCollection::iterator QWebElementCollection::end()
1899 Returns an STL-style iterator pointing to the imaginary element after the
1900 last element in the list.
1906 \fn QWebElementCollection::const_iterator QWebElementCollection::constBegin() const
1908 Returns an STL-style iterator pointing to the first element in the collection.
1914 \fn QWebElementCollection::const_iterator QWebElementCollection::constEnd() const
1916 Returns an STL-style iterator pointing to the imaginary element after the
1917 last element in the list.
1923 \class QWebElementCollection::iterator
1925 \brief The QWebElementCollection::iterator class provides an STL-style iterator for QWebElementCollection.
1927 QWebElementCollection provides STL style iterators for fast low-level access to the elements.
1929 QWebElementCollection::iterator allows you to iterate over a QWebElementCollection.
1933 \fn QWebElementCollection::iterator::iterator(const iterator &other)
1935 Constructs a copy of \a other.
1939 \fn QWebElementCollection::iterator::iterator(const QWebElementCollection *collection, int index)
1944 \fn const QWebElement QWebElementCollection::iterator::operator*() const
1946 Returns the current element.
1950 \fn bool QWebElementCollection::iterator::operator==(const iterator &other) const
1952 Returns true if \a other points to the same item as this iterator;
1953 otherwise returns false.
1959 \fn bool QWebElementCollection::iterator::operator!=(const iterator &other) const
1961 Returns true if \a other points to a different element than this;
1962 iterator; otherwise returns false.
1968 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator++()
1970 The prefix ++ operator (\c{++it}) advances the iterator to the next element in the collection
1971 and returns an iterator to the new current element.
1973 Calling this function on QWebElementCollection::end() leads to undefined results.
1979 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator++(int)
1983 The postfix ++ operator (\c{it++}) advances the iterator to the next element in the collection
1984 and returns an iterator to the previously current element.
1986 Calling this function on QWebElementCollection::end() leads to undefined results.
1990 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator--()
1992 The prefix -- operator (\c{--it}) makes the preceding element current and returns an
1993 iterator to the new current element.
1995 Calling this function on QWebElementCollection::begin() leads to undefined results.
2001 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator--(int)
2005 The postfix -- operator (\c{it--}) makes the preceding element current and returns
2006 an iterator to the previously current element.
2010 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator+=(int j)
2012 Advances the iterator by \a j elements. If \a j is negative, the iterator goes backward.
2014 \sa operator-=(), operator+()
2018 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator-=(int j)
2020 Makes the iterator go back by \a j elements. If \a j is negative, the iterator goes forward.
2022 \sa operator+=(), operator-()
2026 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator+(int j) const
2028 Returns an iterator to the element at \a j positions forward from this iterator. If \a j
2029 is negative, the iterator goes backward.
2031 \sa operator-(), operator+=()
2035 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator-(int j) const
2037 Returns an iterator to the element at \a j positiosn backward from this iterator.
2038 If \a j is negative, the iterator goes forward.
2040 \sa operator+(), operator-=()
2044 \fn int QWebElementCollection::iterator::operator-(iterator other) const
2046 Returns the number of elements between the item point to by \a other
2047 and the element pointed to by this iterator.
2051 \fn bool QWebElementCollection::iterator::operator<(const iterator &other) const
2053 Returns true if the element pointed to by this iterator is less than the element pointed to
2054 by the \a other iterator.
2058 \fn bool QWebElementCollection::iterator::operator<=(const iterator &other) const
2060 Returns true if the element pointed to by this iterator is less than or equal to the
2061 element pointed to by the \a other iterator.
2065 \fn bool QWebElementCollection::iterator::operator>(const iterator &other) const
2067 Returns true if the element pointed to by this iterator is greater than the element pointed to
2068 by the \a other iterator.
2072 \fn bool QWebElementCollection::iterator::operator>=(const iterator &other) const
2074 Returns true if the element pointed to by this iterator is greater than or equal to the
2075 element pointed to by the \a other iterator.
2079 QWebElement QtWebElementRuntime::create(Element* element)
2081 return QWebElement(element);
2084 Element* QtWebElementRuntime::get(const QWebElement& element)
2086 return element.m_element;
2089 static QVariant convertJSValueToWebElementVariant(JSC::JSObject* object, int *distance, HashSet<JSC::JSObject*>* visitedObjects)
2091 Element* element = 0;
2093 if (object && object->inherits(&JSElement::s_info)) {
2094 element =(static_cast<JSElement*>(object))->impl();
2096 // Allow other objects to reach this one. This won't cause our algorithm to
2097 // loop since when we find an Element we do not recurse.
2098 visitedObjects->remove(object);
2099 } else if (object && object->inherits(&JSDocument::s_info)) {
2100 // To support LayoutTestControllerQt::nodesFromRect(), used in DRT, we do an implicit
2101 // conversion from 'document' to the QWebElement representing the 'document.documentElement'.
2102 // We can't simply use a QVariantMap in nodesFromRect() because it currently times out
2103 // when serializing DOMMimeType and DOMPlugin, even if we limit the recursion.
2104 element =(static_cast<JSDocument*>(object))->impl()->documentElement();
2107 return QVariant::fromValue<QWebElement>(QtWebElementRuntime::create(element));
2110 static JSC::JSValue convertWebElementVariantToJSValue(JSC::ExecState* exec, WebCore::JSDOMGlobalObject* globalObject, const QVariant& variant)
2112 return WebCore::toJS(exec, globalObject, QtWebElementRuntime::get(variant.value<QWebElement>()));
2116 void QtWebElementRuntime::initialize()
2118 static bool initialized = false;
2123 int id = qRegisterMetaType<QWebElement>();
2124 JSC::Bindings::registerCustomType(id, convertJSValueToWebElementVariant, convertWebElementVariantToJSValue);