Bug 1518442 - Part 2: Implement Event-based form participation; r=smaug,edgar

For Event-based form participation specification PR:
https://github.com/whatwg/html/pull/4239

Differential Revision: https://phabricator.services.mozilla.com/D43986
This commit is contained in:
John Dai
2019-09-09 13:53:27 +00:00
parent a795993772
commit edce529109
6 changed files with 156 additions and 74 deletions

View File

@@ -39,6 +39,7 @@
// form submission
#include "HTMLFormSubmissionConstants.h"
#include "mozilla/dom/FormData.h"
#include "mozilla/dom/FormDataEvent.h"
#include "mozilla/Telemetry.h"
#include "nsIFormSubmitObserver.h"
#include "nsIObserverService.h"
@@ -117,7 +118,8 @@ HTMLFormElement::HTMLFormElement(
mDeferSubmission(false),
mNotifiedObservers(false),
mNotifiedObserversResult(false),
mEverTriedInvalidSubmit(false) {
mEverTriedInvalidSubmit(false),
mIsConstructingEntryList(false) {
// We start out valid.
AddStatesSilently(NS_EVENT_STATE_VALID);
}
@@ -504,7 +506,8 @@ nsresult HTMLFormElement::DoSubmitOrReset(WidgetEvent* aEvent,
if (eFormSubmit == aMessage) {
// Don't submit if we're not in a document or if we're in
// a sandboxed frame and form submit is disabled.
if (!doc || (doc->GetSandboxFlags() & SANDBOXED_FORMS)) {
if (mIsConstructingEntryList || !doc ||
(doc->GetSandboxFlags() & SANDBOXED_FORMS)) {
return NS_OK;
}
return DoSubmit(aEvent);
@@ -555,6 +558,13 @@ nsresult HTMLFormElement::DoSubmit(WidgetEvent* aEvent) {
// prepare the submission object
//
nsresult rv = BuildSubmission(getter_Transfers(submission), aEvent);
// Don't raise an error if form cannot navigate.
if (rv == NS_ERROR_NOT_AVAILABLE) {
mIsSubmitting = false;
return NS_OK;
}
if (NS_FAILED(rv)) {
mIsSubmitting = false;
return rv;
@@ -606,17 +616,33 @@ nsresult HTMLFormElement::BuildSubmission(HTMLFormSubmission** aFormSubmission,
nsresult rv;
//
// Walk over the form elements and call SubmitNamesValues() on them to get
// their data.
//
auto encoding = GetSubmitEncoding()->OutputEncoding();
RefPtr<FormData> formData =
new FormData(GetOwnerGlobal(), encoding, originatingElement);
rv = ConstructEntryList(formData);
NS_ENSURE_SUBMIT_SUCCESS(rv);
// Step 9. If form cannot navigate, then return.
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm
if (!GetComposedDoc()) {
return NS_ERROR_NOT_AVAILABLE;
}
//
// Get the submission object
//
rv = HTMLFormSubmission::GetFromForm(this, originatingElement,
rv = HTMLFormSubmission::GetFromForm(this, originatingElement, encoding,
aFormSubmission);
NS_ENSURE_SUBMIT_SUCCESS(rv);
//
// Dump the data into the submission object
//
rv = WalkFormElements(*aFormSubmission);
rv = formData->CopySubmissionDataTo(*aFormSubmission);
NS_ENSURE_SUBMIT_SUCCESS(rv);
return NS_OK;
@@ -857,8 +883,15 @@ nsresult HTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
return rv;
}
nsresult HTMLFormElement::WalkFormElements(
HTMLFormSubmission* aFormSubmission) {
nsresult HTMLFormElement::ConstructEntryList(FormData* aFormData) {
MOZ_ASSERT(aFormData, "Must have FormData!");
if (mIsConstructingEntryList) {
// Step 2.2 of https://xhr.spec.whatwg.org/#dom-formdata.
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
AutoRestore<bool> resetConstructingEntryList(mIsConstructingEntryList);
mIsConstructingEntryList = true;
// This shouldn't be called recursively, so use a rather large value
// for the preallocated buffer.
AutoTArray<RefPtr<nsGenericHTMLFormElement>, 100> sortedControls;
@@ -872,12 +905,56 @@ nsresult HTMLFormElement::WalkFormElements(
//
for (uint32_t i = 0; i < len; ++i) {
// Tell the control to submit its name/value pairs to the submission
sortedControls[i]->SubmitNamesValues(aFormSubmission);
sortedControls[i]->SubmitNamesValues(aFormData);
}
FormDataEventInit init;
init.mBubbles = true;
init.mCancelable = false;
init.mFormData = aFormData;
RefPtr<FormDataEvent> event =
FormDataEvent::Constructor(this, NS_LITERAL_STRING("formdata"), init);
event->SetTrusted(true);
EventDispatcher::DispatchDOMEvent(ToSupports(this), nullptr, event, nullptr,
nullptr);
return NS_OK;
}
NotNull<const Encoding*> HTMLFormElement::GetSubmitEncoding() {
nsAutoString acceptCharsetValue;
GetAttr(kNameSpaceID_None, nsGkAtoms::acceptcharset, acceptCharsetValue);
int32_t charsetLen = acceptCharsetValue.Length();
if (charsetLen > 0) {
int32_t offset = 0;
int32_t spPos = 0;
// get charset from charsets one by one
do {
spPos = acceptCharsetValue.FindChar(char16_t(' '), offset);
int32_t cnt = ((-1 == spPos) ? (charsetLen - offset) : (spPos - offset));
if (cnt > 0) {
nsAutoString uCharset;
acceptCharsetValue.Mid(uCharset, offset, cnt);
auto encoding = Encoding::ForLabelNoReplacement(uCharset);
if (encoding) {
return WrapNotNull(encoding);
}
}
offset = spPos + 1;
} while (spPos != -1);
}
// if there are no accept-charset or all the charset are not supported
// Get the charset from document
Document* doc = GetComposedDoc();
if (doc) {
return doc->GetDocumentCharacterSet();
}
return UTF_8_ENCODING;
}
// nsIForm
NS_IMETHODIMP_(uint32_t)