mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
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 -->
This commit is contained in:
commit
56105e9f2f
2 changed files with 59 additions and 9 deletions
|
@ -8,6 +8,7 @@ use dom::attr::AttrHelpers;
|
||||||
use dom::bindings::cell::DOMRefCell;
|
use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
|
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
|
||||||
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
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;
|
||||||
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLInputElementCast, NodeCast};
|
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) {
|
self.input_type.get() == InputType::InputPassword) {
|
||||||
let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event);
|
let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event);
|
||||||
keyevent.map(|keyevent| {
|
keyevent.map(|keyevent| {
|
||||||
match self.textinput.borrow_mut().handle_keydown(keyevent) {
|
// This can't be inlined, as holding on to textinput.borrow_mut()
|
||||||
TriggerDefaultAction => (),
|
// 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 => {
|
DispatchInput => {
|
||||||
self.value_changed.set(true);
|
self.value_changed.set(true);
|
||||||
self.force_relayout();
|
self.force_relayout();
|
||||||
|
@ -813,18 +822,57 @@ impl<'a> Activatable for JSRef<'a, HTMLInputElement> {
|
||||||
let doc = document_from_node(*self).root();
|
let doc = document_from_node(*self).root();
|
||||||
let node: JSRef<Node> = NodeCast::from_ref(doc.r());
|
let node: JSRef<Node> = NodeCast::from_ref(doc.r());
|
||||||
let owner = self.form_owner();
|
let owner = self.form_owner();
|
||||||
|
let form = match owner {
|
||||||
|
None => return,
|
||||||
|
Some(ref f) => f.root()
|
||||||
|
};
|
||||||
|
|
||||||
let elem: JSRef<Element> = ElementCast::from_ref(*self);
|
let elem: JSRef<Element> = ElementCast::from_ref(*self);
|
||||||
if owner.is_none() || elem.click_in_progress() {
|
if elem.click_in_progress() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// This is safe because we are stopping after finding the first element
|
// This is safe because we are stopping after finding the first element
|
||||||
// and only then performing actions which may modify the DOM tree
|
// and only then performing actions which may modify the DOM tree
|
||||||
|
let submit_button;
|
||||||
unsafe {
|
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)
|
.filter_map(HTMLInputElementCast::to_temporary)
|
||||||
.map(|t| t.root())
|
.map(|t| t.root())
|
||||||
.find(|r| r.r().form_owner() == owner)
|
.find(|r| r.r().form_owner() == owner);
|
||||||
.map(|s| s.r().synthetic_click_activation(ctrlKey, shiftKey, altKey, metaKey));
|
}
|
||||||
|
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()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,17 +151,19 @@ impl Window {
|
||||||
(_, VirtualKeyCode::LAlt) => self.toggle_modifier(LEFT_ALT),
|
(_, VirtualKeyCode::LAlt) => self.toggle_modifier(LEFT_ALT),
|
||||||
(_, VirtualKeyCode::RAlt) => self.toggle_modifier(RIGHT_ALT),
|
(_, VirtualKeyCode::RAlt) => self.toggle_modifier(RIGHT_ALT),
|
||||||
(ElementState::Pressed, VirtualKeyCode::Escape) => return true,
|
(ElementState::Pressed, VirtualKeyCode::Escape) => return true,
|
||||||
(ElementState::Pressed, key_code) => {
|
(_, key_code) => {
|
||||||
match Window::glutin_key_to_script_key(key_code) {
|
match Window::glutin_key_to_script_key(key_code) {
|
||||||
Ok(key) => {
|
Ok(key) => {
|
||||||
let state = KeyState::Pressed;
|
let state = match element_state {
|
||||||
|
ElementState::Pressed => KeyState::Pressed,
|
||||||
|
ElementState::Released => KeyState::Released,
|
||||||
|
};
|
||||||
let modifiers = Window::glutin_mods_to_script_mods(self.key_modifiers.get());
|
let modifiers = Window::glutin_mods_to_script_mods(self.key_modifiers.get());
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::KeyEvent(key, state, modifiers));
|
self.event_queue.borrow_mut().push(WindowEvent::KeyEvent(key, state, modifiers));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, _) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue