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 // We can't call setForm here because it contains virtual calls. 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 (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 return; 127 setForm(0); 128 } 129 130 void FormAssociatedElement::setForm(HTMLFormElement* newForm) 131 { 132 if (m_form == newForm) 133 return; 134 willChangeForm(); 135 if (m_form) 136 m_form->removeFormElement(this); 137 m_form = newForm; 138 if (m_form) 139 m_form->registerFormElement(*this); 140 didChangeForm(); 141 } 142 143 void FormAssociatedElement::willChangeForm() 144 { 145 } 146 147 void FormAssociatedElement::didChangeForm() 148 { 149 } 150 151 void FormAssociatedElement::formWillBeDestroyed() 152 { 153 ASSERT(m_form); 154 if (!m_form) 155 return; 156 willChangeForm(); 157 m_form = 0; 158 didChangeForm(); 159 } 160 161 void FormAssociatedElement::resetFormOwner() 162 { 163 HTMLFormElement* originalForm = m_form; 164 setForm(findAssociatedForm(toHTMLElement(this), m_form)); 165 HTMLElement* element = toHTMLElement(this); 166 if (m_form && m_form != originalForm && m_form->inDocument()) 167 element->document().didAssociateFormControl(element); 168 } 169 170 void FormAssociatedElement::formAttributeChanged() 171 { 172 HTMLElement* element = toHTMLElement(this); 173 if (!element->fastHasAttribute(formAttr)) { 174 // The form attribute removed. We need to reset form owner here. 175 HTMLFormElement* originalForm = m_form; 176 setForm(element->findFormAncestor()); 177 HTMLElement* element = toHTMLElement(this); 178 if (m_form && m_form != originalForm && m_form->inDocument()) 179 element->document().didAssociateFormControl(element); 180 m_formAttributeTargetObserver = nullptr; 181 } else { 182 resetFormOwner(); 183 if (element->inDocument()) 184 resetFormAttributeTargetObserver(); 185 } 186 } 187 188 bool FormAssociatedElement::customError() const 189 { 190 const HTMLElement* element = toHTMLElement(this); 191 return element->willValidate() && !m_customValidationMessage.isEmpty(); 192 } 193 194 bool FormAssociatedElement::hasBadInput() const 195 { 196 return false; 197 } 198 199 bool FormAssociatedElement::patternMismatch() const 200 { 201 return false; 202 } 203 204 bool FormAssociatedElement::rangeOverflow() const 205 { 206 return false; 207 } 208 209 bool FormAssociatedElement::rangeUnderflow() const 210 { 211 return false; 212 } 213 214 bool FormAssociatedElement::stepMismatch() const 215 { 216 return false; 217 } 218 219 bool FormAssociatedElement::tooLong() const 220 { 221 return false; 222 } 223 224 bool FormAssociatedElement::typeMismatch() const 225 { 226 return false; 227 } 228 229 bool FormAssociatedElement::valid() const 230 { 231 bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow() 232 || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError(); 233 return !someError; 234 } 235 236 bool FormAssociatedElement::valueMissing() const 237 { 238 return false; 239 } 240 241 String FormAssociatedElement::customValidationMessage() const 242 { 243 return m_customValidationMessage; 244 } 245 246 String FormAssociatedElement::validationMessage() const 247 { 248 return customError() ? m_customValidationMessage : String(); 249 } 250 251 void FormAssociatedElement::setCustomValidity(const String& error) 252 { 253 m_customValidationMessage = error; 254 } 255 256 void FormAssociatedElement::resetFormAttributeTargetObserver() 257 { 258 ASSERT(toHTMLElement(this)->inDocument()); 259 m_formAttributeTargetObserver = FormAttributeTargetObserver::create(toHTMLElement(this)->fastGetAttribute(formAttr), this); 260 } 261 262 void FormAssociatedElement::formAttributeTargetChanged() 263 { 264 resetFormOwner(); 265 } 266 267 const AtomicString& FormAssociatedElement::name() const 268 { 269 const AtomicString& name = toHTMLElement(this)->getNameAttribute(); 270 return name.isNull() ? emptyAtom : name; 271 } 272 273 bool FormAssociatedElement::isFormControlElementWithState() const 274 { 275 return false; 276 } 277 278 const HTMLElement& toHTMLElement(const FormAssociatedElement& associatedElement) 279 { 280 if (associatedElement.isFormControlElement()) 281 return toHTMLFormControlElement(associatedElement); 282 // Assumes the element is an HTMLObjectElement 283 return toHTMLObjectElement(associatedElement); 284 } 285 286 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement) 287 { 288 ASSERT(associatedElement); 289 return &toHTMLElement(*associatedElement); 290 } 291 292 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement) 293 { 294 return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement))); 295 } 296 297 HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement) 298 { 299 return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement))); 300 } 301 302 PassOwnPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element) 303 { 304 return adoptPtr(new FormAttributeTargetObserver(id, element)); 305 } 306 307 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element) 308 : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id) 309 , m_element(element) 310 { 311 } 312 313 void FormAttributeTargetObserver::idTargetChanged() 314 { 315 m_element->formAttributeTargetChanged(); 316 } 317 318 } // namespace Webcore 319