Add a button for enabling push notifications #158
|
@ -234,3 +234,10 @@ for (const input of inputs) {
|
||||||
if (parseInt(input.value) > parseInt(input.max)) input.value = input.max;
|
if (parseInt(input.value) > parseInt(input.max)) input.value = input.max;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!('serviceWorker' in navigator && 'PushManager' in window)) {
|
||||||
|
let e = document.getElementById("enable-push-nav-item").style = "display: none";
|
||||||
|
if (e) {
|
||||||
|
e.style = "display: none"
|
||||||
|
}
|
||||||
|
}
|
|
@ -605,3 +605,51 @@ document.querySelectorAll('form').forEach(form => {
|
||||||
form.classList.add('is-submitting');
|
form.classList.add('is-submitting');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function urlB64ToUint8Array(base64String) {
|
||||||
|
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||||
|
const base64 = (base64String + padding)
|
||||||
|
.replace(/\-/g, '+')
|
||||||
|
.replace(/_/g, '/');
|
||||||
|
|
||||||
|
const rawData = window.atob(base64);
|
||||||
|
const outputArray = new Uint8Array(rawData.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < rawData.length; ++i) {
|
||||||
|
outputArray[i] = rawData.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return outputArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSubscriptionOnServer(subscription, apiEndpoint) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("subscription_json", JSON.stringify(subscription));
|
||||||
|
|
||||||
|
const xhr = createXhrWithFormKey(
|
||||||
|
apiEndpoint,
|
||||||
|
'POST',
|
||||||
|
formData
|
||||||
|
);
|
||||||
|
|
||||||
|
xhr[0].send(xhr[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function enablePushNotifications() {
|
||||||
|
if (!('serviceWorker' in navigator && 'PushManager' in window)) return;
|
||||||
|
let publicKeyElement = document.getElementById('VAPID_PUBLIC_KEY');
|
||||||
|
if (!publicKeyElement) return;
|
||||||
|
|
||||||
|
let publicKey = urlB64ToUint8Array(publicKeyElement.value);
|
||||||
|
navigator.serviceWorker.getRegistration("/assets/js/service_worker.js").then((reg) => {
|
||||||
|
return reg.pushManager.subscribe({
|
||||||
|
userVisibleOnly: true,
|
||||||
|
applicationServerKey: publicKey,
|
||||||
|
})
|
||||||
|
}).then((subscription) => {
|
||||||
|
updateSubscriptionOnServer(subscription, "/push_subscribe")
|
||||||
|
alert("Push notifications are enabled!")
|
||||||
|
}).catch((e) => {
|
||||||
|
alert("Failed to enable push notifications :marseyill:")
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,76 +1,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function urlB64ToUint8Array(base64String) {
|
function registerServiceWorker(serviceWorkerUrl){
|
||||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
|
||||||
const base64 = (base64String + padding)
|
|
||||||
.replace(/\-/g, '+')
|
|
||||||
.replace(/_/g, '/');
|
|
||||||
|
|
||||||
const rawData = window.atob(base64);
|
|
||||||
const outputArray = new Uint8Array(rawData.length);
|
|
||||||
|
|
||||||
for (let i = 0; i < rawData.length; ++i) {
|
|
||||||
outputArray[i] = rawData.charCodeAt(i);
|
|
||||||
}
|
|
||||||
return outputArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateSubscriptionOnServer(subscription, apiEndpoint) {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("subscription_json", JSON.stringify(subscription));
|
|
||||||
|
|
||||||
const xhr = createXhrWithFormKey(
|
|
||||||
apiEndpoint,
|
|
||||||
'POST',
|
|
||||||
formData
|
|
||||||
);
|
|
||||||
|
|
||||||
xhr[0].send(xhr[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function subscribeUser(swRegistration, applicationServerPublicKey, apiEndpoint) {
|
|
||||||
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
|
|
||||||
swRegistration.pushManager.subscribe({
|
|
||||||
userVisibleOnly: true,
|
|
||||||
applicationServerKey: applicationServerKey
|
|
||||||
})
|
|
||||||
.then(function(subscription) {
|
|
||||||
return updateSubscriptionOnServer(subscription, apiEndpoint);
|
|
||||||
|
|
||||||
})
|
|
||||||
.then(function(response) {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Bad status code from server.');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then(function(responseData) {
|
|
||||||
if (responseData.status!=="success") {
|
|
||||||
throw new Error('Bad response from server.');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(function() {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerServiceWorker(serviceWorkerUrl, applicationServerPublicKey, apiEndpoint){
|
|
||||||
let swRegistration = null;
|
|
||||||
if ('serviceWorker' in navigator && 'PushManager' in window) {
|
if ('serviceWorker' in navigator && 'PushManager' in window) {
|
||||||
navigator.serviceWorker.register(serviceWorkerUrl)
|
navigator.serviceWorker.register(serviceWorkerUrl);
|
||||||
.then(function(swReg) {
|
|
||||||
subscribeUser(swReg, applicationServerPublicKey, apiEndpoint);
|
|
||||||
|
|
||||||
swRegistration = swReg;
|
|
||||||
})
|
|
||||||
.catch(function() {
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
return swRegistration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerServiceWorker(
|
registerServiceWorker(
|
||||||
"/assets/js/service_worker.js",
|
"/assets/js/service_worker.js"
|
||||||
document.getElementById('VAPID_PUBLIC_KEY').value,
|
|
||||||
"/push_subscribe"
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -254,7 +254,9 @@
|
||||||
<a class="dropdown-item" href="{{v.url}}"><i class="fas fa-user-circle fa-fw mr-3"></i>My profile</a>
|
<a class="dropdown-item" href="{{v.url}}"><i class="fas fa-user-circle fa-fw mr-3"></i>My profile</a>
|
||||||
<a class="dropdown-item" href="/settings/personal"><i class="fas fa-cog fa-fw mr-3"></i>Settings</a>
|
<a class="dropdown-item" href="/settings/personal"><i class="fas fa-cog fa-fw mr-3"></i>Settings</a>
|
||||||
|
|
||||||
<a class="dropdown-item" href="/app"><i class="fas fa-mobile fa-fw mr-3"></i>Mobile app</a>
|
{% if g.browser != 'webview' %}
|
||||||
|
<a class="dropdown-item" href="/app"><i class="fas fa-mobile fa-fw mr-3"></i>Mobile app</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<a class="dropdown-item donate-link" rel="nofollow noopener" href="/donate"><i class="fas fa-dollar-sign fa-fw mr-3"></i>Donate</a>
|
<a class="dropdown-item donate-link" rel="nofollow noopener" href="/donate"><i class="fas fa-dollar-sign fa-fw mr-3"></i>Donate</a>
|
||||||
|
|
||||||
|
@ -310,7 +312,12 @@
|
||||||
<a class="nav-link" href="/settings/personal"><i class="fas fa-cog fa-fw mr-3"></i>Settings</a>
|
<a class="nav-link" href="/settings/personal"><i class="fas fa-cog fa-fw mr-3"></i>Settings</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<a class="nav-item nav-link" href="/app"><i class="fas fa-mobile fa-fw mr-3"></i>Mobile app</a>
|
|
||||||
|
{% if g.browser == 'webview' %}
|
||||||
|
<a class="nav-item nav-link" href="/app" id="mobile-app-nav-item"><i class="fas fa-mobile fa-fw mr-3"></i>Mobile app</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<a class="nav-item nav-link" href="#" id="enable-push-nav-item" data-nonce="{{g.nonce}}" data-nonce="{{g.nonce}}" data-onclick="enablePushNotifications()"><i class="fas fa-bell fa-fw mr-3"></i>Enable push notifications</a>
|
||||||
|
|
||||||
<a class="nav-item nav-link donate-link" rel="nofollow noopener" href="/donate"><i class="fas fa-dollar-sign fa-fw mr-3"></i>Donate</a>
|
<a class="nav-item nav-link donate-link" rel="nofollow noopener" href="/donate"><i class="fas fa-dollar-sign fa-fw mr-3"></i>Donate</a>
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,10 @@
|
||||||
|
|
||||||
{% if request.path == '/' and v %}
|
{% if request.path == '/' and v %}
|
||||||
<script defer src="{{'js/register_service_worker.js' | asset}}"></script>
|
<script defer src="{{'js/register_service_worker.js' | asset}}"></script>
|
||||||
<input hidden id="VAPID_PUBLIC_KEY" value="{{VAPID_PUBLIC_KEY}}">
|
{% endif %}
|
||||||
|
|
||||||
|
{% if v %}
|
||||||
|
<input hidden id="VAPID_PUBLIC_KEY" value="{{VAPID_PUBLIC_KEY}}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if False and request.path == '/' and g.browser != 'webview' and time.time() > session.get('tooltip_dismissed',0)+86400*30 %}
|
{% if False and request.path == '/' and g.browser != 'webview' and time.time() > session.get('tooltip_dismissed',0)+86400*30 %}
|
||||||
|
|
Loading…
Reference in New Issue