Implement HTMLFormElement#requestAutocomplete and associated events
[WebKit-https.git] / Source / WebCore / html / HTMLFormElement.cpp
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, 2008, 2009 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 "HTMLFormElement.h"
27
28 #include "Attribute.h"
29 #include "DOMFormData.h"
30 #include "DOMWindow.h"
31 #include "Document.h"
32 #include "Event.h"
33 #include "EventNames.h"
34 #include "FileList.h"
35 #include "FileSystem.h"
36 #include "FormController.h"
37 #include "FormData.h"
38 #include "FormDataList.h"
39 #include "FormState.h"
40 #include "Frame.h"
41 #include "FrameLoader.h"
42 #include "FrameLoaderClient.h"
43 #include "HTMLDocument.h"
44 #include "HTMLFormCollection.h"
45 #include "HTMLImageElement.h"
46 #include "HTMLInputElement.h"
47 #include "HTMLNames.h"
48 #include "MIMETypeRegistry.h"
49 #include "NodeRenderingContext.h"
50 #include "Page.h"
51 #include "RenderTextControl.h"
52 #include "ScriptEventListener.h"
53 #include "Settings.h"
54 #include "ValidityState.h"
55 #include <limits>
56
57 #if PLATFORM(WX)
58 #include <wx/defs.h>
59 #include <wx/filename.h>
60 #endif
61
62 using namespace std;
63
64 namespace WebCore {
65
66 using namespace HTMLNames;
67
68 HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* document)
69     : HTMLElement(tagName, document)
70     , m_associatedElementsBeforeIndex(0)
71     , m_associatedElementsAfterIndex(0)
72     , m_wasUserSubmitted(false)
73     , m_isSubmittingOrPreparingForSubmission(false)
74     , m_shouldSubmit(false)
75     , m_isInResetFunction(false)
76     , m_wasDemoted(false)
77 #if ENABLE(REQUEST_AUTOCOMPLETE)
78     , m_requestAutocompleteTimer(this, &HTMLFormElement::requestAutocompleteTimerFired)
79 #endif
80 {
81     ASSERT(hasTagName(formTag));
82 }
83
84 PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
85 {
86     return adoptRef(new HTMLFormElement(formTag, document));
87 }
88
89 PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
90 {
91     return adoptRef(new HTMLFormElement(tagName, document));
92 }
93
94 HTMLFormElement::~HTMLFormElement()
95 {
96     document()->formController()->willDeleteForm(this);
97     if (!shouldAutocomplete())
98         document()->unregisterForPageCacheSuspensionCallbacks(this);
99
100     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
101         m_associatedElements[i]->formWillBeDestroyed();
102     for (unsigned i = 0; i < m_imageElements.size(); ++i)
103         m_imageElements[i]->m_form = 0;
104 }
105
106 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
107 {
108     return document()->completeURL(url).protocolIs("https");
109 }
110
111 bool HTMLFormElement::rendererIsNeeded(const NodeRenderingContext& context)
112 {
113     if (!m_wasDemoted)
114         return HTMLElement::rendererIsNeeded(context);
115
116     ContainerNode* node = parentNode();
117     RenderObject* parentRenderer = node->renderer();
118     // FIXME: Shouldn't we also check for table caption (see |formIsTablePart| below).
119     bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
120         || (parentRenderer->isTableRow() && node->hasTagName(trTag))
121         || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
122         || (parentRenderer->isRenderTableCol() && node->hasTagName(colTag))
123         || (parentRenderer->isTableCell() && node->hasTagName(trTag));
124
125     if (!parentIsTableElementPart)
126         return true;
127
128     EDisplay display = context.style()->display();
129     bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
130         || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
131         || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
132         || display == TABLE_CAPTION;
133
134     return formIsTablePart;
135 }
136
137 Node::InsertionNotificationRequest HTMLFormElement::insertedInto(ContainerNode* insertionPoint)
138 {
139     HTMLElement::insertedInto(insertionPoint);
140     return InsertionDone;
141 }
142
143 static inline Node* findRoot(Node* n)
144 {
145     Node* root = n;
146     for (; n; n = n->parentNode())
147         root = n;
148     return root;
149 }
150
151 void HTMLFormElement::removedFrom(ContainerNode* insertionPoint)
152 {
153     Node* root = findRoot(this);
154     Vector<FormAssociatedElement*> associatedElements(m_associatedElements);
155     for (unsigned i = 0; i < associatedElements.size(); ++i)
156         associatedElements[i]->formRemovedFromTree(root);
157     HTMLElement::removedFrom(insertionPoint);
158 }
159
160 void HTMLFormElement::handleLocalEvents(Event* event)
161 {
162     Node* targetNode = event->target()->toNode();
163     if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
164         event->stopPropagation();
165         return;
166     }
167     HTMLElement::handleLocalEvents(event);
168 }
169
170 unsigned HTMLFormElement::length() const
171 {
172     unsigned len = 0;
173     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
174         if (m_associatedElements[i]->isEnumeratable())
175             ++len;
176     return len;
177 }
178
179 Node* HTMLFormElement::item(unsigned index)
180 {
181     return elements()->item(index);
182 }
183
184 void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
185 {
186     int submissionTriggerCount = 0;
187     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
188         FormAssociatedElement* formAssociatedElement = m_associatedElements[i];
189         if (!formAssociatedElement->isFormControlElement())
190             continue;
191         HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(formAssociatedElement);
192         if (formElement->isSuccessfulSubmitButton()) {
193             if (formElement->renderer()) {
194                 formElement->dispatchSimulatedClick(event);
195                 return;
196             }
197         } else if (formElement->canTriggerImplicitSubmission())
198             ++submissionTriggerCount;
199     }
200     if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
201         prepareForSubmission(event);
202 }
203
204 static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
205 {
206     Node* targetNode = event->target()->toNode();
207     if (!targetNode || !targetNode->isElementNode())
208         return 0;
209     Element* targetElement = static_cast<Element*>(targetNode);
210     if (!targetElement->isFormControlElement())
211         return 0;
212     return static_cast<HTMLFormControlElement*>(targetElement);
213 }
214
215 bool HTMLFormElement::validateInteractively(Event* event)
216 {
217     ASSERT(event);
218     if (!document()->page() || !document()->page()->settings()->interactiveFormValidationEnabled() || noValidate())
219         return true;
220
221     HTMLFormControlElement* submitElement = submitElementFromEvent(event);
222     if (submitElement && submitElement->formNoValidate())
223         return true;
224
225     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
226         if (m_associatedElements[i]->isFormControlElement())
227             static_cast<HTMLFormControlElement*>(m_associatedElements[i])->hideVisibleValidationMessage();
228     }
229
230     Vector<RefPtr<FormAssociatedElement> > unhandledInvalidControls;
231     if (!checkInvalidControlsAndCollectUnhandled(unhandledInvalidControls))
232         return true;
233     // Because the form has invalid controls, we abort the form submission and
234     // show a validation message on a focusable form control.
235
236     // Needs to update layout now because we'd like to call isFocusable(), which
237     // has !renderer()->needsLayout() assertion.
238     document()->updateLayoutIgnorePendingStylesheets();
239
240     RefPtr<HTMLFormElement> protector(this);
241     // Focus on the first focusable control and show a validation message.
242     for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
243         FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
244         HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
245         if (unhandled->isFocusable() && unhandled->inDocument()) {
246             unhandled->scrollIntoViewIfNeeded(false);
247             unhandled->focus();
248             if (unhandled->isFormControlElement())
249                 static_cast<HTMLFormControlElement*>(unhandled)->updateVisibleValidationMessage();
250             break;
251         }
252     }
253     // Warn about all of unfocusable controls.
254     if (document()->frame()) {
255         for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
256             FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
257             HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
258             if (unhandled->isFocusable() && unhandled->inDocument())
259                 continue;
260             String message("An invalid form control with name='%name' is not focusable.");
261             message.replace("%name", unhandledAssociatedElement->name());
262             document()->addConsoleMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, document()->url().string());
263         }
264     }
265     return false;
266 }
267
268 bool HTMLFormElement::prepareForSubmission(Event* event)
269 {
270     Frame* frame = document()->frame();
271     if (m_isSubmittingOrPreparingForSubmission || !frame)
272         return m_isSubmittingOrPreparingForSubmission;
273
274     m_isSubmittingOrPreparingForSubmission = true;
275     m_shouldSubmit = false;
276
277     // Interactive validation must be done before dispatching the submit event.
278     if (!validateInteractively(event)) {
279         m_isSubmittingOrPreparingForSubmission = false;
280         return false;
281     }
282
283     StringPairVector controlNamesAndValues;
284     getTextFieldValues(controlNamesAndValues);
285     RefPtr<FormState> formState = FormState::create(this, controlNamesAndValues, document(), NotSubmittedByJavaScript);
286     frame->loader()->client()->dispatchWillSendSubmitEvent(formState.release());
287
288     if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)))
289         m_shouldSubmit = true;
290
291     m_isSubmittingOrPreparingForSubmission = false;
292
293     if (m_shouldSubmit)
294         submit(event, true, true, NotSubmittedByJavaScript);
295
296     return m_shouldSubmit;
297 }
298
299 void HTMLFormElement::submit()
300 {
301     submit(0, false, true, NotSubmittedByJavaScript);
302 }
303
304 void HTMLFormElement::submitFromJavaScript()
305 {
306     submit(0, false, ScriptController::processingUserGesture(), SubmittedByJavaScript);
307 }
308
309 void HTMLFormElement::getTextFieldValues(StringPairVector& fieldNamesAndValues) const
310 {
311     ASSERT_ARG(fieldNamesAndValues, fieldNamesAndValues.isEmpty());
312
313     fieldNamesAndValues.reserveCapacity(m_associatedElements.size());
314     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
315         FormAssociatedElement* control = m_associatedElements[i];
316         HTMLElement* element = toHTMLElement(control);
317         if (!element->hasLocalName(inputTag))
318             continue;
319
320         HTMLInputElement* input = static_cast<HTMLInputElement*>(control);
321         if (!input->isTextField())
322             continue;
323
324         fieldNamesAndValues.append(make_pair(input->name().string(), input->value()));
325     }
326 }
327
328 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
329 {
330     FrameView* view = document()->view();
331     Frame* frame = document()->frame();
332     if (!view || !frame)
333         return;
334
335     if (m_isSubmittingOrPreparingForSubmission) {
336         m_shouldSubmit = true;
337         return;
338     }
339
340     m_isSubmittingOrPreparingForSubmission = true;
341     m_wasUserSubmitted = processingUserGesture;
342
343     HTMLFormControlElement* firstSuccessfulSubmitButton = 0;
344     bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
345
346     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
347         FormAssociatedElement* associatedElement = m_associatedElements[i];
348         if (!associatedElement->isFormControlElement())
349             continue;
350         if (needButtonActivation) {
351             HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(associatedElement);
352             if (control->isActivatedSubmit())
353                 needButtonActivation = false;
354             else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
355                 firstSuccessfulSubmitButton = control;
356         }
357     }
358
359     if (needButtonActivation && firstSuccessfulSubmitButton)
360         firstSuccessfulSubmitButton->setActivatedSubmit(true);
361
362     bool lockHistory = !processingUserGesture;
363     frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, lockHistory, formSubmissionTrigger));
364
365     if (needButtonActivation && firstSuccessfulSubmitButton)
366         firstSuccessfulSubmitButton->setActivatedSubmit(false);
367
368     m_shouldSubmit = false;
369     m_isSubmittingOrPreparingForSubmission = false;
370 }
371
372 void HTMLFormElement::reset()
373 {
374     Frame* frame = document()->frame();
375     if (m_isInResetFunction || !frame)
376         return;
377
378     m_isInResetFunction = true;
379
380     if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
381         m_isInResetFunction = false;
382         return;
383     }
384
385     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
386         if (m_associatedElements[i]->isFormControlElement())
387             static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
388     }
389
390     m_isInResetFunction = false;
391 }
392
393 #if ENABLE(REQUEST_AUTOCOMPLETE)
394 void HTMLFormElement::requestAutocomplete()
395 {
396     Frame* frame = document()->frame();
397     if (!frame)
398         return;
399
400     if (!shouldAutocomplete()) {
401         finishRequestAutocomplete(AutocompleteResultError);
402         return;
403     }
404
405     StringPairVector controlNamesAndValues;
406     getTextFieldValues(controlNamesAndValues);
407     RefPtr<FormState> formState = FormState::create(this, controlNamesAndValues, document(), SubmittedByJavaScript);
408     frame->loader()->client()->didRequestAutocomplete(formState.release());
409 }
410
411 void HTMLFormElement::finishRequestAutocomplete(AutocompleteResult result)
412 {
413     RefPtr<Event> event(Event::create(result == AutocompleteResultSuccess ? eventNames().autocompleteEvent : eventNames().autocompleteerrorEvent, false, false));
414     event->setTarget(this);
415     m_pendingAutocompleteEvents.append(event.release());
416
417     // Dispatch events later as this API is meant to work asynchronously in all situations and implementations.
418     if (!m_requestAutocompleteTimer.isActive())
419         m_requestAutocompleteTimer.startOneShot(0);
420 }
421
422 void HTMLFormElement::requestAutocompleteTimerFired(Timer<HTMLFormElement>*)
423 {
424     Vector<RefPtr<Event> > pendingEvents;
425     m_pendingAutocompleteEvents.swap(pendingEvents);
426     for (size_t i = 0; i < pendingEvents.size(); ++i)
427         dispatchEvent(pendingEvents[i].release());
428 }
429 #endif
430
431 void HTMLFormElement::parseAttribute(const Attribute& attribute)
432 {
433     if (attribute.name() == actionAttr)
434         m_attributes.parseAction(attribute.value());
435     else if (attribute.name() == targetAttr)
436         m_attributes.setTarget(attribute.value());
437     else if (attribute.name() == methodAttr)
438         m_attributes.updateMethodType(attribute.value());
439     else if (attribute.name() == enctypeAttr)
440         m_attributes.updateEncodingType(attribute.value());
441     else if (attribute.name() == accept_charsetAttr)
442         m_attributes.setAcceptCharset(attribute.value());
443     else if (attribute.name() == autocompleteAttr) {
444         if (!shouldAutocomplete())
445             document()->registerForPageCacheSuspensionCallbacks(this);
446         else
447             document()->unregisterForPageCacheSuspensionCallbacks(this);
448     } else if (attribute.name() == onsubmitAttr)
449         setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attribute));
450     else if (attribute.name() == onresetAttr)
451         setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attribute));
452 #if ENABLE(REQUEST_AUTOCOMPLETE)
453     else if (attribute.name() == onautocompleteAttr)
454         setAttributeEventListener(eventNames().autocompleteEvent, createAttributeEventListener(this, attribute));
455     else if (attribute.name() == onautocompleteerrorAttr)
456         setAttributeEventListener(eventNames().autocompleteerrorEvent, createAttributeEventListener(this, attribute));
457 #endif
458     else
459         HTMLElement::parseAttribute(attribute);
460 }
461
462 template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
463 {
464     size_t size = vec.size();
465     for (size_t i = 0; i != size; ++i)
466         if (vec[i] == item) {
467             vec.remove(i);
468             break;
469         }
470 }
471
472 unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element, unsigned rangeStart, unsigned rangeEnd)
473 {
474     if (m_associatedElements.isEmpty())
475         return 0;
476
477     ASSERT(rangeStart <= rangeEnd);
478
479     if (rangeStart == rangeEnd)
480         return rangeStart;
481
482     unsigned left = rangeStart;
483     unsigned right = rangeEnd - 1;
484     unsigned short position;
485
486     // Does binary search on m_associatedElements in order to find the index
487     // to be inserted.
488     while (left != right) {
489         unsigned middle = left + ((right - left) / 2);
490         ASSERT(middle < m_associatedElementsBeforeIndex || middle >= m_associatedElementsAfterIndex);
491         position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[middle]));
492         if (position & DOCUMENT_POSITION_FOLLOWING)
493             right = middle;
494         else
495             left = middle + 1;
496     }
497     
498     ASSERT(left < m_associatedElementsBeforeIndex || left >= m_associatedElementsAfterIndex);
499     position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[left]));
500     if (position & DOCUMENT_POSITION_FOLLOWING)
501         return left;
502     return left + 1;
503 }
504
505 unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElement)
506 {
507     HTMLElement* element = toHTMLElement(associatedElement);
508     // Treats separately the case where this element has the form attribute
509     // for performance consideration.
510     if (element->fastHasAttribute(formAttr)) {
511         unsigned short position = compareDocumentPosition(element);
512         if (position & DOCUMENT_POSITION_PRECEDING) {
513             ++m_associatedElementsBeforeIndex;
514             ++m_associatedElementsAfterIndex;
515             return HTMLFormElement::formElementIndexWithFormAttribute(element, 0, m_associatedElementsBeforeIndex - 1);
516         }
517         if (position & DOCUMENT_POSITION_FOLLOWING && !(position & DOCUMENT_POSITION_CONTAINED_BY))
518             return HTMLFormElement::formElementIndexWithFormAttribute(element, m_associatedElementsAfterIndex, m_associatedElements.size());
519     }
520
521     // Check for the special case where this element is the very last thing in
522     // the form's tree of children; we don't want to walk the entire tree in that
523     // common case that occurs during parsing; instead we'll just return a value
524     // that says "add this form element to the end of the array".
525     if (element->traverseNextNode(this)) {
526         unsigned i = m_associatedElementsBeforeIndex;
527         for (Node* node = this; node; node = node->traverseNextNode(this)) {
528             if (node == element) {
529                 ++m_associatedElementsAfterIndex;
530                 return i;
531             }
532             if (node->isHTMLElement()
533                     && (static_cast<Element*>(node)->isFormControlElement()
534                         || node->hasTagName(objectTag))
535                     && toHTMLElement(node)->form() == this)
536                 ++i;
537         }
538     }
539     return m_associatedElementsAfterIndex++;
540 }
541
542 void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
543 {
544     m_associatedElements.insert(formElementIndex(e), e);
545 }
546
547 void HTMLFormElement::removeFormElement(FormAssociatedElement* e)
548 {
549     unsigned index;
550     for (index = 0; index < m_associatedElements.size(); ++index) {
551         if (m_associatedElements[index] == e)
552             break;
553     }
554     ASSERT(index < m_associatedElements.size());
555     if (index < m_associatedElementsBeforeIndex)
556         --m_associatedElementsBeforeIndex;
557     if (index < m_associatedElementsAfterIndex)
558         --m_associatedElementsAfterIndex;
559     removeFromVector(m_associatedElements, e);
560 }
561
562 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const
563 {
564     return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribute);
565 }
566
567 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
568 {
569     ASSERT(m_imageElements.find(e) == notFound);
570     m_imageElements.append(e);
571 }
572
573 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
574 {
575     ASSERT(m_imageElements.find(e) != notFound);
576     removeFromVector(m_imageElements, e);
577 }
578
579 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
580 {
581     return ensureCachedHTMLCollection(FormControls);
582 }
583
584 String HTMLFormElement::name() const
585 {
586     return getNameAttribute();
587 }
588
589 bool HTMLFormElement::noValidate() const
590 {
591     return fastHasAttribute(novalidateAttr);
592 }
593
594 // FIXME: This function should be removed because it does not do the same thing as the
595 // JavaScript binding for action, which treats action as a URL attribute. Last time I
596 // (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
597 String HTMLFormElement::action() const
598 {
599     return getAttribute(actionAttr);
600 }
601
602 void HTMLFormElement::setAction(const String &value)
603 {
604     setAttribute(actionAttr, value);
605 }
606
607 void HTMLFormElement::setEnctype(const String &value)
608 {
609     setAttribute(enctypeAttr, value);
610 }
611
612 String HTMLFormElement::method() const
613 {
614     return FormSubmission::Attributes::methodString(m_attributes.method());
615 }
616
617 void HTMLFormElement::setMethod(const String &value)
618 {
619     setAttribute(methodAttr, value);
620 }
621
622 String HTMLFormElement::target() const
623 {
624     return getAttribute(targetAttr);
625 }
626
627 bool HTMLFormElement::wasUserSubmitted() const
628 {
629     return m_wasUserSubmitted;
630 }
631
632 HTMLFormControlElement* HTMLFormElement::defaultButton() const
633 {
634     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
635         if (!m_associatedElements[i]->isFormControlElement())
636             continue;
637         HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(m_associatedElements[i]);
638         if (control->isSuccessfulSubmitButton())
639             return control;
640     }
641
642     return 0;
643 }
644
645 bool HTMLFormElement::checkValidity()
646 {
647     Vector<RefPtr<FormAssociatedElement> > controls;
648     return !checkInvalidControlsAndCollectUnhandled(controls);
649 }
650
651 bool HTMLFormElement::checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement> >& unhandledInvalidControls)
652 {
653     RefPtr<HTMLFormElement> protector(this);
654     // Copy m_associatedElements because event handlers called from
655     // HTMLFormControlElement::checkValidity() might change m_associatedElements.
656     Vector<RefPtr<FormAssociatedElement> > elements;
657     elements.reserveCapacity(m_associatedElements.size());
658     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
659         elements.append(m_associatedElements[i]);
660     bool hasInvalidControls = false;
661     for (unsigned i = 0; i < elements.size(); ++i) {
662         if (elements[i]->form() == this && elements[i]->isFormControlElement()) {
663             HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(elements[i].get());
664             if (!control->checkValidity(&unhandledInvalidControls) && control->form() == this)
665                 hasInvalidControls = true;
666         }
667     }
668     return hasInvalidControls;
669 }
670
671 HTMLFormControlElement* HTMLFormElement::elementForAlias(const AtomicString& alias)
672 {
673     if (alias.isEmpty() || !m_elementAliases)
674         return 0;
675     return m_elementAliases->get(alias.impl()).get();
676 }
677
678 void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
679 {
680     if (alias.isEmpty())
681         return;
682     if (!m_elementAliases)
683         m_elementAliases = adoptPtr(new AliasMap);
684     m_elementAliases->set(alias.impl(), element);
685 }
686
687 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
688 {
689     elements()->namedItems(name, namedItems);
690
691     HTMLFormControlElement* aliasElement = elementForAlias(name);
692     if (aliasElement) {
693         if (namedItems.find(aliasElement) == notFound) {
694             // We have seen it before but it is gone now. Still, we need to return it.
695             // FIXME: The above comment is not clear enough; it does not say why we need to do this.
696             namedItems.append(aliasElement);
697         }
698     }
699     if (namedItems.size() && namedItems.first() != aliasElement)
700         addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
701 }
702
703 void HTMLFormElement::documentDidResumeFromPageCache()
704 {
705     ASSERT(!shouldAutocomplete());
706
707     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
708         if (m_associatedElements[i]->isFormControlElement())
709             static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
710     }
711 }
712
713 void HTMLFormElement::didMoveToNewDocument(Document* oldDocument)
714 {
715     if (!shouldAutocomplete()) {
716         if (oldDocument)
717             oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
718         document()->registerForPageCacheSuspensionCallbacks(this);
719     }
720
721     HTMLElement::didMoveToNewDocument(oldDocument);
722 }
723
724 bool HTMLFormElement::shouldAutocomplete() const
725 {
726     return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
727 }
728
729 void HTMLFormElement::finishParsingChildren()
730 {
731     HTMLElement::finishParsingChildren();
732     document()->formController()->restoreControlStateIn(*this);
733 }
734
735 void HTMLFormElement::copyNonAttributePropertiesFromElement(const Element& source)
736 {
737     m_wasDemoted = static_cast<const HTMLFormElement&>(source).m_wasDemoted;
738     HTMLElement::copyNonAttributePropertiesFromElement(source);
739 }
740
741 } // namespace