pushfeedback 0.1.43 → 0.1.44

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.
@@ -1,845 +1,845 @@
1
- import { h } from '@stencil/core';
2
- import html2canvas from 'html2canvas';
3
- export class FeedbackModal {
4
- constructor() {
5
- this.onScrollDebounced = () => {
6
- clearTimeout(this.scrollTimeout);
7
- this.scrollTimeout = setTimeout(() => {
8
- document.documentElement.classList.remove('feedback-modal-screenshot-closing');
9
- document.documentElement.style.top = "";
10
- window.removeEventListener('scroll', this.onScrollDebounced);
11
- }, 200);
12
- };
13
- this.handleSubmit = async (event) => {
14
- event.preventDefault();
15
- this.resetOverflow();
16
- this.showScreenshotMode = false;
17
- this.showScreenshotTopBar = false;
18
- this.showModal = false;
19
- this.sending = true;
20
- try {
21
- const res = await fetch('https://app.pushfeedback.com/api/feedback/', {
22
- method: 'POST',
23
- body: JSON.stringify({
24
- url: window.location.href,
25
- message: this.formMessage,
26
- email: this.formEmail,
27
- project: this.project,
28
- screenshot: this.encodedScreenshot,
29
- rating: this.selectedRating,
30
- ratingMode: this.ratingMode,
31
- verification: this.formVerification,
32
- session: localStorage.getItem('pushfeedback_sessionid') || '',
33
- }),
34
- headers: {
35
- 'Content-Type': 'application/json'
36
- }
37
- });
38
- if (res.status === 201) {
39
- this.formSuccess = true;
40
- this.formError = false;
41
- }
42
- else {
43
- this.formSuccess = false;
44
- this.formError = true;
45
- this.formErrorStatus = res.status;
46
- }
47
- }
48
- catch (error) {
49
- console.log(error);
50
- this.formSuccess = false;
51
- this.formError = true;
52
- this.formErrorStatus = 500;
53
- }
54
- finally {
55
- this.sending = false;
56
- this.showModal = true;
57
- }
58
- };
59
- this.close = () => {
60
- this.sending = false;
61
- this.showModal = false;
62
- this.showScreenshotMode = false;
63
- this.showScreenshotTopBar = false;
64
- this.hasSelectedElement = false;
65
- this.encodedScreenshot = null;
66
- this.formSuccess = false;
67
- this.formError = false;
68
- this.formErrorStatus = 500;
69
- this.formMessage = '';
70
- this.formEmail = '';
71
- this.resetOverflow();
72
- };
73
- this.openScreenShot = () => {
74
- this.hasSelectedElement = false;
75
- this.showModal = false;
76
- this.showScreenshotMode = true;
77
- this.showScreenshotTopBar = true;
78
- this.encodedScreenshot = null;
79
- if (window.innerWidth > document.documentElement.clientWidth) {
80
- document.documentElement.classList.add('feedback-modal-screenshot-open--scroll');
81
- }
82
- const scrollY = window.scrollY;
83
- document.documentElement.style.top = `-${scrollY}px`;
84
- window.scrollTo(0, parseInt(document.documentElement.style.top || '0') * -1);
85
- document.documentElement.classList.add('feedback-modal-screenshot-open');
86
- };
87
- this.closeScreenShot = () => {
88
- this.showModal = false;
89
- this.showScreenshotMode = false;
90
- this.showScreenshotTopBar = false;
91
- this.hasSelectedElement = false;
92
- this.encodedScreenshot = null;
93
- this.resetOverflow();
94
- };
95
- this.handleMouseOverScreenShot = (event) => {
96
- event.preventDefault();
97
- if (this.hasSelectedElement)
98
- return;
99
- const borderOffset = 2;
100
- this.screenshotModal.style.display = 'none';
101
- const elementUnder = document.elementFromPoint(event.clientX, event.clientY);
102
- const rect = elementUnder.getBoundingClientRect();
103
- this.screenshotModal.style.display = '';
104
- // Get the bounding box of the element selected
105
- this.elementSelected.style.position = "absolute";
106
- this.elementSelected.style.left = `${rect.left}px`;
107
- this.elementSelected.style.top = `${rect.top}px`;
108
- this.elementSelected.style.width = `${rect.width}px`;
109
- this.elementSelected.style.height = `${rect.height}px`;
110
- this.elementSelected.classList.add('feedback-modal-element-hover');
111
- // Set the background color of nonselected areas
112
- // Top
113
- this.topSide.style.position = "absolute";
114
- this.topSide.style.left = `${rect.left}px`;
115
- this.topSide.style.top = '0px';
116
- this.topSide.style.width = `${rect.width + borderOffset}px`;
117
- this.topSide.style.height = `${rect.top}px`;
118
- this.topSide.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
119
- // Left
120
- this.leftSide.style.position = "absolute";
121
- this.leftSide.style.left = '0px';
122
- this.leftSide.style.top = '0px';
123
- this.leftSide.style.width = `${rect.left}px`;
124
- this.leftSide.style.height = '100vh';
125
- this.leftSide.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
126
- // Bottom
127
- this.bottomSide.style.position = "absolute";
128
- this.bottomSide.style.left = `${rect.left}px`;
129
- this.bottomSide.style.top = `${rect.bottom + borderOffset}px`;
130
- this.bottomSide.style.width = `${rect.width + borderOffset}px`;
131
- this.bottomSide.style.height = '100vh';
132
- this.bottomSide.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
133
- // Right
134
- this.rightSide.style.position = "absolute";
135
- this.rightSide.style.left = `${rect.right + borderOffset}px`;
136
- ;
137
- this.rightSide.style.top = '0px';
138
- this.rightSide.style.width = '100%';
139
- this.rightSide.style.height = '100vh';
140
- this.rightSide.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
141
- // Restore the visibility of the screenshot-modal
142
- this.screenshotModal.style.backgroundColor = 'transparent';
143
- };
144
- this.handleMouseClickedSelectedElement = async (event) => {
145
- event.preventDefault();
146
- if (!this.elementSelected) {
147
- return;
148
- }
149
- this.hasSelectedElement = true;
150
- this.elementSelected.classList.add('feedback-modal-element-selected');
151
- // Get the top position including the scroll offset
152
- const rectTop = this.elementSelected.getBoundingClientRect().top;
153
- const topWithScroll = rectTop + window.scrollY;
154
- // Move the element with the scroll offset
155
- this.elementSelected.style.top = `${topWithScroll}px`;
156
- // Clone the selected element and append it to the body
157
- const clonedElementSelected = this.elementSelected.cloneNode(true);
158
- document.body.appendChild(clonedElementSelected);
159
- // Reset the top position of the original element
160
- this.elementSelected.style.top = `${rectTop}px`;
161
- this.showScreenshotTopBar = false;
162
- this.showModal = false;
163
- try {
164
- const dataUrl = await this.captureScreenshot();
165
- console.log('Screenshot captured');
166
- this.encodedScreenshot = dataUrl;
167
- }
168
- catch (error) {
169
- console.error('Failed to capture screenshot:', error);
170
- this.hasSelectedElement = false;
171
- }
172
- finally {
173
- // Remove the cloned element and show the modal again
174
- document.body.removeChild(clonedElementSelected);
175
- this.showModal = true;
176
- }
177
- };
178
- this.sending = false;
179
- this.formMessage = '';
180
- this.formEmail = '';
181
- this.formSuccess = false;
182
- this.formVerification = '';
183
- this.formError = false;
184
- this.formErrorStatus = 500;
185
- this.encodedScreenshot = undefined;
186
- this.isPrivacyChecked = false;
187
- this.whitelabel = false;
188
- this.selectedRating = 0;
189
- this.errorMessage = "Please try again later.";
190
- this.errorMessage403 = "The request URL does not match the one defined in PushFeedback for this project.";
191
- this.errorMessage404 = "We could not find the provided project ID in PushFeedback.";
192
- this.modalTitle = 'Share your feedback';
193
- this.modalTitleSuccess = 'Thanks for your feedback!';
194
- this.modalTitleError = "Oops!";
195
- this.modalPosition = 'center';
196
- this.sendButtonText = 'Send';
197
- this.successMessage = "";
198
- this.project = '';
199
- this.screenshotButtonText = 'Add a screenshot';
200
- this.screenshotTopbarText = 'Select an element on this page';
201
- this.hideEmail = false;
202
- this.emailAddress = '';
203
- this.emailPlaceholder = 'Email address (optional)';
204
- this.messagePlaceholder = 'Comments';
205
- this.hideRating = false;
206
- this.rating = undefined;
207
- this.ratingMode = 'thumbs';
208
- this.ratingPlaceholder = 'Was this page helpful?';
209
- this.ratingStarsPlaceholder = 'How would you rate this page?';
210
- this.showModal = false;
211
- this.showScreenshotMode = false;
212
- this.showScreenshotTopBar = false;
213
- this.hasSelectedElement = false;
214
- this.hideScreenshotButton = false;
215
- this.hidePrivacyPolicy = true;
216
- this.privacyPolicyText = "I have read and expressly consent to the terms of the <a href='https://pushfeedback.com/privacy'>Privacy Policy</a>.";
217
- this.fetchData = true;
218
- }
219
- componentWillLoad() {
220
- if (this.fetchData)
221
- this.fetchProjectData();
222
- this.formEmail = this.emailAddress;
223
- if (this.rating) {
224
- this.selectedRating = this.rating;
225
- }
226
- if (this.ratingMode == "thumbs" && this.rating == 0) {
227
- this.selectedRating = 5;
228
- }
229
- }
230
- async fetchProjectData() {
231
- try {
232
- const response = await fetch('https://app.pushfeedback.com/api/projects/' + this.project + '/');
233
- const data = await response.json();
234
- this.whitelabel = data.whitelabel;
235
- }
236
- catch (error) {
237
- console.log(error);
238
- }
239
- }
240
- resetOverflow() {
241
- document.documentElement.classList.remove('feedback-modal-screenshot-open');
242
- document.documentElement.classList.remove('feedback-modal-screenshot-open--scroll');
243
- document.documentElement.classList.add('feedback-modal-screenshot-closing');
244
- window.scrollTo(0, parseInt(document.documentElement.style.top || '0') * -1);
245
- window.addEventListener('scroll', this.onScrollDebounced);
246
- }
247
- handleMessageInput(event) {
248
- this.formMessage = event.target.value;
249
- }
250
- handleEmailInput(event) {
251
- this.formEmail = event.target.value;
252
- }
253
- captureScreenshot() {
254
- return new Promise((resolve, reject) => {
255
- requestAnimationFrame(() => {
256
- html2canvas(document.body, {
257
- x: window.scrollX,
258
- y: window.scrollY,
259
- width: window.innerWidth,
260
- height: window.innerHeight,
261
- }).then(canvas => {
262
- const dataUrl = canvas.toDataURL();
263
- resolve(dataUrl);
264
- })
265
- .catch(error => {
266
- console.error(error);
267
- reject(error);
268
- });
269
- });
270
- });
271
- }
272
- handleCheckboxChange(event) {
273
- this.isPrivacyChecked = event.target.checked;
274
- }
275
- handleVerification(event) {
276
- this.formVerification = event.target.value;
277
- }
278
- handleRatingChange(newRating) {
279
- this.selectedRating = newRating;
280
- }
281
- render() {
282
- return (h("div", { class: 'feedback-modal-wrapper' }, this.showScreenshotMode && (h("div", { class: "feedback-modal-screenshot", ref: el => (this.screenshotModal = el), onMouseMove: this.handleMouseOverScreenShot }, h("div", { class: "feedback-modal-screenshot-element-selected", ref: el => (this.elementSelected = el), onClick: this.handleMouseClickedSelectedElement }), h("div", { class: "top-side", ref: el => (this.topSide = el) }), h("div", { class: "left-side", ref: el => (this.leftSide = el) }), h("div", { class: "bottom-side", ref: el => (this.bottomSide = el) }), h("div", { class: "right-side", ref: el => (this.rightSide = el) }), this.showScreenshotTopBar && (h("div", { class: "feedback-modal-screenshot-header", onClick: this.closeScreenShot }, h("span", null, this.screenshotTopbarText), h("span", { class: "feedback-modal-screenshot-close" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "#191919", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "feather feather-x" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" }))))))), this.showModal && (h("div", { class: "feedback-overlay" })), this.showModal && (h("div", { class: `feedback-modal-content feedback-modal-content--${this.modalPosition} ${this.showModal ? 'feedback-modal-content--open' : ''}`, ref: el => (this.modalContent = el) }, h("div", { class: "feedback-modal-header" }, !this.formSuccess && !this.formError ? (h("span", null, this.modalTitle)) : this.formSuccess ? (h("span", null, this.modalTitleSuccess)) : h("span", null, this.modalTitleError), h("button", { class: "feedback-modal-close", onClick: this.close }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "#191919", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "feather feather-x" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))), h("div", { class: "feedback-modal-body" }, !this.formSuccess && !this.formError ? (h("form", { onSubmit: this.handleSubmit }, !this.hideRating && (h("div", { class: "feedback-modal-rating" }, this.ratingMode === 'thumbs' ? (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading" }, this.ratingPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--thumbs" }, h("button", { title: "Yes", class: `feedback-modal-rating-button ${this.selectedRating === 1 ? 'feedback-modal-rating-button--selected' : ''}`, onClick: (event) => {
283
- event.preventDefault();
284
- this.handleRatingChange(1);
285
- } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: "M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" }))), h("button", { title: "No", class: `feedback-modal-rating-button ${this.selectedRating === 5 ? 'feedback-modal-rating-button--selected' : ''}`, onClick: (event) => {
286
- event.preventDefault();
287
- this.handleRatingChange(5);
288
- } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" })))))) : (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading" }, this.ratingStarsPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--stars" }, [1, 2, 3, 4, 5].map((rating) => (h("button", { key: rating, class: `feedback-modal-rating-button ${this.selectedRating >= rating ? 'feedback-modal-rating-button--selected' : ''}`, onClick: (event) => {
289
- event.preventDefault();
290
- this.handleRatingChange(rating);
291
- } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" })))))))))), h("div", { class: "feedback-modal-text" }, h("textarea", { placeholder: this.messagePlaceholder, value: this.formMessage, onInput: (event) => this.handleMessageInput(event) })), !this.hideEmail && (h("div", { class: "feedback-modal-email" }, h("input", { placeholder: this.emailPlaceholder, type: "email", onInput: (event) => this.handleEmailInput(event), value: this.formEmail }))), h("div", { class: "feedback-verification" }, h("input", { type: "text", name: "verification", style: { display: 'none' }, onInput: (event) => this.handleVerification(event), value: this.formVerification })), !this.hidePrivacyPolicy && (h("div", { class: "feedback-modal-privacy" }, h("input", { type: "checkbox", id: "privacyPolicy", onChange: (ev) => this.handleCheckboxChange(ev), required: true }), h("span", { innerHTML: this.privacyPolicyText }))), h("div", { class: `feedback-modal-buttons ${this.hideScreenshotButton ? 'single' : ''}` }, !this.hideScreenshotButton && (h("button", { type: "button", class: `feedback-modal-button feedback-modal-button--screenshot ${this.encodedScreenshot ? "feedback-modal-button--active" : ""}`, onClick: this.openScreenShot, disabled: this.sending }, h("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24", viewBox: "0 -960 960 960", width: "24" }, h("path", { d: "M680-80v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-200v-200h80v120h120v80H200Zm0-360v-200h200v80H280v120h-80Zm480 0v-120H560v-80h200v200h-80Z" })), this.screenshotButtonText)), h("button", { class: "feedback-modal-button feedback-modal-button--submit", type: "submit", disabled: this.sending }, this.sendButtonText)))) : this.formSuccess && !this.formError ? (h("p", { class: "feedback-modal-message" }, this.successMessage)) : this.formError && this.formErrorStatus == 404 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage404)) : this.formError && this.formErrorStatus == 403 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage403)) : this.formError ? (h("p", { class: "feedback-modal-message" }, this.errorMessage)) : h("span", null)), h("div", { class: "feedback-modal-footer", style: { display: this.whitelabel ? 'none' : 'block' } }, h("div", { class: "feedback-logo" }, "Powered by ", h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback.com")))))));
292
- }
293
- static get is() { return "feedback-modal"; }
294
- static get encapsulation() { return "shadow"; }
295
- static get originalStyleUrls() {
296
- return {
297
- "$": ["feedback-modal.css"]
298
- };
299
- }
300
- static get styleUrls() {
301
- return {
302
- "$": ["feedback-modal.css"]
303
- };
304
- }
305
- static get properties() {
306
- return {
307
- "errorMessage": {
308
- "type": "string",
309
- "mutable": false,
310
- "complexType": {
311
- "original": "string",
312
- "resolved": "string",
313
- "references": {}
314
- },
315
- "required": false,
316
- "optional": false,
317
- "docs": {
318
- "tags": [],
319
- "text": ""
320
- },
321
- "attribute": "error-message",
322
- "reflect": false,
323
- "defaultValue": "\"Please try again later.\""
324
- },
325
- "errorMessage403": {
326
- "type": "string",
327
- "mutable": false,
328
- "complexType": {
329
- "original": "string",
330
- "resolved": "string",
331
- "references": {}
332
- },
333
- "required": false,
334
- "optional": false,
335
- "docs": {
336
- "tags": [],
337
- "text": ""
338
- },
339
- "attribute": "error-message-4-0-3",
340
- "reflect": false,
341
- "defaultValue": "\"The request URL does not match the one defined in PushFeedback for this project.\""
342
- },
343
- "errorMessage404": {
344
- "type": "string",
345
- "mutable": false,
346
- "complexType": {
347
- "original": "string",
348
- "resolved": "string",
349
- "references": {}
350
- },
351
- "required": false,
352
- "optional": false,
353
- "docs": {
354
- "tags": [],
355
- "text": ""
356
- },
357
- "attribute": "error-message-4-0-4",
358
- "reflect": false,
359
- "defaultValue": "\"We could not find the provided project ID in PushFeedback.\""
360
- },
361
- "modalTitle": {
362
- "type": "string",
363
- "mutable": false,
364
- "complexType": {
365
- "original": "string",
366
- "resolved": "string",
367
- "references": {}
368
- },
369
- "required": false,
370
- "optional": false,
371
- "docs": {
372
- "tags": [],
373
- "text": ""
374
- },
375
- "attribute": "modal-title",
376
- "reflect": false,
377
- "defaultValue": "'Share your feedback'"
378
- },
379
- "modalTitleSuccess": {
380
- "type": "string",
381
- "mutable": false,
382
- "complexType": {
383
- "original": "string",
384
- "resolved": "string",
385
- "references": {}
386
- },
387
- "required": false,
388
- "optional": false,
389
- "docs": {
390
- "tags": [],
391
- "text": ""
392
- },
393
- "attribute": "modal-title-success",
394
- "reflect": false,
395
- "defaultValue": "'Thanks for your feedback!'"
396
- },
397
- "modalTitleError": {
398
- "type": "string",
399
- "mutable": false,
400
- "complexType": {
401
- "original": "string",
402
- "resolved": "string",
403
- "references": {}
404
- },
405
- "required": false,
406
- "optional": false,
407
- "docs": {
408
- "tags": [],
409
- "text": ""
410
- },
411
- "attribute": "modal-title-error",
412
- "reflect": false,
413
- "defaultValue": "\"Oops!\""
414
- },
415
- "modalPosition": {
416
- "type": "string",
417
- "mutable": false,
418
- "complexType": {
419
- "original": "string",
420
- "resolved": "string",
421
- "references": {}
422
- },
423
- "required": false,
424
- "optional": false,
425
- "docs": {
426
- "tags": [],
427
- "text": ""
428
- },
429
- "attribute": "modal-position",
430
- "reflect": false,
431
- "defaultValue": "'center'"
432
- },
433
- "sendButtonText": {
434
- "type": "string",
435
- "mutable": false,
436
- "complexType": {
437
- "original": "string",
438
- "resolved": "string",
439
- "references": {}
440
- },
441
- "required": false,
442
- "optional": false,
443
- "docs": {
444
- "tags": [],
445
- "text": ""
446
- },
447
- "attribute": "send-button-text",
448
- "reflect": false,
449
- "defaultValue": "'Send'"
450
- },
451
- "successMessage": {
452
- "type": "string",
453
- "mutable": false,
454
- "complexType": {
455
- "original": "string",
456
- "resolved": "string",
457
- "references": {}
458
- },
459
- "required": false,
460
- "optional": false,
461
- "docs": {
462
- "tags": [],
463
- "text": ""
464
- },
465
- "attribute": "success-message",
466
- "reflect": false,
467
- "defaultValue": "\"\""
468
- },
469
- "project": {
470
- "type": "string",
471
- "mutable": false,
472
- "complexType": {
473
- "original": "string",
474
- "resolved": "string",
475
- "references": {}
476
- },
477
- "required": false,
478
- "optional": false,
479
- "docs": {
480
- "tags": [],
481
- "text": ""
482
- },
483
- "attribute": "project",
484
- "reflect": false,
485
- "defaultValue": "''"
486
- },
487
- "screenshotButtonText": {
488
- "type": "string",
489
- "mutable": false,
490
- "complexType": {
491
- "original": "string",
492
- "resolved": "string",
493
- "references": {}
494
- },
495
- "required": false,
496
- "optional": false,
497
- "docs": {
498
- "tags": [],
499
- "text": ""
500
- },
501
- "attribute": "screenshot-button-text",
502
- "reflect": false,
503
- "defaultValue": "'Add a screenshot'"
504
- },
505
- "screenshotTopbarText": {
506
- "type": "string",
507
- "mutable": false,
508
- "complexType": {
509
- "original": "string",
510
- "resolved": "string",
511
- "references": {}
512
- },
513
- "required": false,
514
- "optional": false,
515
- "docs": {
516
- "tags": [],
517
- "text": ""
518
- },
519
- "attribute": "screenshot-topbar-text",
520
- "reflect": false,
521
- "defaultValue": "'Select an element on this page'"
522
- },
523
- "hideEmail": {
524
- "type": "boolean",
525
- "mutable": false,
526
- "complexType": {
527
- "original": "boolean",
528
- "resolved": "boolean",
529
- "references": {}
530
- },
531
- "required": false,
532
- "optional": false,
533
- "docs": {
534
- "tags": [],
535
- "text": ""
536
- },
537
- "attribute": "hide-email",
538
- "reflect": false,
539
- "defaultValue": "false"
540
- },
541
- "emailAddress": {
542
- "type": "string",
543
- "mutable": false,
544
- "complexType": {
545
- "original": "string",
546
- "resolved": "string",
547
- "references": {}
548
- },
549
- "required": false,
550
- "optional": false,
551
- "docs": {
552
- "tags": [],
553
- "text": ""
554
- },
555
- "attribute": "email-address",
556
- "reflect": false,
557
- "defaultValue": "''"
558
- },
559
- "emailPlaceholder": {
560
- "type": "string",
561
- "mutable": false,
562
- "complexType": {
563
- "original": "string",
564
- "resolved": "string",
565
- "references": {}
566
- },
567
- "required": false,
568
- "optional": false,
569
- "docs": {
570
- "tags": [],
571
- "text": ""
572
- },
573
- "attribute": "email-placeholder",
574
- "reflect": false,
575
- "defaultValue": "'Email address (optional)'"
576
- },
577
- "messagePlaceholder": {
578
- "type": "string",
579
- "mutable": false,
580
- "complexType": {
581
- "original": "string",
582
- "resolved": "string",
583
- "references": {}
584
- },
585
- "required": false,
586
- "optional": false,
587
- "docs": {
588
- "tags": [],
589
- "text": ""
590
- },
591
- "attribute": "message-placeholder",
592
- "reflect": false,
593
- "defaultValue": "'Comments'"
594
- },
595
- "hideRating": {
596
- "type": "boolean",
597
- "mutable": false,
598
- "complexType": {
599
- "original": "boolean",
600
- "resolved": "boolean",
601
- "references": {}
602
- },
603
- "required": false,
604
- "optional": false,
605
- "docs": {
606
- "tags": [],
607
- "text": ""
608
- },
609
- "attribute": "hide-rating",
610
- "reflect": false,
611
- "defaultValue": "false"
612
- },
613
- "rating": {
614
- "type": "number",
615
- "mutable": false,
616
- "complexType": {
617
- "original": "number",
618
- "resolved": "number",
619
- "references": {}
620
- },
621
- "required": false,
622
- "optional": false,
623
- "docs": {
624
- "tags": [],
625
- "text": ""
626
- },
627
- "attribute": "rating",
628
- "reflect": false
629
- },
630
- "ratingMode": {
631
- "type": "string",
632
- "mutable": false,
633
- "complexType": {
634
- "original": "string",
635
- "resolved": "string",
636
- "references": {}
637
- },
638
- "required": false,
639
- "optional": false,
640
- "docs": {
641
- "tags": [],
642
- "text": ""
643
- },
644
- "attribute": "rating-mode",
645
- "reflect": false,
646
- "defaultValue": "'thumbs'"
647
- },
648
- "ratingPlaceholder": {
649
- "type": "string",
650
- "mutable": false,
651
- "complexType": {
652
- "original": "string",
653
- "resolved": "string",
654
- "references": {}
655
- },
656
- "required": false,
657
- "optional": false,
658
- "docs": {
659
- "tags": [],
660
- "text": ""
661
- },
662
- "attribute": "rating-placeholder",
663
- "reflect": false,
664
- "defaultValue": "'Was this page helpful?'"
665
- },
666
- "ratingStarsPlaceholder": {
667
- "type": "string",
668
- "mutable": false,
669
- "complexType": {
670
- "original": "string",
671
- "resolved": "string",
672
- "references": {}
673
- },
674
- "required": false,
675
- "optional": false,
676
- "docs": {
677
- "tags": [],
678
- "text": ""
679
- },
680
- "attribute": "rating-stars-placeholder",
681
- "reflect": false,
682
- "defaultValue": "'How would you rate this page?'"
683
- },
684
- "showModal": {
685
- "type": "boolean",
686
- "mutable": true,
687
- "complexType": {
688
- "original": "boolean",
689
- "resolved": "boolean",
690
- "references": {}
691
- },
692
- "required": false,
693
- "optional": false,
694
- "docs": {
695
- "tags": [],
696
- "text": ""
697
- },
698
- "attribute": "show-modal",
699
- "reflect": true,
700
- "defaultValue": "false"
701
- },
702
- "showScreenshotMode": {
703
- "type": "boolean",
704
- "mutable": true,
705
- "complexType": {
706
- "original": "boolean",
707
- "resolved": "boolean",
708
- "references": {}
709
- },
710
- "required": false,
711
- "optional": false,
712
- "docs": {
713
- "tags": [],
714
- "text": ""
715
- },
716
- "attribute": "show-screenshot-mode",
717
- "reflect": true,
718
- "defaultValue": "false"
719
- },
720
- "showScreenshotTopBar": {
721
- "type": "boolean",
722
- "mutable": true,
723
- "complexType": {
724
- "original": "boolean",
725
- "resolved": "boolean",
726
- "references": {}
727
- },
728
- "required": false,
729
- "optional": false,
730
- "docs": {
731
- "tags": [],
732
- "text": ""
733
- },
734
- "attribute": "show-screenshot-top-bar",
735
- "reflect": true,
736
- "defaultValue": "false"
737
- },
738
- "hasSelectedElement": {
739
- "type": "boolean",
740
- "mutable": true,
741
- "complexType": {
742
- "original": "boolean",
743
- "resolved": "boolean",
744
- "references": {}
745
- },
746
- "required": false,
747
- "optional": false,
748
- "docs": {
749
- "tags": [],
750
- "text": ""
751
- },
752
- "attribute": "has-selected-element",
753
- "reflect": true,
754
- "defaultValue": "false"
755
- },
756
- "hideScreenshotButton": {
757
- "type": "boolean",
758
- "mutable": false,
759
- "complexType": {
760
- "original": "boolean",
761
- "resolved": "boolean",
762
- "references": {}
763
- },
764
- "required": false,
765
- "optional": false,
766
- "docs": {
767
- "tags": [],
768
- "text": ""
769
- },
770
- "attribute": "hide-screenshot-button",
771
- "reflect": false,
772
- "defaultValue": "false"
773
- },
774
- "hidePrivacyPolicy": {
775
- "type": "boolean",
776
- "mutable": false,
777
- "complexType": {
778
- "original": "boolean",
779
- "resolved": "boolean",
780
- "references": {}
781
- },
782
- "required": false,
783
- "optional": false,
784
- "docs": {
785
- "tags": [],
786
- "text": ""
787
- },
788
- "attribute": "hide-privacy-policy",
789
- "reflect": false,
790
- "defaultValue": "true"
791
- },
792
- "privacyPolicyText": {
793
- "type": "string",
794
- "mutable": false,
795
- "complexType": {
796
- "original": "string",
797
- "resolved": "string",
798
- "references": {}
799
- },
800
- "required": false,
801
- "optional": false,
802
- "docs": {
803
- "tags": [],
804
- "text": ""
805
- },
806
- "attribute": "privacy-policy-text",
807
- "reflect": false,
808
- "defaultValue": "\"I have read and expressly consent to the terms of the <a href='https://pushfeedback.com/privacy'>Privacy Policy</a>.\""
809
- },
810
- "fetchData": {
811
- "type": "boolean",
812
- "mutable": false,
813
- "complexType": {
814
- "original": "boolean",
815
- "resolved": "boolean",
816
- "references": {}
817
- },
818
- "required": false,
819
- "optional": false,
820
- "docs": {
821
- "tags": [],
822
- "text": ""
823
- },
824
- "attribute": "fetch-data",
825
- "reflect": false,
826
- "defaultValue": "true"
827
- }
828
- };
829
- }
830
- static get states() {
831
- return {
832
- "sending": {},
833
- "formMessage": {},
834
- "formEmail": {},
835
- "formSuccess": {},
836
- "formVerification": {},
837
- "formError": {},
838
- "formErrorStatus": {},
839
- "encodedScreenshot": {},
840
- "isPrivacyChecked": {},
841
- "whitelabel": {},
842
- "selectedRating": {}
843
- };
844
- }
845
- }
1
+ import { h } from '@stencil/core';
2
+ import html2canvas from 'html2canvas';
3
+ export class FeedbackModal {
4
+ constructor() {
5
+ this.onScrollDebounced = () => {
6
+ clearTimeout(this.scrollTimeout);
7
+ this.scrollTimeout = setTimeout(() => {
8
+ document.documentElement.classList.remove('feedback-modal-screenshot-closing');
9
+ document.documentElement.style.top = "";
10
+ window.removeEventListener('scroll', this.onScrollDebounced);
11
+ }, 200);
12
+ };
13
+ this.handleSubmit = async (event) => {
14
+ event.preventDefault();
15
+ this.resetOverflow();
16
+ this.showScreenshotMode = false;
17
+ this.showScreenshotTopBar = false;
18
+ this.showModal = false;
19
+ this.sending = true;
20
+ try {
21
+ const res = await fetch('https://app.pushfeedback.com/api/feedback/', {
22
+ method: 'POST',
23
+ body: JSON.stringify({
24
+ url: window.location.href,
25
+ message: this.formMessage,
26
+ email: this.formEmail,
27
+ project: this.project,
28
+ screenshot: this.encodedScreenshot,
29
+ rating: this.selectedRating,
30
+ ratingMode: this.ratingMode,
31
+ verification: this.formVerification,
32
+ session: localStorage.getItem('pushfeedback_sessionid') || '',
33
+ }),
34
+ headers: {
35
+ 'Content-Type': 'application/json'
36
+ }
37
+ });
38
+ if (res.status === 201) {
39
+ this.formSuccess = true;
40
+ this.formError = false;
41
+ }
42
+ else {
43
+ this.formSuccess = false;
44
+ this.formError = true;
45
+ this.formErrorStatus = res.status;
46
+ }
47
+ }
48
+ catch (error) {
49
+ console.log(error);
50
+ this.formSuccess = false;
51
+ this.formError = true;
52
+ this.formErrorStatus = 500;
53
+ }
54
+ finally {
55
+ this.sending = false;
56
+ this.showModal = true;
57
+ }
58
+ };
59
+ this.close = () => {
60
+ this.sending = false;
61
+ this.showModal = false;
62
+ this.showScreenshotMode = false;
63
+ this.showScreenshotTopBar = false;
64
+ this.hasSelectedElement = false;
65
+ this.encodedScreenshot = null;
66
+ this.formSuccess = false;
67
+ this.formError = false;
68
+ this.formErrorStatus = 500;
69
+ this.formMessage = '';
70
+ this.formEmail = '';
71
+ this.resetOverflow();
72
+ };
73
+ this.openScreenShot = () => {
74
+ this.hasSelectedElement = false;
75
+ this.showModal = false;
76
+ this.showScreenshotMode = true;
77
+ this.showScreenshotTopBar = true;
78
+ this.encodedScreenshot = null;
79
+ if (window.innerWidth > document.documentElement.clientWidth) {
80
+ document.documentElement.classList.add('feedback-modal-screenshot-open--scroll');
81
+ }
82
+ const scrollY = window.scrollY;
83
+ document.documentElement.style.top = `-${scrollY}px`;
84
+ window.scrollTo(0, parseInt(document.documentElement.style.top || '0') * -1);
85
+ document.documentElement.classList.add('feedback-modal-screenshot-open');
86
+ };
87
+ this.closeScreenShot = () => {
88
+ this.showModal = false;
89
+ this.showScreenshotMode = false;
90
+ this.showScreenshotTopBar = false;
91
+ this.hasSelectedElement = false;
92
+ this.encodedScreenshot = null;
93
+ this.resetOverflow();
94
+ };
95
+ this.handleMouseOverScreenShot = (event) => {
96
+ event.preventDefault();
97
+ if (this.hasSelectedElement)
98
+ return;
99
+ const borderOffset = 2;
100
+ this.screenshotModal.style.display = 'none';
101
+ const elementUnder = document.elementFromPoint(event.clientX, event.clientY);
102
+ const rect = elementUnder.getBoundingClientRect();
103
+ this.screenshotModal.style.display = '';
104
+ // Get the bounding box of the element selected
105
+ this.elementSelected.style.position = "absolute";
106
+ this.elementSelected.style.left = `${rect.left}px`;
107
+ this.elementSelected.style.top = `${rect.top}px`;
108
+ this.elementSelected.style.width = `${rect.width}px`;
109
+ this.elementSelected.style.height = `${rect.height}px`;
110
+ this.elementSelected.classList.add('feedback-modal-element-hover');
111
+ // Set the background color of nonselected areas
112
+ // Top
113
+ this.topSide.style.position = "absolute";
114
+ this.topSide.style.left = `${rect.left}px`;
115
+ this.topSide.style.top = '0px';
116
+ this.topSide.style.width = `${rect.width + borderOffset}px`;
117
+ this.topSide.style.height = `${rect.top}px`;
118
+ this.topSide.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
119
+ // Left
120
+ this.leftSide.style.position = "absolute";
121
+ this.leftSide.style.left = '0px';
122
+ this.leftSide.style.top = '0px';
123
+ this.leftSide.style.width = `${rect.left}px`;
124
+ this.leftSide.style.height = '100vh';
125
+ this.leftSide.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
126
+ // Bottom
127
+ this.bottomSide.style.position = "absolute";
128
+ this.bottomSide.style.left = `${rect.left}px`;
129
+ this.bottomSide.style.top = `${rect.bottom + borderOffset}px`;
130
+ this.bottomSide.style.width = `${rect.width + borderOffset}px`;
131
+ this.bottomSide.style.height = '100vh';
132
+ this.bottomSide.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
133
+ // Right
134
+ this.rightSide.style.position = "absolute";
135
+ this.rightSide.style.left = `${rect.right + borderOffset}px`;
136
+ ;
137
+ this.rightSide.style.top = '0px';
138
+ this.rightSide.style.width = '100%';
139
+ this.rightSide.style.height = '100vh';
140
+ this.rightSide.style.backgroundColor = "rgba(0, 0, 0, 0.4)";
141
+ // Restore the visibility of the screenshot-modal
142
+ this.screenshotModal.style.backgroundColor = 'transparent';
143
+ };
144
+ this.handleMouseClickedSelectedElement = async (event) => {
145
+ event.preventDefault();
146
+ if (!this.elementSelected) {
147
+ return;
148
+ }
149
+ this.hasSelectedElement = true;
150
+ this.elementSelected.classList.add('feedback-modal-element-selected');
151
+ // Get the top position including the scroll offset
152
+ const rectTop = this.elementSelected.getBoundingClientRect().top;
153
+ const topWithScroll = rectTop + window.scrollY;
154
+ // Move the element with the scroll offset
155
+ this.elementSelected.style.top = `${topWithScroll}px`;
156
+ // Clone the selected element and append it to the body
157
+ const clonedElementSelected = this.elementSelected.cloneNode(true);
158
+ document.body.appendChild(clonedElementSelected);
159
+ // Reset the top position of the original element
160
+ this.elementSelected.style.top = `${rectTop}px`;
161
+ this.showScreenshotTopBar = false;
162
+ this.showModal = false;
163
+ try {
164
+ const dataUrl = await this.captureScreenshot();
165
+ console.log('Screenshot captured');
166
+ this.encodedScreenshot = dataUrl;
167
+ }
168
+ catch (error) {
169
+ console.error('Failed to capture screenshot:', error);
170
+ this.hasSelectedElement = false;
171
+ }
172
+ finally {
173
+ // Remove the cloned element and show the modal again
174
+ document.body.removeChild(clonedElementSelected);
175
+ this.showModal = true;
176
+ }
177
+ };
178
+ this.sending = false;
179
+ this.formMessage = '';
180
+ this.formEmail = '';
181
+ this.formSuccess = false;
182
+ this.formVerification = '';
183
+ this.formError = false;
184
+ this.formErrorStatus = 500;
185
+ this.encodedScreenshot = undefined;
186
+ this.isPrivacyChecked = false;
187
+ this.whitelabel = false;
188
+ this.selectedRating = 0;
189
+ this.errorMessage = "Please try again later.";
190
+ this.errorMessage403 = "The request URL does not match the one defined in PushFeedback for this project.";
191
+ this.errorMessage404 = "We could not find the provided project ID in PushFeedback.";
192
+ this.modalTitle = 'Share your feedback';
193
+ this.modalTitleSuccess = 'Thanks for your feedback!';
194
+ this.modalTitleError = "Oops!";
195
+ this.modalPosition = 'center';
196
+ this.sendButtonText = 'Send';
197
+ this.successMessage = "";
198
+ this.project = '';
199
+ this.screenshotButtonText = 'Add a screenshot';
200
+ this.screenshotTopbarText = 'Select an element on this page';
201
+ this.hideEmail = false;
202
+ this.emailAddress = '';
203
+ this.emailPlaceholder = 'Email address (optional)';
204
+ this.messagePlaceholder = 'Comments';
205
+ this.hideRating = false;
206
+ this.rating = undefined;
207
+ this.ratingMode = 'thumbs';
208
+ this.ratingPlaceholder = 'Was this page helpful?';
209
+ this.ratingStarsPlaceholder = 'How would you rate this page?';
210
+ this.showModal = false;
211
+ this.showScreenshotMode = false;
212
+ this.showScreenshotTopBar = false;
213
+ this.hasSelectedElement = false;
214
+ this.hideScreenshotButton = false;
215
+ this.hidePrivacyPolicy = true;
216
+ this.privacyPolicyText = "I have read and expressly consent to the terms of the <a href='https://pushfeedback.com/privacy'>Privacy Policy</a>.";
217
+ this.fetchData = true;
218
+ }
219
+ componentWillLoad() {
220
+ if (this.fetchData)
221
+ this.fetchProjectData();
222
+ this.formEmail = this.emailAddress;
223
+ if (this.rating) {
224
+ this.selectedRating = this.rating;
225
+ }
226
+ if (this.ratingMode == "thumbs" && this.rating == 0) {
227
+ this.selectedRating = 5;
228
+ }
229
+ }
230
+ async fetchProjectData() {
231
+ try {
232
+ const response = await fetch('https://app.pushfeedback.com/api/projects/' + this.project + '/');
233
+ const data = await response.json();
234
+ this.whitelabel = data.whitelabel;
235
+ }
236
+ catch (error) {
237
+ console.log(error);
238
+ }
239
+ }
240
+ resetOverflow() {
241
+ document.documentElement.classList.remove('feedback-modal-screenshot-open');
242
+ document.documentElement.classList.remove('feedback-modal-screenshot-open--scroll');
243
+ document.documentElement.classList.add('feedback-modal-screenshot-closing');
244
+ window.scrollTo(0, parseInt(document.documentElement.style.top || '0') * -1);
245
+ window.addEventListener('scroll', this.onScrollDebounced);
246
+ }
247
+ handleMessageInput(event) {
248
+ this.formMessage = event.target.value;
249
+ }
250
+ handleEmailInput(event) {
251
+ this.formEmail = event.target.value;
252
+ }
253
+ captureScreenshot() {
254
+ return new Promise((resolve, reject) => {
255
+ requestAnimationFrame(() => {
256
+ html2canvas(document.body, {
257
+ x: window.scrollX,
258
+ y: window.scrollY,
259
+ width: window.innerWidth,
260
+ height: window.innerHeight,
261
+ }).then(canvas => {
262
+ const dataUrl = canvas.toDataURL();
263
+ resolve(dataUrl);
264
+ })
265
+ .catch(error => {
266
+ console.error(error);
267
+ reject(error);
268
+ });
269
+ });
270
+ });
271
+ }
272
+ handleCheckboxChange(event) {
273
+ this.isPrivacyChecked = event.target.checked;
274
+ }
275
+ handleVerification(event) {
276
+ this.formVerification = event.target.value;
277
+ }
278
+ handleRatingChange(newRating) {
279
+ this.selectedRating = newRating;
280
+ }
281
+ render() {
282
+ return (h("div", { class: 'feedback-modal-wrapper' }, this.showScreenshotMode && (h("div", { class: "feedback-modal-screenshot", ref: el => (this.screenshotModal = el), onMouseMove: this.handleMouseOverScreenShot }, h("div", { class: "feedback-modal-screenshot-element-selected", ref: el => (this.elementSelected = el), onClick: this.handleMouseClickedSelectedElement }), h("div", { class: "top-side", ref: el => (this.topSide = el) }), h("div", { class: "left-side", ref: el => (this.leftSide = el) }), h("div", { class: "bottom-side", ref: el => (this.bottomSide = el) }), h("div", { class: "right-side", ref: el => (this.rightSide = el) }), this.showScreenshotTopBar && (h("div", { class: "feedback-modal-screenshot-header", onClick: this.closeScreenShot }, h("span", null, this.screenshotTopbarText), h("span", { class: "feedback-modal-screenshot-close" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "#191919", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "feather feather-x" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" }))))))), this.showModal && (h("div", { class: "feedback-overlay" })), this.showModal && (h("div", { class: `feedback-modal-content feedback-modal-content--${this.modalPosition} ${this.showModal ? 'feedback-modal-content--open' : ''}`, ref: el => (this.modalContent = el) }, h("div", { class: "feedback-modal-header" }, !this.formSuccess && !this.formError ? (h("span", null, this.modalTitle)) : this.formSuccess ? (h("span", null, this.modalTitleSuccess)) : h("span", null, this.modalTitleError), h("button", { class: "feedback-modal-close", onClick: this.close }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "#191919", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", class: "feather feather-x" }, h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))), h("div", { class: "feedback-modal-body" }, !this.formSuccess && !this.formError ? (h("form", { onSubmit: this.handleSubmit }, !this.hideRating && (h("div", { class: "feedback-modal-rating" }, this.ratingMode === 'thumbs' ? (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading" }, this.ratingPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--thumbs" }, h("button", { title: "Yes", class: `feedback-modal-rating-button ${this.selectedRating === 1 ? 'feedback-modal-rating-button--selected' : ''}`, onClick: (event) => {
283
+ event.preventDefault();
284
+ this.handleRatingChange(1);
285
+ } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: "M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" }))), h("button", { title: "No", class: `feedback-modal-rating-button ${this.selectedRating === 5 ? 'feedback-modal-rating-button--selected' : ''}`, onClick: (event) => {
286
+ event.preventDefault();
287
+ this.handleRatingChange(5);
288
+ } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" })))))) : (h("div", { class: "feedback-modal-rating-content" }, h("span", { class: "feedback-modal-input-heading" }, this.ratingStarsPlaceholder), h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--stars" }, [1, 2, 3, 4, 5].map((rating) => (h("button", { key: rating, class: `feedback-modal-rating-button ${this.selectedRating >= rating ? 'feedback-modal-rating-button--selected' : ''}`, onClick: (event) => {
289
+ event.preventDefault();
290
+ this.handleRatingChange(rating);
291
+ } }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "#5F6368", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" })))))))))), h("div", { class: "feedback-modal-text" }, h("textarea", { placeholder: this.messagePlaceholder, value: this.formMessage, onInput: (event) => this.handleMessageInput(event) })), !this.hideEmail && (h("div", { class: "feedback-modal-email" }, h("input", { placeholder: this.emailPlaceholder, type: "email", onInput: (event) => this.handleEmailInput(event), value: this.formEmail }))), h("div", { class: "feedback-verification" }, h("input", { type: "text", name: "verification", style: { display: 'none' }, onInput: (event) => this.handleVerification(event), value: this.formVerification })), !this.hidePrivacyPolicy && (h("div", { class: "feedback-modal-privacy" }, h("input", { type: "checkbox", id: "privacyPolicy", onChange: (ev) => this.handleCheckboxChange(ev), required: true }), h("span", { innerHTML: this.privacyPolicyText }))), h("div", { class: `feedback-modal-buttons ${this.hideScreenshotButton ? 'single' : ''}` }, !this.hideScreenshotButton && (h("button", { type: "button", class: `feedback-modal-button feedback-modal-button--screenshot ${this.encodedScreenshot ? "feedback-modal-button--active" : ""}`, onClick: this.openScreenShot, disabled: this.sending }, h("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24", viewBox: "0 -960 960 960", width: "24" }, h("path", { d: "M680-80v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-200v-200h80v120h120v80H200Zm0-360v-200h200v80H280v120h-80Zm480 0v-120H560v-80h200v200h-80Z" })), this.screenshotButtonText)), h("button", { class: "feedback-modal-button feedback-modal-button--submit", type: "submit", disabled: this.sending }, this.sendButtonText)))) : this.formSuccess && !this.formError ? (h("p", { class: "feedback-modal-message" }, this.successMessage)) : this.formError && this.formErrorStatus == 404 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage404)) : this.formError && this.formErrorStatus == 403 ? (h("p", { class: "feedback-modal-message" }, this.errorMessage403)) : this.formError ? (h("p", { class: "feedback-modal-message" }, this.errorMessage)) : h("span", null)), h("div", { class: "feedback-modal-footer", style: { display: this.whitelabel ? 'none' : 'block' } }, h("div", { class: "feedback-logo" }, "Powered by ", h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback.com")))))));
292
+ }
293
+ static get is() { return "feedback-modal"; }
294
+ static get encapsulation() { return "shadow"; }
295
+ static get originalStyleUrls() {
296
+ return {
297
+ "$": ["feedback-modal.css"]
298
+ };
299
+ }
300
+ static get styleUrls() {
301
+ return {
302
+ "$": ["feedback-modal.css"]
303
+ };
304
+ }
305
+ static get properties() {
306
+ return {
307
+ "errorMessage": {
308
+ "type": "string",
309
+ "mutable": false,
310
+ "complexType": {
311
+ "original": "string",
312
+ "resolved": "string",
313
+ "references": {}
314
+ },
315
+ "required": false,
316
+ "optional": false,
317
+ "docs": {
318
+ "tags": [],
319
+ "text": ""
320
+ },
321
+ "attribute": "error-message",
322
+ "reflect": false,
323
+ "defaultValue": "\"Please try again later.\""
324
+ },
325
+ "errorMessage403": {
326
+ "type": "string",
327
+ "mutable": false,
328
+ "complexType": {
329
+ "original": "string",
330
+ "resolved": "string",
331
+ "references": {}
332
+ },
333
+ "required": false,
334
+ "optional": false,
335
+ "docs": {
336
+ "tags": [],
337
+ "text": ""
338
+ },
339
+ "attribute": "error-message-4-0-3",
340
+ "reflect": false,
341
+ "defaultValue": "\"The request URL does not match the one defined in PushFeedback for this project.\""
342
+ },
343
+ "errorMessage404": {
344
+ "type": "string",
345
+ "mutable": false,
346
+ "complexType": {
347
+ "original": "string",
348
+ "resolved": "string",
349
+ "references": {}
350
+ },
351
+ "required": false,
352
+ "optional": false,
353
+ "docs": {
354
+ "tags": [],
355
+ "text": ""
356
+ },
357
+ "attribute": "error-message-4-0-4",
358
+ "reflect": false,
359
+ "defaultValue": "\"We could not find the provided project ID in PushFeedback.\""
360
+ },
361
+ "modalTitle": {
362
+ "type": "string",
363
+ "mutable": false,
364
+ "complexType": {
365
+ "original": "string",
366
+ "resolved": "string",
367
+ "references": {}
368
+ },
369
+ "required": false,
370
+ "optional": false,
371
+ "docs": {
372
+ "tags": [],
373
+ "text": ""
374
+ },
375
+ "attribute": "modal-title",
376
+ "reflect": false,
377
+ "defaultValue": "'Share your feedback'"
378
+ },
379
+ "modalTitleSuccess": {
380
+ "type": "string",
381
+ "mutable": false,
382
+ "complexType": {
383
+ "original": "string",
384
+ "resolved": "string",
385
+ "references": {}
386
+ },
387
+ "required": false,
388
+ "optional": false,
389
+ "docs": {
390
+ "tags": [],
391
+ "text": ""
392
+ },
393
+ "attribute": "modal-title-success",
394
+ "reflect": false,
395
+ "defaultValue": "'Thanks for your feedback!'"
396
+ },
397
+ "modalTitleError": {
398
+ "type": "string",
399
+ "mutable": false,
400
+ "complexType": {
401
+ "original": "string",
402
+ "resolved": "string",
403
+ "references": {}
404
+ },
405
+ "required": false,
406
+ "optional": false,
407
+ "docs": {
408
+ "tags": [],
409
+ "text": ""
410
+ },
411
+ "attribute": "modal-title-error",
412
+ "reflect": false,
413
+ "defaultValue": "\"Oops!\""
414
+ },
415
+ "modalPosition": {
416
+ "type": "string",
417
+ "mutable": false,
418
+ "complexType": {
419
+ "original": "string",
420
+ "resolved": "string",
421
+ "references": {}
422
+ },
423
+ "required": false,
424
+ "optional": false,
425
+ "docs": {
426
+ "tags": [],
427
+ "text": ""
428
+ },
429
+ "attribute": "modal-position",
430
+ "reflect": false,
431
+ "defaultValue": "'center'"
432
+ },
433
+ "sendButtonText": {
434
+ "type": "string",
435
+ "mutable": false,
436
+ "complexType": {
437
+ "original": "string",
438
+ "resolved": "string",
439
+ "references": {}
440
+ },
441
+ "required": false,
442
+ "optional": false,
443
+ "docs": {
444
+ "tags": [],
445
+ "text": ""
446
+ },
447
+ "attribute": "send-button-text",
448
+ "reflect": false,
449
+ "defaultValue": "'Send'"
450
+ },
451
+ "successMessage": {
452
+ "type": "string",
453
+ "mutable": false,
454
+ "complexType": {
455
+ "original": "string",
456
+ "resolved": "string",
457
+ "references": {}
458
+ },
459
+ "required": false,
460
+ "optional": false,
461
+ "docs": {
462
+ "tags": [],
463
+ "text": ""
464
+ },
465
+ "attribute": "success-message",
466
+ "reflect": false,
467
+ "defaultValue": "\"\""
468
+ },
469
+ "project": {
470
+ "type": "string",
471
+ "mutable": false,
472
+ "complexType": {
473
+ "original": "string",
474
+ "resolved": "string",
475
+ "references": {}
476
+ },
477
+ "required": false,
478
+ "optional": false,
479
+ "docs": {
480
+ "tags": [],
481
+ "text": ""
482
+ },
483
+ "attribute": "project",
484
+ "reflect": false,
485
+ "defaultValue": "''"
486
+ },
487
+ "screenshotButtonText": {
488
+ "type": "string",
489
+ "mutable": false,
490
+ "complexType": {
491
+ "original": "string",
492
+ "resolved": "string",
493
+ "references": {}
494
+ },
495
+ "required": false,
496
+ "optional": false,
497
+ "docs": {
498
+ "tags": [],
499
+ "text": ""
500
+ },
501
+ "attribute": "screenshot-button-text",
502
+ "reflect": false,
503
+ "defaultValue": "'Add a screenshot'"
504
+ },
505
+ "screenshotTopbarText": {
506
+ "type": "string",
507
+ "mutable": false,
508
+ "complexType": {
509
+ "original": "string",
510
+ "resolved": "string",
511
+ "references": {}
512
+ },
513
+ "required": false,
514
+ "optional": false,
515
+ "docs": {
516
+ "tags": [],
517
+ "text": ""
518
+ },
519
+ "attribute": "screenshot-topbar-text",
520
+ "reflect": false,
521
+ "defaultValue": "'Select an element on this page'"
522
+ },
523
+ "hideEmail": {
524
+ "type": "boolean",
525
+ "mutable": false,
526
+ "complexType": {
527
+ "original": "boolean",
528
+ "resolved": "boolean",
529
+ "references": {}
530
+ },
531
+ "required": false,
532
+ "optional": false,
533
+ "docs": {
534
+ "tags": [],
535
+ "text": ""
536
+ },
537
+ "attribute": "hide-email",
538
+ "reflect": false,
539
+ "defaultValue": "false"
540
+ },
541
+ "emailAddress": {
542
+ "type": "string",
543
+ "mutable": false,
544
+ "complexType": {
545
+ "original": "string",
546
+ "resolved": "string",
547
+ "references": {}
548
+ },
549
+ "required": false,
550
+ "optional": false,
551
+ "docs": {
552
+ "tags": [],
553
+ "text": ""
554
+ },
555
+ "attribute": "email-address",
556
+ "reflect": false,
557
+ "defaultValue": "''"
558
+ },
559
+ "emailPlaceholder": {
560
+ "type": "string",
561
+ "mutable": false,
562
+ "complexType": {
563
+ "original": "string",
564
+ "resolved": "string",
565
+ "references": {}
566
+ },
567
+ "required": false,
568
+ "optional": false,
569
+ "docs": {
570
+ "tags": [],
571
+ "text": ""
572
+ },
573
+ "attribute": "email-placeholder",
574
+ "reflect": false,
575
+ "defaultValue": "'Email address (optional)'"
576
+ },
577
+ "messagePlaceholder": {
578
+ "type": "string",
579
+ "mutable": false,
580
+ "complexType": {
581
+ "original": "string",
582
+ "resolved": "string",
583
+ "references": {}
584
+ },
585
+ "required": false,
586
+ "optional": false,
587
+ "docs": {
588
+ "tags": [],
589
+ "text": ""
590
+ },
591
+ "attribute": "message-placeholder",
592
+ "reflect": false,
593
+ "defaultValue": "'Comments'"
594
+ },
595
+ "hideRating": {
596
+ "type": "boolean",
597
+ "mutable": false,
598
+ "complexType": {
599
+ "original": "boolean",
600
+ "resolved": "boolean",
601
+ "references": {}
602
+ },
603
+ "required": false,
604
+ "optional": false,
605
+ "docs": {
606
+ "tags": [],
607
+ "text": ""
608
+ },
609
+ "attribute": "hide-rating",
610
+ "reflect": false,
611
+ "defaultValue": "false"
612
+ },
613
+ "rating": {
614
+ "type": "number",
615
+ "mutable": false,
616
+ "complexType": {
617
+ "original": "number",
618
+ "resolved": "number",
619
+ "references": {}
620
+ },
621
+ "required": false,
622
+ "optional": false,
623
+ "docs": {
624
+ "tags": [],
625
+ "text": ""
626
+ },
627
+ "attribute": "rating",
628
+ "reflect": false
629
+ },
630
+ "ratingMode": {
631
+ "type": "string",
632
+ "mutable": false,
633
+ "complexType": {
634
+ "original": "string",
635
+ "resolved": "string",
636
+ "references": {}
637
+ },
638
+ "required": false,
639
+ "optional": false,
640
+ "docs": {
641
+ "tags": [],
642
+ "text": ""
643
+ },
644
+ "attribute": "rating-mode",
645
+ "reflect": false,
646
+ "defaultValue": "'thumbs'"
647
+ },
648
+ "ratingPlaceholder": {
649
+ "type": "string",
650
+ "mutable": false,
651
+ "complexType": {
652
+ "original": "string",
653
+ "resolved": "string",
654
+ "references": {}
655
+ },
656
+ "required": false,
657
+ "optional": false,
658
+ "docs": {
659
+ "tags": [],
660
+ "text": ""
661
+ },
662
+ "attribute": "rating-placeholder",
663
+ "reflect": false,
664
+ "defaultValue": "'Was this page helpful?'"
665
+ },
666
+ "ratingStarsPlaceholder": {
667
+ "type": "string",
668
+ "mutable": false,
669
+ "complexType": {
670
+ "original": "string",
671
+ "resolved": "string",
672
+ "references": {}
673
+ },
674
+ "required": false,
675
+ "optional": false,
676
+ "docs": {
677
+ "tags": [],
678
+ "text": ""
679
+ },
680
+ "attribute": "rating-stars-placeholder",
681
+ "reflect": false,
682
+ "defaultValue": "'How would you rate this page?'"
683
+ },
684
+ "showModal": {
685
+ "type": "boolean",
686
+ "mutable": true,
687
+ "complexType": {
688
+ "original": "boolean",
689
+ "resolved": "boolean",
690
+ "references": {}
691
+ },
692
+ "required": false,
693
+ "optional": false,
694
+ "docs": {
695
+ "tags": [],
696
+ "text": ""
697
+ },
698
+ "attribute": "show-modal",
699
+ "reflect": true,
700
+ "defaultValue": "false"
701
+ },
702
+ "showScreenshotMode": {
703
+ "type": "boolean",
704
+ "mutable": true,
705
+ "complexType": {
706
+ "original": "boolean",
707
+ "resolved": "boolean",
708
+ "references": {}
709
+ },
710
+ "required": false,
711
+ "optional": false,
712
+ "docs": {
713
+ "tags": [],
714
+ "text": ""
715
+ },
716
+ "attribute": "show-screenshot-mode",
717
+ "reflect": true,
718
+ "defaultValue": "false"
719
+ },
720
+ "showScreenshotTopBar": {
721
+ "type": "boolean",
722
+ "mutable": true,
723
+ "complexType": {
724
+ "original": "boolean",
725
+ "resolved": "boolean",
726
+ "references": {}
727
+ },
728
+ "required": false,
729
+ "optional": false,
730
+ "docs": {
731
+ "tags": [],
732
+ "text": ""
733
+ },
734
+ "attribute": "show-screenshot-top-bar",
735
+ "reflect": true,
736
+ "defaultValue": "false"
737
+ },
738
+ "hasSelectedElement": {
739
+ "type": "boolean",
740
+ "mutable": true,
741
+ "complexType": {
742
+ "original": "boolean",
743
+ "resolved": "boolean",
744
+ "references": {}
745
+ },
746
+ "required": false,
747
+ "optional": false,
748
+ "docs": {
749
+ "tags": [],
750
+ "text": ""
751
+ },
752
+ "attribute": "has-selected-element",
753
+ "reflect": true,
754
+ "defaultValue": "false"
755
+ },
756
+ "hideScreenshotButton": {
757
+ "type": "boolean",
758
+ "mutable": false,
759
+ "complexType": {
760
+ "original": "boolean",
761
+ "resolved": "boolean",
762
+ "references": {}
763
+ },
764
+ "required": false,
765
+ "optional": false,
766
+ "docs": {
767
+ "tags": [],
768
+ "text": ""
769
+ },
770
+ "attribute": "hide-screenshot-button",
771
+ "reflect": false,
772
+ "defaultValue": "false"
773
+ },
774
+ "hidePrivacyPolicy": {
775
+ "type": "boolean",
776
+ "mutable": false,
777
+ "complexType": {
778
+ "original": "boolean",
779
+ "resolved": "boolean",
780
+ "references": {}
781
+ },
782
+ "required": false,
783
+ "optional": false,
784
+ "docs": {
785
+ "tags": [],
786
+ "text": ""
787
+ },
788
+ "attribute": "hide-privacy-policy",
789
+ "reflect": false,
790
+ "defaultValue": "true"
791
+ },
792
+ "privacyPolicyText": {
793
+ "type": "string",
794
+ "mutable": false,
795
+ "complexType": {
796
+ "original": "string",
797
+ "resolved": "string",
798
+ "references": {}
799
+ },
800
+ "required": false,
801
+ "optional": false,
802
+ "docs": {
803
+ "tags": [],
804
+ "text": ""
805
+ },
806
+ "attribute": "privacy-policy-text",
807
+ "reflect": false,
808
+ "defaultValue": "\"I have read and expressly consent to the terms of the <a href='https://pushfeedback.com/privacy'>Privacy Policy</a>.\""
809
+ },
810
+ "fetchData": {
811
+ "type": "boolean",
812
+ "mutable": false,
813
+ "complexType": {
814
+ "original": "boolean",
815
+ "resolved": "boolean",
816
+ "references": {}
817
+ },
818
+ "required": false,
819
+ "optional": false,
820
+ "docs": {
821
+ "tags": [],
822
+ "text": ""
823
+ },
824
+ "attribute": "fetch-data",
825
+ "reflect": false,
826
+ "defaultValue": "true"
827
+ }
828
+ };
829
+ }
830
+ static get states() {
831
+ return {
832
+ "sending": {},
833
+ "formMessage": {},
834
+ "formEmail": {},
835
+ "formSuccess": {},
836
+ "formVerification": {},
837
+ "formError": {},
838
+ "formErrorStatus": {},
839
+ "encodedScreenshot": {},
840
+ "isPrivacyChecked": {},
841
+ "whitelabel": {},
842
+ "selectedRating": {}
843
+ };
844
+ }
845
+ }