Fix PWA install hint dismiss after cached HTML/JS mismatch.
Restore button id, bind dismiss at document level, force hide inline, and fetch pwa.js/style.css network-first. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+22
-14
@@ -4,7 +4,8 @@ const Pwa = (() => {
|
|||||||
const DISMISS_KEY = "pwa-hint-dismissed";
|
const DISMISS_KEY = "pwa-hint-dismissed";
|
||||||
let deferredPrompt = null;
|
let deferredPrompt = null;
|
||||||
let refreshInstallHint = null;
|
let refreshInstallHint = null;
|
||||||
let hintBound = false;
|
let dismissListenerBound = false;
|
||||||
|
let initialized = false;
|
||||||
|
|
||||||
function isStandalone() {
|
function isStandalone() {
|
||||||
return window.matchMedia("(display-mode: standalone)").matches
|
return window.matchMedia("(display-mode: standalone)").matches
|
||||||
@@ -44,40 +45,42 @@ const Pwa = (() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hideHint(hint, { persist = true } = {}) {
|
function hideHint(hint, { persist = true } = {}) {
|
||||||
|
if (!hint) return;
|
||||||
if (persist) {
|
if (persist) {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(DISMISS_KEY, "1");
|
localStorage.setItem(DISMISS_KEY, "1");
|
||||||
} catch {
|
} catch {
|
||||||
/* private mode with storage blocked – still hide for this session */
|
/* storage blocked – still hide for this session */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hint.hidden = true;
|
hint.hidden = true;
|
||||||
hint.classList.add("is-dismissed");
|
hint.classList.add("is-dismissed");
|
||||||
|
hint.style.setProperty("display", "none", "important");
|
||||||
}
|
}
|
||||||
|
|
||||||
function showHint(hint) {
|
function showHint(hint) {
|
||||||
|
if (!hint) return;
|
||||||
hint.hidden = false;
|
hint.hidden = false;
|
||||||
hint.classList.remove("is-dismissed");
|
hint.classList.remove("is-dismissed");
|
||||||
|
hint.style.removeProperty("display");
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindHintActions(hint) {
|
function bindDismissListener() {
|
||||||
if (hintBound) return;
|
if (dismissListenerBound) return;
|
||||||
hintBound = true;
|
dismissListenerBound = true;
|
||||||
|
|
||||||
hint.addEventListener("click", (event) => {
|
document.addEventListener("click", (event) => {
|
||||||
if (event.target.closest(".pwa-hint-dismiss")) {
|
if (!event.target.closest("#pwa-hint-dismiss, .pwa-hint-dismiss")) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
hideHint(hint);
|
event.stopPropagation();
|
||||||
}
|
hideHint(document.getElementById("pwa-install-hint"));
|
||||||
});
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupInstallHint() {
|
function setupInstallHint() {
|
||||||
const hint = document.getElementById("pwa-install-hint");
|
const hint = document.getElementById("pwa-install-hint");
|
||||||
if (!hint) return null;
|
if (!hint) return null;
|
||||||
|
|
||||||
bindHintActions(hint);
|
|
||||||
|
|
||||||
if (isStandalone()) {
|
if (isStandalone()) {
|
||||||
hideHint(hint, { persist: false });
|
hideHint(hint, { persist: false });
|
||||||
return null;
|
return null;
|
||||||
@@ -89,9 +92,10 @@ const Pwa = (() => {
|
|||||||
|
|
||||||
const body = document.getElementById("pwa-hint-body");
|
const body = document.getElementById("pwa-hint-body");
|
||||||
const installBtn = document.getElementById("pwa-install-btn");
|
const installBtn = document.getElementById("pwa-install-btn");
|
||||||
const dismissBtn = hint.querySelector(".pwa-hint-dismiss");
|
const dismissBtn = document.getElementById("pwa-hint-dismiss");
|
||||||
|
|
||||||
const updateHintText = () => {
|
const updateHintText = () => {
|
||||||
|
if (typeof t !== "function") return;
|
||||||
const title = hint.querySelector("[data-i18n='pwa.hintTitle']");
|
const title = hint.querySelector("[data-i18n='pwa.hintTitle']");
|
||||||
if (title) title.textContent = t("pwa.hintTitle");
|
if (title) title.textContent = t("pwa.hintTitle");
|
||||||
if (body && !deferredPrompt) body.textContent = t(platformHintKey());
|
if (body && !deferredPrompt) body.textContent = t(platformHintKey());
|
||||||
@@ -129,6 +133,8 @@ const Pwa = (() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
|
if (initialized) return;
|
||||||
|
initialized = true;
|
||||||
refreshInstallHint = setupInstallHint();
|
refreshInstallHint = setupInstallHint();
|
||||||
await registerServiceWorker();
|
await registerServiceWorker();
|
||||||
}
|
}
|
||||||
@@ -137,6 +143,8 @@ const Pwa = (() => {
|
|||||||
refreshInstallHint?.();
|
refreshInstallHint?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindDismissListener();
|
||||||
|
|
||||||
return { init, refreshHint };
|
return { init, refreshHint };
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
+21
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = "if-viewer-static-v5";
|
const CACHE = "if-viewer-static-v6";
|
||||||
const ASSETS = [
|
const ASSETS = [
|
||||||
"/static/style.css",
|
"/static/style.css",
|
||||||
"/static/favicon.svg",
|
"/static/favicon.svg",
|
||||||
@@ -10,6 +10,11 @@ const ASSETS = [
|
|||||||
"/static/locales/de.json",
|
"/static/locales/de.json",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const NETWORK_FIRST = new Set([
|
||||||
|
"/static/pwa.js",
|
||||||
|
"/static/style.css",
|
||||||
|
]);
|
||||||
|
|
||||||
self.addEventListener("install", (event) => {
|
self.addEventListener("install", (event) => {
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
caches.open(CACHE)
|
caches.open(CACHE)
|
||||||
@@ -33,6 +38,21 @@ self.addEventListener("fetch", (event) => {
|
|||||||
if (url.pathname.includes("/api/")) return;
|
if (url.pathname.includes("/api/")) return;
|
||||||
if (!url.pathname.startsWith("/static/")) return;
|
if (!url.pathname.startsWith("/static/")) return;
|
||||||
|
|
||||||
|
if (NETWORK_FIRST.has(url.pathname)) {
|
||||||
|
event.respondWith(
|
||||||
|
fetch(event.request)
|
||||||
|
.then((response) => {
|
||||||
|
if (response.ok) {
|
||||||
|
const copy = response.clone();
|
||||||
|
caches.open(CACHE).then((cache) => cache.put(event.request, copy));
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.catch(() => caches.match(event.request))
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
caches.match(event.request).then((cached) => cached || fetch(event.request))
|
caches.match(event.request).then((cached) => cached || fetch(event.request))
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
<link rel="apple-touch-icon" href="/static/icon-192.png">
|
<link rel="apple-touch-icon" href="/static/icon-192.png">
|
||||||
<script src="/static/pwa.js" defer></script>
|
<script src="/static/pwa.js?v=7" defer></script>
|
||||||
|
|||||||
@@ -5,6 +5,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="pwa-hint-actions">
|
<div class="pwa-hint-actions">
|
||||||
<button type="button" id="pwa-install-btn" class="viewer-copy-btn" hidden data-i18n="pwa.install">Install</button>
|
<button type="button" id="pwa-install-btn" class="viewer-copy-btn" hidden data-i18n="pwa.install">Install</button>
|
||||||
<button type="button" class="pwa-hint-dismiss" aria-label="Dismiss">×</button>
|
<button type="button" id="pwa-hint-dismiss" class="pwa-hint-dismiss" aria-label="Dismiss">×</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user