WebCore/html/HTMLFormElement.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "FormData.h"
       
    37 #include "FormDataList.h"
       
    38 #include "FormState.h"
       
    39 #include "FormSubmission.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 "RenderTextControl.h"
       
    50 #include "ScriptEventListener.h"
       
    51 #include "ValidityState.h"
       
    52 #include <limits>
       
    53 #include <wtf/CurrentTime.h>
       
    54 #include <wtf/RandomNumber.h>
       
    55 
       
    56 #if PLATFORM(WX)
       
    57 #include <wx/defs.h>
       
    58 #include <wx/filename.h>
       
    59 #endif
       
    60 
       
    61 using namespace std;
       
    62 
       
    63 namespace WebCore {
       
    64 
       
    65 using namespace HTMLNames;
       
    66 
       
    67 static int64_t generateFormDataIdentifier()
       
    68 {
       
    69     // Initialize to the current time to reduce the likelihood of generating
       
    70     // identifiers that overlap with those from past/future browser sessions.
       
    71     static int64_t nextIdentifier = static_cast<int64_t>(currentTime() * 1000000.0);
       
    72     return ++nextIdentifier;
       
    73 }
       
    74 
       
    75 HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* document)
       
    76     : HTMLElement(tagName, document)
       
    77     , m_submissionTrigger(NotSubmittedByJavaScript)
       
    78     , m_autocomplete(true)
       
    79     , m_insubmit(false)
       
    80     , m_doingsubmit(false)
       
    81     , m_inreset(false)
       
    82     , m_malformed(false)
       
    83     , m_demoted(false)
       
    84 {
       
    85     ASSERT(hasTagName(formTag));
       
    86 }
       
    87 
       
    88 PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
       
    89 {
       
    90     return adoptRef(new HTMLFormElement(formTag, document));
       
    91 }
       
    92 
       
    93 PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
       
    94 {
       
    95     return adoptRef(new HTMLFormElement(tagName, document));
       
    96 }
       
    97 
       
    98 HTMLFormElement::~HTMLFormElement()
       
    99 {
       
   100     if (!m_autocomplete)
       
   101         document()->unregisterForDocumentActivationCallbacks(this);
       
   102 
       
   103     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
       
   104         m_associatedElements[i]->formDestroyed();
       
   105     for (unsigned i = 0; i < m_imageElements.size(); ++i)
       
   106         m_imageElements[i]->m_form = 0;
       
   107 }
       
   108 
       
   109 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
       
   110 {
       
   111     return document()->completeURL(url).protocolIs("https");
       
   112 }
       
   113 
       
   114 bool HTMLFormElement::rendererIsNeeded(RenderStyle* style)
       
   115 {
       
   116     if (!isDemoted())
       
   117         return HTMLElement::rendererIsNeeded(style);
       
   118     
       
   119     Node* node = parentNode();
       
   120     RenderObject* parentRenderer = node->renderer();
       
   121     bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
       
   122         || (parentRenderer->isTableRow() && node->hasTagName(trTag))
       
   123         || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
       
   124         || (parentRenderer->isTableCol() && node->hasTagName(colTag)) 
       
   125         || (parentRenderer->isTableCell() && node->hasTagName(trTag));
       
   126 
       
   127     if (!parentIsTableElementPart)
       
   128         return true;
       
   129 
       
   130     EDisplay display = style->display();
       
   131     bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
       
   132         || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
       
   133         || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
       
   134         || display == TABLE_CAPTION;
       
   135 
       
   136     return formIsTablePart;
       
   137 }
       
   138 
       
   139 void HTMLFormElement::insertedIntoDocument()
       
   140 {
       
   141     if (document()->isHTMLDocument())
       
   142         static_cast<HTMLDocument*>(document())->addNamedItem(m_name);
       
   143 
       
   144     HTMLElement::insertedIntoDocument();
       
   145 }
       
   146 
       
   147 void HTMLFormElement::removedFromDocument()
       
   148 {
       
   149     if (document()->isHTMLDocument())
       
   150         static_cast<HTMLDocument*>(document())->removeNamedItem(m_name);
       
   151    
       
   152     HTMLElement::removedFromDocument();
       
   153 }
       
   154 
       
   155 void HTMLFormElement::handleLocalEvents(Event* event)
       
   156 {
       
   157     Node* targetNode = event->target()->toNode();
       
   158     if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
       
   159         event->stopPropagation();
       
   160         return;
       
   161     }
       
   162     HTMLElement::handleLocalEvents(event);
       
   163 }
       
   164 
       
   165 unsigned HTMLFormElement::length() const
       
   166 {
       
   167     unsigned len = 0;
       
   168     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
       
   169         if (m_associatedElements[i]->isEnumeratable())
       
   170             ++len;
       
   171     return len;
       
   172 }
       
   173 
       
   174 Node* HTMLFormElement::item(unsigned index)
       
   175 {
       
   176     return elements()->item(index);
       
   177 }
       
   178 
       
   179 void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
       
   180 {
       
   181     int submissionTriggerCount = 0;
       
   182     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
       
   183         HTMLFormControlElement* formElement = m_associatedElements[i];
       
   184         if (formElement->isSuccessfulSubmitButton()) {
       
   185             if (formElement->renderer()) {
       
   186                 formElement->dispatchSimulatedClick(event);
       
   187                 return;
       
   188             }
       
   189         } else if (formElement->canTriggerImplicitSubmission())
       
   190             ++submissionTriggerCount;
       
   191     }
       
   192     if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
       
   193         prepareSubmit(event);
       
   194 }
       
   195 
       
   196 static void appendMailtoPostFormDataToURL(KURL& url, const FormData& data, const String& encodingType)
       
   197 {
       
   198     String body = data.flattenToString();
       
   199 
       
   200     if (equalIgnoringCase(encodingType, "text/plain")) {
       
   201         // Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20.
       
   202         body = decodeURLEscapeSequences(body.replace('&', "\r\n").replace('+', ' ') + "\r\n");
       
   203     }
       
   204 
       
   205     Vector<char> bodyData;
       
   206     bodyData.append("body=", 5);
       
   207     FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8());
       
   208     body = String(bodyData.data(), bodyData.size()).replace('+', "%20");
       
   209 
       
   210     String query = url.query();
       
   211     if (!query.isEmpty())
       
   212         query.append('&');
       
   213     query.append(body);
       
   214     url.setQuery(query);
       
   215 }
       
   216 
       
   217 PassRefPtr<FormSubmission> HTMLFormElement::prepareFormSubmission(Event* event, bool lockHistory, FormSubmissionTrigger trigger)
       
   218 {
       
   219     KURL actionURL = document()->completeURL(m_formDataBuilder.action().isEmpty() ? document()->url().string() : m_formDataBuilder.action());
       
   220     bool isMailtoForm = actionURL.protocolIs("mailto");
       
   221 
       
   222     if (m_formDataBuilder.isPostMethod()) {
       
   223         if (m_formDataBuilder.isMultiPartForm() && isMailtoForm) {
       
   224             m_formDataBuilder.parseEncodingType("application/x-www-form-urlencoded");
       
   225             ASSERT(!m_formDataBuilder.isMultiPartForm());
       
   226         }
       
   227     } else
       
   228         m_formDataBuilder.setIsMultiPartForm(false);
       
   229 
       
   230     TextEncoding dataEncoding = isMailtoForm ? UTF8Encoding() : m_formDataBuilder.dataEncoding(document());
       
   231     RefPtr<DOMFormData> domFormData = DOMFormData::create(dataEncoding.encodingForFormSubmission());
       
   232     Vector<pair<String, String> > formValues;
       
   233 
       
   234     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
       
   235         HTMLFormControlElement* control = m_associatedElements[i];
       
   236         if (!control->disabled())
       
   237             control->appendFormData(*domFormData, m_formDataBuilder.isMultiPartForm());
       
   238         if (control->hasLocalName(inputTag)) {
       
   239             HTMLInputElement* input = static_cast<HTMLInputElement*>(control);
       
   240             if (input->isTextField()) {
       
   241                 formValues.append(pair<String, String>(input->name(), input->value()));
       
   242                 if (input->isSearchField())
       
   243                     input->addSearchResult();
       
   244             }
       
   245         }
       
   246     }
       
   247 
       
   248     RefPtr<FormData> formData;
       
   249     String boundary;
       
   250 
       
   251     if (m_formDataBuilder.isMultiPartForm()) {
       
   252         formData = FormData::createMultiPart(domFormData->items(), domFormData->encoding(), document());
       
   253         boundary = formData->boundary().data();
       
   254     } else {
       
   255         formData = FormData::create(domFormData->items(), domFormData->encoding());
       
   256         if (m_formDataBuilder.isPostMethod() && isMailtoForm) {
       
   257             // Convert the form data into a string that we put into the URL.
       
   258             appendMailtoPostFormDataToURL(actionURL, *formData, m_formDataBuilder.encodingType());
       
   259             formData = FormData::create();
       
   260         }
       
   261     }
       
   262 
       
   263     formData->setIdentifier(generateFormDataIdentifier());
       
   264     FormSubmission::Method method = m_formDataBuilder.isPostMethod() ? FormSubmission::PostMethod : FormSubmission::GetMethod;
       
   265     String targetOrBaseTarget = m_formDataBuilder.target().isEmpty() ? document()->baseTarget() : m_formDataBuilder.target();
       
   266     return FormSubmission::create(method, actionURL, targetOrBaseTarget, m_formDataBuilder.encodingType(), FormState::create(this, formValues, document()->frame(), trigger), formData.release(), boundary, lockHistory, event);
       
   267 }
       
   268 
       
   269 static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
       
   270 {
       
   271     Node* targetNode = event->target()->toNode();
       
   272     if (!targetNode || !targetNode->isElementNode())
       
   273         return 0;
       
   274     Element* targetElement = static_cast<Element*>(targetNode);
       
   275     if (!targetElement->isFormControlElement())
       
   276         return 0;
       
   277     return static_cast<HTMLFormControlElement*>(targetElement);
       
   278 }
       
   279 
       
   280 bool HTMLFormElement::validateInteractively(Event* event)
       
   281 {
       
   282     ASSERT(event);
       
   283     if (!document()->inStrictMode() || noValidate())
       
   284         return true;
       
   285 
       
   286     HTMLFormControlElement* submitElement = submitElementFromEvent(event);
       
   287     if (submitElement && submitElement->formNoValidate())
       
   288         return true;
       
   289 
       
   290     Vector<RefPtr<HTMLFormControlElement> > unhandledInvalidControls;
       
   291     collectUnhandledInvalidControls(unhandledInvalidControls);
       
   292     if (unhandledInvalidControls.isEmpty())
       
   293         return true;
       
   294     // If the form has invalid controls, abort submission.
       
   295 
       
   296     RefPtr<HTMLFormElement> protector(this);
       
   297     // Focus on the first focusable control.
       
   298     for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
       
   299         HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get();
       
   300         if (unhandled->isFocusable() && unhandled->inDocument()) {
       
   301             RefPtr<Document> originalDocument(unhandled->document());
       
   302             unhandled->scrollIntoViewIfNeeded(false);
       
   303             // scrollIntoViewIfNeeded() dispatches events, so the state
       
   304             // of 'unhandled' might be changed so it's no longer focusable or
       
   305             // moved to another document.
       
   306             if (unhandled->isFocusable() && unhandled->inDocument() && originalDocument == unhandled->document()) {
       
   307                 unhandled->focus();
       
   308                 break;
       
   309             }
       
   310         }
       
   311     }
       
   312     // Warn about all of unfocusable controls.
       
   313     if (Frame* frame = document()->frame()) {
       
   314         for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
       
   315             HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get();
       
   316             if (unhandled->isFocusable() && unhandled->inDocument())
       
   317                 continue;
       
   318             String message("An invalid form control with name='%name' is not focusable.");
       
   319             message.replace("%name", unhandled->name());
       
   320             frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, 0, document()->url().string());
       
   321         }
       
   322     }
       
   323     m_insubmit = false;
       
   324     return false;
       
   325 }
       
   326 
       
   327 bool HTMLFormElement::prepareSubmit(Event* event)
       
   328 {
       
   329     Frame* frame = document()->frame();
       
   330     if (m_insubmit || !frame)
       
   331         return m_insubmit;
       
   332 
       
   333     m_insubmit = true;
       
   334     m_doingsubmit = false;
       
   335 
       
   336     // Interactive validation must be done before dispatching the submit event.
       
   337     if (!validateInteractively(event))
       
   338         return false;
       
   339 
       
   340     frame->loader()->client()->dispatchWillSendSubmitEvent(this);
       
   341 
       
   342     if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)) && !m_doingsubmit)
       
   343         m_doingsubmit = true;
       
   344 
       
   345     m_insubmit = false;
       
   346 
       
   347     if (m_doingsubmit)
       
   348         submit(event, true, false, NotSubmittedByJavaScript);
       
   349 
       
   350     return m_doingsubmit;
       
   351 }
       
   352 
       
   353 void HTMLFormElement::submit(Frame* javaScriptActiveFrame)
       
   354 {
       
   355     if (javaScriptActiveFrame)
       
   356         submit(0, false, !javaScriptActiveFrame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript);
       
   357     else
       
   358         submit(0, false, false, NotSubmittedByJavaScript);
       
   359 }
       
   360 
       
   361 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockHistory, FormSubmissionTrigger formSubmissionTrigger)
       
   362 {
       
   363     FrameView* view = document()->view();
       
   364     Frame* frame = document()->frame();
       
   365     if (!view || !frame)
       
   366         return;
       
   367 
       
   368     if (m_insubmit) {
       
   369         m_doingsubmit = true;
       
   370         return;
       
   371     }
       
   372 
       
   373     m_insubmit = true;
       
   374     m_submissionTrigger = formSubmissionTrigger;
       
   375 
       
   376     HTMLFormControlElement* firstSuccessfulSubmitButton = 0;
       
   377     bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
       
   378     
       
   379     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
       
   380         HTMLFormControlElement* control = m_associatedElements[i];
       
   381         if (needButtonActivation) {
       
   382             if (control->isActivatedSubmit())
       
   383                 needButtonActivation = false;
       
   384             else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
       
   385                 firstSuccessfulSubmitButton = control;
       
   386         }
       
   387     }
       
   388 
       
   389     if (needButtonActivation && firstSuccessfulSubmitButton)
       
   390         firstSuccessfulSubmitButton->setActivatedSubmit(true);
       
   391 
       
   392     frame->loader()->submitForm(prepareFormSubmission(event, lockHistory, formSubmissionTrigger));
       
   393 
       
   394     if (needButtonActivation && firstSuccessfulSubmitButton)
       
   395         firstSuccessfulSubmitButton->setActivatedSubmit(false);
       
   396     
       
   397     m_doingsubmit = m_insubmit = false;
       
   398 }
       
   399 
       
   400 void HTMLFormElement::reset()
       
   401 {
       
   402     Frame* frame = document()->frame();
       
   403     if (m_inreset || !frame)
       
   404         return;
       
   405 
       
   406     m_inreset = true;
       
   407 
       
   408     // ### DOM2 labels this event as not cancelable, however
       
   409     // common browsers( sick! ) allow it be cancelled.
       
   410     if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
       
   411         m_inreset = false;
       
   412         return;
       
   413     }
       
   414 
       
   415     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
       
   416         m_associatedElements[i]->reset();
       
   417 
       
   418     m_inreset = false;
       
   419 }
       
   420 
       
   421 void HTMLFormElement::parseMappedAttribute(Attribute* attr)
       
   422 {
       
   423     if (attr->name() == actionAttr)
       
   424         m_formDataBuilder.parseAction(attr->value());
       
   425     else if (attr->name() == targetAttr)
       
   426         m_formDataBuilder.setTarget(attr->value());
       
   427     else if (attr->name() == methodAttr)
       
   428         m_formDataBuilder.parseMethodType(attr->value());
       
   429     else if (attr->name() == enctypeAttr)
       
   430         m_formDataBuilder.parseEncodingType(attr->value());
       
   431     else if (attr->name() == accept_charsetAttr)
       
   432         // space separated list of charsets the server
       
   433         // accepts - see rfc2045
       
   434         m_formDataBuilder.setAcceptCharset(attr->value());
       
   435     else if (attr->name() == acceptAttr) {
       
   436         // ignore this one for the moment...
       
   437     } else if (attr->name() == autocompleteAttr) {
       
   438         m_autocomplete = !equalIgnoringCase(attr->value(), "off");
       
   439         if (!m_autocomplete)
       
   440             document()->registerForDocumentActivationCallbacks(this);    
       
   441         else
       
   442             document()->unregisterForDocumentActivationCallbacks(this);
       
   443     } else if (attr->name() == onsubmitAttr)
       
   444         setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attr));
       
   445     else if (attr->name() == onresetAttr)
       
   446         setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attr));
       
   447     else if (attr->name() == nameAttr) {
       
   448         const AtomicString& newName = attr->value();
       
   449         if (inDocument() && document()->isHTMLDocument()) {
       
   450             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   451             document->removeNamedItem(m_name);
       
   452             document->addNamedItem(newName);
       
   453         }
       
   454         m_name = newName;
       
   455     } else
       
   456         HTMLElement::parseMappedAttribute(attr);
       
   457 }
       
   458 
       
   459 template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
       
   460 {
       
   461     size_t size = vec.size();
       
   462     for (size_t i = 0; i != size; ++i)
       
   463         if (vec[i] == item) {
       
   464             vec.remove(i);
       
   465             break;
       
   466         }
       
   467 }
       
   468 
       
   469 unsigned HTMLFormElement::formElementIndex(HTMLFormControlElement* e)
       
   470 {
       
   471     // Check for the special case where this element is the very last thing in
       
   472     // the form's tree of children; we don't want to walk the entire tree in that
       
   473     // common case that occurs during parsing; instead we'll just return a value
       
   474     // that says "add this form element to the end of the array".
       
   475     if (e->traverseNextNode(this)) {
       
   476         unsigned i = 0;
       
   477         for (Node* node = this; node; node = node->traverseNextNode(this)) {
       
   478             if (node == e)
       
   479                 return i;
       
   480             if (node->isHTMLElement()
       
   481                     && static_cast<Element*>(node)->isFormControlElement()
       
   482                     && static_cast<HTMLFormControlElement*>(node)->form() == this)
       
   483                 ++i;
       
   484         }
       
   485     }
       
   486     return m_associatedElements.size();
       
   487 }
       
   488 
       
   489 void HTMLFormElement::registerFormElement(HTMLFormControlElement* e)
       
   490 {
       
   491     document()->checkedRadioButtons().removeButton(e);
       
   492     m_checkedRadioButtons.addButton(e);
       
   493     m_associatedElements.insert(formElementIndex(e), e);
       
   494 }
       
   495 
       
   496 void HTMLFormElement::removeFormElement(HTMLFormControlElement* e)
       
   497 {
       
   498     m_checkedRadioButtons.removeButton(e);
       
   499     removeFromVector(m_associatedElements, e);
       
   500 }
       
   501 
       
   502 bool HTMLFormElement::isURLAttribute(Attribute* attr) const
       
   503 {
       
   504     return attr->name() == actionAttr;
       
   505 }
       
   506 
       
   507 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
       
   508 {
       
   509     ASSERT(m_imageElements.find(e) == notFound);
       
   510     m_imageElements.append(e);
       
   511 }
       
   512 
       
   513 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
       
   514 {
       
   515     ASSERT(m_imageElements.find(e) != notFound);
       
   516     removeFromVector(m_imageElements, e);
       
   517 }
       
   518 
       
   519 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
       
   520 {
       
   521     return HTMLFormCollection::create(this);
       
   522 }
       
   523 
       
   524 String HTMLFormElement::name() const
       
   525 {
       
   526     return getAttribute(nameAttr);
       
   527 }
       
   528 
       
   529 bool HTMLFormElement::noValidate() const
       
   530 {
       
   531     return !getAttribute(novalidateAttr).isNull();
       
   532 }
       
   533 
       
   534 String HTMLFormElement::action() const
       
   535 {
       
   536     return getAttribute(actionAttr);
       
   537 }
       
   538 
       
   539 void HTMLFormElement::setAction(const String &value)
       
   540 {
       
   541     setAttribute(actionAttr, value);
       
   542 }
       
   543 
       
   544 void HTMLFormElement::setEnctype(const String &value)
       
   545 {
       
   546     setAttribute(enctypeAttr, value);
       
   547 }
       
   548 
       
   549 String HTMLFormElement::method() const
       
   550 {
       
   551     return getAttribute(methodAttr);
       
   552 }
       
   553 
       
   554 void HTMLFormElement::setMethod(const String &value)
       
   555 {
       
   556     setAttribute(methodAttr, value);
       
   557 }
       
   558 
       
   559 String HTMLFormElement::target() const
       
   560 {
       
   561     return getAttribute(targetAttr);
       
   562 }
       
   563 
       
   564 FormSubmissionTrigger HTMLFormElement::submissionTrigger() const
       
   565 {
       
   566     return m_submissionTrigger;
       
   567 }
       
   568 
       
   569 HTMLFormControlElement* HTMLFormElement::defaultButton() const
       
   570 {
       
   571     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
       
   572         HTMLFormControlElement* control = m_associatedElements[i];
       
   573         if (control->isSuccessfulSubmitButton())
       
   574             return control;
       
   575     }
       
   576 
       
   577     return 0;
       
   578 }
       
   579 
       
   580 bool HTMLFormElement::checkValidity()
       
   581 {
       
   582     Vector<RefPtr<HTMLFormControlElement> > controls;
       
   583     collectUnhandledInvalidControls(controls);
       
   584     return controls.isEmpty();
       
   585 }
       
   586 
       
   587 void HTMLFormElement::collectUnhandledInvalidControls(Vector<RefPtr<HTMLFormControlElement> >& unhandledInvalidControls)
       
   588 {
       
   589     RefPtr<HTMLFormElement> protector(this);
       
   590     // Copy m_associatedElements because event handlers called from
       
   591     // HTMLFormControlElement::checkValidity() might change m_associatedElements.
       
   592     Vector<RefPtr<HTMLFormControlElement> > elements;
       
   593     elements.reserveCapacity(m_associatedElements.size());
       
   594     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
       
   595         elements.append(m_associatedElements[i]);
       
   596     for (unsigned i = 0; i < elements.size(); ++i) {
       
   597         if (elements[i]->form() == this)
       
   598             elements[i]->checkValidity(&unhandledInvalidControls);
       
   599     }
       
   600 }
       
   601 
       
   602 PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias)
       
   603 {
       
   604     if (alias.isEmpty() || !m_elementAliases)
       
   605         return 0;
       
   606     return m_elementAliases->get(alias.impl());
       
   607 }
       
   608 
       
   609 void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
       
   610 {
       
   611     if (alias.isEmpty())
       
   612         return;
       
   613     if (!m_elementAliases)
       
   614         m_elementAliases.set(new AliasMap);
       
   615     m_elementAliases->set(alias.impl(), element);
       
   616 }
       
   617 
       
   618 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
       
   619 {
       
   620     elements()->namedItems(name, namedItems);
       
   621 
       
   622     // see if we have seen something with this name before
       
   623     RefPtr<HTMLFormControlElement> aliasElem;
       
   624     if ((aliasElem = elementForAlias(name))) {
       
   625         bool found = false;
       
   626         for (unsigned n = 0; n < namedItems.size(); n++) {
       
   627             if (namedItems[n] == aliasElem.get()) {
       
   628                 found = true;
       
   629                 break;
       
   630             }
       
   631         }
       
   632         if (!found)
       
   633             // we have seen it before but it is gone now. still, we need to return it.
       
   634             namedItems.append(aliasElem.get());
       
   635     }
       
   636     // name has been accessed, remember it
       
   637     if (namedItems.size() && aliasElem != namedItems.first())
       
   638         addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);        
       
   639 }
       
   640 
       
   641 void HTMLFormElement::documentDidBecomeActive()
       
   642 {
       
   643     ASSERT(!m_autocomplete);
       
   644     
       
   645     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
       
   646         m_associatedElements[i]->reset();
       
   647 }
       
   648 
       
   649 void HTMLFormElement::willMoveToNewOwnerDocument()
       
   650 {
       
   651     if (!m_autocomplete)
       
   652         document()->unregisterForDocumentActivationCallbacks(this);
       
   653     HTMLElement::willMoveToNewOwnerDocument();
       
   654 }
       
   655 
       
   656 void HTMLFormElement::didMoveToNewOwnerDocument()
       
   657 {
       
   658     if (!m_autocomplete)
       
   659         document()->registerForDocumentActivationCallbacks(this);
       
   660     HTMLElement::didMoveToNewOwnerDocument();
       
   661 }
       
   662 
       
   663 } // namespace