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