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