PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / admin / resources / service_worker.js

service_worker.js in VikBooking Hotel Booking Engine & PMS trunk, at admin/resources/service_worker.js

265 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * VikBooking Service Worker v1.0.0
3 * Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
4 * http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
5 * https://vikwp.com | https://e4j.com | https://e4jconnect.com
6 */
7
8 class VBOWorker {
9
10 /**
11 * @var self the singleton instance of the VBOWorker class.
12 */
13 static instance;
14
15 /**
16 * @var ServiceWorkerGlobalScope
17 */
18 worker;
19
20 /**
21 * Class constructor sets the ServiceWorker global scope object.
22 *
23 * @param ServiceWorkerGlobalScope worker the SW object to register.
24 */
25 constructor(worker) {
26 this.worker = worker;
27 }
28
29 /**
30 * Registers the global ServiceWorker object inside a new VBOWorker instance.
31 *
32 * @param ServiceWorkerGlobalScope worker the SW object to bind.
33 *
34 * @return undefined
35 */
36 static register(worker) {
37 if (!(worker instanceof ServiceWorkerGlobalScope)) {
38 throw new Error('Invalid ServiceWorkerGlobalScope object');
39 }
40
41 VBOWorker.instance = new VBOWorker(worker);
42
43 return;
44 }
45
46 /**
47 * Returns an instance of the VBOWorker object.
48 *
49 * @param ServiceWorkerGlobalScope worker the SW object to bind.
50 *
51 * @return VBOWorker
52 */
53 static getInstance(worker) {
54 if (!VBOWorker.instance) {
55 // register the ServiceWorkerGlobalScope object in a new VBOWorker instance
56 VBOWorker.register(worker);
57 }
58
59 return VBOWorker.instance;
60 }
61
62 /**
63 * Gets the ServiceWorker origin (base) domain.
64 *
65 * @return string
66 */
67 getOrigin() {
68 return this.worker.location.origin || '';
69 }
70
71 /**
72 * Gets the ServiceWorker installation reference (full) URI to this file.
73 *
74 * @return string
75 */
76 getHref() {
77 return this.worker.location.href || '';
78 }
79
80 /**
81 * Gets the ServiceWorker relative path to this file.
82 *
83 * @return string
84 */
85 getPath() {
86 return this.worker.location.pathname || '';
87 }
88
89 /**
90 * Tells if the client App is running on the Joomla CMS.
91 *
92 * @return bool
93 */
94 isJoomla() {
95 let match_admin_cms_path = new RegExp(/\/(administrator\/components)\//);
96
97 return this.getHref().match(match_admin_cms_path) ? true : false;
98 }
99
100 /**
101 * Tells if the client App is running on the WordPress CMS.
102 *
103 * @return bool
104 */
105 isWordPress() {
106 let match_admin_cms_path = new RegExp(/\/(wp-content\/plugins)\//);
107
108 return this.getHref().match(match_admin_cms_path) ? true : false;
109 }
110
111 /**
112 * Builds the URI to the CMS back-end section to VikBooking.
113 *
114 * @return string
115 */
116 getVikBookingAdminURI() {
117 let vbo_base_admin_uri = '/';
118
119 if (this.isWordPress()) {
120 vbo_base_admin_uri = this.getHref().split('wp-content/plugins/')[0] + 'wp-admin/admin.php?page=vikbooking';
121 } else if (this.isJoomla()) {
122 vbo_base_admin_uri = this.getHref().split('administrator/components/')[0] + 'administrator/index.php?option=com_vikbooking';
123 }
124
125 return vbo_base_admin_uri;
126 }
127
128 /**
129 * Builds the URI to allow VikBooking to render the data from a Push notification.
130 *
131 * @param object payload the payload data to encode and add it to query string.
132 *
133 * @return string
134 */
135 buildVikBookingAdminPushURI(payload) {
136 // base64 encode the payload and append it to a query string value
137 return this.getVikBookingAdminURI() + '&push_notification=' + btoa(JSON.stringify(payload || {}));
138 }
139 }
140
141 // register the ServiceWorkerGlobalScope object
142 VBOWorker.register(self);
143
144 // install event listener
145 self.addEventListener('install', (event) => {
146 /**
147 * Force the waiting ServiceWorker to become the active one
148 * by triggering the "activate" event.
149 */
150 event.waitUntil(self.skipWaiting());
151 });
152
153 // activate event listener
154 self.addEventListener('activate', (event) => {
155 /**
156 * Set this ServiceWorker as the active one for all clients that match the worker's
157 * scope and trigger the "controllerchange" event for the claimed clients (unused).
158 */
159 event.waitUntil(self.clients.claim());
160 });
161
162 // push event listener
163 self.addEventListener('push', (event) => {
164 if (!self.Notification || self.Notification.permission != 'granted') {
165 // unable to proceed
166 return;
167 }
168
169 // define how to dispatch the Push notification
170 const dispatchNotification = (data) => {
171 // get the notification data payload
172 let payload = data.json();
173
174 // check if support for Web App badge is available
175 if (typeof navigator.setAppBadge !== 'undefined') {
176 // set application badge count
177 navigator.setAppBadge((payload.unreadCount || 1));
178 }
179
180 // show the Push notification
181 return self.registration.showNotification((payload.title || 'Notification'), {
182 body: payload.message || data.text(),
183 data: payload,
184 silent: false,
185 });
186 };
187
188 if (event.data) {
189 // asynchronously show the notification by passing the PushMessageData object
190 event.waitUntil(dispatchNotification(event.data));
191 }
192 });
193
194 // notification click event listener
195 self.addEventListener('notificationclick', (event) => {
196 // clicked notification payload
197 let payload = event.notification.data || {};
198
199 // check if support for Web App badge is available
200 if (typeof navigator.setAppBadge !== 'undefined') {
201 // clear application badge count
202 navigator.clearAppBadge();
203 }
204
205 // match client options
206 let matchOptions = {
207 includeUncontrolled: true,
208 type: 'window',
209 };
210
211 // registration origin (website root URI)
212 let sw_origin = self.location.origin || '';
213
214 // valid client match regular expression
215 let match_admin_regexp = new RegExp(/\/(wp-admin|administrator)\//);
216
217 // close the notification
218 event.notification.close();
219
220 // check for open tabs/windows
221 event.waitUntil(self.clients.matchAll(matchOptions).then((clientList) => {
222 // parse claimed clients found, if any
223 for (const client of clientList) {
224 if (client.url.indexOf(sw_origin) !== 0) {
225 // the client URL does not match the ServiceWorker origin
226 continue;
227 }
228
229 if (client.url.match(match_admin_regexp)) {
230 // client URL matched the admin section of the platform
231
232 if (!client.focused) {
233 // focus available client
234 clientList[0].focus();
235 }
236
237 /**
238 * Post message to the application with the clicked notification payload
239 * to let the application handle the notification click action.
240 */
241 clientList[0].postMessage(payload);
242
243 // process completed
244 return;
245 }
246 }
247
248 // fallback to opening a new window
249
250 if (payload.type && (payload.title || payload.message)) {
251 /**
252 * Attempt to render the VikBooking admin URL by injecting
253 * the Push notification payload values via query string.
254 */
255 self.clients.openWindow(VBOWorker.getInstance().buildVikBookingAdminPushURI(payload));
256 } else if (payload.url) {
257 // open the requested URL
258 self.clients.openWindow(payload.url);
259 } else {
260 // open a blank new window by letting the browser detect the URL
261 self.clients.openWindow('/');
262 }
263 }));
264 });
265