Issue #2532 - Implement form[method=dialog]

See bug 1557303
This commit is contained in:
Moonchild 2024-06-15 10:11:00 +02:00 committed by roytam1
commit 6ee3f46900
11 changed files with 162 additions and 2 deletions

View file

@ -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) {

View file

@ -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<nsAString> retValue;
retValue = &aFormSubmission->ReturnValue();
dialog->Close(retValue);
return NS_OK;
}
nsresult
HTMLFormElement::DoSecureToInsecureSubmitCheck(nsIURI* aActionURL,
bool* aCancelSubmit)

View file

@ -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.
*

View file

@ -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) {

View file

@ -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<HTMLDialogElement> mDialogElement;
nsString mReturnValue;
};
/**
* Handle multipart/form-data encoding, which does files as well as normal
* inputs. This always does POST.

View file

@ -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];

View file

@ -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<nsIntPoint*>(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) {

View file

@ -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.
*/

View file

@ -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

View file

@ -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

View file

@ -16,6 +16,7 @@ namespace dom {
class Element;
class HTMLFieldSetElement;
class HTMLFormSubmission;
class DialogFormSubmission;
} // namespace dom
} // namespace mozilla