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 "core/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 : public IdTargetObserver {
40 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
41 public:
42 static PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*);
43 virtual void trace(Visitor*) OVERRIDE;
44 virtual void idTargetChanged() OVERRIDE;
45
46 private:
47 FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*);
48
49 RawPtrWillBeMember<FormAssociatedElement> m_element;
50 };
51
FormAssociatedElement()52 FormAssociatedElement::FormAssociatedElement()
53 : m_formWasSetByParser(false)
54 {
55 }
56
~FormAssociatedElement()57 FormAssociatedElement::~FormAssociatedElement()
58 {
59 // We can't call setForm here because it contains virtual calls.
60 }
61
trace(Visitor * visitor)62 void FormAssociatedElement::trace(Visitor* visitor)
63 {
64 visitor->trace(m_formAttributeTargetObserver);
65 visitor->trace(m_form);
66 visitor->trace(m_validityState);
67 }
68
validity()69 ValidityState* FormAssociatedElement::validity()
70 {
71 if (!m_validityState)
72 m_validityState = ValidityState::create(this);
73
74 return m_validityState.get();
75 }
76
didMoveToNewDocument(Document & oldDocument)77 void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument)
78 {
79 HTMLElement* element = toHTMLElement(this);
80 if (element->fastHasAttribute(formAttr))
81 setFormAttributeTargetObserver(nullptr);
82 }
83
insertedInto(ContainerNode * insertionPoint)84 void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
85 {
86 if (!m_formWasSetByParser || insertionPoint->highestAncestorOrSelf() != m_form->highestAncestorOrSelf())
87 resetFormOwner();
88
89 if (!insertionPoint->inDocument())
90 return;
91
92 HTMLElement* element = toHTMLElement(this);
93 if (element->fastHasAttribute(formAttr))
94 resetFormAttributeTargetObserver();
95 }
96
removedFrom(ContainerNode * insertionPoint)97 void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
98 {
99 HTMLElement* element = toHTMLElement(this);
100 if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
101 setFormAttributeTargetObserver(nullptr);
102 // If the form and element are both in the same tree, preserve the connection to the form.
103 // Otherwise, null out our form and remove ourselves from the form's list of elements.
104 if (m_form && element->highestAncestorOrSelf() != m_form->highestAncestorOrSelf())
105 resetFormOwner();
106 }
107
findAssociatedForm(const HTMLElement * element)108 HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element)
109 {
110 const AtomicString& formId(element->fastGetAttribute(formAttr));
111 // 3. If the element is reassociateable, has a form content attribute, and
112 // is itself in a Document, then run these substeps:
113 if (!formId.isNull() && element->inDocument()) {
114 // 3.1. If the first element in the Document to have an ID that is
115 // case-sensitively equal to the element's form content attribute's
116 // value is a form element, then associate the form-associated element
117 // with that form element.
118 // 3.2. Abort the "reset the form owner" steps.
119 Element* newFormCandidate = element->treeScope().getElementById(formId);
120 return isHTMLFormElement(newFormCandidate) ? toHTMLFormElement(newFormCandidate) : 0;
121 }
122 // 4. Otherwise, if the form-associated element in question has an ancestor
123 // form element, then associate the form-associated element with the nearest
124 // such ancestor form element.
125 return element->findFormAncestor();
126 }
127
formRemovedFromTree(const Node & formRoot)128 void FormAssociatedElement::formRemovedFromTree(const Node& formRoot)
129 {
130 ASSERT(m_form);
131 if (toHTMLElement(this)->highestAncestorOrSelf() == formRoot)
132 return;
133 resetFormOwner();
134 }
135
associateByParser(HTMLFormElement * form)136 void FormAssociatedElement::associateByParser(HTMLFormElement* form)
137 {
138 if (form && form->inDocument()) {
139 m_formWasSetByParser = true;
140 setForm(form);
141 form->didAssociateByParser();
142 }
143 }
144
setForm(HTMLFormElement * newForm)145 void FormAssociatedElement::setForm(HTMLFormElement* newForm)
146 {
147 if (m_form.get() == newForm)
148 return;
149 willChangeForm();
150 if (m_form)
151 m_form->disassociate(*this);
152 if (newForm) {
153 #if ENABLE(OILPAN)
154 m_form = newForm;
155 #else
156 m_form = newForm->createWeakPtr();
157 #endif
158 m_form->associate(*this);
159 } else {
160 #if ENABLE(OILPAN)
161 m_form = nullptr;
162 #else
163 m_form = WeakPtr<HTMLFormElement>();
164 #endif
165 }
166 didChangeForm();
167 }
168
willChangeForm()169 void FormAssociatedElement::willChangeForm()
170 {
171 }
172
didChangeForm()173 void FormAssociatedElement::didChangeForm()
174 {
175 }
176
resetFormOwner()177 void FormAssociatedElement::resetFormOwner()
178 {
179 m_formWasSetByParser = false;
180 HTMLElement* element = toHTMLElement(this);
181 const AtomicString& formId(element->fastGetAttribute(formAttr));
182 HTMLFormElement* nearestForm = element->findFormAncestor();
183 // 1. If the element's form owner is not null, and either the element is not
184 // reassociateable or its form content attribute is not present, and the
185 // element's form owner is its nearest form element ancestor after the
186 // change to the ancestor chain, then do nothing, and abort these steps.
187 if (m_form && formId.isNull() && m_form.get() == nearestForm)
188 return;
189
190 HTMLFormElement* originalForm = m_form.get();
191 setForm(findAssociatedForm(element));
192 // FIXME: Move didAssociateFormControl call to didChangeForm or
193 // HTMLFormElement::associate.
194 if (m_form && m_form.get() != originalForm && m_form->inDocument())
195 element->document().didAssociateFormControl(element);
196 }
197
formAttributeChanged()198 void FormAssociatedElement::formAttributeChanged()
199 {
200 resetFormOwner();
201 resetFormAttributeTargetObserver();
202 }
203
customError() const204 bool FormAssociatedElement::customError() const
205 {
206 const HTMLElement* element = toHTMLElement(this);
207 return element->willValidate() && !m_customValidationMessage.isEmpty();
208 }
209
hasBadInput() const210 bool FormAssociatedElement::hasBadInput() const
211 {
212 return false;
213 }
214
patternMismatch() const215 bool FormAssociatedElement::patternMismatch() const
216 {
217 return false;
218 }
219
rangeOverflow() const220 bool FormAssociatedElement::rangeOverflow() const
221 {
222 return false;
223 }
224
rangeUnderflow() const225 bool FormAssociatedElement::rangeUnderflow() const
226 {
227 return false;
228 }
229
stepMismatch() const230 bool FormAssociatedElement::stepMismatch() const
231 {
232 return false;
233 }
234
tooLong() const235 bool FormAssociatedElement::tooLong() const
236 {
237 return false;
238 }
239
typeMismatch() const240 bool FormAssociatedElement::typeMismatch() const
241 {
242 return false;
243 }
244
valid() const245 bool FormAssociatedElement::valid() const
246 {
247 bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
248 || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
249 return !someError;
250 }
251
valueMissing() const252 bool FormAssociatedElement::valueMissing() const
253 {
254 return false;
255 }
256
customValidationMessage() const257 String FormAssociatedElement::customValidationMessage() const
258 {
259 return m_customValidationMessage;
260 }
261
validationMessage() const262 String FormAssociatedElement::validationMessage() const
263 {
264 return customError() ? m_customValidationMessage : String();
265 }
266
setCustomValidity(const String & error)267 void FormAssociatedElement::setCustomValidity(const String& error)
268 {
269 m_customValidationMessage = error;
270 }
271
setFormAttributeTargetObserver(PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> newObserver)272 void FormAssociatedElement::setFormAttributeTargetObserver(PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> newObserver)
273 {
274 if (m_formAttributeTargetObserver)
275 m_formAttributeTargetObserver->unregister();
276 m_formAttributeTargetObserver = newObserver;
277 }
278
resetFormAttributeTargetObserver()279 void FormAssociatedElement::resetFormAttributeTargetObserver()
280 {
281 HTMLElement* element = toHTMLElement(this);
282 const AtomicString& formId(element->fastGetAttribute(formAttr));
283 if (!formId.isNull() && element->inDocument())
284 setFormAttributeTargetObserver(FormAttributeTargetObserver::create(formId, this));
285 else
286 setFormAttributeTargetObserver(nullptr);
287 }
288
formAttributeTargetChanged()289 void FormAssociatedElement::formAttributeTargetChanged()
290 {
291 resetFormOwner();
292 }
293
name() const294 const AtomicString& FormAssociatedElement::name() const
295 {
296 const AtomicString& name = toHTMLElement(this)->getNameAttribute();
297 return name.isNull() ? emptyAtom : name;
298 }
299
isFormControlElementWithState() const300 bool FormAssociatedElement::isFormControlElementWithState() const
301 {
302 return false;
303 }
304
toHTMLElement(const FormAssociatedElement & associatedElement)305 const HTMLElement& toHTMLElement(const FormAssociatedElement& associatedElement)
306 {
307 if (associatedElement.isFormControlElement())
308 return toHTMLFormControlElement(associatedElement);
309 // Assumes the element is an HTMLObjectElement
310 return toHTMLObjectElement(associatedElement);
311 }
312
toHTMLElement(const FormAssociatedElement * associatedElement)313 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
314 {
315 ASSERT(associatedElement);
316 return &toHTMLElement(*associatedElement);
317 }
318
toHTMLElement(FormAssociatedElement * associatedElement)319 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
320 {
321 return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
322 }
323
toHTMLElement(FormAssociatedElement & associatedElement)324 HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement)
325 {
326 return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement)));
327 }
328
create(const AtomicString & id,FormAssociatedElement * element)329 PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
330 {
331 return adoptPtrWillBeNoop(new FormAttributeTargetObserver(id, element));
332 }
333
FormAttributeTargetObserver(const AtomicString & id,FormAssociatedElement * element)334 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
335 : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id)
336 , m_element(element)
337 {
338 }
339
trace(Visitor * visitor)340 void FormAttributeTargetObserver::trace(Visitor* visitor)
341 {
342 visitor->trace(m_element);
343 IdTargetObserver::trace(visitor);
344 }
345
idTargetChanged()346 void FormAttributeTargetObserver::idTargetChanged()
347 {
348 m_element->formAttributeTargetChanged();
349 }
350
351 } // namespace Webcore
352