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 "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
FormAssociatedElement()51 FormAssociatedElement::FormAssociatedElement()
52 : m_form(0)
53 {
54 }
55
~FormAssociatedElement()56 FormAssociatedElement::~FormAssociatedElement()
57 {
58 // We can't call setForm here because it contains virtual calls.
59 }
60
validity()61 ValidityState* FormAssociatedElement::validity()
62 {
63 if (!m_validityState)
64 m_validityState = ValidityState::create(this);
65
66 return m_validityState.get();
67 }
68
didMoveToNewDocument(Document & oldDocument)69 void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument)
70 {
71 HTMLElement* element = toHTMLElement(this);
72 if (element->fastHasAttribute(formAttr))
73 m_formAttributeTargetObserver = nullptr;
74 }
75
insertedInto(ContainerNode * insertionPoint)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
removedFrom(ContainerNode * insertionPoint)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
findAssociatedForm(const HTMLElement * element,HTMLFormElement * currentAssociatedForm)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
formRemovedFromTree(const Node * formRoot)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
setForm(HTMLFormElement * newForm)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
willChangeForm()143 void FormAssociatedElement::willChangeForm()
144 {
145 }
146
didChangeForm()147 void FormAssociatedElement::didChangeForm()
148 {
149 }
150
formWillBeDestroyed()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
resetFormOwner()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
formAttributeChanged()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
customError() const188 bool FormAssociatedElement::customError() const
189 {
190 const HTMLElement* element = toHTMLElement(this);
191 return element->willValidate() && !m_customValidationMessage.isEmpty();
192 }
193
hasBadInput() const194 bool FormAssociatedElement::hasBadInput() const
195 {
196 return false;
197 }
198
patternMismatch() const199 bool FormAssociatedElement::patternMismatch() const
200 {
201 return false;
202 }
203
rangeOverflow() const204 bool FormAssociatedElement::rangeOverflow() const
205 {
206 return false;
207 }
208
rangeUnderflow() const209 bool FormAssociatedElement::rangeUnderflow() const
210 {
211 return false;
212 }
213
stepMismatch() const214 bool FormAssociatedElement::stepMismatch() const
215 {
216 return false;
217 }
218
tooLong() const219 bool FormAssociatedElement::tooLong() const
220 {
221 return false;
222 }
223
typeMismatch() const224 bool FormAssociatedElement::typeMismatch() const
225 {
226 return false;
227 }
228
valid() const229 bool FormAssociatedElement::valid() const
230 {
231 bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
232 || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
233 return !someError;
234 }
235
valueMissing() const236 bool FormAssociatedElement::valueMissing() const
237 {
238 return false;
239 }
240
customValidationMessage() const241 String FormAssociatedElement::customValidationMessage() const
242 {
243 return m_customValidationMessage;
244 }
245
validationMessage() const246 String FormAssociatedElement::validationMessage() const
247 {
248 return customError() ? m_customValidationMessage : String();
249 }
250
setCustomValidity(const String & error)251 void FormAssociatedElement::setCustomValidity(const String& error)
252 {
253 m_customValidationMessage = error;
254 }
255
resetFormAttributeTargetObserver()256 void FormAssociatedElement::resetFormAttributeTargetObserver()
257 {
258 ASSERT(toHTMLElement(this)->inDocument());
259 m_formAttributeTargetObserver = FormAttributeTargetObserver::create(toHTMLElement(this)->fastGetAttribute(formAttr), this);
260 }
261
formAttributeTargetChanged()262 void FormAssociatedElement::formAttributeTargetChanged()
263 {
264 resetFormOwner();
265 }
266
name() const267 const AtomicString& FormAssociatedElement::name() const
268 {
269 const AtomicString& name = toHTMLElement(this)->getNameAttribute();
270 return name.isNull() ? emptyAtom : name;
271 }
272
isFormControlElementWithState() const273 bool FormAssociatedElement::isFormControlElementWithState() const
274 {
275 return false;
276 }
277
toHTMLElement(const FormAssociatedElement & associatedElement)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
toHTMLElement(const FormAssociatedElement * associatedElement)286 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
287 {
288 ASSERT(associatedElement);
289 return &toHTMLElement(*associatedElement);
290 }
291
toHTMLElement(FormAssociatedElement * associatedElement)292 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
293 {
294 return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
295 }
296
toHTMLElement(FormAssociatedElement & associatedElement)297 HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement)
298 {
299 return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement)));
300 }
301
create(const AtomicString & id,FormAssociatedElement * element)302 PassOwnPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
303 {
304 return adoptPtr(new FormAttributeTargetObserver(id, element));
305 }
306
FormAttributeTargetObserver(const AtomicString & id,FormAssociatedElement * element)307 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
308 : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id)
309 , m_element(element)
310 {
311 }
312
idTargetChanged()313 void FormAttributeTargetObserver::idTargetChanged()
314 {
315 m_element->formAttributeTargetChanged();
316 }
317
318 } // namespace Webcore
319