Skip to content

Commit fb89f92

Browse files
committed
Add native browser notification helper functions
1 parent 1da5d94 commit fb89f92

File tree

4 files changed

+120
-0
lines changed

4 files changed

+120
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
/* Global: window */
16+
17+
import { isContextSecure } from './utilities/browserContext.js';
18+
19+
/**
20+
* Get the current browser notification permission.
21+
* @returns {NotificationPermission|undefined} {@link NotificationPermission}, or `undefined` if unsupported.
22+
*/
23+
export const getBrowserNotificationPermission = () =>
24+
window?.Notification?.permission;
25+
26+
/**
27+
* Request browser notification permission (async/await).
28+
* @returns {Promise<NotificationPermission|undefined>} Resolves to {@link NotificationPermission}, or `undefined` if unsupported
29+
*/
30+
export const requestBrowserNotificationPermissions = async () => {
31+
if (!isContextSecure()) {
32+
return undefined;
33+
}
34+
35+
const permission = getBrowserNotificationPermission();
36+
if (permission === 'granted') {
37+
return permission;
38+
}
39+
40+
return await window.Notification?.requestPermission();
41+
};
42+
43+
/**
44+
* Check if notifications can be shown immediately.
45+
* @returns {boolean} `true` if the Notification API is available, the context is secure
46+
* and the {@link NotificationPermission browser notification permission} is `granted`, `false` otherwise.
47+
*/
48+
export const checkBrowserNotificationPermissions = () =>
49+
isContextSecure() && getBrowserNotificationPermission() === 'granted';
50+
51+
/**
52+
* @typedef {object} NotificationOptions
53+
* @property {string} title Notification title
54+
* @property {string} [body] Notification body
55+
* @property {string} [icon] Notification icon URL (defaults to server icon)
56+
* @property {(event: Event) => void} [onclick] Triggered when the notification is clicked
57+
* @property {(event: Event) => void} [onerror] Triggered if the notification fails to display
58+
* @property {(event: Event) => void} [onshow] Triggered when the notification is shown
59+
* @property {(event: Event) => void} [onclose] Triggered when the notification is closed
60+
*/
61+
62+
/**
63+
* Show a native browser notification.
64+
* @param {NotificationOptions} options - The browser notification options
65+
* @returns {Notification|null} {@link Notification} instance, or `null` if unavailable
66+
*/
67+
export const showNativeBrowserNotification = (options) => {
68+
if (!checkBrowserNotificationPermissions()) {
69+
return null;
70+
}
71+
72+
const {
73+
title,
74+
onclick,
75+
onerror,
76+
onshow,
77+
onclose,
78+
icon = '/favicon.ico',
79+
...notificationOptions
80+
} = options;
81+
if (!title) {
82+
return null;
83+
}
84+
85+
const notification = new window.Notification(title, { icon, ...notificationOptions });
86+
Object.entries({ onclick, onerror, onshow, onclose })
87+
.filter(([_, eventFunc]) => typeof eventFunc === 'function')
88+
.forEach(([eventName, eventFunc]) => {
89+
notification[eventName] = eventFunc;
90+
});
91+
92+
return notification;
93+
};

Framework/Frontend/js/src/components/CopyToClipboardComponent.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ export class CopyToClipboardComponent extends StatefulComponent {
6565
/**
6666
* Checks if context is secure (HTTPS)
6767
*
68+
* @deprecated Use `isContextSecure` from `./utilities/browserContext.js` instead.
69+
* Calling this method directly is discouraged; it may be removed in future versions.
6870
* @returns {boolean} Returns `true` if context is secure
6971
*/
7072
isContextSecure() {

Framework/Frontend/js/src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export { default as switchCase } from './switchCase.js';
2626
export { documentClickTaggedEventRegistry } from './utilities/documentClickTaggedEventRegistry.js';
2727
export { buildUrl } from './utilities/buildUrl.js';
2828
export { parseUrlParameters } from './utilities/parseUrlParameters.js';
29+
export { isContextSecure } from './utilities/browserContext.js';
2930

3031
// Formatters
3132
export { formatTimeDuration } from './formatter/formatTimeDuration.js';
@@ -54,3 +55,5 @@ export * from './icons.js';
5455

5556
export * from './chart.js';
5657
export * from './Notification.js';
58+
59+
export * from './BrowserNotification.js';
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
/* Global: window */
16+
17+
/**
18+
* Checks whether the context is secure (HTTPS)
19+
* @returns {boolean} Returns `true` if context is secure, `false` otherwise.
20+
*/
21+
export const isContextSecure = () =>
22+
window.isSecureContext;

0 commit comments

Comments
 (0)