pub mod dynamic;
mod event;
pub mod render_position;
pub mod renderable;
pub mod text;
use js_sys::Function;
use wasm_bindgen::JsValue;
use web_sys::{console, Document};
use crate::component::Component;
pub use self::event::EventType;
use self::{
render_position::RenderPosition,
renderable::{DomNodeBuildResult, DynamicContent, Renderable, RenderedNode},
};
#[derive(Clone, Copy)]
pub enum DomElementKind {
H1,
Div,
P,
Button,
}
impl Default for DomElementKind {
fn default() -> Self {
Self::Div
}
}
impl From<DomElementKind> for &str {
fn from(dom_node_kind: DomElementKind) -> &'static str {
use DomElementKind::*;
match dom_node_kind {
H1 => "h1",
Div => "div",
P => "p",
Button => "button",
}
}
}
pub enum TextContent {
Static(String),
Dynamic {
dependencies: Vec<usize>,
update_type: usize,
},
}
pub enum NodeContent {
Text(TextContent),
Nodes(Vec<Box<dyn Renderable>>),
}
pub enum DomContent {
Element {
kind: DomElementKind,
content: Option<Vec<Box<dyn Renderable>>>,
},
Text {
content: String,
},
}
pub struct DomNode {
kind: DomElementKind,
children: Vec<Box<dyn Renderable>>,
listeners: Vec<EventType>,
}
impl DomNode {
pub fn h1() -> Self {
Self {
kind: DomElementKind::H1,
children: Vec::new(),
listeners: Vec::new(),
}
}
pub fn p() -> Self {
Self {
kind: DomElementKind::P,
children: Vec::new(),
listeners: Vec::new(),
}
}
pub fn button() -> Self {
Self {
kind: DomElementKind::Button,
children: Vec::new(),
listeners: Vec::new(),
}
}
pub fn div() -> Self {
Self {
kind: DomElementKind::Div,
children: Vec::new(),
listeners: Vec::new(),
}
}
pub fn child(mut self, child: Box<dyn Renderable>) -> Self {
self.children.push(child);
self
}
pub fn listen(mut self, event: EventType) -> Self {
self.listeners.push(event);
self
}
}
impl Renderable for DomNode {
fn render(
self: Box<Self>,
document: &Document,
component: &dyn Component,
element: Option<RenderedNode>,
get_event_closure: &mut dyn FnMut(EventType) -> Function,
) -> Result<Option<DomNodeBuildResult>, JsValue> {
let element = element
.and_then(|element| {
if let RenderedNode::Element(element) = element {
Some(element)
} else {
None
}
})
.unwrap_or_else(|| {
console::log_1(&"creating element".into());
document
.create_element(self.kind.into())
.expect("to be able to create element")
});
let mut dynamic_content = Vec::<DynamicContent>::new();
for event in self.listeners {
element.add_event_listener_with_callback(
&String::from(event),
&get_event_closure(event),
)?;
}
Ok(Some(DomNodeBuildResult {
element: Some(RenderedNode::Element(element)),
cache_node: true,
children: Some(self.children),
dynamic_content,
in_place: false,
}))
}
}