1use crate::{Error, Event, EventResult, Node, Scope, scene::Listener};
2use fusor::bind::{Checkbox, TextValue};
3use std::{cell::RefCell, fmt::Display, rc::Rc};
4
5impl Scope {
6 fn effect(&mut self, node: Node, mut update: impl FnMut(&Node) + 'static) -> Result<(), Error> {
7 self.watch(move || {
8 update(&node);
9 Ok(())
10 })
11 }
12 pub fn text<T: Display>(
13 &mut self,
14 id: usize,
15 read: impl Fn() -> T + 'static,
16 ) -> Result<(), Error> {
17 self.effect(
18 crate::scope::anchor(&self.texts, "text", id)?,
19 move |node| node.set_text(read().to_string()),
20 )
21 }
22 pub fn on<R: EventResult>(
23 &mut self,
24 id: usize,
25 name: &'static str,
26 mut callback: impl FnMut(Event) -> R + 'static,
27 ) -> Result<(), Error> {
28 let node = self.element(id)?;
29 let listener: Listener = Rc::new(RefCell::new(move |event| callback(event).into_result()));
30 node.0
31 .listeners
32 .borrow_mut()
33 .entry(name)
34 .or_default()
35 .push(listener);
36 Ok(())
37 }
38 pub fn bind_text(&mut self, id: usize, model: impl TextValue) -> Result<(), Error> {
39 let input_model = model.clone();
40 self.on(id, "input", move |event| {
41 input_model.edit(event.target.value())
42 })?;
43 let blur_model = model.clone();
44 self.on(id, "blur", move |_| blur_model.touch())?;
45 let node = self.element(id)?;
46 self.watch(move || {
47 if !model.shows(&node.value()) {
48 node.set_value(model.text());
49 }
50 Ok(())
51 })
52 }
53 pub fn bind_checkbox(
54 &mut self,
55 id: usize,
56 model: impl Checkbox,
57 choice: impl Fn() -> String + 'static,
58 ) -> Result<(), Error> {
59 let choice = Rc::new(choice);
60 let (input_choice, input_model) = (choice.clone(), model.clone());
61 self.on(id, "change", move |event| {
62 input_model.check(&input_choice(), event.target.checked())
63 })?;
64 let node = self.element(id)?;
65 self.watch(move || {
66 node.set_checked(model.checked(&choice()));
67 Ok(())
68 })
69 }
70 pub fn value<T: Display>(
71 &mut self,
72 id: usize,
73 read: impl Fn() -> T + 'static,
74 ) -> Result<(), Error> {
75 self.effect(self.element(id)?, move |node| {
76 node.set_value(read().to_string())
77 })
78 }
79 pub fn checked(&mut self, id: usize, read: impl Fn() -> bool + 'static) -> Result<(), Error> {
80 self.effect(self.element(id)?, move |node| node.set_checked(read()))
81 }
82 pub fn attribute<T: Display>(
83 &mut self,
84 id: usize,
85 name: &'static str,
86 read: impl Fn() -> T + 'static,
87 ) -> Result<(), Error> {
88 self.effect(self.element(id)?, move |node| {
89 node.set_attribute(name, Some(read().to_string()))
90 })
91 }
92 pub fn boolean(
93 &mut self,
94 id: usize,
95 name: &'static str,
96 read: impl Fn() -> bool + 'static,
97 ) -> Result<(), Error> {
98 self.effect(self.element(id)?, move |node| {
99 node.set_attribute(name, read().then(String::new))
100 })
101 }
102 pub fn class(
103 &mut self,
104 id: usize,
105 name: &'static str,
106 read: impl Fn() -> bool + 'static,
107 ) -> Result<(), Error> {
108 self.effect(self.element(id)?, move |node| {
109 node.set_attribute(
110 "class",
111 Some(crate::text::toggle_class(
112 &node.attribute("class").unwrap_or_default(),
113 name,
114 read(),
115 )),
116 )
117 })
118 }
119}