Skip to content

Commit cde2a3a

Browse files
authored
Merge pull request #1217 from Patternslib/navigate-event
Add polyfill for navigation API.
2 parents f1ae17b + b9c328f commit cde2a3a

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/core/polyfills.js

+41
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,44 @@
3838
true
3939
);
4040
})();
41+
42+
// Navigation polyfill for Firefox and Safari, as of 2024-01-04
43+
// NOTE: this is a very basic polyfill, it only supports firing a `navigate`
44+
// event on location change and even that without interception support, etc.
45+
!(function () {
46+
if (window.navigation == undefined) {
47+
48+
class NavigateEvent extends CustomEvent {
49+
constructor() {
50+
super("navigate");
51+
this.destination = { url: undefined };
52+
}
53+
}
54+
55+
// Create a navigation object on the window
56+
// We create a DOM element for the navigation object so that we can
57+
// attach events on it.
58+
window.navigation = document.createElement("div");
59+
60+
const create_event = (args) => {
61+
const event = new NavigateEvent();
62+
event.destination.url = args[2];
63+
return event;
64+
};
65+
66+
// Patch pushState to trigger an `navigate` event on the navigation
67+
// object when the URL changes.
68+
const pushState = window.history.pushState;
69+
window.history.pushState = function () {
70+
pushState.apply(window.history, arguments);
71+
window.navigation.dispatchEvent(create_event(arguments));
72+
};
73+
74+
// Same with replaceState
75+
const replaceState = window.history.replaceState;
76+
window.history.replaceState = function () {
77+
replaceState.apply(window.history, arguments);
78+
window.navigation.dispatchEvent(create_event(arguments));
79+
};
80+
}
81+
})();

src/core/polyfills.test.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import "./polyfills";
2+
3+
describe("NavigateEvent tests", () => {
4+
afterEach(() => {
5+
document.body.innerHTML = "";
6+
});
7+
8+
it("should fire an event when history.pushState is called.", () => {
9+
let destination_url;
10+
11+
window.navigation.addEventListener("navigate", (event) => {
12+
destination_url = event.destination.url;
13+
});
14+
15+
const path = "foo/bar/baz.html";
16+
history.pushState(null, "", path);
17+
18+
expect(destination_url).toBe(path);
19+
});
20+
21+
22+
it("should fire an event when history.replaceState is called.", () => {
23+
let destination_url;
24+
25+
window.navigation.addEventListener("navigate", (event) => {
26+
destination_url = event.destination.url;
27+
});
28+
29+
const path = "foo/bar/baz.html";
30+
history.replaceState(null, "", path);
31+
32+
expect(destination_url).toBe(path);
33+
});
34+
});

0 commit comments

Comments
 (0)