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, 2007, 2008, 2010 Apple Inc. All rights reserved.
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 "HTMLOptGroupElement.h"
27
28#include "Document.h"
29#include "HTMLNames.h"
30#include "HTMLSelectElement.h"
31#include "RenderMenuList.h"
32#include "NodeRenderStyle.h"
33#include "StyleResolver.h"
34#include <wtf/StdLibExtras.h>
35
36namespace WebCore {
37
38using namespace HTMLNames;
39
40inline HTMLOptGroupElement::HTMLOptGroupElement(const QualifiedName& tagName, Document& document)
41    : HTMLElement(tagName, document)
42{
43    ASSERT(hasTagName(optgroupTag));
44    setHasCustomStyleResolveCallbacks();
45}
46
47PassRefPtr<HTMLOptGroupElement> HTMLOptGroupElement::create(const QualifiedName& tagName, Document& document)
48{
49    return adoptRef(new HTMLOptGroupElement(tagName, document));
50}
51
52bool HTMLOptGroupElement::isDisabledFormControl() const
53{
54    return fastHasAttribute(disabledAttr);
55}
56
57bool HTMLOptGroupElement::isFocusable() const
58{
59    // Optgroup elements do not have a renderer so we check the renderStyle instead.
60    return supportsFocus() && renderStyle() && renderStyle()->display() != NONE;
61}
62
63const AtomicString& HTMLOptGroupElement::formControlType() const
64{
65    DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, optgroup, ("optgroup", AtomicString::ConstructFromLiteral));
66    return optgroup;
67}
68
69void HTMLOptGroupElement::childrenChanged(const ChildChange& change)
70{
71    recalcSelectOptions();
72    HTMLElement::childrenChanged(change);
73}
74
75void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
76{
77    HTMLElement::parseAttribute(name, value);
78    recalcSelectOptions();
79
80    if (name == disabledAttr)
81        didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled);
82}
83
84void HTMLOptGroupElement::recalcSelectOptions()
85{
86    ContainerNode* select = parentNode();
87    while (select && !select->hasTagName(selectTag))
88        select = select->parentNode();
89    if (select)
90        toHTMLSelectElement(select)->setRecalcListItems();
91}
92
93void HTMLOptGroupElement::didAttachRenderers()
94{
95    // If after attaching nothing called styleForRenderer() on this node we
96    // manually cache the value. This happens if our parent doesn't have a
97    // renderer like <optgroup> or if it doesn't allow children like <select>.
98    if (!m_style && parentNode()->renderStyle())
99        updateNonRenderStyle(*parentNode()->renderStyle());
100}
101
102void HTMLOptGroupElement::willDetachRenderers()
103{
104    m_style.clear();
105}
106
107void HTMLOptGroupElement::updateNonRenderStyle(RenderStyle& parentStyle)
108{
109    m_style = document().ensureStyleResolver().styleForElement(this, &parentStyle);
110}
111
112RenderStyle* HTMLOptGroupElement::nonRendererStyle() const
113{
114    return m_style.get();
115}
116
117PassRefPtr<RenderStyle> HTMLOptGroupElement::customStyleForRenderer(RenderStyle& parentStyle)
118{
119    // styleForRenderer is called whenever a new style should be associated
120    // with an Element so now is a good time to update our cached style.
121    updateNonRenderStyle(parentStyle);
122    return m_style;
123}
124
125String HTMLOptGroupElement::groupLabelText() const
126{
127    String itemText = document().displayStringModifiedByEncoding(getAttribute(labelAttr));
128
129    // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior.
130    itemText = itemText.stripWhiteSpace();
131    // We want to collapse our whitespace too.  This will match other browsers.
132    itemText = itemText.simplifyWhiteSpace();
133
134    return itemText;
135}
136
137HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const
138{
139    ContainerNode* select = parentNode();
140    while (select && !select->hasTagName(selectTag))
141        select = select->parentNode();
142
143    if (!select)
144       return 0;
145
146    return toHTMLSelectElement(select);
147}
148
149void HTMLOptGroupElement::accessKeyAction(bool)
150{
151    HTMLSelectElement* select = ownerSelectElement();
152    // send to the parent to bring focus to the list box
153    if (select && !select->focused())
154        select->accessKeyAction(false);
155}
156
157} // namespace
158