jsdet_browser/
mutation.rs1use crate::dom::NodeId;
9
10#[derive(Debug, Clone)]
12pub struct MutationObserverRegistration {
13 pub target: NodeId,
15 pub options: MutationObserverOptions,
17 pub callback_id: u32,
19}
20
21#[derive(Debug, Clone, Default)]
23pub struct MutationObserverOptions {
24 pub child_list: bool,
25 pub attributes: bool,
26 pub character_data: bool,
27 pub subtree: bool,
28 pub attribute_old_value: bool,
29 pub character_data_old_value: bool,
30 pub attribute_filter: Vec<String>,
31}
32
33impl MutationObserverOptions {
34 pub fn from_json(json: &str) -> Self {
35 #[derive(serde::Deserialize, Default)]
36 struct Opts {
37 #[serde(default, alias = "childList")]
38 child_list: bool,
39 #[serde(default)]
40 attributes: bool,
41 #[serde(default, alias = "characterData")]
42 character_data: bool,
43 #[serde(default)]
44 subtree: bool,
45 #[serde(default, alias = "attributeOldValue")]
46 attribute_old_value: bool,
47 #[serde(default, alias = "characterDataOldValue")]
48 character_data_old_value: bool,
49 #[serde(default, alias = "attributeFilter")]
50 attribute_filter: Vec<String>,
51 }
52
53 let opts: Opts = serde_json::from_str(json).unwrap_or_default();
54 Self {
55 child_list: opts.child_list,
56 attributes: opts.attributes,
57 character_data: opts.character_data,
58 subtree: opts.subtree,
59 attribute_old_value: opts.attribute_old_value,
60 character_data_old_value: opts.character_data_old_value,
61 attribute_filter: opts.attribute_filter,
62 }
63 }
64}
65
66#[derive(Debug, Clone, serde::Serialize)]
68pub struct MutationRecord {
69 #[serde(rename = "type")]
70 pub mutation_type: String,
71 pub target: u32,
72 #[serde(skip_serializing_if = "Vec::is_empty")]
73 pub added_nodes: Vec<u32>,
74 #[serde(skip_serializing_if = "Vec::is_empty")]
75 pub removed_nodes: Vec<u32>,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub attribute_name: Option<String>,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub old_value: Option<String>,
80}
81
82#[derive(Debug, Default)]
84pub struct MutationObserverRegistry {
85 observers: Vec<MutationObserverRegistration>,
86 next_id: u32,
87 pending: Vec<(u32, Vec<MutationRecord>)>,
89}
90
91impl MutationObserverRegistry {
92 pub fn new() -> Self {
93 Self::default()
94 }
95
96 pub fn observe(&mut self, target: NodeId, options: MutationObserverOptions) -> u32 {
98 let id = self.next_id;
99 self.next_id += 1;
100 self.observers.push(MutationObserverRegistration {
101 target,
102 options,
103 callback_id: id,
104 });
105 id
106 }
107
108 pub fn disconnect(&mut self, callback_id: u32) {
110 self.observers.retain(|o| o.callback_id != callback_id);
111 }
112
113 pub fn notify_child_change(&mut self, target: NodeId, added: &[NodeId], removed: &[NodeId]) {
115 for observer in &self.observers {
116 if (observer.target == target || observer.options.subtree)
117 && observer.options.child_list
118 {
119 let record = MutationRecord {
120 mutation_type: "childList".into(),
121 target: target.0,
122 added_nodes: added.iter().map(|n| n.0).collect(),
123 removed_nodes: removed.iter().map(|n| n.0).collect(),
124 attribute_name: None,
125 old_value: None,
126 };
127 self.pending.push((observer.callback_id, vec![record]));
128 }
129 }
130 }
131
132 pub fn notify_attribute_change(
134 &mut self,
135 target: NodeId,
136 attribute_name: &str,
137 old_value: Option<&str>,
138 ) {
139 for observer in &self.observers {
140 if (observer.target == target || observer.options.subtree)
141 && observer.options.attributes
142 {
143 if !observer.options.attribute_filter.is_empty()
144 && !observer
145 .options
146 .attribute_filter
147 .iter()
148 .any(|f| f == attribute_name)
149 {
150 continue;
151 }
152 let record = MutationRecord {
153 mutation_type: "attributes".into(),
154 target: target.0,
155 added_nodes: Vec::new(),
156 removed_nodes: Vec::new(),
157 attribute_name: Some(attribute_name.to_string()),
158 old_value: if observer.options.attribute_old_value {
159 old_value.map(|s| s.to_string())
160 } else {
161 None
162 },
163 };
164 self.pending.push((observer.callback_id, vec![record]));
165 }
166 }
167 }
168
169 pub fn drain_pending(&mut self) -> Vec<(u32, String)> {
171 let pending = std::mem::take(&mut self.pending);
172 pending
173 .into_iter()
174 .map(|(id, records)| {
175 let json = serde_json::to_string(&records).unwrap_or_default();
176 (id, json)
177 })
178 .collect()
179 }
180}