web-push-notifications 3.40.3 → 3.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/.editorconfig +11 -0
  2. package/.gitlab-ci.yml +190 -0
  3. package/babel.config.js +7 -0
  4. package/ci/cdn/Dockerfile +12 -0
  5. package/ci/dev/Dockerfile +30 -0
  6. package/ci/dev/rootfs/entrypoint.sh +18 -0
  7. package/ci/dev/rootfs/entrypoint.sh.d/nginx.sh +6 -0
  8. package/ci/dev/rootfs/entrypoint.sh.d/supervisor.sh +5 -0
  9. package/ci/dev/rootfs/etc/nginx/_real_ip.conf +2 -0
  10. package/ci/dev/rootfs/etc/nginx/conf.d/default.conf +20 -0
  11. package/ci/dev/rootfs/etc/supervisor.d/nginx.ini +11 -0
  12. package/ci/github/Dockerfile +59 -0
  13. package/ci/github/release-zip.js +61 -0
  14. package/ci/npm/Dockerfile +19 -0
  15. package/config/config.js +24 -0
  16. package/config/configBuilder.js +126 -0
  17. package/config/helpers.js +9 -0
  18. package/config/index.js +1 -0
  19. package/develop/README.md +42 -0
  20. package/develop/favicon.png +0 -0
  21. package/develop/index.html +511 -0
  22. package/eslint.config.mjs +114 -0
  23. package/package.json +4 -34
  24. package/{lib → public}/index.d.ts +10 -10
  25. package/scripts/zip.js +26 -0
  26. package/src/core/Pushwoosh.ts +768 -0
  27. package/src/core/Pushwoosh.types.ts +254 -0
  28. package/src/core/Safari.types.ts +26 -0
  29. package/src/core/constants.ts +58 -0
  30. package/src/core/events.types.ts +46 -0
  31. package/src/core/functions.ts +33 -0
  32. package/src/core/legacyEventsMap.ts +64 -0
  33. package/src/core/logger.ts +64 -0
  34. package/src/core/modules/EventBus/EventBus.ts +66 -0
  35. package/src/core/modules/EventBus/index.ts +1 -0
  36. package/src/core/storage.ts +254 -0
  37. package/src/helpers/logger.ts +81 -0
  38. package/src/helpers/pwlogger/Logger.constants.ts +31 -0
  39. package/src/helpers/pwlogger/Logger.ts +218 -0
  40. package/src/helpers/pwlogger/Logger.types.ts +66 -0
  41. package/src/helpers/pwlogger/handlers/handler-console/handler-console.ts +40 -0
  42. package/src/helpers/pwlogger/index.ts +2 -0
  43. package/src/helpers/unescape.ts +36 -0
  44. package/src/models/InboxMessages.ts +202 -0
  45. package/src/models/InboxMessages.types.ts +111 -0
  46. package/src/models/NotificationPayload.ts +216 -0
  47. package/src/models/NotificationPayload.types.ts +65 -0
  48. package/src/modules/Api/Api.ts +386 -0
  49. package/src/modules/Api/Api.types.ts +7 -0
  50. package/src/modules/ApiClient/ApiClient.ts +153 -0
  51. package/src/modules/ApiClient/ApiClient.types.ts +222 -0
  52. package/src/modules/Data/Data.ts +345 -0
  53. package/src/modules/DateModule.ts +53 -0
  54. package/src/modules/InboxMessagesPublic.ts +222 -0
  55. package/src/modules/PlatformChecker/PlatformChecker.ts +170 -0
  56. package/src/modules/PlatformChecker/PlatformChecker.types.ts +5 -0
  57. package/src/modules/PlatformChecker/index.ts +1 -0
  58. package/src/modules/storage/Storage.ts +164 -0
  59. package/src/modules/storage/Storage.types.ts +54 -0
  60. package/src/modules/storage/Store.ts +104 -0
  61. package/src/modules/storage/migrations/26-11-2018.ts +25 -0
  62. package/src/modules/storage/migrations/MigrationExecutor.ts +31 -0
  63. package/src/modules/storage/migrations/Migrations.ts +41 -0
  64. package/src/modules/storage/migrations/constants.ts +8 -0
  65. package/src/modules/storage/migrations/helpers.ts +16 -0
  66. package/src/modules/storage/migrations/initial.ts +47 -0
  67. package/src/modules/storage/version.ts +2 -0
  68. package/src/npm.ts +1 -0
  69. package/src/pushwoosh-web-notifications.ts +47 -0
  70. package/src/pushwoosh-widget-inbox.ts +8 -0
  71. package/src/pushwoosh-widget-subscribe-popup.ts +9 -0
  72. package/src/pushwoosh-widget-subscription-button.ts +8 -0
  73. package/src/pushwoosh-widget-subscription-prompt.ts +6 -0
  74. package/src/service-worker.ts +455 -0
  75. package/src/services/PushService/PushService.ts +2 -0
  76. package/src/services/PushService/PushService.types.ts +74 -0
  77. package/src/services/PushService/drivers/PushServiceDefault/PushServiceDefault.ts +235 -0
  78. package/src/services/PushService/drivers/PushServiceDefault/PushServiceDefault.types.ts +3 -0
  79. package/src/services/PushService/drivers/PushServiceSafari/PushServiceSafari.ts +125 -0
  80. package/src/services/PushService/drivers/PushServiceSafari/PushServiceSafari.types.ts +4 -0
  81. package/src/widget-inbox.ts +1 -0
  82. package/src/widget-subscribe-popup.ts +1 -0
  83. package/src/widget-subscription-button.ts +1 -0
  84. package/src/widget-subscription-prompt.ts +33 -0
  85. package/src/widgets/Inbox/InboxWidget.ts +564 -0
  86. package/src/widgets/Inbox/constants.ts +49 -0
  87. package/src/widgets/Inbox/css/inboxWidgetStyle.css +274 -0
  88. package/src/widgets/Inbox/helpers.ts +63 -0
  89. package/src/widgets/Inbox/inbox.d.ts +9 -0
  90. package/src/widgets/Inbox/inbox_widget.types.ts +41 -0
  91. package/src/widgets/Inbox/index.ts +1 -0
  92. package/src/widgets/Inbox/widgetTemplates.ts +55 -0
  93. package/src/widgets/SubscribePopup/SubscribePopup.ts +241 -0
  94. package/src/widgets/SubscribePopup/constants.ts +66 -0
  95. package/src/widgets/SubscribePopup/helpers.ts +11 -0
  96. package/src/widgets/SubscribePopup/index.ts +1 -0
  97. package/src/widgets/SubscribePopup/popupTemplates.ts +24 -0
  98. package/src/widgets/SubscribePopup/styles/popup.css +226 -0
  99. package/src/widgets/SubscribePopup/types/subscribe-popup.ts +68 -0
  100. package/src/widgets/SubscriptionButton/assets/css/main.css +205 -0
  101. package/src/widgets/SubscriptionButton/bell.ts +67 -0
  102. package/src/widgets/SubscriptionButton/constants.ts +28 -0
  103. package/src/widgets/SubscriptionButton/index.ts +377 -0
  104. package/src/widgets/SubscriptionButton/positioning.ts +165 -0
  105. package/src/widgets/SubscriptionButton/subscribe_widget.types.ts +53 -0
  106. package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.constants.ts +1 -0
  107. package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.helpers.ts +110 -0
  108. package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.ts +102 -0
  109. package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.types.ts +23 -0
  110. package/src/widgets/SubscriptionPrompt/constants.ts +22 -0
  111. package/src/widgets/SubscriptionPrompt/helpers.ts +42 -0
  112. package/src/widgets/widgets.d.ts +4 -0
  113. package/src/worker/global.ts +36 -0
  114. package/src/worker/notification.ts +34 -0
  115. package/src/worker/worker.types.ts +4 -0
  116. package/test/__helpers__/apiHelpers.ts +22 -0
  117. package/test/__helpers__/keyValueHelpers.ts +15 -0
  118. package/test/__helpers__/platformHelpers.ts +54 -0
  119. package/test/__helpers__/sinonHelpers.ts +7 -0
  120. package/test/__helpers__/storageHelpers.ts +56 -0
  121. package/test/__mocks__/apiRequests.ts +26 -0
  122. package/test/__mocks__/idbMock.ts +12 -0
  123. package/test/__mocks__/idbObjectStoreMock.ts +38 -0
  124. package/test/__mocks__/inboxMessages.ts +292 -0
  125. package/test/__mocks__/models/inboxModel.ts +71 -0
  126. package/test/__mocks__/modules/apiClientModule.ts +18 -0
  127. package/test/__mocks__/modules/dateModule.ts +34 -0
  128. package/test/__mocks__/modules/inboxParamsModule.ts +21 -0
  129. package/test/__mocks__/modules/paramsBuilder.ts +12 -0
  130. package/test/__mocks__/modules/paramsModule.ts +35 -0
  131. package/test/__mocks__/modules/payloadBuilderModule.ts +15 -0
  132. package/test/__mocks__/modules/storageModule.ts +58 -0
  133. package/test/__mocks__/navigator.ts +38 -0
  134. package/test/__mocks__/notification.ts +84 -0
  135. package/test/__mocks__/pushwoosh.ts +12 -0
  136. package/test/__mocks__/userAgents +8 -0
  137. package/test/functions.test.ts +22 -0
  138. package/test/ignore-html.js +6 -0
  139. package/test/mocha.opts +6 -0
  140. package/test/modules/DateModule/unit.test.ts +80 -0
  141. package/test/modules/storage/Storage/unit.test.ts +180 -0
  142. package/test/modules/storage/Store/unit.test.ts +192 -0
  143. package/testRegister.js +24 -0
  144. package/tsconfig.json +31 -0
  145. package/webpack.config.js +163 -0
  146. package/lib/index.js +0 -2
  147. package/lib/index.js.map +0 -1
  148. package/lib/service-worker.js +0 -2
  149. package/lib/service-worker.js.map +0 -1
@@ -0,0 +1,377 @@
1
+ import {
2
+ PERMISSION_GRANTED,
3
+ PERMISSION_DENIED,
4
+ PERMISSION_PROMPT,
5
+ } from '../../core/constants';
6
+ import mainCss from './assets/css/main.css';
7
+ import bellSVG from './bell';
8
+ import {
9
+ SUBSCRIBE_WIDGET_DEFAULT_CONFIG,
10
+ WIDGET_CONTAINER_ID,
11
+ } from './constants';
12
+ import Positioning from './positioning';
13
+ import { type TBellConfig, type TCSSStylesObject, type TStyleKeys } from './subscribe_widget.types';
14
+ import { type Pushwoosh } from '../../core/Pushwoosh';
15
+ import {
16
+ type TPlatformChrome,
17
+ type TPlatformEdge,
18
+ type TPlatformFirefox,
19
+ type TPlatformSafari,
20
+ } from '../../modules/PlatformChecker/PlatformChecker.types';
21
+
22
+ export class PWSubscriptionButtonWidget {
23
+ widget: HTMLElement;
24
+ tooltip: HTMLElement;
25
+ popover: HTMLElement;
26
+ style: HTMLElement;
27
+ pw: Pushwoosh;
28
+ config: TBellConfig;
29
+
30
+ constructor(pw: Pushwoosh) {
31
+ // Set Pushwoosh object
32
+ this.pw = pw;
33
+ if (!pw.platformChecker.isAvailableNotifications) {
34
+ console.warn('Browser does not support push notifications');
35
+ return;
36
+ }
37
+
38
+ // Bindings
39
+ this.clickBell = this.clickBell.bind(this);
40
+ this.onSubscribeEvent = this.onSubscribeEvent.bind(this);
41
+ this.onUnsubscribeEvent = this.onUnsubscribeEvent.bind(this);
42
+ this.onPermissionDeniedEvent = this.onPermissionDeniedEvent.bind(this);
43
+ this.clickOutOfPopover = this.clickOutOfPopover.bind(this);
44
+
45
+ // Config
46
+ const tooltipText = Object.assign(SUBSCRIBE_WIDGET_DEFAULT_CONFIG.tooltipText, pw.initParams.subscribeWidget!.tooltipText);
47
+ this.config = Object.assign({}, SUBSCRIBE_WIDGET_DEFAULT_CONFIG, pw.initParams.subscribeWidget);
48
+ this.config.tooltipText = tooltipText;
49
+
50
+ // Render if not subscribed
51
+ pw.isSubscribed().then((isSubscribed) => {
52
+ if (!isSubscribed) {
53
+ this.render();
54
+ }
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Apply styles to element
60
+ * @param styles
61
+ * @param {HTMLElement} element
62
+ */
63
+ private addStylesToElement(styles: TCSSStylesObject, element: HTMLElement) {
64
+ Object.keys(styles).forEach((st: TStyleKeys) => {
65
+ element.style[st] = styles[st];
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Create container element
71
+ * @returns {HTMLElement}
72
+ */
73
+ private createContainer(): HTMLElement {
74
+ const container = document.createElement('div');
75
+ container.id = WIDGET_CONTAINER_ID;
76
+ container.className = 'pushwoosh-subscribe-widget';
77
+ const position = Positioning.getBellPosition(this.config.position, this.config.indent);
78
+ const styles = Object.assign({
79
+ zIndex: this.config.zIndex,
80
+ }, position);
81
+ this.addStylesToElement(styles, container);
82
+ return container;
83
+ }
84
+
85
+ /**
86
+ * Create styles element
87
+ * @returns {HTMLElement}
88
+ */
89
+ private createStyle(): HTMLElement {
90
+ const styleNode = document.createElement('style');
91
+ styleNode.innerHTML = mainCss;
92
+ return styleNode;
93
+ }
94
+
95
+ /**
96
+ * Create cell button element
97
+ * @returns {HTMLElement}
98
+ */
99
+ private createBell(): HTMLElement {
100
+ const { config } = this;
101
+ let bell;
102
+ if (config.buttonImage) {
103
+ bell = document.createElement('img') as HTMLImageElement;
104
+ bell.src = config.buttonImage;
105
+ } else {
106
+ bell = document.createElement('div');
107
+ this.addStylesToElement({
108
+ backgroundColor: config.bgColor,
109
+ boxShadow: config.shadow,
110
+ lineHeight: config.size,
111
+ border: config.bellButtonBorder,
112
+ }, bell);
113
+
114
+ bell.innerHTML = bellSVG(config.bellColor, config.bellStrokeColor);
115
+ }
116
+ this.addStylesToElement({
117
+ width: config.size,
118
+ height: config.size,
119
+ }, bell);
120
+ bell.className = 'pushwoosh-subscribe-widget__bell-button';
121
+ return bell;
122
+ }
123
+
124
+ /**
125
+ * Create tooltip element
126
+ * @returns {Promise<HTMLElement>}
127
+ */
128
+ private async createTooltip(): Promise<HTMLElement> {
129
+ const tooltip = document.createElement('div');
130
+ const [position, modification] = Positioning.getTooltipPosition(this.config.position, this.config.size);
131
+ tooltip.className = `pushwoosh-subscribe-widget__tooltip pushwoosh-subscribe-widget__tooltip__${modification}`;
132
+ this.addStylesToElement(position, tooltip);
133
+
134
+ tooltip.appendChild(await this.createTooltipContent());
135
+ return tooltip;
136
+ }
137
+
138
+ /**
139
+ * Create tooltip content element
140
+ * @returns {Promise<HTMLElement>}
141
+ */
142
+ private async createTooltipContent(): Promise<HTMLElement> {
143
+ const tooltipContent = document.createElement('div');
144
+ tooltipContent.innerText = await this.tooltipTextFactory();
145
+ tooltipContent.className = 'pushwoosh-subscribe-widget__tooltip-content';
146
+ return tooltipContent;
147
+ }
148
+
149
+ /**
150
+ * Tooltip text content depending of the permissions
151
+ * @returns {Promise<string>}
152
+ */
153
+ private async tooltipTextFactory(): Promise<string> {
154
+ const permission = this.pw.driver.getPermission();
155
+ const { tooltipText } = this.config;
156
+ const isManuallyUnsubscribed = await this.pw.data.getStatusManualUnsubscribed();
157
+
158
+ switch (permission) {
159
+ case PERMISSION_GRANTED:
160
+ return isManuallyUnsubscribed ? tooltipText.needSubscribe : tooltipText.alreadySubscribed;
161
+ case PERMISSION_PROMPT:
162
+ return tooltipText.needSubscribe;
163
+ case PERMISSION_DENIED:
164
+ return tooltipText.blockSubscribe;
165
+ default:
166
+ return tooltipText.needSubscribe;
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Create permission denied popover element
172
+ * @returns {HTMLElement}
173
+ */
174
+ private createPopover(): HTMLElement {
175
+ const popoverContentWrapper = document.createElement('div');
176
+ const popover = document.createElement('div');
177
+ const [position, modification] = Positioning.getPopoverPosition(this.config.position, this.config.size);
178
+ popover.className = `pushwoosh-subscribe-widget__popover pushwoosh-subscribe-widget__popover__${modification}`;
179
+ popoverContentWrapper.className = 'pushwoosh-subscribe-widget__popover-content-wrapper';
180
+
181
+ this.style.innerHTML += Positioning.getPopoverArrowPosition(this.config.position, this.config.size);
182
+
183
+ const styles = Object.assign({
184
+ maxWidth: `calc(100vw - ${this.config.indent} - ${this.config.indent})`,
185
+ }, position);
186
+ this.addStylesToElement(styles, popover);
187
+
188
+ popoverContentWrapper.appendChild(this.createPopoverContent());
189
+ popover.appendChild(popoverContentWrapper);
190
+ return popover;
191
+ }
192
+
193
+ private getBrowserName() {
194
+ const platformChecker = this.pw.platformChecker;
195
+ let browser;
196
+ if (platformChecker.isOpera) {
197
+ browser = 'opera';
198
+ } else if (<TPlatformChrome>platformChecker.platform === 11 && navigator.userAgent.match(/Android/i)) {
199
+ browser = 'mobileChrome';
200
+ } else if (<TPlatformFirefox>platformChecker.platform === 12) {
201
+ browser = 'firefox';
202
+ } else if (<TPlatformSafari>platformChecker.platform === 10) {
203
+ browser = 'safari';
204
+ } else if (<TPlatformEdge>platformChecker.platform === 150) {
205
+ browser = 'edge';
206
+ } else {
207
+ browser = 'chrome';
208
+ }
209
+ return browser;
210
+ }
211
+
212
+ /**
213
+ * Create permission denied popover content element
214
+ * @returns {HTMLElement}
215
+ */
216
+ private createPopoverContent(): HTMLElement {
217
+ const { config } = this;
218
+ const popoverContent = document.createElement('div');
219
+ popoverContent.className = 'pushwoosh-subscribe-widget__popover-content';
220
+
221
+ const browser = this.getBrowserName();
222
+
223
+ const userImageSrc = config.contentImages && config.contentImages[browser];
224
+ if (userImageSrc) {
225
+ const image = document.createElement('img') as HTMLImageElement;
226
+ image.src = userImageSrc;
227
+ popoverContent.appendChild(image);
228
+ } else {
229
+ const standardImagesMap: Record<string, string> = {
230
+ opera: 'opera',
231
+ mobileChrome: 'mobile_chrome',
232
+ firefox: 'FF',
233
+ safari: 'safari',
234
+ };
235
+ const standardImage = standardImagesMap[browser] || 'chrome';
236
+ [{
237
+ src: this.getImageSrc(standardImage),
238
+ width: 500,
239
+ height: 130,
240
+ }, {
241
+ src: this.getImageSrc(`${standardImage}_unlock`),
242
+ width: 500,
243
+ height: 230,
244
+ }].forEach((imageAttrs) => {
245
+ const image = document.createElement('img');
246
+ Object.assign(image, imageAttrs);
247
+ popoverContent.appendChild(image);
248
+ });
249
+ }
250
+
251
+ return popoverContent;
252
+ }
253
+
254
+ /**
255
+ * Return source of help images depending of the browser
256
+ * @returns {string}
257
+ */
258
+ getImageSrc(img: string): string {
259
+ return `https://cdn.pushwoosh.com/webpush/img/${img}.jpg`;
260
+ }
261
+
262
+ private async render() {
263
+ this.widget = this.createContainer();
264
+ this.style = this.createStyle();
265
+ const bell = this.createBell();
266
+ this.tooltip = await this.createTooltip();
267
+ this.popover = await this.createPopover();
268
+
269
+ this.widget.appendChild(this.style);
270
+ this.widget.appendChild(bell);
271
+ this.widget.appendChild(this.tooltip);
272
+ this.widget.appendChild(this.popover);
273
+
274
+ document.body.appendChild(this.widget);
275
+
276
+ this.pw.push(['onSubscribe', this.onSubscribeEvent]);
277
+ this.pw.push(['onUnsubscribe', this.onUnsubscribeEvent]);
278
+ this.pw.push(['onPermissionDenied', this.onPermissionDeniedEvent]);
279
+
280
+ this.addEventListeners();
281
+ }
282
+
283
+ addEventListeners() {
284
+ this.widget.addEventListener('click', this.clickBell);
285
+ window.addEventListener('click', this.clickOutOfPopover);
286
+ }
287
+
288
+ /**
289
+ * Toggle visibility of popover
290
+ */
291
+ toggleHelpPopover() {
292
+ this.popover.classList.toggle('pushwoosh-subscribe-widget__popover__visible');
293
+ }
294
+
295
+ /**
296
+ * Click bell button event callback
297
+ * @returns {Promise<void>}
298
+ */
299
+ private async clickBell() {
300
+ const permission = this.pw.driver.getPermission();
301
+
302
+ switch (permission) {
303
+ case PERMISSION_GRANTED:
304
+ await this.pw.subscribe();
305
+
306
+ break;
307
+ case PERMISSION_PROMPT:
308
+ await this.pw.subscribe();
309
+
310
+ break;
311
+ case PERMISSION_DENIED:
312
+ this.toggleHelpPopover();
313
+
314
+ break;
315
+ default:
316
+ console.warn('Unknown browser notification permission');
317
+ }
318
+ }
319
+
320
+ /**
321
+ * On subscribe event callback
322
+ * @returns {Promise<void>}
323
+ */
324
+ private async onSubscribeEvent() {
325
+ const tooltipContent = this.tooltip.querySelector('div');
326
+
327
+ if (tooltipContent === null) {
328
+ return;
329
+ }
330
+
331
+ tooltipContent.innerText = this.config.tooltipText.successSubscribe;
332
+ this.tooltip.classList.add('pushwoosh-subscribe-widget__tooltip__visible');
333
+
334
+ setTimeout(async () => {
335
+ this.tooltip.classList.remove('pushwoosh-subscribe-widget__tooltip__visible');
336
+ tooltipContent.innerText = await this.tooltipTextFactory();
337
+
338
+ this.widget.classList.add('pushwoosh-subscribe-widget__subscribed');
339
+ }, 2000);
340
+ }
341
+
342
+ /**
343
+ * On permission denied event
344
+ * @returns {Promise<void>}
345
+ */
346
+ private async onPermissionDeniedEvent(): Promise<void> {
347
+ this.addEventListeners();
348
+
349
+ const tooltipContent = this.tooltip.querySelector('div');
350
+ if (tooltipContent === null) return;
351
+ tooltipContent.innerText = await this.tooltipTextFactory();
352
+ }
353
+
354
+ /**
355
+ * Out of popover click event
356
+ * @param {MessageEvent} ev
357
+ */
358
+ clickOutOfPopover(ev: MessageEvent) {
359
+ const closeRule = this.popover.classList.contains('pushwoosh-subscribe-widget__popover__visible')
360
+ && !(ev.target as any).classList.contains('pushwoosh-subscribe-widget__popover')
361
+ && (ev.target as any).closest('.pushwoosh-subscribe-widget__popover') === null
362
+ && !(ev.target as any).classList.contains('pushwoosh-subscribe-widget__bell-button')
363
+ && (ev.target as any).closest('.pushwoosh-subscribe-widget__bell-button') === null;
364
+
365
+ if (closeRule) this.popover.classList.remove('pushwoosh-subscribe-widget__popover__visible');
366
+ }
367
+
368
+ private async onUnsubscribeEvent() {
369
+ const tooltipContent = this.tooltip.querySelector('div');
370
+
371
+ if (tooltipContent === null) {
372
+ return;
373
+ }
374
+
375
+ tooltipContent.innerText = await this.tooltipTextFactory();
376
+ }
377
+ }
@@ -0,0 +1,165 @@
1
+ import {
2
+ BELL_POSITION_TOP_RIGHT,
3
+ BELL_POSITION_TOP_LEFT,
4
+ BELL_POSITION_BOTTOM_LEFT,
5
+ BELL_POSITION_BOTTOM_RIGHT,
6
+ } from './constants';
7
+ import { type TBellPosition, type TPositionStyles } from './subscribe_widget.types';
8
+
9
+ export default class Positioning {
10
+ public static getBellPosition(position: TBellPosition, indent: string): TPositionStyles {
11
+ let positionStyles: TPositionStyles;
12
+
13
+ switch (position) {
14
+ case BELL_POSITION_BOTTOM_RIGHT:
15
+ positionStyles = {
16
+ top: 'auto',
17
+ left: 'auto',
18
+ bottom: indent,
19
+ right: indent,
20
+ };
21
+ break;
22
+ case BELL_POSITION_BOTTOM_LEFT:
23
+ positionStyles = {
24
+ top: 'auto',
25
+ left: indent,
26
+ bottom: indent,
27
+ right: 'auto',
28
+ };
29
+ break;
30
+ case BELL_POSITION_TOP_LEFT:
31
+ positionStyles = {
32
+ top: indent,
33
+ left: indent,
34
+ bottom: 'auto',
35
+ right: 'auto',
36
+ };
37
+ break;
38
+ case BELL_POSITION_TOP_RIGHT:
39
+ positionStyles = {
40
+ top: indent,
41
+ left: 'auto',
42
+ bottom: 'auto',
43
+ right: indent,
44
+ };
45
+ break;
46
+ default:
47
+ positionStyles = {
48
+ top: 'auto',
49
+ left: 'auto',
50
+ bottom: indent,
51
+ right: indent,
52
+ };
53
+ }
54
+
55
+ return positionStyles;
56
+ }
57
+
58
+ public static getTooltipPosition(bellPosition: TBellPosition, bellSize: string): [{ left: string } | { right: string }, string] {
59
+ let positionStyles;
60
+ let tooltipModification;
61
+ const increaseIndent = (parseInt(bellSize) + 12) + 'px';
62
+
63
+ switch (bellPosition) {
64
+ case BELL_POSITION_BOTTOM_RIGHT:
65
+ positionStyles = { right: increaseIndent };
66
+ tooltipModification = 'right';
67
+ break;
68
+ case BELL_POSITION_BOTTOM_LEFT:
69
+ positionStyles = { left: increaseIndent };
70
+ tooltipModification = 'left';
71
+ break;
72
+ case BELL_POSITION_TOP_LEFT:
73
+ positionStyles = { left: increaseIndent };
74
+ tooltipModification = 'left';
75
+ break;
76
+ case BELL_POSITION_TOP_RIGHT:
77
+ positionStyles = { right: increaseIndent };
78
+ tooltipModification = 'right';
79
+ break;
80
+ default:
81
+ positionStyles = { right: increaseIndent };
82
+ tooltipModification = 'right';
83
+ }
84
+
85
+ return [positionStyles, tooltipModification];
86
+ }
87
+
88
+ public static getPopoverPosition(bellPosition: TBellPosition, bellSize: string): [TPositionStyles, string] {
89
+ let positionStyles;
90
+ let popoverModification;
91
+ const increaseIndent = (parseInt(bellSize) + 15) + 'px';
92
+
93
+ switch (bellPosition) {
94
+ case BELL_POSITION_BOTTOM_RIGHT:
95
+ positionStyles = {
96
+ bottom: increaseIndent,
97
+ right: '0',
98
+ left: 'auto',
99
+ top: 'auto',
100
+ };
101
+ popoverModification = 'bottom';
102
+ break;
103
+ case BELL_POSITION_BOTTOM_LEFT:
104
+ positionStyles = {
105
+ bottom: increaseIndent,
106
+ left: '0',
107
+ right: 'auto',
108
+ top: 'auto',
109
+ };
110
+ popoverModification = 'bottom';
111
+ break;
112
+ case BELL_POSITION_TOP_LEFT:
113
+ positionStyles = {
114
+ top: increaseIndent,
115
+ left: '0',
116
+ right: 'auto',
117
+ bottom: 'auto',
118
+ };
119
+ popoverModification = 'top';
120
+ break;
121
+ case BELL_POSITION_TOP_RIGHT:
122
+ positionStyles = {
123
+ top: increaseIndent,
124
+ right: '0',
125
+ left: 'auto',
126
+ bottom: 'auto',
127
+ };
128
+ popoverModification = 'top';
129
+ break;
130
+ default:
131
+ positionStyles = {
132
+ bottom: increaseIndent,
133
+ right: '0',
134
+ left: 'auto',
135
+ top: 'auto',
136
+ };
137
+ popoverModification = 'bottom';
138
+ }
139
+
140
+ return [positionStyles, popoverModification];
141
+ }
142
+
143
+ public static getPopoverArrowPosition(bellPosition: TBellPosition, bellSize: string) {
144
+ let arrowAdditionalStyles;
145
+
146
+ switch (bellPosition) {
147
+ case BELL_POSITION_BOTTOM_RIGHT:
148
+ arrowAdditionalStyles = `\n.pushwoosh-subscribe-widget__popover__bottom:after {left: auto; right: ${(parseInt(bellSize) / 2 - 4) + 'px'}`;
149
+ break;
150
+ case BELL_POSITION_BOTTOM_LEFT:
151
+ arrowAdditionalStyles = `\n.pushwoosh-subscribe-widget__popover__bottom:after {right: auto; left: ${(parseInt(bellSize) / 2 - 12) + 'px'}`;
152
+ break;
153
+ case BELL_POSITION_TOP_LEFT:
154
+ arrowAdditionalStyles = `\n.pushwoosh-subscribe-widget__popover__top:after {right: auto; left: ${(parseInt(bellSize) / 2 - 12) + 'px'}`;
155
+ break;
156
+ case BELL_POSITION_TOP_RIGHT:
157
+ arrowAdditionalStyles = `\n.pushwoosh-subscribe-widget__popover__top:after {left: auto; right: ${(parseInt(bellSize) / 2 - 4) + 'px'}`;
158
+ break;
159
+ default:
160
+ arrowAdditionalStyles = `\n.pushwoosh-subscribe-widget__popover__bottom:after {left: auto; right: ${(parseInt(bellSize) / 2 - 4) + 'px'}`;
161
+ }
162
+
163
+ return arrowAdditionalStyles;
164
+ }
165
+ }
@@ -0,0 +1,53 @@
1
+ export type TBellPosition = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
2
+
3
+ export type TTooltipText = {
4
+ successSubscribe: string;
5
+ needSubscribe: string;
6
+ blockSubscribe: string;
7
+ alreadySubscribed: string;
8
+ };
9
+ export type TBellConfig = {
10
+ position: TBellPosition;
11
+ bgColor: string;
12
+ bellColor: string;
13
+ bellStrokeColor: string;
14
+ bellButtonBorder: string;
15
+ shadow: string;
16
+ size: string;
17
+ indent: string; // edge indent
18
+ zIndex: string;
19
+ tooltipText: TTooltipText;
20
+ buttonImage?: string;
21
+ contentImages?: Record<string, string>;
22
+ };
23
+
24
+ export type TPositionStyles = {
25
+ top: string;
26
+ bottom: string;
27
+ left: string;
28
+ right: string;
29
+ };
30
+
31
+ export type TEvent = {
32
+ event_id: number | string;
33
+ application: string;
34
+ };
35
+
36
+ export type TStyleKeys = 'left'
37
+ | 'right'
38
+ | 'top'
39
+ | 'bottom'
40
+ | 'zIndex'
41
+ | 'position'
42
+ | 'backgroundColor'
43
+ | 'background'
44
+ | 'width'
45
+ | 'height'
46
+ | 'boxShadow'
47
+ | 'lineHeight'
48
+ | 'border'
49
+ | 'maxWidth'
50
+ | 'maxHeight';
51
+ export type TCSSStylesObject = {
52
+ [style: string]: string;
53
+ };
@@ -0,0 +1 @@
1
+ export const SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE = 'pushwoosh-subscription-widget';
@@ -0,0 +1,110 @@
1
+ import { SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE } from './SubscriptionPromptWidget.constants';
2
+ import { type ISubscriptionPromptWidgetParams } from './SubscriptionPromptWidget.types';
3
+
4
+ export const getHTML = (params: ISubscriptionPromptWidgetParams): string => {
5
+ return `
6
+ <div id="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}-root" class="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}">
7
+ <div class="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__body">
8
+ <div class="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__header">
9
+ ${params.headerText}
10
+ </div>
11
+ <div class="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__description">
12
+ ${params.subheaderText}
13
+ </div>
14
+ <div class="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__controls">
15
+ <button type="button" id="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}-decline" class="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__control ${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__control_decline">
16
+ ${params.buttonCancelText}
17
+ </button>
18
+ <button type="button" id="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}-accept" class="${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__control ${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__control_accept">
19
+ ${params.buttonAcceptText}
20
+ </button>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ `;
25
+ };
26
+
27
+ export const getStyles = (params: ISubscriptionPromptWidgetParams) => {
28
+ const styles = document.createElement('style');
29
+
30
+ styles.innerHTML = `
31
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE} * {
32
+ box-sizing: border-box!important;
33
+ }
34
+
35
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE} {
36
+ position: fixed;
37
+ top: 0;
38
+ left: 0;
39
+ right: 0;
40
+ margin: 0 auto;
41
+ width: 320px;
42
+ display: none;
43
+ z-index: 2147483648;
44
+ opacity: 0.99;
45
+ }
46
+
47
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}_show {
48
+ display: block;
49
+ }
50
+
51
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__body {
52
+ width: 320px;
53
+ background-color: ${params.backgroundColor ? params.backgroundColor : '#FFFFFF'};
54
+ box-shadow: 0 9px 15px rgba(0, 0, 0, 0.1), 0 0 6px rgba(0, 0, 0, 0.06);
55
+ border-radius: 4px;
56
+ padding: 20px 20px 12px;
57
+ }
58
+
59
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__header {
60
+ color: ${params.headerTextColor};
61
+ font-size: 18px;
62
+ font-weight: bold;
63
+ }
64
+
65
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__description {
66
+ color: ${params.subheaderTextColor};
67
+ font-size: 14px;
68
+ line-height: 1.5;
69
+ margin-top: 14px;
70
+ }
71
+
72
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__description:empty {
73
+ display: none;
74
+ }
75
+
76
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__controls {
77
+ display: flex;
78
+ flex-wrap: nowrap;
79
+ justify-content: flex-end;
80
+ margin: 20px 0 0;
81
+ }
82
+
83
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__control {
84
+ -webkit-appearance: none;
85
+ border: 1px solid transparent;
86
+ font-size: 12px;
87
+ font-weight: bold;
88
+ padding: 0 20px;
89
+ height: 32px;
90
+ cursor: pointer;
91
+ }
92
+
93
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__control_decline {
94
+ color: ${params.buttonCancelTextColor};
95
+ background-color: ${params.buttonCancelBackgroundColor};
96
+ border-radius: ${params.buttonCancelRound};
97
+ border-color: ${params.buttonCancelBorderColor};
98
+ }
99
+
100
+ .${SUBSCRIPTION_PROMPT_WIDGET_NAMESPACE}__control_accept {
101
+ color: ${params.buttonAcceptTextColor};
102
+ background-color: ${params.buttonAcceptBackgroundColor};
103
+ border-radius: ${params.buttonAcceptRound};
104
+ border-color: ${params.buttonAcceptBorderColor};
105
+ margin: 0 0 0 12px;
106
+ }
107
+ `;
108
+
109
+ return styles;
110
+ };