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