mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Move InputRadio to Activatable
This commit is contained in:
parent
a5180a473d
commit
e68119f82f
1 changed files with 114 additions and 35 deletions
|
@ -16,7 +16,7 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLFor
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLFieldSetElementDerived, EventTargetCast};
|
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLFieldSetElementDerived, EventTargetCast};
|
||||||
use dom::bindings::codegen::InheritTypes::KeyboardEventCast;
|
use dom::bindings::codegen::InheritTypes::KeyboardEventCast;
|
||||||
use dom::bindings::global::Window;
|
use dom::bindings::global::Window;
|
||||||
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, ResultRootable};
|
use dom::bindings::js::{JS, JSRef, Root, Temporary, OptionalRootable, ResultRootable, MutNullableJS};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::document::{Document, DocumentHelpers};
|
use dom::document::{Document, DocumentHelpers};
|
||||||
use dom::element::{AttributeHandlers, Element, HTMLInputElementTypeId};
|
use dom::element::{AttributeHandlers, Element, HTMLInputElementTypeId};
|
||||||
|
@ -37,6 +37,7 @@ use string_cache::Atom;
|
||||||
use std::ascii::OwnedAsciiExt;
|
use std::ascii::OwnedAsciiExt;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
const DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
|
const DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
|
||||||
const DEFAULT_RESET_VALUE: &'static str = "Reset";
|
const DEFAULT_RESET_VALUE: &'static str = "Reset";
|
||||||
|
@ -68,16 +69,25 @@ pub struct HTMLInputElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[jstraceable]
|
#[jstraceable]
|
||||||
|
#[must_root]
|
||||||
struct InputActivationState {
|
struct InputActivationState {
|
||||||
indeterminate: bool,
|
indeterminate: bool,
|
||||||
checked: bool
|
checked: bool,
|
||||||
|
checked_radio: MutNullableJS<HTMLInputElement>,
|
||||||
|
// In case mutability changed
|
||||||
|
was_mutable: bool,
|
||||||
|
// In case the type changed
|
||||||
|
old_type: InputType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputActivationState {
|
impl InputActivationState {
|
||||||
fn new() -> InputActivationState {
|
fn new() -> InputActivationState {
|
||||||
InputActivationState {
|
InputActivationState {
|
||||||
indeterminate: false,
|
indeterminate: false,
|
||||||
checked: false
|
checked: false,
|
||||||
|
checked_radio: Default::default(),
|
||||||
|
was_mutable: false,
|
||||||
|
old_type: InputText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +290,6 @@ impl<'a> HTMLInputElementHelpers for JSRef<'a, HTMLInputElement> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_radio_group_name(self) -> Option<String> {
|
fn get_radio_group_name(self) -> Option<String> {
|
||||||
//TODO: determine form owner
|
//TODO: determine form owner
|
||||||
let elem: JSRef<Element> = ElementCast::from_ref(self);
|
let elem: JSRef<Element> = ElementCast::from_ref(self);
|
||||||
|
@ -550,45 +559,94 @@ impl<'a> Activatable for JSRef<'a, HTMLInputElement> {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/interaction.html#run-pre-click-activation-steps
|
// https://html.spec.whatwg.org/multipage/interaction.html#run-pre-click-activation-steps
|
||||||
fn pre_click_activation(&self) {
|
fn pre_click_activation(&self) {
|
||||||
match self.input_type.get() {
|
let mut cache = self.activation_state.borrow_mut();
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#submit-button-state-%28type=submit%29
|
let ty = self.input_type.get();
|
||||||
|
cache.old_type = ty;
|
||||||
|
if self.mutable() {
|
||||||
|
cache.was_mutable = true;
|
||||||
|
match ty {
|
||||||
|
// https://html.spec.whatwg.org/multipage/forms.html#submit-button-state-(type=submit):activation-behavior
|
||||||
// InputSubmit => (), // No behavior defined
|
// InputSubmit => (), // No behavior defined
|
||||||
InputCheckbox => {
|
InputCheckbox => {
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#checkbox-state-%28type=checkbox%29
|
// https://html.spec.whatwg.org/multipage/forms.html#checkbox-state-(type=checkbox):pre-click-activation-steps
|
||||||
if self.mutable() {
|
|
||||||
// cache current values of `checked` and `indeterminate`
|
// cache current values of `checked` and `indeterminate`
|
||||||
// we may need to restore them later
|
// we may need to restore them later
|
||||||
let mut cache = self.activation_state.borrow_mut();
|
|
||||||
cache.indeterminate = self.Indeterminate();
|
cache.indeterminate = self.Indeterminate();
|
||||||
cache.checked = self.Checked();
|
cache.checked = self.Checked();
|
||||||
self.SetIndeterminate(false);
|
self.SetIndeterminate(false);
|
||||||
self.SetChecked(!cache.checked);
|
self.SetChecked(!cache.checked);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
// https://html.spec.whatwg.org/multipage/forms.html#radio-button-state-(type=radio):pre-click-activation-steps
|
||||||
|
InputRadio => {
|
||||||
|
cache.checked_radio.assign(self.get_radio_group_all(self.get_radio_group_name().as_ref()
|
||||||
|
.map(|s| s.as_slice()))
|
||||||
|
.into_iter().find(|r| r.root().Checked()));
|
||||||
|
self.SetChecked(true);
|
||||||
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
cache.was_mutable = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/interaction.html#run-canceled-activation-steps
|
// https://html.spec.whatwg.org/multipage/interaction.html#run-canceled-activation-steps
|
||||||
fn canceled_activation(&self) {
|
fn canceled_activation(&self) {
|
||||||
match self.input_type.get() {
|
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#submit-button-state-%28type=submit%29
|
|
||||||
// InputSubmit => (), // No behavior defined
|
|
||||||
InputCheckbox => {
|
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#checkbox-state-%28type=checkbox%29
|
|
||||||
let cache = self.activation_state.borrow();
|
let cache = self.activation_state.borrow();
|
||||||
|
let ty = self.input_type.get();
|
||||||
|
if cache.old_type != ty {
|
||||||
|
// Type changed, abandon ship
|
||||||
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27414
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match ty {
|
||||||
|
// https://html.spec.whatwg.org/multipage/forms.html#submit-button-state-(type=submit):activation-behavior
|
||||||
|
// InputSubmit => (), // No behavior defined
|
||||||
|
// https://html.spec.whatwg.org/multipage/forms.html#checkbox-state-(type=checkbox):canceled-activation-steps
|
||||||
|
InputCheckbox => {
|
||||||
|
// We want to restore state only if the element had been changed in the first place
|
||||||
|
if cache.was_mutable {
|
||||||
self.SetIndeterminate(cache.indeterminate);
|
self.SetIndeterminate(cache.indeterminate);
|
||||||
self.SetChecked(cache.checked);
|
self.SetChecked(cache.checked);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
// https://html.spec.whatwg.org/multipage/forms.html#radio-button-state-(type=radio):canceled-activation-steps
|
||||||
|
InputRadio => {
|
||||||
|
// We want to restore state only if the element had been changed in the first place
|
||||||
|
if cache.was_mutable {
|
||||||
|
let old_checked: Option<Root<HTMLInputElement>> = cache.checked_radio.get().root();
|
||||||
|
let name = self.get_radio_group_name();
|
||||||
|
old_checked.map_or_else(|| self.SetChecked(false),
|
||||||
|
|o| {
|
||||||
|
// Avoiding iterating through the whole tree here, instead
|
||||||
|
// we can check if the conditions for radio group siblings apply
|
||||||
|
if name != None && // unless self no longer has a button group
|
||||||
|
name == o.get_radio_group_name() && // TODO should be compatibility caseless
|
||||||
|
self.form_owner() == o.form_owner() &&
|
||||||
|
// TODO Both a and b are in the same home subtree
|
||||||
|
o.input_type.get() == InputRadio {
|
||||||
|
o.SetChecked(true);
|
||||||
|
} else {
|
||||||
|
self.SetChecked(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/interaction.html#run-post-click-activation-steps
|
// https://html.spec.whatwg.org/multipage/interaction.html#run-post-click-activation-steps
|
||||||
fn activation_behavior(&self) {
|
fn activation_behavior(&self) {
|
||||||
match self.input_type.get() {
|
let ty = self.input_type.get();
|
||||||
|
if self.activation_state.borrow().old_type != ty {
|
||||||
|
// Type changed, abandon ship
|
||||||
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27414
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match ty {
|
||||||
InputSubmit => {
|
InputSubmit => {
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#submit-button-state-%28type=submit%29
|
// https://html.spec.whatwg.org/multipage/forms.html#submit-button-state-(type=submit):activation-behavior
|
||||||
// FIXME (Manishearth): support document owners (needs ability to get parent browsing context)
|
// FIXME (Manishearth): support document owners (needs ability to get parent browsing context)
|
||||||
if self.mutable() /* and document owner is fully active */ {
|
if self.mutable() /* and document owner is fully active */ {
|
||||||
self.form_owner().map(|o| {
|
self.form_owner().map(|o| {
|
||||||
|
@ -597,7 +655,8 @@ impl<'a> Activatable for JSRef<'a, HTMLInputElement> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
InputCheckbox => {
|
InputCheckbox => {
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#checkbox-state-%28type=checkbox%29
|
// https://html.spec.whatwg.org/multipage/forms.html#checkbox-state-(type=checkbox):activation-behavior
|
||||||
|
if self.mutable() {
|
||||||
let win = window_from_node(*self).root();
|
let win = window_from_node(*self).root();
|
||||||
let event = Event::new(&Window(*win),
|
let event = Event::new(&Window(*win),
|
||||||
"input".to_string(),
|
"input".to_string(),
|
||||||
|
@ -612,6 +671,26 @@ impl<'a> Activatable for JSRef<'a, HTMLInputElement> {
|
||||||
event.set_trusted(true);
|
event.set_trusted(true);
|
||||||
let target: JSRef<EventTarget> = EventTargetCast::from_ref(*self);
|
let target: JSRef<EventTarget> = EventTargetCast::from_ref(*self);
|
||||||
target.DispatchEvent(*event).ok();
|
target.DispatchEvent(*event).ok();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InputRadio => {
|
||||||
|
// https://html.spec.whatwg.org/multipage/forms.html#radio-button-state-(type=radio):activation-behavior
|
||||||
|
if self.mutable() {
|
||||||
|
let win = window_from_node(*self).root();
|
||||||
|
let event = Event::new(&Window(*win),
|
||||||
|
"input".to_string(),
|
||||||
|
Bubbles, NotCancelable).root();
|
||||||
|
event.set_trusted(true);
|
||||||
|
let target: JSRef<EventTarget> = EventTargetCast::from_ref(*self);
|
||||||
|
target.DispatchEvent(*event).ok();
|
||||||
|
|
||||||
|
let event = Event::new(&Window(*win),
|
||||||
|
"change".to_string(),
|
||||||
|
Bubbles, NotCancelable).root();
|
||||||
|
event.set_trusted(true);
|
||||||
|
let target: JSRef<EventTarget> = EventTargetCast::from_ref(*self);
|
||||||
|
target.DispatchEvent(*event).ok();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue