113 lines
4.3 KiB
HTML
113 lines
4.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Notification + Push test</title>
|
|
<style>
|
|
body { font-family: system-ui, sans-serif; max-width: 32rem; margin: 2rem auto; padding: 0 1rem; line-height: 1.5; }
|
|
button { display: block; width: 100%; padding: .9rem; margin: .6rem 0; font-size: 1rem; border: 1px solid #999; border-radius: .5rem; background: #f5f5f5; }
|
|
button:active { background: #e5e5e5; }
|
|
h2 { margin-top: 1.5rem; font-size: 1rem; color: #555; border-bottom: 1px solid #ddd; padding-bottom: .25rem; }
|
|
#status { padding: .75rem; border-radius: .5rem; background: #eef; white-space: pre-wrap; font-size: .9rem; }
|
|
code { background: #eee; padding: 0 .25rem; border-radius: .25rem; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Notification + Push test</h1>
|
|
|
|
<h2>Local (page open)</h2>
|
|
<button id="register">1. Register service worker</button>
|
|
<button id="permission">2. Request permission</button>
|
|
<button id="notify">3. Fire a local notification</button>
|
|
|
|
<h2>Push (server-sent, works with tab closed)</h2>
|
|
<button id="subscribe">4. Subscribe to push</button>
|
|
<button id="sendTest">5. Ask server to push now</button>
|
|
|
|
<div id="status">Status will appear here.</div>
|
|
|
|
<script>
|
|
const statusEl = document.getElementById('status');
|
|
function log(msg) {
|
|
statusEl.textContent = msg + '\n\n' +
|
|
'Permission: ' + Notification.permission + '\n' +
|
|
'SW controller: ' + (navigator.serviceWorker.controller ? 'yes' : 'no');
|
|
}
|
|
|
|
// VAPID public key arrives base64url-encoded; the browser needs a Uint8Array.
|
|
function urlBase64ToUint8Array(base64String) {
|
|
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
|
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
|
|
const raw = atob(base64);
|
|
return Uint8Array.from([...raw].map(c => c.charCodeAt(0)));
|
|
}
|
|
|
|
document.getElementById('register').addEventListener('click', async () => {
|
|
if (!('serviceWorker' in navigator)) return log('No service worker support.');
|
|
try {
|
|
await navigator.serviceWorker.register('sw.js');
|
|
await navigator.serviceWorker.ready;
|
|
log('Service worker registered and ready.');
|
|
} catch (e) {
|
|
log('Registration failed: ' + e);
|
|
}
|
|
});
|
|
|
|
document.getElementById('permission').addEventListener('click', async () => {
|
|
const result = await Notification.requestPermission();
|
|
log('Permission result: ' + result);
|
|
});
|
|
|
|
document.getElementById('notify').addEventListener('click', async () => {
|
|
if (Notification.permission !== 'granted') return log('Permission not granted yet (run step 2).');
|
|
|
|
const reg = await navigator.serviceWorker.ready; // Android Chrome needs the SW, not new Notification()
|
|
await reg.showNotification('OGLAS trough alert!', {
|
|
body: 'Trough 21 appears to be empty',
|
|
icon: '/sh3d/icon.svg',
|
|
badge: 'https://dummyimage.com/96x96/333/fff.png&text=!',
|
|
vibrate: [120, 60, 120],
|
|
tag: 'test', renotify: true,
|
|
actions: [ { action: 'open', title: 'Open' }, { action: 'dismiss', title: 'Dismiss' } ]
|
|
});
|
|
log('Local notification fired.');
|
|
});
|
|
|
|
document.getElementById('subscribe').addEventListener('click', async () => {
|
|
if (Notification.permission !== 'granted') return log('Grant permission first (step 2).');
|
|
try {
|
|
const reg = await navigator.serviceWorker.ready;
|
|
const key = await (await fetch('/sh3d/api/vapidPublicKey')).text();
|
|
const sub = await reg.pushManager.subscribe({
|
|
userVisibleOnly: true, // required on Chrome
|
|
applicationServerKey: urlBase64ToUint8Array(key)
|
|
});
|
|
await fetch('/sh3d/api/subscribe', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(sub)
|
|
});
|
|
log('Subscribed and sent subscription to server.');
|
|
} catch (e) {
|
|
log('Subscribe failed: ' + e);
|
|
}
|
|
});
|
|
|
|
document.getElementById('sendTest').addEventListener('click', async () => {
|
|
try {
|
|
const res = await fetch('/sh3d/api/send', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ title: 'Server push', body: 'If you see this, the loop works.' })
|
|
});
|
|
const data = await res.json();
|
|
log('Server reports sent to ' + data.sent + ' subscription(s).\nNow background the tab and send again to prove it works closed.');
|
|
} catch (e) {
|
|
log('Send request failed: ' + e);
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|