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.
- package/.editorconfig +11 -0
- package/.gitlab-ci.yml +190 -0
- package/babel.config.js +7 -0
- package/ci/cdn/Dockerfile +12 -0
- package/ci/dev/Dockerfile +30 -0
- package/ci/dev/rootfs/entrypoint.sh +18 -0
- package/ci/dev/rootfs/entrypoint.sh.d/nginx.sh +6 -0
- package/ci/dev/rootfs/entrypoint.sh.d/supervisor.sh +5 -0
- package/ci/dev/rootfs/etc/nginx/_real_ip.conf +2 -0
- package/ci/dev/rootfs/etc/nginx/conf.d/default.conf +20 -0
- package/ci/dev/rootfs/etc/supervisor.d/nginx.ini +11 -0
- package/ci/github/Dockerfile +59 -0
- package/ci/github/release-zip.js +61 -0
- package/ci/npm/Dockerfile +19 -0
- package/config/config.js +24 -0
- package/config/configBuilder.js +126 -0
- package/config/helpers.js +9 -0
- package/config/index.js +1 -0
- package/develop/README.md +42 -0
- package/develop/favicon.png +0 -0
- package/develop/index.html +511 -0
- package/eslint.config.mjs +114 -0
- package/package.json +4 -34
- package/{lib → public}/index.d.ts +10 -10
- package/scripts/zip.js +26 -0
- package/src/core/Pushwoosh.ts +768 -0
- package/src/core/Pushwoosh.types.ts +254 -0
- package/src/core/Safari.types.ts +26 -0
- package/src/core/constants.ts +58 -0
- package/src/core/events.types.ts +46 -0
- package/src/core/functions.ts +33 -0
- package/src/core/legacyEventsMap.ts +64 -0
- package/src/core/logger.ts +64 -0
- package/src/core/modules/EventBus/EventBus.ts +66 -0
- package/src/core/modules/EventBus/index.ts +1 -0
- package/src/core/storage.ts +254 -0
- package/src/helpers/logger.ts +81 -0
- package/src/helpers/pwlogger/Logger.constants.ts +31 -0
- package/src/helpers/pwlogger/Logger.ts +218 -0
- package/src/helpers/pwlogger/Logger.types.ts +66 -0
- package/src/helpers/pwlogger/handlers/handler-console/handler-console.ts +40 -0
- package/src/helpers/pwlogger/index.ts +2 -0
- package/src/helpers/unescape.ts +36 -0
- package/src/models/InboxMessages.ts +202 -0
- package/src/models/InboxMessages.types.ts +111 -0
- package/src/models/NotificationPayload.ts +216 -0
- package/src/models/NotificationPayload.types.ts +65 -0
- package/src/modules/Api/Api.ts +386 -0
- package/src/modules/Api/Api.types.ts +7 -0
- package/src/modules/ApiClient/ApiClient.ts +153 -0
- package/src/modules/ApiClient/ApiClient.types.ts +222 -0
- package/src/modules/Data/Data.ts +345 -0
- package/src/modules/DateModule.ts +53 -0
- package/src/modules/InboxMessagesPublic.ts +222 -0
- package/src/modules/PlatformChecker/PlatformChecker.ts +170 -0
- package/src/modules/PlatformChecker/PlatformChecker.types.ts +5 -0
- package/src/modules/PlatformChecker/index.ts +1 -0
- package/src/modules/storage/Storage.ts +164 -0
- package/src/modules/storage/Storage.types.ts +54 -0
- package/src/modules/storage/Store.ts +104 -0
- package/src/modules/storage/migrations/26-11-2018.ts +25 -0
- package/src/modules/storage/migrations/MigrationExecutor.ts +31 -0
- package/src/modules/storage/migrations/Migrations.ts +41 -0
- package/src/modules/storage/migrations/constants.ts +8 -0
- package/src/modules/storage/migrations/helpers.ts +16 -0
- package/src/modules/storage/migrations/initial.ts +47 -0
- package/src/modules/storage/version.ts +2 -0
- package/src/npm.ts +1 -0
- package/src/pushwoosh-web-notifications.ts +47 -0
- package/src/pushwoosh-widget-inbox.ts +8 -0
- package/src/pushwoosh-widget-subscribe-popup.ts +9 -0
- package/src/pushwoosh-widget-subscription-button.ts +8 -0
- package/src/pushwoosh-widget-subscription-prompt.ts +6 -0
- package/src/service-worker.ts +455 -0
- package/src/services/PushService/PushService.ts +2 -0
- package/src/services/PushService/PushService.types.ts +74 -0
- package/src/services/PushService/drivers/PushServiceDefault/PushServiceDefault.ts +235 -0
- package/src/services/PushService/drivers/PushServiceDefault/PushServiceDefault.types.ts +3 -0
- package/src/services/PushService/drivers/PushServiceSafari/PushServiceSafari.ts +125 -0
- package/src/services/PushService/drivers/PushServiceSafari/PushServiceSafari.types.ts +4 -0
- package/src/widget-inbox.ts +1 -0
- package/src/widget-subscribe-popup.ts +1 -0
- package/src/widget-subscription-button.ts +1 -0
- package/src/widget-subscription-prompt.ts +33 -0
- package/src/widgets/Inbox/InboxWidget.ts +564 -0
- package/src/widgets/Inbox/constants.ts +49 -0
- package/src/widgets/Inbox/css/inboxWidgetStyle.css +274 -0
- package/src/widgets/Inbox/helpers.ts +63 -0
- package/src/widgets/Inbox/inbox.d.ts +9 -0
- package/src/widgets/Inbox/inbox_widget.types.ts +41 -0
- package/src/widgets/Inbox/index.ts +1 -0
- package/src/widgets/Inbox/widgetTemplates.ts +55 -0
- package/src/widgets/SubscribePopup/SubscribePopup.ts +241 -0
- package/src/widgets/SubscribePopup/constants.ts +66 -0
- package/src/widgets/SubscribePopup/helpers.ts +11 -0
- package/src/widgets/SubscribePopup/index.ts +1 -0
- package/src/widgets/SubscribePopup/popupTemplates.ts +24 -0
- package/src/widgets/SubscribePopup/styles/popup.css +226 -0
- package/src/widgets/SubscribePopup/types/subscribe-popup.ts +68 -0
- package/src/widgets/SubscriptionButton/assets/css/main.css +205 -0
- package/src/widgets/SubscriptionButton/bell.ts +67 -0
- package/src/widgets/SubscriptionButton/constants.ts +28 -0
- package/src/widgets/SubscriptionButton/index.ts +377 -0
- package/src/widgets/SubscriptionButton/positioning.ts +165 -0
- package/src/widgets/SubscriptionButton/subscribe_widget.types.ts +53 -0
- package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.constants.ts +1 -0
- package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.helpers.ts +110 -0
- package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.ts +102 -0
- package/src/widgets/SubscriptionPrompt/SubscriptionPromptWidget.types.ts +23 -0
- package/src/widgets/SubscriptionPrompt/constants.ts +22 -0
- package/src/widgets/SubscriptionPrompt/helpers.ts +42 -0
- package/src/widgets/widgets.d.ts +4 -0
- package/src/worker/global.ts +36 -0
- package/src/worker/notification.ts +34 -0
- package/src/worker/worker.types.ts +4 -0
- package/test/__helpers__/apiHelpers.ts +22 -0
- package/test/__helpers__/keyValueHelpers.ts +15 -0
- package/test/__helpers__/platformHelpers.ts +54 -0
- package/test/__helpers__/sinonHelpers.ts +7 -0
- package/test/__helpers__/storageHelpers.ts +56 -0
- package/test/__mocks__/apiRequests.ts +26 -0
- package/test/__mocks__/idbMock.ts +12 -0
- package/test/__mocks__/idbObjectStoreMock.ts +38 -0
- package/test/__mocks__/inboxMessages.ts +292 -0
- package/test/__mocks__/models/inboxModel.ts +71 -0
- package/test/__mocks__/modules/apiClientModule.ts +18 -0
- package/test/__mocks__/modules/dateModule.ts +34 -0
- package/test/__mocks__/modules/inboxParamsModule.ts +21 -0
- package/test/__mocks__/modules/paramsBuilder.ts +12 -0
- package/test/__mocks__/modules/paramsModule.ts +35 -0
- package/test/__mocks__/modules/payloadBuilderModule.ts +15 -0
- package/test/__mocks__/modules/storageModule.ts +58 -0
- package/test/__mocks__/navigator.ts +38 -0
- package/test/__mocks__/notification.ts +84 -0
- package/test/__mocks__/pushwoosh.ts +12 -0
- package/test/__mocks__/userAgents +8 -0
- package/test/functions.test.ts +22 -0
- package/test/ignore-html.js +6 -0
- package/test/mocha.opts +6 -0
- package/test/modules/DateModule/unit.test.ts +80 -0
- package/test/modules/storage/Storage/unit.test.ts +180 -0
- package/test/modules/storage/Store/unit.test.ts +192 -0
- package/testRegister.js +24 -0
- package/tsconfig.json +31 -0
- package/webpack.config.js +163 -0
- package/lib/index.js +0 -2
- package/lib/index.js.map +0 -1
- package/lib/service-worker.js +0 -2
- 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
|
+
};
|