mod classes;
mod component;
mod conversion;
mod listener;
pub use classes::*;
pub use component::*;
pub use conversion::*;
pub use listener::*;
use crate::virtual_dom::{VNode, VPortal};
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::JsValue;
use web_sys::{Element, Node};
pub type Html = VNode;
#[derive(Default, Clone)]
pub struct NodeRef(Rc<RefCell<NodeRefInner>>);
impl PartialEq for NodeRef {
fn eq(&self, other: &Self) -> bool {
self.0.as_ptr() == other.0.as_ptr() || Some(self) == other.0.borrow().link.as_ref()
}
}
impl std::fmt::Debug for NodeRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"NodeRef {{ references: {:?} }}",
self.get().map(|n| crate::utils::print_node(&n))
)
}
}
#[derive(PartialEq, Debug, Default, Clone)]
struct NodeRefInner {
node: Option<Node>,
link: Option<NodeRef>,
}
impl NodeRef {
pub fn get(&self) -> Option<Node> {
let inner = self.0.borrow();
inner.node.clone().or_else(|| inner.link.as_ref()?.get())
}
pub fn cast<INTO: AsRef<Node> + From<JsValue>>(&self) -> Option<INTO> {
let node = self.get();
node.map(Into::into).map(INTO::from)
}
pub(crate) fn new(node: Node) -> Self {
let node_ref = NodeRef::default();
node_ref.set(Some(node));
node_ref
}
pub(crate) fn set(&self, node: Option<Node>) {
let mut this = self.0.borrow_mut();
this.node = node;
this.link = None;
}
pub(crate) fn link(&self, node_ref: Self) {
if self == &node_ref {
return;
}
let mut this = self.0.borrow_mut();
this.node = None;
this.link = Some(node_ref);
}
pub(crate) fn reuse(&self, node_ref: Self) {
if self == &node_ref {
return;
}
let mut this = self.0.borrow_mut();
let existing = node_ref.0.borrow();
this.node = existing.node.clone();
this.link = existing.link.clone();
}
}
pub fn create_portal(child: Html, host: Element) -> Html {
VNode::VPortal(VPortal::new(child, host))
}
#[cfg(test)]
mod tests {
use super::*;
use gloo_utils::document;
#[cfg(feature = "wasm_test")]
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
#[cfg(feature = "wasm_test")]
wasm_bindgen_test_configure!(run_in_browser);
#[test]
fn self_linking_node_ref() {
let node: Node = document().create_text_node("test node").into();
let node_ref = NodeRef::new(node.clone());
let node_ref_2 = NodeRef::new(node.clone());
node_ref.link(node_ref.clone());
assert_eq!(node, node_ref.get().unwrap());
node_ref.link(node_ref_2.clone());
node_ref_2.link(node_ref);
assert_eq!(node, node_ref_2.get().unwrap());
}
}