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