-
Notifications
You must be signed in to change notification settings - Fork 1
/
kosherify.js
95 lines (83 loc) · 3.01 KB
/
kosherify.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
let conversion = {
"Advent calendar": "Shul Calendar",
"Advent": "Shul Calendar",
"Christmas": "Chanuka",
"December": "Kislev",
"Easter Bunny": "Magic Matzo Ball",
"Easter": "Pesach",
"North Pole": "Shtetl",
"Santa": "The Rebbe",
"an elf": "a Chossid",
"elf": "chossid",
"elves'": "chassidim's",
"elves": "chassidim",
"elvish": "chassidish",
"reindeer": "Moshiach's donkey", // Unfortunately we can't distinguish singular and plural
"sleigh": "wagon",
"bells": "accordions",
"bell": "accordion",
"stars": "Chanuka candles",
"star": "Chanuka candle",
"magic": "kabbalah",
"magical": "kabbalistic",
"magician": "kabbalist"
}
// Optimisations so we don't do this every time the function is called
conversion = Object.entries(conversion).map(([from, to]) => [new RegExp(`\\b${from}${/\w$/.test(from) ? '\\b' : ''}`, 'ig'), to]);
// Add stars as a special case, not requiring word boundaries
conversion.push(['*', '🕯']);
// Store all the replacements we've done, so we can toggle
/**
* @type {{node: Text, orig: string, changed: string}[]}
*/
const replacements = [];
function processNode(/**@type{Node}*/ node) {
if (node instanceof Text) {
const orig = node.textContent,
changed = fix(node.textContent);
if (changed !== orig)
replacements.push({node, orig, changed});
}
else if (node instanceof HTMLElement && node.tagName === 'CODE')
return;
else if (node instanceof HTMLElement && node.classList.contains('calendar'))
// Only replace the stars at the end
node.querySelectorAll('.calendar-mark-complete,.calendar-mark-verycomplete').forEach(processNode);
else
node.childNodes.forEach(processNode);
}
function fix(/**@type{string}*/ text) {
return conversion.reduce(
(txt, [from, to]) => txt.replaceAll(from, (match) => match[0] === match[0].toUpperCase() ? `${to[0].toUpperCase()}${to.slice(1)}` : to),
text
)
}
processNode(document);
/** @type{HTMLButtonElement} */
let button;
function kosherify() {
replacements.forEach(({node, changed}) => node.textContent = changed);
document.body.classList.add('kosher');
button.title = 'Treifify';
}
function treifify() {
replacements.forEach(({node, orig}) => node.textContent = orig);
document.body.classList.remove('kosher');
button.title = 'Kosherify';
}
function toggle() {
if (document.body.classList.contains('kosher'))
treifify();
else
kosherify();
}
if (replacements.length) {
// Create toggle button
button = document.createElement('button');
button.id = 'kosherify_toggle';
// We can't do this in CSS because Chrome doesn't find it
button.style.backgroundImage = `url(${(globalThis.browser??globalThis.chrome).runtime.getURL('jaoc128.png')})`;
document.body.appendChild(button);
button.addEventListener('click', toggle);
kosherify();
}