diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-04-27 08:05:25 -0500 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-04-27 08:05:25 -0500 |
commit | 56105e9f2fb390b431416473a616000636ad409c (patch) | |
tree | 1af5cd41883bc97ccb912d818affbc4887dac27c /components/script | |
parent | 0cd0abb7186c4a67458f5b3af825502a6709a21c (diff) | |
parent | 69110297c9b2ea16a873147fa2748b144b372f14 (diff) | |
download | servo-56105e9f2fb390b431416473a616000636ad409c.tar.gz servo-56105e9f2fb390b431416473a616000636ad409c.zip |
Auto merge of #5865 - gfxmonk:implicit-submit, r=Manishearth
With submission-blocking rules from https://html.spec.whatwg.org/multipage/forms.html#implicit-submission.
I wasn't sure if/where it would be relevant to add new tests (I couldn't find any existing tests in wpt to enable), so just let me know if this needs tests.
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/5865)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/htmlinputelement.rs | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 56596a181e9..c68e70f3f74 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -8,6 +8,7 @@ use dom::attr::AttrHelpers; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::Bindings::EventBinding::EventMethods; +use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods; use dom::bindings::codegen::Bindings::HTMLInputElementBinding; use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLInputElementCast, NodeCast}; @@ -617,8 +618,16 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLInputElement> { self.input_type.get() == InputType::InputPassword) { let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event); keyevent.map(|keyevent| { - match self.textinput.borrow_mut().handle_keydown(keyevent) { - TriggerDefaultAction => (), + // This can't be inlined, as holding on to textinput.borrow_mut() + // during self.implicit_submission will cause a panic. + let action = self.textinput.borrow_mut().handle_keydown(keyevent); + match action { + TriggerDefaultAction => { + self.implicit_submission(keyevent.CtrlKey(), + keyevent.ShiftKey(), + keyevent.AltKey(), + keyevent.MetaKey()); + }, DispatchInput => { self.value_changed.set(true); self.force_relayout(); @@ -813,18 +822,57 @@ impl<'a> Activatable for JSRef<'a, HTMLInputElement> { let doc = document_from_node(*self).root(); let node: JSRef<Node> = NodeCast::from_ref(doc.r()); let owner = self.form_owner(); + let form = match owner { + None => return, + Some(ref f) => f.root() + }; + let elem: JSRef<Element> = ElementCast::from_ref(*self); - if owner.is_none() || elem.click_in_progress() { + if elem.click_in_progress() { return; } // This is safe because we are stopping after finding the first element // and only then performing actions which may modify the DOM tree + let submit_button; unsafe { - node.query_selector_iter("input[type=submit]".to_owned()).unwrap() + submit_button = node.query_selector_iter("input[type=submit]".to_owned()).unwrap() .filter_map(HTMLInputElementCast::to_temporary) .map(|t| t.root()) - .find(|r| r.r().form_owner() == owner) - .map(|s| s.r().synthetic_click_activation(ctrlKey, shiftKey, altKey, metaKey)); + .find(|r| r.r().form_owner() == owner); + } + match submit_button { + Some(button) => { + if button.r().is_instance_activatable() { + button.r().synthetic_click_activation(ctrlKey, shiftKey, altKey, metaKey) + } + } + None => { + unsafe { + // Safe because we don't perform any DOM modification + // until we're done with the iterator. + let inputs = node.query_selector_iter("input".to_owned()).unwrap() + .filter_map(HTMLInputElementCast::to_temporary) + .filter(|input| { + let input = input.root(); + input.r().form_owner() == owner && match input.r().Type().as_slice() { + "text" | "search" | "url" | "tel" | + "email" | "password" | "datetime" | + "date" | "month" | "week" | "time" | + "datetime-local" | "number" + => true, + _ => false + } + }); + + if inputs.skip(1).next().is_some() { + // lazily test for > 1 submission-blocking inputs + return; + } + } + + form.r().submit(SubmittedFrom::NotFromFormSubmitMethod, + FormSubmitter::FormElement(form.r())); + } } } } |