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 "HTMLFormControlElement.h"
29 #include "HTMLFormElement.h"
30 #include "HTMLNames.h"
31 #include "HTMLObjectElement.h"
32 #include "ValidityState.h"
33 
34 namespace WebCore {
35 
36 using namespace HTMLNames;
37 
FormAssociatedElement(HTMLFormElement * form)38 FormAssociatedElement::FormAssociatedElement(HTMLFormElement* form)
39     : m_form(form)
40 {
41 }
42 
~FormAssociatedElement()43 FormAssociatedElement::~FormAssociatedElement()
44 {
45 }
46 
validity()47 ValidityState* FormAssociatedElement::validity()
48 {
49     if (!m_validityState)
50         m_validityState = ValidityState::create(this);
51 
52     return m_validityState.get();
53 }
54 
willMoveToNewOwnerDocument()55 void FormAssociatedElement::willMoveToNewOwnerDocument()
56 {
57     HTMLElement* element = toHTMLElement(this);
58     if (element->fastHasAttribute(formAttr))
59         element->document()->unregisterFormElementWithFormAttribute(this);
60 }
61 
insertedIntoDocument()62 void FormAssociatedElement::insertedIntoDocument()
63 {
64     HTMLElement* element = toHTMLElement(this);
65     if (element->fastHasAttribute(formAttr))
66         element->document()->registerFormElementWithFormAttribute(this);
67 }
68 
removedFromDocument()69 void FormAssociatedElement::removedFromDocument()
70 {
71     HTMLElement* element = toHTMLElement(this);
72     if (element->fastHasAttribute(formAttr))
73         element->document()->unregisterFormElementWithFormAttribute(this);
74 }
75 
insertedIntoTree()76 void FormAssociatedElement::insertedIntoTree()
77 {
78     HTMLElement* element = toHTMLElement(this);
79     if (element->fastHasAttribute(formAttr)) {
80         Element* formElement = element->treeScope()->getElementById(element->fastGetAttribute(formAttr));
81         if (formElement && formElement->hasTagName(formTag)) {
82             if (m_form)
83                 m_form->removeFormElement(this);
84             m_form = static_cast<HTMLFormElement*>(formElement);
85             m_form->registerFormElement(this);
86         }
87     }
88     if (!m_form) {
89         // This handles the case of a new form element being created by
90         // JavaScript and inserted inside a form.  In the case of the parser
91         // setting a form, we will already have a non-null value for m_form,
92         // and so we don't need to do anything.
93         m_form = element->findFormAncestor();
94         if (m_form)
95             m_form->registerFormElement(this);
96     }
97 }
98 
findRoot(Node * n)99 static inline Node* findRoot(Node* n)
100 {
101     Node* root = n;
102     for (; n; n = n->parentNode())
103         root = n;
104     return root;
105 }
106 
removedFromTree()107 void FormAssociatedElement::removedFromTree()
108 {
109     HTMLElement* element = toHTMLElement(this);
110 
111     // If the form and element are both in the same tree, preserve the connection to the form.
112     // Otherwise, null out our form and remove ourselves from the form's list of elements.
113     if (m_form && findRoot(element) != findRoot(m_form))
114         removeFromForm();
115 }
116 
removeFromForm()117 void FormAssociatedElement::removeFromForm()
118 {
119     if (!m_form)
120         return;
121     m_form->removeFormElement(this);
122     m_form = 0;
123 }
124 
resetFormOwner(HTMLFormElement * form)125 void FormAssociatedElement::resetFormOwner(HTMLFormElement* form)
126 {
127     HTMLElement* element = toHTMLElement(this);
128     const AtomicString& formId(element->fastGetAttribute(formAttr));
129     if (m_form) {
130         if (formId.isNull())
131             return;
132         m_form->removeFormElement(this);
133     }
134     m_form = 0;
135     if (!formId.isNull() && element->inDocument()) {
136         // The HTML5 spec says that the element should be associated with
137         // the first element in the document to have an ID that equal to
138         // the value of form attribute, so we put the result of
139         // treeScope()->getElementById() over the given element.
140         Element* firstElement = element->treeScope()->getElementById(formId);
141         if (firstElement && firstElement->hasTagName(formTag))
142             m_form = static_cast<HTMLFormElement*>(firstElement);
143         else
144             m_form = form;
145     } else
146         m_form = element->findFormAncestor();
147     if (m_form)
148         m_form->registerFormElement(this);
149 }
150 
formAttributeChanged()151 void FormAssociatedElement::formAttributeChanged()
152 {
153     HTMLElement* element = toHTMLElement(this);
154     if (!element->fastHasAttribute(formAttr)) {
155         // The form attribute removed. We need to reset form owner here.
156         if (m_form)
157             m_form->removeFormElement(this);
158         m_form = element->findFormAncestor();
159         if (m_form)
160             form()->registerFormElement(this);
161         element->document()->unregisterFormElementWithFormAttribute(this);
162     } else
163         resetFormOwner(0);
164 }
165 
toHTMLElement(const FormAssociatedElement * associatedElement)166 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
167 {
168     if (associatedElement->isFormControlElement())
169         return static_cast<const HTMLFormControlElement*>(associatedElement);
170     // Assumes the element is an HTMLObjectElement
171     const HTMLElement* element = static_cast<const HTMLObjectElement*>(associatedElement);
172     ASSERT(element->hasTagName(objectTag));
173     return element;
174 }
175 
toHTMLElement(FormAssociatedElement * associatedElement)176 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
177 {
178     return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
179 }
180 
181 } // namespace Webcore
182