-
-
Notifications
You must be signed in to change notification settings - Fork 25
/
error-handler.ts
105 lines (90 loc) · 2.75 KB
/
error-handler.ts
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
import {get, purgeFromStorage, set} from '../../state';
import {startPassage} from '../../story';
import {CustomElement} from '../../util/custom-element';
import './error-handler.css';
/**
* When an uncaught error occurs, this custom element replaces its content with
* an error message allowing the user to try to remedy the situation. It's
* available as `<error-handler>`.
*/
export class ErrorHandler extends CustomElement {
constructor() {
super();
this.delegate('click', '[data-back]', () => {
const trail = get('trail');
this.classList.remove('active');
if (Array.isArray(trail)) {
set('trail', trail.slice(0, trail.length - 1));
} else {
window.alert(
'Sorry, going back was not successful. Please try hard restarting.'
);
}
});
this.delegate('click', '[data-refresh]', () => {
const trail = get('trail');
this.classList.remove('active');
if (Array.isArray(trail)) {
set('trail', [...trail]);
} else {
set('trail', [startPassage()?.name]);
}
});
this.delegate('click', '[data-hard-restart]', () => {
purgeFromStorage(true);
window.location.reload();
});
}
connectedCallback() {
window.addEventListener('error', this);
window.addEventListener('unhandledrejection', this);
}
disconnectedCallback() {
window.removeEventListener('error', this);
window.removeEventListener('unhandledrejection', this);
}
handleEvent(event: ErrorEvent | PromiseRejectionEvent) {
// Marked will blame itself if rendering has problems, but it probably is our
// fault, so remove that pointer.
const markedError =
'\nPlease report this to https://github.com/markedjs/marked.';
const error =
event.type === 'unhandledrejection'
? (event as PromiseRejectionEvent).reason
: (event as ErrorEvent).error;
try {
let detail = '';
if (error?.stack) {
detail = `${error.message}\n\nStack trace:\n${error.stack}`;
} else {
detail = `${error.message}\n\n[No stack trace available]`;
}
detail = detail.replace(markedError, '');
const trail = get('trail');
this.classList.add('active');
/* eslint-disable indent */
this.innerHTML = `
<p>
An unexpected error has occurred.
</p>
<pre>${get('config.testing') ? detail : ''}</pre>
<ul>
<li>
<inline-button class="link" ${
Array.isArray(trail) && trail.length > 1
? 'data-back'
: 'data-refresh'
}>Go back</inline-button> to the previous passage.
</li>
<li>
<inline-button class="link" data-hard-restart>Hard restart</inline-button>, clearing all progress and beginning from the start.
</li>
</ul>
`;
} catch (error) {
// Things have gotten really screwy--at least log the error.
// eslint-disable-next-line no-console
console.error(error);
}
}
}