-
Notifications
You must be signed in to change notification settings - Fork 478
Expand file tree
/
Copy pathhistory.js
More file actions
115 lines (95 loc) · 3.14 KB
/
history.js
File metadata and controls
115 lines (95 loc) · 3.14 KB
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
114
115
import { uuid } from "../../util"
export class History {
location
restorationIdentifier = uuid()
restorationData = {}
started = false
currentIndex = 0
constructor(delegate) {
this.delegate = delegate
}
start() {
if (!this.started) {
addEventListener("popstate", this.onPopState, false)
this.currentIndex = history.state?.turbo?.restorationIndex || 0
this.started = true
this.replace(new URL(window.location.href))
}
}
stop() {
if (this.started) {
removeEventListener("popstate", this.onPopState, false)
this.started = false
}
}
push(location, restorationIdentifier) {
this.update(history.pushState, location, restorationIdentifier)
}
replace(location, restorationIdentifier) {
this.update(history.replaceState, location, restorationIdentifier)
}
update(method, location, restorationIdentifier = uuid()) {
if (method === history.pushState) ++this.currentIndex
const state = { turbo: { restorationIdentifier, restorationIndex: this.currentIndex } }
method.call(history, state, "", location.href)
this.location = location
this.restorationIdentifier = restorationIdentifier
}
// Restoration data
getRestorationDataForIdentifier(restorationIdentifier) {
return this.restorationData[restorationIdentifier] || {}
}
updateRestorationData(additionalData) {
const { restorationIdentifier } = this
const restorationData = this.restorationData[restorationIdentifier]
this.restorationData[restorationIdentifier] = {
...restorationData,
...additionalData
}
}
// Scroll restoration
assumeControlOfScrollRestoration() {
if (!this.previousScrollRestoration) {
this.previousScrollRestoration = history.scrollRestoration ?? "auto"
history.scrollRestoration = "manual"
}
}
relinquishControlOfScrollRestoration() {
if (this.previousScrollRestoration) {
history.scrollRestoration = this.previousScrollRestoration
delete this.previousScrollRestoration
}
}
// Event handlers
onPopState = (event) => {
const newLocation = new URL(window.location.href)
// Ignore popstate events triggered by hash-only changes not managed by Turbo
if (!event.state?.turbo && this.location && this.#onlyHashChanged(newLocation)) {
this.location = newLocation
return
}
const { turbo } = event.state || {}
this.location = newLocation
if (turbo) {
const { restorationIdentifier, restorationIndex } = turbo
this.restorationIdentifier = restorationIdentifier
const direction = restorationIndex > this.currentIndex ? "forward" : "back"
this.delegate.historyPoppedToLocationWithRestorationIdentifierAndDirection(
this.location,
restorationIdentifier,
direction
)
this.currentIndex = restorationIndex
} else {
this.currentIndex++
this.delegate.historyPoppedWithEmptyState(this.location)
}
}
#onlyHashChanged(newLocation) {
return (
this.location.origin === newLocation.origin &&
this.location.pathname === newLocation.pathname &&
this.location.search === newLocation.search
)
}
}