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)
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.
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.
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.
26 #include "HTMLFormElement.h"
28 #include "Attribute.h"
29 #include "DOMFormData.h"
30 #include "DOMWindow.h"
33 #include "EventNames.h"
35 #include "FileSystem.h"
37 #include "FormDataList.h"
38 #include "FormState.h"
40 #include "FrameLoader.h"
41 #include "FrameLoaderClient.h"
42 #include "HTMLDocument.h"
43 #include "HTMLFormCollection.h"
44 #include "HTMLImageElement.h"
45 #include "HTMLInputElement.h"
46 #include "HTMLNames.h"
47 #include "MIMETypeRegistry.h"
49 #include "RenderTextControl.h"
50 #include "ScriptEventListener.h"
52 #include "ValidityState.h"
57 #include <wx/filename.h>
64 using namespace HTMLNames;
66 HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* document)
67 : HTMLElement(tagName, document)
68 , m_wasUserSubmitted(false)
69 , m_autocomplete(true)
71 , m_doingsubmit(false)
76 ASSERT(hasTagName(formTag));
79 PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
81 return adoptRef(new HTMLFormElement(formTag, document));
84 PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
86 return adoptRef(new HTMLFormElement(tagName, document));
89 HTMLFormElement::~HTMLFormElement()
92 document()->unregisterForDocumentActivationCallbacks(this);
94 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
95 m_associatedElements[i]->formDestroyed();
96 for (unsigned i = 0; i < m_imageElements.size(); ++i)
97 m_imageElements[i]->m_form = 0;
100 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
102 return document()->completeURL(url).protocolIs("https");
105 bool HTMLFormElement::rendererIsNeeded(RenderStyle* style)
108 return HTMLElement::rendererIsNeeded(style);
110 ContainerNode* node = parentNode();
111 RenderObject* parentRenderer = node->renderer();
112 bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
113 || (parentRenderer->isTableRow() && node->hasTagName(trTag))
114 || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
115 || (parentRenderer->isTableCol() && node->hasTagName(colTag))
116 || (parentRenderer->isTableCell() && node->hasTagName(trTag));
118 if (!parentIsTableElementPart)
121 EDisplay display = style->display();
122 bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
123 || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
124 || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
125 || display == TABLE_CAPTION;
127 return formIsTablePart;
130 void HTMLFormElement::insertedIntoDocument()
132 if (document()->isHTMLDocument())
133 static_cast<HTMLDocument*>(document())->addNamedItem(m_name);
135 HTMLElement::insertedIntoDocument();
138 void HTMLFormElement::removedFromDocument()
140 if (document()->isHTMLDocument())
141 static_cast<HTMLDocument*>(document())->removeNamedItem(m_name);
143 HTMLElement::removedFromDocument();
146 void HTMLFormElement::handleLocalEvents(Event* event)
148 Node* targetNode = event->target()->toNode();
149 if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
150 event->stopPropagation();
153 HTMLElement::handleLocalEvents(event);
156 unsigned HTMLFormElement::length() const
159 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
160 if (m_associatedElements[i]->isEnumeratable())
165 Node* HTMLFormElement::item(unsigned index)
167 return elements()->item(index);
170 void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
172 int submissionTriggerCount = 0;
173 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
174 HTMLFormControlElement* formElement = m_associatedElements[i];
175 if (formElement->isSuccessfulSubmitButton()) {
176 if (formElement->renderer()) {
177 formElement->dispatchSimulatedClick(event);
180 } else if (formElement->canTriggerImplicitSubmission())
181 ++submissionTriggerCount;
183 if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
184 prepareSubmit(event);
187 static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
189 Node* targetNode = event->target()->toNode();
190 if (!targetNode || !targetNode->isElementNode())
192 Element* targetElement = static_cast<Element*>(targetNode);
193 if (!targetElement->isFormControlElement())
195 return static_cast<HTMLFormControlElement*>(targetElement);
198 bool HTMLFormElement::validateInteractively(Event* event)
201 if (!document()->page() || !document()->page()->settings()->interactiveFormValidationEnabled() || noValidate())
204 HTMLFormControlElement* submitElement = submitElementFromEvent(event);
205 if (submitElement && submitElement->formNoValidate())
208 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
209 m_associatedElements[i]->hideVisibleValidationMessage();
211 Vector<RefPtr<HTMLFormControlElement> > unhandledInvalidControls;
212 collectUnhandledInvalidControls(unhandledInvalidControls);
213 if (unhandledInvalidControls.isEmpty())
215 // If the form has invalid controls, abort submission.
217 RefPtr<HTMLFormElement> protector(this);
218 // Focus on the first focusable control and show a validation message.
219 for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
220 HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get();
221 if (unhandled->isFocusable() && unhandled->inDocument()) {
222 RefPtr<Document> originalDocument(unhandled->document());
223 unhandled->scrollIntoViewIfNeeded(false);
224 // scrollIntoViewIfNeeded() dispatches events, so the state
225 // of 'unhandled' might be changed so it's no longer focusable or
226 // moved to another document.
227 if (unhandled->isFocusable() && unhandled->inDocument() && originalDocument == unhandled->document()) {
229 unhandled->updateVisibleValidationMessage();
234 // Warn about all of unfocusable controls.
235 if (Frame* frame = document()->frame()) {
236 for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
237 HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get();
238 if (unhandled->isFocusable() && unhandled->inDocument())
240 String message("An invalid form control with name='%name' is not focusable.");
241 message.replace("%name", unhandled->name());
242 frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, 0, document()->url().string());
249 bool HTMLFormElement::prepareSubmit(Event* event)
251 Frame* frame = document()->frame();
252 if (m_insubmit || !frame)
256 m_doingsubmit = false;
258 // Interactive validation must be done before dispatching the submit event.
259 if (!validateInteractively(event))
262 frame->loader()->client()->dispatchWillSendSubmitEvent(this);
264 if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)) && !m_doingsubmit)
265 m_doingsubmit = true;
270 submit(event, true, true, NotSubmittedByJavaScript);
272 return m_doingsubmit;
275 void HTMLFormElement::submit(Frame* javaScriptActiveFrame)
277 if (javaScriptActiveFrame)
278 submit(0, false, javaScriptActiveFrame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript);
280 submit(0, false, true, NotSubmittedByJavaScript);
283 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
285 FrameView* view = document()->view();
286 Frame* frame = document()->frame();
291 m_doingsubmit = true;
296 m_wasUserSubmitted = processingUserGesture;
298 HTMLFormControlElement* firstSuccessfulSubmitButton = 0;
299 bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
301 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
302 HTMLFormControlElement* control = m_associatedElements[i];
303 if (needButtonActivation) {
304 if (control->isActivatedSubmit())
305 needButtonActivation = false;
306 else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
307 firstSuccessfulSubmitButton = control;
311 if (needButtonActivation && firstSuccessfulSubmitButton)
312 firstSuccessfulSubmitButton->setActivatedSubmit(true);
314 frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, !processingUserGesture, formSubmissionTrigger));
316 if (needButtonActivation && firstSuccessfulSubmitButton)
317 firstSuccessfulSubmitButton->setActivatedSubmit(false);
319 m_doingsubmit = m_insubmit = false;
322 void HTMLFormElement::reset()
324 Frame* frame = document()->frame();
325 if (m_inreset || !frame)
330 // ### DOM2 labels this event as not cancelable, however
331 // common browsers( sick! ) allow it be cancelled.
332 if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
337 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
338 m_associatedElements[i]->reset();
343 void HTMLFormElement::parseMappedAttribute(Attribute* attr)
345 if (attr->name() == actionAttr)
346 m_attributes.parseAction(attr->value());
347 else if (attr->name() == targetAttr)
348 m_attributes.setTarget(attr->value());
349 else if (attr->name() == methodAttr)
350 m_attributes.parseMethodType(attr->value());
351 else if (attr->name() == enctypeAttr)
352 m_attributes.parseEncodingType(attr->value());
353 else if (attr->name() == accept_charsetAttr)
354 // space separated list of charsets the server
355 // accepts - see rfc2045
356 m_attributes.setAcceptCharset(attr->value());
357 else if (attr->name() == acceptAttr) {
358 // ignore this one for the moment...
359 } else if (attr->name() == autocompleteAttr) {
360 m_autocomplete = !equalIgnoringCase(attr->value(), "off");
362 document()->registerForDocumentActivationCallbacks(this);
364 document()->unregisterForDocumentActivationCallbacks(this);
365 } else if (attr->name() == onsubmitAttr)
366 setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attr));
367 else if (attr->name() == onresetAttr)
368 setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attr));
369 else if (attr->name() == nameAttr) {
370 const AtomicString& newName = attr->value();
371 if (inDocument() && document()->isHTMLDocument()) {
372 HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
373 document->removeNamedItem(m_name);
374 document->addNamedItem(newName);
378 HTMLElement::parseMappedAttribute(attr);
381 template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
383 size_t size = vec.size();
384 for (size_t i = 0; i != size; ++i)
385 if (vec[i] == item) {
391 unsigned HTMLFormElement::formElementIndex(HTMLFormControlElement* e)
393 // Check for the special case where this element is the very last thing in
394 // the form's tree of children; we don't want to walk the entire tree in that
395 // common case that occurs during parsing; instead we'll just return a value
396 // that says "add this form element to the end of the array".
397 if (e->traverseNextNode(this)) {
399 for (Node* node = this; node; node = node->traverseNextNode(this)) {
402 if (node->isHTMLElement()
403 && static_cast<Element*>(node)->isFormControlElement()
404 && static_cast<HTMLFormControlElement*>(node)->form() == this)
408 return m_associatedElements.size();
411 void HTMLFormElement::registerFormElement(HTMLFormControlElement* e)
413 document()->checkedRadioButtons().removeButton(e);
414 m_checkedRadioButtons.addButton(e);
415 m_associatedElements.insert(formElementIndex(e), e);
418 void HTMLFormElement::removeFormElement(HTMLFormControlElement* e)
420 m_checkedRadioButtons.removeButton(e);
421 removeFromVector(m_associatedElements, e);
424 bool HTMLFormElement::isURLAttribute(Attribute* attr) const
426 return attr->name() == actionAttr;
429 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
431 ASSERT(m_imageElements.find(e) == notFound);
432 m_imageElements.append(e);
435 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
437 ASSERT(m_imageElements.find(e) != notFound);
438 removeFromVector(m_imageElements, e);
441 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
443 return HTMLFormCollection::create(this);
446 String HTMLFormElement::name() const
448 return getAttribute(nameAttr);
451 bool HTMLFormElement::noValidate() const
453 return !getAttribute(novalidateAttr).isNull();
456 // FIXME: This function should be removed because it does not do the same thing as the
457 // JavaScript binding for action, which treats action as a URL attribute. Last time I
458 // (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
459 String HTMLFormElement::action() const
461 return getAttribute(actionAttr);
464 void HTMLFormElement::setAction(const String &value)
466 setAttribute(actionAttr, value);
469 void HTMLFormElement::setEnctype(const String &value)
471 setAttribute(enctypeAttr, value);
474 String HTMLFormElement::method() const
476 return getAttribute(methodAttr);
479 void HTMLFormElement::setMethod(const String &value)
481 setAttribute(methodAttr, value);
484 String HTMLFormElement::target() const
486 return getAttribute(targetAttr);
489 bool HTMLFormElement::wasUserSubmitted() const
491 return m_wasUserSubmitted;
494 HTMLFormControlElement* HTMLFormElement::defaultButton() const
496 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
497 HTMLFormControlElement* control = m_associatedElements[i];
498 if (control->isSuccessfulSubmitButton())
505 bool HTMLFormElement::checkValidity()
507 Vector<RefPtr<HTMLFormControlElement> > controls;
508 collectUnhandledInvalidControls(controls);
509 return controls.isEmpty();
512 void HTMLFormElement::collectUnhandledInvalidControls(Vector<RefPtr<HTMLFormControlElement> >& unhandledInvalidControls)
514 RefPtr<HTMLFormElement> protector(this);
515 // Copy m_associatedElements because event handlers called from
516 // HTMLFormControlElement::checkValidity() might change m_associatedElements.
517 Vector<RefPtr<HTMLFormControlElement> > elements;
518 elements.reserveCapacity(m_associatedElements.size());
519 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
520 elements.append(m_associatedElements[i]);
521 for (unsigned i = 0; i < elements.size(); ++i) {
522 if (elements[i]->form() == this)
523 elements[i]->checkValidity(&unhandledInvalidControls);
527 PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias)
529 if (alias.isEmpty() || !m_elementAliases)
531 return m_elementAliases->get(alias.impl());
534 void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
538 if (!m_elementAliases)
539 m_elementAliases = adoptPtr(new AliasMap);
540 m_elementAliases->set(alias.impl(), element);
543 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
545 elements()->namedItems(name, namedItems);
547 // see if we have seen something with this name before
548 RefPtr<HTMLFormControlElement> aliasElem;
549 if ((aliasElem = elementForAlias(name))) {
551 for (unsigned n = 0; n < namedItems.size(); n++) {
552 if (namedItems[n] == aliasElem.get()) {
558 // we have seen it before but it is gone now. still, we need to return it.
559 namedItems.append(aliasElem.get());
561 // name has been accessed, remember it
562 if (namedItems.size() && aliasElem != namedItems.first())
563 addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
566 void HTMLFormElement::documentDidBecomeActive()
568 ASSERT(!m_autocomplete);
570 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
571 m_associatedElements[i]->reset();
574 void HTMLFormElement::willMoveToNewOwnerDocument()
577 document()->unregisterForDocumentActivationCallbacks(this);
578 HTMLElement::willMoveToNewOwnerDocument();
581 void HTMLFormElement::didMoveToNewOwnerDocument()
584 document()->registerForDocumentActivationCallbacks(this);
585 HTMLElement::didMoveToNewOwnerDocument();