forked from nodejs/node
-
Notifications
You must be signed in to change notification settings - Fork 1
/
api.js
141 lines (116 loc) · 3.91 KB
/
api.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
'use strict';
{
function setupTheme() {
const kCustomPreference = 'customDarkTheme';
const userSettings = sessionStorage.getItem(kCustomPreference);
const themeToggleButton = document.getElementById('theme-toggle-btn');
if (userSettings === null && window.matchMedia) {
const mq = window.matchMedia('(prefers-color-scheme: dark)');
if ('onchange' in mq) {
function mqChangeListener(e) {
document.documentElement.classList.toggle('dark-mode', e.matches);
}
mq.addEventListener('change', mqChangeListener);
if (themeToggleButton) {
themeToggleButton.addEventListener('click', function() {
mq.removeEventListener('change', mqChangeListener);
}, { once: true });
}
}
if (mq.matches) {
document.documentElement.classList.add('dark-mode');
}
} else if (userSettings === 'true') {
document.documentElement.classList.add('dark-mode');
}
if (themeToggleButton) {
themeToggleButton.hidden = false;
themeToggleButton.addEventListener('click', function() {
sessionStorage.setItem(
kCustomPreference,
document.documentElement.classList.toggle('dark-mode')
);
});
}
}
function setupPickers() {
function closeAllPickers() {
for (const picker of pickers) {
picker.parentNode.classList.remove('expanded');
}
window.removeEventListener('click', closeAllPickers);
window.removeEventListener('keydown', onKeyDown);
}
function onKeyDown(e) {
if (e.key === 'Escape') {
closeAllPickers();
}
}
const pickers = document.querySelectorAll('.picker-header > a');
for (const picker of pickers) {
const parentNode = picker.parentNode;
picker.addEventListener('click', (e) => {
e.preventDefault();
/*
closeAllPickers as window event trigger already closed all the pickers,
if it already closed there is nothing else to do here
*/
if (parentNode.classList.contains('expanded')) {
return;
}
/*
In the next frame reopen the picker if needed and also setup events
to close pickers if needed.
*/
requestAnimationFrame(() => {
parentNode.classList.add('expanded');
window.addEventListener('click', closeAllPickers);
window.addEventListener('keydown', onKeyDown);
});
});
}
}
function setupStickyHeaders() {
const header = document.querySelector('.header');
let ignoreNextIntersection = false;
new IntersectionObserver(
([e]) => {
const currentStatus = header.classList.contains('is-pinned');
const newStatus = e.intersectionRatio < 1;
// Same status, do nothing
if (currentStatus === newStatus) {
return;
} else if (ignoreNextIntersection) {
ignoreNextIntersection = false;
return;
}
/*
To avoid flickering, ignore the next changes event that is triggered
as the visible elements in the header change once we pin it.
The timer is reset anyway after few milliseconds.
*/
ignoreNextIntersection = true;
setTimeout(() => {
ignoreNextIntersection = false;
}, 50);
header.classList.toggle('is-pinned', newStatus);
},
{ threshold: [1] }
).observe(header);
}
function bootstrap() {
// Check if we have JavaScript support
document.documentElement.classList.add('has-js');
// Restore user mode preferences
setupTheme();
// Handle pickers with click/taps rather than hovers
setupPickers();
// Track when the header is in sticky position
setupStickyHeaders();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bootstrap, { once: true });
} else {
bootstrap();
}
}