1(function(window, document, _undefined) { 2 "use strict"; 3 4 console.log("ð BF LiveScore: Global JS v5 Loaded..."); 5 6 XF.BFLiveScoreGlobal = XF.Element.newHandler({ 7 init: function() { 8// --- SMART CHECK: Do we need the socket? --- 9 10 // 1. Is there a scoreboard (Widget OR BBCode) on this page? 11 var widgetExists = document.querySelector('.bf-ls-wrapper'); 12 13 // 2. Is the user following any matches? 14 var hasFollows = false; 15 try { 16 var stored = localStorage.getItem('bfLiveScore_follows'); 17 if (stored) { 18 var parsed = JSON.parse(stored); 19 if (Array.isArray(parsed) && parsed.length > 0) { 20 hasFollows = true; 21 } 22 } 23 } catch(e) {} 24 25 // --- THE DECISION LOGIC --- 26 // If I am NOT looking at a scoreboard AND I am NOT following any matches... 27 // Then I have absolutely no reason to be connected. Sleep. 28 if (!widgetExists && !hasFollows) { 29 console.log("ð¤ BF LiveScore: No widget & no follows. WebSocket sleeping."); 30 return; 31 } 32 33 if (hasFollows && !widgetExists) { 34 console.log("ð BF LiveScore: User has active follows. Connecting globally for alerts."); 35 } 36 // ------------------------------------------- 37 this.setupCentrifugo(); 38 }, 39 40 setupCentrifugo: function() { 41 if (!window.bfCentrifugoConfig) return; 42 43 // Retry if library not ready 44 if (!window.Centrifuge) { 45 var self = this; 46 setTimeout(function() { self.setupCentrifugo(); }, 500); 47 return; 48 } 49 50 try { 51 // --- OLS FIX: FORCE THE CORRECT URL STRUCTURE --- 52 // If the config endpoint is just "/connection", append "/websocket" 53 var finalUrl = window.bfCentrifugoConfig.url; 54 if (finalUrl.endsWith('/connection') || finalUrl.endsWith('/connection/')) { 55 finalUrl = finalUrl.replace(/\/+$/, "") + "/websocket"; 56 } 57 // ------------------------------------------------ 58 59 console.log("ð BF LiveScore: Init Client ->", finalUrl); 60 61 // Initialize Client 62 var centrifuge = new Centrifuge(finalUrl, { 63 debug: true, 64}); 65 66 // --- Connection State Logging --- 67 centrifuge.on('connecting', function(ctx) { 68 console.log("ð BF LiveScore: Client Connecting...", ctx); 69 }); 70 71 centrifuge.on('connected', function(ctx) { 72 console.log("â BF LiveScore: Client CONNECTED! Transport:", ctx.transport); 73 }); 74 75 centrifuge.on('disconnected', function(ctx) { 76 console.error("â BF LiveScore: Client DISCONNECTED. Reason:", ctx.reason, ctx); 77 }); 78 // ------------------------------------- 79 80 var self = this; 81 82 // --- UPDATED SUBSCRIPTION CHANNEL TO MATCH CONFIG NAMESPACE --- 83 var sub = centrifuge.newSubscription('livescore_updates:feed'); 84 85 sub.on('subscribe', function(ctx) { 86 console.log('â BF LiveScore: Channel Subscribed', ctx); 87 }); 88 89 sub.on('error', function(err) { 90 console.error('â BF LiveScore: Subscription Error', err); 91 }); 92 93 sub.on('publication', function(ctx) { 94 console.log('ð© BF LiveScore: Data Received', ctx); 95 var payload = ctx.data; 96 if (payload && payload.data) payload = payload.data; 97 98 if (payload && payload.matches) { 99 self.handleUpdates(payload.matches); 100 } 101 }); 102 103 sub.subscribe(); 104 centrifuge.connect(); 105 106 window.bfCentrifugeClient = centrifuge; 107 108 } catch(e) { 109 console.error('â BF LiveScore: Init Exception', e); 110 } 111 }, 112 113 handleUpdates: function(matches) { 114 console.log("â¡ Processing " + matches.length + " matches."); 115 var event = new CustomEvent('bf-livescore-update', { detail: matches }); 116 document.dispatchEvent(event); 117 118 if (!XF.config.userId) return; 119 120 var self = this;
121 var storedFollows = []; 122 try { storedFollows = JSON.parse(localStorage.getItem('bfLiveScore_follows')) || []; } catch(e) {} 123 var followedSet = new Set(storedFollows.map(String)); 124 125 matches.forEach(function(m) { 126 if (followedSet.has(String(m.id))) { 127 self.checkForGoal(m); 128 } 129 }); 130 }, 131 132 checkForGoal: function(match) { 133 var key = 'bf_last_score_' + match.id; 134 var lastScore = sessionStorage.getItem(key); 135 var currentScore = match.score; 136 sessionStorage.setItem(key, currentScore); 137 138 if (!lastScore) return; 139 if (lastScore === currentScore) return; 140 141 if (currentScore.indexOf('-') > -1 && lastScore.indexOf('-') > -1) { 142 this.triggerCelebration(match); 143 } 144 }, 145 146 triggerCelebration: function(match) { 147 var overlay = document.getElementById('bf-goal-celebration'); 148 if (overlay) { 149 var teamSpan = overlay.querySelector('.bf-goal-team'); 150 if (teamSpan) teamSpan.textContent = match.home + " vs " + match.away; 151 overlay.classList.remove('active'); 152 void overlay.offsetWidth; 153 overlay.classList.add('active'); 154 var container = overlay.querySelector('.bf-confetti-container'); 155 if (container) this.spawnConfetti(container); 156 } 157 }, 158 159 spawnConfetti: function(container) { 160 var old = container.querySelectorAll('.bf-confetti-piece'); 161 old.forEach(function(el) { el.remove(); }); 162 var colors = ['#e74c3c', '#f1c40f', '#3498db', '#2ecc71', '#9b59b6', '#ffffff']; 163 for (var i = 0; i < 50; i++) { 164 var confetti = document.createElement('div'); 165 confetti.className = 'bf-confetti-piece'; 166 confetti.style.left = Math.random() * 100 + '%'; 167 confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; 168 confetti.style.animation = 'bf-confetti-fall ' + (Math.random() * 3 + 2) + 's linear forwards'; 169 confetti.style.animationDelay = (Math.random() * 2) + 's'; 170 container.appendChild(confetti); 171 } 172 } 173 }); 174 175 XF.Element.register('bf-livescore-global', 'XF.BFLiveScoreGlobal'); 176 177 document.addEventListener('click', function(e) { 178 var overlay = document.getElementById('bf-ls-global-overlay'); 179 if (overlay && (e.target.closest('.bf-ls-modal-close') || e.target === overlay)) { 180 e.preventDefault(); 181 overlay.classList.remove('active'); 182 document.body.style.overflow = ''; 183 } 184 }); 185 document.addEventListener('keydown', function(e) { 186 if (e.key === "Escape" || e.key === "Esc") { 187 var overlay = document.getElementById('bf-ls-global-overlay'); 188 if (overlay && overlay.classList.contains('active')) { 189 e.preventDefault(); 190 overlay.classList.remove('active'); 191 document.body.style.overflow = ''; 192 } 193 } 194 }); 195 196})(window, document);
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.