on master help sign in
examples/todomvc: Use the element builder for rendering
commit8862ed92fc933cc7de57101b7cf6d5a8993dc3a0 authorNick Fitzgerald <fitzgen@gmail.com> dateWed 13 Feb 2019, 14:35 (8 years ago) parent112586c
3 files changed+180−368
examples/todomvc/src/lib.rs+2−2 examples/todomvc/src/todo.rs+70−124 examples/todomvc/src/todos.rs+108−242
examples/todomvc/src/lib.rs+2−2
@@ -10,9 +10,9 @@ pub mod todos;
1010pub mod utils;
1111pub mod visibility;
1212
13−use controller::Controller;
13+use crate::controller::Controller;
14+use crate::todos::Todos;
1415use dodrio::Vdom;
15−use todos::Todos;
1616use wasm_bindgen::prelude::*;
1717
1818/// Run the TodoMVC app!
examples/todomvc/src/todo.rs+70−124
@@ -1,7 +1,7 @@
11//! Type definition and `dodrio::Render` implementation for a single todo item.
22
33use crate::keys;
4−use dodrio::{bumpalo::Bump, on, Attribute, Node, Render, RootRender, VdomWeak};
4+use dodrio::{bumpalo::Bump, Node, Render, RootRender, VdomWeak};
55use serde::{Deserialize, Serialize};
66use std::marker::PhantomData;
77use wasm_bindgen::{prelude::*, JsCast};
@@ -93,137 +93,83 @@ impl<C> Todo<C> {
9393}
9494
9595impl<C: TodoActions> Render for Todo<C> {
96− fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> dodrio::Node<'bump>
96+ fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
9797 where
9898 'a: 'bump,
9999 {
100− use dodrio::bumpalo::{self, collections::String};
101−
102− let mut class = String::new_in(bump);
103− if self.completed {
104− class.push_str("completed ");
105− }
106− if self.edits.is_some() {
107− class.push_str("editing");
108− }
100+ use dodrio::{
101+ builder::*,
102+ bumpalo::{self, collections::String},
103+ };
109104
110105 let id = self.id;
111106 let title = self.edits.as_ref().unwrap_or(&self.title);
112− let elem_id = bumpalo::format!(in bump, "todo-{}", id);
113−
114− let mut input_attrs = bumpalo::vec![
115− in bump;
116− Attribute {
117− name: "class",
118− value: "toggle",
119− },
120− Attribute {
121− name: "type",
122− value: "checkbox",
123− }
124− ];
125− if self.completed {
126− input_attrs.push(Attribute {
127− name: "checked",
128− value: "",
129− });
130− }
131− let input_attrs = input_attrs.into_bump_slice();
132−
133− Node::element(
134− bump,
135− "li",
136− [],
137− [Attribute {
138− name: "class",
139− value: class.into_bump_str(),
140− }],
141− [
142− Node::element(
143− bump,
144− "div",
145− [],
146− [Attribute {
147− name: "class",
148− value: "view",
149− }],
150− [
151− Node::element(
152− bump,
153− "input",
154− [on(bump, "click", move |root, vdom, _event| {
107+
108+ li(bump)
109+ .attr("class", {
110+ let mut class = String::new_in(bump);
111+ if self.completed {
112+ class.push_str("completed ");
113+ }
114+ if self.edits.is_some() {
115+ class.push_str("editing");
116+ }
117+ class.into_bump_str()
118+ })
119+ .children([
120+ div(bump)
121+ .attr("class", "view")
122+ .children([
123+ input(bump)
124+ .attr("class", "toggle")
125+ .attr("type", "checkbox")
126+ .bool_attr("checked", self.completed)
127+ .on("click", move |root, vdom, _event| {
155128 C::toggle_completed(root, vdom, id);
156− })],
157− input_attrs,
158− [],
159− ),
160− Node::element(
161− bump,
162− "label",
163− [on(bump, "dblclick", move |root, vdom, _event| {
129+ })
130+ .finish(),
131+ label(bump)
132+ .on("dblclick", move |root, vdom, _event| {
164133 C::begin_editing(root, vdom, id);
165− })],
166− [],
167− [Node::text(title)],
168− ),
169− Node::element(
170− bump,
171− "button",
172− [on(bump, "click", move |root, vdom, _event| {
134+ })
135+ .children([text(title)])
136+ .finish(),
137+ button(bump)
138+ .attr("class", "destroy")
139+ .on("click", move |root, vdom, _event| {
173140 C::delete(root, vdom, id);
174− })],
175− [Attribute {
176− name: "class",
177− value: "destroy",
178− }],
179− [],
180− ),
181− ],
182− ),
183− Node::element(
184− bump,
185− "input",
186− [
187− on(bump, "input", move |root, vdom, event| {
188− let input = event
189− .target()
190− .unwrap_throw()
191− .unchecked_into::<web_sys::HtmlInputElement>();
192− C::update_edits(root, vdom, id, input.value());
193− }),
194− on(bump, "blur", move |root, vdom, _event| {
195− C::finish_edits(root, vdom, id);
196− }),
197− on(bump, "keydown", move |root, vdom, event| {
198− let event = event.unchecked_into::<web_sys::KeyboardEvent>();
199− match event.key_code() {
200− keys::ENTER => C::finish_edits(root, vdom, id),
201− keys::ESCAPE => C::cancel_edits(root, vdom, id),
202− _ => {}
203− }
204− }),
205− ],
206− [
207− Attribute {
208− name: "class",
209− value: "edit",
210− },
211− Attribute {
212− name: "value",
213− value: title,
214− },
215− Attribute {
216− name: "name",
217− value: "title",
218− },
219− Attribute {
220− name: "id",
221− value: elem_id.into_bump_str(),
222− },
223− ],
224− [],
225− ),
226− ],
227− )
141+ })
142+ .finish(),
143+ ])
144+ .finish(),
145+ input(bump)
146+ .attr("class", "edit")
147+ .attr("value", title)
148+ .attr("name", "title")
149+ .attr(
150+ "id",
151+ bumpalo::format!(in bump, "todo-{}", id).into_bump_str(),
152+ )
153+ .on("input", move |root, vdom, event| {
154+ let input = event
155+ .target()
156+ .unwrap_throw()
157+ .unchecked_into::<web_sys::HtmlInputElement>();
158+ C::update_edits(root, vdom, id, input.value());
159+ })
160+ .on("blur", move |root, vdom, _event| {
161+ C::finish_edits(root, vdom, id);
162+ })
163+ .on("keydown", move |root, vdom, event| {
164+ let event = event.unchecked_into::<web_sys::KeyboardEvent>();
165+ match event.key_code() {
166+ keys::ENTER => C::finish_edits(root, vdom, id),
167+ keys::ESCAPE => C::cancel_edits(root, vdom, id),
168+ _ => {}
169+ }
170+ })
171+ .finish(),
172+ ])
173+ .finish()
228174 }
229175}
examples/todomvc/src/todos.rs+108−242
@@ -7,7 +7,7 @@ use crate::visibility::Visibility;
77use crate::{keys, utils};
88use dodrio::{
99 bumpalo::{self, Bump},
10− on, Attribute, Node, Render, RootRender, VdomWeak,
10+ Node, Render, RootRender, VdomWeak,
1111};
1212use serde::{Deserialize, Serialize};
1313use std::marker::PhantomData;
@@ -140,65 +140,42 @@ impl<C: TodosActions> Todos<C> {
140140 where
141141 'a: 'bump,
142142 {
143− Node::element(
144− bump,
145− "header",
146− [],
147− [Attribute {
148− name: "class",
149− value: "header",
150− }],
151− [
152− Node::element(bump, "h1", [], [], [Node::text("todos")]),
153− Node::element(
154− bump,
155− "input",
156− [
157− on(bump, "input", |root, vdom, event| {
158− let input = event
159− .target()
160− .unwrap_throw()
161− .unchecked_into::<web_sys::HtmlInputElement>();
162− C::update_draft(root, vdom, input.value());
163− }),
164− on(bump, "keydown", |root, vdom, event| {
165− let event = event.unchecked_into::<web_sys::KeyboardEvent>();
166− if event.key_code() == keys::ENTER {
167− C::finish_draft(root, vdom);
168− }
169− }),
170− ],
171− [
172− Attribute {
173− name: "class",
174− value: "new-todo",
175− },
176− Attribute {
177− name: "placeholder",
178− value: "What needs to be done?",
179− },
180− Attribute {
181− name: "autofocus",
182− value: "",
183− },
184− Attribute {
185− name: "value",
186− value: &self.draft,
187− },
188− ],
189− [],
190− ),
191− ],
192− )
143+ use dodrio::builder::*;
144+
145+ header(bump)
146+ .attr("class", "header")
147+ .children([
148+ h1(bump).children([text("todos")]).finish(),
149+ input(bump)
150+ .on("input", |root, vdom, event| {
151+ let input = event
152+ .target()
153+ .unwrap_throw()
154+ .unchecked_into::<web_sys::HtmlInputElement>();
155+ C::update_draft(root, vdom, input.value());
156+ })
157+ .on("keydown", |root, vdom, event| {
158+ let event = event.unchecked_into::<web_sys::KeyboardEvent>();
159+ if event.key_code() == keys::ENTER {
160+ C::finish_draft(root, vdom);
161+ }
162+ })
163+ .attr("class", "new-todo")
164+ .attr("placeholder", "What needs to be done?")
165+ .attr("autofocus", "")
166+ .attr("value", &self.draft)
167+ .finish(),
168+ ])
169+ .finish()
193170 }
194171
195172 fn todos_list<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
196173 where
197174 'a: 'bump,
198175 {
199− use dodrio::bumpalo::collections::Vec;
176+ use dodrio::{builder::*, bumpalo::collections::Vec};
200177
201− let mut todos = Vec::new_in(bump);
178+ let mut todos = Vec::with_capacity_in(self.todos.len(), bump);
202179 todos.extend(
203180 self.todos
204181 .iter()
@@ -209,91 +186,43 @@ impl<C: TodosActions> Todos<C> {
209186 })
210187 .map(|t| t.render(bump)),
211188 );
212− let todos = todos.into_bump_slice();
213−
214− let mut input_attrs = bumpalo::vec![
215− in bump;
216− Attribute {
217− name: "class",
218− value: "toggle-all",
219− },
220− Attribute {
221− name: "id",
222− value: "toggle-all",
223− },
224− Attribute {
225− name: "type",
226− value: "checkbox",
227− },
228− Attribute {
229− name: "name",
230− value: "toggle",
231− }
232− ];
233− if self.todos.iter().all(|t| t.is_complete()) {
234− input_attrs.push(Attribute {
235− name: "checked",
236− value: "",
237− });
238− }
239− let input_attrs = input_attrs.into_bump_slice();
240−
241− Node::element(
242− bump,
243− "section",
244− [],
245− [
246− Attribute {
247− name: "class",
248− value: "main",
249− },
250− Attribute {
251− name: "visibility",
252− value: if self.todos.is_empty() {
253− "hidden"
254− } else {
255− "visible"
256− },
189+
190+ section(bump)
191+ .attr("class", "main")
192+ .attr(
193+ "visibility",
194+ if self.todos.is_empty() {
195+ "hidden"
196+ } else {
197+ "visible"
257198 },
258− ],
259− [
260− Node::element(
261− bump,
262− "input",
263− [on(bump, "click", |root, vdom, _event| {
199+ )
200+ .children([
201+ input(bump)
202+ .attr("class", "toggle-all")
203+ .attr("id", "toggle-all")
204+ .attr("type", "checkbox")
205+ .attr("name", "toggle")
206+ .bool_attr("checked", self.todos.iter().all(|t| t.is_complete()))
207+ .on("click", |root, vdom, _event| {
264208 C::toggle_all(root, vdom);
265− })],
266− input_attrs,
267− [],
268− ),
269− Node::element(
270− bump,
271− "label",
272− [],
273− [Attribute {
274− name: "for",
275− value: "toggle-all",
276− }],
277− [Node::text("Mark all as complete")],
278− ),
279− Node::element(
280− bump,
281− "ul",
282− [],
283− [Attribute {
284− name: "class",
285− value: "todo-list",
286− }],
287− todos,
288− ),
289− ],
290− )
209+ })
210+ .finish(),
211+ label(bump)
212+ .attr("for", "toggle-all")
213+ .children([text("Mark all as complete")])
214+ .finish(),
215+ ul(bump).attr("class", "todo-list").children(todos).finish(),
216+ ])
217+ .finish()
291218 }
292219
293220 fn footer<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
294221 where
295222 'a: 'bump,
296223 {
224+ use dodrio::builder::*;
225+
297226 let completed_count = self.todos.iter().filter(|t| t.is_complete()).count();
298227 let incomplete_count = self.todos.len() - completed_count;
299228 let items_left = if incomplete_count == 1 {
@@ -303,95 +232,43 @@ impl<C: TodosActions> Todos<C> {
303232 };
304233 let incomplete_count = bumpalo::format!(in bump, "{}", incomplete_count);
305234
306− let attrs = if self.todos.is_empty() {
307− &bump.alloc([
308− Attribute {
309− name: "class",
310− value: "footer",
311− },
312− Attribute {
313− name: "hidden",
314− value: "",
315− },
316− ])[..]
317− } else {
318− &bump.alloc([Attribute {
319− name: "class",
320− value: "footer",
321− }])[..]
322− };
323−
324235 let clear_completed_text = bumpalo::format!(
325236 in bump,
326237 "Clear completed ({})",
327238 self.todos.iter().filter(|t| t.is_complete()).count()
328239 );
329240
330− Node::element(
331− bump,
332− "footer",
333− [],
334− attrs,
335− [
336− Node::element(
337− bump,
338− "span",
339− [],
340− [Attribute {
341− name: "class",
342− value: "todo-count",
343− }],
344− [
345− Node::element(
346− bump,
347− "strong",
348− [],
349− [],
350− [Node::text(incomplete_count.into_bump_str())],
351− ),
352− Node::text(items_left),
353− ],
354− ),
355− Node::element(
356− bump,
357− "ul",
358− [],
359− [Attribute {
360− name: "class",
361− value: "filters",
362− }],
363− [
241+ footer(bump)
242+ .attr("class", "footer")
243+ .bool_attr("hidden", self.todos.is_empty())
244+ .children([
245+ span(bump)
246+ .attr("class", "todo-count")
247+ .children([
248+ strong(bump)
249+ .children([text(incomplete_count.into_bump_str())])
250+ .finish(),
251+ text(items_left),
252+ ])
253+ .finish(),
254+ ul(bump)
255+ .attr("class", "filters")
256+ .children([
364257 self.visibility_swap(bump, "#/", Visibility::All),
365258 self.visibility_swap(bump, "#/active", Visibility::Active),
366259 self.visibility_swap(bump, "#/completed", Visibility::Completed),
367− ],
368− ),
369− Node::element(
370− bump,
371− "button",
372− [on(bump, "click", |root, vdom, _event| {
260+ ])
261+ .finish(),
262+ button(bump)
263+ .on("click", |root, vdom, _event| {
373264 C::delete_completed(root, vdom);
374− })],
375− {
376− let mut attrs = bumpalo::vec![
377− in bump;
378− Attribute {
379− name: "class",
380− value: "clear-completed",
381− }
382− ];
383− if self.todos.iter().all(|t| !t.is_complete()) {
384− attrs.push(Attribute {
385− name: "hidden",
386− value: "",
387− });
388− }
389− attrs
390− },
391− [Node::text(clear_completed_text.into_bump_str())],
392− ),
393− ],
394− )
265+ })
266+ .attr("class", "clear-completed")
267+ .bool_attr("hidden", completed_count == 0)
268+ .children([text(clear_completed_text.into_bump_str())])
269+ .finish(),
270+ ])
271+ .finish()
395272 }
396273
397274 fn visibility_swap<'a, 'bump>(
@@ -403,34 +280,25 @@ impl<C: TodosActions> Todos<C> {
403280 where
404281 'a: 'bump,
405282 {
406− Node::element(
407− bump,
408− "li",
409− [on(bump, "click", move |root, vdom, _event| {
283+ use dodrio::builder::*;
284+
285+ li(bump)
286+ .on("click", move |root, vdom, _event| {
410287 C::change_visibility(root, vdom, target_vis);
411− })],
412− [],
413− [Node::element(
414− bump,
415− "a",
416− [],
417− [
418− Attribute {
419− name: "href",
420− value: url,
421− },
422− Attribute {
423− name: "class",
424− value: if self.visibility == target_vis {
425− "selected"
426− } else {
427− ""
428− },
288+ })
289+ .children([a(bump)
290+ .attr("href", url)
291+ .attr(
292+ "class",
293+ if self.visibility == target_vis {
294+ "selected"
295+ } else {
296+ ""
429297 },
430− ],
431− [Node::text(target_vis.label())],
432− )],
433− )
298+ )
299+ .children([text(target_vis.label())])
300+ .finish()])
301+ .finish()
434302 }
435303}
436304
@@ -439,12 +307,10 @@ impl<C: TodosActions> Render for Todos<C> {
439307 where
440308 'a: 'bump,
441309 {
442− Node::element(
443− bump,
444− "div",
445− [],
446− [],
447− [self.header(bump), self.todos_list(bump), self.footer(bump)],
448− )
310+ use dodrio::builder::*;
311+
312+ div(bump)
313+ .children([self.header(bump), self.todos_list(bump), self.footer(bump)])
314+ .finish()
449315 }
450316}