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