Skip to content

Commit

Permalink
Improved documentation of util crate. Moved history() into it. Misc c…
Browse files Browse the repository at this point in the history
…leanup
  • Loading branch information
David-OConnor committed Apr 7, 2019
1 parent 278b77a commit 5476109
Show file tree
Hide file tree
Showing 14 changed files with 56 additions and 123 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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'] }
Expand Down
4 changes: 2 additions & 2 deletions examples/counter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 1 addition & 1 deletion examples/server_integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
File renamed without changes.
4 changes: 2 additions & 2 deletions examples/todomvc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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'] }
6 changes: 4 additions & 2 deletions examples/todomvc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ fn view(model: &Model) -> Vec<El<Msg>> {
ul![class!["todo-list"], todo_els]
]
} else {
seed::empty()
// seed::empty()
span![]
};

vec![
Expand All @@ -334,7 +335,8 @@ fn view(model: &Model) -> Vec<El<Msg>> {
if model.active_count() > 0 || model.completed_count() > 0 {
footer(&model)
} else {
seed::empty()
// seed::empty()
span![]
},
]
}
Expand Down
4 changes: 2 additions & 2 deletions src/dom_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub fn input_ev<Ms, T: ToString>(
) -> Listener<Ms> {
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())
};
Expand Down Expand Up @@ -295,7 +295,7 @@ impl<Ms> Listener<Ms> {
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);
}
}
Expand Down
8 changes: 3 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -48,8 +48,7 @@ pub fn empty<Ms>() -> dom_types::El<Ms> {
/// * [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval)
pub fn set_interval(handler: Box<Fn()>, timeout: i32) {
let callback = Closure::wrap(handler as Box<dyn Fn()>);
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,
Expand All @@ -65,8 +64,7 @@ pub fn set_interval(handler: Box<Fn()>, timeout: i32) {
/// * [MDN docs](https://developer.mozilla.org/en-US/docs/Wemb/API/WindowOrWorkerGlobalScope/setTimeout)
pub fn set_timeout(handler: Box<Fn()>, timeout: i32) {
let callback = Closure::wrap(handler as Box<dyn Fn()>);
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,
Expand Down
12 changes: 8 additions & 4 deletions src/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down Expand Up @@ -198,9 +204,7 @@ pub fn push_route<U: Into<Url>>(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");
}
Expand Down
17 changes: 12 additions & 5 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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::<web_sys::HtmlInputElement>() {
return input.value();
}
Expand All @@ -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::<web_sys::HtmlInputElement>() {
input.set_value(value);
Expand All @@ -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<S: ToString>(text: S) {
// ignore clippy about &S
Expand Down
91 changes: 11 additions & 80 deletions src/vdom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -137,52 +136,8 @@ impl<Ms> Update<Ms> {
}
}

//
//trait ViewReturn2<T, Ms> {
// fn convert(r: T) -> Vec<El<Ms>>;
//}
//
//impl<T, Ms> ViewReturn2<T, Ms> for El<Ms> {
// fn convert(el: El<Ms>) -> Vec<El<Ms>> {
// vec![el]
// }
//}
//
//impl<T, Ms> ViewReturn2<T, Ms> for Vec<El<Ms>> {
// fn convert(els: Vec<El<Ms>>) -> Vec<El<Ms>> {
// els
// }
//}
//
///// Thin wrapper; impl From for Vec<El<Ms>> appears not to work directly.
//struct ViewReturn<Ms: 'static> {
// els: Vec<El<Ms>>
//}
//


//pub struct View<Ms: 'static> {
// els: Either<El<Ms>, Vec<El<Ms>>>
//}
//
//impl<Ms> From<El<Ms>> for View<Ms> {
// fn from(el: El<Ms>) -> Self {
// Self { els: Left(el) }
// }
//}
//
//impl<Ms> From<Vec<El<Ms>>> for View<Ms> {
// fn from(els: Vec<El<Ms>>) -> Self {
// Self { els: Right(els) }
// }
//}


type UpdateFn<Ms, Mdl> = fn(Ms, &mut Mdl) -> Update<Ms>;
//type ViewFn<Ms, Mdl> = Either<fn(&Mdl) -> El<Ms>, fn(&Mdl) -> Vec<El<Ms>>>;
type ViewFn<Ms, Mdl> = fn(&Mdl) -> Vec<El<Ms>>;
//type ViewFn<Ms, Mdl> = fn(&Mdl) -> Into<ViewReturn<Ms>>;
//type ViewFn<T, Ms, Mdl> = fn(&Mdl) -> ViewReturn2<Ms>;
type RoutesFn<Ms> = fn(&routing::Url) -> Ms;
type WindowEvents<Ms, Mdl> = fn(&Mdl) -> Vec<dom_types::Listener<Ms>>;
type MsgListeners<Ms> = Vec<Box<Fn(&Ms)>>;
Expand Down Expand Up @@ -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<Ms: Clone + 'static, Mdl: 'static> {
model: Mdl,
Expand Down Expand Up @@ -379,7 +335,7 @@ impl<Ms: Clone, Mdl> App<Ms, Mdl> {
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
Expand All @@ -404,8 +360,11 @@ impl<Ms: Clone, Mdl> App<Ms, Mdl> {

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));

Expand Down Expand Up @@ -478,9 +437,11 @@ impl<Ms: Clone, Mdl> App<Ms, Mdl> {
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
Expand All @@ -497,6 +458,7 @@ impl<Ms: Clone, Mdl> App<Ms, Mdl> {
old_vdom,
&mut topel_new_vdom,
&self.cfg.mount_point,
// &self.cfg.document,
None,
&self.mailbox(),
&self.clone(),
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(_) => {
Expand Down
23 changes: 7 additions & 16 deletions src/websys_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,26 +254,19 @@ pub fn patch_el_details<Ms: Clone>(old: &mut El<Ms>, new: &mut El<Ms>, 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::<web_sys::HtmlInputElement>() {
input.set_value(&new_val);
}
if let Some(input) = old_el_ws.dyn_ref::<web_sys::HtmlTextAreaElement>() {
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::<web_sys::Element>() {
Some(el) => el
Expand Down Expand Up @@ -398,9 +391,7 @@ pub fn el_from_ws<Ms>(node: &web_sys::Node) -> Option<El<Ms>> {
}
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
Expand Down

0 comments on commit 5476109

Please # to comment.