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->document()->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 // document()->getElementById() over the given element.
140 Element* firstElement = element->document()->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