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, 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/HTMLLabelElement.h"
     27 
     28 #include "HTMLNames.h"
     29 #include "core/dom/ElementTraversal.h"
     30 #include "core/events/Event.h"
     31 #include "core/events/ThreadLocalEventNames.h"
     32 #include "core/html/FormAssociatedElement.h"
     33 
     34 namespace WebCore {
     35 
     36 using namespace HTMLNames;
     37 
     38 static bool supportsLabels(Element* element)
     39 {
     40     if (!element || !element->isHTMLElement())
     41         return false;
     42     if (!toHTMLElement(element)->isLabelable())
     43         return false;
     44     return toLabelableElement(element)->supportLabels();
     45 }
     46 
     47 inline HTMLLabelElement::HTMLLabelElement(Document& document)
     48     : HTMLElement(labelTag, document)
     49 {
     50     ScriptWrappable::init(this);
     51 }
     52 
     53 PassRefPtr<HTMLLabelElement> HTMLLabelElement::create(Document& document)
     54 {
     55     return adoptRef(new HTMLLabelElement(document));
     56 }
     57 
     58 bool HTMLLabelElement::rendererIsFocusable() const
     59 {
     60     HTMLLabelElement* that = const_cast<HTMLLabelElement*>(this);
     61     return that->isContentEditable();
     62 }
     63 
     64 LabelableElement* HTMLLabelElement::control()
     65 {
     66     const AtomicString& controlId = getAttribute(forAttr);
     67     if (controlId.isNull()) {
     68         // Search the children and descendants of the label element for a form element.
     69         // per http://dev.w3.org/html5/spec/Overview.html#the-label-element
     70         // the form element must be "labelable form-associated element".
     71         Element* element = this;
     72         while ((element = ElementTraversal::next(*element, this))) {
     73             if (!supportsLabels(element))
     74                 continue;
     75             return toLabelableElement(element);
     76         }
     77         return 0;
     78     }
     79 
     80     if (Element* element = treeScope().getElementById(controlId)) {
     81         if (supportsLabels(element))
     82             return toLabelableElement(element);
     83     }
     84 
     85     return 0;
     86 }
     87 
     88 HTMLFormElement* HTMLLabelElement::formOwner() const
     89 {
     90     return FormAssociatedElement::findAssociatedForm(this, 0);
     91 }
     92 
     93 void HTMLLabelElement::setActive(bool down)
     94 {
     95     if (down == active())
     96         return;
     97 
     98     // Update our status first.
     99     HTMLElement::setActive(down);
    100 
    101     // Also update our corresponding control.
    102     if (HTMLElement* element = control())
    103         element->setActive(down);
    104 }
    105 
    106 void HTMLLabelElement::setHovered(bool over)
    107 {
    108     if (over == hovered())
    109         return;
    110 
    111     // Update our status first.
    112     HTMLElement::setHovered(over);
    113 
    114     // Also update our corresponding control.
    115     if (HTMLElement* element = control())
    116         element->setHovered(over);
    117 }
    118 
    119 bool HTMLLabelElement::isInteractiveContent() const
    120 {
    121     return true;
    122 }
    123 
    124 bool HTMLLabelElement::isInInteractiveContent(Node* node) const
    125 {
    126     if (!containsIncludingShadowDOM(node))
    127         return false;
    128     while (node && this != node) {
    129         if (node->isHTMLElement() && toHTMLElement(node)->isInteractiveContent())
    130             return true;
    131         node = node->parentOrShadowHostNode();
    132     }
    133     return false;
    134 }
    135 
    136 void HTMLLabelElement::defaultEventHandler(Event* evt)
    137 {
    138     static bool processingClick = false;
    139 
    140     if (evt->type() == EventTypeNames::click && !processingClick) {
    141         RefPtr<HTMLElement> element = control();
    142 
    143         // If we can't find a control or if the control received the click
    144         // event, then there's no need for us to do anything.
    145         if (!element || (evt->target() && element->containsIncludingShadowDOM(evt->target()->toNode())))
    146             return;
    147 
    148         if (evt->target() && isInInteractiveContent(evt->target()->toNode()))
    149             return;
    150 
    151         processingClick = true;
    152 
    153         document().updateLayoutIgnorePendingStylesheets();
    154         if (element->isMouseFocusable())
    155             element->focus(true, FocusDirectionMouse);
    156 
    157         // Click the corresponding control.
    158         element->dispatchSimulatedClick(evt);
    159 
    160         processingClick = false;
    161 
    162         evt->setDefaultHandled();
    163     }
    164 
    165     HTMLElement::defaultEventHandler(evt);
    166 }
    167 
    168 bool HTMLLabelElement::willRespondToMouseClickEvents()
    169 {
    170     if (control() && control()->willRespondToMouseClickEvents())
    171         return true;
    172 
    173     return HTMLElement::willRespondToMouseClickEvents();
    174 }
    175 
    176 void HTMLLabelElement::focus(bool, FocusDirection direction)
    177 {
    178     // to match other browsers, always restore previous selection
    179     if (HTMLElement* element = control())
    180         element->focus(true, direction);
    181     if (isFocusable())
    182         HTMLElement::focus(true, direction);
    183 }
    184 
    185 void HTMLLabelElement::accessKeyAction(bool sendMouseEvents)
    186 {
    187     if (HTMLElement* element = control())
    188         element->accessKeyAction(sendMouseEvents);
    189     else
    190         HTMLElement::accessKeyAction(sendMouseEvents);
    191 }
    192 
    193 } // namespace
    194