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