[ticket/17010] Make webpush js not depend on twig compilation

PHPBB3-17010
This commit is contained in:
Marc Alexander 2023-11-05 12:56:01 +01:00
parent d85da61c9a
commit fa91bf791f
No known key found for this signature in database
GPG key ID: 50E0D2423696F995
3 changed files with 77 additions and 41 deletions

View file

@ -4,37 +4,48 @@
function PhpbbWebpush() { function PhpbbWebpush() {
/** @type {string} URL to service worker */ /** @type {string} URL to service worker */
const serviceWorkerUrl = '{{ U_WEBPUSH_WORKER_URL }}'; let serviceWorkerUrl = '';
/** @type {string} URL to subscribe to push */ /** @type {string} URL to subscribe to push */
const subscribeUrl = '{{ U_WEBPUSH_SUBSCRIBE }}'; let subscribeUrl = '';
/** @type {string} URL to unsubscribe from push */ /** @type {string} URL to unsubscribe from push */
const unsubscribeUrl = '{{ U_WEBPUSH_UNSUBSCRIBE }}'; let unsubscribeUrl = '';
/** @type { {creationTime: number, formToken: string} } Form tokens */ /** @type { {creationTime: number, formToken: string} } Form tokens */
this.formTokens = { this.formTokens = {
creationTime: {{ FORM_TOKENS.creation_time }}, creationTime: 0,
formToken: '{{ FORM_TOKENS.form_token }}' formToken: '',
}; };
/** @type [{endpoint: string, expiration: string}[]] Subscriptions */ /** @type {{endpoint: string, expiration: string}[]} Subscriptions */
let subscriptions = [ let subscriptions;
{% for sub in SUBSCRIPTIONS %}
{endpoint: '{{ sub.endpoint }}', expiration: '{{ sub.expiration }}' }, /** @type {string} Title of error message */
{% endfor %} let ajaxErrorTitle = '';
];
/** @type {string} VAPID public key */ /** @type {string} VAPID public key */
const VAPID_PUBLIC_KEY = '{{ VAPID_PUBLIC_KEY }}'; let vapidPublicKey = '';
let subscribeButton, /** @type {HTMLElement} Subscribe button */
unsubscribeButton; let subscribeButton;
/** @type {HTMLElement} Unsubscribe button */
let unsubscribeButton;
/** /**
* Init function for phpBB webpush * Init function for phpBB Web Push
* @type {array} options
*/ */
this.init = function() { this.init = function(options) {
serviceWorkerUrl = options.serviceWorkerUrl;
subscribeUrl = options.subscribeUrl;
unsubscribeUrl = options.unsubscribeUrl;
this.formTokens = options.formTokens;
subscriptions = options.subscriptions;
ajaxErrorTitle = options.ajaxErrorTitle;
vapidPublicKey = options.vapidPublicKey;
subscribeButton = document.querySelector('#subscribe_webpush'); subscribeButton = document.querySelector('#subscribe_webpush');
unsubscribeButton = document.querySelector('#unsubscribe_webpush'); unsubscribeButton = document.querySelector('#unsubscribe_webpush');
@ -70,17 +81,17 @@ function PhpbbWebpush() {
function updateButtonState() { function updateButtonState() {
if (Notification.permission === 'granted') { if (Notification.permission === 'granted') {
navigator.serviceWorker.getRegistration(serviceWorkerUrl) navigator.serviceWorker.getRegistration(serviceWorkerUrl)
.then((registration) => { .then(registration => {
if (typeof registration === 'undefined') { if (typeof registration === 'undefined') {
return; return;
} }
registration.pushManager.getSubscription() registration.pushManager.getSubscription()
.then((subscribed) => { .then(subscribed => {
if (isValidSubscription(subscribed)) { if (isValidSubscription(subscribed)) {
setSubscriptionState(true); setSubscriptionState(true);
} }
}) });
}); });
} }
} }
@ -91,7 +102,7 @@ function PhpbbWebpush() {
* @param {PushSubscription} subscription * @param {PushSubscription} subscription
* @returns {boolean} * @returns {boolean}
*/ */
const isValidSubscription = (subscription) => { const isValidSubscription = subscription => {
if (!subscription) { if (!subscription) {
return false; return false;
} }
@ -153,27 +164,27 @@ function PhpbbWebpush() {
} }
} }
let newSubscription = await registration.pushManager.subscribe({ const newSubscription = await registration.pushManager.subscribe({
userVisibleOnly: true, userVisibleOnly: true,
applicationServerKey: urlB64ToUint8Array(VAPID_PUBLIC_KEY), applicationServerKey: urlB64ToUint8Array(vapidPublicKey),
}); });
const loadingIndicator = phpbb.loadingIndicator(); const loadingIndicator = phpbb.loadingIndicator();
fetch(subscribeUrl, { fetch(subscribeUrl, {
method: 'POST', method: 'POST',
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest' 'X-Requested-With': 'XMLHttpRequest',
}, },
body: getFormData(newSubscription) body: getFormData(newSubscription),
}) })
.then((response) => { .then(response => {
loadingIndicator.fadeOut(phpbb.alertTime); loadingIndicator.fadeOut(phpbb.alertTime);
return response.json(); return response.json();
}) })
.then(handleSubscribe) .then(handleSubscribe)
.catch((error) => { .catch(error => {
loadingIndicator.fadeOut(phpbb.alertTime); loadingIndicator.fadeOut(phpbb.alertTime);
phpbb.alert('{{ lang('AJAX_ERROR_TITLE') }}', error); phpbb.alert(ajaxErrorTitle, error);
}); });
} }
@ -196,22 +207,22 @@ function PhpbbWebpush() {
fetch(unsubscribeUrl, { fetch(unsubscribeUrl, {
method: 'POST', method: 'POST',
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest' 'X-Requested-With': 'XMLHttpRequest',
}, },
body: getFormData({endpoint: subscription.endpoint}) body: getFormData({ endpoint: subscription.endpoint }),
}) })
.then(() => { .then(() => {
loadingIndicator.fadeOut(phpbb.alertTime); loadingIndicator.fadeOut(phpbb.alertTime);
return subscription.unsubscribe(); return subscription.unsubscribe();
}) })
.then((unsubscribed) => { .then(unsubscribed => {
if (unsubscribed) { if (unsubscribed) {
setSubscriptionState(false); setSubscriptionState(false);
} }
}) })
.catch((error) => { .catch(error => {
loadingIndicator.fadeOut(phpbb.alertTime); loadingIndicator.fadeOut(phpbb.alertTime);
phpbb.alert('{{ lang('AJAX_ERROR_TITLE') }}', error); phpbb.alert(ajaxErrorTitle, error);
}); });
} }
@ -223,7 +234,7 @@ function PhpbbWebpush() {
function handleSubscribe(response) { function handleSubscribe(response) {
if (response.success) { if (response.success) {
setSubscriptionState(true); setSubscriptionState(true);
if (response.hasOwnProperty('form_tokens')) { if ('form_tokens' in response) {
updateFormTokens(response.form_tokens); updateFormTokens(response.form_tokens);
} }
} }
@ -236,7 +247,7 @@ function PhpbbWebpush() {
* @returns {FormData} Form data * @returns {FormData} Form data
*/ */
function getFormData(data) { function getFormData(data) {
let formData = new FormData(); const formData = new FormData();
formData.append('form_token', phpbb.webpush.formTokens.formToken); formData.append('form_token', phpbb.webpush.formTokens.formToken);
formData.append('creation_time', phpbb.webpush.formTokens.creationTime.toString()); formData.append('creation_time', phpbb.webpush.formTokens.creationTime.toString());
formData.append('data', JSON.stringify(data)); formData.append('data', JSON.stringify(data));
@ -261,13 +272,14 @@ function PhpbbWebpush() {
* @returns {Uint8Array} * @returns {Uint8Array}
*/ */
function urlB64ToUint8Array(base64String) { function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4); const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/'); const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
const rawData = window.atob(base64); const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length); const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) { for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i); outputArray[i] = rawData.charCodeAt(i);
} }
return outputArray; return outputArray;
} }
} }
@ -283,5 +295,6 @@ function domReady(callBack) {
phpbb.webpush = new PhpbbWebpush(); phpbb.webpush = new PhpbbWebpush();
domReady(() => { domReady(() => {
phpbb.webpush.init(); /* global phpbbWebpushOptions */
phpbb.webpush.init(phpbbWebpushOptions);
}); });

View file

@ -1,6 +1,8 @@
{% include('ucp_header.html') %} {% include('ucp_header.html') %}
{% INCLUDEJS(T_WEBPUSH_JS_PATH) %} {% if NOTIFICATIONS_WEBPUSH_ENABLE %}
{% include('ucp_notifications_webpush.html') %}
{% endif %}
<form id="ucp" method="post" action="{{ S_UCP_ACTION }}"{{ S_FORM_ENCTYPE }}> <form id="ucp" method="post" action="{{ S_UCP_ACTION }}"{{ S_FORM_ENCTYPE }}>

View file

@ -0,0 +1,21 @@
<script>
phpbbWebpushOptions = {
serviceWorkerUrl: '{{ U_WEBPUSH_WORKER_URL }}',
subscribeUrl: '{{ U_WEBPUSH_SUBSCRIBE }}',
unsubscribeUrl: '{{ U_WEBPUSH_UNSUBSCRIBE }}',
ajaxErrorTitle: '{{ lang('AJAX_ERROR_TITLE') }}',
vapidPublicKey: '{{ VAPID_PUBLIC_KEY }}',
formTokens: {
creationTime: '{{ WEBPUSH_FORM_TOKENS.creation_time }}',
formToken: '{{ WEBPUSH_FORM_TOKENS.form_token }}',
},
subscriptions: [
{% for sub in SUBSCRIPTIONS %}
{endpoint: '{{ sub.endpoint }}', expiration: '{{ sub.expiration }}' },
{% endfor %}
],
}
</script>
{% INCLUDEJS(T_ASSETS_PATH ~ '/javascript/webpush.js') %}