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 "core/HTMLNames.h" 29 #include "core/dom/IdTargetObserver.h" 30 #include "core/dom/NodeTraversal.h" 31 #include "core/html/HTMLFormControlElement.h" 32 #include "core/html/HTMLFormElement.h" 33 #include "core/html/HTMLLabelElement.h" 34 #include "core/html/HTMLObjectElement.h" 35 #include "core/html/ValidityState.h" 36 37 namespace blink { 38 39 using namespace HTMLNames; 40 41 class FormAttributeTargetObserver : public IdTargetObserver { 42 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED; 43 public: 44 static PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*); 45 virtual void trace(Visitor*) OVERRIDE; 46 virtual void idTargetChanged() OVERRIDE; 47 48 private: 49 FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*); 50 51 RawPtrWillBeMember<FormAssociatedElement> m_element; 52 }; 53 54 FormAssociatedElement::FormAssociatedElement() 55 : m_formWasSetByParser(false) 56 { 57 } 58 59 FormAssociatedElement::~FormAssociatedElement() 60 { 61 // We can't call setForm here because it contains virtual calls. 62 } 63 64 void FormAssociatedElement::trace(Visitor* visitor) 65 { 66 visitor->trace(m_formAttributeTargetObserver); 67 visitor->trace(m_form); 68 visitor->trace(m_validityState); 69 } 70 71 ValidityState* FormAssociatedElement::validity() 72 { 73 if (!m_validityState) 74 m_validityState = ValidityState::create(this); 75 76 return m_validityState.get(); 77 } 78 79 void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument) 80 { 81 HTMLElement* element = toHTMLElement(this); 82 if (element->fastHasAttribute(formAttr)) 83 setFormAttributeTargetObserver(nullptr); 84 } 85 86 void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint) 87 { 88 if (!m_formWasSetByParser || !m_form || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get())) 89 resetFormOwner(); 90 91 if (!insertionPoint->inDocument()) 92 return; 93 94 HTMLElement* element = toHTMLElement(this); 95 if (element->fastHasAttribute(formAttr)) 96 resetFormAttributeTargetObserver(); 97 } 98 99 void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint) 100 { 101 HTMLElement* element = toHTMLElement(this); 102 if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr)) 103 setFormAttributeTargetObserver(nullptr); 104 // If the form and element are both in the same tree, preserve the connection to the form. 105 // Otherwise, null out our form and remove ourselves from the form's list of elements. 106 if (m_form && NodeTraversal::highestAncestorOrSelf(*element) != NodeTraversal::highestAncestorOrSelf(*m_form.get())) 107 resetFormOwner(); 108 } 109 110 HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element) 111 { 112 const AtomicString& formId(element->fastGetAttribute(formAttr)); 113 // 3. If the element is reassociateable, has a form content attribute, and 114 // is itself in a Document, then run these substeps: 115 if (!formId.isNull() && element->inDocument()) { 116 // 3.1. If the first element in the Document to have an ID that is 117 // case-sensitively equal to the element's form content attribute's 118 // value is a form element, then associate the form-associated element 119 // with that form element. 120 // 3.2. Abort the "reset the form owner" steps. 121 Element* newFormCandidate = element->treeScope().getElementById(formId); 122 return isHTMLFormElement(newFormCandidate) ? toHTMLFormElement(newFormCandidate) : 0; 123 } 124 // 4. Otherwise, if the form-associated element in question has an ancestor 125 // form element, then associate the form-associated element with the nearest 126 // such ancestor form element. 127 return element->findFormAncestor(); 128 } 129 130 void FormAssociatedElement::formRemovedFromTree(const Node& formRoot) 131 { 132 ASSERT(m_form); 133 if (NodeTraversal::highestAncestorOrSelf(toHTMLElement(*this)) == formRoot) 134 return; 135 resetFormOwner(); 136 } 137 138 void FormAssociatedElement::associateByParser(HTMLFormElement* form) 139 { 140 if (form && form->inDocument()) { 141 m_formWasSetByParser = true; 142 setForm(form); 143 form->didAssociateByParser(); 144 } 145 } 146 147 void FormAssociatedElement::setForm(HTMLFormElement* newForm) 148 { 149 if (m_form.get() == newForm) 150 return; 151 willChangeForm(); 152 if (m_form) 153 m_form->disassociate(*this); 154 if (newForm) { 155 #if ENABLE(OILPAN) 156 m_form = newForm; 157 #else 158 m_form = newForm->createWeakPtr(); 159 #endif 160 m_form->associate(*this); 161 } else { 162 #if ENABLE(OILPAN) 163 m_form = nullptr; 164 #else 165 m_form = WeakPtr<HTMLFormElement>(); 166 #endif 167 } 168 didChangeForm(); 169 } 170 171 void FormAssociatedElement::willChangeForm() 172 { 173 } 174 175 void FormAssociatedElement::didChangeForm() 176 { 177 } 178 179 void FormAssociatedElement::resetFormOwner() 180 { 181 m_formWasSetByParser = false; 182 HTMLElement* element = toHTMLElement(this); 183 const AtomicString& formId(element->fastGetAttribute(formAttr)); 184 HTMLFormElement* nearestForm = element->findFormAncestor(); 185 // 1. If the element's form owner is not null, and either the element is not 186 // reassociateable or its form content attribute is not present, and the 187 // element's form owner is its nearest form element ancestor after the 188 // change to the ancestor chain, then do nothing, and abort these steps. 189 if (m_form && formId.isNull() && m_form.get() == nearestForm) 190 return; 191 192 HTMLFormElement* originalForm = m_form.get(); 193 setForm(findAssociatedForm(element)); 194 // FIXME: Move didAssociateFormControl call to didChangeForm or 195 // HTMLFormElement::associate. 196 if (m_form && m_form.get() != originalForm && m_form->inDocument()) 197 element->document().didAssociateFormControl(element); 198 } 199 200 void FormAssociatedElement::formAttributeChanged() 201 { 202 resetFormOwner(); 203 resetFormAttributeTargetObserver(); 204 } 205 206 bool FormAssociatedElement::customError() const 207 { 208 const HTMLElement* element = toHTMLElement(this); 209 return element->willValidate() && !m_customValidationMessage.isEmpty(); 210 } 211 212 bool FormAssociatedElement::hasBadInput() const 213 { 214 return false; 215 } 216 217 bool FormAssociatedElement::patternMismatch() const 218 { 219 return false; 220 } 221 222 bool FormAssociatedElement::rangeOverflow() const 223 { 224 return false; 225 } 226 227 bool FormAssociatedElement::rangeUnderflow() const 228 { 229 return false; 230 } 231 232 bool FormAssociatedElement::stepMismatch() const 233 { 234 return false; 235 } 236 237 bool FormAssociatedElement::tooLong() const 238 { 239 return false; 240 } 241 242 bool FormAssociatedElement::typeMismatch() const 243 { 244 return false; 245 } 246 247 bool FormAssociatedElement::valid() const 248 { 249 bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow() 250 || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError(); 251 return !someError; 252 } 253 254 bool FormAssociatedElement::valueMissing() const 255 { 256 return false; 257 } 258 259 String FormAssociatedElement::customValidationMessage() const 260 { 261 return m_customValidationMessage; 262 } 263 264 String FormAssociatedElement::validationMessage() const 265 { 266 return customError() ? m_customValidationMessage : String(); 267 } 268 269 void FormAssociatedElement::setCustomValidity(const String& error) 270 { 271 m_customValidationMessage = error; 272 } 273 274 void FormAssociatedElement::setFormAttributeTargetObserver(PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> newObserver) 275 { 276 if (m_formAttributeTargetObserver) 277 m_formAttributeTargetObserver->unregister(); 278 m_formAttributeTargetObserver = newObserver; 279 } 280 281 void FormAssociatedElement::resetFormAttributeTargetObserver() 282 { 283 HTMLElement* element = toHTMLElement(this); 284 const AtomicString& formId(element->fastGetAttribute(formAttr)); 285 if (!formId.isNull() && element->inDocument()) 286 setFormAttributeTargetObserver(FormAttributeTargetObserver::create(formId, this)); 287 else 288 setFormAttributeTargetObserver(nullptr); 289 } 290 291 void FormAssociatedElement::formAttributeTargetChanged() 292 { 293 resetFormOwner(); 294 } 295 296 const AtomicString& FormAssociatedElement::name() const 297 { 298 const AtomicString& name = toHTMLElement(this)->getNameAttribute(); 299 return name.isNull() ? emptyAtom : name; 300 } 301 302 bool FormAssociatedElement::isFormControlElementWithState() const 303 { 304 return false; 305 } 306 307 const HTMLElement& toHTMLElement(const FormAssociatedElement& associatedElement) 308 { 309 if (associatedElement.isFormControlElement()) 310 return toHTMLFormControlElement(associatedElement); 311 else if (associatedElement.isLabelElement()) 312 return toHTMLLabelElement(associatedElement); 313 else 314 return toHTMLObjectElement(associatedElement); 315 } 316 317 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement) 318 { 319 ASSERT(associatedElement); 320 return &toHTMLElement(*associatedElement); 321 } 322 323 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement) 324 { 325 return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement))); 326 } 327 328 HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement) 329 { 330 return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement))); 331 } 332 333 PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element) 334 { 335 return adoptPtrWillBeNoop(new FormAttributeTargetObserver(id, element)); 336 } 337 338 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element) 339 : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id) 340 , m_element(element) 341 { 342 } 343 344 void FormAttributeTargetObserver::trace(Visitor* visitor) 345 { 346 visitor->trace(m_element); 347 IdTargetObserver::trace(visitor); 348 } 349 350 void FormAttributeTargetObserver::idTargetChanged() 351 { 352 m_element->formAttributeTargetChanged(); 353 } 354 355 } // namespace blink 356