/
history.js
100 lines (81 loc) · 1.82 KB
/
history.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
const deepEqual = require('deep-equal');
module.exports = function history() {
let historyData = [];
let currentPosition = null;
const listeners = [];
function current() {
if (!historyData.length) {
return null;
}
return historyData[currentPosition];
}
function notifyListeners() {
listeners.slice().forEach((listener) => {
listener();
});
}
function cut() {
if (currentPosition !== null) {
historyData = historyData.slice(0, currentPosition + 1);
}
}
function push(item) {
if (deepEqual(item, current())) {
return current();
}
cut();
historyData.push(item);
if (currentPosition === null) {
currentPosition = 0;
} else {
currentPosition += 1;
}
process.nextTick(notifyListeners);
return current();
}
function canGoBack(steps = 1) {
return currentPosition - steps >= 0;
}
function canGoForward(steps = 1) {
return currentPosition + steps <= historyData.length - 1;
}
function back(steps = 1) {
if (canGoBack(steps)) {
currentPosition -= steps;
} else {
currentPosition = 0;
}
process.nextTick(notifyListeners);
return current();
}
function forward(steps = 1) {
if (canGoForward(steps)) {
currentPosition += steps;
} else {
currentPosition = historyData.length - 1;
}
process.nextTick(notifyListeners);
return current();
}
function subscribe(listener) {
listeners.push(listener);
let isSubscribed = true;
return function unsubscribe() {
if (!isSubscribed) {
return;
}
isSubscribed = false;
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
}
return {
push,
canGoBack,
canGoForward,
back,
forward,
current,
subscribe,
};
};