use std::fmt;
use include_doc::function_body;
use wasm_bindgen::JsCast;
use crate::{
document::{Document, DocumentHead},
dom::Hydro,
node::element::{Const, GenericElement},
};
#[derive(Default)]
pub struct HydrationStats {
nodes_added: u64,
nodes_removed: u64,
empty_text_removed: u64,
attributes_set: u64,
attributes_removed: u64,
}
impl HydrationStats {
pub fn only_whitespace_diffs(&self) -> bool {
self.nodes_added == 0
&& self.nodes_removed == 0
&& self.attributes_set == 0
&& self.attributes_removed == 0
}
pub fn exact_match(&self) -> bool {
self.empty_text_removed == 0 && self.only_whitespace_diffs()
}
pub fn nodes_added(&self) -> u64 {
self.nodes_added
}
pub fn nodes_removed(&self) -> u64 {
self.nodes_removed
}
pub fn empty_text_removed(&self) -> u64 {
self.empty_text_removed
}
pub fn attributes_set(&self) -> u64 {
self.attributes_set
}
pub fn attributes_removed(&self) -> u64 {
self.attributes_removed
}
pub(super) fn node_added(&mut self, _elem: &web_sys::Node) {
self.nodes_added += 1;
}
pub(super) fn node_removed(&mut self, node: &web_sys::Node) {
match node
.dyn_ref::<web_sys::Text>()
.and_then(|t| t.text_content())
{
Some(text) if text.trim().is_empty() => self.empty_text_removed += 1,
_ => self.nodes_removed += 1,
}
}
pub(super) fn attribute_set(&mut self, _elem: &web_sys::Element, _name: &str, _value: &str) {
self.attributes_set += 1;
}
pub(super) fn attribute_removed(&mut self, _elem: &web_sys::Element, _name: &str) {
self.attributes_removed += 1;
}
}
impl fmt::Display for HydrationStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Hydration stats:")?;
writeln!(f, " nodes added = {}", self.nodes_added)?;
writeln!(f, " nodes removed = {}", self.nodes_removed)?;
writeln!(f, " empty text removed = {}", self.empty_text_removed)?;
writeln!(f, " attributes set = {}", self.attributes_set)?;
writeln!(f, " attributes removed = {}", self.attributes_removed)
}
}
#[doc = function_body!("tests/doc/hydration.rs", hydrate_example, [])]
pub async fn hydrate(id: &str, element: impl Into<GenericElement<Hydro, Const>>) -> HydrationStats {
Hydro::mount(id, element).await
}
#[doc = function_body!("tests/doc/hydration.rs", hydrate_in_head_example, [])]
pub async fn hydrate_in_head(id: &str, children: DocumentHead<Hydro>) -> HydrationStats {
Hydro::mount_in_head(id, children).await
}