PassRefPtr<DOMStringList> HTMLPropertiesCollection::names() const { m_properties.clear(); m_propertyNames->clear(); if (!base()->isHTMLElement() || !toHTMLElement(base())->fastHasAttribute(itemscopeAttr)) return m_propertyNames; findPropetiesOfAnItem(base()); std::sort(m_properties.begin(), m_properties.end(), compareTreeOrder); for (size_t i = 0; i < m_properties.size(); ++i) { // For each item properties, split the value of that itemprop attribute on spaces. // Add all tokens to property names, with the order preserved but with duplicates removed. DOMSettableTokenList* itemProperty = m_properties[i]->itemProp(); for (size_t i = 0; i < itemProperty->length(); ++i) { AtomicString propertyName = itemProperty->item(i); if (m_propertyNames->isEmpty() || !m_propertyNames->contains(propertyName)) m_propertyNames->append(propertyName); } } return m_propertyNames; }
void HTMLPropertiesCollection::findPropetiesOfAnItem(Node* root) const { // 5.2.5 Associating names with items. Vector<Node*> memory; memory.append(root); Vector<Node*> pending; // Add the child elements of root, if any, to pending. for (Node* child = root->firstChild(); child; child = child->nextSibling()) if (child->isHTMLElement()) pending.append(child); // If root has an itemref attribute, split the value of that itemref attribute on spaces. // For each resulting token ID, if there is an element in the home subtree of root with the ID ID, // then add the first such element to pending. if (toHTMLElement(root)->fastHasAttribute(itemrefAttr)) { DOMSettableTokenList* itemRef = root->itemRef(); for (size_t i = 0; i < itemRef->length(); ++i) { AtomicString id = itemRef->item(i); Element* element = root->document()->getElementById(id); if (element && element->isHTMLElement()) pending.append(element); } } // Loop till we have processed all pending elements while (!pending.isEmpty()) { // Remove first element from pending and let current be that element. Node* current = pending[0]; pending.remove(0); // If current is already in memory, there is a microdata error; if (memory.contains(current)) { // microdata error; continue; } memory.append(current); // If current does not have an itemscope attribute, then: add all the child elements of current to pending. HTMLElement* element = toHTMLElement(current); if (!element->fastHasAttribute(itemscopeAttr)) { for (Node* child = current->firstChild(); child; child = child->nextSibling()) if (child->isHTMLElement()) pending.append(child); } // If current has an itemprop attribute specified, add it to results. if (element->fastHasAttribute(itempropAttr)) m_properties.append(current); } }
void HTMLPropertiesCollection::updateNameCache() const { if (hasNameCache()) return; updateRefElements(); for (unsigned i = 0; i < m_itemRefElements.size(); ++i) { HTMLElement* refElement = m_itemRefElements[i]; for (HTMLElement* element = virtualItemAfter(refElement, 0); element; element = virtualItemAfter(refElement, element)) { DOMSettableTokenList* itemProperty = element->itemProp(); for (unsigned propertyIndex = 0; propertyIndex < itemProperty->length(); ++propertyIndex) updatePropertyCache(element, itemProperty->item(propertyIndex)); } } setHasNameCache(); }