1const divInstall = document.getElementById('installContainer'); 2const butInstall = document.getElementById('butInstall'); 3 4window.addEventListener("online", function(){ 5 // console.log("Sei online!"); 6 document.body.classList.toggle('offline', false); 7}); 8window.addEventListener("offline", function(){ 9 // console.log("Oh no, connessione persa."); 10 document.body.classList.toggle('offline', true); 11}); 12 13window.addEventListener('beforeinstallprompt', (event) => { 14 // Prevent the mini-infobar from appearing on mobile. 15 event.preventDefault(); 16 console.log('ð', 'beforeinstallprompt', event); 17 // Stash the event so it can be triggered later. 18 window.deferredPrompt = event; 19 // Remove the 'hidden' class from the install button container. 20 if(divInstall)divInstall.classList.toggle('hidden', false); 21}); 22 23if(butInstall) 24 butInstall.addEventListener('click', async () => { 25 console.log('ð', 'butInstall-clicked'); 26 const promptEvent = window.deferredPrompt; 27 if (!promptEvent) { 28 // The deferred prompt isn't available. 29 return; 30 } 31 // Show the install prompt. 32 promptEvent.prompt(); 33 // Log the result 34 const result = await promptEvent.userChoice; 35 console.log('ð', 'userChoice', result); 36 // Reset the deferred prompt variable, since 37 // prompt() can only be called once. 38 window.deferredPrompt = null; 39 // Hide the install button. 40 if(divInstall)divInstall.classList.toggle('hidden', true); 41 }); 42 43window.addEventListener('appinstalled', (event) => { 44 console.log('ð', 'appinstalled', event); 45 // Clear the deferredPrompt so it can be garbage collected 46 window.deferredPrompt = null; 47 if(divInstall)divInstall.classList.toggle('hidden', true); 48}); 49 50// const apiKeyNews = 'API-KEY'; 51 52const fetchNews = async () => { 53 // const url = `http://newsapi.org/v2/everything?q=bitcoin&sortBy=publishedAt&apiKey=${apiKeyNews}`; 54 // const response = await fetch(url) 55 //response = '{}'; 56 //return response.json(); 57 console.log('sinc2'); 58 return false; 59}; 60 61function urlBase64ToUint8Array(base64String) { 62 const padding = '='.repeat((4 - base64String.length % 4) % 4); 63 const base64 = (base64String + padding) 64 .replace(/\-/g, '+') 65 .replace(/_/g, '/'); 66 67 const rawData = window.atob(base64); 68 const outputArray = new Uint8Array(rawData.length); 69 70 for (let i = 0; i < rawData.length; ++i) { 71 outputArray[i] = rawData.charCodeAt(i); 72 } 73 return outputArray; 74} 75 76 77const mainApp = async () => { 78 /* Only register a service worker if it's supported */ 79 if ('serviceWorker' in navigator) { 80 // navigator.serviceWorker.register('/service-worker.min.js'). 81 navigator.serviceWorker.register('/service-worker.js?v=1.8'). 82 then(function (registration) { 83 // Registration was successful`` 84 console.log('Registrazione ServiceWorker riuscita per: ', registration.scope); 85 const permission = Notification.permission; 86 console.log("fgp - Notifiche: "+permission); 87 if (permission === 'denied') { 88 // L'utente ha bloccato le notifiche in precedenza 89 mostraAvvisoInterfaccia("Hai disattivato le notifiche. Controlla le impostazioni del browser per ricevere gli avvisi."); 90 } else if (permission === 'default') { 91 // L'utente non ha ancora deciso (mostriamo un pulsante nell'app) 92 mostraPulsanteAttivazione(); 93 } else if (permission === 'granted') { 94 // Tutto ok, verifichiamo se l'iscrizione sul server è ancora valida 95 gestisciIscrizioneEsistente(registration); 96 } 97 /*const subscribeOptions = { 98 userVisibleOnly: true, 99 applicationServerKey: urlBase64ToUint8Array( 100 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U', 101 ), 102 }; 103 registration.pushManager.subscribe( 104 subscribeOptions 105 //{userVisibleOnly: true} 106 107 ).then( 108 function(pushSubscription) { 109 console.log("Push2: "+pushSubscription.endpoint); 110 // The push subscription details needed by the application 111 // server are now available, and can be sent to it using, 112 // for example, an XMLHttpRequest. 113 }, function(error) { 114 // During development it often helps to log errors to the 115 // console. In a production environment it might make sense to 116 // also report information about errors back to the 117 // application server.
118 console.log("Push: "+error); 119 } 120 );*/ 121 122 /*getToken(messaging, { 123 serviceWorkerRegistration: registration, 124 vapidKey: 'key' }).then((currentToken) => { 125 if(currentToken){ 126 // send token 127 console.log("Token: "+currentToken); 128 } else { 129 console.log('Token non generato. Richiedi permessi'); 130 } 131 }).catch((err) => { 132 console.log('Errore generazione token: ',err); 133 });*/ 134 }).catch(function (err) { 135 // registration failed :( 136 console.log('Registrazione ServiceWorker non riuscita: ', err); 137 }); 138 } 139 140 const news = await fetchNews(); 141 /*if (news.formattedTime) { 142 setLastFetchedDate(news.formattedTime); 143 }*/ 144 145 const articles = news.articles; 146 if (articles && articles.length) { 147 const newsElement = document.getElementById('news'); 148 if (!newsElement) return; 149 150 articles.forEach(article => { 151 newsElement.appendChild(createArticleElement(article)); 152 }); 153 } 154 155 const registration = await navigator.serviceWorker.ready; 156 // Check if periodicSync is supported 157 if ('periodicSync' in registration) { 158 // Request permission 159 const status = await navigator.permissions.query({ 160 name: 'periodic-background-sync', 161 }); 162 163 if (status.state === 'granted') { 164 try { 165 // Register new sync every 24 hours 166 await registration.periodicSync.register('news', { 167 minInterval: 1 * 1 * 60 * 1000, // 1 minuto 168 });
169 console.log('Sincronizzazione periodica in background attivata'+' '+'news'); 170 } catch(e) { 171 console.error(`Periodic background sync failed:\nx${e}`); 172 } 173 } else { 174 console.info('Periodic background sync is not granted.'); 175 } 176 } else { 177 console.log('Periodic background sync is not supported.'); 178 } 179} 180/* 181navigator.serviceWorker.ready.then(registration => { 182 if (registration.sync) { 183 console.log("Background Sync is supported."); 184 } else { 185 console.log("Background Sync isn't supported."); 186 } 187}); 188 189/*async function registerPeriodicNewsCheck() { 190 const registration = await navigator.serviceWorker.ready; 191 try { 192 await registration.periodicSync.register('fetch-news', { 193 minInterval: 24 * 60 * 60 * 1000, 194 }); 195 } catch { 196 console.log('Periodic Sync could not be registered!'); 197 } 198}*/ 199 200/** 201 * Warn the page must be served over HTTPS 202 * The `beforeinstallprompt` event won't fire if the page is served over HTTP. 203 * Installability requires a service worker with a fetch event handler, and 204 * if the page isn't served over HTTPS, the service worker won't load. 205 */ 206if (window.location.protocol === 'http:') { 207 const requireHTTPS = document.getElementById('requireHTTPS'); 208 if(requireHTTPS){ 209 const link = requireHTTPS.querySelector('a'); 210 link.href = window.location.href.replace('http://', 'https://'); 211 requireHTTPS.classList.remove('hidden'); 212 } 213} 214 215function mostraAvvisoInterfaccia(messaggio) { 216 // alert(messaggio); 217 // const alertBox = document.getElementById('alert-notifiche'); 218 const alertBox = document.getElementById('container-notifiche'); 219 if (alertBox) { 220 alertBox.innerText = messaggio; 221 alertBox.style.display = 'block'; 222 } 223} 224function mostraPulsanteAttivazione() { 225 const container = document.getElementById('container-notifiche'); 226 const btn = document.getElementById('btn-attiva-push'); 227 if (container && btn) { 228 // Mostriamo il banner 229 container.style.display = 'block'; 230 // Al click, chiediamo il permesso e iscriviamo l'utente 231 btn.onclick = async () => { 232 const permission = await Notification.requestPermission(); 233 if (permission === 'granted') { 234 console.log("Permesso concesso!"); 235 // Richiamiamo la funzione di iscrizione che abbiamo creato nei passaggi precedenti 236 const registration = await navigator.serviceWorker.ready; 237 abilitaNotifiche(registration); 238 container.style.display = 'none'; // Nascondiamo il banner 239 } else { 240 alert("Senza permessi non potrai ricevere gli avvisi in tempo reale."); 241 } 242 }; 243 } 244} 245 246async function gestisciIscrizioneEsistente(registration) { 247 try { 248 // Verifica se esiste già una sottoscrizione attiva nel browser 249 const subscription = await registration.pushManager.getSubscription(); 250 if (subscription) { 251 console.log("Sottoscrizione esistente trovata."); 252 // Opzionale: Invia comunque al server per aggiornare il database 253 // e assicurarsi che i dati non siano scaduti 254 await inviaSottoscrizioneAlServer(subscription); 255 // Nascondi eventuali pulsanti di attivazione perché siamo già attivi 256 const container = document.getElementById('container-notifiche'); 257 if (container) container.style.display = 'none'; 258 } else { 259 // Se non c'è una sottoscrizione ma avevamo i permessi, 260 // potremmo aver bisogno di ri-crearla 261 console.log("Sottoscrizione non trovata, ma i permessi sono attivi."); 262 mostraPulsanteAttivazione(); 263 } 264 } catch (error) { 265 console.error("Errore nel recupero della sottoscrizione:", error); 266 } 267} 268 269// Questa è la funzione di supporto che invia i dati al tuo file PHP 270async function inviaSottoscrizioneAlServer(subscription) { 271 // La sottoscrizione deve essere trasformata in JSON per essere inviata 272 const subJSON = JSON.stringify(subscription); 273 try { 274 const response = await fetch('/push/salva_iscrizione.php', { 275 method: 'POST', 276 headers: { 277 'Content-Type': 'application/json' 278 }, 279 body: subJSON 280 }); 281 const result = await response.json(); 282 if (result.status === 'success') { 283 console.log("Database sincronizzato con successo."); 284 } 285 } catch (error) { 286 console.error("Impossibile sincronizzare la sottoscrizione col server:", error); 287 } 288} 289 290async function abilitaNotifiche(registration) { 291 // 1. Definiamo la tua Chiave Pubblica VAPID 292 // Sostituisci questa stringa con la chiave reale generata per il tuo server 293 const key = VAPID_PUBLIC_KEY; 294 try { 295 // 2. Creiamo la sottoscrizione verso i server di Google/Mozilla/Apple 296 const subscription = await registration.pushManager.subscribe({ 297 userVisibleOnly: true, // Obbligatorio: garantisce che ogni push mostri una notifica visiva 298 applicationServerKey: urlBase64ToUint8Array(key) 299 }); 300 console.log("Iscrizione completata nel browser:", subscription); 301 // 3. Inviamo la sottoscrizione al database 302 // await inviaSottoscrizioneAlServer(subscription, CONFIG_PUSH.RUOLO, CONFIG_PUSH.ID_UTENTE); 303 await inviaSottoscrizioneAlServer(subscription); 304 alert("Notifiche attivate! Riceverai gli avvisi in tempo reale."); 305 } catch (error) { 306 if (Notification.permission === 'denied') { 307 console.error("L'utente ha bloccato le notifiche."); 308 alert("Hai bloccato le notifiche. Sbloccale dalle impostazioni del browser (icona lucchetto)."); 309 } else { 310 console.error("Errore durante l'abilitazione delle notifiche:", error); 311 alert("Errore durante l'abilitazione delle notifiche:"); 312 alert(error); 313 } 314 } 315} 316 317/** 318 * Funzione di utilità necessaria per convertire la chiave VAPID 319 * dal formato stringa a quello richiesto dal browser (Uint8Array) 320 */ 321function urlBase64ToUint8Array(base64String) { 322 const padding = '='.repeat((4 - base64String.length % 4) % 4); 323 const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/'); 324 const rawData = window.atob(base64); 325 const outputArray = new Uint8Array(rawData.length); 326 for (let i = 0; i < rawData.length; ++i) { 327 outputArray[i] = rawData.charCodeAt(i); 328 } 329 return outputArray; 330} 331 332mainApp();
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.