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