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