Skip to content

Commit b9c328f

Browse files
committed
feat(core polyfills): Add polyfill for navigation API.
This polyfill adds support for the "navigate" event on the navigation object. We path "history.pushState" and "history.replaceState" to send the "navigate" event on the "window.navigation" object when the URL changes. This polyfill is for current Firefox and Safari. Chrome based browsers already support this. More information on: https://developer.mozilla.org/en-US/docs/Web/API/Navigation/navigate_event
1 parent f1ae17b commit b9c328f

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)