From 54761096fbae8d1a4dd23d4ca24121c5a3ab5f08 Mon Sep 17 00:00:00 2001 From: DavidOConnor Date: Sun, 7 Apr 2019 17:38:31 -0400 Subject: [PATCH] Improved documentation of util crate. Moved history() into it. Misc cleanup --- Cargo.toml | 4 +- examples/counter/Cargo.toml | 4 +- examples/server_integration/README.md | 2 +- .../{frontend => client}/Cargo.toml | 4 +- .../{frontend => client}/serve.py | 0 .../{frontend => client}/src/lib.rs | 0 examples/todomvc/Cargo.toml | 4 +- examples/todomvc/src/lib.rs | 6 +- src/dom_types.rs | 4 +- src/lib.rs | 8 +- src/routing.rs | 12 ++- src/util.rs | 17 +++- src/vdom.rs | 91 +++---------------- src/websys_bridge.rs | 23 ++--- 14 files changed, 56 insertions(+), 123 deletions(-) rename examples/server_integration/{frontend => client}/Cargo.toml (84%) rename examples/server_integration/{frontend => client}/serve.py (100%) rename examples/server_integration/{frontend => client}/src/lib.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 791fd599e..22bd8aa8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,11 @@ edition = "2018" crate-type = ["cdylib", "rlib"] [dev-dependencies] -wasm-bindgen-test = "^0.2.38" # NOTE: keep in sync with wasm-bindgen version +wasm-bindgen-test = "^0.2.40" # NOTE: keep in sync with wasm-bindgen version [dependencies] # NOTE: keep in sync with wasm-bindgen-test version -wasm-bindgen = {version = "^0.2.38", features = ["serde-serialize"]} +wasm-bindgen = {version = "^0.2.40", features = ["serde-serialize"]} js-sys = "0.3.6" console_error_panic_hook = "^0.1.5" serde = { version = "^1.0.85", features = ['derive'] } diff --git a/examples/counter/Cargo.toml b/examples/counter/Cargo.toml index 7a5dd20b2..b13ed11e3 100644 --- a/examples/counter/Cargo.toml +++ b/examples/counter/Cargo.toml @@ -9,5 +9,5 @@ crate-type = ["cdylib"] [dependencies] seed = {path = "../../"} -wasm-bindgen = "^0.2.37" -web-sys = "^0.3.6" +wasm-bindgen = "^0.2.40" +web-sys = "^0.3.17" diff --git a/examples/server_integration/README.md b/examples/server_integration/README.md index 5cfb01646..dec78f3c9 100644 --- a/examples/server_integration/README.md +++ b/examples/server_integration/README.md @@ -8,5 +8,5 @@ a simple exmaple for a get request. ## Execute First run either `build.sh` or `build.ps1` depending on your operating -system to compile and package the frontend part and afterwards start the +system to compile and package the client, and afterwards start the server by executing `cargo +nightly run`. diff --git a/examples/server_integration/frontend/Cargo.toml b/examples/server_integration/client/Cargo.toml similarity index 84% rename from examples/server_integration/frontend/Cargo.toml rename to examples/server_integration/client/Cargo.toml index 2ae7ab686..4bc706142 100644 --- a/examples/server_integration/frontend/Cargo.toml +++ b/examples/server_integration/client/Cargo.toml @@ -10,6 +10,6 @@ crate-type = ["cdylib", "rlib"] [dependencies] futures = "^0.1.20" seed = { path = "../../../"} -wasm-bindgen = "^0.2.37" -web-sys = "^0.3.6" +wasm-bindgen = "^0.2.40" +web-sys = "^0.3.17" shared = { path = "../shared"} diff --git a/examples/server_integration/frontend/serve.py b/examples/server_integration/client/serve.py similarity index 100% rename from examples/server_integration/frontend/serve.py rename to examples/server_integration/client/serve.py diff --git a/examples/server_integration/frontend/src/lib.rs b/examples/server_integration/client/src/lib.rs similarity index 100% rename from examples/server_integration/frontend/src/lib.rs rename to examples/server_integration/client/src/lib.rs diff --git a/examples/todomvc/Cargo.toml b/examples/todomvc/Cargo.toml index 732ec0c0a..643d3f0e2 100644 --- a/examples/todomvc/Cargo.toml +++ b/examples/todomvc/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] seed = {path = "../../"} -wasm-bindgen = "^0.2.37" -web-sys = "^0.3.6" +wasm-bindgen = "^0.2.40" +web-sys = "^0.3.17" serde = { version = "^1.0.80", features = ['derive'] } diff --git a/examples/todomvc/src/lib.rs b/examples/todomvc/src/lib.rs index 36545e536..7874365cf 100644 --- a/examples/todomvc/src/lib.rs +++ b/examples/todomvc/src/lib.rs @@ -312,7 +312,8 @@ fn view(model: &Model) -> Vec> { ul![class!["todo-list"], todo_els] ] } else { - seed::empty() + // seed::empty() + span![] }; vec![ @@ -334,7 +335,8 @@ fn view(model: &Model) -> Vec> { if model.active_count() > 0 || model.completed_count() > 0 { footer(&model) } else { - seed::empty() + // seed::empty() + span![] }, ] } diff --git a/src/dom_types.rs b/src/dom_types.rs index b76c94428..09fcf0cd9 100644 --- a/src/dom_types.rs +++ b/src/dom_types.rs @@ -68,7 +68,7 @@ pub fn input_ev( ) -> Listener { let closure = move |event: web_sys::Event| { if let Some(target) = event.target() { - return handler(util::input_value(&target)); + return handler(util::get_value(&target)); } handler(String::new()) }; @@ -295,7 +295,7 @@ impl Listener { let el_ws2 = el_ws.clone(); let closure = Closure::wrap(Box::new(move |_| { if let Some(val) = val2.clone() { - if util::input_value(&el_ws2) != val { + if util::get_value(&el_ws2) != val { util::set_value(&el_ws2, &val); } } diff --git a/src/lib.rs b/src/lib.rs index 9fe84d531..d55ab9ee1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ pub use crate::{ fetch::{spawn_local, Method, Request}, routing::{push_path, push_route, Url}, - util::{document, error, log, window}, + util::{document, error, history, log, window}, vdom::App, // todo remove App once new update system in place? websys_bridge::{to_html_el, to_input, to_kbevent, to_mouse_event, to_select, to_textarea}, }; @@ -48,8 +48,7 @@ pub fn empty() -> dom_types::El { /// * [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval) pub fn set_interval(handler: Box, timeout: i32) { let callback = Closure::wrap(handler as Box); - let window = web_sys::window().expect("Can't find window"); - window + util::window() .set_interval_with_callback_and_timeout_and_arguments_0( callback.as_ref().unchecked_ref(), timeout, @@ -65,8 +64,7 @@ pub fn set_interval(handler: Box, timeout: i32) { /// * [MDN docs](https://developer.mozilla.org/en-US/docs/Wemb/API/WindowOrWorkerGlobalScope/setTimeout) pub fn set_timeout(handler: Box, timeout: i32) { let callback = Closure::wrap(handler as Box); - let window = web_sys::window().expect("Can't find window"); - window + util::window() .set_timeout_with_callback_and_timeout_and_arguments_0( callback.as_ref().unchecked_ref(), timeout, diff --git a/src/routing.rs b/src/routing.rs index 256fa7f5f..c51c0ff7d 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -3,7 +3,8 @@ use serde::{Deserialize, Serialize}; use wasm_bindgen::{closure::Closure, JsCast, JsValue}; -/// Repeated here from seed::util, to make this module standalone. +/// Repeated here from seed::util, to make this module standalone. Once we have a Gloo module +/// that handles this, use it. mod util { /// Convenience function to avoid repeating expect logic. pub fn window() -> web_sys::Window { @@ -14,6 +15,11 @@ mod util { pub fn document() -> web_sys::Document { window().document().expect("Can't find document") } + + /// Convenience function to access web_sys history + pub fn history() -> web_sys::History { + window().history().expect("Can't find history") + } } /// Contains all information used in pushing and handling routes. @@ -198,9 +204,7 @@ pub fn push_route>(url3: U) { path = path + "#" + &hash; } - util::window() - .history() - .expect("Can't find history") + util::history() .push_state_with_url(&data, &title, Some(&path)) .expect("Problem pushing state"); } diff --git a/src/util.rs b/src/util.rs index 5b3eebcf6..b20fc45c8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,6 @@ -//use wasm_bindgen::{closure::{Closure, WasmClosure}, JsCast}; +//! Provide a wrapper for commonly-used, but verbose web_sys features. +//! This module is decoupled / independent. + use wasm_bindgen::JsCast; use web_sys; @@ -12,9 +14,14 @@ pub fn document() -> web_sys::Document { window().document().expect("Can't find document") } +/// Convenience function to access the web_sys history. +pub fn history() -> web_sys::History { + window().history().expect("Can't find history") +} + /// Simplify getting the value of input elements; required due to the need to cast -/// from general nodes/elements to HTML__Elements. -pub fn input_value(target: &web_sys::EventTarget) -> String { +/// from general nodes/elements to HTML_Elements. +pub fn get_value(target: &web_sys::EventTarget) -> String { if let Some(input) = target.dyn_ref::() { return input.value(); } @@ -27,7 +34,7 @@ pub fn input_value(target: &web_sys::EventTarget) -> String { "".into() } -/// todo more DRY that could be addressed by Traits. ? +/// Similar to get_value. pub fn set_value(target: &web_sys::EventTarget, value: &str) { if let Some(input) = target.dyn_ref::() { input.set_value(value); @@ -49,7 +56,7 @@ pub fn set_value(target: &web_sys::EventTarget, value: &str) { // Closure::wrap(Box::new(inner)) //} -/// A convenience function for logging to the web browser's console. See also +/// Convenience function for logging to the web browser's console. See also /// the log! macro, which is more flexible. pub fn log(text: S) { // ignore clippy about &S diff --git a/src/vdom.rs b/src/vdom.rs index 6420af8b7..1918e377a 100644 --- a/src/vdom.rs +++ b/src/vdom.rs @@ -9,7 +9,6 @@ use wasm_bindgen::closure::Closure; use wasm_bindgen::JsValue; use wasm_bindgen_futures::future_to_promise; use web_sys::{Document, Element, Event, EventTarget, Window}; -//use either::{Left, Right, Either}; /// Determines if an update should cause the VDom to rerender or not. #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -137,52 +136,8 @@ impl Update { } } -// -//trait ViewReturn2 { -// fn convert(r: T) -> Vec>; -//} -// -//impl ViewReturn2 for El { -// fn convert(el: El) -> Vec> { -// vec![el] -// } -//} -// -//impl ViewReturn2 for Vec> { -// fn convert(els: Vec>) -> Vec> { -// els -// } -//} -// -///// Thin wrapper; impl From for Vec> appears not to work directly. -//struct ViewReturn { -// els: Vec> -//} -// - - -//pub struct View { -// els: Either, Vec>> -//} -// -//impl From> for View { -// fn from(el: El) -> Self { -// Self { els: Left(el) } -// } -//} -// -//impl From>> for View { -// fn from(els: Vec>) -> Self { -// Self { els: Right(els) } -// } -//} - - type UpdateFn = fn(Ms, &mut Mdl) -> Update; -//type ViewFn = Either El, fn(&Mdl) -> Vec>>; type ViewFn = fn(&Mdl) -> Vec>; -//type ViewFn = fn(&Mdl) -> Into>; -//type ViewFn = fn(&Mdl) -> ViewReturn2; type RoutesFn = fn(&routing::Url) -> Ms; type WindowEvents = fn(&Mdl) -> Vec>; type MsgListeners = Vec>; @@ -272,6 +227,7 @@ enum Parent { El(Element), } +/// Used to create and store initial app configuration, ie items passed by the app creator #[derive(Clone)] pub struct AppBuilder { model: Mdl, @@ -379,7 +335,7 @@ impl App { let view_els = (self.cfg.view)(&self.data.model.borrow()); // todo add these directly to the mount point. - let mut topel_vdom = El::empty(dom_types::Tag::Div); + let mut topel_vdom = El::empty(dom_types::Tag::Section); topel_vdom.children = view_els; // TODO: use window events @@ -404,8 +360,11 @@ impl App { attach_listeners(&mut topel_vdom, &self.mailbox()); - // Attach all children: This is where our initial render occurs. + // Attach all top-level elements to the mount point: This is where our initial render occurs. websys_bridge::attach_el_and_children(&mut topel_vdom, &self.cfg.mount_point, &self); + // for top_child in &mut topel_vdom.children { + // websys_bridge::attach_el_and_children(top_child, &self.cfg.mount_point, &self) + // } self.data.main_el_vdom.replace(Some(topel_vdom)); @@ -478,9 +437,11 @@ impl App { let view_els = (self.cfg.view)(&self.data.model.borrow()); // todo add these directly to the mount point. - let mut topel_new_vdom = El::empty(dom_types::Tag::Div); + let mut topel_new_vdom = El::empty(dom_types::Tag::Section); topel_new_vdom.children = view_els; + // self.data.main_el_vdom.children = view_els; + let mut old_vdom = self .data .main_el_vdom @@ -497,6 +458,7 @@ impl App { old_vdom, &mut topel_new_vdom, &self.cfg.mount_point, + // &self.cfg.document, None, &self.mailbox(), &self.clone(), @@ -814,37 +776,6 @@ pub(crate) fn patch<'a, Ms: Clone, Mdl>( let child_old = old_children_iter.next().unwrap(); let child_new = new_children_iter.next().unwrap(); - // If a key's specified, use it to match the child - // There can be multiple optomizations, but assume one key. If there are multiple - // keys, use the first (There should only be one, but no constraints atm). - // if let Some(key) = child_new.key() { - // let _matching = old.children.iter().filter(|c| c.key() == Some(key)); - // // todo continue implementation: Patch and re-order. - // } - - // match old.children.get(i_new) { - // Some(child_old) => { - // // todo: This approach is still inefficient use of key, since it overwrites - // // todo non-matching keys, preventing them from being found later. - // if let Some(key) = child_new.key() { - // if child_old.key() == Some(key) { - // continue - // } - // } - // - // // Don't compare equality here; we do that at the top of this function - // // in the recursion. - // patch(document, &mut child_old.clone(), child_new, &old_el_ws, &mailbox); - // old_children_patched.push(child_old.id.expect("Can't find child's id")); - // }, - // None => { - // // We ran out of old children to patch; create new ones. - // websys_bridge::attach_el_and_children(child_new, &old_el_ws); - // let mut child_new = child_new; - // attach_listeners(&mut child_new, &mailbox); - // } - // } - // Don't compare equality here; we do that at the top of this function // in the recursion. if let Some(new_el_ws) = patch( @@ -925,7 +856,7 @@ pub(crate) fn patch<'a, Ms: Clone, Mdl>( (unmount_actions.actions)(&child_el_ws); } - // todo get to the bottom of this + // todo get to the bottom of this: Ie why we need this code sometimes when using raw html elements. match old_el_ws.remove_child(&child_el_ws) { Ok(_) => {} Err(_) => { diff --git a/src/websys_bridge.rs b/src/websys_bridge.rs index a6cb6573e..6ba5d3aa9 100644 --- a/src/websys_bridge.rs +++ b/src/websys_bridge.rs @@ -254,26 +254,19 @@ pub fn patch_el_details(old: &mut El, new: &mut El, old_el_ws // The value's different if old_val != new_val { set_attr_shim(&old_el_ws, key, new_val); - - // We handle value in the vdom using attributes, but the DOM needs - // to use set_value. - if key == &dom_types::At::Value { - if let Some(input) = old_el_ws.dyn_ref::() { - input.set_value(&new_val); - } - if let Some(input) = old_el_ws.dyn_ref::() { - input.set_value(&new_val); - } - } } - }, + } None => set_attr_shim(&old_el_ws, key, new_val), } + // We handle value in the vdom using attributes, but the DOM needs + // to use set_value. + if key == &dom_types::At::Value { + crate::util::set_value(old_el_ws, &new_val); + } } // Remove attributes that aren't in the new vdom. for name in old.attrs.vals.keys() { if new.attrs.vals.get(name).is_none() { - // todo get to the bottom of this match old_el_ws.dyn_ref::() { Some(el) => el @@ -398,9 +391,7 @@ pub fn el_from_ws(node: &web_sys::Node) -> Option> { } Some(result) } - 3 => { - Some(El::new_text(&node.text_content().expect("Can't find text"))) - } + 3 => Some(El::new_text(&node.text_content().expect("Can't find text"))), _ => { crate::log("Unexpected node type found from raw html"); None