diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp
index e3fdbb4d32..cab5213da4 100644
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -33,6 +33,7 @@
#include "nsFocusManager.h"
#include "mozilla/dom/HTMLFormElement.h"
#include "mozAutoDocUpdate.h"
+#include "mozilla/Preferences.h"
#define NS_IN_SUBMIT_CLICK (1 << 0)
#define NS_OUTER_ACTIVATE_EVENT (1 << 1)
@@ -186,6 +187,9 @@ HTMLButtonElement::ParseAttribute(int32_t aNamespaceID,
}
if (aAttribute == nsGkAtoms::formmethod) {
+ if (Preferences::GetBool("dom.dialog_element.enabled", false)) {
+ return aResult.ParseEnumValue(aValue, kFormMethodTableDialogEnabled, false);
+ }
return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
}
if (aAttribute == nsGkAtoms::formenctype) {
diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp
index c8bb526379..34476cd741 100644
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -321,6 +321,9 @@ HTMLFormElement::ParseAttribute(int32_t aNamespaceID,
{
if (aNamespaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::method) {
+ if (Preferences::GetBool("dom.dialog_element.enabled", false)) {
+ return aResult.ParseEnumValue(aValue, kFormMethodTableDialogEnabled, false);
+ }
return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
}
if (aAttribute == nsGkAtoms::enctype) {
@@ -686,6 +689,26 @@ HTMLFormElement::DoSubmit(WidgetEvent* aEvent)
//
// perform the submission
//
+ if (!submission) {
+ mIsSubmitting = false;
+#ifdef DEBUG
+ HTMLDialogElement* dialog = nullptr;
+ for (nsIContent* parent = GetParent(); parent;
+ parent = parent->GetParent()) {
+ dialog = HTMLDialogElement::FromContentOrNull(parent);
+ if (dialog) {
+ break;
+ }
+ }
+ MOZ_ASSERT(!dialog || !dialog->Open());
+#endif
+ return NS_OK;
+ }
+
+ if (DialogFormSubmission* dialogSubmission =
+ submission->GetAsDialogSubmission()) {
+ return SubmitDialog(dialogSubmission);
+ }
return SubmitSubmission(submission);
}
@@ -722,8 +745,10 @@ HTMLFormElement::BuildSubmission(HTMLFormSubmission** aFormSubmission,
//
// Dump the data into the submission object
//
- rv = WalkFormElements(*aFormSubmission);
- NS_ENSURE_SUBMIT_SUCCESS(rv);
+ if (!(*aFormSubmission)->GetAsDialogSubmission()) {
+ rv = WalkFormElements(*aFormSubmission);
+ NS_ENSURE_SUBMIT_SUCCESS(rv);
+ }
return NS_OK;
}
@@ -862,6 +887,22 @@ HTMLFormElement::SubmitSubmission(HTMLFormSubmission* aFormSubmission)
return rv;
}
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submit-dialog
+nsresult HTMLFormElement::SubmitDialog(DialogFormSubmission* aFormSubmission) {
+ mIsSubmitting = false;
+
+ // Close the dialog subject. If there is a result, let that be the return
+ // value.
+ HTMLDialogElement* dialog = aFormSubmission->DialogElement();
+ MOZ_ASSERT(dialog);
+
+ Optional retValue;
+ retValue = &aFormSubmission->ReturnValue();
+ dialog->Close(retValue);
+
+ return NS_OK;
+}
+
nsresult
HTMLFormElement::DoSecureToInsecureSubmitCheck(nsIURI* aActionURL,
bool* aCancelSubmit)
diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h
index f13eab9acc..102e24fdf9 100644
--- a/dom/html/HTMLFormElement.h
+++ b/dom/html/HTMLFormElement.h
@@ -483,6 +483,12 @@ protected:
*/
nsresult SubmitSubmission(HTMLFormSubmission* aFormSubmission);
+ /**
+ * Submit a form[method=dialog]
+ * @param aFormSubmission the submission object
+ */
+ nsresult SubmitDialog(DialogFormSubmission* aFormSubmission);
+
/**
* Notify any submit observers of the submit.
*
diff --git a/dom/html/HTMLFormSubmission.cpp b/dom/html/HTMLFormSubmission.cpp
index d447f51476..d098783dd7 100644
--- a/dom/html/HTMLFormSubmission.cpp
+++ b/dom/html/HTMLFormSubmission.cpp
@@ -944,6 +944,30 @@ HTMLFormSubmission::GetFromForm(nsGenericHTMLElement* aForm,
charset.AssignLiteral("UTF-8");
}
+ if (method == NS_FORM_METHOD_DIALOG) {
+ HTMLDialogElement* dialog = nullptr;
+ for (nsIContent* parent = aForm->GetParent(); parent;
+ parent = parent->GetParent()) {
+ dialog = HTMLDialogElement::FromContentOrNull(parent);
+ if (dialog) {
+ break;
+ }
+ }
+
+ // If there isn't one, or if it does not have an open attribute, do
+ // nothing.
+ if (!dialog || !dialog->Open()) {
+ return NS_OK;
+ }
+
+ nsAutoString result;
+ if (aOriginatingElement) {
+ aOriginatingElement->ResultForDialogSubmit(result);
+ }
+ *aFormSubmission = new DialogFormSubmission(result, charset, aOriginatingElement, dialog);
+ return NS_OK;
+ }
+
// Choose encoder
if (method == NS_FORM_METHOD_POST &&
enctype == NS_FORM_ENCTYPE_MULTIPART) {
diff --git a/dom/html/HTMLFormSubmission.h b/dom/html/HTMLFormSubmission.h
index 506aa668df..d2ea8df8b5 100644
--- a/dom/html/HTMLFormSubmission.h
+++ b/dom/html/HTMLFormSubmission.h
@@ -7,6 +7,7 @@
#define mozilla_dom_HTMLFormSubmission_h
#include "mozilla/Attributes.h"
+#include "mozilla/dom/HTMLDialogElement.h"
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsNCRFallbackEncoderWrapper.h"
@@ -121,6 +122,8 @@ public:
return mOriginatingElement.get();
}
+ virtual DialogFormSubmission* GetAsDialogSubmission() { return nullptr; }
+
protected:
/**
* Can only be constructed by subclasses.
@@ -168,6 +171,50 @@ private:
nsNCRFallbackEncoderWrapper mEncoder;
};
+
+class DialogFormSubmission final : public HTMLFormSubmission {
+ public:
+ DialogFormSubmission(nsAString& aResult,
+ const nsACString& aCharset, Element* aSubmitter,
+ HTMLDialogElement* aDialogElement)
+ : HTMLFormSubmission(aCharset, aSubmitter)
+ , mDialogElement(aDialogElement)
+ , mReturnValue(aResult) {
+ }
+
+ nsresult AddNameValuePair(const nsAString& aName,
+ const nsAString& aValue) override {
+ MOZ_CRASH("This method should not be called");
+ return NS_OK;
+ }
+
+ nsresult AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob) override {
+ MOZ_CRASH("This method should not be called");
+ return NS_OK;
+ }
+
+ nsresult AddNameDirectoryPair(const nsAString& aName,
+ Directory* aDirectory) override {
+ MOZ_CRASH("This method should not be called");
+ return NS_OK;
+ }
+
+ nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) override {
+ MOZ_CRASH("This method should not be called");
+ return NS_OK;
+ }
+
+ DialogFormSubmission* GetAsDialogSubmission() override { return this; }
+
+ HTMLDialogElement* DialogElement() { return mDialogElement; }
+
+ nsString& ReturnValue() { return mReturnValue; }
+
+ private:
+ const RefPtr mDialogElement;
+ nsString mReturnValue;
+};
+
/**
* Handle multipart/form-data encoding, which does files as well as normal
* inputs. This always does POST.
diff --git a/dom/html/HTMLFormSubmissionConstants.h b/dom/html/HTMLFormSubmissionConstants.h
index 261af61652..d3a880c58a 100644
--- a/dom/html/HTMLFormSubmissionConstants.h
+++ b/dom/html/HTMLFormSubmissionConstants.h
@@ -14,6 +14,13 @@ static const nsAttrValue::EnumTable kFormMethodTable[] = {
{ nullptr, 0 }
};
+static const nsAttrValue::EnumTable kFormMethodTableDialogEnabled[] = {
+ {"get", NS_FORM_METHOD_GET},
+ {"post", NS_FORM_METHOD_POST},
+ {"dialog", NS_FORM_METHOD_DIALOG},
+ {nullptr, 0}
+};
+
// Default method is 'get'.
static const nsAttrValue::EnumTable* kFormDefaultMethod = &kFormMethodTable[0];
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index dd2d134f8e..718e65c435 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1482,6 +1482,26 @@ NS_IMPL_STRING_ATTR(HTMLInputElement, Placeholder, placeholder)
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLInputElement, Type, type,
kInputDefaultType->tag)
+void HTMLInputElement::ResultForDialogSubmit(nsAString& aResult) {
+ if (mType == NS_FORM_INPUT_IMAGE) {
+ // Get a property set by the frame to find out where it was clicked.
+ nsIntPoint* lastClickedPoint =
+ static_cast(GetProperty(nsGkAtoms::imageClickedPoint));
+ int32_t x, y;
+ if (lastClickedPoint) {
+ x = lastClickedPoint->x;
+ y = lastClickedPoint->y;
+ } else {
+ x = y = 0;
+ }
+ aResult.AppendInt(x);
+ aResult.AppendLiteral(",");
+ aResult.AppendInt(y);
+ } else {
+ GetAttr(kNameSpaceID_None, nsGkAtoms::value, aResult);
+ }
+}
+
NS_IMETHODIMP
HTMLInputElement::GetAutocomplete(nsAString& aValue)
{
@@ -5916,6 +5936,9 @@ HTMLInputElement::ParseAttribute(int32_t aNamespaceID,
return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
}
if (aAttribute == nsGkAtoms::formenctype) {
+ if (Preferences::GetBool("dom.dialog_element.enabled", false)) {
+ return aResult.ParseEnumValue(aValue, kFormMethodTableDialogEnabled, false);
+ }
return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
}
if (aAttribute == nsGkAtoms::autocomplete) {
diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h
index 24fc7454ac..44e1f9c1ca 100644
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -968,6 +968,8 @@ protected:
const nsAttrValue* aOldValue,
bool aNotify) override;
+ virtual void ResultForDialogSubmit(nsAString& aResult) override;
+
/**
* Dispatch a select event. Returns true if the event was not cancelled.
*/
diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h
index 56812b445b..d2b7f45e9c 100644
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -861,6 +861,10 @@ public:
static bool
IsScrollGrabAllowed(JSContext*, JSObject*);
+ virtual inline void ResultForDialogSubmit(nsAString& aResult) {
+ GetAttr(kNameSpaceID_None, nsGkAtoms::value, aResult);
+ }
+
protected:
/**
* Add/remove this element to the documents name cache
diff --git a/dom/html/nsIForm.h b/dom/html/nsIForm.h
index 44eedc5103..6c2b1d8623 100644
--- a/dom/html/nsIForm.h
+++ b/dom/html/nsIForm.h
@@ -12,6 +12,7 @@ class nsIFormControl;
#define NS_FORM_METHOD_GET 0
#define NS_FORM_METHOD_POST 1
+#define NS_FORM_METHOD_DIALOG 2
#define NS_FORM_ENCTYPE_URLENCODED 0
#define NS_FORM_ENCTYPE_MULTIPART 1
#define NS_FORM_ENCTYPE_TEXTPLAIN 2
diff --git a/dom/html/nsIFormControl.h b/dom/html/nsIFormControl.h
index 067ac7cae8..1815c88543 100644
--- a/dom/html/nsIFormControl.h
+++ b/dom/html/nsIFormControl.h
@@ -16,6 +16,7 @@ namespace dom {
class Element;
class HTMLFieldSetElement;
class HTMLFormSubmission;
+class DialogFormSubmission;
} // namespace dom
} // namespace mozilla