2 * Copyright (c) 2011 Motorola Mobility, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
14 * Neither the name of Motorola Mobility, Inc. nor the names of its contributors may
15 * be used to endorse or promote products derived from this software without
16 * specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "HTMLPropertiesCollection.h"
37 #include "DOMSettableTokenList.h"
38 #include "DOMStringList.h"
39 #include "HTMLElement.h"
40 #include "HTMLNames.h"
42 #include "StaticNodeList.h"
46 using namespace HTMLNames;
48 PassRefPtr<HTMLPropertiesCollection> HTMLPropertiesCollection::create(Node* itemNode)
50 return adoptRef(new HTMLPropertiesCollection(itemNode));
53 HTMLPropertiesCollection::HTMLPropertiesCollection(Node* itemNode)
54 : HTMLCollection(itemNode, ItemProperties, DoNotSupportItemBefore)
55 , m_hasPropertyNameCache(false)
56 , m_hasItemRefElements(false)
60 HTMLPropertiesCollection::~HTMLPropertiesCollection()
64 void HTMLPropertiesCollection::updateRefElements() const
66 if (m_hasItemRefElements)
69 HTMLElement* baseElement = toHTMLElement(base());
71 m_itemRefElements.clear();
72 m_hasItemRefElements = true;
74 if (!baseElement->fastHasAttribute(itemscopeAttr))
77 if (!baseElement->fastHasAttribute(itemrefAttr)) {
78 m_itemRefElements.append(baseElement);
82 DOMSettableTokenList* itemRef = baseElement->itemRef();
83 RefPtr<DOMSettableTokenList> processedItemRef = DOMSettableTokenList::create();
84 Node* rootNode = baseElement->treeScope()->rootNode();
86 for (Node* current = rootNode->firstChild(); current; current = current->traverseNextNode(rootNode)) {
87 if (!current->isHTMLElement())
89 HTMLElement* element = toHTMLElement(current);
91 if (element == baseElement) {
92 m_itemRefElements.append(element);
96 const AtomicString& id = element->getIdAttribute();
97 if (!processedItemRef->tokens().contains(id) && itemRef->tokens().contains(id)) {
98 processedItemRef->setValue(id);
99 if (!element->isDescendantOf(baseElement))
100 m_itemRefElements.append(element);
105 static Node* nextNodeWithProperty(Node* base, Node* node)
107 // An Microdata item may contain properties which in turn are items themselves. Properties can
108 // also themselves be groups of name-value pairs, by putting the itemscope attribute on the element
109 // that declares the property. If the property has an itemscope attribute specified then we need
110 // to traverse the next sibling.
111 return node == base || (node->isHTMLElement() && !toHTMLElement(node)->fastHasAttribute(itemscopeAttr))
112 ? node->traverseNextNode(base) : node->traverseNextSibling(base);
115 Element* HTMLPropertiesCollection::itemAfter(unsigned& offsetInArray, Element* previousItem) const
117 while (offsetInArray < m_itemRefElements.size()) {
118 if (Element* next = itemAfter(m_itemRefElements[offsetInArray], previousItem))
126 HTMLElement* HTMLPropertiesCollection::itemAfter(HTMLElement* base, Element* previous) const
129 current = previous ? nextNodeWithProperty(base, previous) : base;
131 for (; current; current = nextNodeWithProperty(base, current)) {
132 if (!current->isHTMLElement())
134 HTMLElement* element = toHTMLElement(current);
135 if (element->fastHasAttribute(itempropAttr) && element->itemProp()->length()) {
143 void HTMLPropertiesCollection::updateNameCache() const
145 if (m_hasPropertyNameCache)
150 for (unsigned i = 0; i < m_itemRefElements.size(); ++i) {
151 HTMLElement* refElement = m_itemRefElements[i];
152 for (HTMLElement* element = itemAfter(refElement, 0); element; element = itemAfter(refElement, element)) {
153 DOMSettableTokenList* itemProperty = element->itemProp();
154 for (unsigned propertyIndex = 0; propertyIndex < itemProperty->length(); ++propertyIndex)
155 updatePropertyCache(element, itemProperty->item(propertyIndex));
159 m_hasPropertyNameCache = true;
162 PassRefPtr<DOMStringList> HTMLPropertiesCollection::names() const
165 if (!m_propertyNames)
166 m_propertyNames = DOMStringList::create();
167 return m_propertyNames;
170 PassRefPtr<NodeList> HTMLPropertiesCollection::namedItem(const String& name) const
174 Vector<RefPtr<Node> > namedItems;
175 Vector<Element*>* propertyResults = m_propertyCache.get(AtomicString(name).impl());
176 for (unsigned i = 0; propertyResults && i < propertyResults->size(); ++i)
177 namedItems.append(propertyResults->at(i));
179 // FIXME: HTML5 specifies that this should return PropertyNodeList.
180 return namedItems.isEmpty() ? 0 : StaticNodeList::adopt(namedItems);
183 bool HTMLPropertiesCollection::hasNamedItem(const AtomicString& name) const
187 if (Vector<Element*>* propertyCache = m_propertyCache.get(name.impl())) {
188 if (!propertyCache->isEmpty())
195 } // namespace WebCore
197 #endif // ENABLE(MICRODATA)