1(function () { 2 "use strict"; 3 4 var CFG = window.SUMAHODEHOKEN_INSTALL_PROMPT || {}; 5 var mobileQuery = window.matchMedia("(max-width: 767px)"); 6 var promptEvent = null; 7 var promptEl = null; 8 var showTimer = null; 9 var serviceWorkerRegistration = null; 10 var serviceWorkerError = null; 11 12 registerServiceWorker(); 13 14 window.addEventListener("beforeinstallprompt", function (event) { 15 event.preventDefault(); 16 promptEvent = event; 17 logConditions("beforeinstallprompt received"); 18 scheduleShow(); 19 }); 20 21 window.addEventListener("appinstalled", function () { 22 logConditions("appinstalled received"); 23 dismiss(30); 24 }); 25 26 document.addEventListener("DOMContentLoaded", function () { 27 promptEl = document.getElementById("site-install-prompt"); 28 if (!promptEl) return; 29 30 var closeBtn = promptEl.querySelector("[data-install-prompt-close]"); 31 var actionBtn = promptEl.querySelector("[data-install-prompt-action]"); 32 33 if (closeBtn) { 34 closeBtn.addEventListener("click", function () { 35 dismiss(Number(CFG.dismissDays) || 7); 36 }); 37 } 38 39 if (actionBtn) { 40 actionBtn.addEventListener("click", onInstallClick); 41 } 42 43 logConditions("DOMContentLoaded"); 44 setTimeout(function () { 45 logConditions("35 seconds after DOMContentLoaded"); 46 }, 35000); 47 48 if (promptEvent) scheduleShow(); 49 50 if (mobileQuery.addEventListener) { 51 mobileQuery.addEventListener("change", function () { 52 logConditions("viewport changed"); 53 if (mobileQuery.matches) scheduleShow(); 54 else hide(); 55 }); 56 } 57 }); 58 59 function scheduleShow() { 60 if (!shouldShow()) return; 61 clearTimeout(showTimer); 62 showTimer = setTimeout(show, Number(CFG.showDelay) || 1200); 63 } 64 65 function shouldShow() { 66 return !!promptEl && !!promptEvent && mobileQuery.matches && !isStandalone() && !isDismissed(); 67 } 68 69 function logConditions(stage) { 70 var standalone = isStandalone(); 71 var dismissed = isDismissed(); 72 var status = { 73 stage: stage, 74 secureContext: window.isSecureContext, 75 promptElementFound: !!promptEl, 76 mobileViewport: mobileQuery.matches, 77 viewportWidth: window.innerWidth, 78 standaloneMode: standalone,
79 dismissalActive: dismissed, 80 serviceWorkerSupported: "serviceWorker" in window.navigator, 81 serviceWorkerRegistered: !!serviceWorkerRegistration, 82 serviceWorkerControlled: !!(window.navigator.serviceWorker && window.navigator.serviceWorker.controller), 83 serviceWorkerState: getServiceWorkerState(), 84 serviceWorkerError: serviceWorkerError, 85 beforeInstallPromptReceived: !!promptEvent, 86 displayEligible: !!promptEl && !!promptEvent && mobileQuery.matches && !standalone && !dismissed 87 }; 88 89 console.log("[Install Prompt Debug]", status); 90 } 91 92 function registerServiceWorker() { 93 if (!("serviceWorker" in window.navigator) || !CFG.serviceWorkerUrl) { 94 serviceWorkerError = "Service Worker is not supported or its URL is missing."; 95 return; 96 } 97 98 window.navigator.serviceWorker.addEventListener("controllerchange", function () { 99 logConditions("service worker controller changed"); 100 }); 101 102 window.navigator.serviceWorker.register(CFG.serviceWorkerUrl, { 103 scope: CFG.serviceWorkerScope || "/" 104 }).then(function (registration) { 105 serviceWorkerRegistration = registration; 106 serviceWorkerError = null; 107 logConditions("service worker registered"); 108 return window.navigator.serviceWorker.ready; 109 }).then(function (registration) { 110 serviceWorkerRegistration = registration; 111 logConditions("service worker ready"); 112 }).catch(function (error) { 113 serviceWorkerError = error && error.message ? error.message : String(error); 114 logConditions("service worker registration failed"); 115 }); 116 } 117 118 function getServiceWorkerState() { 119 if (!serviceWorkerRegistration) return null; 120 121 var worker = serviceWorkerRegistration.active || 122 serviceWorkerRegistration.waiting || 123 serviceWorkerRegistration.installing; 124 return worker ? worker.state : null; 125 } 126 127 function isStandalone() { 128 return window.matchMedia("(display-mode: standalone)").matches || 129 window.navigator.standalone === true; 130 } 131 132 function isDismissed() { 133 var key = CFG.storageKey || "sumahodehoken_install_prompt_dismissed_until"; 134 try { 135 var until = Number(window.localStorage.getItem(key) || 0); 136 return until > Date.now(); 137 } catch (e) { 138 return false; 139 } 140 } 141 142 function dismiss(days) { 143 var key = CFG.storageKey || "sumahodehoken_install_prompt_dismissed_until"; 144 try { 145 window.localStorage.setItem(key, String(Date.now() + days * 24 * 60 * 60 * 1000)); 146 } catch (e) { 147 // no-op 148 } 149 hide(); 150 } 151 152 function show() { 153 if (!shouldShow()) return; 154 promptEl.hidden = false; 155 promptEl.setAttribute("aria-hidden", "false"); 156 window.requestAnimationFrame(function () { 157 promptEl.classList.add("is-visible"); 158 }); 159 } 160 161 function hide() { 162 if (!promptEl) return; 163 promptEl.classList.remove("is-visible"); 164 promptEl.setAttribute("aria-hidden", "true"); 165 setTimeout(function () { 166 if (!promptEl.classList.contains("is-visible")) { 167 promptEl.hidden = true; 168 } 169 }, 220); 170 } 171 172 function onInstallClick() { 173 logConditions("install button clicked"); 174 175 if (!promptEvent) { 176 hide(); 177 return; 178 } 179 180 var currentPrompt = promptEvent; 181 promptEvent = null; 182 hide(); 183 184 Promise.resolve(currentPrompt.prompt()).then(function (choice) { 185 dismiss(choice && choice.outcome === "accepted" ? 30 : (Number(CFG.dismissDays) || 7)); 186 }).catch(function () { 187 dismiss(Number(CFG.dismissDays) || 7); 188 }); 189 } 190})();
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.