-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfunction.js
148 lines (125 loc) · 4.65 KB
/
function.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
142
143
144
145
146
147
148
/* (C) Copyright 2019-2024 Robert Grimm
Licensed under the MIT License (https://opensource.org/licenses/MIT) */
const DEBUG = Boolean(
document.documentElement.classList.contains('debug')
|| document.body.classList.contains('debug')
);
if (DEBUG) console.log(`☑️ Preparing dynamic page enhancements.`);
// -----------------------------------------------------------------------------
function createFooterWithReferences() {
// >>> (1) Read from DOM: Check footer, determine options, extract links.
const article = document.querySelector('main > article');
if (!article || article.querySelector('footer.references')) {
if (DEBUG) console.log(`☑️ No need for (re)creating printed references.`);
return;
}
let options = {};
const { url } = import.meta;
const { pathname } = new URL(url);
const { scripts } = document;
for (let index = 0; index < scripts.length; index++) {
const script = scripts[index];
const { src } = script;
if (src === url || src === pathname) {
options = script.dataset;
break;
}
}
const hyperlinks = article.querySelectorAll('a[href]');
// >>> (2) Prepare changes to DOM: Create footer with references.
const footer = document.createElement('footer');
footer.className = 'references';
const h2 = document.createElement('h2');
if (options.referenceFooterClass) h2.className = options.referenceFooterClass;
h2.innerText = 'References';
footer.appendChild(h2);
const ol = document.createElement('ol');
ol.className = 'counted';
footer.appendChild(ol);
let count = 0;
for (const { href } of hyperlinks) {
if (!href.startsWith('https://apparebit.com/')) {
const link = document.createElement('a');
link.href = href;
link.innerText = href;
const li = document.createElement('li');
li.appendChild(link);
ol.appendChild(li);
count++;
}
}
// >>> (3) Write to DOM: Add newly created footer to article.
article.appendChild(footer);
if (DEBUG) {
const total = hyperlinks.length;
console.log(`✅ Created footer with ${count}/${total} references.`);
}
}
// -----------------------------------------------------------------------------
function updateThemeColor() {
// Extract <meta name="theme-color"> elements with data-fallback attribute.
// There might be two, one for light mode and one for dark mode.
const themes = []
for (const element of document.querySelectorAll('meta[name=theme-color]')) {
if (element.dataset.fallback) {
const visible = element.content;
const invisible = element.dataset.fallback;
themes.push({ element, visible, invisible })
}
}
if (themes.length === 0) {
if (DEBUG) console.log(`☑️ No <meta name=theme-color> with fallback.`);
return;
}
// Extract element whose visibility will control theme color.
let header = document.querySelector('.cover img');
if (!header) header = document.querySelector('.page-header');
if (!header) {
if (DEBUG) console.error(`❌ No header element to control theme color switching!`);
return;
}
// Set up intersection observer to update <meta content> attribute. Update
// *all*, so that we don't need to monitor light/dark mode changes, too.
const updateThemes = isVisible => {
if (DEBUG) {
console.log(`❇️ Activating ${isVisible ? 'above' : 'below'} fold theme colors.`);
}
for (const theme of themes) {
theme.element.content = isVisible ? theme.visible : theme.invisible;
}
};
const observer = new IntersectionObserver(entries => {
for (const entry of entries) {
updateThemes(entry.isIntersecting);
}
});
observer.observe(header);
// Et voila!
if (DEBUG) {
const elements = `${themes.length} theme${themes.length === 1 ? '' : 's'}`;
console.log(`✅ Enabled color switching for ${elements}.`);
}
}
// -----------------------------------------------------------------------------
function setup() {
if (DEBUG) {
console.log(`☑️ Configuring dynamic page enhancements after content loaded.`);
}
// Safari doesn't support beforeprint event, so media query serves as fallback.
// https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeprint
if (document.body.classList.contains('print-references')) {
if (DEBUG) console.log(`☑️ Page requests printed references.`);
window.addEventListener('beforeprint', createFooterWithReferences);
window.matchMedia('print').addListener(event => {
if (event.matches) {
createFooterWithReferences();
}
});
}
updateThemeColor();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', setup);
} else {
setup();
}