script: Make EventTarget::fire return bool according to spec (#39308)

This is a continuation of #38566, newly discovered when fixing
https://github.com/servo/servo/issues/38616#issuecomment-3261561671.

We add more documentation and return `bool` for the function family of
[event firing](https://dom.spec.whatwg.org/#concept-event-fire).

Testing: No behaviour change.

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
Euclid Ye 2025-09-15 16:07:08 +08:00 committed by GitHub
parent 059a2fd86d
commit 8f4ced66d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 20 deletions

View file

@ -885,7 +885,7 @@ impl EventTarget {
} }
// https://dom.spec.whatwg.org/#concept-event-fire // https://dom.spec.whatwg.org/#concept-event-fire
pub(crate) fn fire_event(&self, name: Atom, can_gc: CanGc) -> DomRoot<Event> { pub(crate) fn fire_event(&self, name: Atom, can_gc: CanGc) -> bool {
self.fire_event_with_params( self.fire_event_with_params(
name, name,
EventBubbles::DoesNotBubble, EventBubbles::DoesNotBubble,
@ -896,7 +896,7 @@ impl EventTarget {
} }
// https://dom.spec.whatwg.org/#concept-event-fire // https://dom.spec.whatwg.org/#concept-event-fire
pub(crate) fn fire_bubbling_event(&self, name: Atom, can_gc: CanGc) -> DomRoot<Event> { pub(crate) fn fire_bubbling_event(&self, name: Atom, can_gc: CanGc) -> bool {
self.fire_event_with_params( self.fire_event_with_params(
name, name,
EventBubbles::Bubbles, EventBubbles::Bubbles,
@ -907,7 +907,7 @@ impl EventTarget {
} }
// https://dom.spec.whatwg.org/#concept-event-fire // https://dom.spec.whatwg.org/#concept-event-fire
pub(crate) fn fire_cancelable_event(&self, name: Atom, can_gc: CanGc) -> DomRoot<Event> { pub(crate) fn fire_cancelable_event(&self, name: Atom, can_gc: CanGc) -> bool {
self.fire_event_with_params( self.fire_event_with_params(
name, name,
EventBubbles::DoesNotBubble, EventBubbles::DoesNotBubble,
@ -918,11 +918,7 @@ impl EventTarget {
} }
// https://dom.spec.whatwg.org/#concept-event-fire // https://dom.spec.whatwg.org/#concept-event-fire
pub(crate) fn fire_bubbling_cancelable_event( pub(crate) fn fire_bubbling_cancelable_event(&self, name: Atom, can_gc: CanGc) -> bool {
&self,
name: Atom,
can_gc: CanGc,
) -> DomRoot<Event> {
self.fire_event_with_params( self.fire_event_with_params(
name, name,
EventBubbles::Bubbles, EventBubbles::Bubbles,
@ -940,11 +936,10 @@ impl EventTarget {
cancelable: EventCancelable, cancelable: EventCancelable,
composed: EventComposed, composed: EventComposed,
can_gc: CanGc, can_gc: CanGc,
) -> DomRoot<Event> { ) -> bool {
let event = Event::new(&self.global(), name, bubbles, cancelable, can_gc); let event = Event::new(&self.global(), name, bubbles, cancelable, can_gc);
event.set_composed(composed.into()); event.set_composed(composed.into());
event.fire(self, can_gc); event.fire(self, can_gc)
event
} }
/// <https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener> /// <https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener>

View file

@ -1148,7 +1148,7 @@ impl HTMLFormElement {
} }
}) })
.collect::<Vec<DomRoot<Element>>>(); .collect::<Vec<DomRoot<Element>>>();
// Step 4 // Step 4: If invalid controls is empty, then return a positive result.
if invalid_controls.is_empty() { if invalid_controls.is_empty() {
return Ok(()); return Ok(());
} }
@ -1156,10 +1156,13 @@ impl HTMLFormElement {
let unhandled_invalid_controls = invalid_controls let unhandled_invalid_controls = invalid_controls
.into_iter() .into_iter()
.filter_map(|field| { .filter_map(|field| {
let event = field // Step 6.1: Let notCanceled be the result of firing an event named invalid at
// field, with the cancelable attribute initialized to true.
let not_canceled = field
.upcast::<EventTarget>() .upcast::<EventTarget>()
.fire_cancelable_event(atom!("invalid"), can_gc); .fire_cancelable_event(atom!("invalid"), can_gc);
if !event.DefaultPrevented() { // Step 6.2: If notCanceled is true, then add field to unhandled invalid controls.
if not_canceled {
return Some(field); return Some(field);
} }
None None
@ -1302,6 +1305,7 @@ impl HTMLFormElement {
Some(form_data.datums()) Some(form_data.datums())
} }
/// <https://html.spec.whatwg.org/multipage/#dom-form-reset>
pub(crate) fn reset(&self, _reset_method_flag: ResetFrom, can_gc: CanGc) { pub(crate) fn reset(&self, _reset_method_flag: ResetFrom, can_gc: CanGc) {
// https://html.spec.whatwg.org/multipage/#locked-for-reset // https://html.spec.whatwg.org/multipage/#locked-for-reset
if self.marked_for_reset.get() { if self.marked_for_reset.get() {
@ -1310,10 +1314,13 @@ impl HTMLFormElement {
self.marked_for_reset.set(true); self.marked_for_reset.set(true);
} }
let event = self // https://html.spec.whatwg.org/multipage/#concept-form-reset
// Let reset be the result of firing an event named reset at form,
// with the bubbles and cancelable attributes initialized to true.
let reset = self
.upcast::<EventTarget>() .upcast::<EventTarget>()
.fire_bubbling_cancelable_event(atom!("reset"), can_gc); .fire_bubbling_cancelable_event(atom!("reset"), can_gc);
if event.DefaultPrevented() { if !reset {
return; return;
} }

View file

@ -1,7 +1,6 @@
/* This Source Code Form is subject to the terms of the Mozilla Public /* 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 * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods; use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions; use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::Castable;
@ -62,14 +61,15 @@ pub(crate) trait Validatable {
return true; return true;
} }
// Step 1.1. // Step 1.1: Let report be the result of firing an event named invalid at element,
let event = self // with the cancelable attribute initialized to true.
let report = self
.as_element() .as_element()
.upcast::<EventTarget>() .upcast::<EventTarget>()
.fire_cancelable_event(atom!("invalid"), can_gc); .fire_cancelable_event(atom!("invalid"), can_gc);
// Step 1.2. // Step 1.2.
if !event.DefaultPrevented() { if report {
let flags = self.validity_state().invalid_flags(); let flags = self.validity_state().invalid_flags();
println!( println!(
"Validation error: {}", "Validation error: {}",