1use std::fmt;
13
14#[cfg(feature = "web")]
15pub use self::create_element::VIRTUAL_NODE_MARKER_PROPERTY;
16#[cfg(feature = "web")]
17pub use self::event::EventAttribFn;
18pub use self::iterable_nodes::*;
19pub use self::velement::*;
20pub use self::vtext::*;
21
22#[cfg(feature = "web")]
23pub mod event;
24pub mod test_utils;
25
26#[cfg(feature = "web")]
27mod create_element;
28
29mod iterable_nodes;
30mod velement;
31mod vtext;
32
33#[derive(PartialEq)]
49pub enum VirtualNode {
50 Element(VElement),
52 Text(VText),
58}
59
60impl VirtualNode {
61 pub fn element<S>(tag: S) -> Self
71 where
72 S: Into<String>,
73 {
74 VirtualNode::Element(VElement::new(tag))
75 }
76
77 pub fn text<S>(text: S) -> Self
87 where
88 S: Into<String>,
89 {
90 VirtualNode::Text(VText::new(text.into()))
91 }
92
93 pub fn as_velement_ref(&self) -> Option<&VElement> {
99 match self {
100 VirtualNode::Element(ref element_node) => Some(element_node),
101 _ => None,
102 }
103 }
104
105 pub fn as_velement_mut(&mut self) -> Option<&mut VElement> {
110 match self {
111 VirtualNode::Element(ref mut element_node) => Some(element_node),
112 _ => None,
113 }
114 }
115
116 pub fn as_vtext_ref(&self) -> Option<&VText> {
122 match self {
123 VirtualNode::Text(ref text_node) => Some(text_node),
124 _ => None,
125 }
126 }
127
128 pub fn as_vtext_mut(&mut self) -> Option<&mut VText> {
133 match self {
134 VirtualNode::Text(ref mut text_node) => Some(text_node),
135 _ => None,
136 }
137 }
138
139 #[cfg(feature = "web")]
141 pub fn create_dom_node(
142 &self,
143 events: &mut self::event::VirtualEvents,
144 ) -> (web_sys::Node, crate::event::VirtualEventNode) {
145 match self {
146 VirtualNode::Text(text_node) => (
147 text_node.create_text_node().into(),
148 events.create_text_node(),
149 ),
150 VirtualNode::Element(element_node) => {
151 let (elem, events) = element_node.create_element_node(events);
152 (elem.into(), events)
153 }
154 }
155 }
156
157 pub fn insert_space_before_text(&mut self) {
164 match self {
165 VirtualNode::Text(text_node) => {
166 text_node.text = " ".to_string() + &text_node.text;
167 }
168 _ => {}
169 }
170 }
171
172 pub fn insert_space_after_text(&mut self) {
180 match self {
181 VirtualNode::Text(text_node) => {
182 text_node.text += " ";
183 }
184 _ => {}
185 }
186 }
187}
188
189pub trait View {
191 fn render(&self) -> VirtualNode;
193}
194
195impl<V> From<&V> for VirtualNode
196where
197 V: View,
198{
199 fn from(v: &V) -> Self {
200 v.render()
201 }
202}
203
204impl From<VText> for VirtualNode {
205 fn from(other: VText) -> Self {
206 VirtualNode::Text(other)
207 }
208}
209
210impl From<VElement> for VirtualNode {
211 fn from(other: VElement) -> Self {
212 VirtualNode::Element(other)
213 }
214}
215
216impl From<&str> for VirtualNode {
217 fn from(other: &str) -> Self {
218 VirtualNode::text(other)
219 }
220}
221
222impl From<String> for VirtualNode {
223 fn from(other: String) -> Self {
224 VirtualNode::text(other.as_str())
225 }
226}
227
228impl IntoIterator for VirtualNode {
229 type Item = VirtualNode;
230 type IntoIter = ::std::vec::IntoIter<VirtualNode>;
232
233 fn into_iter(self) -> Self::IntoIter {
234 vec![self].into_iter()
235 }
236}
237
238impl Into<::std::vec::IntoIter<VirtualNode>> for VirtualNode {
239 fn into(self) -> ::std::vec::IntoIter<VirtualNode> {
240 self.into_iter()
241 }
242}
243
244impl fmt::Debug for VirtualNode {
245 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 match self {
247 VirtualNode::Element(e) => write!(f, "Node::{:?}", e),
248 VirtualNode::Text(t) => write!(f, "Node::{:?}", t),
249 }
250 }
251}
252
253impl fmt::Display for VirtualNode {
255 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
256 match self {
257 VirtualNode::Element(element) => write!(f, "{}", element),
258 VirtualNode::Text(text) => write!(f, "{}", text),
259 }
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 #[test]
268 fn self_closing_tag_to_string() {
269 let node = VirtualNode::element("br");
270
271 assert_eq!(&node.to_string(), "<br>");
273 }
274
275 #[test]
276 fn to_string() {
277 let mut node = VirtualNode::Element(VElement::new("div"));
278 node.as_velement_mut()
279 .unwrap()
280 .attrs
281 .insert("id".into(), "some-id".into());
282
283 let mut child = VirtualNode::Element(VElement::new("span"));
284
285 let text = VirtualNode::Text(VText::new("Hello world"));
286
287 child.as_velement_mut().unwrap().children.push(text);
288
289 node.as_velement_mut().unwrap().children.push(child);
290
291 let expected = r#"<div id="some-id"><span>Hello world</span></div>"#;
292
293 assert_eq!(node.to_string(), expected);
294 }
295
296 #[test]
298 fn boolean_attribute_true_shown() {
299 let mut button = VElement::new("button");
300 button.attrs.insert("disabled".into(), true.into());
301
302 let expected = "<button disabled></button>";
303 let button = VirtualNode::Element(button).to_string();
304
305 assert_eq!(button.to_string(), expected);
306 }
307
308 #[test]
310 fn boolean_attribute_false_ignored() {
311 let mut button = VElement::new("button");
312 button.attrs.insert("disabled".into(), false.into());
313
314 let expected = "<button></button>";
315 let button = VirtualNode::Element(button).to_string();
316
317 assert_eq!(button.to_string(), expected);
318 }
319}