use crate::pages::router;
use reinhardt_pages::component::PageExt;
use reinhardt_pages::{Element, cleanup_reactive_nodes};
use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::*;
use web_sys::{Event, HtmlElement, window};
fn render_current_route(app_element: &web_sys::Element) -> Result<(), JsValue> {
cleanup_reactive_nodes();
let view = router::with_router(|r| r.render_current());
app_element.set_inner_html("");
let wrapper = Element::new(app_element.clone());
view.mount(&wrapper)
.map_err(|e| JsValue::from_str(&format!("Mount failed: {:?}", e)))
}
#[allow(clippy::main_recursion)]
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
let window = window().ok_or_else(|| JsValue::from_str("No window object"))?;
let document = window
.document()
.ok_or_else(|| JsValue::from_str("No document object"))?;
let app_element = document
.get_element_by_id("app")
.ok_or_else(|| JsValue::from_str("No #app element found"))?;
reinhardt_pages::reactive::runtime::set_scheduler(|task| {
wasm_bindgen_futures::spawn_local(async move { task() });
});
router::init_global_router();
render_current_route(&app_element)?;
let app_clone = app_element.clone();
let render_subscription = router::with_router(|r| {
r.on_navigate(move |_path, _params| {
if let Err(e) = render_current_route(&app_clone) {
web_sys::console::error_1(&format!("Re-mount failed: {:?}", e).into());
}
})
});
std::mem::forget(render_subscription);
let link_handler = Closure::wrap(Box::new(move |event: Event| {
if let Some(target) = event.target()
&& let Ok(element) = target.dyn_into::<HtmlElement>()
{
let mut current = Some(element);
while let Some(el) = current {
if el.tag_name().to_lowercase() == "a" {
if let Some(href) = el.get_attribute("href") {
if href.starts_with('/') {
event.prevent_default();
router::with_router(|r| {
let _ = r.push(&href);
});
return;
}
}
break;
}
current = el
.parent_element()
.and_then(|p| p.dyn_into::<HtmlElement>().ok());
}
}
}) as Box<dyn FnMut(_)>);
document.add_event_listener_with_callback("click", link_handler.as_ref().unchecked_ref())?;
link_handler.forget();
let popstate_handler = Closure::wrap(Box::new(move |_event: Event| {
router::with_router(|r| {
let current_path = web_sys::window()
.and_then(|w| {
let location = w.location();
let pathname = location.pathname().ok()?;
let search = location.search().ok().unwrap_or_default();
Some(format!("{}{}", pathname, search))
})
.unwrap_or_else(|| "/".to_string());
let _ = r.replace(¤t_path);
});
}) as Box<dyn FnMut(_)>);
window
.add_event_listener_with_callback("popstate", popstate_handler.as_ref().unchecked_ref())?;
popstate_handler.forget();
Ok(())
}