aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/script/dom/activation.rs9
-rw-r--r--components/script/dom/event.rs4
-rw-r--r--components/script/dom/htmlformelement.rs2
-rw-r--r--components/script/dom/htmlinputelement.rs127
4 files changed, 104 insertions, 38 deletions
diff --git a/components/script/dom/activation.rs b/components/script/dom/activation.rs
index 25f67397cc9..5d9a63f45ef 100644
--- a/components/script/dom/activation.rs
+++ b/components/script/dom/activation.rs
@@ -16,12 +16,17 @@ pub(crate) trait Activatable {
fn is_instance_activatable(&self) -> bool;
// https://dom.spec.whatwg.org/#eventtarget-legacy-pre-activation-behavior
- fn legacy_pre_activation_behavior(&self) -> Option<InputActivationState> {
+ fn legacy_pre_activation_behavior(&self, _can_gc: CanGc) -> Option<InputActivationState> {
None
}
// https://dom.spec.whatwg.org/#eventtarget-legacy-canceled-activation-behavior
- fn legacy_canceled_activation_behavior(&self, _state_before: Option<InputActivationState>) {}
+ fn legacy_canceled_activation_behavior(
+ &self,
+ _state_before: Option<InputActivationState>,
+ _can_gc: CanGc,
+ ) {
+ }
// https://dom.spec.whatwg.org/#eventtarget-activation-behavior
// event and target are used only by HTMLAnchorElement, in the case
diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs
index 0ced6c40b16..e199e12f655 100644
--- a/components/script/dom/event.rs
+++ b/components/script/dom/event.rs
@@ -507,7 +507,7 @@ impl Event {
// corresponding pre-activation behavior.
pre_activation_result = activation_target
.as_maybe_activatable()
- .and_then(|activatable| activatable.legacy_pre_activation_behavior());
+ .and_then(|activatable| activatable.legacy_pre_activation_behavior(can_gc));
}
let timeline_window = DomRoot::downcast::<Window>(target.global())
@@ -623,7 +623,7 @@ impl Event {
// Step 11.2 Otherwise, if activationTarget has legacy-canceled-activation behavior, then run
// activationTarget’s legacy-canceled-activation behavior.
else {
- activatable.legacy_canceled_activation_behavior(pre_activation_result);
+ activatable.legacy_canceled_activation_behavior(pre_activation_result, can_gc);
}
}
}
diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs
index 260c6cfb620..69290f89b0a 100644
--- a/components/script/dom/htmlformelement.rs
+++ b/components/script/dom/htmlformelement.rs
@@ -1276,7 +1276,7 @@ impl HTMLFormElement {
NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLInputElement,
)) => {
- child.downcast::<HTMLInputElement>().unwrap().reset();
+ child.downcast::<HTMLInputElement>().unwrap().reset(can_gc);
},
NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLSelectElement,
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs
index 85ebac012bb..9da0bd4e6c3 100644
--- a/components/script/dom/htmlinputelement.rs
+++ b/components/script/dom/htmlinputelement.rs
@@ -815,7 +815,16 @@ impl HTMLInputElement {
}
let mut is_required = self.Required();
let mut is_checked = self.Checked();
- for other in radio_group_iter(self, self.radio_group_name().as_ref()) {
+ let root = self
+ .upcast::<Node>()
+ .GetRootNode(&GetRootNodeOptions::empty());
+ let form = self.form_owner();
+ for other in radio_group_iter(
+ self,
+ self.radio_group_name().as_ref(),
+ form.as_deref(),
+ &root,
+ ) {
is_required = is_required || other.Required();
is_checked = is_checked || other.Checked();
}
@@ -1339,8 +1348,7 @@ impl HTMLInputElementMethods<crate::DomTypeHolder> for HTMLInputElement {
},
}
- self.validity_state()
- .perform_validation_and_update(ValidationFlags::all(), can_gc);
+ update_related_validity_states(self, can_gc);
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
Ok(())
}
@@ -1684,26 +1692,49 @@ impl HTMLInputElementMethods<crate::DomTypeHolder> for HTMLInputElement {
fn radio_group_iter<'a>(
elem: &'a HTMLInputElement,
group: Option<&'a Atom>,
+ form: Option<&'a HTMLFormElement>,
+ root: &'a Node,
) -> impl Iterator<Item = DomRoot<HTMLInputElement>> + 'a {
- let owner = elem.form_owner();
- let root = elem
- .upcast::<Node>()
- .GetRootNode(&GetRootNodeOptions::empty());
-
- // If group is None, in_same_group always fails, but we need to always return elem.
root.traverse_preorder(ShadowIncluding::No)
.filter_map(DomRoot::downcast::<HTMLInputElement>)
- .filter(move |r| &**r == elem || in_same_group(r, owner.as_deref(), group, None))
+ .filter(move |r| &**r == elem || in_same_group(r, form, group, None))
}
fn broadcast_radio_checked(broadcaster: &HTMLInputElement, group: Option<&Atom>) {
- for r in radio_group_iter(broadcaster, group) {
+ let root = broadcaster
+ .upcast::<Node>()
+ .GetRootNode(&GetRootNodeOptions::empty());
+ let form = broadcaster.form_owner();
+ for r in radio_group_iter(broadcaster, group, form.as_deref(), &root) {
if broadcaster != &*r && r.Checked() {
r.SetChecked(false);
}
}
}
+fn perform_radio_group_validation(elem: &HTMLInputElement, group: Option<&Atom>, can_gc: CanGc) {
+ let root = elem
+ .upcast::<Node>()
+ .GetRootNode(&GetRootNodeOptions::empty());
+ let form = elem.form_owner();
+ for r in radio_group_iter(elem, group, form.as_deref(), &root) {
+ r.validity_state()
+ .perform_validation_and_update(ValidationFlags::all(), can_gc);
+ }
+}
+
+fn update_related_validity_states(elem: &HTMLInputElement, can_gc: CanGc) {
+ match elem.input_type() {
+ InputType::Radio => {
+ perform_radio_group_validation(elem, elem.radio_group_name().as_ref(), can_gc)
+ },
+ _ => {
+ elem.validity_state()
+ .perform_validation_and_update(ValidationFlags::all(), can_gc);
+ },
+ }
+}
+
// https://html.spec.whatwg.org/multipage/#radio-button-group
fn in_same_group(
other: &HTMLInputElement,
@@ -1868,11 +1899,12 @@ impl HTMLInputElement {
}
// https://html.spec.whatwg.org/multipage/#the-input-element:concept-form-reset-control
- pub(crate) fn reset(&self) {
+ pub(crate) fn reset(&self, can_gc: CanGc) {
match self.input_type() {
InputType::Radio | InputType::Checkbox => {
self.update_checked_state(self.DefaultChecked(), false);
self.checked_changed.set(false);
+ update_related_validity_states(self, can_gc);
},
InputType::Image => (),
_ => (),
@@ -2520,8 +2552,7 @@ impl VirtualMethods for HTMLInputElement {
_ => {},
}
- self.validity_state()
- .perform_validation_and_update(ValidationFlags::all(), can_gc);
+ update_related_validity_states(self, can_gc);
}
fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
@@ -2549,13 +2580,12 @@ impl VirtualMethods for HTMLInputElement {
self.upcast::<Element>()
.check_ancestors_disabled_state_for_form_control();
- for r in radio_group_iter(self, self.radio_group_name().as_ref()) {
- r.validity_state()
- .perform_validation_and_update(ValidationFlags::all(), can_gc);
- }
+ update_related_validity_states(self, can_gc);
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
+ let form_owner = self.form_owner();
+
self.super_type().unwrap().unbind_from_tree(context, can_gc);
let node = self.upcast::<Node>();
@@ -2569,6 +2599,19 @@ impl VirtualMethods for HTMLInputElement {
el.check_disabled_attribute();
}
+ if self.input_type() == InputType::Radio {
+ let root = context.parent.GetRootNode(&GetRootNodeOptions::empty());
+ for r in radio_group_iter(
+ self,
+ self.radio_group_name().as_ref(),
+ form_owner.as_deref(),
+ &root,
+ ) {
+ r.validity_state()
+ .perform_validation_and_update(ValidationFlags::all(), can_gc);
+ }
+ }
+
self.validity_state()
.perform_validation_and_update(ValidationFlags::all(), can_gc);
}
@@ -2680,8 +2723,7 @@ impl VirtualMethods for HTMLInputElement {
}
}
- self.validity_state()
- .perform_validation_and_update(ValidationFlags::all(), can_gc);
+ update_related_validity_states(self, can_gc);
}
// https://html.spec.whatwg.org/multipage/#the-input-element%3Aconcept-node-clone-ext
@@ -2703,8 +2745,7 @@ impl VirtualMethods for HTMLInputElement {
elem.textinput
.borrow_mut()
.set_content(self.textinput.borrow().get_content());
- elem.validity_state()
- .perform_validation_and_update(ValidationFlags::all(), can_gc);
+ update_related_validity_states(self, can_gc);
}
}
@@ -2819,40 +2860,58 @@ impl Activatable for HTMLInputElement {
}
// https://dom.spec.whatwg.org/#eventtarget-legacy-pre-activation-behavior
- fn legacy_pre_activation_behavior(&self) -> Option<InputActivationState> {
+ fn legacy_pre_activation_behavior(&self, can_gc: CanGc) -> Option<InputActivationState> {
let ty = self.input_type();
- match ty {
+ let activation_state = match ty {
InputType::Checkbox => {
let was_checked = self.Checked();
let was_indeterminate = self.Indeterminate();
self.SetIndeterminate(false);
self.SetChecked(!was_checked);
- return Some(InputActivationState {
+ Some(InputActivationState {
checked: was_checked,
indeterminate: was_indeterminate,
checked_radio: None,
old_type: InputType::Checkbox,
- });
+ })
},
InputType::Radio => {
- let checked_member =
- radio_group_iter(self, self.radio_group_name().as_ref()).find(|r| r.Checked());
+ let root = self
+ .upcast::<Node>()
+ .GetRootNode(&GetRootNodeOptions::empty());
+ let form_owner = self.form_owner();
+ let checked_member = radio_group_iter(
+ self,
+ self.radio_group_name().as_ref(),
+ form_owner.as_deref(),
+ &root,
+ )
+ .find(|r| r.Checked());
let was_checked = self.Checked();
self.SetChecked(true);
- return Some(InputActivationState {
+ Some(InputActivationState {
checked: was_checked,
indeterminate: false,
checked_radio: checked_member.as_deref().map(DomRoot::from_ref),
old_type: InputType::Radio,
- });
+ })
},
- _ => (),
+ _ => None,
+ };
+
+ if activation_state.is_some() {
+ update_related_validity_states(self, can_gc);
}
- None
+
+ activation_state
}
// https://dom.spec.whatwg.org/#eventtarget-legacy-canceled-activation-behavior
- fn legacy_canceled_activation_behavior(&self, cache: Option<InputActivationState>) {
+ fn legacy_canceled_activation_behavior(
+ &self,
+ cache: Option<InputActivationState>,
+ can_gc: CanGc,
+ ) {
// Step 1
let ty = self.input_type();
let cache = match cache {
@@ -2899,6 +2958,8 @@ impl Activatable for HTMLInputElement {
},
_ => (),
}
+
+ update_related_validity_states(self, can_gc);
}
/// <https://html.spec.whatwg.org/multipage/#input-activation-behavior>