1/** 2 * Shared casino page chrome â balance HUD, guest banner, bet panel helper. 3 */ 4(function (global) { 5 'use strict'; 6 7 var boundRoots = []; 8 var displayedBalanceByRoot = new WeakMap(); 9 var balanceAnimChainByRoot = new WeakMap(); 10 var animLockByRoot = new WeakMap(); 11 var pendingBalanceByRoot = new WeakMap(); 12 13 var FLY_PULL_MS = 110; 14 var FLY_SLING_MS = 150; 15 var FLY_TOTAL_MS = FLY_PULL_MS + FLY_SLING_MS + 30; 16 17 function formatBalanceText(balance) { 18 if (balance == null) return 'â'; 19 return global.CasinoCore.formatCoins(balance); 20 } 21 22 function updateBalanceElImmediate(root, balance) { 23 var el = root.querySelector('[data-casino-balance]'); 24 if (!el) return; 25 el.textContent = formatBalanceText(balance); 26 if (balance == null) { 27 displayedBalanceByRoot.delete(root); 28 return; 29 } 30 displayedBalanceByRoot.set(root, balance); 31 } 32 33 function getBalanceHost(root) { 34 return root.querySelector('[data-casino-balance-host]') 35 || root.querySelector('.casino-balance'); 36 } 37 38 function flushPendingBalance(root) { 39 if (animLockByRoot.get(root)) return; 40 if (!pendingBalanceByRoot.has(root)) return; 41 var pending = pendingBalanceByRoot.get(root); 42 pendingBalanceByRoot.delete(root); 43 updateBalanceElImmediate(root, pending); 44 } 45 46 function onWalletBalance(root, balance) { 47 if (balance == null) { 48 updateBalanceElImmediate(root, balance); 49 return; 50 } 51 if (animLockByRoot.get(root)) { 52 pendingBalanceByRoot.set(root, balance); 53 return; 54 } 55 updateBalanceElImmediate(root, balance); 56 } 57 58 function playBalanceDeltaAnim(root, delta) { 59 return new Promise(function (resolve) { 60 var host = getBalanceHost(root); 61 var valueEl = root.querySelector('[data-casino-balance]'); 62 if (!host || !valueEl || !delta) { 63 resolve(); 64 return; 65 } 66 67 var valueStyle = global.getComputedStyle(valueEl); 68 var hostRect = host.getBoundingClientRect(); 69 var valueRect = valueEl.getBoundingClientRect(); 70 var y = hostRect.top + hostRect.height * 0.5; 71 72 var fly = document.createElement('span'); 73 fly.className = 'casino-balance-fly ' + (delta > 0 74 ? 'casino-balance-fly--gain' 75 : 'casino-balance-fly--loss'); 76 fly.textContent = (delta > 0 ? '+' : 'â') + global.CasinoCore.formatCoins(Math.abs(delta)); 77 fly.style.fontSize = valueStyle.fontSize; 78 fly.style.fontWeight = valueStyle.fontWeight; 79 fly.style.lineHeight = valueStyle.lineHeight; 80 fly.style.top = y + 'px'; 81 fly.style.visibility = 'hidden'; 82 document.body.appendChild(fly); 83 84 var flyW = fly.getBoundingClientRect().width; 85 var gap = 12; 86 var pull = 26; 87 var startX = hostRect.right + gap + flyW * 0.5; 88 var pullX = hostRect.right + gap + pull + flyW * 0.5; 89 var endX = valueRect.left + valueRect.width * 0.62; 90 91 fly.style.left = startX + 'px'; 92 fly.style.visibility = ''; 93 94 host.classList.add('casino-balance--animating'); 95 96 global.requestAnimationFrame(function () { 97 fly.classList.add('casino-balance-fly--visible'); 98 global.requestAnimationFrame(function () { 99 fly.classList.add('casino-balance-fly--pull'); 100 fly.style.left = pullX + 'px'; 101 }); 102 }); 103 104 global.setTimeout(function () { 105 fly.classList.remove('casino-balance-fly--pull'); 106 fly.classList.add('casino-balance-fly--sling'); 107 fly.style.left = endX + 'px'; 108 }, FLY_PULL_MS); 109 110 global.setTimeout(function () { 111 fly.remove(); 112 host.classList.remove('casino-balance--animating'); 113 resolve(); 114 }, FLY_TOTAL_MS); 115 }); 116 } 117 118 function popBalanceValue(root) { 119 var el = root.querySelector('[data-casino-balance]'); 120 if (!el) return; 121 el.classList.remove('casino-balance-value--pop'); 122 void el.offsetWidth; 123 el.classList.add('casino-balance-value--pop'); 124 global.setTimeout(function () { 125 el.classList.remove('casino-balance-value--pop'); 126 }, 260); 127 } 128 129 function playBalanceDelta(root, delta, newBalance) { 130 if (!root || !Number.isFinite(delta) || delta === 0 || newBalance == null) { 131 return Promise.resolve(); 132 } 133 134 var chain = balanceAnimChainByRoot.get(root) || Promise.resolve(); 135 chain = chain.then(function () { 136 animLockByRoot.set(root, true); 137 var fromBalance = newBalance - delta; 138 updateBalanceElImmediate(root, fromBalance); 139 140 return playBalanceDeltaAnim(root, delta).then(function () { 141 updateBalanceElImmediate(root, newBalance); 142 popBalanceValue(root); 143 animLockByRoot.set(root, false); 144 flushPendingBalance(root); 145 }); 146 }); 147 balanceAnimChainByRoot.set(root, chain); 148 return chain; 149 } 150 151 function afterBet(root, res) { 152 if (!res || !res.ok || res.balance == null) return Promise.resolve(); 153 var bet = Math.floor(Number(res.bet) || 0); 154 if (bet <= 0) return Promise.resolve(); 155 return playBalanceDelta(root, -bet, res.balance); 156 } 157 158 function afterPayout(root, res, amount) { 159 if (!res || !res.ok || res.balance == null) return Promise.resolve(); 160 var win = Math.floor(Number(amount != null ? amount : res.delta) || 0); 161 if (win <= 0) return Promise.resolve(); 162 return playBalanceDelta(root, win, res.balance); 163 } 164 165 function syncBetSelectionUI(root) { 166 if (!root) return; 167 var amount = getBetAmount(root); 168 var label = root.querySelector('[data-casino-bet-selected]'); 169 if (label) { 170 if (amount > 0 && global.CasinoCore.isCasinoLoggedIn()) { 171 label.textContent = 'Betting ' + global.CasinoCore.formatCoins(amount) + ' per drop'; 172 label.hidden = false;
173 } else { 174 label.hidden = true; 175 label.textContent = ''; 176 } 177 } 178 syncChipActiveFromInput(root); 179 } 180 181 function applyAuthMode(root) { 182 if (!root) return; 183 var loggedIn = global.CasinoCore.isCasinoLoggedIn(); 184 root.classList.toggle('casino--guest', !loggedIn); 185 root.classList.toggle('casino--logged-in', loggedIn); 186 187 var guestBanner = root.querySelector('[data-casino-guest-banner]'); 188 if (guestBanner) guestBanner.hidden = loggedIn; 189 190 var walletBlock = root.querySelector('[data-casino-wallet-block]'); 191 if (walletBlock) walletBlock.hidden = !loggedIn; 192 193 var claimBtn = root.querySelector('[data-casino-daily-claim]'); 194 if (claimBtn) claimBtn.hidden = !loggedIn; 195 196 var gambleBlocks = root.querySelectorAll('[data-casino-gamble]'); 197 for (var i = 0; i < gambleBlocks.length; i++) { 198 gambleBlocks[i].hidden = !loggedIn; 199 } 200 201 var playBlocks = root.querySelectorAll('[data-casino-play-only]'); 202 for (var j = 0; j < playBlocks.length; j++) { 203 playBlocks[j].hidden = loggedIn; 204 } 205 206 syncBetSelectionUI(root); 207 } 208 209 function syncDailyClaimButton(root) { 210 var btn = root.querySelector('[data-casino-daily-claim]'); 211 if (!btn || !global.CasinoCore.isCasinoLoggedIn()) return; 212 var can = global.CasinoWallet.canClaimDaily(); 213 btn.disabled = !can; 214 btn.setAttribute('aria-disabled', can ? 'false' : 'true'); 215 var label = btn.querySelector('[data-casino-claim-label]'); 216 if (label) { 217 label.textContent = can 218 ? 'Claim ' + global.CasinoCore.formatCoins(global.CasinoCore.DAILY_BONUS) + ' coins' 219 : 'Claimed today'; 220 } 221 } 222 223 function bindRoot(root) { 224 if (!root || boundRoots.indexOf(root) !== -1) return; 225 boundRoots.push(root); 226 227 applyAuthMode(root); 228 229 if (global.CasinoWallet) { 230 global.CasinoWallet.onBalance(function (balance) { 231 onWalletBalance(root, balance); 232 syncDailyClaimButton(root); 233 }); 234 } 235 236 var signInBtn = root.querySelector('[data-casino-sign-in]'); 237 if (signInBtn) { 238 signInBtn.addEventListener('click', function (e) { 239 e.preventDefault(); 240 global.CasinoCore.promptSignIn(); 241 }); 242 } 243 244 var claimBtn = root.querySelector('[data-casino-daily-claim]'); 245 if (claimBtn) { 246 claimBtn.addEventListener('click', function () { 247 if (claimBtn.disabled) return; 248 claimBtn.disabled = true; 249 global.CasinoWallet.claimDaily().then(function (res) { 250 syncDailyClaimButton(root); 251 if (res.ok) { 252 playBalanceDelta(root, global.CasinoCore.DAILY_BONUS, res.balance); 253 claimBtn.classList.add('casino-claim--pop'); 254 global.setTimeout(function () { 255 claimBtn.classList.remove('casino-claim--pop'); 256 }, 400); 257 } 258 }); 259 }); 260 } 261 262 syncDailyClaimButton(root); 263 syncBetSelectionUI(root); 264 } 265 266 function initPage(rootSelector) { 267 var root = typeof rootSelector === 'string' 268 ? document.querySelector(rootSelector) 269 : rootSelector; 270 if (!root) return; 271 bindRoot(root); 272 } 273 274 function destroy() { 275 boundRoots = []; 276 displayedBalanceByRoot = new WeakMap(); 277 balanceAnimChainByRoot = new WeakMap(); 278 animLockByRoot = new WeakMap(); 279 pendingBalanceByRoot = new WeakMap(); 280 } 281 282 function syncChipActiveFromInput(root) { 283 var input = root.querySelector('[data-casino-bet-input]'); 284 var chips = root.querySelectorAll('[data-casino-bet-chip]'); 285 if (!input || !chips.length) return; 286 var val = input.value === '' ? null : Math.floor(Number(input.value) || 0); 287 var matched = false;
288 for (var i = 0; i < chips.length; i++) { 289 var chipAmount = Math.floor(Number(chips[i].getAttribute('data-amount')) || 0); 290 var active = val !== null && chipAmount === val; 291 chips[i].classList.toggle('is-active', active); 292 chips[i].setAttribute('aria-pressed', active ? 'true' : 'false'); 293 if (active) matched = true; 294 } 295 input.classList.toggle('is-custom', val !== null && !matched); 296 } 297 298 function emitBetChange(root) { 299 if (!root) return; 300 try { 301 root.dispatchEvent(new CustomEvent('casino-bet-change', { bubbles: true })); 302 } catch (e) {} 303 } 304 305 function getBetAmount(root) { 306 var input = root.querySelector('[data-casino-bet-input]'); 307 if (input && input.value !== '') { 308 return Math.max(0, Math.floor(Number(input.value) || 0)); 309 } 310 var active = root.querySelector('[data-casino-bet-chip].is-active'); 311 if (active) return Math.floor(Number(active.getAttribute('data-amount')) || 0); 312 return 0; 313 } 314 315 function bindBetChips(root) { 316 var chips = root.querySelectorAll('[data-casino-bet-chip]'); 317 var input = root.querySelector('[data-casino-bet-input]'); 318 for (var i = 0; i < chips.length; i++) { 319 chips[i].setAttribute('aria-pressed', 'false'); 320 chips[i].addEventListener('click', function () { 321 var amount = this.getAttribute('data-amount') || ''; 322 if (input) input.value = amount; 323 syncChipActiveFromInput(root); 324 syncBetSelectionUI(root); 325 emitBetChange(root); 326 }); 327 } 328 if (input) { 329 input.addEventListener('input', function () { 330 syncChipActiveFromInput(root); 331 syncBetSelectionUI(root); 332 emitBetChange(root); 333 }); 334 input.addEventListener('change', function () { 335 var val = Math.floor(Number(input.value) || 0); 336 var min = Math.floor(Number(input.min) || 0); 337 if (input.value !== '' && val < min) { 338 input.value = String(min); 339 } 340 syncChipActiveFromInput(root); 341 syncBetSelectionUI(root); 342 emitBetChange(root); 343 }); 344 } 345 if (chips.length && !input) { 346 if (!root.querySelector('[data-casino-bet-chip].is-active')) { 347 chips[0].classList.add('is-active'); 348 } 349 } else if (chips.length && input && input.value === '') { 350 chips[0].click(); 351 } else { 352 syncChipActiveFromInput(root); 353 } 354 syncBetSelectionUI(root); 355 } 356 357 function showResult(root, message, kind) { 358 var el = root.querySelector('[data-casino-result]'); 359 if (!el) return; 360 if (!message) { 361 el.hidden = true; 362 el.textContent = ''; 363 return; 364 } 365 el.textContent = message; 366 el.className = 'casino-result casino-result--' + (kind || 'info'); 367 el.hidden = false; 368 } 369 370 global.addEventListener('usernameSet', function () { 371 for (var i = 0; i < boundRoots.length; i++) { 372 applyAuthMode(boundRoots[i]); 373 syncDailyClaimButton(boundRoots[i]); 374 syncBetSelectionUI(boundRoots[i]); 375 } 376 }); 377 378 global.CasinoShell = { 379 initPage: initPage, 380 destroy: destroy, 381 getBetAmount: getBetAmount, 382 bindBetChips: bindBetChips, 383 syncBetSelectionUI: syncBetSelectionUI, 384 showResult: showResult, 385 applyAuthMode: applyAuthMode, 386 playBalanceDelta: playBalanceDelta, 387 afterBet: afterBet, 388 afterPayout: afterPayout 389 }; 390})(typeof window !== 'undefined' ? window : this);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.