Skip to main content

workflow_html/
render.rs

1use crate::Html;
2use crate::interface::Hooks;
3use crate::utils::{Element, ElementResult, document};
4use std::collections::BTreeMap;
5pub use std::fmt::{Result, Write};
6pub use std::sync::Arc;
7
8/// A collection of retained renderables kept alive for the lifetime of an [`Html`].
9pub type Renderables = Vec<Arc<dyn Render>>;
10
11//pub type RenderPtr = Arc<dyn Render>;
12
13/// Implemented by values that can be rendered both to an HTML string and to
14/// live DOM nodes, optionally exposing `@name` hooks and retained renderables.
15pub trait Render {
16    //type Type;
17    //fn on(&mut self, _event:&str, _cb: Box<dyn Fn(dyn Render) -> ElementResult<()>>){
18
19    //}
20    /// Renders this value to an HTML string by concatenating its markup fragments.
21    fn html(&self) -> String {
22        let mut buf = vec![];
23        self.render(&mut buf).unwrap();
24        buf.join("")
25    }
26    // fn render_tree(self)->ElementResult<(Vec<Element>, BTreeMap<String, Element>)>{
27    /// Renders this value into a detached container and returns an [`Html`]
28    /// holding the resulting root elements, hooks and retained renderables.
29    fn render_tree(self) -> ElementResult<Html>
30    where
31        Self: Sized,
32    {
33        let mut parent = document().create_element("div").unwrap();
34        //parent.set_attribute("class", "temp-root")?;
35        let mut renderable = vec![];
36        //renderable.push((*self).clone());
37        let map = self.render_tree_into(&mut parent, &mut renderable)?;
38        let mut list = vec![];
39        let children = parent.children();
40        let len = children.length();
41        for index in 0..len {
42            if let Some(child) = children.get_with_index(index) {
43                list.push(child);
44            }
45        }
46
47        Html::new(list, map, renderable)
48    }
49    /// Renders this value's DOM nodes into the existing `parent` element,
50    /// collecting retained renderables and returning the resulting map of
51    /// `@name` hook bindings.
52    fn render_tree_into(
53        self,
54        parent: &mut Element,
55        renderables: &mut Renderables,
56    ) -> ElementResult<BTreeMap<String, Element>>
57    where
58        Self: Sized,
59    {
60        let mut map = BTreeMap::new();
61        self.render_node(parent, &mut map, renderables)?;
62        Ok(map)
63    }
64
65    /// Builds the live DOM nodes for this value under `_parent`, recording any
66    /// `@name` hooks into `_map` and pushing retained renderables onto
67    /// `_renderables`. The default implementation does nothing.
68    fn render_node(
69        self,
70        _parent: &mut Element,
71        _map: &mut Hooks,
72        _renderables: &mut Renderables,
73    ) -> ElementResult<()>
74    where
75        Self: Sized,
76    {
77        Ok(())
78    }
79
80    /// Renders this value as HTML markup, appending fragments to `_w`.
81    fn render(&self, _w: &mut Vec<String>) -> ElementResult<()>;
82
83    /// Releases any retained event-listener closures held by this value and its
84    /// children. The default implementation does nothing.
85    fn remove_event_listeners(&self) -> ElementResult<()> {
86        Ok(())
87    }
88}
89
90//impl Render for () {}
91
92impl Render for () {
93    fn render(&self, _w: &mut Vec<String>) -> ElementResult<()> {
94        Ok(())
95    }
96}
97
98impl Render for &str {
99    fn render(&self, w: &mut Vec<String>) -> ElementResult<()> {
100        w.push(self.to_string());
101        Ok(())
102    }
103    fn render_node(
104        self,
105        parent: &mut Element,
106        _map: &mut Hooks,
107        _renderables: &mut Renderables,
108    ) -> ElementResult<()> {
109        let el = document().create_text_node(self);
110        parent.append_child(&el)?;
111        Ok(())
112    }
113}
114
115impl<T: Render + Clone> Render for Vec<T> {
116    fn render(&self, list: &mut Vec<std::string::String>) -> ElementResult<()> {
117        for item in self {
118            item.render(list)?;
119        }
120        Ok(())
121    }
122
123    fn render_node(
124        self,
125        parent: &mut Element,
126        map: &mut Hooks,
127        renderables: &mut Renderables,
128    ) -> ElementResult<()> {
129        for item in self {
130            item.render_node(parent, map, renderables)?;
131        }
132        Ok(())
133    }
134}
135/*
136impl<T: Render + Clone> Render for Arc<Vec<T>> {
137    fn render(&self, list: &mut Vec<std::string::String>) -> ElementResult<()> {
138        for item in self.iter() {
139            item.render(list)?;
140        }
141        Ok(())
142    }
143
144    fn render_node(
145        self,
146        parent: &mut Element,
147        map: &mut Hooks,
148        renderables: &mut Renderables,
149    ) -> ElementResult<()> {
150        for item in self.iter() {
151            item.clone().render_node(parent, map, renderables)?;
152        }
153        Ok(())
154    }
155}
156*/
157
158impl<T: Render + Clone> Render for Option<T> {
159    fn render_node(
160        self,
161        parent: &mut Element,
162        map: &mut Hooks,
163        renderables: &mut Renderables,
164    ) -> ElementResult<()> {
165        if let Some(h) = self {
166            h.render_node(parent, map, renderables)?;
167        }
168        Ok(())
169    }
170
171    fn render(&self, w: &mut Vec<String>) -> ElementResult<()> {
172        if let Some(h) = self {
173            h.render(w)?;
174        }
175        Ok(())
176    }
177}
178
179macro_rules! impl_tuple {
180    ($($ident:ident)+) => {
181        impl<$($ident: Render,)+> Render for ($($ident,)+) {
182            #[inline]
183            #[allow(non_snake_case)]
184            fn render(&self, w: &mut Vec<String>)->ElementResult<()>{
185                let ($($ident,)+) = self;
186                $($ident.render(w)?;)+
187                Ok(())
188            }
189            #[allow(non_snake_case)]
190            fn render_node(
191                self,
192                parent:&mut Element,
193                map:&mut Hooks,
194                renderables:&mut Renderables
195            )->ElementResult<()>{
196                let ($($ident,)+) = self;
197                $($ident.render_node(parent, map, renderables)?;)+
198                Ok(())
199            }
200        }
201    }
202}
203
204macro_rules! impl_types {
205    ($($ident:ident)+) => {
206        $(
207            impl Render for $ident {
208                fn render(&self, w: &mut Vec<String>)->ElementResult<()>{
209                    w.push(format!("{}", self));
210                    Ok(())
211                }
212                fn render_node(
213                    self,
214                    parent:&mut Element,
215                    _map:&mut Hooks,
216                    _renderables:&mut Renderables
217                )->ElementResult<()>{
218                    let el = document().create_text_node(&format!("{}", self));
219                    parent.append_child(&el)?;
220                    Ok(())
221                }
222            }
223        )+
224    }
225}
226
227impl_types! {f32 f64 u128 u64 u32 u16 u8 i8 i16 i32 i64 i128 bool String usize}
228
229impl_tuple! {A B}
230impl_tuple! {A B C}
231impl_tuple! {A B C D}
232impl_tuple! {A B C D E}
233impl_tuple! {A B C D F G}
234impl_tuple! {A B C D F G H}
235impl_tuple! {A B C D F G H I}
236impl_tuple! {A B C D F G H I J}
237impl_tuple! {A B C D F G H I J K}