Auto merge of #20671 - cbrewster:history_url, r=asajeffrey

Make session history aware of URLs

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach build-geckolib` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20671)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-04-30 13:33:23 -04:00 committed by GitHub
commit 847115ba04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 192 additions and 56 deletions

View file

@ -12,8 +12,10 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::{Dom, DomRoot};
use dom::bindings::str::{DOMString, USVString};
use dom::bindings::structuredclone::StructuredCloneData;
use dom::event::Event;
use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::hashchangeevent::HashChangeEvent;
use dom::popstateevent::PopStateEvent;
use dom::window::Window;
use dom_struct::dom_struct;
@ -71,8 +73,22 @@ impl History {
Ok(())
}
// https://html.spec.whatwg.org/multipage/#history-traversal
// Steps 5-16
#[allow(unsafe_code)]
pub fn activate_state(&self, state_id: Option<HistoryStateId>) {
pub fn activate_state(&self, state_id: Option<HistoryStateId>, url: ServoUrl) {
// Steps 5
let document = self.window.Document();
let old_url = document.url().clone();
document.set_url(url.clone());
// Step 6
let hash_changed = old_url.fragment() != url.fragment();
// TODO: Step 8 - scroll restoration
// Step 11
let state_changed = state_id != self.state_id.get();
self.state_id.set(state_id);
let serialized_data = match state_id {
Some(state_id) => {
@ -98,8 +114,26 @@ impl History {
}
}
unsafe {
PopStateEvent::dispatch_jsval(self.window.upcast::<EventTarget>(), &*self.window, self.state.handle());
// TODO: Queue events on DOM Manipulation task source if non-blocking flag is set.
// Step 16.1
if state_changed {
PopStateEvent::dispatch_jsval(
self.window.upcast::<EventTarget>(),
&*self.window,
unsafe { self.state.handle() }
);
}
// Step 16.3
if hash_changed {
let event = HashChangeEvent::new(
&self.window,
atom!("hashchange"),
true,
false,
old_url.into_string(),
url.into_string());
event.upcast::<Event>().fire(self.window.upcast::<EventTarget>());
}
}
@ -175,7 +209,7 @@ impl History {
PushOrReplace::Push => {
let state_id = HistoryStateId::new();
self.state_id.set(Some(state_id));
let msg = ScriptMsg::PushHistoryState(state_id);
let msg = ScriptMsg::PushHistoryState(state_id, new_url.clone());
let _ = self.window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg);
state_id
},
@ -188,7 +222,7 @@ impl History {
state_id
},
};
let msg = ScriptMsg::ReplaceHistoryState(state_id);
let msg = ScriptMsg::ReplaceHistoryState(state_id, new_url.clone());
let _ = self.window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg);
state_id
},

View file

@ -1169,7 +1169,7 @@ impl ScriptThread {
Navigate(id, ..) => Some(id),
PostMessage(id, ..) => Some(id),
UpdatePipelineId(_, _, id, _) => Some(id),
UpdateHistoryStateId(id, ..) => Some(id),
UpdateHistoryState(id, ..) => Some(id),
RemoveHistoryStates(id, ..) => Some(id),
FocusIFrame(id, ..) => Some(id),
WebDriverScriptCommand(id, ..) => Some(id),
@ -1297,8 +1297,8 @@ impl ScriptThread {
browsing_context_id,
new_pipeline_id,
reason),
ConstellationControlMsg::UpdateHistoryStateId(pipeline_id, history_state_id) =>
self.handle_update_history_state_id_msg(pipeline_id, history_state_id),
ConstellationControlMsg::UpdateHistoryState(pipeline_id, history_state_id, url) =>
self.handle_update_history_state_msg(pipeline_id, history_state_id, url),
ConstellationControlMsg::RemoveHistoryStates(pipeline_id, history_states) =>
self.handle_remove_history_states(pipeline_id, history_states),
ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id) =>
@ -1679,10 +1679,14 @@ impl ScriptThread {
}
}
fn handle_update_history_state_id_msg(&self, pipeline_id: PipelineId, history_state_id: Option<HistoryStateId>) {
fn handle_update_history_state_msg(
&self, pipeline_id: PipelineId,
history_state_id: Option<HistoryStateId>,
url: ServoUrl,
) {
match { self.documents.borrow().find_window(pipeline_id) } {
None => return warn!("update history state after pipeline {} closed.", pipeline_id),
Some(window) => window.History().r().activate_state(history_state_id),
Some(window) => window.History().r().activate_state(history_state_id, url),
}
}