fighting-konoha/pwa.js

45 lines
3.1 KiB
JavaScript

/* PWA (RENCANA 4.7): menangkap `beforeinstallprompt` supaya Pengaturan bisa menawarkan "Pasang aplikasi", hanya bila peramban mengizinkannya.
Dimuat di index.html dan mobile.html (sinkron di <head>, agar event tidak terlewat). Event dikirim ke dokumen paling atas: di HP dokumen itu mobile.html
dan game berjalan di iframe, jadi iframe memakai window.parent.KonohaPWA (satu asal; dipanggil langsung supaya ketukan pemain tetap dianggap gestur untuk prompt()).
window.KonohaPWA = { available(), install() -> 'accepted' | 'dismissed' | 'unavailable', onChange(fn) -> fungsi berhenti }.
iOS tidak punya event ini (pasang lewat Bagikan > Tambah ke Layar Utama), jadi di sana tombol tidak pernah tampil. */
(() => {
'use strict';
let host = null;
try { host = window.parent !== window ? window.parent.KonohaPWA || null : null; } catch (_) { host = null; }
if (!host) {
let saved = null, installed = false;
const subs = new Set();
const standalone = () => { try { return matchMedia('(display-mode: standalone)').matches || matchMedia('(display-mode: fullscreen)').matches || navigator.standalone === true; } catch (_) { return false; } };
const emit = () => { for (const fn of [...subs]) { try { fn(); } catch (_) { subs.delete(fn); } } };
host = window.KonohaPWA = {
available: () => !!saved && !installed && !standalone(),
onChange(fn) { subs.add(fn); return () => subs.delete(fn); },
async install() {
const ev = saved;
if (!ev) return 'unavailable';
saved = null; emit(); // satu event hanya bisa dipakai sekali
try { ev.prompt(); return (await ev.userChoice).outcome; } catch (_) { return 'unavailable'; }
},
};
window.addEventListener('beforeinstallprompt', e => { e.preventDefault(); saved = e; emit(); });
window.addEventListener('appinstalled', () => { installed = true; saved = null; emit(); });
}
// Baris di Pengaturan (hanya di halaman game, bukan di mobile.html): tampil hanya selama pemasangan tersedia.
function mountRow() {
const panel = document.getElementById('settings-panel');
if (!panel || panel.querySelector('#pwa-row')) return;
const row = document.createElement('div');
row.className = 'setting-row'; row.id = 'pwa-row'; row.style.display = 'none';
row.innerHTML = '<span>Pasang aplikasi<small>Buka dari layar utama, layar penuh tanpa bilah alamat</small></span><button type="button" class="kf-set-btn" id="pwa-install">PASANG</button>';
(panel.querySelector('.dialog-buttons') || panel.lastElementChild).before(row);
const sync = () => { let ok = false; try { ok = host.available(); } catch (_) { /* host dari dokumen yang sudah dibongkar */ } row.style.display = ok ? '' : 'none'; };
row.querySelector('#pwa-install').onclick = () => { host.install(); };
try { host.onChange(sync); } catch (_) { /* tanpa langganan: status tetap dibaca lagi tiap Pengaturan dibuka */ }
new MutationObserver(sync).observe(panel, { attributes: true, attributeFilter: ['open'] });
sync();
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mountRow); else mountRow();
})();