f05177c1a792f00c1d10d3b3a8df2b9f7cfedf73
[WebKit-https.git] / Source / WebCore / html / FormAssociatedElement.cpp
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 "config.h"
26 #include "FormAssociatedElement.h"
27
28 #include "FormController.h"
29 #include "HTMLFormControlElement.h"
30 #include "HTMLFormElement.h"
31 #include "HTMLNames.h"
32 #include "HTMLObjectElement.h"
33 #include "IdTargetObserver.h"
34 #include "ValidityState.h"
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 class FormAttributeTargetObserver : IdTargetObserver {
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     setForm(0);
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 (oldDocument && element->fastHasAttribute(formAttr))
73         resetFormAttributeTargetObserver();
74 }
75
76 void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
77 {
78     resetFormOwner();
79     if (!insertionPoint->inDocument())
80         return;
81
82     HTMLElement* element = toHTMLElement(this);
83     if (element->fastHasAttribute(formAttr))
84         resetFormAttributeTargetObserver();
85 }
86
87 void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
88 {
89     HTMLElement* element = toHTMLElement(this);
90     if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
91         m_formAttributeTargetObserver = nullptr;
92     // If the form and element are both in the same tree, preserve the connection to the form.
93     // Otherwise, null out our form and remove ourselves from the form's list of elements.
94     if (m_form && element->highestAncestor() != m_form->highestAncestor())
95         setForm(0);
96 }
97
98 HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element, HTMLFormElement* currentAssociatedForm)
99 {
100     const AtomicString& formId(element->fastGetAttribute(formAttr));
101     if (!formId.isNull() && element->inDocument()) {
102         // The HTML5 spec says that the element should be associated with
103         // the first element in the document to have an ID that equal to
104         // the value of form attribute, so we put the result of
105         // treeScope()->getElementById() over the given element.
106         HTMLFormElement* newForm = 0;
107         Element* newFormCandidate = element->treeScope()->getElementById(formId);
108         if (newFormCandidate && newFormCandidate->hasTagName(formTag))
109             newForm = static_cast<HTMLFormElement*>(newFormCandidate);
110         return newForm;
111     }
112
113     if (!currentAssociatedForm)
114         return element->findFormAncestor();
115
116     return currentAssociatedForm;
117 }
118
119 void FormAssociatedElement::formRemovedFromTree(const Node* formRoot)
120 {
121     ASSERT(m_form);
122     if (toHTMLElement(this)->highestAncestor() != formRoot)
123         setForm(0);
124 }
125
126 void FormAssociatedElement::setForm(HTMLFormElement* newForm)
127 {
128     if (m_form == newForm)
129         return;
130     willChangeForm();
131     if (m_form)
132         m_form->removeFormElement(this);
133     m_form = newForm;
134     if (m_form)
135         m_form->registerFormElement(this);
136     didChangeForm();
137 }
138
139 void FormAssociatedElement::willChangeForm()
140 {
141 }
142
143 void FormAssociatedElement::didChangeForm()
144 {
145 }
146
147 void FormAssociatedElement::formWillBeDestroyed()
148 {
149     ASSERT(m_form);
150     if (!m_form)
151         return;
152     willChangeForm();
153     m_form = 0;
154     didChangeForm();
155 }
156
157 void FormAssociatedElement::resetFormOwner()
158 {
159     setForm(findAssociatedForm(toHTMLElement(this), m_form));
160 }
161
162 void FormAssociatedElement::formAttributeChanged()
163 {
164     HTMLElement* element = toHTMLElement(this);
165     if (!element->fastHasAttribute(formAttr)) {
166         // The form attribute removed. We need to reset form owner here.
167         setForm(element->findFormAncestor());
168         m_formAttributeTargetObserver = nullptr;
169     } else {
170         resetFormOwner();
171         resetFormAttributeTargetObserver();
172     }
173 }
174
175 bool FormAssociatedElement::customError() const
176 {
177     const HTMLElement* element = toHTMLElement(this);
178     return element->willValidate() && !m_customValidationMessage.isEmpty();
179 }
180
181 bool FormAssociatedElement::patternMismatch() const
182 {
183     return false;
184 }
185
186 bool FormAssociatedElement::rangeOverflow() const
187 {
188     return false;
189 }
190
191 bool FormAssociatedElement::rangeUnderflow() const
192 {
193     return false;
194 }
195
196 bool FormAssociatedElement::stepMismatch() const
197 {
198     return false;
199 }
200
201 bool FormAssociatedElement::tooLong() const
202 {
203     return false;
204 }
205
206 bool FormAssociatedElement::typeMismatch() const
207 {
208     return false;
209 }
210
211 bool FormAssociatedElement::valid() const
212 {
213     bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
214         || tooLong() || patternMismatch() || valueMissing() || customError();
215     return !someError;
216 }
217
218 bool FormAssociatedElement::valueMissing() const
219 {
220     return false;
221 }
222
223 String FormAssociatedElement::customValidationMessage() const
224 {
225     return m_customValidationMessage;
226 }
227
228 String FormAssociatedElement::validationMessage() const
229 {
230     return customError() ? m_customValidationMessage : String();
231 }
232
233 void FormAssociatedElement::setCustomValidity(const String& error)
234 {
235     m_customValidationMessage = error;
236 }
237
238 void FormAssociatedElement::resetFormAttributeTargetObserver()
239 {
240     m_formAttributeTargetObserver = FormAttributeTargetObserver::create(toHTMLElement(this)->fastGetAttribute(formAttr), this);
241 }
242
243 void FormAssociatedElement::formAttributeTargetChanged()
244 {
245     resetFormOwner();
246 }
247
248 const AtomicString& FormAssociatedElement::name() const
249 {
250     const AtomicString& name = toHTMLElement(this)->getNameAttribute();
251     return name.isNull() ? emptyAtom : name;
252 }
253
254 bool FormAssociatedElement::isFormControlElementWithState() const
255 {
256     return false;
257 }
258
259 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
260 {
261     if (associatedElement->isFormControlElement())
262         return static_cast<const HTMLFormControlElement*>(associatedElement);
263     // Assumes the element is an HTMLObjectElement
264     const HTMLElement* element = static_cast<const HTMLObjectElement*>(associatedElement);
265     ASSERT(element->hasTagName(objectTag));
266     return element;
267 }
268
269 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
270 {
271     return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
272 }
273
274 PassOwnPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
275 {
276     return adoptPtr(new FormAttributeTargetObserver(id, element));
277 }
278
279 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
280     : IdTargetObserver(toHTMLElement(element)->treeScope()->idTargetObserverRegistry(), id)
281     , m_element(element)
282 {
283 }
284
285 void FormAttributeTargetObserver::idTargetChanged()
286 {
287     m_element->formAttributeTargetChanged();
288 }
289
290 } // namespace Webcore