1 use webcore::value::{Reference, Value};
2 use webcore::try_from::TryInto;
3 use webapi::event::{IEvent, Event};
4 
5 /// The `HashChangeEvent` is fired when the fragment
6 /// identifier of the URL has changed (the part of the URL
7 /// that follows the # symbol, including the # symbol).
8 ///
9 /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/hashchange)
10 // https://html.spec.whatwg.org/#event-hashchange
11 // https://html.spec.whatwg.org/#hashchangeevent
12 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
13 #[reference(instance_of = "HashChangeEvent")]
14 #[reference(event = "hashchange")]
15 #[reference(subclass_of(Event))]
16 pub struct HashChangeEvent( Reference );
17 
18 impl IEvent for HashChangeEvent {}
19 
20 impl HashChangeEvent {
21     /// The previous URL from which the window was navigated.
22     ///
23     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HashChangeEvent)
24     // https://html.spec.whatwg.org/#the-hashchangeevent-interface:dom-hashchangeevent-oldurl
25     #[inline]
old_url( &self ) -> String26     pub fn old_url( &self ) -> String {
27         js!(
28             return @{self.as_ref()}.oldURL;
29         ).try_into().unwrap()
30     }
31 
32     /// The new URL to which the window was navigated.
33     ///
34     /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HashChangeEvent)
35     // https://html.spec.whatwg.org/#the-hashchangeevent-interface:dom-hashchangeevent-newurl
36     #[inline]
new_url( &self ) -> String37     pub fn new_url( &self ) -> String {
38         js!(
39             return @{self.as_ref()}.newURL;
40         ).try_into().unwrap()
41     }
42 }
43 
44 /// A `PopStateEvent` is dispatched to the window every time the active history entry changes
45 /// between two history entries for the same document. If the history entry being activated was
46 /// created by a call to `history.push_state()` or was affected by a call to
47 /// `history.replace_state()`, the `PopStateEvent`'s state property contains a copy of the history
48 /// entry's state object.
49 ///
50 /// Note that just calling `history.push_state()` or `history.replace_state()` won't trigger a
51 /// `PopStateEvent`. The `PopStateEvent` is only triggered by doing a browser action such as a
52 /// clicking on the back button (or calling `history.back()`). And the event is only
53 /// triggered when the user navigates between two history entries for the same document.
54 ///
55 /// Browsers tend to handle the `PopStateEvent` differently on page load. Chrome and Safari always
56 /// emit a `PopStateEvent` on page load, but Firefox doesn't.
57 ///
58 /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/PopStateEvent)
59 // https://html.spec.whatwg.org/#event-popstate
60 // https://html.spec.whatwg.org/#popstateevent
61 #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
62 #[reference(instance_of = "Event")]
63 #[reference(event = "popstate")]
64 #[reference(subclass_of(Event))]
65 pub struct PopStateEvent(Reference);
66 
67 impl PopStateEvent {
68     /// The state object associated to the new history entry, if that entry was created with
69     /// push_state or affected by replace_state.
70     ///
71     /// Example usage:
72     ///
73     /// ```rust,ignore
74     /// let state: Option<MyStruct> = event.state().try_into().ok();
75     /// ```
76     // https://html.spec.whatwg.org/#dom-popstateevent-state
77     #[inline]
state(&self) -> Value78     pub fn state(&self) -> Value {
79         js!(return @{self}.state;)
80     }
81 }
82 
83 impl IEvent for PopStateEvent {}
84 
85 #[cfg(all(test, feature = "web_test"))]
86 mod tests {
87     use super::*;
88     use webapi::event::ConcreteEvent;
89 
90     #[test]
test_hash_change_event()91     fn test_hash_change_event() {
92         let event: HashChangeEvent = js!(
93             return new HashChangeEvent(
94                 @{HashChangeEvent::EVENT_TYPE},
95                 {
96                     oldURL: "http://test.com#foo",
97                     newURL: "http://test.com#bar"
98                 }
99             );
100         ).try_into().unwrap();
101         assert_eq!( event.event_type(), HashChangeEvent::EVENT_TYPE );
102         assert_eq!( event.old_url(), "http://test.com#foo" );
103         assert_eq!( event.new_url(), "http://test.com#bar" );
104     }
105 
106     #[test]
test_pop_state_event()107     fn test_pop_state_event() {
108         let event: PopStateEvent = js!(
109             return new PopStateEvent(
110                 @{PopStateEvent::EVENT_TYPE},
111                 {
112                     state: {
113                         color: "tomato"
114                     }
115                 }
116             );
117         ).try_into().unwrap();
118 
119         assert_eq!(event.event_type(), PopStateEvent::EVENT_TYPE);
120 
121         let state_value: Value = event.state();
122         let state: std::collections::BTreeMap<String, Value> = state_value
123             .as_object()
124             .unwrap()
125             .into();
126         let mut expected = std::collections::BTreeMap::new();
127         expected.insert("color".to_string(), "tomato".into());
128 
129         assert_eq!(state, expected);
130     }
131 }
132