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