1import * as c from './config.js'; 2 3let deferredPrompt; // Initialize deferredPrompt for use later to show browser install prompt. 4 5/****************** Install and Update *******************************/ 6 7// Verhindert automatischen Install Prompt und zeigt Install Button an (Nicht IOS) 8export function beforeInstallPrompt(event) { 9 event.preventDefault(); // kleine infobar nicht anzeigen 10 console.log('beforeinstallprompt fired'); 11 deferredPrompt = event; 12 13 if (localStorage.getItem("closedPWAInstallBanner") != "true") { 14 showClass(c.get('pwaInstallBanner')); 15 Array.from(c.getByClass('pwaInstallBut')).forEach(function(element) { 16 element.addEventListener('click', showInstallation); 17 }); 18 19 Array.from(c.getByClass('pwaInstallBannerClose')).forEach(function(element) { 20 element.addEventListener('click', function (e) { 21 hideClass(c.get('pwaInstallBanner')); 22 localStorage.setItem("closedPWAInstallBanner", "true");}); 23 }); 24 } 25 26 return false; 27} 28 29// Da kein Install Prompt bei IOS gibt es hier eine gesonderte Abfrage 30export function checkIOSInstall() { 31 if (isIos() && !isInStandaloneMode()) { 32 console.log('Detect installable IOS'); 33 if (localStorage.getItem("closedpwaInstallBannerIOS") != "true") { 34 showClass(c.get('pwaInstallBannerIOS')); 35 Array.from(c.getByClass('pwaInstallBannerIOSClose')).forEach(function(element) { 36 element.addEventListener('click', function (e) { 37 hideClass(c.get('pwaInstallBannerIOS')); 38 localStorage.setItem("closedpwaInstallBannerIOS", "true");}); 39 }); 40 } 41 } 42} 43 44// Detects if device is on iOS 45export const isIos = () => { 46 const userAgent = window.navigator.userAgent.toLowerCase(); 47 48 // Traditional detection 49 if (/iphone|ipad|ipod/.test(userAgent)) { 50 return true; 51 } 52 53 // Additional check for iPadOS in desktop mode 54 if (/macintosh/.test(userAgent) && 'ontouchend' in document) { 55 return true; 56 } 57 58 return false; 59} 60// Checks if should display install popup notification: 61export const isInStandaloneMode = () => ('standalone' in window.navigator) && (window.navigator.standalone); 62 63// Installation durch Button klick aufgerufen 64export function showInstallation() { 65 console.log('ð', 'Install geklickt'); 66 if (!deferredPrompt) {return;} 67 deferredPrompt.prompt(); // Show the install prompt. 68 deferredPrompt.userChoice.then(function(choiceResult) { 69 console.log(choiceResult.outcome); 70 if (choiceResult.outcome === 'dismissed') { 71 console.log('User cancelled installation'); 72 } else { 73 console.log('User added to home screen'); 74 } 75 }); 76 // Hide the install button. 77 hideClass(c.get('pwaInstallBanner')); 78 hideClass(c.get('pwaInstallBannerIOS')); 79} 80 81// Wird nach der Installation aufgerufen 82export function appinstalled(event) { 83 console.log('ð', 'appinstalled', event); 84 // Platz Für Installations Counter 85 hideClass(c.get('pwaInstallBanner')); 86 hideClass(c.get('pwaInstallBannerIOS')); 87 deferredPrompt = null; 88} 89 90//Erkennt ob ein Neuer Service Worker auf Aktivierung wartet 91export function invokeServiceWorkerUpdateFlow(registration) { 92 console.log("New Service Worker waiting"); 93 let uuid = c.getUUID(); 94 showClass(c.get('pwaUpdateBanner')); 95 Array.from(c.getByClass('pwaUpdateBut')).forEach(function(element) { 96 element.addEventListener('click', async () => { 97 if (registration.waiting) { 98 // let waiting Service Worker know it should became active 99 registration.waiting.postMessage(JSON.stringify({uuid, cmd: 'setPushUUID'})); 100 registration.waiting.postMessage(JSON.stringify({cmd: 'SKIP_WAITING'})); 101 } 102 }) 103 }) 104} 105 106/****************** Notification *******************************/ 107 108/* Notification Permission */ 109export function askForNotificationPermission() { 110 Notification.requestPermission(function(result) { 111 console.log('Permission result:', result); 112 113 if (result === "granted") { 114 hideClass(c.get('enableNotifications')); 115 showClass(c.get('pwaCategories')); 116 configurePushSub(); 117 } else { 118 // Handle denial (including iOS soft denial) 119 const denialCount = parseInt(localStorage.getItem('notificationDenials') || '0') + 1; 120 localStorage.setItem('notificationDenials', denialCount.toString()); 121 122 if (denialCount >= 2) { 123 // After 2 attempts, treat as denied 124 hideClass(c.get('enableNotifications')); 125 showClass(c.get('blockedNotifications')); 126 localStorage.setItem("closedEnableNotification", "true"); 127 } else { 128 // Show message but keep button available 129 console.log('Permission denied, attempt:', denialCount); 130 // Optionally show a message to user about trying again 131 } 132 } 133 }); 134}; 135 136export async function configurePushSub() { 137 if (!('serviceWorker' in navigator)) return; 138 try { 139 const reg = await navigator.serviceWorker.ready; 140 const sub = await reg.pushManager.getSubscription(); 141 if (sub === null) { 142 const PublicKeyResponse = await fetch('/output/pwa/get_wpnPublicServerKey.php'); 143 const {key:wpnPublicServerKey} = await PublicKeyResponse.json(); 144 if (typeof wpnPublicServerKey !== 'string' || wpnPublicServerKey.length < 10) { 145 throw new Error('Bad Result from /output/pwa/get_wpnPublicServerKey.php'); 146 } 147 const applicationServerKey = urlB64ToUint8Array(wpnPublicServerKey); 148 const options = {userVisibleOnly: true, applicationServerKey: applicationServerKey}; 149 const newsub = await reg.pushManager.subscribe(options); 150 const {OK:code} = await saveSubscription(newsub); 151 console.log(code); 152 if (code == "200") { 153 reg.showNotification('Erfolgreich aktiviert!', {body: 'Benachrichtigungen erfolgreich aktiviert!',dir: 'ltr',lang: 'en-US', vibrate: [100, 50, 200]}); 154 console.log('Sent Notification 1'); 155 window.location = c.get('redirectNavID'); 156 } else { 157 console.log("Fehler") 158 } 159 } else { 160 console.log("Anmeldung existiert"); 161 window.location = c.get('redirectNavID'); 162 } 163 } catch (error) { 164 console.error(error); 165 } 166} 167 168/* For Key Generation*/ 169export const urlB64ToUint8Array = base64String => { 170 const padding = '='.repeat((4 - (base64String.length % 4)) % 4) 171 const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/') 172 const rawData = atob(base64) 173 const outputArray = new Uint8Array(rawData.length) 174 for (let i = 0; i < rawData.length; ++i) { 175 outputArray[i] = rawData.charCodeAt(i) 176 } 177 return outputArray 178}; 179 180/* Save Subcription */ 181export const saveSubscription = async (subscription) => { 182 let uuid = c.getUUID(); 183 subscription = JSON.stringify(subscription); 184 subscription = JSON.parse(subscription); 185 console.log(subscription.keys.auth); 186 let formData = new FormData(); 187 formData.append('endpoint', subscription.endpoint); 188 formData.append('p256dh', subscription.keys.p256dh); 189 formData.append('auth', subscription.keys.auth); 190 formData.append('uuid', uuid); 191 const response = await fetch('/output/pwa/saveSubscription.php', { 192 method: 'post', 193 body: formData, 194 }); 195 console.log(response); 196 return response.json(); 197}; 198 199/* Notify From Browser */ 200export function notifyMe() { 201 console.log("NotifyMe"); 202 if (!("Notification" in window)) { 203 // Check if the browser supports notifications 204 console.log('Dieser Browser Unterstüzt keine Notification'); 205 } else if (Notification.permission === "granted") { 206 // Check whether notification permissions have already been granted; 207 // if so, create a notification 208 console.log('Sent Notification'); 209 if ('serviceWorker' in navigator) { 210 var options = { 211 body: 'You successfully subscribed to our Notification service!', 212 dir: 'ltr', 213 lang: 'en-US', // BCP 47, 214 vibrate: [100, 50, 200], 215 }; 216 navigator.serviceWorker.ready 217 .then(function(swreg) { 218 console.log('Subscribe Notification'); 219 swreg.showNotification('Successfully subscribed (from SW)!', options); 220 }); 221 } 222 } else if (Notification.permission !== "denied") { 223 // We need to ask the user for permission 224 Notification.requestPermission().then((permission) => { 225 // If the user accepts, let's create a notification 226 if (permission === "granted") { 227 console.log('Sent Notification'); 228 const notification = new Notification("You successfully subscribed to our Notification service!"); 229 // ⦠230 } 231 }); 232 } 233} 234 235/****************** HELPER *******************************/ 236 237export function hideClass(data) { 238 console.log("hide: ",data); 239 let dataClass = document.querySelectorAll(data);
240 Array.from(dataClass).forEach(function(element) { 241 element.style.display = "none"; 242 }); 243} 244 245export function showClass(data) { 246 console.log("show: ",data); 247 let dataClass = document.querySelectorAll(data); 248 Array.from(dataClass).forEach(function(element) { 249 element.style.display = "inline-block"; 250 }); 251} 252 253/* Noch nicht verwendete Möglichkeiten */ 254//Möglichkeit den Display Modus zu tracken 255// Noch nicht aufgerufen 256export function getPWADisplayMode() { 257 const isStandalone = window.matchMedia('(display-mode: standalone)').matches; 258 if (document.referrer.startsWith('android-app://')) { 259 return 'twa'; 260 } else if (navigator.standalone || isStandalone) { 261 return 'standalone'; 262 } 263 return 'browser'; 264} 265 266window.matchMedia('(display-mode: standalone)').addEventListener('change', (evt) => { 267 let displayMode = 'browser'; 268 if (evt.matches) { 269 displayMode = 'standalone'; 270 } 271 // Log display mode change to analytics 272 console.log('DISPLAY_MODE_CHANGED', displayMode); 273}); 274 275 276 277 278 279 280
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.