2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
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.
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.
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.
26 #include "core/html/HTMLLabelElement.h"
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"
36 using namespace HTMLNames;
38 static bool supportsLabels(const Element& element)
40 if (!element.isHTMLElement())
42 if (!toHTMLElement(element).isLabelable())
44 return toLabelableElement(element).supportLabels();
47 inline HTMLLabelElement::HTMLLabelElement(Document& document)
48 : HTMLElement(labelTag, document)
50 ScriptWrappable::init(this);
53 PassRefPtr<HTMLLabelElement> HTMLLabelElement::create(Document& document)
55 return adoptRef(new HTMLLabelElement(document));
58 bool HTMLLabelElement::rendererIsFocusable() const
60 HTMLLabelElement* that = const_cast<HTMLLabelElement*>(this);
61 return that->isContentEditable();
64 LabelableElement* HTMLLabelElement::control() const
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 for (Element* element = ElementTraversal::next(*this, this); element; element = ElementTraversal::next(*element, this)) {
72 if (!supportsLabels(*element))
74 return toLabelableElement(element);
79 if (Element* element = treeScope().getElementById(controlId)) {
80 if (supportsLabels(*element))
81 return toLabelableElement(element);
87 HTMLFormElement* HTMLLabelElement::formOwner() const
89 return FormAssociatedElement::findAssociatedForm(this);
92 void HTMLLabelElement::setActive(bool down)
97 // Update our status first.
98 HTMLElement::setActive(down);
100 // Also update our corresponding control.
101 if (HTMLElement* element = control())
102 element->setActive(down);
105 void HTMLLabelElement::setHovered(bool over)
107 if (over == hovered())
110 // Update our status first.
111 HTMLElement::setHovered(over);
113 // Also update our corresponding control.
114 if (HTMLElement* element = control())
115 element->setHovered(over);
118 bool HTMLLabelElement::isInteractiveContent() const
123 bool HTMLLabelElement::isInInteractiveContent(Node* node) const
125 if (!containsIncludingShadowDOM(node))
127 while (node && this != node) {
128 if (node->isHTMLElement() && toHTMLElement(node)->isInteractiveContent())
130 node = node->parentOrShadowHostNode();
135 void HTMLLabelElement::defaultEventHandler(Event* evt)
137 static bool processingClick = false;
139 if (evt->type() == EventTypeNames::click && !processingClick) {
140 RefPtr<HTMLElement> element = control();
142 // If we can't find a control or if the control received the click
143 // event, then there's no need for us to do anything.
144 if (!element || (evt->target() && element->containsIncludingShadowDOM(evt->target()->toNode())))
147 if (evt->target() && isInInteractiveContent(evt->target()->toNode()))
150 processingClick = true;
152 document().updateLayoutIgnorePendingStylesheets();
153 if (element->isMouseFocusable())
154 element->focus(true, FocusDirectionMouse);
156 // Click the corresponding control.
157 element->dispatchSimulatedClick(evt);
159 processingClick = false;
161 evt->setDefaultHandled();
164 HTMLElement::defaultEventHandler(evt);
167 bool HTMLLabelElement::willRespondToMouseClickEvents()
169 if (control() && control()->willRespondToMouseClickEvents())
172 return HTMLElement::willRespondToMouseClickEvents();
175 void HTMLLabelElement::focus(bool, FocusDirection direction)
177 // to match other browsers, always restore previous selection
178 if (HTMLElement* element = control())
179 element->focus(true, direction);
181 HTMLElement::focus(true, direction);
184 void HTMLLabelElement::accessKeyAction(bool sendMouseEvents)
186 if (HTMLElement* element = control())
187 element->accessKeyAction(sendMouseEvents);
189 HTMLElement::accessKeyAction(sendMouseEvents);