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 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/FormAssociatedElement.h" 27 28 #include "HTMLNames.h" 29 #include "core/dom/IdTargetObserver.h" 30 #include "core/html/HTMLFormControlElement.h" 31 #include "core/html/HTMLFormElement.h" 32 #include "core/html/HTMLObjectElement.h" 33 #include "core/html/ValidityState.h" 34 35 namespace WebCore { 36 37 using namespace HTMLNames; 38 39 class FormAttributeTargetObserver : IdTargetObserver { 40 WTF_MAKE_FAST_ALLOCATED; 41 public: 42 static PassOwnPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*); 43 virtual void idTargetChanged() OVERRIDE; 44 45 private: 46 FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*); 47 48 FormAssociatedElement* m_element; 49 }; 50 51 FormAssociatedElement::FormAssociatedElement() 52 : m_form(0) 53 { 54 } 55 56 FormAssociatedElement::~FormAssociatedElement() 57 { 58 setForm(0); 59 } 60 61 ValidityState* FormAssociatedElement::validity() 62 { 63 if (!m_validityState) 64 m_validityState = ValidityState::create(this); 65 66 return m_validityState.get(); 67 } 68 69 void FormAssociatedElement::didMoveToNewDocument(Document* oldDocument) 70 { 71 HTMLElement* element = toHTMLElement(this); 72 if (oldDocument && element->fastHasAttribute(formAttr)) 73 m_formAttributeTargetObserver = nullptr; 74 } 75 76 void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint) 77 { 78 if (m_form && insertionPoint->highestAncestor() != m_form->highestAncestor()) 79 setForm(0); 80 81 resetFormOwner(); 82 if (!insertionPoint->inDocument()) 83 return; 84 85 HTMLElement* element = toHTMLElement(this); 86 if (element->fastHasAttribute(formAttr)) 87 resetFormAttributeTargetObserver(); 88 } 89 90 void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint) 91 { 92 HTMLElement* element = toHTMLElement(this); 93 if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr)) 94 m_formAttributeTargetObserver = nullptr; 95 // If the form and element are both in the same tree, preserve the connection to the form. 96 // Otherwise, null out our form and remove ourselves from the form's list of elements. 97 if (m_form && element->highestAncestor() != m_form->highestAncestor()) 98 setForm(0); 99 } 100 101 HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element, HTMLFormElement* currentAssociatedForm) 102 { 103 const AtomicString& formId(element->fastGetAttribute(formAttr)); 104 if (!formId.isNull() && element->inDocument()) { 105 // The HTML5 spec says that the element should be associated with 106 // the first element in the document to have an ID that equal to 107 // the value of form attribute, so we put the result of 108 // treeScope()->getElementById() over the given element. 109 HTMLFormElement* newForm = 0; 110 Element* newFormCandidate = element->treeScope()->getElementById(formId); 111 if (newFormCandidate && newFormCandidate->hasTagName(formTag)) 112 newForm = toHTMLFormElement(newFormCandidate); 113 return newForm; 114 } 115 116 if (!currentAssociatedForm) 117 return element->findFormAncestor(); 118 119 return currentAssociatedForm; 120 } 121 122 void FormAssociatedElement::formRemovedFromTree(const Node* formRoot) 123 { 124 ASSERT(m_form); 125 if (toHTMLElement(this)->highestAncestor() != formRoot) 126 setForm(0); 127 } 128 129 void FormAssociatedElement::setForm(HTMLFormElement* newForm) 130 { 131 if (m_form == newForm) 132 return; 133 willChangeForm(); 134 if (m_form) 135 m_form->removeFormElement(this); 136 m_form = newForm; 137 if (m_form) 138 m_form->registerFormElement(this); 139 didChangeForm(); 140 } 141 142 void FormAssociatedElement::willChangeForm() 143 { 144 } 145 146 void FormAssociatedElement::didChangeForm() 147 { 148 } 149 150 void FormAssociatedElement::formWillBeDestroyed() 151 { 152 ASSERT(m_form); 153 if (!m_form) 154 return; 155 willChangeForm(); 156 m_form = 0; 157 didChangeForm(); 158 } 159 160 void FormAssociatedElement::resetFormOwner() 161 { 162 HTMLFormElement* originalForm = m_form; 163 setForm(findAssociatedForm(toHTMLElement(this), m_form)); 164 HTMLElement* element = toHTMLElement(this); 165 if (m_form && m_form != originalForm && m_form->inDocument()) 166 element->document()->didAssociateFormControl(element); 167 } 168 169 void FormAssociatedElement::formAttributeChanged() 170 { 171 HTMLElement* element = toHTMLElement(this); 172 if (!element->fastHasAttribute(formAttr)) { 173 // The form attribute removed. We need to reset form owner here. 174 HTMLFormElement* originalForm = m_form; 175 setForm(element->findFormAncestor()); 176 HTMLElement* element = toHTMLElement(this); 177 if (m_form && m_form != originalForm && m_form->inDocument()) 178 element->document()->didAssociateFormControl(element); 179 m_formAttributeTargetObserver = nullptr; 180 } else { 181 resetFormOwner(); 182 if (element->inDocument()) 183 resetFormAttributeTargetObserver(); 184 } 185 } 186 187 bool FormAssociatedElement::customError() const 188 { 189 const HTMLElement* element = toHTMLElement(this); 190 return element->willValidate() && !m_customValidationMessage.isEmpty(); 191 } 192 193 bool FormAssociatedElement::hasBadInput() const 194 { 195 return false; 196 } 197 198 bool FormAssociatedElement::patternMismatch() const 199 { 200 return false; 201 } 202 203 bool FormAssociatedElement::rangeOverflow() const 204 { 205 return false; 206 } 207 208 bool FormAssociatedElement::rangeUnderflow() const 209 { 210 return false; 211 } 212 213 bool FormAssociatedElement::stepMismatch() const 214 { 215 return false; 216 } 217 218 bool FormAssociatedElement::tooLong() const 219 { 220 return false; 221 } 222 223 bool FormAssociatedElement::typeMismatch() const 224 { 225 return false; 226 } 227 228 bool FormAssociatedElement::valid() const 229 { 230 bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow() 231 || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError(); 232 return !someError; 233 } 234 235 bool FormAssociatedElement::valueMissing() const 236 { 237 return false; 238 } 239 240 String FormAssociatedElement::customValidationMessage() const 241 { 242 return m_customValidationMessage; 243 } 244 245 String FormAssociatedElement::validationMessage() const 246 { 247 return customError() ? m_customValidationMessage : String(); 248 } 249 250 void FormAssociatedElement::setCustomValidity(const String& error) 251 { 252 m_customValidationMessage = error; 253 } 254 255 void FormAssociatedElement::resetFormAttributeTargetObserver() 256 { 257 ASSERT(toHTMLElement(this)->inDocument()); 258 m_formAttributeTargetObserver = FormAttributeTargetObserver::create(toHTMLElement(this)->fastGetAttribute(formAttr), this); 259 } 260 261 void FormAssociatedElement::formAttributeTargetChanged() 262 { 263 resetFormOwner(); 264 } 265 266 const AtomicString& FormAssociatedElement::name() const 267 { 268 const AtomicString& name = toHTMLElement(this)->getNameAttribute(); 269 return name.isNull() ? emptyAtom : name; 270 } 271 272 bool FormAssociatedElement::isFormControlElementWithState() const 273 { 274 return false; 275 } 276 277 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement) 278 { 279 if (associatedElement->isFormControlElement()) 280 return static_cast<const HTMLFormControlElement*>(associatedElement); 281 // Assumes the element is an HTMLObjectElement 282 const HTMLElement* element = static_cast<const HTMLObjectElement*>(associatedElement); 283 ASSERT(element->hasTagName(objectTag)); 284 return element; 285 } 286 287 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement) 288 { 289 return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement))); 290 } 291 292 PassOwnPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element) 293 { 294 return adoptPtr(new FormAttributeTargetObserver(id, element)); 295 } 296 297 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element) 298 : IdTargetObserver(toHTMLElement(element)->treeScope()->idTargetObserverRegistry(), id) 299 , m_element(element) 300 { 301 } 302 303 void FormAttributeTargetObserver::idTargetChanged() 304 { 305 m_element->formAttributeTargetChanged(); 306 } 307 308 } // namespace Webcore 309