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 "HTMLLabelElement.h"
     27 
     28 #include "Document.h"
     29 #include "Event.h"
     30 #include "EventNames.h"
     31 #include "HTMLFormControlElement.h"
     32 #include "HTMLFormElement.h"
     33 #include "HTMLNames.h"
     34 
     35 namespace WebCore {
     36 
     37 using namespace HTMLNames;
     38 
     39 static HTMLFormControlElement* nodeAsLabelableFormControl(Node* node)
     40 {
     41     if (!node || !node->isElementNode() || !static_cast<Element*>(node)->isFormControlElement())
     42         return 0;
     43 
     44     HTMLFormControlElement* formControlElement = static_cast<HTMLFormControlElement*>(node);
     45     if (!formControlElement->isLabelable())
     46         return 0;
     47 
     48     return formControlElement;
     49 }
     50 
     51 inline HTMLLabelElement::HTMLLabelElement(const QualifiedName& tagName, Document* document)
     52     : HTMLElement(tagName, document)
     53 {
     54     ASSERT(hasTagName(labelTag));
     55 }
     56 
     57 PassRefPtr<HTMLLabelElement> HTMLLabelElement::create(const QualifiedName& tagName, Document* document)
     58 {
     59     return adoptRef(new HTMLLabelElement(tagName, document));
     60 }
     61 
     62 bool HTMLLabelElement::isFocusable() const
     63 {
     64     return false;
     65 }
     66 
     67 HTMLFormControlElement* HTMLLabelElement::control()
     68 {
     69     const AtomicString& controlId = getAttribute(forAttr);
     70     if (controlId.isNull()) {
     71         // Search the children and descendants of the label element for a form element.
     72         // per http://dev.w3.org/html5/spec/Overview.html#the-label-element
     73         // the form element must be "labelable form-associated element".
     74         Node* node = this;
     75         while ((node = node->traverseNextNode(this))) {
     76             if (HTMLFormControlElement* formControlElement = nodeAsLabelableFormControl(node))
     77                 return formControlElement;
     78         }
     79         return 0;
     80     }
     81 
     82     // Find the first element whose id is controlId. If it is found and it is a labelable form control,
     83     // return it, otherwise return 0.
     84     return nodeAsLabelableFormControl(document()->getElementById(controlId));
     85 }
     86 
     87 void HTMLLabelElement::setActive(bool down, bool pause)
     88 {
     89     if (down == active())
     90         return;
     91 
     92     // Update our status first.
     93     HTMLElement::setActive(down, pause);
     94 
     95     // Also update our corresponding control.
     96     if (HTMLElement* element = control())
     97         element->setActive(down, pause);
     98 }
     99 
    100 void HTMLLabelElement::setHovered(bool over)
    101 {
    102     if (over == hovered())
    103         return;
    104 
    105     // Update our status first.
    106     HTMLElement::setHovered(over);
    107 
    108     // Also update our corresponding control.
    109     if (HTMLElement* element = control())
    110         element->setHovered(over);
    111 }
    112 
    113 void HTMLLabelElement::defaultEventHandler(Event* evt)
    114 {
    115     static bool processingClick = false;
    116 
    117     if (evt->type() == eventNames().clickEvent && !processingClick) {
    118         RefPtr<HTMLElement> element = control();
    119 
    120         // If we can't find a control or if the control received the click
    121         // event, then there's no need for us to do anything.
    122         if (!element || (evt->target() && element->containsIncludingShadowDOM(evt->target()->toNode())))
    123             return;
    124 
    125         processingClick = true;
    126 
    127         // Click the corresponding control.
    128         element->dispatchSimulatedClick(evt);
    129 
    130         // If the control can be focused via the mouse, then do that too.
    131         if (element->isMouseFocusable())
    132             element->focus();
    133 
    134         processingClick = false;
    135 
    136         evt->setDefaultHandled();
    137     }
    138 
    139     HTMLElement::defaultEventHandler(evt);
    140 }
    141 
    142 void HTMLLabelElement::focus(bool)
    143 {
    144     // to match other browsers, always restore previous selection
    145     if (HTMLElement* element = control())
    146         element->focus();
    147 }
    148 
    149 void HTMLLabelElement::accessKeyAction(bool sendToAnyElement)
    150 {
    151     if (HTMLElement* element = control())
    152         element->accessKeyAction(sendToAnyElement);
    153     else
    154         HTMLElement::accessKeyAction(sendToAnyElement);
    155 }
    156 
    157 void HTMLLabelElement::parseMappedAttribute(Attribute* attribute)
    158 {
    159     if (attribute->name() == forAttr) {
    160         // htmlFor attribute change affects other nodes than this.
    161         // Clear the caches to ensure that the labels caches are cleared.
    162         if (document())
    163             document()->notifyLocalNodeListsLabelChanged();
    164     } else
    165         HTMLElement::parseMappedAttribute(attribute);
    166 }
    167 
    168 } // namespace
    169