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