browser_panic_hook/mode/
mod.rs1mod basic;
2mod custom_body;
3
4pub use basic::Basic;
5pub use custom_body::CustomBody;
6
7use crate::utils::{extract_message, Unescaped};
8use std::borrow::Cow;
9use std::ops::Deref;
10use std::panic::PanicInfo;
11use wasm_bindgen::{JsCast, JsValue};
12use web_sys::{Document, HtmlElement};
13
14pub trait PresentationMode {
15 fn present(&self, info: PanicDetails) -> Result<(), Cow<'static, str>>;
16}
17
18pub struct PanicDetails<'a>(pub &'a PanicInfo<'a>);
19
20impl<'a> PanicDetails<'a> {
21 pub fn message(&self) -> Unescaped {
22 extract_message(&self.0).into()
23 }
24
25 pub fn location(&self) -> Option<Unescaped> {
26 self.0.location().map(|l| Unescaped::from(l.to_string()))
27 }
28}
29
30impl<'a> Deref for PanicDetails<'a> {
31 type Target = PanicInfo<'a>;
32
33 fn deref(&self) -> &Self::Target {
34 &self.0
35 }
36}
37
38impl<'a> From<&'a PanicInfo<'a>> for PanicDetails<'a> {
39 fn from(info: &'a PanicInfo) -> Self {
40 Self(info)
41 }
42}
43
44fn build_body(
45 doc: &Document,
46 body_class: Option<&str>,
47 content: String,
48) -> Result<HtmlElement, JsValue> {
49 let body = doc.create_element("body")?;
50
51 let body: HtmlElement = body
52 .dyn_into()
53 .map_err(|_| JsValue::from_str("Unable to convert into HTML element"))?;
54
55 if let Some(class) = body_class {
56 body.set_class_name(class);
57 }
58
59 body.set_inner_html(&content);
60
61 Ok(body)
62}
63
64fn set_body(class: Option<&str>, content: String) -> Result<(), Cow<'static, str>> {
65 let doc = web_sys::window()
66 .and_then(|w| w.document())
67 .ok_or_else(|| "Unable to acquire document")?;
68
69 doc.set_body(Some(&build_body(&doc, class, content).map_err(
70 |err| match err.as_string() {
71 Some(err) => err,
72 None => format!("{err:?}"),
73 },
74 )?));
75
76 Ok(())
77}