1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 * 23 */ 24 25#include "config.h" 26#include "HTMLOptionElement.h" 27 28#include "CSSStyleSelector.h" 29#include "Document.h" 30#include "ExceptionCode.h" 31#include "HTMLNames.h" 32#include "HTMLSelectElement.h" 33#include "MappedAttribute.h" 34#include "NodeRenderStyle.h" 35#include "RenderMenuList.h" 36#include "Text.h" 37#include <wtf/StdLibExtras.h> 38#include <wtf/Vector.h> 39 40namespace WebCore { 41 42using namespace HTMLNames; 43 44HTMLOptionElement::HTMLOptionElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) 45 : HTMLFormControlElement(tagName, doc, f) 46 , m_style(0) 47{ 48 ASSERT(hasTagName(optionTag)); 49} 50 51bool HTMLOptionElement::checkDTD(const Node* newChild) 52{ 53 return newChild->isTextNode() || newChild->hasTagName(scriptTag); 54} 55 56void HTMLOptionElement::attach() 57{ 58 if (parentNode()->renderStyle()) 59 setRenderStyle(styleForRenderer()); 60 HTMLFormControlElement::attach(); 61} 62 63void HTMLOptionElement::detach() 64{ 65 m_style.clear(); 66 HTMLFormControlElement::detach(); 67} 68 69bool HTMLOptionElement::supportsFocus() const 70{ 71 return HTMLElement::supportsFocus(); 72} 73 74bool HTMLOptionElement::isFocusable() const 75{ 76 // Option elements do not have a renderer so we check the renderStyle instead. 77 return supportsFocus() && renderStyle() && renderStyle()->display() != NONE; 78} 79 80const AtomicString& HTMLOptionElement::formControlType() const 81{ 82 DEFINE_STATIC_LOCAL(const AtomicString, option, ("option")); 83 return option; 84} 85 86String HTMLOptionElement::text() const 87{ 88 return OptionElement::collectOptionLabelOrText(m_data, this); 89} 90 91void HTMLOptionElement::setText(const String &text, ExceptionCode& ec) 92{ 93 // Handle the common special case where there's exactly 1 child node, and it's a text node. 94 Node* child = firstChild(); 95 if (child && child->isTextNode() && !child->nextSibling()) { 96 static_cast<Text *>(child)->setData(text, ec); 97 return; 98 } 99 100 removeChildren(); 101 appendChild(Text::create(document(), text), ec); 102} 103 104void HTMLOptionElement::accessKeyAction(bool) 105{ 106 HTMLSelectElement* select = ownerSelectElement(); 107 if (select) 108 select->accessKeySetSelectedIndex(index()); 109} 110 111int HTMLOptionElement::index() const 112{ 113 return OptionElement::optionIndex(ownerSelectElement(), this); 114} 115 116void HTMLOptionElement::parseMappedAttribute(MappedAttribute *attr) 117{ 118 if (attr->name() == selectedAttr) 119 m_data.setSelected(!attr->isNull()); 120 else if (attr->name() == valueAttr) 121 m_data.setValue(attr->value()); 122 else if (attr->name() == labelAttr) 123 m_data.setLabel(attr->value()); 124 else 125 HTMLFormControlElement::parseMappedAttribute(attr); 126} 127 128String HTMLOptionElement::value() const 129{ 130 return OptionElement::collectOptionValue(m_data, this); 131} 132 133void HTMLOptionElement::setValue(const String& value) 134{ 135 setAttribute(valueAttr, value); 136} 137 138bool HTMLOptionElement::selected() const 139{ 140 if (HTMLSelectElement* select = ownerSelectElement()) 141 select->recalcListItemsIfNeeded(); 142 return m_data.selected(); 143} 144 145void HTMLOptionElement::setSelected(bool selected) 146{ 147 if (m_data.selected() == selected) 148 return; 149 150 OptionElement::setSelectedState(m_data, this, selected); 151 152 if (HTMLSelectElement* select = ownerSelectElement()) 153 select->setSelectedIndex(selected ? index() : -1, false); 154} 155 156void HTMLOptionElement::setSelectedState(bool selected) 157{ 158 OptionElement::setSelectedState(m_data, this, selected); 159} 160 161void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 162{ 163 HTMLSelectElement* select = ownerSelectElement(); 164 if (select) 165 select->childrenChanged(changedByParser); 166 HTMLFormControlElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 167} 168 169HTMLSelectElement* HTMLOptionElement::ownerSelectElement() const 170{ 171 Node* select = parentNode(); 172#ifdef ANDROID_FIX 173 while (select && !(select->hasTagName(selectTag) || select->hasTagName(keygenTag))) 174#else 175 while (select && !select->hasTagName(selectTag)) 176#endif 177 select = select->parentNode(); 178 179 if (!select) 180 return 0; 181 182 return static_cast<HTMLSelectElement*>(select); 183} 184 185bool HTMLOptionElement::defaultSelected() const 186{ 187 return !getAttribute(selectedAttr).isNull(); 188} 189 190void HTMLOptionElement::setDefaultSelected(bool b) 191{ 192 setAttribute(selectedAttr, b ? "" : 0); 193} 194 195String HTMLOptionElement::label() const 196{ 197 return m_data.label(); 198} 199 200void HTMLOptionElement::setLabel(const String& value) 201{ 202 setAttribute(labelAttr, value); 203} 204 205void HTMLOptionElement::setRenderStyle(PassRefPtr<RenderStyle> newStyle) 206{ 207 m_style = newStyle; 208} 209 210RenderStyle* HTMLOptionElement::nonRendererRenderStyle() const 211{ 212 return m_style.get(); 213} 214 215String HTMLOptionElement::textIndentedToRespectGroupLabel() const 216{ 217 return OptionElement::collectOptionTextRespectingGroupLabel(m_data, this); 218} 219 220bool HTMLOptionElement::disabled() const 221{ 222 return ownElementDisabled() || (parentNode() && static_cast<HTMLFormControlElement*>(parentNode())->disabled()); 223} 224 225void HTMLOptionElement::insertedIntoTree(bool deep) 226{ 227 if (HTMLSelectElement* select = ownerSelectElement()) { 228 select->setRecalcListItems(); 229 // Avoid our selected() getter since it will recalculate list items incorrectly for us. 230 if (m_data.selected()) 231 select->setSelectedIndex(index(), false); 232 select->scrollToSelection(); 233 } 234 235 HTMLFormControlElement::insertedIntoTree(deep); 236} 237 238} // namespace 239