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