Ignore:
File:
1 edited

Legend:

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

    r0475b13 r9a00f28  
    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 <%# Het script van deze pagina staat in assets/js/mod/admin-push.js (shaer-bqr). %>
     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>
    61163<% } %>
Note: See TracChangeset for help on using the changeset viewer.