• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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