aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCYBAI <cyb.ai.815@gmail.com>2019-01-09 18:57:35 +0800
committerCYBAI <cyb.ai.815@gmail.com>2019-01-23 00:38:44 +0800
commit9d70f5135614b8fa0ba4e1322ac114587b959eb5 (patch)
treefa73d59cfa8b8b4276cd9d586c637e8f2821c61e
parent477b6ef886401e54fa9dbe4b07298cf5cafc0315 (diff)
downloadservo-9d70f5135614b8fa0ba4e1322ac114587b959eb5.tar.gz
servo-9d70f5135614b8fa0ba4e1322ac114587b959eb5.zip
Implement formdata event
-rw-r--r--components/atoms/static_atoms.txt1
-rw-r--r--components/script/dom/formdata.rs24
-rw-r--r--components/script/dom/formdataevent.rs90
-rwxr-xr-xcomponents/script/dom/htmlformelement.rs86
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/webidls/FormDataEvent.webidl14
-rw-r--r--tests/wpt/metadata/html/dom/interfaces.https.html.ini30
-rw-r--r--tests/wpt/metadata/html/semantics/forms/form-submission-0/FormDataEvent.window.js.ini7
-rw-r--r--tests/wpt/metadata/html/semantics/forms/form-submission-0/constructing-form-data-set.html.ini10
-rw-r--r--tests/wpt/metadata/html/semantics/forms/form-submission-0/form-submission-algorithm.html.ini4
-rw-r--r--tests/wpt/metadata/xhr/formdata.htm.ini7
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json2
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.html1
13 files changed, 188 insertions, 89 deletions
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt
index e14826f8430..db5680256f7 100644
--- a/components/atoms/static_atoms.txt
+++ b/components/atoms/static_atoms.txt
@@ -30,6 +30,7 @@ error
fantasy
fetch
file
+formdata
fullscreenchange
fullscreenerror
gattserverdisconnected
diff --git a/components/script/dom/formdata.rs b/components/script/dom/formdata.rs
index 2150e2aa7e5..7a084ca0162 100644
--- a/components/script/dom/formdata.rs
+++ b/components/script/dom/formdata.rs
@@ -6,7 +6,7 @@ use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::FormDataBinding::FormDataMethods;
use crate::dom::bindings::codegen::Bindings::FormDataBinding::FormDataWrap;
use crate::dom::bindings::codegen::UnionTypes::FileOrUSVString;
-use crate::dom::bindings::error::Fallible;
+use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::iterable::Iterable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
@@ -26,10 +26,9 @@ pub struct FormData {
}
impl FormData {
- fn new_inherited(opt_form: Option<&HTMLFormElement>) -> FormData {
- let data = match opt_form {
- Some(form) => form
- .get_form_dataset(None)
+ fn new_inherited(form_datums: Option<Vec<FormDatum>>) -> FormData {
+ let data = match form_datums {
+ Some(data) => data
.iter()
.map(|datum| (LocalName::from(datum.name.as_ref()), datum.clone()))
.collect::<Vec<(LocalName, FormDatum)>>(),
@@ -42,20 +41,27 @@ impl FormData {
}
}
- pub fn new(form: Option<&HTMLFormElement>, global: &GlobalScope) -> DomRoot<FormData> {
+ pub fn new(form_datums: Option<Vec<FormDatum>>, global: &GlobalScope) -> DomRoot<FormData> {
reflect_dom_object(
- Box::new(FormData::new_inherited(form)),
+ Box::new(FormData::new_inherited(form_datums)),
global,
FormDataWrap,
)
}
+ // https://xhr.spec.whatwg.org/#dom-formdata
pub fn Constructor(
global: &GlobalScope,
form: Option<&HTMLFormElement>,
) -> Fallible<DomRoot<FormData>> {
- // TODO: Construct form data set for form if it is supplied
- Ok(FormData::new(form, global))
+ if let Some(opt_form) = form {
+ return match opt_form.get_form_dataset(None) {
+ Some(form_datums) => Ok(FormData::new(Some(form_datums), global)),
+ None => Err(Error::InvalidState),
+ };
+ }
+
+ Ok(FormData::new(None, global))
}
}
diff --git a/components/script/dom/formdataevent.rs b/components/script/dom/formdataevent.rs
new file mode 100644
index 00000000000..f7ebb57bbfb
--- /dev/null
+++ b/components/script/dom/formdataevent.rs
@@ -0,0 +1,90 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
+use crate::dom::bindings::codegen::Bindings::FormDataEventBinding;
+use crate::dom::bindings::codegen::Bindings::FormDataEventBinding::FormDataEventMethods;
+use crate::dom::bindings::error::{Error, Fallible};
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::event::Event;
+use crate::dom::event::{EventBubbles, EventCancelable};
+use crate::dom::formdata::FormData;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
+use dom_struct::dom_struct;
+use servo_atoms::Atom;
+
+#[dom_struct]
+pub struct FormDataEvent {
+ event: Event,
+ form_data: Dom<FormData>,
+}
+
+impl FormDataEvent {
+ pub fn new(
+ global: &GlobalScope,
+ type_: Atom,
+ can_bubble: EventBubbles,
+ cancelable: EventCancelable,
+ form_data: &FormData,
+ ) -> DomRoot<FormDataEvent> {
+ let ev = reflect_dom_object(
+ Box::new(FormDataEvent {
+ event: Event::new_inherited(),
+ form_data: Dom::from_ref(form_data),
+ }),
+ global,
+ FormDataEventBinding::Wrap,
+ );
+
+ {
+ let event = ev.upcast::<Event>();
+ event.init_event(type_, bool::from(can_bubble), bool::from(cancelable));
+ }
+ ev
+ }
+
+ pub fn Constructor(
+ window: &Window,
+ type_: DOMString,
+ init: &FormDataEventBinding::FormDataEventInit,
+ ) -> Fallible<DomRoot<FormDataEvent>> {
+ let bubbles = EventBubbles::from(init.parent.bubbles);
+ let cancelable = EventCancelable::from(init.parent.cancelable);
+
+ let form_data = match init.formData {
+ Some(ref form_data) => form_data.clone(),
+ None => {
+ return Err(Error::Type(
+ "required member formData is undefined".to_string(),
+ ));
+ },
+ };
+
+ let event = FormDataEvent::new(
+ &window.global(),
+ Atom::from(type_),
+ bubbles,
+ cancelable,
+ &*form_data,
+ );
+
+ Ok(event)
+ }
+}
+
+impl FormDataEventMethods for FormDataEvent {
+ // https://html.spec.whatwg.org/multipage/#dom-formdataevent-formdata
+ fn FormData(&self) -> DomRoot<FormData> {
+ DomRoot::from_ref(&*self.form_data)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-event-istrusted
+ fn IsTrusted(&self) -> bool {
+ self.event.IsTrusted()
+ }
+}
diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs
index 5469f0b7fc5..6a4a4b97fe5 100755
--- a/components/script/dom/htmlformelement.rs
+++ b/components/script/dom/htmlformelement.rs
@@ -20,8 +20,11 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::blob::Blob;
use crate::dom::document::Document;
use crate::dom::element::{AttributeMutation, Element};
+use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::file::File;
+use crate::dom::formdata::FormData;
+use crate::dom::formdataevent::FormDataEvent;
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlbuttonelement::HTMLButtonElement;
use crate::dom::htmlcollection::CollectionFilter;
@@ -68,6 +71,8 @@ pub struct GenerationId(u32);
pub struct HTMLFormElement {
htmlelement: HTMLElement,
marked_for_reset: Cell<bool>,
+ /// https://html.spec.whatwg.org/multipage/#constructing-entry-list
+ constructing_entry_list: Cell<bool>,
elements: DomOnceCell<HTMLFormControlsCollection>,
generation_id: Cell<GenerationId>,
controls: DomRefCell<Vec<Dom<Element>>>,
@@ -82,6 +87,7 @@ impl HTMLFormElement {
HTMLFormElement {
htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
marked_for_reset: Cell::new(false),
+ constructing_entry_list: Cell::new(false),
elements: Default::default(),
generation_id: Cell::new(GenerationId(0)),
controls: DomRefCell::new(Vec::new()),
@@ -311,11 +317,16 @@ impl HTMLFormElement {
/// [Form submission](https://html.spec.whatwg.org/multipage/#concept-form-submit)
pub fn submit(&self, submit_method_flag: SubmittedFrom, submitter: FormSubmitter) {
- // Step 1
+ // TODO: Step 1. If form cannot navigate , then return.
+ // Step 2
+ if self.constructing_entry_list.get() {
+ return;
+ }
+ // Step 3
let doc = document_from_node(self);
let base = doc.base_url();
- // TODO: Handle browsing contexts (Step 2, 3)
- // Step 4
+ // TODO: Handle browsing contexts (Step 4, 5)
+ // Step 6
if submit_method_flag == SubmittedFrom::NotFromForm && !submitter.no_validate(self) {
if self.interactive_validation().is_err() {
// TODO: Implement event handlers on all form control elements
@@ -323,7 +334,7 @@ impl HTMLFormElement {
return;
}
}
- // Step 5
+ // Step 7
if submit_method_flag == SubmittedFrom::NotFromForm {
let event = self
.upcast::<EventTarget>()
@@ -332,30 +343,36 @@ impl HTMLFormElement {
return;
}
}
- // Step 6
- let mut form_data = self.get_form_dataset(Some(submitter));
- // Step 7
+ // Step 8
let encoding = self.pick_encoding();
- // Step 8
+ // Step 9
+ let mut form_data = match self.get_form_dataset(Some(submitter)) {
+ Some(form_data) => form_data,
+ None => return,
+ };
+
+ // TODO: Step 10. If form cannot navigate, then return.
+
+ // Step 11
let mut action = submitter.action();
- // Step 9
+ // Step 12
if action.is_empty() {
action = DOMString::from(base.as_str());
}
- // Step 10-11
+ // Step 13-14
let action_components = match base.join(&action) {
Ok(url) => url,
Err(_) => return,
};
- // Step 12-15
+ // Step 15-17
let scheme = action_components.scheme().to_owned();
let enctype = submitter.enctype();
let method = submitter.method();
- // Step 16, 17
+ // Step 18-21
let target_attribute_value = submitter.target();
let source = doc.browsing_context().unwrap();
let (maybe_chosen, _new) = source.choose_browsing_context(target_attribute_value, false);
@@ -375,7 +392,7 @@ impl HTMLFormElement {
Some(target_document.url()),
);
- // Step 18
+ // Step 22
match (&*scheme, method) {
(_, FormMethod::FormDialog) => {
// TODO: Submit dialog
@@ -597,18 +614,18 @@ impl HTMLFormElement {
}
/// <https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set>
- /// Steps range from 1 to 3
+ /// Steps range from 3 to 5
fn get_unclean_dataset(&self, submitter: Option<FormSubmitter>) -> Vec<FormDatum> {
let controls = self.controls.borrow();
let mut data_set = Vec::new();
for child in controls.iter() {
- // Step 3.1: The field element is disabled.
+ // Step 5.1: The field element is disabled.
if child.disabled_state() {
continue;
}
let child = child.upcast::<Node>();
- // Step 3.1: The field element has a datalist element ancestor.
+ // Step 5.1: The field element has a datalist element ancestor.
if child
.ancestors()
.any(|a| DomRoot::downcast::<HTMLDataListElement>(a).is_some())
@@ -657,7 +674,7 @@ impl HTMLFormElement {
}
/// <https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set>
- pub fn get_form_dataset(&self, submitter: Option<FormSubmitter>) -> Vec<FormDatum> {
+ pub fn get_form_dataset(&self, submitter: Option<FormSubmitter>) -> Option<Vec<FormDatum>> {
fn clean_crlf(s: &str) -> DOMString {
// Step 4
let mut buf = "".to_owned();
@@ -689,9 +706,16 @@ impl HTMLFormElement {
DOMString::from(buf)
}
- // Step 1-3
+ // Step 1
+ if self.constructing_entry_list.get() {
+ return None;
+ }
+
+ // Step 2
+ self.constructing_entry_list.set(true);
+
+ // Step 3-6
let mut ret = self.get_unclean_dataset(submitter);
- // Step 4
for datum in &mut ret {
match &*datum.ty {
"file" | "textarea" => (), // TODO
@@ -704,8 +728,28 @@ impl HTMLFormElement {
},
}
}
- // Step 5
- ret
+
+ let window = window_from_node(self);
+
+ // Step 6
+ let form_data = FormData::new(Some(ret), &window.global());
+
+ // Step 7
+ let event = FormDataEvent::new(
+ &window.global(),
+ atom!("formdata"),
+ EventBubbles::Bubbles,
+ EventCancelable::NotCancelable,
+ &form_data,
+ );
+
+ event.upcast::<Event>().fire(self.upcast::<EventTarget>());
+
+ // Step 8
+ self.constructing_entry_list.set(false);
+
+ // Step 9
+ Some(form_data.datums())
}
pub fn reset(&self, _reset_method_flag: ResetFrom) {
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index d316000eee4..4d8e89d274f 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -303,6 +303,7 @@ pub mod filereader;
pub mod filereadersync;
pub mod focusevent;
pub mod formdata;
+pub mod formdataevent;
pub mod gainnode;
pub mod gamepad;
pub mod gamepadbutton;
diff --git a/components/script/dom/webidls/FormDataEvent.webidl b/components/script/dom/webidls/FormDataEvent.webidl
new file mode 100644
index 00000000000..d34f57b3a09
--- /dev/null
+++ b/components/script/dom/webidls/FormDataEvent.webidl
@@ -0,0 +1,14 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://html.spec.whatwg.org/multipage/#the-formdataevent-interface
+[Exposed=Window,
+ Constructor(DOMString type, optional FormDataEventInit eventInitDict)]
+interface FormDataEvent : Event {
+ readonly attribute FormData formData;
+};
+
+dictionary FormDataEventInit : EventInit {
+ /*required*/ FormData formData;
+};
diff --git a/tests/wpt/metadata/html/dom/interfaces.https.html.ini b/tests/wpt/metadata/html/dom/interfaces.https.html.ini
index a8713f72d2e..09b0653c697 100644
--- a/tests/wpt/metadata/html/dom/interfaces.https.html.ini
+++ b/tests/wpt/metadata/html/dom/interfaces.https.html.ini
@@ -10940,36 +10940,6 @@
[ImageData interface: new ImageData(10, 10) must inherit property "data" with the proper type]
expected: FAIL
- [FormDataEvent interface object name]
- expected: FAIL
-
- [FormDataEvent interface: existence and properties of interface prototype object's "constructor" property]
- expected: FAIL
-
- [FormDataEvent interface: existence and properties of interface prototype object's @@unscopables property]
- expected: FAIL
-
- [FormDataEvent interface: attribute formData]
- expected: FAIL
-
- [Stringification of new FormDataEvent("formdata", { formData: new FormData() })]
- expected: FAIL
-
- [FormDataEvent interface: new FormDataEvent("formdata", { formData: new FormData() }) must inherit property "formData" with the proper type]
- expected: FAIL
-
- [FormDataEvent interface: existence and properties of interface object]
- expected: FAIL
-
- [FormDataEvent interface object length]
- expected: FAIL
-
- [FormDataEvent must be primary interface of new FormDataEvent("formdata", { formData: new FormData() })]
- expected: FAIL
-
- [FormDataEvent interface: existence and properties of interface prototype object]
- expected: FAIL
-
[OffscreenCanvasRenderingContext2D interface: operation measureText(DOMString)]
expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/FormDataEvent.window.js.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/FormDataEvent.window.js.ini
deleted file mode 100644
index 73c78e8da19..00000000000
--- a/tests/wpt/metadata/html/semantics/forms/form-submission-0/FormDataEvent.window.js.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[FormDataEvent.window.html]
- [Successful FormDataEvent constructor]
- expected: FAIL
-
- [Failing FormDataEvent constructor]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/constructing-form-data-set.html.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/constructing-form-data-set.html.ini
index 8916c9b84fd..956dc69251e 100644
--- a/tests/wpt/metadata/html/semantics/forms/form-submission-0/constructing-form-data-set.html.ini
+++ b/tests/wpt/metadata/html/semantics/forms/form-submission-0/constructing-form-data-set.html.ini
@@ -10,13 +10,3 @@
[Entries added to "formData" IDL attribute should be submitted.]
expected: FAIL
-
- ["formData" IDL attribute should have entries for form-associated elements in the first event handler, and the second handler can read entries set by the first handler.]
- expected: FAIL
-
- ["formdata" event bubbles, and is not cancelable.]
- expected: FAIL
-
- ["formdata" event bubbles in an orphan tree.]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-submission-algorithm.html.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-submission-algorithm.html.ini
deleted file mode 100644
index be6f220e3a4..00000000000
--- a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-submission-algorithm.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[form-submission-algorithm.html]
- [If constructing entry list flag of form is true, then return]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/xhr/formdata.htm.ini b/tests/wpt/metadata/xhr/formdata.htm.ini
deleted file mode 100644
index cf8cacd24af..00000000000
--- a/tests/wpt/metadata/xhr/formdata.htm.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[formdata.htm]
- [|new FormData()| in formdata event handler should throw]
- expected: FAIL
-
- [Newly created FormData contains entries added to "formData" IDL attribute of FormDataEvent.]
- expected: FAIL
-
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index 86ac13bc878..16cb02a6068 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -27102,7 +27102,7 @@
"testharness"
],
"mozilla/interfaces.html": [
- "95ab0109c82c8e90a3e53a3579b9337e2091e26c",
+ "55cafc9995da83d48230eed5b5c3863d8cf173c9",
"testharness"
],
"mozilla/interfaces.js": [
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html
index 95ab0109c82..55cafc9995d 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.html
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html
@@ -77,6 +77,7 @@ test_interfaces([
"FileReader",
"FocusEvent",
"FormData",
+ "FormDataEvent",
"GainNode",
"HashChangeEvent",
"Headers",