diff options
-rw-r--r-- | components/devtools/actors/inspector.rs | 17 | ||||
-rw-r--r-- | components/devtools/actors/inspector/node.rs | 22 | ||||
-rw-r--r-- | components/devtools/actors/inspector/walker.rs | 87 | ||||
-rw-r--r-- | components/script/devtools.rs | 5 | ||||
-rw-r--r-- | components/shared/devtools/lib.rs | 2 |
5 files changed, 121 insertions, 12 deletions
diff --git a/components/devtools/actors/inspector.rs b/components/devtools/actors/inspector.rs index 0e1ecd86177..db3cde89bec 100644 --- a/components/devtools/actors/inspector.rs +++ b/components/devtools/actors/inspector.rs @@ -86,14 +86,27 @@ impl Actor for InspectorActor { self.script_chan.send(GetRootNode(pipeline, tx)).unwrap(); let root_info = rx.recv().unwrap().ok_or(())?; - let root = root_info.encode(registry, false, self.script_chan.clone(), pipeline); + let name = self + .walker + .borrow() + .clone() + .unwrap_or_else(|| registry.new_name("walker")); + + let root = root_info.encode( + registry, + false, + self.script_chan.clone(), + pipeline, + name.clone(), + ); if self.walker.borrow().is_none() { let walker = WalkerActor { - name: registry.new_name("walker"), + name, script_chan: self.script_chan.clone(), pipeline, root_node: root.clone(), + mutations: RefCell::new(vec![]), }; let mut walker_name = self.walker.borrow_mut(); *walker_name = Some(walker.name()); diff --git a/components/devtools/actors/inspector/node.rs b/components/devtools/actors/inspector/node.rs index 041a7ee1618..845d394ffaa 100644 --- a/components/devtools/actors/inspector/node.rs +++ b/components/devtools/actors/inspector/node.rs @@ -16,6 +16,7 @@ use serde::Serialize; use serde_json::{self, Map, Value}; use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; +use crate::actors::inspector::walker::WalkerActor; use crate::protocol::JsonPacketStream; use crate::{EmptyReplyMsg, StreamId}; @@ -77,6 +78,7 @@ pub struct NodeActor { name: String, script_chan: IpcSender<DevtoolScriptControlMsg>, pipeline: PipelineId, + pub walker: String, } impl Actor for NodeActor { @@ -102,12 +104,16 @@ impl Actor for NodeActor { "modifyAttributes" => { let target = msg.get("to").ok_or(())?.as_str().ok_or(())?; let mods = msg.get("modifications").ok_or(())?.as_array().ok_or(())?; - let modifications = mods + let modifications: Vec<_> = mods .iter() .filter_map(|json_mod| { serde_json::from_str(&serde_json::to_string(json_mod).ok()?).ok() }) .collect(); + + let walker = registry.find::<WalkerActor>(&self.walker); + walker.new_mutations(stream, &self.name, &modifications); + self.script_chan .send(ModifyAttribute( self.pipeline, @@ -127,8 +133,13 @@ impl Actor for NodeActor { .send(GetDocumentElement(self.pipeline, tx)) .unwrap(); let doc_elem_info = rx.recv().map_err(|_| ())?.ok_or(())?; - let node = - doc_elem_info.encode(registry, true, self.script_chan.clone(), self.pipeline); + let node = doc_elem_info.encode( + registry, + true, + self.script_chan.clone(), + self.pipeline, + self.walker.clone(), + ); let msg = GetUniqueSelectorReply { from: self.name(), @@ -150,6 +161,7 @@ pub trait NodeInfoToProtocol { display: bool, script_chan: IpcSender<DevtoolScriptControlMsg>, pipeline: PipelineId, + walker: String, ) -> NodeActorMsg; } @@ -160,6 +172,7 @@ impl NodeInfoToProtocol for NodeInfo { display: bool, script_chan: IpcSender<DevtoolScriptControlMsg>, pipeline: PipelineId, + walker: String, ) -> NodeActorMsg { let actor = if !actors.script_actor_registered(self.unique_id.clone()) { let name = actors.new_name("node"); @@ -167,6 +180,7 @@ impl NodeInfoToProtocol for NodeInfo { name: name.clone(), script_chan: script_chan.clone(), pipeline, + walker: walker.clone(), }; actors.register_script_actor(self.unique_id, name.clone()); actors.register_later(Box::new(node_actor)); @@ -192,7 +206,7 @@ impl NodeInfoToProtocol for NodeInfo { let mut children = rx.recv().ok()??; let child = children.pop()?; - let msg = child.encode(actors, true, script_chan.clone(), pipeline); + let msg = child.encode(actors, true, script_chan.clone(), pipeline, walker); // If the node child is not a text node, do not represent it inline. if msg.node_type != TEXT_NODE { diff --git a/components/devtools/actors/inspector/walker.rs b/components/devtools/actors/inspector/walker.rs index 8588de77ace..8589fd1a494 100644 --- a/components/devtools/actors/inspector/walker.rs +++ b/components/devtools/actors/inspector/walker.rs @@ -4,11 +4,12 @@ //! The walker actor is responsible for traversing the DOM tree in various ways to create new nodes +use std::cell::RefCell; use std::net::TcpStream; use base::id::PipelineId; -use devtools_traits::DevtoolScriptControlMsg; use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement}; +use devtools_traits::{DevtoolScriptControlMsg, Modification}; use ipc_channel::ipc::{self, IpcSender}; use serde::Serialize; use serde_json::{self, Map, Value}; @@ -30,6 +31,7 @@ pub struct WalkerActor { pub script_chan: IpcSender<DevtoolScriptControlMsg>, pub pipeline: PipelineId, pub root_node: NodeActorMsg, + pub mutations: RefCell<Vec<(Modification, String)>>, } #[derive(Serialize)] @@ -70,11 +72,34 @@ struct WatchRootNodeReply { } #[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct MutationMsg { + attribute_name: String, + new_value: Option<String>, + target: String, + #[serde(rename = "type")] + type_: String, +} + +#[derive(Serialize)] +struct GetMutationsReply { + from: String, + mutations: Vec<MutationMsg>, +} + +#[derive(Serialize)] struct GetOffsetParentReply { from: String, node: Option<()>, } +#[derive(Serialize)] +struct NewMutationsReply { + from: String, + #[serde(rename = "type")] + type_: String, +} + impl Actor for WalkerActor { fn name(&self) -> String { self.name.clone() @@ -90,6 +115,8 @@ impl Actor for WalkerActor { /// /// - `getLayoutInspector`: Returns the Layout inspector actor, placeholder /// + /// - `getMutations`: Returns the list of attribute changes since it was last called + /// /// - `getOffsetParent`: Placeholder /// /// - `querySelector`: Recursively looks for the specified selector in the tree, reutrning the @@ -121,7 +148,13 @@ impl Actor for WalkerActor { nodes: children .into_iter() .map(|child| { - child.encode(registry, true, self.script_chan.clone(), self.pipeline) + child.encode( + registry, + true, + self.script_chan.clone(), + self.pipeline, + self.name(), + ) }) .collect(), from: self.name(), @@ -140,8 +173,13 @@ impl Actor for WalkerActor { .send(GetDocumentElement(self.pipeline, tx)) .map_err(|_| ())?; let doc_elem_info = rx.recv().map_err(|_| ())?.ok_or(())?; - let node = - doc_elem_info.encode(registry, true, self.script_chan.clone(), self.pipeline); + let node = doc_elem_info.encode( + registry, + true, + self.script_chan.clone(), + self.pipeline, + self.name(), + ); let msg = DocumentElementReply { from: self.name(), @@ -163,6 +201,24 @@ impl Actor for WalkerActor { let _ = stream.write_json_packet(&msg); ActorMessageStatus::Processed }, + "getMutations" => { + let msg = GetMutationsReply { + from: self.name(), + mutations: self + .mutations + .borrow_mut() + .drain(..) + .map(|(mutation, target)| MutationMsg { + attribute_name: mutation.attribute_name, + new_value: mutation.new_value, + target, + type_: "attributes".into(), + }) + .collect(), + }; + let _ = stream.write_json_packet(&msg); + ActorMessageStatus::Processed + }, "getOffsetParent" => { let msg = GetOffsetParentReply { from: self.name(), @@ -177,6 +233,7 @@ impl Actor for WalkerActor { let mut hierarchy = find_child( &self.script_chan, self.pipeline, + &self.name, registry, selector, node, @@ -211,11 +268,30 @@ impl Actor for WalkerActor { } } +impl WalkerActor { + pub(crate) fn new_mutations( + &self, + stream: &mut TcpStream, + target: &str, + modifications: &[Modification], + ) { + { + let mut mutations = self.mutations.borrow_mut(); + mutations.extend(modifications.iter().cloned().map(|m| (m, target.into()))); + } + let _ = stream.write_json_packet(&NewMutationsReply { + from: self.name(), + type_: "newMutations".into(), + }); + } +} + /// Recursively searches for a child with the specified selector /// If it is found, returns a list with the child and all of its ancestors. fn find_child( script_chan: &IpcSender<DevtoolScriptControlMsg>, pipeline: PipelineId, + name: &str, registry: &ActorRegistry, selector: &str, node: &str, @@ -232,7 +308,7 @@ fn find_child( let children = rx.recv().unwrap().ok_or(vec![])?; for child in children { - let msg = child.encode(registry, true, script_chan.clone(), pipeline); + let msg = child.encode(registry, true, script_chan.clone(), pipeline, name.into()); if msg.display_name == selector { hierarchy.push(msg); return Ok(hierarchy); @@ -245,6 +321,7 @@ fn find_child( match find_child( script_chan, pipeline, + name, registry, selector, &msg.actor, diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 14f792555a4..7b031da2886 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -235,6 +235,11 @@ pub fn handle_modify_attribute( node_id: String, modifications: Vec<Modification>, ) { + let Some(document) = documents.find_document(pipeline) else { + return warn!("document for pipeline id {} is not found", &pipeline); + }; + let _realm = enter_realm(document.window()); + let node = match find_node_by_unique_id(documents, pipeline, &node_id) { None => { return warn!( diff --git a/components/shared/devtools/lib.rs b/components/shared/devtools/lib.rs index 2455a324712..bf6ebed2466 100644 --- a/components/shared/devtools/lib.rs +++ b/components/shared/devtools/lib.rs @@ -222,7 +222,7 @@ pub enum DevtoolScriptControlMsg { Reload(PipelineId), } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Modification { pub attribute_name: String, |