1(function () { 2 function webAppDetection() { 3 var s = this; 4 this.isAndroid = function () { 5 try { 6 return /Android/.test(window.navigator.userAgent); 7 } catch (t) { 8 return false; 9 } 10 }; 11 this.isIOS = function () { 12 try { 13 var e = ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"]; 14 return e.includes(navigator.platform) || (navigator.userAgent.includes("Mac") && "ontouchend" in document); 15 } catch (i) { 16 return false; 17 } 18 }; 19 this.isMacOs = function () { 20 try { 21 return window.navigator.platform.toLowerCase().includes("mac") && !s.isIOS(); 22 } catch (e) { 23 return false; 24 } 25 }; 26 this.isWindows = function () { 27 try { 28 return window.navigator.platform.toLowerCase().includes("win"); 29 } catch (e) { 30 return false; 31 } 32 }; 33 this.isSafari = function () { 34 try { 35 return navigator.vendor && navigator.vendor.includes("Apple") && navigator.userAgent && !navigator.userAgent.includes("CriOS") && !navigator.userAgent.includes("FxiOS") && !navigator.userAgent.includes("EdgiOS"); 36 } catch (e) { 37 return false; 38 } 39 }; 40 this.isFirefox = function () { 41 try { 42 var e = navigator.userAgent.toLowerCase().includes("firefox"); 43 if (!e) return false; 44 var t = window.navigator.platform.toLowerCase(); 45 return t.includes("mac") || t.includes("win"); 46 } catch (a) { 47 return false; 48 } 49 }; 50 this.isSamsungInternet = function () { 51 try { 52 return navigator.userAgent.toLowerCase().includes("samsungbrowser"); 53 } catch (e) { 54 return false; 55 } 56 }; 57 this.isChromeEdgeOnMacOs = function () { 58 try { 59 return navigator.vendor.toLowerCase().includes("google") && window.navigator.platform.toLowerCase().includes("mac"); 60 } catch (e) { 61 return false; 62 } 63 }; 64 this.isArc = function () { 65 try { 66 return getComputedStyle(document.documentElement).getPropertyValue("--arc-palette-title"); 67 } catch (e) { 68 return false; 69 } 70 }; 71 this.isEdge = function () { 72 try { 73 return window.navigator.userAgent.includes("Edge") || window.navigator.userAgent.includes("Edg/") || window.navigator.userAgent.includes("EdgiOS"); 74 } catch (e) { 75 return false; 76 } 77 }; 78 this.isChrome = function () { 79 try { 80 var e = window.navigator.userAgent.toLowerCase(); 81 var t = window.chrome || e.includes("chrome"); 82 if (!t) return false; 83 if (s.isEdge()) return false; 84 if (e.includes("opr")) return false; 85 if (s.isArc()) return false; 86 return true; 87 } catch (r) { 88 return false; 89 } 90 }; 91 this.isOpera = function () { 92 try { 93 return window.navigator.userAgent.toLowerCase().includes("opr"); 94 } catch (e) { 95 return false; 96 } 97 }; 98 this.supportsNativeiOSPush = function () { 99 return window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers["progressier-requests-push-status"]; 100 }; 101 this.appstore = function () { 102 return s.supportsNativeiOSPush(); 103 }; 104 this.supportsPush = function () { 105 if (s.supportsNativeiOSPush()) return true; 106 return window.PushManager && navigator.serviceWorker && window.Notification; 107 }; 108 this.isFromTwitter = function () { 109 if (s.definitelyNotTwitter) return false; 110 if (!s.isIOS() && !s.isAndroid()) return false; 111 if (s.isIOS() && !s.isSafari()) return false; 112 return document.referrer.includes("https://t.co") || window.location.href.includes("progressierreferrer=twitter"); 113 }; 114 this.isInAppBrowser = function () { 115 try { 116 var t = window.navigator.userAgent; 117 var e = ["wv", "Line/", "FBAN", "FBBV", "FBAV", "FB_IAB", "Instagram", "MicroMessenger", "Twitter", "Kakao", "KAKAO"]; 118 return e.some(function (e) { 119 return t.includes(e); 120 }); 121 } catch (a) { 122 return false;
123 } 124 }; 125 this.isChromeOS = function () { 126 try { 127 return window.navigator.platform.toLowerCase().includes("linux") && window.navigator.userAgent.toLowerCase().includes("cros"); 128 } catch (e) { 129 return false; 130 } 131 }; 132 this.isDesktop = function () { 133 try { 134 if (s.isWindows()) return true; 135 if (s.isIOS() || s.isAndroid()) return false; 136 if (s.isMacOs() || s.isChromeOS()) return true; 137 return false; 138 } catch (e) { 139 return false; 140 } 141 }; 142 this.isSafariWithPushOnMacOs = function () { 143 return s.isSafari() && s.isMacOs() && s.supportsPush(); 144 }; 145 this.isSafariWithInstallationMacOS = function () { 146 try { 147 if (!s.isSafari() || !s.isMacOs()) return false; 148 var e = navigator.userAgent; 149 if (!/Safari\//i.test(e)) return false; 150 var t = e.match(/Version\/(\d+)/i); 151 if (t && t[1]) return parseInt(t[1], 10) >= 17; 152 return false; 153 } catch (n) { 154 return false; 155 } 156 }; 157 this.canBePushPrompted = function () { 158 if (!s.isIOS() && !s.isAndroid()) return false; 159 if (!s.supportsPush()) return false; 160 var e = Notification.permission; 161 return e !== "denied" && e !== "granted"; 162 }; 163 this.isStandalone = function () { 164 return navigator.standalone || window.matchMedia("(display-mode: standalone)").matches || (window.matchMedia("(display-mode: fullscreen)").matches && (s.isAndroid() || s.isIOS())) || window.matchMedia("(display-mode: minimal-ui)").matches || window.matchMedia("(display-mode: window-controls-overlay)").matches; 165 }; 166 this.iosVersion = function () { 167 if (!s.isIOS()) return false; 168 var e = navigator.userAgent; 169 if (!/iP(hone|od|ad)/.test(e)) return false; 170 var t = e.match(/OS (\d+)_(\d+)_?(\d+)?/); 171 if (!t || !t[1]) return false; 172 return parseFloat(t[1] + "." + (t[2] || 0)); 173 }; 174 this.recentiOS = function () { 175 try { 176 let e = s.iosVersion(); 177 if (!e || e < 16.7) return false; 178 let t = navigator.userAgent.match(/CriOS\/(\d+)/); 179 if (!t) return false; 180 return parseInt(t[1], 10) >= 116; 181 } catch (e) { 182 return false; 183 } 184 }; 185 this.isTWA = function () { 186 if (!s.isAndroid() || !s.isStandalone()) return false; 187 try { 188 if (document.referrer.startsWith("android-app://") || window.sessionStorage.getItem("opened-from-twa")) { 189 window.sessionStorage.setItem("opened-from-twa", true); 190 return true; 191 } 192 } catch (e) {} 193 return false; 194 }; 195 this.requiresInScopeSw = function () { 196 try { 197 if (s.isIOS() || s.isSafari() || s.isFirefox() || s.isOpera() || s.isArc()) return false; 198 if (s.isSamsungInternet()) return true; 199 let e = window.navigator.userAgent; 200 let t = e.match(/Chrome\/(\d+)/); 201 let i = parseInt(t[1]); 202 if (i >= 111 && e.includes("Android")) return false; 203 return i < 114; 204 } catch (e) { 205 return true; 206 } 207 }; 208 this.isIframe = function () { 209 try { 210 return window.self !== window.top; 211 } catch (e) { 212 return true; 213 } 214 }; 215 try { 216 s.result = {}; 217 for (var e in s) { 218 if (typeof s[e] === "function") s.result[e] = s[e](); 219 } 220 } catch (t) {} 221 } 222 223 var obj = { 224 installable: false, 225 standalone: false, 226 detection: new webAppDetection(), 227 emit: function (event, data) { 228 const e = new CustomEvent(event, data); 229 window.dispatchEvent(e); 230 }, 231 install: function () { 232 if (obj.nativePrompt) { 233 obj.nativePrompt.prompt(); 234 obj.nativePrompt.userChoice.then(function (choiceResult) { 235 if (choiceResult.outcome === "accepted") { 236 localStorage.setItem("webAppInstalled", 'true'); 237 } 238 }); 239 } 240 } 241 } 242 243 function installPromptHandler(e) { 244 obj.nativePrompt = e; 245 obj.installable = true; 246 localStorage.setItem("webAppAvailable", 'true'); 247 } 248 249 window.addEventListener("beforeinstallprompt", installPromptHandler); 250 251 function generateWebIcon() { 252 let icon512 = ''; 253 let icon192 = ''; 254 window.webAppManifestSettings.icons.forEach(icon => { 255 if (icon.sizes === '512x512') { 256 icon512 = icon.src; 257 } else if (icon.sizes === '192x192') { 258 icon192 = icon.src; 259 } 260 }) 261 } 262 263 function createManifestLink() {
264 if ("webAppManifestSettings" in window) { 265 const manifest = JSON.stringify(window.webAppManifestSettings) 266 let link = document.createElement("link") 267 link.rel = "manifest" 268 link.href = "data:text/json;charset=utf-8," + encodeURIComponent(manifest) 269 270 const existingManifest = document.querySelector('link[rel="manifest"]') 271 if (existingManifest) { 272 document.head.replaceChild(link, existingManifest) 273 } else { 274 document.head.appendChild(link) 275 } 276 } 277 } 278 279 async function generateStartupImageBase64(src, backgroundColor, width, height) { 280 return new Promise((resolve, reject) => { 281 const canvas = document.createElement('canvas'); 282 canvas.width = width; 283 canvas.height = height; 284 const ctx = canvas.getContext('2d'); 285 const imgSize = width > height ? height : width; 286 287 ctx.fillStyle = backgroundColor; 288 ctx.fillRect(0, 0, width, height); 289 290 const img = new Image(); 291 img.crossOrigin = "anonymous"; 292 img.onload = () => { 293 const x = (width - imgSize/3) / 2; 294 const y = (height - imgSize/3) / 2; 295 ctx.drawImage(img, x, y, imgSize/3, imgSize/3); 296 resolve(canvas.toDataURL()); 297 }; 298 img.onerror = reject; 299 img.src = src; 300 }); 301 } 302 303 async function createIosStartupLink() { 304 const isIOS = obj.detection.isIOS(); 305 if (isIOS && window.webAppManifestSettings.icons.length > 0) { 306 const screenWidth = window.screen.width * 2; 307 const screenHeight = window.screen.height * 2; 308 const color = window.webAppManifestSettings.background_color; 309 const icon = window.webAppManifestSettings.icons.find(icon => icon.sizes === '512x512'); 310 311 if (icon && color) { 312 const portraitImage = await generateStartupImageBase64(icon.src, color, screenWidth, screenHeight); 313 const landscapeImage = await generateStartupImageBase64(icon.src, color, screenHeight, screenWidth); 314 315 const portraitLink = document.createElement('link'); 316 portraitLink.rel = 'apple-touch-startup-image'; 317 portraitLink.media = `screen and (device-width: ${screenWidth/2}px) and (device-height: ${screenHeight/2}px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)`; 318 portraitLink.href = portraitImage; 319 document.head.appendChild(portraitLink); 320 321 const landscapeLink = document.createElement('link'); 322 landscapeLink.rel = 'apple-touch-startup-image'; 323 landscapeLink.media = `screen and (device-width: ${screenWidth/2}px) and (device-height: ${screenHeight/2}px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)`; 324 landscapeLink.href = landscapeImage; 325 document.head.appendChild(landscapeLink); 326 } 327 } 328 } 329 330 function checkStandalone() { 331 const isIOS = obj.detection.isIOS(); 332 const standalone = obj.detection.isStandalone(); 333 if (standalone && !isIOS) 334 localStorage.setItem("webAppInstalled", 'true'); 335 } 336 337 function checkWebApp(pollTimes = 20, duration = 300) { 338 return new Promise((resolve, _reject) => { 339 let times = 0; 340 const interval = setInterval(() => { 341 const available = localStorage.getItem("webAppAvailable") === "true"; 342 const installed = localStorage.getItem("webAppInstalled") === "true"; 343 344 if (obj.installable || available && !installed || obj.detection.isIOS() && obj.detection.isSafari()) { 345 clearInterval(interval); 346 obj.emit("webAppDetected", obj.nativePrompt); 347 localStorage.setItem("webAppInstalled", 'false'); 348 window.removeEventListener("beforeinstallprompt", installPromptHandler); 349 resolve(true); 350 } 351 352 times++; 353 if (times >= pollTimes) { 354 clearInterval(interval); 355 window.removeEventListener("beforeinstallprompt", installPromptHandler); 356 if (installed) { 357 obj.emit("webAppDetected", { detail :'launchAllowed' }); 358 } else { 359 localStorage.setItem("webAppUnavailable", 'true'); 360 obj.emit("webAppDetected", { detail: 'unavailable'}); 361 } 362 resolve(false); 363 } 364 }, duration); 365 }); 366 }; 367
368 function init() { 369 if(!obj.detection.isSamsungInternet()) createManifestLink(); 370 createIosStartupLink(); 371 generateWebIcon(); 372 checkWebApp(); 373 checkStandalone(); 374 } 375 376 init(); 377})();
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.