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/v8/ExceptionMessages.h"
     26 #include "bindings/v8/ExceptionState.h"
     27 #include "core/dom/ExceptionCode.h"
     28 #include "core/dom/NamedNodesCollection.h"
     29 #include "core/html/HTMLOptionElement.h"
     30 #include "core/html/HTMLSelectElement.h"
     31 
     32 namespace WebCore {
     33 
     34 HTMLOptionsCollection::HTMLOptionsCollection(ContainerNode& select)
     35     : HTMLCollection(select, SelectOptions, DoesNotOverrideItemAfter)
     36 {
     37     ASSERT(isHTMLSelectElement(select));
     38     ScriptWrappable::init(this);
     39 }
     40 
     41 void HTMLOptionsCollection::supportedPropertyNames(Vector<String>& names)
     42 {
     43     // As per http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#htmloptionscollection:
     44     // The supported property names consist of the non-empty values of all the id and name attributes of all the elements
     45     // represented by the collection, in tree order, ignoring later duplicates, with the id of an element preceding its
     46     // name if it contributes both, they differ from each other, and neither is the duplicate of an earlier entry.
     47     HashSet<AtomicString> existingNames;
     48     unsigned length = this->length();
     49     for (unsigned i = 0; i < length; ++i) {
     50         Element* element = item(i);
     51         ASSERT(element);
     52         const AtomicString& idAttribute = element->getIdAttribute();
     53         if (!idAttribute.isEmpty()) {
     54             HashSet<AtomicString>::AddResult addResult = existingNames.add(idAttribute);
     55             if (addResult.isNewEntry)
     56                 names.append(idAttribute);
     57         }
     58         const AtomicString& nameAttribute = element->getNameAttribute();
     59         if (!nameAttribute.isEmpty()) {
     60             HashSet<AtomicString>::AddResult addResult = existingNames.add(nameAttribute);
     61             if (addResult.isNewEntry)
     62                 names.append(nameAttribute);
     63         }
     64     }
     65 }
     66 
     67 PassRefPtrWillBeRawPtr<HTMLOptionsCollection> HTMLOptionsCollection::create(ContainerNode& select, CollectionType)
     68 {
     69     return adoptRefWillBeNoop(new HTMLOptionsCollection(select));
     70 }
     71 
     72 void HTMLOptionsCollection::add(PassRefPtrWillBeRawPtr<HTMLOptionElement> element, ExceptionState& exceptionState)
     73 {
     74     add(element, length(), exceptionState);
     75 }
     76 
     77 void HTMLOptionsCollection::add(PassRefPtrWillBeRawPtr<HTMLOptionElement> element, int index, ExceptionState& exceptionState)
     78 {
     79     HTMLOptionElement* newOption = element.get();
     80 
     81     if (!newOption) {
     82         exceptionState.throwTypeError("The element provided was not an HTMLOptionElement.");
     83         return;
     84     }
     85 
     86     if (index < -1) {
     87         exceptionState.throwDOMException(IndexSizeError, "The index provided (" + String::number(index) + ") is less than -1.");
     88         return;
     89     }
     90 
     91     HTMLSelectElement& select = toHTMLSelectElement(ownerNode());
     92 
     93     if (index == -1 || unsigned(index) >= length())
     94         select.add(newOption, 0, exceptionState);
     95     else
     96         select.addBeforeOptionAtIndex(newOption, index, exceptionState);
     97 
     98     ASSERT(!exceptionState.hadException());
     99 }
    100 
    101 void HTMLOptionsCollection::remove(int index)
    102 {
    103     toHTMLSelectElement(ownerNode()).remove(index);
    104 }
    105 
    106 void HTMLOptionsCollection::remove(HTMLOptionElement* option)
    107 {
    108     return remove(option->index());
    109 }
    110 
    111 int HTMLOptionsCollection::selectedIndex() const
    112 {
    113     return toHTMLSelectElement(ownerNode()).selectedIndex();
    114 }
    115 
    116 void HTMLOptionsCollection::setSelectedIndex(int index)
    117 {
    118     toHTMLSelectElement(ownerNode()).setSelectedIndex(index);
    119 }
    120 
    121 void HTMLOptionsCollection::setLength(unsigned length, ExceptionState& exceptionState)
    122 {
    123     toHTMLSelectElement(ownerNode()).setLength(length, exceptionState);
    124 }
    125 
    126 void HTMLOptionsCollection::namedGetter(const AtomicString& name, bool& returnValue0Enabled, RefPtrWillBeRawPtr<NodeList>& returnValue0, bool& returnValue1Enabled, RefPtrWillBeRawPtr<Element>& returnValue1)
    127 {
    128     WillBeHeapVector<RefPtrWillBeMember<Element> > namedItems;
    129     this->namedItems(name, namedItems);
    130 
    131     if (!namedItems.size())
    132         return;
    133 
    134     if (namedItems.size() == 1) {
    135         returnValue1Enabled = true;
    136         returnValue1 = namedItems.at(0);
    137         return;
    138     }
    139 
    140     // FIXME: The spec and Firefox do not return a NodeList. They always return the first matching Element.
    141     returnValue0Enabled = true;
    142     returnValue0 = NamedNodesCollection::create(namedItems);
    143 }
    144 
    145 bool HTMLOptionsCollection::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeRawPtr<HTMLOptionElement> value, ExceptionState& exceptionState)
    146 {
    147     HTMLSelectElement& base = toHTMLSelectElement(ownerNode());
    148     if (!value) { // undefined or null
    149         base.remove(index);
    150         return true;
    151     }
    152     base.setOption(index, value.get(), exceptionState);
    153     return true;
    154 }
    155 
    156 } //namespace
    157 
    158