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