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