1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. 6 * (C) 2006 Alexey Proskuryakov (ap (at) 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 "core/html/HTMLOptGroupElement.h" 27 28 #include "core/HTMLNames.h" 29 #include "core/dom/NodeRenderStyle.h" 30 #include "core/dom/Text.h" 31 #include "core/editing/htmlediting.h" 32 #include "core/html/HTMLContentElement.h" 33 #include "core/html/HTMLDivElement.h" 34 #include "core/html/HTMLSelectElement.h" 35 #include "core/html/shadow/ShadowElementNames.h" 36 #include "wtf/StdLibExtras.h" 37 #include "wtf/unicode/CharacterNames.h" 38 39 namespace blink { 40 41 using namespace HTMLNames; 42 43 inline HTMLOptGroupElement::HTMLOptGroupElement(Document& document) 44 : HTMLElement(optgroupTag, document) 45 { 46 setHasCustomStyleCallbacks(); 47 } 48 49 PassRefPtrWillBeRawPtr<HTMLOptGroupElement> HTMLOptGroupElement::create(Document& document) 50 { 51 RefPtrWillBeRawPtr<HTMLOptGroupElement> optGroupElement = adoptRefWillBeNoop(new HTMLOptGroupElement(document)); 52 optGroupElement->ensureUserAgentShadowRoot(); 53 return optGroupElement.release(); 54 } 55 56 bool HTMLOptGroupElement::isDisabledFormControl() const 57 { 58 return fastHasAttribute(disabledAttr); 59 } 60 61 void HTMLOptGroupElement::childrenChanged(const ChildrenChange& change) 62 { 63 recalcSelectOptions(); 64 HTMLElement::childrenChanged(change); 65 } 66 67 void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 68 { 69 HTMLElement::parseAttribute(name, value); 70 recalcSelectOptions(); 71 72 if (name == disabledAttr) { 73 pseudoStateChanged(CSSSelector::PseudoDisabled); 74 pseudoStateChanged(CSSSelector::PseudoEnabled); 75 } else if (name == labelAttr) { 76 updateGroupLabel(); 77 } 78 } 79 80 void HTMLOptGroupElement::recalcSelectOptions() 81 { 82 if (HTMLSelectElement* select = Traversal<HTMLSelectElement>::firstAncestor(*this)) 83 select->setRecalcListItems(); 84 } 85 86 void HTMLOptGroupElement::attach(const AttachContext& context) 87 { 88 if (context.resolvedStyle) { 89 ASSERT(!m_style || m_style == context.resolvedStyle); 90 m_style = context.resolvedStyle; 91 } 92 HTMLElement::attach(context); 93 } 94 95 void HTMLOptGroupElement::detach(const AttachContext& context) 96 { 97 m_style.clear(); 98 HTMLElement::detach(context); 99 } 100 101 void HTMLOptGroupElement::updateNonRenderStyle() 102 { 103 m_style = originalStyleForRenderer(); 104 if (renderer()) { 105 if (HTMLSelectElement* select = ownerSelectElement()) 106 select->updateListOnRenderer(); 107 } 108 } 109 110 RenderStyle* HTMLOptGroupElement::nonRendererStyle() const 111 { 112 return m_style.get(); 113 } 114 115 PassRefPtr<RenderStyle> HTMLOptGroupElement::customStyleForRenderer() 116 { 117 updateNonRenderStyle(); 118 return m_style; 119 } 120 121 String HTMLOptGroupElement::groupLabelText() const 122 { 123 String itemText = getAttribute(labelAttr); 124 125 // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior. 126 itemText = itemText.stripWhiteSpace(); 127 // We want to collapse our whitespace too. This will match other browsers. 128 itemText = itemText.simplifyWhiteSpace(); 129 130 return itemText; 131 } 132 133 HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const 134 { 135 return Traversal<HTMLSelectElement>::firstAncestor(*this); 136 } 137 138 void HTMLOptGroupElement::accessKeyAction(bool) 139 { 140 HTMLSelectElement* select = ownerSelectElement(); 141 // send to the parent to bring focus to the list box 142 if (select && !select->focused()) 143 select->accessKeyAction(false); 144 } 145 146 void HTMLOptGroupElement::didAddUserAgentShadowRoot(ShadowRoot& root) 147 { 148 DEFINE_STATIC_LOCAL(AtomicString, labelPadding, ("0 2px 1px 2px", AtomicString::ConstructFromLiteral)); 149 DEFINE_STATIC_LOCAL(AtomicString, labelMinHeight, ("1.2em", AtomicString::ConstructFromLiteral)); 150 RefPtrWillBeRawPtr<HTMLDivElement> label = HTMLDivElement::create(document()); 151 label->setAttribute(roleAttr, AtomicString("group", AtomicString::ConstructFromLiteral)); 152 label->setAttribute(aria_labelAttr, AtomicString()); 153 label->setInlineStyleProperty(CSSPropertyPadding, labelPadding); 154 label->setInlineStyleProperty(CSSPropertyMinHeight, labelMinHeight); 155 label->setIdAttribute(ShadowElementNames::optGroupLabel()); 156 root.appendChild(label); 157 158 RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create(document()); 159 content->setAttribute(selectAttr, "option,optgroup"); 160 root.appendChild(content); 161 } 162 163 void HTMLOptGroupElement::updateGroupLabel() 164 { 165 const String& labelText = groupLabelText(); 166 HTMLDivElement& label = optGroupLabelElement(); 167 label.setTextContent(labelText); 168 label.setAttribute(aria_labelAttr, AtomicString(labelText)); 169 } 170 171 HTMLDivElement& HTMLOptGroupElement::optGroupLabelElement() const 172 { 173 return *toHTMLDivElement(userAgentShadowRoot()->getElementById(ShadowElementNames::optGroupLabel())); 174 } 175 176 } // namespace 177