diff --git a/components/script/dom/formdata.rs b/components/script/dom/formdata.rs index 2dce36757eb..d5302eb462e 100644 --- a/components/script/dom/formdata.rs +++ b/components/script/dom/formdata.rs @@ -20,7 +20,12 @@ use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::blob::Blob; use crate::dom::file::File; use crate::dom::globalscope::GlobalScope; -use crate::dom::htmlformelement::{FormDatum, FormDatumValue, HTMLFormElement}; +use crate::dom::htmlbuttonelement::HTMLButtonElement; +use crate::dom::htmlelement::HTMLElement; +use crate::dom::htmlformelement::{ + FormDatum, FormDatumValue, FormSubmitterElement, HTMLFormElement, +}; +use crate::dom::htmlinputelement::HTMLInputElement; use crate::script_runtime::CanGc; #[dom_struct] @@ -70,20 +75,60 @@ impl FormData { impl FormDataMethods for FormData { // https://xhr.spec.whatwg.org/#dom-formdata - fn Constructor( + fn Constructor<'a>( global: &GlobalScope, proto: Option, can_gc: CanGc, - form: Option<&HTMLFormElement>, + form: Option<&'a HTMLFormElement>, + submitter: Option<&'a HTMLElement>, ) -> Fallible> { + // Helper to validate the submitter + fn validate_submitter<'b>( + submitter: &'b HTMLElement, + form: &'b HTMLFormElement, + ) -> Result, Error> { + let submit_button = submitter + .downcast::() + .map(FormSubmitterElement::Button) + .or_else(|| { + submitter + .downcast::() + .map(FormSubmitterElement::Input) + }) + .ok_or(Error::Type( + "submitter is not a form submitter element".to_string(), + ))?; + + // Step 1.1.1. If submitter is not a submit button, then throw a TypeError. + if !submit_button.is_submit_button() { + return Err(Error::Type("submitter is not a submit button".to_string())); + } + + // Step 1.1.2. If submitter’s form owner is not form, then throw a "NotFoundError" + // DOMException. + if !matches!(submit_button.form_owner(), Some(owner) if *owner == *form) { + return Err(Error::NotFound); + } + + Ok(submit_button) + } + + // Step 1. If form is given, then: if let Some(opt_form) = form { - return match opt_form.get_form_dataset(None, None, can_gc) { + // Step 1.1. If submitter is non-null, then: + let submitter_element = submitter + .map(|s| validate_submitter(s, opt_form)) + .transpose()?; + + // Step 1.2. Let list be the result of constructing the entry list for form and submitter. + return match opt_form.get_form_dataset(submitter_element, None, can_gc) { Some(form_datums) => Ok(FormData::new_with_proto( Some(form_datums), global, proto, can_gc, )), + // Step 1.3. If list is null, then throw an "InvalidStateError" DOMException. None => Err(Error::InvalidState), }; } diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index cae5c4d5963..886684dc23f 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -1475,7 +1475,7 @@ impl FormSubmitterElement<'_> { } // https://html.spec.whatwg.org/multipage/#concept-submit-button - fn is_submit_button(&self) -> bool { + pub(crate) fn is_submit_button(&self) -> bool { match *self { // https://html.spec.whatwg.org/multipage/#image-button-state-(type=image) // https://html.spec.whatwg.org/multipage/#submit-button-state-(type=submit) @@ -1487,7 +1487,7 @@ impl FormSubmitterElement<'_> { } // https://html.spec.whatwg.org/multipage/#form-owner - fn form_owner(&self) -> Option> { + pub(crate) fn form_owner(&self) -> Option> { match *self { FormSubmitterElement::Button(button_el) => button_el.form_owner(), FormSubmitterElement::Input(input_el) => input_el.form_owner(), diff --git a/components/script/dom/webidls/FormData.webidl b/components/script/dom/webidls/FormData.webidl index ea07dd4249c..49d62aff182 100644 --- a/components/script/dom/webidls/FormData.webidl +++ b/components/script/dom/webidls/FormData.webidl @@ -10,7 +10,7 @@ typedef (File or USVString) FormDataEntryValue; [Exposed=(Window,Worker)] interface FormData { - [Throws] constructor(optional HTMLFormElement form); + [Throws] constructor(optional HTMLFormElement form, optional HTMLElement? submitter = null); undefined append(USVString name, USVString value); undefined append(USVString name, Blob value, optional USVString filename); undefined delete(USVString name); diff --git a/tests/wpt/meta/xhr/formdata/constructor-submitter.html.ini b/tests/wpt/meta/xhr/formdata/constructor-submitter.html.ini index 1f81e642bed..6590fc5018a 100644 --- a/tests/wpt/meta/xhr/formdata/constructor-submitter.html.ini +++ b/tests/wpt/meta/xhr/formdata/constructor-submitter.html.ini @@ -1,13 +1,4 @@ [constructor-submitter.html] - [FormData construction should throw a TypeError if a non-null submitter is not a submit button] - expected: FAIL - - [FormData construction should throw a 'NotFoundError' DOMException if a non-null submitter is not owned by the form] - expected: FAIL - - [The constructed FormData object should contain an in-tree-order entry for a named submit button submitter] - expected: FAIL - [The constructed FormData object should contain in-tree-order entries for an activated Image Button submitter] expected: FAIL