PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / bingo-card / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/bingo-card/frontend.js

375 lines 16.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 function typoCssVarsForEl(typo, prefix, el) {
5 if (!typo) return;
6 if (typo.family) el.style.setProperty(prefix + 'font-family', "'" + typo.family + "', sans-serif");
7 if (typo.weight) el.style.setProperty(prefix + 'font-weight', typo.weight);
8 if (typo.transform) el.style.setProperty(prefix + 'text-transform', typo.transform);
9 if (typo.style) el.style.setProperty(prefix + 'font-style', typo.style);
10 if (typo.decoration) el.style.setProperty(prefix + 'text-decoration', typo.decoration);
11 var su = typo.sizeUnit || 'px';
12 if (typo.sizeDesktop !== '' && typo.sizeDesktop != null) el.style.setProperty(prefix + 'font-size-d', typo.sizeDesktop + su);
13 if (typo.sizeTablet !== '' && typo.sizeTablet != null) el.style.setProperty(prefix + 'font-size-t', typo.sizeTablet + su);
14 if (typo.sizeMobile !== '' && typo.sizeMobile != null) el.style.setProperty(prefix + 'font-size-m', typo.sizeMobile + su);
15 var lhu = typo.lineHeightUnit || 'px';
16 if (typo.lineHeightDesktop !== '' && typo.lineHeightDesktop != null) el.style.setProperty(prefix + 'line-height-d', typo.lineHeightDesktop + lhu);
17 if (typo.lineHeightTablet !== '' && typo.lineHeightTablet != null) el.style.setProperty(prefix + 'line-height-t', typo.lineHeightTablet + lhu);
18 if (typo.lineHeightMobile !== '' && typo.lineHeightMobile != null) el.style.setProperty(prefix + 'line-height-m', typo.lineHeightMobile + lhu);
19 var lsu = typo.letterSpacingUnit || 'px';
20 if (typo.letterSpacingDesktop !== '' && typo.letterSpacingDesktop != null) { el.style.setProperty(prefix + 'letter-spacing-d', typo.letterSpacingDesktop + lsu); el.style.setProperty(prefix + 'letter-spacing', typo.letterSpacingDesktop + lsu); }
21 if (typo.letterSpacingTablet !== '' && typo.letterSpacingTablet != null) el.style.setProperty(prefix + 'letter-spacing-t', typo.letterSpacingTablet + lsu);
22 if (typo.letterSpacingMobile !== '' && typo.letterSpacingMobile != null) el.style.setProperty(prefix + 'letter-spacing-m', typo.letterSpacingMobile + lsu);
23 var wsu = typo.wordSpacingUnit || 'px';
24 if (typo.wordSpacingDesktop !== '' && typo.wordSpacingDesktop != null) { el.style.setProperty(prefix + 'word-spacing-d', typo.wordSpacingDesktop + wsu); el.style.setProperty(prefix + 'word-spacing', typo.wordSpacingDesktop + wsu); }
25 if (typo.wordSpacingTablet !== '' && typo.wordSpacingTablet != null) el.style.setProperty(prefix + 'word-spacing-t', typo.wordSpacingTablet + wsu);
26 if (typo.wordSpacingMobile !== '' && typo.wordSpacingMobile != null) el.style.setProperty(prefix + 'word-spacing-m', typo.wordSpacingMobile + wsu);
27 }
28
29 var COL_LETTERS = ['B','I','N','G','O'];
30 var COL_RANGES = [[1,15],[16,30],[31,45],[46,60],[61,75]];
31 var COL_BG = ['#e0f2fe','#fef9c3','#dcfce7','#fce7f3','#ede9fe'];
32
33 function generateCard() {
34 return COL_LETTERS.map(function (col, ci) {
35 var nums = [];
36 var lo = COL_RANGES[ci][0], hi = COL_RANGES[ci][1];
37 while (nums.length < 5) {
38 var n = Math.floor(Math.random() * (hi - lo + 1)) + lo;
39 if (nums.indexOf(n) === -1) nums.push(n);
40 }
41 return nums;
42 });
43 }
44
45 function checkBingo(marks) {
46 var lines = [];
47 /* 5 rows */
48 for (var r = 0; r < 5; r++) {
49 lines.push([[0,r],[1,r],[2,r],[3,r],[4,r]]);
50 }
51 /* 5 cols */
52 for (var c = 0; c < 5; c++) {
53 lines.push([[c,0],[c,1],[c,2],[c,3],[c,4]]);
54 }
55 /* 2 diagonals */
56 lines.push([[0,0],[1,1],[2,2],[3,3],[4,4]]);
57 lines.push([[4,0],[3,1],[2,2],[1,3],[0,4]]);
58
59 var winLines = lines.filter(function (line) {
60 return line.every(function (pos) { return marks[pos[0]][pos[1]]; });
61 });
62 return winLines;
63 }
64
65 function initBlock(root) {
66 var opts;
67 try { opts = JSON.parse(root.getAttribute('data-opts')); } catch (e) { return; }
68 var a = opts;
69
70 var card = generateCard();
71 var marks = COL_LETTERS.map(function () { return [false,false,false,false,false]; });
72 marks[2][2] = true; /* FREE space */
73
74 var calledNumbers = [];
75 var allNumbers = [];
76 for (var ci = 0; ci < 5; ci++) {
77 for (var n = COL_RANGES[ci][0]; n <= COL_RANGES[ci][1]; n++) {
78 allNumbers.push({ col: ci, num: n });
79 }
80 }
81 var callPool = allNumbers.slice();
82 var lastCalled = null;
83 var hasBingo = false;
84 var autoTimer = null;
85
86 root.innerHTML = '';
87
88 typoCssVarsForEl(a.titleTypo, '--bkbg-bng-title-', root);
89 typoCssVarsForEl(a.subtitleTypo, '--bkbg-bng-sub-', root);
90
91 var wrap = document.createElement('div');
92 wrap.className = 'bkbg-bng-wrap';
93 wrap.style.cssText = 'background:' + a.sectionBg + ';max-width:' + a.contentMaxWidth + 'px;margin:0 auto;';
94 root.appendChild(wrap);
95
96 if (a.showTitle) {
97 var h = document.createElement('div');
98 h.className = 'bkbg-bng-title';
99 h.style.color = a.titleColor;
100 h.textContent = a.title;
101 wrap.appendChild(h);
102 }
103 if (a.showSubtitle) {
104 var sub = document.createElement('div');
105 sub.className = 'bkbg-bng-subtitle';
106 sub.style.color = '#6b7280';
107 sub.textContent = a.subtitle;
108 wrap.appendChild(sub);
109 }
110
111 /* Win banner */
112 var winBanner = document.createElement('div');
113 winBanner.className = 'bkbg-bng-win-banner';
114 winBanner.style.background = a.bingoColor;
115 winBanner.innerHTML = '<span class="bkbg-bng-win-emoji">🎉</span><div class="bkbg-bng-win-text">BINGO!</div><div class="bkbg-bng-win-sub">You got a bingo! Keep going for more!</div>';
116 wrap.appendChild(winBanner);
117
118 /* Caller */
119 var callerEl = null, calledNumEl = null, callBtn = null, resetBtn = null;
120 if (a.showCaller) {
121 callerEl = document.createElement('div');
122 callerEl.className = 'bkbg-bng-caller';
123 callerEl.style.cssText = 'background:' + a.headerBg + ';color:' + a.headerColor + ';';
124 wrap.appendChild(callerEl);
125
126 var callerLabel = document.createElement('div');
127 callerLabel.className = 'bkbg-bng-caller-label';
128 callerLabel.textContent = 'LAST CALLED';
129 callerEl.appendChild(callerLabel);
130
131 calledNumEl = document.createElement('div');
132 calledNumEl.className = 'bkbg-bng-called-num';
133 calledNumEl.textContent = '';
134 callerEl.appendChild(calledNumEl);
135
136 var callerBtns = document.createElement('div');
137 callerBtns.className = 'bkbg-bng-caller-btns';
138 callerEl.appendChild(callerBtns);
139
140 callBtn = document.createElement('button');
141 callBtn.className = 'bkbg-bng-call-btn';
142 callBtn.style.background = a.accentColor;
143 callBtn.textContent = '▶ Call Number';
144 callerBtns.appendChild(callBtn);
145
146 if (a.autoCall) {
147 var autoBtn = document.createElement('button');
148 autoBtn.className = 'bkbg-bng-call-btn';
149 autoBtn.style.background = '#6366f1';
150 autoBtn.textContent = '⏱ Auto Call';
151 var autoRunning = false;
152 autoBtn.addEventListener('click', function () {
153 if (autoRunning) {
154 clearInterval(autoTimer);
155 autoRunning = false;
156 autoBtn.textContent = '⏱ Auto Call';
157 callBtn.disabled = false;
158 } else {
159 autoRunning = true;
160 autoBtn.textContent = '⏹ Stop Auto';
161 callBtn.disabled = true;
162 autoTimer = setInterval(function () {
163 if (!callNumber()) {
164 clearInterval(autoTimer);
165 autoRunning = false;
166 autoBtn.textContent = '⏱ Auto Call';
167 callBtn.disabled = false;
168 }
169 }, (a.autoCallInterval || 5) * 1000);
170 }
171 });
172 callerBtns.appendChild(autoBtn);
173 }
174 }
175
176 /* Grid */
177 var gridWrap = document.createElement('div');
178 gridWrap.className = 'bkbg-bng-grid-wrap';
179 gridWrap.style.borderColor = a.headerBg;
180 wrap.appendChild(gridWrap);
181
182 var headerRow = document.createElement('div');
183 headerRow.className = 'bkbg-bng-header-row';
184 COL_LETTERS.forEach(function (col) {
185 var hc = document.createElement('div');
186 hc.className = 'bkbg-bng-header-cell';
187 hc.style.cssText = 'background:' + a.headerBg + ';color:' + a.headerColor + ';';
188 hc.textContent = col;
189 headerRow.appendChild(hc);
190 });
191 gridWrap.appendChild(headerRow);
192
193 var cellGrid = document.createElement('div');
194 cellGrid.className = 'bkbg-bng-cell-grid';
195 gridWrap.appendChild(cellGrid);
196
197 var cellEls = []; /* [col][row] */
198 var cellMarkedBg, cellDefaultBg;
199
200 for (var c = 0; c < 5; c++) {
201 cellEls[c] = [];
202 for (var r = 0; r < 5; r++) {
203 (function (ci, ri) {
204 var isFree = (ci === 2 && ri === 2);
205 var cellEl = document.createElement('div');
206 cellEl.className = 'bkbg-bng-cell' + (isFree ? ' bkbg-bng-marked' : '');
207 cellEl.style.cssText = 'border-color:' + a.borderColor + ';background:' + (isFree ? a.freeColor : a.cellBg) + ';color:' + (isFree ? '#fff' : a.cellColor) + ';';
208
209 if (isFree) {
210 var fl = document.createElement('span');
211 fl.className = 'bkbg-bng-free-label';
212 fl.textContent = 'FREE';
213 cellEl.appendChild(fl);
214 } else {
215 cellEl.textContent = card[ci][ri];
216 cellEl.addEventListener('click', function () {
217 if (marks[ci][ri]) return;
218 marks[ci][ri] = true;
219 cellEl.classList.add('bkbg-bng-marked');
220 cellEl.style.cssText = 'border-color:' + a.borderColor + ';background:' + a.markedColor + ';color:#fff;';
221 checkForBingo();
222 });
223 }
224
225 cellEls[ci][ri] = cellEl;
226 cellGrid.appendChild(cellEl);
227 })(c, r);
228 }
229 }
230
231 /* Called list */
232 var calledChipsEl = null;
233 if (a.showCalledList) {
234 var calledListEl = document.createElement('div');
235 calledListEl.className = 'bkbg-bng-called-list';
236 calledListEl.style.cssText = 'background:#fff;border-color:' + a.borderColor + ';margin-top:14px;';
237 var clTitle = document.createElement('div');
238 clTitle.className = 'bkbg-bng-called-list-title';
239 clTitle.style.color = '#6b7280';
240 clTitle.textContent = 'Called Numbers';
241 calledListEl.appendChild(clTitle);
242 calledChipsEl = document.createElement('div');
243 calledChipsEl.className = 'bkbg-bng-called-chips';
244 calledListEl.appendChild(calledChipsEl);
245 wrap.appendChild(calledListEl);
246 }
247
248 /* Actions */
249 var actionsEl = document.createElement('div');
250 actionsEl.className = 'bkbg-bng-actions';
251 actionsEl.style.marginTop = '14px';
252 wrap.appendChild(actionsEl);
253
254 var newCardBtn = document.createElement('button');
255 newCardBtn.className = 'bkbg-bng-call-btn bkbg-bng-call-btn-outline';
256 newCardBtn.style.cssText = 'border-color:' + a.headerBg + ';color:' + a.headerBg + ';background:transparent;';
257 newCardBtn.textContent = '🔀 New Card';
258 actionsEl.appendChild(newCardBtn);
259
260 var resetGameBtn = document.createElement('button');
261 resetGameBtn.className = 'bkbg-bng-call-btn bkbg-bng-call-btn-outline';
262 resetGameBtn.style.cssText = 'border-color:#6b7280;color:#6b7280;background:transparent;';
263 resetGameBtn.textContent = '↺ Reset Game';
264 actionsEl.appendChild(resetGameBtn);
265
266 function addChip(colIdx, num) {
267 if (!calledChipsEl) return;
268 var chip = document.createElement('div');
269 chip.className = 'bkbg-bng-chip';
270 chip.style.background = a.accentColor;
271 chip.textContent = COL_LETTERS[colIdx] + '-' + num;
272 calledChipsEl.insertBefore(chip, calledChipsEl.firstChild);
273 }
274
275 function callNumber() {
276 if (!callPool.length) {
277 if (callBtn) callBtn.disabled = true;
278 return false;
279 }
280 var idx = Math.floor(Math.random() * callPool.length);
281 var called = callPool.splice(idx, 1)[0];
282 calledNumbers.push(called);
283 lastCalled = called;
284
285 if (calledNumEl) {
286 calledNumEl.classList.remove('bkbg-bng-pop');
287 void calledNumEl.offsetWidth;
288 calledNumEl.textContent = COL_LETTERS[called.col] + '-' + called.num;
289 calledNumEl.classList.add('bkbg-bng-pop');
290 }
291
292 addChip(called.col, called.num);
293
294 /* Highlight card if number matches */
295 for (var r = 0; r < 5; r++) {
296 if (card[called.col][r] === called.num && !marks[called.col][r]) {
297 var ce = cellEls[called.col][r];
298 ce.style.outline = '3px solid ' + a.accentColor;
299 }
300 }
301
302 if (!callPool.length && callBtn) callBtn.disabled = true;
303 return true;
304 }
305
306 function checkForBingo() {
307 var winLines = checkBingo(marks);
308 if (winLines.length && !hasBingo) {
309 hasBingo = true;
310 winBanner.classList.add('bkbg-bng-show');
311 winLines.forEach(function (line) {
312 line.forEach(function (pos) {
313 cellEls[pos[0]][pos[1]].classList.add('bkbg-bng-win-cell');
314 cellEls[pos[0]][pos[1]].style.background = a.bingoColor;
315 });
316 });
317 }
318 }
319
320 function resetGame() {
321 clearInterval(autoTimer);
322 callPool = allNumbers.slice();
323 calledNumbers = [];
324 lastCalled = null;
325 hasBingo = false;
326 winBanner.classList.remove('bkbg-bng-show');
327 if (calledNumEl) calledNumEl.textContent = '';
328 if (callBtn) callBtn.disabled = false;
329 if (calledChipsEl) calledChipsEl.innerHTML = '';
330 marks = COL_LETTERS.map(function () { return [false,false,false,false,false]; });
331 marks[2][2] = true;
332 for (var ci = 0; ci < 5; ci++) {
333 for (var ri = 0; ri < 5; ri++) {
334 var isFree = (ci === 2 && ri === 2);
335 var ce = cellEls[ci][ri];
336 ce.classList.remove('bkbg-bng-marked', 'bkbg-bng-win-cell');
337 ce.style.outline = '';
338 if (isFree) {
339 ce.classList.add('bkbg-bng-marked');
340 ce.style.cssText = 'border-color:' + a.borderColor + ';background:' + a.freeColor + ';color:#fff;';
341 } else {
342 ce.style.cssText = 'border-color:' + a.borderColor + ';background:' + a.cellBg + ';color:' + a.cellColor + ';';
343 }
344 }
345 }
346 }
347
348 function newCard() {
349 card = generateCard();
350 resetGame();
351 for (var ci = 0; ci < 5; ci++) {
352 for (var ri = 0; ri < 5; ri++) {
353 if (!(ci === 2 && ri === 2)) {
354 cellEls[ci][ri].textContent = card[ci][ri];
355 }
356 }
357 }
358 }
359
360 if (callBtn) { callBtn.addEventListener('click', callNumber); }
361 resetGameBtn.addEventListener('click', resetGame);
362 newCardBtn.addEventListener('click', newCard);
363 }
364
365 function init() {
366 document.querySelectorAll('.bkbg-bng-app').forEach(initBlock);
367 }
368
369 if (document.readyState === 'loading') {
370 document.addEventListener('DOMContentLoaded', init);
371 } else {
372 init();
373 }
374 })();
375