stdweb/webapi/events/
history.rs

1use webcore::value::{Reference, Value};
2use webcore::try_from::TryInto;
3use 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))]
16pub struct HashChangeEvent( Reference );
17
18impl IEvent for HashChangeEvent {}
19
20impl 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]
26    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]
37    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))]
65pub struct PopStateEvent(Reference);
66
67impl 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]
78    pub fn state(&self) -> Value {
79        js!(return @{self}.state;)
80    }
81}
82
83impl IEvent for PopStateEvent {}
84
85#[cfg(all(test, feature = "web_test"))]
86mod tests {
87    use super::*;
88    use webapi::event::ConcreteEvent;
89
90    #[test]
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]
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}