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"
36 #include "FormController.h"
38 #include "FormDataList.h"
39 #include "FormState.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"
51 #include "RenderTextControl.h"
52 #include "ScriptEventListener.h"
54 #include "ValidityState.h"
59 #include <wx/filename.h>
66 using namespace HTMLNames;
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)
78 ASSERT(hasTagName(formTag));
81 PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
83 return adoptRef(new HTMLFormElement(formTag, document));
86 PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
88 return adoptRef(new HTMLFormElement(tagName, document));
91 HTMLFormElement::~HTMLFormElement()
93 document()->formController()->willDeleteForm(this);
94 if (!shouldAutocomplete())
95 document()->unregisterForPageCacheSuspensionCallbacks(this);
97 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
98 m_associatedElements[i]->formWillBeDestroyed();
99 for (unsigned i = 0; i < m_imageElements.size(); ++i)
100 m_imageElements[i]->m_form = 0;
103 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
105 return document()->completeURL(url).protocolIs("https");
108 bool HTMLFormElement::rendererIsNeeded(const NodeRenderingContext& context)
111 return HTMLElement::rendererIsNeeded(context);
113 ContainerNode* node = parentNode();
114 RenderObject* parentRenderer = node->renderer();
115 // FIXME: Shouldn't we also check for table caption (see |formIsTablePart| below).
116 bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
117 || (parentRenderer->isTableRow() && node->hasTagName(trTag))
118 || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
119 || (parentRenderer->isRenderTableCol() && node->hasTagName(colTag))
120 || (parentRenderer->isTableCell() && node->hasTagName(trTag));
122 if (!parentIsTableElementPart)
125 EDisplay display = context.style()->display();
126 bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
127 || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
128 || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
129 || display == TABLE_CAPTION;
131 return formIsTablePart;
134 Node::InsertionNotificationRequest HTMLFormElement::insertedInto(ContainerNode* insertionPoint)
136 HTMLElement::insertedInto(insertionPoint);
137 return InsertionDone;
140 static inline Node* findRoot(Node* n)
143 for (; n; n = n->parentNode())
148 void HTMLFormElement::removedFrom(ContainerNode* insertionPoint)
150 Node* root = findRoot(this);
151 Vector<FormAssociatedElement*> associatedElements(m_associatedElements);
152 for (unsigned i = 0; i < associatedElements.size(); ++i)
153 associatedElements[i]->formRemovedFromTree(root);
154 HTMLElement::removedFrom(insertionPoint);
157 void HTMLFormElement::handleLocalEvents(Event* event)
159 Node* targetNode = event->target()->toNode();
160 if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
161 event->stopPropagation();
164 HTMLElement::handleLocalEvents(event);
167 unsigned HTMLFormElement::length() const
170 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
171 if (m_associatedElements[i]->isEnumeratable())
176 Node* HTMLFormElement::item(unsigned index)
178 return elements()->item(index);
181 void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
183 int submissionTriggerCount = 0;
184 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
185 FormAssociatedElement* formAssociatedElement = m_associatedElements[i];
186 if (!formAssociatedElement->isFormControlElement())
188 HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(formAssociatedElement);
189 if (formElement->isSuccessfulSubmitButton()) {
190 if (formElement->renderer()) {
191 formElement->dispatchSimulatedClick(event);
194 } else if (formElement->canTriggerImplicitSubmission())
195 ++submissionTriggerCount;
197 if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
198 prepareForSubmission(event);
201 static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
203 Node* targetNode = event->target()->toNode();
204 if (!targetNode || !targetNode->isElementNode())
206 Element* targetElement = static_cast<Element*>(targetNode);
207 if (!targetElement->isFormControlElement())
209 return static_cast<HTMLFormControlElement*>(targetElement);
212 bool HTMLFormElement::validateInteractively(Event* event)
215 if (!document()->page() || !document()->page()->settings()->interactiveFormValidationEnabled() || noValidate())
218 HTMLFormControlElement* submitElement = submitElementFromEvent(event);
219 if (submitElement && submitElement->formNoValidate())
222 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
223 if (m_associatedElements[i]->isFormControlElement())
224 static_cast<HTMLFormControlElement*>(m_associatedElements[i])->hideVisibleValidationMessage();
227 Vector<RefPtr<FormAssociatedElement> > unhandledInvalidControls;
228 if (!checkInvalidControlsAndCollectUnhandled(unhandledInvalidControls))
230 // Because the form has invalid controls, we abort the form submission and
231 // show a validation message on a focusable form control.
233 // Needs to update layout now because we'd like to call isFocusable(), which
234 // has !renderer()->needsLayout() assertion.
235 document()->updateLayoutIgnorePendingStylesheets();
237 RefPtr<HTMLFormElement> protector(this);
238 // Focus on the first focusable control and show a validation message.
239 for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
240 FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
241 HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
242 if (unhandled->isFocusable() && unhandled->inDocument()) {
243 unhandled->scrollIntoViewIfNeeded(false);
245 if (unhandled->isFormControlElement())
246 static_cast<HTMLFormControlElement*>(unhandled)->updateVisibleValidationMessage();
250 // Warn about all of unfocusable controls.
251 if (document()->frame()) {
252 for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
253 FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
254 HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
255 if (unhandled->isFocusable() && unhandled->inDocument())
257 String message("An invalid form control with name='%name' is not focusable.");
258 message.replace("%name", unhandledAssociatedElement->name());
259 document()->addConsoleMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, document()->url().string());
265 bool HTMLFormElement::prepareForSubmission(Event* event)
267 Frame* frame = document()->frame();
268 if (m_isSubmittingOrPreparingForSubmission || !frame)
269 return m_isSubmittingOrPreparingForSubmission;
271 m_isSubmittingOrPreparingForSubmission = true;
272 m_shouldSubmit = false;
274 // Interactive validation must be done before dispatching the submit event.
275 if (!validateInteractively(event)) {
276 m_isSubmittingOrPreparingForSubmission = false;
280 StringPairVector controlNamesAndValues;
281 getTextFieldValues(controlNamesAndValues);
282 RefPtr<FormState> formState = FormState::create(this, controlNamesAndValues, document(), NotSubmittedByJavaScript);
283 frame->loader()->client()->dispatchWillSendSubmitEvent(formState.release());
285 if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)))
286 m_shouldSubmit = true;
288 m_isSubmittingOrPreparingForSubmission = false;
291 submit(event, true, true, NotSubmittedByJavaScript);
293 return m_shouldSubmit;
296 void HTMLFormElement::submit()
298 submit(0, false, true, NotSubmittedByJavaScript);
301 void HTMLFormElement::submitFromJavaScript()
303 submit(0, false, ScriptController::processingUserGesture(), SubmittedByJavaScript);
306 void HTMLFormElement::getTextFieldValues(StringPairVector& fieldNamesAndValues) const
308 ASSERT_ARG(fieldNamesAndValues, fieldNamesAndValues.isEmpty());
310 fieldNamesAndValues.reserveCapacity(m_associatedElements.size());
311 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
312 FormAssociatedElement* control = m_associatedElements[i];
313 HTMLElement* element = toHTMLElement(control);
314 if (!element->hasLocalName(inputTag))
317 HTMLInputElement* input = static_cast<HTMLInputElement*>(control);
318 if (!input->isTextField())
321 fieldNamesAndValues.append(make_pair(input->name().string(), input->value()));
325 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
327 FrameView* view = document()->view();
328 Frame* frame = document()->frame();
332 if (m_isSubmittingOrPreparingForSubmission) {
333 m_shouldSubmit = true;
337 m_isSubmittingOrPreparingForSubmission = true;
338 m_wasUserSubmitted = processingUserGesture;
340 HTMLFormControlElement* firstSuccessfulSubmitButton = 0;
341 bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
343 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
344 FormAssociatedElement* associatedElement = m_associatedElements[i];
345 if (!associatedElement->isFormControlElement())
347 if (needButtonActivation) {
348 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(associatedElement);
349 if (control->isActivatedSubmit())
350 needButtonActivation = false;
351 else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
352 firstSuccessfulSubmitButton = control;
356 if (needButtonActivation && firstSuccessfulSubmitButton)
357 firstSuccessfulSubmitButton->setActivatedSubmit(true);
359 bool lockHistory = !processingUserGesture;
360 frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, lockHistory, formSubmissionTrigger));
362 if (needButtonActivation && firstSuccessfulSubmitButton)
363 firstSuccessfulSubmitButton->setActivatedSubmit(false);
365 m_shouldSubmit = false;
366 m_isSubmittingOrPreparingForSubmission = false;
369 void HTMLFormElement::reset()
371 Frame* frame = document()->frame();
372 if (m_isInResetFunction || !frame)
375 m_isInResetFunction = true;
377 if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
378 m_isInResetFunction = false;
382 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
383 if (m_associatedElements[i]->isFormControlElement())
384 static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
387 m_isInResetFunction = false;
390 void HTMLFormElement::parseAttribute(const Attribute& attribute)
392 if (attribute.name() == actionAttr)
393 m_attributes.parseAction(attribute.value());
394 else if (attribute.name() == targetAttr)
395 m_attributes.setTarget(attribute.value());
396 else if (attribute.name() == methodAttr)
397 m_attributes.updateMethodType(attribute.value());
398 else if (attribute.name() == enctypeAttr)
399 m_attributes.updateEncodingType(attribute.value());
400 else if (attribute.name() == accept_charsetAttr)
401 m_attributes.setAcceptCharset(attribute.value());
402 else if (attribute.name() == autocompleteAttr) {
403 if (!shouldAutocomplete())
404 document()->registerForPageCacheSuspensionCallbacks(this);
406 document()->unregisterForPageCacheSuspensionCallbacks(this);
407 } else if (attribute.name() == onsubmitAttr)
408 setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attribute));
409 else if (attribute.name() == onresetAttr)
410 setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attribute));
412 HTMLElement::parseAttribute(attribute);
415 template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
417 size_t size = vec.size();
418 for (size_t i = 0; i != size; ++i)
419 if (vec[i] == item) {
425 unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element, unsigned rangeStart, unsigned rangeEnd)
427 if (m_associatedElements.isEmpty())
430 ASSERT(rangeStart <= rangeEnd);
432 if (rangeStart == rangeEnd)
435 unsigned left = rangeStart;
436 unsigned right = rangeEnd - 1;
437 unsigned short position;
439 // Does binary search on m_associatedElements in order to find the index
441 while (left != right) {
442 unsigned middle = left + ((right - left) / 2);
443 ASSERT(middle < m_associatedElementsBeforeIndex || middle >= m_associatedElementsAfterIndex);
444 position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[middle]));
445 if (position & DOCUMENT_POSITION_FOLLOWING)
451 ASSERT(left < m_associatedElementsBeforeIndex || left >= m_associatedElementsAfterIndex);
452 position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[left]));
453 if (position & DOCUMENT_POSITION_FOLLOWING)
458 unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElement)
460 HTMLElement* element = toHTMLElement(associatedElement);
461 // Treats separately the case where this element has the form attribute
462 // for performance consideration.
463 if (element->fastHasAttribute(formAttr)) {
464 unsigned short position = compareDocumentPosition(element);
465 if (position & DOCUMENT_POSITION_PRECEDING) {
466 ++m_associatedElementsBeforeIndex;
467 ++m_associatedElementsAfterIndex;
468 return HTMLFormElement::formElementIndexWithFormAttribute(element, 0, m_associatedElementsBeforeIndex - 1);
470 if (position & DOCUMENT_POSITION_FOLLOWING && !(position & DOCUMENT_POSITION_CONTAINED_BY))
471 return HTMLFormElement::formElementIndexWithFormAttribute(element, m_associatedElementsAfterIndex, m_associatedElements.size());
474 // Check for the special case where this element is the very last thing in
475 // the form's tree of children; we don't want to walk the entire tree in that
476 // common case that occurs during parsing; instead we'll just return a value
477 // that says "add this form element to the end of the array".
478 if (element->traverseNextNode(this)) {
479 unsigned i = m_associatedElementsBeforeIndex;
480 for (Node* node = this; node; node = node->traverseNextNode(this)) {
481 if (node == element) {
482 ++m_associatedElementsAfterIndex;
485 if (node->isHTMLElement()
486 && (static_cast<Element*>(node)->isFormControlElement()
487 || node->hasTagName(objectTag))
488 && toHTMLElement(node)->form() == this)
492 return m_associatedElementsAfterIndex++;
495 void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
497 m_associatedElements.insert(formElementIndex(e), e);
500 void HTMLFormElement::removeFormElement(FormAssociatedElement* e)
503 for (index = 0; index < m_associatedElements.size(); ++index) {
504 if (m_associatedElements[index] == e)
507 ASSERT(index < m_associatedElements.size());
508 if (index < m_associatedElementsBeforeIndex)
509 --m_associatedElementsBeforeIndex;
510 if (index < m_associatedElementsAfterIndex)
511 --m_associatedElementsAfterIndex;
512 removeFromVector(m_associatedElements, e);
515 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const
517 return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribute);
520 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
522 ASSERT(m_imageElements.find(e) == notFound);
523 m_imageElements.append(e);
526 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
528 ASSERT(m_imageElements.find(e) != notFound);
529 removeFromVector(m_imageElements, e);
532 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
534 return ensureCachedHTMLCollection(FormControls);
537 String HTMLFormElement::name() const
539 return getNameAttribute();
542 bool HTMLFormElement::noValidate() const
544 return fastHasAttribute(novalidateAttr);
547 // FIXME: This function should be removed because it does not do the same thing as the
548 // JavaScript binding for action, which treats action as a URL attribute. Last time I
549 // (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
550 String HTMLFormElement::action() const
552 return getAttribute(actionAttr);
555 void HTMLFormElement::setAction(const String &value)
557 setAttribute(actionAttr, value);
560 void HTMLFormElement::setEnctype(const String &value)
562 setAttribute(enctypeAttr, value);
565 String HTMLFormElement::method() const
567 return FormSubmission::Attributes::methodString(m_attributes.method());
570 void HTMLFormElement::setMethod(const String &value)
572 setAttribute(methodAttr, value);
575 String HTMLFormElement::target() const
577 return getAttribute(targetAttr);
580 bool HTMLFormElement::wasUserSubmitted() const
582 return m_wasUserSubmitted;
585 HTMLFormControlElement* HTMLFormElement::defaultButton() const
587 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
588 if (!m_associatedElements[i]->isFormControlElement())
590 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(m_associatedElements[i]);
591 if (control->isSuccessfulSubmitButton())
598 bool HTMLFormElement::checkValidity()
600 Vector<RefPtr<FormAssociatedElement> > controls;
601 return !checkInvalidControlsAndCollectUnhandled(controls);
604 bool HTMLFormElement::checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement> >& unhandledInvalidControls)
606 RefPtr<HTMLFormElement> protector(this);
607 // Copy m_associatedElements because event handlers called from
608 // HTMLFormControlElement::checkValidity() might change m_associatedElements.
609 Vector<RefPtr<FormAssociatedElement> > elements;
610 elements.reserveCapacity(m_associatedElements.size());
611 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
612 elements.append(m_associatedElements[i]);
613 bool hasInvalidControls = false;
614 for (unsigned i = 0; i < elements.size(); ++i) {
615 if (elements[i]->form() == this && elements[i]->isFormControlElement()) {
616 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(elements[i].get());
617 if (!control->checkValidity(&unhandledInvalidControls) && control->form() == this)
618 hasInvalidControls = true;
621 return hasInvalidControls;
624 HTMLFormControlElement* HTMLFormElement::elementForAlias(const AtomicString& alias)
626 if (alias.isEmpty() || !m_elementAliases)
628 return m_elementAliases->get(alias.impl()).get();
631 void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
635 if (!m_elementAliases)
636 m_elementAliases = adoptPtr(new AliasMap);
637 m_elementAliases->set(alias.impl(), element);
640 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
642 elements()->namedItems(name, namedItems);
644 HTMLFormControlElement* aliasElement = elementForAlias(name);
646 if (namedItems.find(aliasElement) == notFound) {
647 // We have seen it before but it is gone now. Still, we need to return it.
648 // FIXME: The above comment is not clear enough; it does not say why we need to do this.
649 namedItems.append(aliasElement);
652 if (namedItems.size() && namedItems.first() != aliasElement)
653 addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
656 void HTMLFormElement::documentDidResumeFromPageCache()
658 ASSERT(!shouldAutocomplete());
660 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
661 if (m_associatedElements[i]->isFormControlElement())
662 static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
666 void HTMLFormElement::didMoveToNewDocument(Document* oldDocument)
668 if (!shouldAutocomplete()) {
670 oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
671 document()->registerForPageCacheSuspensionCallbacks(this);
674 HTMLElement::didMoveToNewDocument(oldDocument);
677 bool HTMLFormElement::shouldAutocomplete() const
679 return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
682 void HTMLFormElement::finishParsingChildren()
684 HTMLElement::finishParsingChildren();
685 document()->formController()->restoreControlStateIn(*this);
688 void HTMLFormElement::copyNonAttributePropertiesFromElement(const Element& source)
690 m_wasDemoted = static_cast<const HTMLFormElement&>(source).m_wasDemoted;
691 HTMLElement::copyNonAttributePropertiesFromElement(source);