word-games-theme 3.3.6 → 3.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/_data/footer/en/data.json +95 -0
- data/_data/header/en/data.json +559 -36
- data/_data/home_sections.json +453 -0
- data/_data/wordgames/en/root.json +16 -13
- data/_includes/featurePageAuthors/featurePageAuthors.html +36 -59
- data/_includes/home/ad-preview.html +3 -0
- data/_includes/home/ad-slot.html +3 -0
- data/_includes/home/chips.html +6 -0
- data/_includes/home/crosswords.html +18 -0
- data/_includes/home/daily-hints.html +15 -0
- data/_includes/home/footer.html +212 -0
- data/_includes/home/game-art.html +18 -0
- data/_includes/home/game-cards.html +22 -0
- data/_includes/home/header.html +82 -0
- data/_includes/home/icon.html +19 -0
- data/_includes/home/letter-lists.html +17 -0
- data/_includes/home/logo.html +84 -0
- data/_includes/home/solvers.html +9 -0
- data/_includes/wordgames/advanced-filter/advanced-filter.html +15 -14
- data/_includes/wordgames/faqs/faqs.html +2 -4
- data/_includes/wordgames/headings/headings.html +1 -1
- data/_includes/wordgames/infographics/infographics.html +2 -136
- data/_includes/wordgames/search-box/search-box.html +1 -1
- data/_includes/wordgames-v2/advanced-filter/advanced-filter.html +421 -0
- data/_includes/wordgames-v2/faqs/faqs.html +35 -0
- data/_includes/wordgames-v2/featurehighlights/featurehighlights.html +70 -0
- data/_includes/wordgames-v2/head/head.html +170 -0
- data/_includes/wordgames-v2/headings/headings.html +14 -0
- data/_includes/wordgames-v2/howto/howto.html +94 -0
- data/_includes/wordgames-v2/infographics/infographics.html +358 -0
- data/_includes/wordgames-v2/search-box/dict-picker.html +26 -0
- data/_includes/wordgames-v2/search-box/search-box.html +87 -0
- data/_layouts/wordgames-home-v2.html +141 -0
- data/assets/css/ad-preview.css +85 -0
- data/assets/css/home-hub.css +1879 -0
- data/assets/css/wordfinder-result.css +5 -5
- data/assets/css/wordgames-home-v2.css +2955 -0
- data/assets/css/wordgames-home.css +3 -4
- data/assets/css/wordgames-result.css +1 -1
- data/assets/css/wordle-solver.css +2 -2
- data/assets/images/close-menu.svg +1 -14
- data/assets/images/hamburger-menu.svg +1 -5
- data/assets/images/logo-hub.svg +24 -0
- data/assets/images/logo.svg +13 -106
- data/assets/images/questionmark.svg +1 -1
- data/assets/images/wordswithletters-logo.svg +96 -0
- data/assets/js/ad-preview.js +141 -0
- data/assets/js/home-hub.js +275 -0
- data/assets/js/home-ui.js +286 -0
- data/assets/js/scrabbleDictonary.js +8 -202
- data/assets/js/wordleSolver-worker.js +2 -7
- data/assets/js/wordleSolver.js +2 -2
- metadata +35 -6
- data/_data/.DS_Store +0 -0
- data/_includes/.DS_Store +0 -0
- data/assets/.DS_Store +0 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Home Hub - World-Class Puzzle Portal Client Scripts
|
|
3
|
+
* Blazing fast vanilla JS with instant search, filter tabs & keyboard navigation.
|
|
4
|
+
*/
|
|
5
|
+
(function () {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
var doc = document;
|
|
9
|
+
var root = doc.documentElement;
|
|
10
|
+
root.classList.add('js');
|
|
11
|
+
|
|
12
|
+
var $ = function (s, c) { return (c || doc).querySelector(s); };
|
|
13
|
+
var $$ = function (s, c) { return Array.prototype.slice.call((c || doc).querySelectorAll(s)); };
|
|
14
|
+
|
|
15
|
+
var storage = {
|
|
16
|
+
get: function (k) { try { return localStorage.getItem(k); } catch (e) { return null; } },
|
|
17
|
+
set: function (k, v) { try { localStorage.setItem(k, v); } catch (e) {} }
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/* ==========================================
|
|
21
|
+
2. Mobile Burger & Mega Menu Navigation
|
|
22
|
+
========================================== */
|
|
23
|
+
var burger = $('#hh-burger');
|
|
24
|
+
var nav = $('#hh-nav');
|
|
25
|
+
var megaWrap = $('.hh-mega-wrap');
|
|
26
|
+
var megaTrigger = $('.hh-mega-trigger');
|
|
27
|
+
|
|
28
|
+
if (burger && nav) {
|
|
29
|
+
burger.addEventListener('click', function () {
|
|
30
|
+
var isOpen = nav.classList.toggle('is-open');
|
|
31
|
+
burger.setAttribute('aria-expanded', isOpen);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (megaTrigger && megaWrap) {
|
|
36
|
+
megaTrigger.addEventListener('click', function (e) {
|
|
37
|
+
e.stopPropagation();
|
|
38
|
+
var isOpen = megaWrap.classList.toggle('is-open');
|
|
39
|
+
megaTrigger.setAttribute('aria-expanded', isOpen);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
doc.addEventListener('click', function (e) {
|
|
43
|
+
if (!megaWrap.contains(e.target)) {
|
|
44
|
+
megaWrap.classList.remove('is-open');
|
|
45
|
+
megaTrigger.setAttribute('aria-expanded', 'false');
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* ==========================================
|
|
51
|
+
3. Interactive Search & Instant Autocomplete
|
|
52
|
+
========================================== */
|
|
53
|
+
var cards = $$('.hh-game-card');
|
|
54
|
+
var searchInput = $('#hh-q');
|
|
55
|
+
var searchClear = $('#hh-search-clear');
|
|
56
|
+
var searchDropdown = $('#hh-search-dropdown');
|
|
57
|
+
var searchResultsList = $('#hh-search-results-list');
|
|
58
|
+
var searchCountBadge = $('#hh-search-count-badge');
|
|
59
|
+
var emptyState = $('#hh-empty');
|
|
60
|
+
var countBadge = $('#hh-count');
|
|
61
|
+
var groups = $$('.hh-group');
|
|
62
|
+
var currentTab = 'all';
|
|
63
|
+
var tabs = $$('.hh-tab-btn');
|
|
64
|
+
|
|
65
|
+
// Pre-index games for live search dropdown
|
|
66
|
+
var searchIndex = cards.map(function (card) {
|
|
67
|
+
var titleEl = $('.hh-game-card__title', card);
|
|
68
|
+
var descEl = $('.hh-game-card__desc', card);
|
|
69
|
+
var iconEl = $('.hh-game-card__icon-wrap', card);
|
|
70
|
+
return {
|
|
71
|
+
id: card.dataset.id,
|
|
72
|
+
title: titleEl ? titleEl.textContent.trim() : '',
|
|
73
|
+
desc: descEl ? descEl.textContent.trim() : '',
|
|
74
|
+
iconHtml: iconEl ? iconEl.innerHTML : '',
|
|
75
|
+
url: card.dataset.id,
|
|
76
|
+
group: card.dataset.group,
|
|
77
|
+
searchText: (card.dataset.search || '').toLowerCase()
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
function renderSearchDropdown(query) {
|
|
82
|
+
if (!searchDropdown || !searchResultsList) return;
|
|
83
|
+
|
|
84
|
+
if (!query) {
|
|
85
|
+
searchDropdown.hidden = true;
|
|
86
|
+
searchResultsList.innerHTML = '';
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
var matches = searchIndex.filter(function (item) {
|
|
91
|
+
return item.searchText.indexOf(query) > -1;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (searchCountBadge) {
|
|
95
|
+
searchCountBadge.textContent = matches.length + (matches.length === 1 ? ' result' : ' results');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (matches.length === 0) {
|
|
99
|
+
searchResultsList.innerHTML = '<div style="padding: 16px; text-align: center; color: var(--text-muted); font-size: 13.5px;">No solvers found for "' + escapeHtml(query) + '".</div>';
|
|
100
|
+
searchDropdown.hidden = false;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
var html = matches.slice(0, 6).map(function (item) {
|
|
105
|
+
var highlightedTitle = highlightMatch(item.title, query);
|
|
106
|
+
return (
|
|
107
|
+
'<a href="' + item.url + '" class="hh-search-result-item">' +
|
|
108
|
+
'<div class="hh-search-result-item__icon">' + item.iconHtml + '</div>' +
|
|
109
|
+
'<div class="hh-search-result-item__text">' +
|
|
110
|
+
'<div class="hh-search-result-item__title">' + highlightedTitle + '</div>' +
|
|
111
|
+
'<div class="hh-search-result-item__desc">' + escapeHtml(item.desc) + '</div>' +
|
|
112
|
+
'</div>' +
|
|
113
|
+
'<span class="hh-search-result-item__arrow">→</span>' +
|
|
114
|
+
'</a>'
|
|
115
|
+
);
|
|
116
|
+
}).join('');
|
|
117
|
+
|
|
118
|
+
searchResultsList.innerHTML = html;
|
|
119
|
+
searchDropdown.hidden = false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function escapeHtml(str) {
|
|
123
|
+
return str.replace(/[&<>"']/g, function (m) {
|
|
124
|
+
return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[m];
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function highlightMatch(text, term) {
|
|
129
|
+
var regex = new RegExp('(' + term.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') + ')', 'gi');
|
|
130
|
+
return escapeHtml(text).replace(regex, '<mark>$1</mark>');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function applyFilters() {
|
|
134
|
+
var term = searchInput ? searchInput.value.trim().toLowerCase() : '';
|
|
135
|
+
var visibleCount = 0;
|
|
136
|
+
|
|
137
|
+
if (searchClear) {
|
|
138
|
+
searchClear.hidden = term.length === 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
cards.forEach(function (card) {
|
|
142
|
+
var grp = card.dataset.group;
|
|
143
|
+
var matchesTab = currentTab === 'all' || currentTab === grp;
|
|
144
|
+
var matchesQuery = !term || card.dataset.search.indexOf(term) > -1;
|
|
145
|
+
var show = matchesTab && matchesQuery;
|
|
146
|
+
|
|
147
|
+
card.classList.toggle('is-hidden', !show);
|
|
148
|
+
if (show) visibleCount++;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Hide entire groups if no visible cards remain
|
|
152
|
+
groups.forEach(function (grp) {
|
|
153
|
+
var hasVisible = $('.hh-game-card:not(.is-hidden)', grp);
|
|
154
|
+
grp.classList.toggle('is-hidden', !hasVisible);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (countBadge) countBadge.textContent = visibleCount;
|
|
158
|
+
if (emptyState) emptyState.hidden = visibleCount > 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (searchInput) {
|
|
162
|
+
searchInput.addEventListener('input', function () {
|
|
163
|
+
var val = searchInput.value.trim().toLowerCase();
|
|
164
|
+
applyFilters();
|
|
165
|
+
renderSearchDropdown(val);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
searchInput.addEventListener('keydown', function (e) {
|
|
169
|
+
if (e.key === 'Escape') {
|
|
170
|
+
searchInput.value = '';
|
|
171
|
+
applyFilters();
|
|
172
|
+
if (searchDropdown) searchDropdown.hidden = true;
|
|
173
|
+
searchInput.blur();
|
|
174
|
+
}
|
|
175
|
+
if (e.key === 'Enter') {
|
|
176
|
+
var firstMatch = $('.hh-search-result-item') || $('.hh-game-card:not(.is-hidden) .hh-game-card__inner');
|
|
177
|
+
if (firstMatch) {
|
|
178
|
+
window.location.href = firstMatch.href;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Close dropdown on outside click
|
|
184
|
+
doc.addEventListener('click', function (e) {
|
|
185
|
+
if (searchDropdown && !searchDropdown.contains(e.target) && !searchInput.contains(e.target)) {
|
|
186
|
+
searchDropdown.hidden = true;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (searchClear && searchInput) {
|
|
192
|
+
searchClear.addEventListener('click', function () {
|
|
193
|
+
searchInput.value = '';
|
|
194
|
+
applyFilters();
|
|
195
|
+
if (searchDropdown) searchDropdown.hidden = true;
|
|
196
|
+
searchInput.focus();
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Global Keyboard Shortcut: Cmd/Ctrl+K to focus hub search */
|
|
201
|
+
doc.addEventListener('keydown', function (e) {
|
|
202
|
+
var tag = e.target.tagName;
|
|
203
|
+
if (((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') && tag !== 'INPUT' && tag !== 'TEXTAREA') {
|
|
204
|
+
e.preventDefault();
|
|
205
|
+
if (searchInput) {
|
|
206
|
+
searchInput.focus();
|
|
207
|
+
searchInput.select();
|
|
208
|
+
searchInput.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
/* ==========================================
|
|
214
|
+
4. Category Tab Switching
|
|
215
|
+
========================================== */
|
|
216
|
+
tabs.forEach(function (tab) {
|
|
217
|
+
tab.addEventListener('click', function () {
|
|
218
|
+
currentTab = tab.dataset.filter;
|
|
219
|
+
tabs.forEach(function (t) {
|
|
220
|
+
var isCurrent = t === tab;
|
|
221
|
+
t.classList.toggle('is-active', isCurrent);
|
|
222
|
+
t.setAttribute('aria-selected', isCurrent ? 'true' : 'false');
|
|
223
|
+
});
|
|
224
|
+
applyFilters();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
/* Popular Chips Click */
|
|
229
|
+
$$('.hh-chip').forEach(function (chip) {
|
|
230
|
+
chip.addEventListener('click', function () {
|
|
231
|
+
var query = chip.dataset.q;
|
|
232
|
+
if (searchInput) {
|
|
233
|
+
searchInput.value = query;
|
|
234
|
+
applyFilters();
|
|
235
|
+
renderSearchDropdown(query.toLowerCase());
|
|
236
|
+
}
|
|
237
|
+
var gamesSec = $('#games');
|
|
238
|
+
if (gamesSec) {
|
|
239
|
+
gamesSec.scrollIntoView({ behavior: 'smooth' });
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
/* Reset Button */
|
|
245
|
+
var resetBtn = $('#hh-reset');
|
|
246
|
+
if (resetBtn && searchInput) {
|
|
247
|
+
resetBtn.addEventListener('click', function () {
|
|
248
|
+
searchInput.value = '';
|
|
249
|
+
if (tabs.length > 0) tabs[0].click();
|
|
250
|
+
applyFilters();
|
|
251
|
+
if (searchDropdown) searchDropdown.hidden = true;
|
|
252
|
+
searchInput.focus();
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* ==========================================
|
|
257
|
+
5. Quick Letter Unscrambler Sanitizer
|
|
258
|
+
========================================== */
|
|
259
|
+
var unscrambleInput = $('#hh-unscramble-input');
|
|
260
|
+
var unscrambleForm = $('#hh-unscramble-form');
|
|
261
|
+
if (unscrambleInput && unscrambleForm) {
|
|
262
|
+
unscrambleInput.addEventListener('input', function () {
|
|
263
|
+
// Allow letters, wildcards (?, *) and spaces
|
|
264
|
+
unscrambleInput.value = unscrambleInput.value.replace(/[^a-zA-Z?* ]/g, '').toUpperCase();
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Check URL params for ?q=
|
|
269
|
+
var urlParams = new URLSearchParams(window.location.search);
|
|
270
|
+
var initialQ = urlParams.get('q');
|
|
271
|
+
if (initialQ && searchInput) {
|
|
272
|
+
searchInput.value = initialQ;
|
|
273
|
+
applyFilters();
|
|
274
|
+
}
|
|
275
|
+
})();
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/* Home UI: mega menu, theme toggle, rails, tabs, copy-on-click. No dependencies. */
|
|
2
|
+
(function () {
|
|
3
|
+
'use strict';
|
|
4
|
+
var d = document;
|
|
5
|
+
var $ = function (s, c) { return (c || d).querySelector(s); };
|
|
6
|
+
var $$ = function (s, c) { return Array.prototype.slice.call((c || d).querySelectorAll(s)); };
|
|
7
|
+
var store = {
|
|
8
|
+
get: function (k) { try { return localStorage.getItem(k); } catch (e) { return null; } },
|
|
9
|
+
set: function (k, v) { try { localStorage.setItem(k, v); } catch (e) { } }
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/* Mega menu */
|
|
13
|
+
var items = $$('.wg-menu__item');
|
|
14
|
+
function closeAll(except) {
|
|
15
|
+
items.forEach(function (li) {
|
|
16
|
+
if (li === except) return;
|
|
17
|
+
li.classList.remove('is-open');
|
|
18
|
+
var b = $('.wg-menu__btn', li);
|
|
19
|
+
if (b) b.setAttribute('aria-expanded', 'false');
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
items.forEach(function (li) {
|
|
23
|
+
var btn = $('.wg-menu__btn', li);
|
|
24
|
+
if (!btn) return;
|
|
25
|
+
btn.addEventListener('click', function (e) {
|
|
26
|
+
e.stopPropagation();
|
|
27
|
+
var open = !li.classList.contains('is-open');
|
|
28
|
+
closeAll(li);
|
|
29
|
+
li.classList.toggle('is-open', open);
|
|
30
|
+
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
d.addEventListener('click', function (e) { if (!e.target.closest('.wg-menu')) closeAll(); });
|
|
34
|
+
/* desktop: hovering another item closes a menu that was opened by click */
|
|
35
|
+
var hoverMenu = window.matchMedia('(hover: hover) and (min-width: 992px)');
|
|
36
|
+
items.forEach(function (li) {
|
|
37
|
+
li.addEventListener('mouseenter', function () { if (hoverMenu.matches) closeAll(li); });
|
|
38
|
+
});
|
|
39
|
+
d.addEventListener('keydown', function (e) {
|
|
40
|
+
if (e.key === 'Escape') {
|
|
41
|
+
var open = $('.wg-menu__item.is-open .wg-menu__btn');
|
|
42
|
+
closeAll();
|
|
43
|
+
if (open) open.focus();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/* Mobile drawer (open/close itself is handled by theme.js; sync aria + scroll lock) */
|
|
48
|
+
var burger = $('#button-toggle');
|
|
49
|
+
var drawer = $('#navbarSupportedContent');
|
|
50
|
+
if (burger && drawer) {
|
|
51
|
+
burger.addEventListener('click', function () {
|
|
52
|
+
setTimeout(function () {
|
|
53
|
+
var open = drawer.classList.contains('show');
|
|
54
|
+
burger.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
55
|
+
burger.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
|
|
56
|
+
d.body.classList.toggle('wg-lock', open);
|
|
57
|
+
}, 0);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Rail arrows */
|
|
62
|
+
$$('.wg-section').forEach(function (sec) {
|
|
63
|
+
var rail = $('.wg-rail', sec);
|
|
64
|
+
if (!rail) return;
|
|
65
|
+
$$('[data-scroll]', sec).forEach(function (btn) {
|
|
66
|
+
btn.addEventListener('click', function () {
|
|
67
|
+
var dir = parseInt(btn.getAttribute('data-scroll'), 10);
|
|
68
|
+
rail.scrollBy({ left: dir * rail.clientWidth * 0.8, behavior: 'smooth' });
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/* Crossword tabs */
|
|
74
|
+
var tabs = $('[data-tabs]');
|
|
75
|
+
function showTab(id) {
|
|
76
|
+
if (!tabs) return;
|
|
77
|
+
$$('.wg-tab', tabs).forEach(function (t) {
|
|
78
|
+
var on = t.getAttribute('data-tab') === id;
|
|
79
|
+
t.classList.toggle('is-active', on);
|
|
80
|
+
t.setAttribute('aria-selected', on ? 'true' : 'false');
|
|
81
|
+
});
|
|
82
|
+
$$('.wg-clues', tabs).forEach(function (p) { p.hidden = p.id !== 'panel-' + id; });
|
|
83
|
+
}
|
|
84
|
+
if (tabs) {
|
|
85
|
+
$$('.wg-tab', tabs).forEach(function (t, i, all) {
|
|
86
|
+
t.addEventListener('click', function () { showTab(t.getAttribute('data-tab')); });
|
|
87
|
+
t.addEventListener('keydown', function (e) {
|
|
88
|
+
var n = e.key === 'ArrowRight' ? i + 1 : e.key === 'ArrowLeft' ? i - 1 : null;
|
|
89
|
+
if (n === null) return;
|
|
90
|
+
var next = all[(n + all.length) % all.length];
|
|
91
|
+
next.focus();
|
|
92
|
+
showTab(next.getAttribute('data-tab'));
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
$$('[data-cross-tab]').forEach(function (a) {
|
|
96
|
+
a.addEventListener('click', function () { showTab(a.getAttribute('data-cross-tab')); closeAll(); });
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
var seo = $('[data-seo]');
|
|
101
|
+
|
|
102
|
+
/* The word finder removes the features/how-to blocks after a search; drop the empty wrapper too */
|
|
103
|
+
if (seo) {
|
|
104
|
+
var seoBody = $('.wg-seo__body', seo);
|
|
105
|
+
if (seoBody) {
|
|
106
|
+
new MutationObserver(function () {
|
|
107
|
+
if (!$('#featureContainer', seoBody) && !$('#howContainer', seoBody)) seo.hidden = true;
|
|
108
|
+
}).observe(seoBody, { childList: true });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Back to top */
|
|
113
|
+
var topBtn = $('#wg-top');
|
|
114
|
+
if (topBtn) {
|
|
115
|
+
var onScroll = function () { topBtn.hidden = window.scrollY < 900; };
|
|
116
|
+
window.addEventListener('scroll', onScroll, { passive: true });
|
|
117
|
+
onScroll();
|
|
118
|
+
topBtn.addEventListener('click', function () {
|
|
119
|
+
var smooth = !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
120
|
+
window.scrollTo({ top: 0, behavior: smooth ? 'smooth' : 'auto' });
|
|
121
|
+
var box = $('.serachBox .txtBox');
|
|
122
|
+
if (box) box.focus({ preventScroll: true });
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* "/" focuses the letters box (skipped while typing in a field) */
|
|
127
|
+
d.addEventListener('keydown', function (e) {
|
|
128
|
+
if (e.key !== '/' || e.ctrlKey || e.metaKey || e.altKey) return;
|
|
129
|
+
var t = e.target;
|
|
130
|
+
if (t && (t.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName))) return;
|
|
131
|
+
var box = $('.serachBox .txtBox');
|
|
132
|
+
if (!box) return;
|
|
133
|
+
e.preventDefault();
|
|
134
|
+
box.focus();
|
|
135
|
+
box.scrollIntoView({ block: 'center' });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
/* Letters box: live counter, quick-rack chips, filter-active badge */
|
|
139
|
+
(function () {
|
|
140
|
+
var box = $('.serachBox .txtBox');
|
|
141
|
+
if (!box) return;
|
|
142
|
+
var wrap = box.closest('.txt-box-container');
|
|
143
|
+
var count = $('.wg-char-count', wrap);
|
|
144
|
+
var max = parseInt(box.getAttribute('maxlength'), 10) || 15;
|
|
145
|
+
var reset = $('.wg-reset');
|
|
146
|
+
var fields = [box].concat($$('.fillterWrapper .filter_val'));
|
|
147
|
+
var syncReset = function () {
|
|
148
|
+
if (reset) reset.hidden = !fields.some(function (f) { return f.value !== ''; });
|
|
149
|
+
};
|
|
150
|
+
fields.forEach(function (f) { f.addEventListener('input', syncReset); });
|
|
151
|
+
if (reset) reset.addEventListener('click', function () {
|
|
152
|
+
fields.forEach(function (f) {
|
|
153
|
+
if (f.value === '') return;
|
|
154
|
+
f.value = '';
|
|
155
|
+
f.dispatchEvent(new Event('input', { bubbles: true }));
|
|
156
|
+
});
|
|
157
|
+
syncReset();
|
|
158
|
+
box.focus();
|
|
159
|
+
});
|
|
160
|
+
var sync = function () {
|
|
161
|
+
syncReset();
|
|
162
|
+
var n = box.value.length;
|
|
163
|
+
wrap.classList.toggle('has-value', n > 0);
|
|
164
|
+
if (count) {
|
|
165
|
+
count.textContent = n + '/' + max;
|
|
166
|
+
count.classList.toggle('is-full', n >= max);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
box.addEventListener('input', sync);
|
|
170
|
+
var clear = $('.letter-close-button', wrap);
|
|
171
|
+
if (clear) clear.addEventListener('click', function () { setTimeout(sync, 0); box.focus(); });
|
|
172
|
+
|
|
173
|
+
var upd = function () { };
|
|
174
|
+
var toggle = $('.filtersOptions');
|
|
175
|
+
var inputs = $$('.fillterWrapper .filter_val');
|
|
176
|
+
if (toggle && inputs.length) {
|
|
177
|
+
var badge = d.createElement('span');
|
|
178
|
+
badge.className = 'wg-filter-badge';
|
|
179
|
+
badge.hidden = true;
|
|
180
|
+
toggle.appendChild(badge);
|
|
181
|
+
upd = function () {
|
|
182
|
+
var n = inputs.filter(function (i) { return i.value !== ''; }).length;
|
|
183
|
+
badge.textContent = n;
|
|
184
|
+
badge.hidden = n === 0;
|
|
185
|
+
};
|
|
186
|
+
inputs.forEach(function (i) { i.addEventListener('input', upd); });
|
|
187
|
+
d.addEventListener('click', function () { setTimeout(upd, 0); });
|
|
188
|
+
upd();
|
|
189
|
+
}
|
|
190
|
+
sync();
|
|
191
|
+
/* the word finder restores values from the URL without firing input events */
|
|
192
|
+
[150, 500, 1200, 2500].forEach(function (t) { setTimeout(function () { sync(); upd(); }, t); });
|
|
193
|
+
window.addEventListener('pageshow', function () { sync(); upd(); });
|
|
194
|
+
})();
|
|
195
|
+
|
|
196
|
+
/* Dictionary chip + popover (markup is server-rendered; this only wires it to the hidden select) */
|
|
197
|
+
(function () {
|
|
198
|
+
var dd = $('.wg-dd');
|
|
199
|
+
var sel = dd && $('select', dd);
|
|
200
|
+
var btn = dd && $('.wg-dd__btn', dd);
|
|
201
|
+
var menu = dd && $('.wg-dd__menu', dd);
|
|
202
|
+
if (!sel || !btn || !menu) return;
|
|
203
|
+
var short = { Dictionary: 'All dictionaries', twl06: 'US · TWL', sowpods: 'UK · SOWPODS', wwf: 'Words With Friends' };
|
|
204
|
+
var opts = $$('li', menu);
|
|
205
|
+
function paint() {
|
|
206
|
+
$('.wg-dd__label', dd).textContent = short[sel.value] || sel.options[sel.selectedIndex].textContent;
|
|
207
|
+
opts.forEach(function (li) {
|
|
208
|
+
var on = li.dataset.value === sel.value;
|
|
209
|
+
li.classList.toggle('is-on', on);
|
|
210
|
+
li.setAttribute('aria-selected', on);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function open(v) {
|
|
214
|
+
menu.hidden = !v;
|
|
215
|
+
btn.setAttribute('aria-expanded', v);
|
|
216
|
+
dd.classList.toggle('is-open', v);
|
|
217
|
+
if (v) { var cur = $('.is-on', menu) || menu.firstElementChild; cur.focus(); }
|
|
218
|
+
}
|
|
219
|
+
function choose(v) {
|
|
220
|
+
if (sel.value !== v) {
|
|
221
|
+
sel.value = v;
|
|
222
|
+
sel.dispatchEvent(new Event('change', { bubbles: true }));
|
|
223
|
+
}
|
|
224
|
+
paint();
|
|
225
|
+
open(false);
|
|
226
|
+
btn.focus();
|
|
227
|
+
}
|
|
228
|
+
opts.forEach(function (li) {
|
|
229
|
+
li.addEventListener('click', function () { choose(li.dataset.value); });
|
|
230
|
+
li.addEventListener('keydown', function (e) {
|
|
231
|
+
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); choose(li.dataset.value); }
|
|
232
|
+
else if (e.key === 'ArrowDown') { e.preventDefault(); (li.nextElementSibling || menu.firstElementChild).focus(); }
|
|
233
|
+
else if (e.key === 'ArrowUp') { e.preventDefault(); (li.previousElementSibling || menu.lastElementChild).focus(); }
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
btn.addEventListener('click', function () { open(menu.hidden); });
|
|
237
|
+
d.addEventListener('click', function (e) { if (!menu.hidden && !dd.contains(e.target)) open(false); });
|
|
238
|
+
d.addEventListener('keydown', function (e) { if (e.key === 'Escape' && !menu.hidden) { open(false); btn.focus(); } });
|
|
239
|
+
sel.addEventListener('change', paint);
|
|
240
|
+
paint();
|
|
241
|
+
/* the word finder can set the select from the URL without firing change */
|
|
242
|
+
[200, 800, 2000].forEach(function (t) { setTimeout(paint, t); });
|
|
243
|
+
window.addEventListener('pageshow', paint);
|
|
244
|
+
})();
|
|
245
|
+
|
|
246
|
+
/* Rails: disable arrows at the ends */
|
|
247
|
+
$$('.wg-section').forEach(function (sec) {
|
|
248
|
+
var rail = $('.wg-rail', sec);
|
|
249
|
+
if (!rail) return;
|
|
250
|
+
var prev = $('[data-scroll="-1"]', sec), next = $('[data-scroll="1"]', sec);
|
|
251
|
+
var sync = function () {
|
|
252
|
+
var max = rail.scrollWidth - rail.clientWidth - 2;
|
|
253
|
+
if (prev) prev.disabled = rail.scrollLeft <= 2;
|
|
254
|
+
if (next) next.disabled = rail.scrollLeft >= max;
|
|
255
|
+
};
|
|
256
|
+
rail.addEventListener('scroll', sync, { passive: true });
|
|
257
|
+
window.addEventListener('resize', sync);
|
|
258
|
+
sync();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
/* Copy a word on click (Ctrl/Cmd/Shift-click still opens the dictionary link) */
|
|
262
|
+
var toast;
|
|
263
|
+
function say(msg) {
|
|
264
|
+
if (!toast) {
|
|
265
|
+
toast = d.createElement('div');
|
|
266
|
+
toast.className = 'wg-toast';
|
|
267
|
+
toast.setAttribute('role', 'status');
|
|
268
|
+
d.body.appendChild(toast);
|
|
269
|
+
}
|
|
270
|
+
toast.textContent = msg;
|
|
271
|
+
toast.classList.add('is-on');
|
|
272
|
+
clearTimeout(say.t);
|
|
273
|
+
say.t = setTimeout(function () { toast.classList.remove('is-on'); }, 1400);
|
|
274
|
+
}
|
|
275
|
+
d.addEventListener('click', function (e) {
|
|
276
|
+
var li = e.target.closest && e.target.closest('.list_word');
|
|
277
|
+
if (!li || e.ctrlKey || e.metaKey || e.shiftKey || e.button !== 0) return;
|
|
278
|
+
var clone = li.cloneNode(true);
|
|
279
|
+
var pts = clone.querySelector('.points');
|
|
280
|
+
if (pts) pts.remove();
|
|
281
|
+
var word = clone.textContent.trim();
|
|
282
|
+
if (!word || !navigator.clipboard) return;
|
|
283
|
+
e.preventDefault();
|
|
284
|
+
navigator.clipboard.writeText(word).then(function () { say('Copied "' + word + '"'); }, function () { });
|
|
285
|
+
});
|
|
286
|
+
})();
|