|
4 | 4 | const prevButton = document.getElementById('prev-button'); |
5 | 5 | const nextButton = document.getElementById('next-button'); |
6 | 6 | const revealButton = document.getElementById('reveal-button'); |
| 7 | + const categorySelect = document.getElementById('category-select'); |
7 | 8 | const categoryList = document.getElementById('joke-categories'); |
8 | 9 |
|
9 | | - if (!setupEl || !punchlineEl || !prevButton || !nextButton || !revealButton) { |
| 10 | + if (!setupEl || !punchlineEl || !prevButton || !nextButton || !revealButton || !categorySelect) { |
10 | 11 | return; |
11 | 12 | } |
12 | 13 |
|
13 | 14 | const jokes = Array.isArray(window.jokes) |
14 | | - ? window.jokes.filter((entry) => entry && entry.joke) |
| 15 | + ? window.jokes |
| 16 | + .map((entry) => { |
| 17 | + if (!entry || typeof entry.joke !== 'string') { |
| 18 | + return null; |
| 19 | + } |
| 20 | + const joke = entry.joke; |
| 21 | + const punchline = typeof entry.punchline === 'string' ? entry.punchline : ''; |
| 22 | + return { joke, punchline }; |
| 23 | + }) |
| 24 | + .filter(Boolean) |
15 | 25 | : []; |
16 | 26 |
|
17 | 27 | let deck = []; |
18 | 28 | let index = 0; |
19 | 29 | let punchlineVisible = false; |
| 30 | + let activeCategory = 'any'; |
20 | 31 |
|
21 | 32 | const categorize = |
22 | 33 | window.jokeCategoryHelper && typeof window.jokeCategoryHelper.categorize === 'function' |
|
28 | 39 | ? window.jokeCategoryHelper.fallback |
29 | 40 | : 'Classic Dad'; |
30 | 41 |
|
| 42 | + const normalizedJokes = jokes.map((entry) => { |
| 43 | + const categories = categorize |
| 44 | + ? categorize(entry.joke, entry.punchline) |
| 45 | + : null; |
| 46 | + const list = Array.isArray(categories) |
| 47 | + ? categories |
| 48 | + .map((label) => (typeof label === 'string' ? label.trim() : '')) |
| 49 | + .filter((label, idx, array) => label && array.indexOf(label) === idx) |
| 50 | + : []; |
| 51 | + return { |
| 52 | + joke: entry.joke, |
| 53 | + punchline: entry.punchline, |
| 54 | + categories: list.length ? list : [fallbackCategory], |
| 55 | + }; |
| 56 | + }); |
| 57 | + |
| 58 | + const categorySet = new Set(); |
| 59 | + normalizedJokes.forEach((entry) => { |
| 60 | + entry.categories.forEach((label) => { |
| 61 | + categorySet.add(label); |
| 62 | + }); |
| 63 | + }); |
| 64 | + |
| 65 | + const categoryOptions = Array.from(categorySet).sort((a, b) => a.localeCompare(b)); |
| 66 | + |
| 67 | + const optionFragment = document.createDocumentFragment(); |
| 68 | + const allOption = document.createElement('option'); |
| 69 | + allOption.value = 'any'; |
| 70 | + allOption.textContent = 'All jokes'; |
| 71 | + optionFragment.appendChild(allOption); |
| 72 | + |
| 73 | + categoryOptions.forEach((label) => { |
| 74 | + const option = document.createElement('option'); |
| 75 | + option.value = label; |
| 76 | + option.textContent = label; |
| 77 | + optionFragment.appendChild(option); |
| 78 | + }); |
| 79 | + |
| 80 | + categorySelect.appendChild(optionFragment); |
| 81 | + categorySelect.value = 'any'; |
| 82 | + if (categoryOptions.length) { |
| 83 | + categorySelect.disabled = false; |
| 84 | + } |
| 85 | + |
| 86 | + function getActiveCollection() { |
| 87 | + if (activeCategory === 'any') { |
| 88 | + return normalizedJokes; |
| 89 | + } |
| 90 | + return normalizedJokes.filter((entry) => entry.categories.includes(activeCategory)); |
| 91 | + } |
| 92 | + |
31 | 93 | function renderCategories(values) { |
32 | 94 | if (!categoryList) { |
33 | 95 | return; |
|
58 | 120 |
|
59 | 121 | function ensureDeck() { |
60 | 122 | if (deck.length === 0) { |
61 | | - deck = shuffle(jokes); |
| 123 | + const available = getActiveCollection(); |
| 124 | + deck = shuffle(available); |
62 | 125 | index = 0; |
63 | 126 | } |
64 | 127 | } |
|
71 | 134 | } |
72 | 135 |
|
73 | 136 | function render() { |
74 | | - if (!jokes.length) { |
| 137 | + const available = getActiveCollection(); |
| 138 | + |
| 139 | + if (!available.length) { |
75 | 140 | setupEl.textContent = 'No jokes available.'; |
76 | 141 | punchlineEl.textContent = ''; |
77 | 142 | punchlineEl.classList.remove('is-visible'); |
|
90 | 155 |
|
91 | 156 | ensureDeck(); |
92 | 157 | const current = deck[index]; |
| 158 | + if (!current) { |
| 159 | + return; |
| 160 | + } |
93 | 161 | const hasPunchline = typeof current.punchline === 'string' && current.punchline.trim().length > 0; |
94 | 162 | const punchlineText = hasPunchline ? current.punchline : '💩'; |
95 | | - const categories = categorize |
96 | | - ? categorize(current.joke, current.punchline) |
| 163 | + const categories = Array.isArray(current.categories) && current.categories.length |
| 164 | + ? current.categories |
97 | 165 | : [fallbackCategory]; |
98 | 166 |
|
99 | 167 | setupEl.textContent = current.joke; |
|
110 | 178 |
|
111 | 179 | function showNext() { |
112 | 180 | ensureDeck(); |
| 181 | + if (!deck.length) { |
| 182 | + return; |
| 183 | + } |
113 | 184 | index = (index + 1) % deck.length; |
114 | 185 | render(); |
115 | 186 | } |
116 | 187 |
|
117 | 188 | function showPrev() { |
118 | 189 | ensureDeck(); |
| 190 | + if (!deck.length) { |
| 191 | + return; |
| 192 | + } |
119 | 193 | index = (index - 1 + deck.length) % deck.length; |
120 | 194 | render(); |
121 | 195 | } |
|
127 | 201 | setPunchlineVisible(!punchlineVisible); |
128 | 202 | } |
129 | 203 |
|
| 204 | + function resetDeck() { |
| 205 | + deck = []; |
| 206 | + ensureDeck(); |
| 207 | + } |
| 208 | + |
| 209 | + categorySelect.addEventListener('change', (event) => { |
| 210 | + activeCategory = event.target.value; |
| 211 | + resetDeck(); |
| 212 | + render(); |
| 213 | + }); |
| 214 | + |
130 | 215 | prevButton.addEventListener('click', showPrev); |
131 | 216 | nextButton.addEventListener('click', showNext); |
132 | 217 | revealButton.addEventListener('click', togglePunchline); |
|
136 | 221 | return; |
137 | 222 | } |
138 | 223 |
|
| 224 | + const target = event.target; |
| 225 | + const tagName = target && target.tagName; |
| 226 | + if (tagName && ['INPUT', 'TEXTAREA', 'SELECT'].includes(tagName)) { |
| 227 | + return; |
| 228 | + } |
| 229 | + |
139 | 230 | if (event.key === 'ArrowRight') { |
140 | 231 | event.preventDefault(); |
141 | 232 | showNext(); |
|
0 commit comments