Skip to content

Commit b6e8fc1

Browse files
committed
Flawed implementation. History manager file
1 parent 01dda29 commit b6e8fc1

1 file changed

Lines changed: 160 additions & 0 deletions

File tree

src/client/History.ts

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// // Subscribing can be enabled if we want reactivity
2+
// export type Subscriber<HistoryState> = (stack: ReadonlyArray<HistoryState>, pointer: number) => void;
3+
//
4+
5+
export type HistoryState = { hash: string, index: number, view?: string }
6+
7+
class HistoryManager {
8+
private stack: HistoryState[] = [];
9+
// When pointer = -1, unset pointer; When pointer = -2, don't handle hashes
10+
private pointer = -1;
11+
// private subscribers = new Set<Subscriber<HistoryState>>();
12+
13+
constructor() {
14+
console.debug("HistoryManager: ", this);
15+
}
16+
17+
// on navigation to a new page
18+
push(state: HistoryState) {
19+
if (this.pointer < this.stack.length - 1) {
20+
this.stack.length = this.pointer + 1; // Replace branch
21+
}
22+
this.pointer = this.stack.length;
23+
state.index = this.pointer;
24+
25+
this.stack.push(state);
26+
this.APIpush();
27+
// this.notify();
28+
}
29+
30+
replace(state: HistoryState) {
31+
state.index = this.pointer;
32+
if (this.pointer >= 0) {
33+
this.stack[this.pointer] = state;
34+
} else {
35+
this.push(state);
36+
}
37+
38+
this.APIreplace();
39+
// this.notify();
40+
}
41+
42+
back(): HistoryState | undefined {
43+
if (this.pointer > 0) {
44+
this.pointer--;
45+
// this.notify();
46+
this.APIreplace();
47+
return this.current;
48+
}
49+
return undefined;
50+
}
51+
52+
forward(): HistoryState | undefined {
53+
if (this.pointer < this.stack.length - 1) {
54+
this.pointer++;
55+
// this.notify();
56+
this.APIreplace();
57+
return this.current;
58+
}
59+
return undefined;
60+
}
61+
62+
goto(idx: number): HistoryState | undefined {
63+
if (idx < 0 || idx >= this.stack.length) {
64+
return undefined;
65+
}
66+
67+
this.pointer = idx;
68+
this.APIreplace(); // Make sure to handle our final detination
69+
70+
71+
72+
let recreatePointer = this.pointer;
73+
// Don't handle hashes while recreating and navigating history
74+
this.pointer = -2;
75+
76+
// Recreate lost history
77+
for (; recreatePointer + 1 < this.length - 1; recreatePointer--) {
78+
this.APIpush(this.stack[recreatePointer]);
79+
}
80+
// Navigate
81+
for (let i = this.length - 1; i > idx; i--) {
82+
history.back();
83+
}
84+
for (let i = 0; i < idx; i++) {
85+
history.forward();
86+
}
87+
88+
this.pointer = idx;
89+
// this.notify();
90+
return this.current;
91+
}
92+
93+
get current(): HistoryState | undefined {
94+
return this.stack[this.pointer] ?? { hash: "", index: 0 };
95+
}
96+
97+
// read-only copy of the stack
98+
toArray(): ReadonlyArray<HistoryState> {
99+
return this.stack.slice();
100+
}
101+
102+
get length(): number {
103+
return this.stack.length;
104+
}
105+
106+
get index(): number {
107+
return this.pointer;
108+
}
109+
110+
clear() {
111+
this.stack = [];
112+
this.pointer = -1;
113+
// this.notify();
114+
}
115+
116+
private APIpush(state: HistoryState = this.current!): void {
117+
const view = state.view ?? state.hash;
118+
history.pushState(state, "", new URL(view, location.href));
119+
}
120+
121+
private APIreplace(state: HistoryState = this.current!): void {
122+
const view = state.view ?? state.hash;
123+
history.replaceState(state, "", new URL(view, location.href));
124+
}
125+
126+
127+
128+
// // subscribe to changes; returns an unsubscribe function
129+
// subscribe(fn: Subscriber<HistoryState>): () => void {
130+
// this.subscribers.add(fn);
131+
// // call immediately with snapshot
132+
// fn(this.toArray(), this.pointer);
133+
// return () => {
134+
// this.subscribers.delete(fn);
135+
// };
136+
//
137+
138+
// private notify() {
139+
// const ROstack = this.toArray();
140+
// const idx = this.pointer;
141+
// for (const subscriber of Array.from(this.subscribers)) {
142+
// try {
143+
// subscriber(ROstack, idx);
144+
// } catch (error) {
145+
// console.error(`History subscriber encountered error: ${error}`);
146+
// }
147+
// }
148+
// }
149+
150+
}
151+
152+
declare global {
153+
interface Window { __historyManager__?: HistoryManager }
154+
}
155+
156+
157+
158+
window.__historyManager__ = new HistoryManager();
159+
export const historyManager = window.__historyManager__;
160+
export default historyManager;

0 commit comments

Comments
 (0)