1
2pub use url::Url;
3
4use yew::html::{Component, Env};
5use stdweb::Value;
6use stdweb::web::{self, IEventTarget};
7
8pub struct RouterTask<CTX: 'static, COMP: Component<CTX>> {
11 _handle1: web::EventListenerHandle,
12 handle2: Value,
13 history: web::History,
14 route_fn: &'static Fn(RouteInfo) -> COMP::Message,
15 window: web::Window,
16}
17
18#[derive(Debug, Clone)]
20pub struct RouteInfo {
21 pub url: Url,
23 pub state: Value,
25}
26
27impl RouteInfo {
28 fn new(url: Url, state: Value) -> RouteInfo {
30 RouteInfo {
31 url: url,
32 state: state,
33 }
34 }
35}
36
37fn current_url(window: &web::Window) -> Url {
38 let location = expect!(window.location(), "could not get location");
40 let href = expect!(location.href(), "could not get href");
41 expect!(Url::parse(&href), "location.href did not parse")
42}
43
44impl<'a, CTX: 'a, COMP: Component<CTX>> RouterTask<CTX, COMP> {
45 pub fn new(
51 env: &mut Env<'a, CTX, COMP>,
52 route_fn: &'static Fn(RouteInfo) -> COMP::Message,
53 ) -> Self
54 {
55 let window = web::window();
56 let callback = env.send_back(route_fn);
57
58 let callback1 = callback.clone();
59 let callback2 = callback;
60
61 let cl_window = window.clone();
62 let handle1 = window
63 .add_event_listener(move |event: web::event::PopStateEvent| {
64 callback1.emit(RouteInfo::new(current_url(&cl_window), event.state()));
65 });
66
67 let cl_window = window.clone();
74 let rs_handle = move || {
75 callback2.emit(RouteInfo::new(current_url(&cl_window), Value::Null));
76 };
77
78 let handle2 = js!{
79 var callback = @{rs_handle};
80 function listener() {
81 callback();
82 }
83 window.addEventListener("load", listener);
84 return {
85 callback: callback,
86 listener: listener
87 };
88 };
89
90 RouterTask {
91 _handle1: handle1,
92 handle2: handle2,
93 route_fn: route_fn,
94 history: window.history(),
95 window: window,
96 }
97 }
98
99 pub fn current_url(&self) -> Url {
101 current_url(&self.window)
102 }
103
104 pub fn push_state(&self, state: Value, title: &str, url: Url) -> COMP::Message {
109 self.history.push_state(state.clone(), title, Some(url.as_str()));
110 let info = RouteInfo {
111 url: url,
112 state: state,
113 };
114 (*self.route_fn)(info)
115 }
116
117 pub fn push_hash(&self, hash: Option<&str>) -> COMP::Message {
119 let mut url = current_url(&self.window);
120 url.set_fragment(hash);
121 self.push_state(Value::Null, "", url)
122 }
123}
124
125impl<CTX, COMP: Component<CTX>> Drop for RouterTask<CTX, COMP> {
126 fn drop(&mut self) {
127 js! { @(no_return)
128 var handle = @{&self.handle2};
129 window.removeEventListener("load", handle.listener);
130 handle.callback.drop();
131 }
132 }
133}
134