1// ---- Element refs ---- 2const buttonInstall = document.getElementById('buttonInstall'); 3const buttonMobileInstall = document.getElementById('buttonMobileInstall'); 4const addToHomeBtn = document.getElementById('addToHomeBtn'); 5const iosHint = document.getElementById('iosHint'); 6const genericHint = document.getElementById('genericHint'); 7const firefoxHint = document.getElementById('firefoxHint'); 8const toast = document.getElementById('toast'); 9const heading = document.getElementById('heading'); 10const subtext = document.getElementById('subtext'); 11 12// iOS / Firefox manual-instructions banner 13const iosBanner = document.getElementById('iosInstallBanner'); 14const firefoxBanner = document.getElementById('firefoxInstallBanner'); 15 16let deferredPrompt = null; 17let beforeInstallPromptFired = false; 18 19const isStandalone = window.matchMedia('(display-mode: standalone)').matches 20 || window.navigator.standalone === true; 21const ua = window.navigator.userAgent.toLowerCase(); 22const isIOS = /iphone|ipad|ipod/.test(ua); 23const isFirefox = ua.includes('firefox') && ua.includes('android'); 24const isOpera = ua.includes('opera') && ua.includes('android'); 25const isOnPwaForm = window.location.pathname.includes('pwa-form'); 26 27function setPWAInstalledCookie() { 28 document.cookie = 'afbggPWAApp=1; path=/; max-age=31536000; SameSite=Lax'; 29} 30 31function showToast(msg) { 32 if (!toast) return; 33 toast.textContent = msg; 34 toast.classList.add('show'); 35 setTimeout(() => toast.classList.remove('show'), 3200); 36} 37function showInstallPromotion() { 38 if (buttonInstall) buttonInstall.style.display = 'block'; 39 if (buttonMobileInstall) buttonMobileInstall.style.display = 'block'; 40} 41function hideInstallPromotion() { 42 if (buttonInstall) buttonInstall.style.display = 'none'; 43 if (buttonMobileInstall) buttonMobileInstall.style.display = 'none'; 44} 45 46// Hide install buttons by default until we know install is available 47hideInstallPromotion(); 48 49window.addEventListener('beforeinstallprompt', (event) => { 50 event.preventDefault(); 51 deferredPrompt = event; 52 beforeInstallPromptFired = true; 53 showInstallPromotion(); 54 if (beforeInstallPromptFired && addToHomeBtn) { 55 addToHomeBtn.disabled = false; 56 } 57 console.debug("'beforeinstallprompt' event was fired."); 58}); 59 60 61//special handle for these browser, cause it no support PWA 62//if ((isFirefox || isIOS || isOpera) && !isStandalone) { 63// beforeInstallPromptFired = true; 64// if (addToHomeBtn) { 65// addToHomeBtn.disabled = false; 66// } 67//} 68 69window.addEventListener('appinstalled', () => { 70 setPWAInstalledCookie(); 71 showToast('Installed. Look for the icon on your home screen.'); 72 if (heading) heading.textContent = heading.dataset.langHeadingintsall; 73 if (subtext) subtext.textContent = subtext.dataset.langSubtextintsall; 74 if (addToHomeBtn) { 75 addToHomeBtn.textContent = addToHomeBtn.dataset.langAlreadyintsall; 76 addToHomeBtn.disabled = true; 77 } 78}); 79 80// ---- Redirect to pwa-form ---- 81//window.addEventListener('load', () => { 82// setTimeout(() => { 83// if (beforeInstallPromptFired && !isOnPwaForm) { 84// window.location.href = window.location.origin + '/pwa-form'; 85// } 86// }, 1000); 87//}); 88 89// ---- Click handler ---- 90if (addToHomeBtn) { 91 addToHomeBtn.addEventListener('click', async () => { 92 console.log(deferredPrompt) 93 if (deferredPrompt) { 94 hideInstallPromotion(); 95 deferredPrompt.prompt(); 96 const { outcome } = await deferredPrompt.userChoice; 97 console.debug('User response to the install prompt:', outcome); 98 deferredPrompt = null; 99 100 if (outcome === 'accepted') { 101 setPWAInstalledCookie(); 102 showToast('Installed. Look for the icon on your home screen.'); 103 } 104 } else if (isIOS) { 105 iosHint?.classList.remove('hidden'); 106 firefoxHint?.classList.add('hidden'); 107 genericHint?.classList.add('hidden'); 108 } else if (isFirefox) { 109 iosHint?.classList.add('hidden'); 110 genericHint?.classList.add('hidden'); 111 firefoxHint?.classList.remove('hidden'); 112 } else { 113 genericHint?.classList.remove('hidden'); 114 firefoxHint?.classList.add('hidden'); 115 iosHint?.classList.add('hidden'); 116 showToast('Getting things ready â try again in a moment.'); 117 } 118 }); 119} 120 121if (buttonInstall) { 122 buttonInstall.addEventListener('click', async () => { 123 console.log(deferredPrompt) 124 if (deferredPrompt) { 125 hideInstallPromotion(); 126 deferredPrompt.prompt(); 127 const { outcome } = await deferredPrompt.userChoice; 128 console.debug('User response to the install prompt:', outcome); 129 deferredPrompt = null; 130 } 131 }) 132} 133 134if (buttonMobileInstall) { 135 buttonMobileInstall.addEventListener('click', async () => { 136 console.log(deferredPrompt) 137 if (deferredPrompt) { 138 hideInstallPromotion(); 139 deferredPrompt.prompt(); 140 const { outcome } = await deferredPrompt.userChoice; 141 console.debug('User response to the install prompt:', outcome); 142 deferredPrompt = null; 143 } 144 }) 145} 146 147if (isStandalone) { 148 setPWAInstalledCookie(); 149 if (heading) heading.textContent = heading.dataset.langHeadingintsall; 150 if (subtext) subtext.textContent = subtext.dataset.langSubtextintsall;
151 if (addToHomeBtn) { 152 addToHomeBtn.textContent = addToHomeBtn.dataset.langAlreadyintsall; 153 addToHomeBtn.disabled = true; 154 } 155} 156 157 158// ============================================================ 159// iOS Safari â no beforeinstallprompt support, show manual banner 160// ============================================================ 161function dismissIosBanner() { 162 if (iosBanner) iosBanner.style.display = 'none'; 163 localStorage.setItem('iosInstallDismissedAt', Date.now().toString()); 164} 165// Expose globally so the inline onclick in the banner HTML can call it 166window.dismissIosBanner = dismissIosBanner; 167 168// Hide iOS banner by default, same pattern as Android/Desktop buttons 169if (iosBanner) iosBanner.style.display = 'none'; 170 171if (isIOS && !isRunningStandalone) { 172 const dismissedAt = localStorage.getItem('iosInstallDismissedAt'); 173 const sevenDaysMs = 7 * 24 * 60 * 60 * 1000; 174 const recentlyDismissed = dismissedAt && (Date.now() - Number(dismissedAt) < sevenDaysMs); 175 176 if (!recentlyDismissed && iosBanner) { 177 iosBanner.style.display = 'flex'; 178 console.debug('Showing iOS manual install banner.'); 179 } 180} 181 182// ============================================================ 183// Firefox (Desktop + Android) â no beforeinstallprompt support either 184// ============================================================ 185 186function dismissFirefoxBanner() { 187 if (firefoxBanner) firefoxBanner.style.display = 'none'; 188 localStorage.setItem('firefoxInstallDismissedAt', Date.now().toString()); 189} 190// Expose globally so the inline onclick in the banner HTML can call it 191window.dismissFirefoxBanner = dismissFirefoxBanner; 192 193// Hide Firefox banner by default, same pattern as the others 194if (firefoxBanner) firefoxBanner.style.display = 'none'; 195 196if (isFirefox && !isRunningStandalone) { 197 const dismissedAt = localStorage.getItem('firefoxInstallDismissedAt'); 198 const sevenDaysMs = 7 * 24 * 60 * 60 * 1000; 199 const recentlyDismissed = dismissedAt && (Date.now() - Number(dismissedAt) < sevenDaysMs); 200 201 if (!recentlyDismissed && firefoxBanner) { 202 firefoxBanner.style.display = 'flex'; 203 console.debug('Showing Firefox manual install banner.'); 204 } 205}
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.