-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Copy pathurl-listeners.js
113 lines (99 loc) · 2.92 KB
/
url-listeners.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { dispatch, listen } from 'codesandbox-api';
const origHistoryProto = window.history.__proto__; // eslint-disable-line no-proto
const historyList = [];
let historyPosition = -1;
let disableNextHashChange = false;
function sendUrlChange(url) {
dispatch({
type: 'urlchange',
url,
back: historyPosition > 0,
forward: historyPosition < historyList.length - 1,
});
}
function pushHistory(url, state) {
// remove "future" locations
historyList.splice(historyPosition + 1);
historyList.push({ url, state });
historyPosition = historyList.length - 1;
}
function pathWithHash(location) {
return `${location.pathname}${location.hash}`;
}
export default function setupHistoryListeners() {
function handleMessage(data, source) {
if (source) {
if (data.type === 'urlback') {
history.back();
} else if (data.type === 'urlforward') {
history.forward();
} else if (data.type === 'refresh') {
document.location.reload();
}
}
}
Object.assign(window.history, {
go(delta) {
const newPos = historyPosition + delta;
if (newPos >= 0 && newPos <= historyList.length - 1) {
historyPosition = newPos;
const { url, state } = historyList[historyPosition];
const oldURL = document.location.href;
origHistoryProto.replaceState.call(window.history, state, '', url);
const newURL = document.location.href;
sendUrlChange(newURL);
window.dispatchEvent(new PopStateEvent('popstate', { state }));
if (newURL.indexOf('#') !== -1) {
disableNextHashChange = true;
window.dispatchEvent(
new HashChangeEvent('hashchange', { oldURL, newURL })
);
}
}
},
back() {
window.history.go(-1);
},
forward() {
window.history.go(1);
},
pushState(state, title, url) {
origHistoryProto.replaceState.call(window.history, state, title, url);
pushHistory(url, state);
sendUrlChange(document.location.href);
},
replaceState(state, title, url) {
origHistoryProto.replaceState.call(window.history, state, title, url);
historyList[historyPosition] = { state, url };
sendUrlChange(document.location.href);
},
});
Object.defineProperties(window.history, {
length: {
get() {
return historyList.length;
},
configurable: true,
},
state: {
get() {
return historyList[historyPosition].state;
},
configurable: true,
},
});
window.addEventListener('hashchange', () => {
if (!disableNextHashChange) {
const url = pathWithHash(document.location);
pushHistory(url, null);
sendUrlChange(document.location.href);
} else {
disableNextHashChange = false;
}
});
pushHistory(pathWithHash(document.location), null);
setTimeout(() => {
sendUrlChange(document.location.href);
});
return listen(handleMessage);
}