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)
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.
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.
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.
26 #include "core/html/FormAssociatedElement.h"
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"
39 using namespace HTMLNames
;
41 class FormAttributeTargetObserver
: public IdTargetObserver
{
42 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(FormAttributeTargetObserver
);
44 static PassOwnPtrWillBeRawPtr
<FormAttributeTargetObserver
> create(const AtomicString
& id
, FormAssociatedElement
*);
45 DECLARE_VIRTUAL_TRACE();
46 void idTargetChanged() override
;
49 FormAttributeTargetObserver(const AtomicString
& id
, FormAssociatedElement
*);
51 RawPtrWillBeMember
<FormAssociatedElement
> m_element
;
54 FormAssociatedElement::FormAssociatedElement()
55 : m_formWasSetByParser(false)
59 FormAssociatedElement::~FormAssociatedElement()
61 // We can't call setForm here because it contains virtual calls.
64 DEFINE_TRACE(FormAssociatedElement
)
66 visitor
->trace(m_formAttributeTargetObserver
);
67 visitor
->trace(m_form
);
68 visitor
->trace(m_validityState
);
71 ValidityState
* FormAssociatedElement::validity()
74 m_validityState
= ValidityState::create(this);
76 return m_validityState
.get();
79 void FormAssociatedElement::didMoveToNewDocument(Document
& oldDocument
)
81 HTMLElement
* element
= toHTMLElement(this);
82 if (element
->fastHasAttribute(formAttr
))
83 setFormAttributeTargetObserver(nullptr);
86 void FormAssociatedElement::insertedInto(ContainerNode
* insertionPoint
)
88 if (!m_formWasSetByParser
|| !m_form
|| NodeTraversal::highestAncestorOrSelf(*insertionPoint
) != NodeTraversal::highestAncestorOrSelf(*m_form
.get()))
91 if (!insertionPoint
->inDocument())
94 HTMLElement
* element
= toHTMLElement(this);
95 if (element
->fastHasAttribute(formAttr
))
96 resetFormAttributeTargetObserver();
99 void FormAssociatedElement::removedFrom(ContainerNode
* insertionPoint
)
101 HTMLElement
* element
= toHTMLElement(this);
102 if (insertionPoint
->inDocument() && element
->fastHasAttribute(formAttr
)) {
103 setFormAttributeTargetObserver(nullptr);
107 // If the form and element are both in the same tree, preserve the connection to the form.
108 // Otherwise, null out our form and remove ourselves from the form's list of elements.
109 if (m_form
&& NodeTraversal::highestAncestorOrSelf(*element
) != NodeTraversal::highestAncestorOrSelf(*m_form
.get()))
113 HTMLFormElement
* FormAssociatedElement::findAssociatedForm(const HTMLElement
* element
)
115 const AtomicString
& formId(element
->fastGetAttribute(formAttr
));
116 // 3. If the element is reassociateable, has a form content attribute, and
117 // is itself in a Document, then run these substeps:
118 if (!formId
.isNull() && element
->inDocument()) {
119 // 3.1. If the first element in the Document to have an ID that is
120 // case-sensitively equal to the element's form content attribute's
121 // value is a form element, then associate the form-associated element
122 // with that form element.
123 // 3.2. Abort the "reset the form owner" steps.
124 Element
* newFormCandidate
= element
->treeScope().getElementById(formId
);
125 return isHTMLFormElement(newFormCandidate
) ? toHTMLFormElement(newFormCandidate
) : 0;
127 // 4. Otherwise, if the form-associated element in question has an ancestor
128 // form element, then associate the form-associated element with the nearest
129 // such ancestor form element.
130 return element
->findFormAncestor();
133 void FormAssociatedElement::formRemovedFromTree(const Node
& formRoot
)
136 if (NodeTraversal::highestAncestorOrSelf(toHTMLElement(*this)) == formRoot
)
141 void FormAssociatedElement::associateByParser(HTMLFormElement
* form
)
143 if (form
&& form
->inDocument()) {
144 m_formWasSetByParser
= true;
146 form
->didAssociateByParser();
150 void FormAssociatedElement::setForm(HTMLFormElement
* newForm
)
152 if (m_form
.get() == newForm
)
156 m_form
->disassociate(*this);
161 m_form
= newForm
->createWeakPtr();
163 m_form
->associate(*this);
170 void FormAssociatedElement::willChangeForm()
174 void FormAssociatedElement::didChangeForm()
176 if (!m_formWasSetByParser
&& m_form
&& m_form
->inDocument()) {
177 HTMLElement
* element
= toHTMLElement(this);
178 element
->document().didAssociateFormControl(element
);
182 void FormAssociatedElement::resetFormOwner()
184 m_formWasSetByParser
= false;
185 HTMLElement
* element
= toHTMLElement(this);
186 const AtomicString
& formId(element
->fastGetAttribute(formAttr
));
187 HTMLFormElement
* nearestForm
= element
->findFormAncestor();
188 // 1. If the element's form owner is not null, and either the element is not
189 // reassociateable or its form content attribute is not present, and the
190 // element's form owner is its nearest form element ancestor after the
191 // change to the ancestor chain, then do nothing, and abort these steps.
192 if (m_form
&& formId
.isNull() && m_form
.get() == nearestForm
)
195 setForm(findAssociatedForm(element
));
198 void FormAssociatedElement::formAttributeChanged()
201 resetFormAttributeTargetObserver();
204 bool FormAssociatedElement::customError() const
206 const HTMLElement
* element
= toHTMLElement(this);
207 return element
->willValidate() && !m_customValidationMessage
.isEmpty();
210 bool FormAssociatedElement::hasBadInput() const
215 bool FormAssociatedElement::patternMismatch() const
220 bool FormAssociatedElement::rangeOverflow() const
225 bool FormAssociatedElement::rangeUnderflow() const
230 bool FormAssociatedElement::stepMismatch() const
235 bool FormAssociatedElement::tooLong() const
240 bool FormAssociatedElement::tooShort() const
245 bool FormAssociatedElement::typeMismatch() const
250 bool FormAssociatedElement::valid() const
252 bool someError
= typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
253 || tooLong() || tooShort() || patternMismatch() || valueMissing() || hasBadInput()
258 bool FormAssociatedElement::valueMissing() const
263 String
FormAssociatedElement::customValidationMessage() const
265 return m_customValidationMessage
;
268 String
FormAssociatedElement::validationMessage() const
270 return customError() ? m_customValidationMessage
: String();
273 void FormAssociatedElement::setCustomValidity(const String
& error
)
275 m_customValidationMessage
= error
;
278 void FormAssociatedElement::setFormAttributeTargetObserver(PassOwnPtrWillBeRawPtr
<FormAttributeTargetObserver
> newObserver
)
280 if (m_formAttributeTargetObserver
)
281 m_formAttributeTargetObserver
->unregister();
282 m_formAttributeTargetObserver
= newObserver
;
285 void FormAssociatedElement::resetFormAttributeTargetObserver()
287 HTMLElement
* element
= toHTMLElement(this);
288 const AtomicString
& formId(element
->fastGetAttribute(formAttr
));
289 if (!formId
.isNull() && element
->inDocument())
290 setFormAttributeTargetObserver(FormAttributeTargetObserver::create(formId
, this));
292 setFormAttributeTargetObserver(nullptr);
295 void FormAssociatedElement::formAttributeTargetChanged()
300 const AtomicString
& FormAssociatedElement::name() const
302 const AtomicString
& name
= toHTMLElement(this)->getNameAttribute();
303 return name
.isNull() ? emptyAtom
: name
;
306 bool FormAssociatedElement::isFormControlElementWithState() const
311 const HTMLElement
& toHTMLElement(const FormAssociatedElement
& associatedElement
)
313 if (associatedElement
.isFormControlElement())
314 return toHTMLFormControlElement(associatedElement
);
315 if (associatedElement
.isLabelElement())
316 return toHTMLLabelElement(associatedElement
);
317 return toHTMLObjectElement(associatedElement
);
320 const HTMLElement
* toHTMLElement(const FormAssociatedElement
* associatedElement
)
322 ASSERT(associatedElement
);
323 return &toHTMLElement(*associatedElement
);
326 HTMLElement
* toHTMLElement(FormAssociatedElement
* associatedElement
)
328 return const_cast<HTMLElement
*>(toHTMLElement(static_cast<const FormAssociatedElement
*>(associatedElement
)));
331 HTMLElement
& toHTMLElement(FormAssociatedElement
& associatedElement
)
333 return const_cast<HTMLElement
&>(toHTMLElement(static_cast<const FormAssociatedElement
&>(associatedElement
)));
336 PassOwnPtrWillBeRawPtr
<FormAttributeTargetObserver
> FormAttributeTargetObserver::create(const AtomicString
& id
, FormAssociatedElement
* element
)
338 return adoptPtrWillBeNoop(new FormAttributeTargetObserver(id
, element
));
341 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString
& id
, FormAssociatedElement
* element
)
342 : IdTargetObserver(toHTMLElement(element
)->treeScope().idTargetObserverRegistry(), id
)
347 DEFINE_TRACE(FormAttributeTargetObserver
)
349 visitor
->trace(m_element
);
350 IdTargetObserver::trace(visitor
);
353 void FormAttributeTargetObserver::idTargetChanged()
355 m_element
->formAttributeTargetChanged();