1use super::*;
4
5pub(crate) fn make_io_entry(it: &mut Interp, target: Value) -> Value {
15 let rect = dom_get_bounding_client_rect(it, target.clone(), &[]).unwrap_or(Value::Undefined);
16 let entry = Obj::plain();
17 {
18 let mut b = entry.borrow_mut();
19 b.props.insert("isIntersecting".into(), Value::Bool(true));
20 b.props
21 .insert("intersectionRatio".into(), Value::Number(1.0));
22 b.props.insert("boundingClientRect".into(), rect.clone());
23 b.props.insert("intersectionRect".into(), rect);
24 b.props.insert("rootBounds".into(), Value::Null);
25 b.props.insert("time".into(), Value::Number(next_perf_timestamp()));
26 b.props.insert("target".into(), target);
27 }
28 Value::Object(entry)
29}
30
31pub(crate) fn io_observe(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
32 let cb = if let Value::Object(o) = &this {
34 o.borrow().props.get("_cb").cloned()
35 } else {
36 None
37 };
38 if let Some(cb) = cb {
39 let target = arg(a, 0);
40 let entries = Value::Object(Obj::array(alloc::vec![make_io_entry(it, target)]));
41 it.call_listener(
42 &cb,
43 Value::Undefined,
44 &[entries, Value::Undefined],
45 "IntersectionObserver callback",
46 );
47 }
48 Ok(Value::Undefined)
49}
50
51pub(crate) fn io_unobserve(_it: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
52 Ok(Value::Undefined)
53}
54pub(crate) fn io_disconnect(_it: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
55 Ok(Value::Undefined)
56}
57
58pub(crate) fn io_take_records(_it: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
59 Ok(Value::Object(Obj::array(alloc::vec![])))
60}
61
62pub(crate) fn intersection_observer_ctor(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
72 let cb = arg(a, 0);
73 let options = arg(a, 1);
74 let root = obj_prop(&options, "root").unwrap_or(Value::Null);
75 let root_margin = obj_prop(&options, "rootMargin")
76 .map(|v| v.to_js_string())
77 .unwrap_or_else(|| String::from("0px 0px 0px 0px"));
78 let threshold_val = obj_prop(&options, "threshold");
79 let thresholds = match threshold_val {
80 Some(v) => {
81 let items = this_items(&v);
82 if items.is_empty() && !matches!(v, Value::Object(_)) {
83 alloc::vec![v.to_number()]
84 } else {
85 items.iter().map(|x| x.to_number()).collect()
86 }
87 }
88 None => alloc::vec![0.0],
89 };
90 let obs = Obj::plain();
91 {
92 let mut b = obs.borrow_mut();
93 b.props.insert("_cb".into(), cb);
94 b.props.insert("root".into(), root);
95 b.props.insert("rootMargin".into(), Value::str(root_margin));
96 b.props.insert(
97 "thresholds".into(),
98 Value::Object(Obj::array(thresholds.into_iter().map(Value::Number).collect())),
99 );
100 b.props.insert("observe".into(), nv("observe", io_observe));
101 b.props
102 .insert("unobserve".into(), nv("unobserve", io_unobserve));
103 b.props
104 .insert("disconnect".into(), nv("disconnect", io_disconnect));
105 b.props
106 .insert("takeRecords".into(), nv("takeRecords", io_take_records));
107 }
108 Ok(Value::Object(obs))
109}
110
111pub fn make_resolved_promise(val: Value) -> ObjRef {
113 use super::super::value::PromiseState;
114 let state = alloc::rc::Rc::new(core::cell::RefCell::new(PromiseState::pending()));
115 state.borrow_mut().status = super::super::value::PromiseStatus::Fulfilled;
116 state.borrow_mut().value = val;
117 let obj = Obj::plain();
118 obj.borrow_mut().kind = super::super::value::ObjKind::PromiseObj(state.clone());
119 let mut b = obj.borrow_mut();
121 b.props.insert("then".into(), nv("then", dom_noop));
122 b.props.insert("catch".into(), nv("catch", dom_noop));
123 b.props.insert("finally".into(), nv("finally", dom_noop));
124 drop(b);
125 obj
126}
127
128pub fn fire_intersection_observers(_it: &mut Interp) {
130 }
133
134pub fn flush_mutation_observers(it: &mut Interp) {
137 let all_recs = drain_mut_records(it);
139 if all_recs.is_empty() {
140 return;
141 }
142 use alloc::collections::BTreeMap;
144 let mut groups: BTreeMap<u32, (Value, alloc::vec::Vec<super::super::dom_bridge::MutRec>)> =
145 BTreeMap::new();
146 {
147 let dom = it.dom.borrow();
148 for (id, rec) in all_recs {
149 let cb = dom
150 .mut_observers
151 .iter()
152 .find(|o| o.id == id)
153 .map(|o| o.callback.clone())
154 .unwrap_or(Value::Undefined);
155 groups.entry(id).or_insert((cb, alloc::vec![])).1.push(rec);
156 }
157 }
158 for (_id, (cb, recs)) in groups {
159 if !matches!(cb, Value::Object(_)) {
160 continue;
161 }
162 let js_recs: alloc::vec::Vec<Value> =
163 recs.iter().map(|r| make_mut_record(it, r)).collect();
164 let arr = Value::Object(Obj::array(js_recs));
165 it.call_listener(&cb, Value::Undefined, &[arr], "MutationObserver callback");
166 }
167}
168
169pub(crate) fn ro_observe(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
171 let cb = if let Value::Object(o) = &this {
172 o.borrow().props.get("_cb").cloned()
173 } else {
174 None
175 };
176 if let Some(cb) = cb {
177 let target = arg(a, 0);
178 let (_, _, w, h) = this_dom_idx(&target)
186 .and_then(|idx| it.dom.borrow().get_rect(idx))
187 .unwrap_or((0, 0, 0, 0));
188 let (w, h) = (w as f64, h as f64);
189 let entry = Obj::plain();
190 {
191 let mut b = entry.borrow_mut();
192 b.props.insert("target".into(), target);
193 let cr = Obj::plain();
194 {
195 let mut c = cr.borrow_mut();
196 c.props.insert("width".into(), Value::Number(w));
197 c.props.insert("height".into(), Value::Number(h));
198 c.props.insert("x".into(), Value::Number(0.0));
199 c.props.insert("y".into(), Value::Number(0.0));
200 }
201 b.props.insert("contentRect".into(), Value::Object(cr));
202 let make_size = || {
203 let s = Obj::plain();
204 s.borrow_mut().props.insert("inlineSize".into(), Value::Number(w));
205 s.borrow_mut().props.insert("blockSize".into(), Value::Number(h));
206 Value::Object(s)
207 };
208 b.props
209 .insert("borderBoxSize".into(), Value::Object(Obj::array(alloc::vec![make_size()])));
210 b.props
211 .insert("contentBoxSize".into(), Value::Object(Obj::array(alloc::vec![make_size()])));
212 b.props.insert(
217 "devicePixelContentBoxSize".into(),
218 Value::Object(Obj::array(alloc::vec![make_size()])),
219 );
220 }
221 let entries = Value::Object(Obj::array(alloc::vec![Value::Object(entry)]));
222 it.call_listener(&cb, Value::Undefined, &[entries], "ResizeObserver callback");
223 }
224 Ok(Value::Undefined)
225}
226pub(crate) fn ro_unobserve(_: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
227 Ok(Value::Undefined)
228}
229pub(crate) fn ro_disconnect(_: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
230 Ok(Value::Undefined)
231}
232
233pub(crate) fn resize_observer_ctor(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
234 let cb = arg(a, 0);
235 let obs = Obj::plain();
236 {
237 let mut b = obs.borrow_mut();
238 b.props.insert("_cb".into(), cb);
239 b.props.insert("observe".into(), nv("observe", ro_observe));
240 b.props
241 .insert("unobserve".into(), nv("unobserve", ro_unobserve));
242 b.props
243 .insert("disconnect".into(), nv("disconnect", ro_disconnect));
244 }
245 Ok(Value::Object(obs))
246}
247
248pub(crate) fn mo_observe(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
250 let Value::Object(self_obj) = &this else { return Ok(Value::Undefined) };
251 let obs_id = match self_obj.borrow().props.get("_id") {
252 Some(Value::Number(n)) => *n as u32,
253 _ => return Ok(Value::Undefined),
254 };
255 let callback = self_obj.borrow().props.get("_cb").cloned().unwrap_or(Value::Undefined);
256 let target_idx = match arg(a, 0) {
257 Value::Object(o) => match o.borrow().kind {
258 super::super::value::ObjKind::DomElement(i) => i,
259 _ => return Ok(Value::Undefined),
260 },
261 _ => return Ok(Value::Undefined),
262 };
263 let opts = arg(a, 1);
264 let child_list = obj_prop(&opts, "childList")
265 .map(|v| v.truthy())
266 .unwrap_or(false);
267 let attributes_specified = obj_prop(&opts, "attributes");
268 let mut attributes = attributes_specified.as_ref().map(|v| v.truthy()).unwrap_or(false);
269 let subtree = obj_prop(&opts, "subtree")
270 .map(|v| v.truthy())
271 .unwrap_or(false);
272 let attribute_old_value = obj_prop(&opts, "attributeOldValue")
273 .map(|v| v.truthy())
274 .unwrap_or(false);
275 let attribute_filter = match obj_prop(&opts, "attributeFilter") {
276 Some(v @ Value::Object(_)) => Some(
277 generic_array_items(it, &v)
278 .iter()
279 .map(|item| item.to_js_string())
280 .collect::<Vec<String>>(),
281 ),
282 _ => None,
283 };
284 let character_data_specified = obj_prop(&opts, "characterData");
289 let mut character_data = character_data_specified.as_ref().map(|v| v.truthy()).unwrap_or(false);
290 let character_data_old_value = obj_prop(&opts, "characterDataOldValue")
291 .map(|v| v.truthy())
292 .unwrap_or(false);
293 if attributes_specified.is_none() && (attribute_old_value || attribute_filter.is_some()) {
301 attributes = true;
302 }
303 if character_data_specified.is_none() && character_data_old_value {
304 character_data = true;
305 }
306 use super::super::dom_bridge::MutObsReg;
307 let mut dom = it.dom.borrow_mut();
308 dom.mut_observers.retain(|o| o.id != obs_id);
310 dom.mut_observers.push(MutObsReg {
311 id: obs_id,
312 target_idx,
313 child_list,
314 attributes,
315 subtree,
316 callback,
317 attribute_old_value,
318 attribute_filter,
319 character_data,
320 character_data_old_value,
321 });
322 Ok(Value::Undefined)
323}
324
325pub(crate) fn mo_disconnect(it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
326 let Value::Object(self_obj) = &this else { return Ok(Value::Undefined) };
327 let obs_id = match self_obj.borrow().props.get("_id") {
328 Some(Value::Number(n)) => *n as u32,
329 _ => return Ok(Value::Undefined),
330 };
331 it.dom.borrow_mut().mut_observers.retain(|o| o.id != obs_id);
332 it.dom.borrow_mut().mut_records.retain(|(id, _)| *id != obs_id);
333 Ok(Value::Undefined)
334}
335
336pub(crate) fn mo_take_records(it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
337 let Value::Object(self_obj) = &this else {
338 return Ok(Value::Object(Obj::array(alloc::vec![])));
339 };
340 let obs_id = match self_obj.borrow().props.get("_id") {
341 Some(Value::Number(n)) => *n as u32,
342 _ => return Ok(Value::Object(Obj::array(alloc::vec![]))),
343 };
344 let records = build_mut_records_for(it, obs_id);
345 Ok(Value::Object(Obj::array(records)))
346}
347
348pub(crate) fn build_mut_records_for(it: &mut Interp, obs_id: u32) -> alloc::vec::Vec<Value> {
349 let mut matched = alloc::vec![];
350 let mut rest = alloc::vec![];
351 for (id, r) in core::mem::take(&mut it.dom.borrow_mut().mut_records) {
352 if id == obs_id { matched.push(r); } else { rest.push((id, r)); }
353 }
354 it.dom.borrow_mut().mut_records = rest;
355 matched.iter().map(|r| make_mut_record(it, r)).collect()
356}
357
358pub(crate) fn drain_mut_records(it: &mut Interp) -> alloc::vec::Vec<(u32, super::super::dom_bridge::MutRec)> {
359 core::mem::take(&mut it.dom.borrow_mut().mut_records)
360}
361
362pub(crate) fn make_mut_record(it: &mut Interp, r: &super::super::dom_bridge::MutRec) -> Value {
363 let rec = Obj::plain();
364 {
365 let mut b = rec.borrow_mut();
366 b.props.insert("type".into(), Value::str(r.type_));
367 let target = Value::Object(Obj::dom(r.target_idx));
368 b.props.insert("target".into(), target);
369 let added: alloc::vec::Vec<Value> = r.added.iter().map(|&i| Value::Object(Obj::dom(i))).collect();
370 b.props.insert("addedNodes".into(), Value::Object(Obj::array(added)));
371 let removed: alloc::vec::Vec<Value> = r.removed.iter().map(|&i| Value::Object(Obj::dom(i))).collect();
372 b.props.insert("removedNodes".into(), Value::Object(Obj::array(removed)));
373 b.props.insert(
374 "attributeName".into(),
375 r.attribute_name
376 .as_deref()
377 .map(Value::str)
378 .unwrap_or(Value::Null),
379 );
380 b.props.insert(
381 "oldValue".into(),
382 r.old_value.as_deref().map(Value::str).unwrap_or(Value::Null),
383 );
384 }
385 let _ = it;
386 Value::Object(rec)
387}
388
389pub(crate) fn mutation_observer_ctor(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
390 let cb = arg(a, 0);
391 let obs_id = {
392 let mut dom = it.dom.borrow_mut();
393 let id = dom.next_mut_obs_id;
394 dom.next_mut_obs_id += 1;
395 id
396 };
397 let obs = Obj::plain();
398 {
399 let mut b = obs.borrow_mut();
400 b.props.insert("_cb".into(), cb);
401 b.props.insert("_id".into(), Value::Number(obs_id as f64));
402 b.props.insert("observe".into(), nv("observe", mo_observe));
403 b.props.insert("disconnect".into(), nv("disconnect", mo_disconnect));
404 b.props.insert("takeRecords".into(), nv("takeRecords", mo_take_records));
405 }
406 Ok(Value::Object(obs))
407}
408