Changeset 0475b13 in Klonkt for src/views/pages/admin-push.ejs


Ignore:
Timestamp:
08/07/2026 01:38:51 PM (5 weeks ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
54ee51c
Parents:
792af53
git-author:
Robin <roboburr@…> (08/07/2026 01:04:55 PM)
git-committer:
roboburr <roboburr@…> (08/07/2026 01:38:51 PM)
Message:

Acht schone pagina's uit inline script naar modules (shaer-bqr, stap 3b)

Alle acht zonder EJS-interpolatie, dus ongewijzigd te verplaatsen: admin-help,
admin-epk, admin-paid, admin-settings, auth-register, admin-push, admin-site-edit
(2 blokken) en authorize-interaction (3 blokken).

Elke route zegt nu welke module hij wil via pageJs; de bootstrap in de shell
haalt hem op. Meerdere blokken uit een pagina belanden in EEN module, gescheiden
door een streep -- ze deelden toch al een pagina en een levensduur.

Templates compileren, modules syntactisch ok, suite 565/565. Het echte bewijs
per pagina is er via een LINK naartoe gaan; na een herlading werkt alles toch al.

Commit met expliciete paden, niet met -A: eerder vandaag veegde ik daarmee
andermans werk uit dezelfde werkmap mee.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/views/pages/admin-push.ejs

    r792af53 r0475b13  
    5858  i18n: { on: t('push.state_on'), off: t('push.state_off'), denied: t('push.state_denied'), unknown: t('push.state_unknown'), unsupported: t('push.state_unsupported'), failed: t('push.enable_failed') },
    5959}).replace(/</g, '\\u003c') %></script>
    60 <script>
    61 (function () {
    62   var cfg = JSON.parse(document.getElementById('np-data').textContent);
    63   var elState = document.getElementById('np-state');
    64   var btnOn = document.getElementById('np-on'), btnOff = document.getElementById('np-off'), btnTest = document.getElementById('np-test');
    65   var alertsBox = document.getElementById('np-alerts'), savedMsg = document.getElementById('np-saved');
    66   var currentEndpoint = null;
    67 
    68   var isIos = /iPad|iPhone|iPod/.test(navigator.userAgent);
    69   var standalone = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true;
    70   if (isIos && !standalone) document.getElementById('np-ios-hint').hidden = false;
    71 
    72   if (!('serviceWorker' in navigator) || !('PushManager' in window) || !('Notification' in window)) {
    73     document.getElementById('np-unsupported').hidden = false;
    74     elState.textContent = cfg.i18n.unsupported;
    75     return;
    76   }
    77 
    78   function b64ToU8(s) {
    79     var pad = '='.repeat((4 - (s.length % 4)) % 4);
    80     var raw = atob((s + pad).replace(/-/g, '+').replace(/_/g, '/'));
    81     var out = new Uint8Array(raw.length);
    82     for (var i = 0; i < raw.length; i++) out[i] = raw.charCodeAt(i);
    83     return out;
    84   }
    85   function post(url, body) {
    86     return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body || {}) });
    87   }
    88   function deviceLabel() {
    89     var ua = navigator.userAgent;
    90     var browser = /Firefox\//.test(ua) ? 'Firefox' : /Edg\//.test(ua) ? 'Edge' : /Chrome\//.test(ua) ? 'Chrome' : /Safari\//.test(ua) ? 'Safari' : 'Browser';
    91     var os = /Android/.test(ua) ? 'Android' : /iPad|iPhone|iPod/.test(ua) ? 'iOS' : /Mac/.test(ua) ? 'macOS' : /Win/.test(ua) ? 'Windows' : /Linux/.test(ua) ? 'Linux' : '';
    92     return (browser + (os ? ' op ' + os : ''));
    93   }
    94   function readAlertBoxes() {
    95     var out = {};
    96     alertsBox.querySelectorAll('input[data-alert]').forEach(function (cb) { out[cb.getAttribute('data-alert')] = cb.checked ? 1 : 0; });
    97     return out;
    98   }
    99   function setAlertBoxes(alerts) {
    100     alertsBox.querySelectorAll('input[data-alert]').forEach(function (cb) {
    101       cb.checked = !!alerts[cb.getAttribute('data-alert')];
    102     });
    103   }
    104 
    105   function render(sub) {
    106     currentEndpoint = sub ? sub.endpoint : null;
    107     elState.textContent = sub ? cfg.i18n.on : (Notification.permission === 'denied' ? cfg.i18n.denied : cfg.i18n.off);
    108     btnOn.hidden = !!sub || Notification.permission === 'denied';
    109     btnOff.hidden = !sub;
    110     btnTest.hidden = !sub;
    111     alertsBox.hidden = !sub;
    112   }
    113 
    114   navigator.serviceWorker.ready.then(function (reg) {
    115     return reg.pushManager.getSubscription();
    116   }).then(function (sub) {
    117     // Show this device's SAVED prefs when we know them, defaults otherwise.
    118     setAlertBoxes((sub && cfg.saved[sub.endpoint]) ? Object.assign({}, cfg.alerts, cfg.saved[sub.endpoint]) : cfg.alerts);
    119     render(sub);
    120   }).catch(function () { elState.textContent = cfg.i18n.unknown; });
    121 
    122   btnOn.addEventListener('click', function () {
    123     btnOn.disabled = true;
    124     Notification.requestPermission().then(function (perm) {
    125       if (perm !== 'granted') { btnOn.disabled = false; render(null); return; }
    126       navigator.serviceWorker.ready.then(function (reg) {
    127         return reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: b64ToU8(cfg.vapid) });
    128       }).then(function (sub) {
    129         return post('/push/subscribe', { subscription: sub.toJSON(), alerts: readAlertBoxes(), uaLabel: deviceLabel() })
    130           .then(function (r) { if (!r.ok) throw new Error('subscribe failed'); render(sub); location.reload(); });
    131       }).catch(function () { btnOn.disabled = false; elState.textContent = cfg.i18n.failed; });
    132     });
    133   });
    134 
    135   btnOff.addEventListener('click', function () {
    136     navigator.serviceWorker.ready.then(function (reg) { return reg.pushManager.getSubscription(); }).then(function (sub) {
    137       if (!sub) { render(null); return; }
    138       var ep = sub.endpoint;
    139       sub.unsubscribe().then(function () { return post('/push/unsubscribe', { endpoint: ep }); })
    140         .then(function () { location.reload(); });
    141     });
    142   });
    143 
    144   btnTest.addEventListener('click', function () {
    145     btnTest.disabled = true;
    146     post('/push/test').then(function () { setTimeout(function () { btnTest.disabled = false; }, 2000); });
    147   });
    148 
    149   alertsBox.addEventListener('change', function () {
    150     if (!currentEndpoint) return;
    151     post('/push/alerts', { endpoint: currentEndpoint, alerts: readAlertBoxes() }).then(function (r) {
    152       if (r.ok) { savedMsg.hidden = false; setTimeout(function () { savedMsg.hidden = true; }, 1500); }
    153     });
    154   });
    155 
    156   document.querySelectorAll('.np-remove').forEach(function (btn) {
    157     btn.addEventListener('click', function () {
    158       post('/push/unsubscribe', { endpoint: btn.getAttribute('data-endpoint') }).then(function () { location.reload(); });
    159     });
    160   });
    161 })();
    162 </script>
     60<%# Het script van deze pagina staat in assets/js/mod/admin-push.js (shaer-bqr). %>
    16361<% } %>
Note: See TracChangeset for help on using the changeset viewer.