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-2016 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 "ElementAncestorIterator.h"
30#include "HTMLNames.h"
31#include "HTMLSelectElement.h"
32#include "RenderMenuList.h"
33#include "NodeRenderStyle.h"
34#include "StyleResolver.h"
35#include <wtf/IsoMallocInlines.h>
36#include <wtf/StdLibExtras.h>
37
38namespace WebCore {
39
40WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLOptGroupElement);
41
42using namespace HTMLNames;
43
44inline HTMLOptGroupElement::HTMLOptGroupElement(const QualifiedName& tagName, Document& document)
45 : HTMLElement(tagName, document)
46{
47 ASSERT(hasTagName(optgroupTag));
48}
49
50Ref<HTMLOptGroupElement> HTMLOptGroupElement::create(const QualifiedName& tagName, Document& document)
51{
52 return adoptRef(*new HTMLOptGroupElement(tagName, document));
53}
54
55bool HTMLOptGroupElement::isDisabledFormControl() const
56{
57 return hasAttributeWithoutSynchronization(disabledAttr);
58}
59
60bool HTMLOptGroupElement::isFocusable() const
61{
62 if (!supportsFocus())
63 return false;
64 // Optgroup elements do not have a renderer.
65 auto* style = const_cast<HTMLOptGroupElement&>(*this).computedStyle();
66 return style && style->display() != DisplayType::None;
67}
68
69const AtomicString& HTMLOptGroupElement::formControlType() const
70{
71 static NeverDestroyed<const AtomicString> optgroup("optgroup", AtomicString::ConstructFromLiteral);
72 return optgroup;
73}
74
75void HTMLOptGroupElement::childrenChanged(const ChildChange& change)
76{
77 recalcSelectOptions();
78 HTMLElement::childrenChanged(change);
79}
80
81void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
82{
83 HTMLElement::parseAttribute(name, value);
84 recalcSelectOptions();
85
86 if (name == disabledAttr)
87 invalidateStyleForSubtree();
88}
89
90void HTMLOptGroupElement::recalcSelectOptions()
91{
92 if (auto selectElement = makeRefPtr(ancestorsOfType<HTMLSelectElement>(*this).first())) {
93 selectElement->setRecalcListItems();
94 selectElement->updateValidity();
95 }
96}
97
98String HTMLOptGroupElement::groupLabelText() const
99{
100 String itemText = document().displayStringModifiedByEncoding(attributeWithoutSynchronization(labelAttr));
101
102 // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior.
103 itemText = itemText.stripWhiteSpace();
104 // We want to collapse our whitespace too. This will match other browsers.
105 itemText = itemText.simplifyWhiteSpace();
106
107 return itemText;
108}
109
110HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const
111{
112 RefPtr<ContainerNode> select = parentNode();
113 while (select && !is<HTMLSelectElement>(*select))
114 select = select->parentNode();
115
116 if (!select)
117 return nullptr;
118
119 return downcast<HTMLSelectElement>(select.get());
120}
121
122void HTMLOptGroupElement::accessKeyAction(bool)
123{
124 RefPtr<HTMLSelectElement> select = ownerSelectElement();
125 // send to the parent to bring focus to the list box
126 if (select && !select->focused())
127 select->accessKeyAction(false);
128}
129
130} // namespace
131