• 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 "HTMLFormControlElement.h"
27 
28 #include "ChromeClient.h"
29 #include "Document.h"
30 #include "EventHandler.h"
31 #include "EventNames.h"
32 #include "Frame.h"
33 #include "HTMLFormElement.h"
34 #include "HTMLInputElement.h"
35 #include "HTMLNames.h"
36 #include "HTMLParser.h"
37 #include "HTMLTokenizer.h"
38 #include "MappedAttribute.h"
39 #include "Page.h"
40 #include "RenderBox.h"
41 #include "RenderTheme.h"
42 #include "ValidityState.h"
43 
44 namespace WebCore {
45 
46 using namespace HTMLNames;
47 
HTMLFormControlElement(const QualifiedName & tagName,Document * doc,HTMLFormElement * f)48 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
49     : HTMLElement(tagName, doc)
50     , m_form(f)
51     , m_disabled(false)
52     , m_readOnly(false)
53     , m_valueMatchesRenderer(false)
54 {
55     if (!m_form)
56         m_form = findFormAncestor();
57     if (m_form)
58         m_form->registerFormElement(this);
59 }
60 
~HTMLFormControlElement()61 HTMLFormControlElement::~HTMLFormControlElement()
62 {
63     if (m_form)
64         m_form->removeFormElement(this);
65 }
66 
validity()67 ValidityState* HTMLFormControlElement::validity()
68 {
69     if (!m_validityState)
70         m_validityState = ValidityState::create(this);
71 
72     return m_validityState.get();
73 }
74 
parseMappedAttribute(MappedAttribute * attr)75 void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr)
76 {
77     if (attr->name() == nameAttr) {
78         // Do nothing.
79     } else if (attr->name() == disabledAttr) {
80         bool oldDisabled = m_disabled;
81         m_disabled = !attr->isNull();
82         if (oldDisabled != m_disabled) {
83             setNeedsStyleRecalc();
84             if (renderer() && renderer()->style()->hasAppearance())
85                 renderer()->theme()->stateChanged(renderer(), EnabledState);
86         }
87     } else if (attr->name() == readonlyAttr) {
88         bool oldReadOnly = m_readOnly;
89         m_readOnly = !attr->isNull();
90         if (oldReadOnly != m_readOnly) {
91             setNeedsStyleRecalc();
92             if (renderer() && renderer()->style()->hasAppearance())
93                 renderer()->theme()->stateChanged(renderer(), ReadOnlyState);
94         }
95     } else
96         HTMLElement::parseMappedAttribute(attr);
97 }
98 
attach()99 void HTMLFormControlElement::attach()
100 {
101     ASSERT(!attached());
102 
103     HTMLElement::attach();
104 
105     // The call to updateFromElement() needs to go after the call through
106     // to the base class's attach() because that can sometimes do a close
107     // on the renderer.
108     if (renderer())
109         renderer()->updateFromElement();
110 
111     // Focus the element if it should honour its autofocus attribute.
112     // We have to determine if the element is a TextArea/Input/Button/Select,
113     // if input type hidden ignore autofocus. So if disabled or readonly.
114     bool isInputTypeHidden = false;
115     if (hasTagName(inputTag))
116         isInputTypeHidden = static_cast<HTMLInputElement*>(this)->isInputTypeHidden();
117 
118     if (autofocus() && renderer() && !document()->ignoreAutofocus() && !isReadOnlyFormControl() &&
119             ((hasTagName(inputTag) && !isInputTypeHidden) || hasTagName(selectTag) ||
120               hasTagName(buttonTag) || hasTagName(textareaTag)))
121          focus();
122 }
123 
insertedIntoTree(bool deep)124 void HTMLFormControlElement::insertedIntoTree(bool deep)
125 {
126     if (!m_form) {
127         // This handles the case of a new form element being created by
128         // JavaScript and inserted inside a form.  In the case of the parser
129         // setting a form, we will already have a non-null value for m_form,
130         // and so we don't need to do anything.
131         m_form = findFormAncestor();
132         if (m_form)
133             m_form->registerFormElement(this);
134         else
135             document()->checkedRadioButtons().addButton(this);
136     }
137 
138     HTMLElement::insertedIntoTree(deep);
139 }
140 
findRoot(Node * n)141 static inline Node* findRoot(Node* n)
142 {
143     Node* root = n;
144     for (; n; n = n->parentNode())
145         root = n;
146     return root;
147 }
148 
removedFromTree(bool deep)149 void HTMLFormControlElement::removedFromTree(bool deep)
150 {
151     // If the form and element are both in the same tree, preserve the connection to the form.
152     // Otherwise, null out our form and remove ourselves from the form's list of elements.
153     HTMLParser* parser = 0;
154     if (Tokenizer* tokenizer = document()->tokenizer())
155         if (tokenizer->isHTMLTokenizer())
156             parser = static_cast<HTMLTokenizer*>(tokenizer)->htmlParser();
157 
158     if (m_form && !(parser && parser->isHandlingResidualStyleAcrossBlocks()) && findRoot(this) != findRoot(m_form)) {
159         m_form->removeFormElement(this);
160         m_form = 0;
161     }
162 
163     HTMLElement::removedFromTree(deep);
164 }
165 
formControlName() const166 const AtomicString& HTMLFormControlElement::formControlName() const
167 {
168     const AtomicString& n = getAttribute(nameAttr);
169     return n.isNull() ? emptyAtom : n;
170 }
171 
setName(const AtomicString & value)172 void HTMLFormControlElement::setName(const AtomicString &value)
173 {
174     setAttribute(nameAttr, value);
175 }
176 
dispatchFormControlChangeEvent()177 void HTMLFormControlElement::dispatchFormControlChangeEvent()
178 {
179     dispatchEvent(eventNames().changeEvent, true, false);
180 }
181 
disabled() const182 bool HTMLFormControlElement::disabled() const
183 {
184     return m_disabled;
185 }
186 
setDisabled(bool b)187 void HTMLFormControlElement::setDisabled(bool b)
188 {
189     setAttribute(disabledAttr, b ? "" : 0);
190 }
191 
setReadOnly(bool b)192 void HTMLFormControlElement::setReadOnly(bool b)
193 {
194     setAttribute(readonlyAttr, b ? "" : 0);
195 }
196 
autofocus() const197 bool HTMLFormControlElement::autofocus() const
198 {
199     return hasAttribute(autofocusAttr);
200 }
201 
setAutofocus(bool b)202 void HTMLFormControlElement::setAutofocus(bool b)
203 {
204     setAttribute(autofocusAttr, b ? "autofocus" : 0);
205 }
206 
required() const207 bool HTMLFormControlElement::required() const
208 {
209     return hasAttribute(requiredAttr);
210 }
211 
setRequired(bool b)212 void HTMLFormControlElement::setRequired(bool b)
213 {
214     setAttribute(requiredAttr, b ? "required" : 0);
215 }
216 
recalcStyle(StyleChange change)217 void HTMLFormControlElement::recalcStyle(StyleChange change)
218 {
219     HTMLElement::recalcStyle(change);
220 
221     if (renderer())
222         renderer()->updateFromElement();
223 }
224 
isFocusable() const225 bool HTMLFormControlElement::isFocusable() const
226 {
227     if (disabled() || !renderer() ||
228         (renderer()->style() && renderer()->style()->visibility() != VISIBLE) ||
229         !renderer()->isBox() || toRenderBox(renderer())->size().isEmpty())
230         return false;
231     return true;
232 }
233 
isKeyboardFocusable(KeyboardEvent * event) const234 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
235 {
236     if (isFocusable())
237         if (document()->frame())
238             return document()->frame()->eventHandler()->tabsToAllControls(event);
239     return false;
240 }
241 
isMouseFocusable() const242 bool HTMLFormControlElement::isMouseFocusable() const
243 {
244 #if PLATFORM(GTK)
245     return HTMLElement::isMouseFocusable();
246 #else
247     return false;
248 #endif
249 }
250 
tabIndex() const251 short HTMLFormControlElement::tabIndex() const
252 {
253     // Skip the supportsFocus check in HTMLElement.
254     return Element::tabIndex();
255 }
256 
willValidate() const257 bool HTMLFormControlElement::willValidate() const
258 {
259     // FIXME: Implementation shall be completed with these checks:
260     //      The control does not have a repetition template as an ancestor.
261     //      The control does not have a datalist element as an ancestor.
262     //      The control is not an output element.
263     return form() && name().length() && !disabled() && !isReadOnlyFormControl();
264 }
265 
setCustomValidity(const String & error)266 void HTMLFormControlElement::setCustomValidity(const String& error)
267 {
268     validity()->setCustomErrorMessage(error);
269 }
270 
dispatchFocusEvent()271 void HTMLFormControlElement::dispatchFocusEvent()
272 {
273     if (document()->frame() && document()->frame()->page())
274         document()->frame()->page()->chrome()->client()->formDidFocus(this);
275 
276     HTMLElement::dispatchFocusEvent();
277 }
278 
dispatchBlurEvent()279 void HTMLFormControlElement::dispatchBlurEvent()
280 {
281     if (document()->frame() && document()->frame()->page())
282         document()->frame()->page()->chrome()->client()->formDidBlur(this);
283 
284     HTMLElement::dispatchBlurEvent();
285 }
286 
supportsFocus() const287 bool HTMLFormControlElement::supportsFocus() const
288 {
289     return isFocusable() || (!disabled() && !document()->haveStylesheetsLoaded());
290 }
291 
virtualForm() const292 HTMLFormElement* HTMLFormControlElement::virtualForm() const
293 {
294     return m_form;
295 }
296 
removeFromForm()297 void HTMLFormControlElement::removeFromForm()
298 {
299     if (!m_form)
300         return;
301     m_form->removeFormElement(this);
302     m_form = 0;
303 }
304 
HTMLFormControlElementWithState(const QualifiedName & tagName,Document * doc,HTMLFormElement * f)305 HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
306     : HTMLFormControlElement(tagName, doc, f)
307 {
308     document()->registerFormElementWithState(this);
309 }
310 
~HTMLFormControlElementWithState()311 HTMLFormControlElementWithState::~HTMLFormControlElementWithState()
312 {
313     document()->unregisterFormElementWithState(this);
314 }
315 
willMoveToNewOwnerDocument()316 void HTMLFormControlElementWithState::willMoveToNewOwnerDocument()
317 {
318     document()->unregisterFormElementWithState(this);
319     HTMLFormControlElement::willMoveToNewOwnerDocument();
320 }
321 
didMoveToNewOwnerDocument()322 void HTMLFormControlElementWithState::didMoveToNewOwnerDocument()
323 {
324     document()->registerFormElementWithState(this);
325     HTMLFormControlElement::didMoveToNewOwnerDocument();
326 }
327 
finishParsingChildren()328 void HTMLFormControlElementWithState::finishParsingChildren()
329 {
330     HTMLFormControlElement::finishParsingChildren();
331     Document* doc = document();
332     if (doc->hasStateForNewFormElements()) {
333         String state;
334         if (doc->takeStateForFormElement(name().impl(), type().impl(), state))
335             restoreFormControlState(state);
336     }
337 }
338 
339 } // namespace Webcore
340