devtools: Show attached event listeners in inspector tab (#42355)

This change makes the devtools inspector show any event listeners that
are attached to a node. The primary motivation is making the devtools
more useful for debugging real-world websites.

<img width="536" height="268" alt="image"
src="https://github.com/user-attachments/assets/5ba13e41-14b4-4202-b994-eadff5d1c6b5"
/>

You can also click on the event listener to show some more info, though
most of that (everything except the event type and the event phase) is
currently just placeholder text:

<img width="1360" height="456" alt="image"
src="https://github.com/user-attachments/assets/ec025847-43fc-489c-8b26-46afb6dada64"
/>


Testing: This change adds a new test

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
Simon Wülker
2026-02-11 14:31:25 +01:00
committed by GitHub
parent 2b6a260125
commit 929e275fcd
8 changed files with 158 additions and 3 deletions

View File

@@ -9,7 +9,7 @@ use base::generic_channel::GenericSender;
use base::id::PipelineId;
use devtools_traits::{
AttrModification, AutoMargins, ComputedNodeLayout, CssDatabaseProperty, EvaluateJSReply,
NodeInfo, NodeStyle, RuleModification, TimelineMarker, TimelineMarkerType,
EventListenerInfo, NodeInfo, NodeStyle, RuleModification, TimelineMarker, TimelineMarkerType,
};
use js::conversions::jsstr_to_string;
use js::jsval::UndefinedValue;
@@ -40,7 +40,7 @@ use crate::dom::document::AnimationFrameCallback;
use crate::dom::element::Element;
use crate::dom::globalscope::GlobalScope;
use crate::dom::node::{Node, NodeTraits, ShadowIncluding};
use crate::dom::types::HTMLElement;
use crate::dom::types::{EventTarget, HTMLElement};
use crate::realms::enter_realm;
use crate::script_runtime::{CanGc, IntroductionType};
@@ -97,6 +97,23 @@ pub(crate) fn handle_evaluate_js(
reply.send(result).unwrap();
}
pub(crate) fn handle_get_event_listener_info(
documents: &DocumentCollection,
pipeline: PipelineId,
node_id: &str,
reply: GenericSender<Vec<EventListenerInfo>>,
) {
let Some(node) = find_node_by_unique_id(documents, pipeline, node_id) else {
reply.send(vec![]).unwrap();
return;
};
let event_listeners = node
.upcast::<EventTarget>()
.summarize_event_listeners_for_devtools();
reply.send(event_listeners).unwrap();
}
pub(crate) fn handle_get_root_node(
documents: &DocumentCollection,
pipeline: PipelineId,