Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2006, 2011, 2012 Apple Computer, Inc.
      3  * Copyright (C) 2014 Samsung Electronics. All rights reserved.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  *
     20  */
     21 
     22 #include "config.h"
     23 #include "core/html/HTMLOptionsCollection.h"
     24 
     25 #include "bindings/core/v8/ExceptionMessages.h"
     26 #include "bindings/core/v8/ExceptionState.h"
     27 #include "core/dom/ExceptionCode.h"
     28 #include "core/dom/StaticNodeList.h"
     29 #include "core/html/HTMLOptionElement.h"
     30 #include "core/html/HTMLSelectElement.h"
     31 
     32 namespace blink {
     33 
     34 HTMLOptionsCollection::HTMLOptionsCollection(ContainerNode& select)
     35     : HTMLCollection(select, SelectOptions, DoesNotOverrideItemAfter)
     36 {
     37     ASSERT(isHTMLSelectElement(select));
     38 }
     39 
     40 void HTMLOptionsCollection::supportedPropertyNames(Vector<String>& names)
     41 {
     42     // As per http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#htmloptionscollection:
     43     // The supported property names consist of the non-empty values of all the id and name attributes of all the elements
     44     // represented by the collection, in tree order, ignoring later duplicates, with the id of an element preceding its
     45     // name if it contributes both, they differ from each other, and neither is the duplicate of an earlier entry.
     46     HashSet<AtomicString> existingNames;
     47     unsigned length = this->length();
     48     for (unsigned i = 0; i < length; ++i) {
     49         Element* element = item(i);
     50         ASSERT(element);
     51         const AtomicString& idAttribute = element->getIdAttribute();
     52         if (!idAttribute.isEmpty()) {
     53             HashSet<AtomicString>::AddResult addResult = existingNames.add(idAttribute);
     54             if (addResult.isNewEntry)
     55                 names.append(idAttribute);
     56         }
     57         const AtomicString& nameAttribute = element->getNameAttribute();
     58         if (!nameAttribute.isEmpty()) {
     59             HashSet<AtomicString>::AddResult addResult = existingNames.add(nameAttribute);
     60             if (addResult.isNewEntry)
     61                 names.append(nameAttribute);
     62         }
     63     }
     64 }
     65 
     66 PassRefPtrWillBeRawPtr<HTMLOptionsCollection> HTMLOptionsCollection::create(ContainerNode& select, CollectionType)
     67 {
     68     return adoptRefWillBeNoop(new HTMLOptionsCollection(select));
     69 }
     70 
     71 void HTMLOptionsCollection::add(PassRefPtrWillBeRawPtr<HTMLOptionElement> element, ExceptionState& exceptionState)
     72 {
     73     add(element, length(), exceptionState);
     74 }
     75 
     76 void HTMLOptionsCollection::add(PassRefPtrWillBeRawPtr<HTMLOptionElement> element, int index, ExceptionState& exceptionState)
     77 {
     78     HTMLOptionElement* newOption = element.get();
     79 
     80     if (!newOption) {
     81         exceptionState.throwTypeError("The element provided was not an HTMLOptionElement.");
     82         return;
     83     }
     84 
     85     if (index < -1) {
     86         exceptionState.throwDOMException(IndexSizeError, "The index provided (" + String::number(index) + ") is less than -1.");
     87         return;
     88     }
     89 
     90     HTMLSelectElement& select = toHTMLSelectElement(ownerNode());
     91 
     92     if (index == -1 || unsigned(index) >= length())
     93         select.add(newOption, 0, exceptionState);
     94     else
     95         select.addBeforeOptionAtIndex(newOption, index, exceptionState);
     96 
     97     ASSERT(!exceptionState.hadException());
     98 }
     99 
    100 void HTMLOptionsCollection::remove(int index)
    101 {
    102     toHTMLSelectElement(ownerNode()).remove(index);
    103 }
    104 
    105 int HTMLOptionsCollection::selectedIndex() const
    106 {
    107     return toHTMLSelectElement(ownerNode()).selectedIndex();
    108 }
    109 
    110 void HTMLOptionsCollection::setSelectedIndex(int index)
    111 {
    112     toHTMLSelectElement(ownerNode()).setSelectedIndex(index);
    113 }
    114 
    115 void HTMLOptionsCollection::setLength(unsigned length, ExceptionState& exceptionState)
    116 {
    117     toHTMLSelectElement(ownerNode()).setLength(length, exceptionState);
    118 }
    119 
    120 void HTMLOptionsCollection::namedGetter(const AtomicString& name, RefPtrWillBeRawPtr<NodeList>& returnValue0, RefPtrWillBeRawPtr<Element>& returnValue1)
    121 {
    122     WillBeHeapVector<RefPtrWillBeMember<Element> > namedItems;
    123     this->namedItems(name, namedItems);
    124 
    125     if (!namedItems.size())
    126         return;
    127 
    128     if (namedItems.size() == 1) {
    129         returnValue1 = namedItems.at(0);
    130         return;
    131     }
    132 
    133     // FIXME: The spec and Firefox do not return a NodeList. They always return the first matching Element.
    134     returnValue0 = StaticElementList::adopt(namedItems);
    135 }
    136 
    137 bool HTMLOptionsCollection::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeRawPtr<HTMLOptionElement> value, ExceptionState& exceptionState)
    138 {
    139     HTMLSelectElement& base = toHTMLSelectElement(ownerNode());
    140     if (!value) { // undefined or null
    141         base.remove(index);
    142         return true;
    143     }
    144     base.setOption(index, value.get(), exceptionState);
    145     return true;
    146 }
    147 
    148 } //namespace
    149 
    150