Home | History | Annotate | Download | only in html
      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