pushfeedback 0.1.67 → 0.1.68
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/dist/cjs/feedback-button_2.cjs.entry.js +724 -186
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/pushfeedback.cjs.js +1 -1
- package/dist/collection/components/feedback-button/feedback-button.js +60 -0
- package/dist/collection/components/feedback-modal/feedback-modal.css +419 -11
- package/dist/collection/components/feedback-modal/feedback-modal.js +747 -158
- package/dist/components/feedback-button.js +9 -0
- package/dist/components/feedback-modal2.js +739 -186
- package/dist/esm/feedback-button_2.entry.js +724 -186
- package/dist/esm/loader.js +1 -1
- package/dist/esm/pushfeedback.js +1 -1
- package/dist/pushfeedback/p-7406f7be.entry.js +7 -0
- package/dist/pushfeedback/pushfeedback.css +1 -1
- package/dist/pushfeedback/pushfeedback.esm.js +1 -1
- package/dist/types/components/feedback-button/feedback-button.d.ts +3 -0
- package/dist/types/components/feedback-modal/feedback-modal.d.ts +77 -21
- package/dist/types/components.d.ts +12 -0
- package/package.json +1 -1
- package/dist/pushfeedback/p-51e790c7.entry.js +0 -22
|
@@ -30,6 +30,9 @@ const FeedbackButton = class {
|
|
|
30
30
|
this.project = '';
|
|
31
31
|
this.rating = undefined;
|
|
32
32
|
this.ratingMode = 'thumbs';
|
|
33
|
+
this.canvasEditorTitle = 'Edit screenshot';
|
|
34
|
+
this.canvasEditorCancelText = 'Cancel';
|
|
35
|
+
this.canvasEditorSaveText = 'Save';
|
|
33
36
|
this.emailPlaceholder = 'Email address (optional)';
|
|
34
37
|
this.errorMessage = 'Please try again later.';
|
|
35
38
|
this.errorMessage403 = 'The request URL does not match the one defined in PushFeedback for this project.';
|
|
@@ -90,6 +93,9 @@ const FeedbackButton = class {
|
|
|
90
93
|
'project',
|
|
91
94
|
'rating',
|
|
92
95
|
'ratingMode',
|
|
96
|
+
'canvasEditorTitle',
|
|
97
|
+
'canvasEditorCancelText',
|
|
98
|
+
'canvasEditorSaveText',
|
|
93
99
|
'emailPlaceholder',
|
|
94
100
|
'errorMessage',
|
|
95
101
|
'errorMessage403',
|
|
@@ -203,14 +209,14 @@ function commonjsRequire () {
|
|
|
203
209
|
|
|
204
210
|
var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
205
211
|
/*!
|
|
206
|
-
* html2canvas-pro 1.5.
|
|
207
|
-
* Copyright (c) 2024 yorickshan
|
|
212
|
+
* html2canvas-pro 1.5.11 <https://yorickshan.github.io/html2canvas-pro/>
|
|
213
|
+
* Copyright (c) 2024-present yorickshan and html2canvas-pro contributors
|
|
208
214
|
* Released under MIT License
|
|
209
215
|
*/
|
|
210
216
|
(function (global, factory) {
|
|
211
217
|
module.exports = factory() ;
|
|
212
218
|
})(commonjsGlobal, (function () {
|
|
213
|
-
|
|
219
|
+
/******************************************************************************
|
|
214
220
|
Copyright (c) Microsoft Corporation.
|
|
215
221
|
|
|
216
222
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
@@ -224,7 +230,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
224
230
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
225
231
|
PERFORMANCE OF THIS SOFTWARE.
|
|
226
232
|
***************************************************************************** */
|
|
227
|
-
/* global Reflect, Promise */
|
|
233
|
+
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
228
234
|
|
|
229
235
|
var extendStatics = function(d, b) {
|
|
230
236
|
extendStatics = Object.setPrototypeOf ||
|
|
@@ -268,7 +274,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
268
274
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
269
275
|
function step(op) {
|
|
270
276
|
if (f) throw new TypeError("Generator is already executing.");
|
|
271
|
-
while (_) try {
|
|
277
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
272
278
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
273
279
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
274
280
|
switch (op[0]) {
|
|
@@ -297,8 +303,13 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
297
303
|
ar[i] = from[i];
|
|
298
304
|
}
|
|
299
305
|
}
|
|
300
|
-
return to.concat(ar || from);
|
|
301
|
-
}
|
|
306
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
310
|
+
var e = new Error(message);
|
|
311
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
312
|
+
};
|
|
302
313
|
|
|
303
314
|
var Bounds = /** @class */ (function () {
|
|
304
315
|
function Bounds(left, top, width, height) {
|
|
@@ -3933,7 +3944,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
3933
3944
|
case 'gurmukhi':
|
|
3934
3945
|
return 22 /* LIST_STYLE_TYPE.GURMUKHI */;
|
|
3935
3946
|
case 'hebrew':
|
|
3936
|
-
return
|
|
3947
|
+
return 52 /* LIST_STYLE_TYPE.HEBREW */;
|
|
3937
3948
|
case 'hiragana':
|
|
3938
3949
|
return 23 /* LIST_STYLE_TYPE.HIRAGANA */;
|
|
3939
3950
|
case 'hiragana-iroha':
|
|
@@ -6209,7 +6220,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
6209
6220
|
return createCounterStyleFromRange(value, 0xae6, 0xaef, true, defaultSuffix);
|
|
6210
6221
|
case 22 /* LIST_STYLE_TYPE.GURMUKHI */:
|
|
6211
6222
|
return createCounterStyleFromRange(value, 0xa66, 0xa6f, true, defaultSuffix);
|
|
6212
|
-
case
|
|
6223
|
+
case 52 /* LIST_STYLE_TYPE.HEBREW */:
|
|
6213
6224
|
return createAdditiveCounter(value, 1, 10999, HEBREW, 3 /* LIST_STYLE_TYPE.DECIMAL */, defaultSuffix);
|
|
6214
6225
|
case 23 /* LIST_STYLE_TYPE.HIRAGANA */:
|
|
6215
6226
|
return createCounterStyleFromSymbols(value, 'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわゐゑをん');
|
|
@@ -6668,8 +6679,8 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
6668
6679
|
});
|
|
6669
6680
|
};
|
|
6670
6681
|
var ignoredStyleProperties = [
|
|
6671
|
-
'all',
|
|
6672
|
-
'd',
|
|
6682
|
+
'all', // #2476
|
|
6683
|
+
'd', // #2483
|
|
6673
6684
|
'content' // Safari shows pseudoelements if content is set
|
|
6674
6685
|
];
|
|
6675
6686
|
var copyCSSStyles = function (style, target) {
|
|
@@ -6786,12 +6797,21 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
6786
6797
|
};
|
|
6787
6798
|
Cache.prototype.loadImage = function (key) {
|
|
6788
6799
|
return __awaiter(this, void 0, void 0, function () {
|
|
6789
|
-
var isSameOrigin, useCORS, useProxy, src;
|
|
6800
|
+
var isSameOrigin, _a, useCORS, useProxy, src;
|
|
6790
6801
|
var _this = this;
|
|
6791
|
-
return __generator(this, function (
|
|
6792
|
-
switch (
|
|
6802
|
+
return __generator(this, function (_b) {
|
|
6803
|
+
switch (_b.label) {
|
|
6793
6804
|
case 0:
|
|
6794
|
-
|
|
6805
|
+
if (!(typeof this._options.customIsSameOrigin === 'function')) return [3 /*break*/, 2];
|
|
6806
|
+
return [4 /*yield*/, this._options.customIsSameOrigin(key, CacheStorage.isSameOrigin)];
|
|
6807
|
+
case 1:
|
|
6808
|
+
_a = _b.sent();
|
|
6809
|
+
return [3 /*break*/, 3];
|
|
6810
|
+
case 2:
|
|
6811
|
+
_a = CacheStorage.isSameOrigin(key);
|
|
6812
|
+
_b.label = 3;
|
|
6813
|
+
case 3:
|
|
6814
|
+
isSameOrigin = _a;
|
|
6795
6815
|
useCORS = !isInlineImage(key) && this._options.useCORS === true && FEATURES.SUPPORT_CORS_IMAGES && !isSameOrigin;
|
|
6796
6816
|
useProxy = !isInlineImage(key) &&
|
|
6797
6817
|
!isSameOrigin &&
|
|
@@ -6808,12 +6828,12 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
6808
6828
|
return [2 /*return*/];
|
|
6809
6829
|
}
|
|
6810
6830
|
src = key;
|
|
6811
|
-
if (!useProxy) return [3 /*break*/,
|
|
6831
|
+
if (!useProxy) return [3 /*break*/, 5];
|
|
6812
6832
|
return [4 /*yield*/, this.proxy(src)];
|
|
6813
|
-
case
|
|
6814
|
-
src =
|
|
6815
|
-
|
|
6816
|
-
case
|
|
6833
|
+
case 4:
|
|
6834
|
+
src = _b.sent();
|
|
6835
|
+
_b.label = 5;
|
|
6836
|
+
case 5:
|
|
6817
6837
|
this.context.logger.debug("Added image ".concat(key.substring(0, 256)));
|
|
6818
6838
|
return [4 /*yield*/, new Promise(function (resolve, reject) {
|
|
6819
6839
|
var img = new Image();
|
|
@@ -6832,7 +6852,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
6832
6852
|
setTimeout(function () { return reject("Timed out (".concat(_this._options.imageTimeout, "ms) loading image")); }, _this._options.imageTimeout);
|
|
6833
6853
|
}
|
|
6834
6854
|
})];
|
|
6835
|
-
case
|
|
6855
|
+
case 6: return [2 /*return*/, _b.sent()];
|
|
6836
6856
|
}
|
|
6837
6857
|
});
|
|
6838
6858
|
});
|
|
@@ -7958,7 +7978,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
7958
7978
|
};
|
|
7959
7979
|
CanvasRenderer.prototype.renderNodeContent = function (paint) {
|
|
7960
7980
|
return __awaiter(this, void 0, void 0, function () {
|
|
7961
|
-
var container, curves, styles, _i, _a, child, image, image, iframeRenderer, canvas, size, _b, fontFamily, fontSize, baseline, bounds, x, textBounds, img, image, url,
|
|
7981
|
+
var container, curves, styles, _i, _a, child, image, image, iframeRenderer, canvas, size, _b, font, fontFamily, fontSize, baseline, bounds, x, textBounds, img, image, url, font, bounds;
|
|
7962
7982
|
return __generator(this, function (_c) {
|
|
7963
7983
|
switch (_c.label) {
|
|
7964
7984
|
case 0:
|
|
@@ -8058,9 +8078,9 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
8058
8078
|
}
|
|
8059
8079
|
}
|
|
8060
8080
|
if (isTextInputElement(container) && container.value.length) {
|
|
8061
|
-
_b = this.createFontStyle(styles),
|
|
8081
|
+
_b = this.createFontStyle(styles), font = _b[0], fontFamily = _b[1], fontSize = _b[2];
|
|
8062
8082
|
baseline = this.fontMetrics.getMetrics(fontFamily, fontSize).baseline;
|
|
8063
|
-
this.ctx.font =
|
|
8083
|
+
this.ctx.font = font;
|
|
8064
8084
|
this.ctx.fillStyle = asString(styles.color);
|
|
8065
8085
|
this.ctx.textBaseline = 'alphabetic';
|
|
8066
8086
|
this.ctx.textAlign = canvasTextAlign(container.styles.textAlign);
|
|
@@ -8109,8 +8129,8 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
8109
8129
|
case 18: return [3 /*break*/, 20];
|
|
8110
8130
|
case 19:
|
|
8111
8131
|
if (paint.listValue && container.styles.listStyleType !== -1 /* LIST_STYLE_TYPE.NONE */) {
|
|
8112
|
-
|
|
8113
|
-
this.ctx.font =
|
|
8132
|
+
font = this.createFontStyle(styles)[0];
|
|
8133
|
+
this.ctx.font = font;
|
|
8114
8134
|
this.ctx.fillStyle = asString(styles.color);
|
|
8115
8135
|
this.ctx.textBaseline = 'middle';
|
|
8116
8136
|
this.ctx.textAlign = 'right';
|
|
@@ -8340,7 +8360,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
8340
8360
|
canvas.height = height;
|
|
8341
8361
|
ctx = canvas.getContext('2d');
|
|
8342
8362
|
gradient_1 = ctx.createLinearGradient(x0, y0, x1, y1);
|
|
8343
|
-
processColorStops(backgroundImage.stops, lineLength).forEach(function (colorStop) {
|
|
8363
|
+
processColorStops(backgroundImage.stops, lineLength || 1).forEach(function (colorStop) {
|
|
8344
8364
|
return gradient_1.addColorStop(colorStop.stop, asString(colorStop.color));
|
|
8345
8365
|
});
|
|
8346
8366
|
ctx.fillStyle = gradient_1;
|
|
@@ -8875,7 +8895,8 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
8875
8895
|
allowTaint: (_b = opts.allowTaint) !== null && _b !== void 0 ? _b : false,
|
|
8876
8896
|
imageTimeout: (_c = opts.imageTimeout) !== null && _c !== void 0 ? _c : 15000,
|
|
8877
8897
|
proxy: opts.proxy,
|
|
8878
|
-
useCORS: (_d = opts.useCORS) !== null && _d !== void 0 ? _d : false
|
|
8898
|
+
useCORS: (_d = opts.useCORS) !== null && _d !== void 0 ? _d : false,
|
|
8899
|
+
customIsSameOrigin: opts.customIsSameOrigin
|
|
8879
8900
|
};
|
|
8880
8901
|
contextOptions = __assign({ logging: (_e = opts.logging) !== null && _e !== void 0 ? _e : true, cache: opts.cache }, resourceOptions);
|
|
8881
8902
|
windowOptions = {
|
|
@@ -8976,7 +8997,7 @@ var html2canvasPro = createCommonjsModule(function (module, exports) {
|
|
|
8976
8997
|
//# sourceMappingURL=html2canvas-pro.js.map
|
|
8977
8998
|
});
|
|
8978
8999
|
|
|
8979
|
-
const feedbackModalCss = ".text-center{flex-grow:1;text-align:center}.feedback-modal-wrapper *{font-family:var(--feedback-font-family)}.feedback-modal-wrapper--custom-font *{font-family:inherit}.feedback-modal-wrapper{position:absolute;z-index:var(--feedback-modal-modal-wrapper-z-index)}.feedback-overlay{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;opacity:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index);transition:opacity 0.2s ease-out}.feedback-overlay--visible{opacity:1}.feedback-modal{display:inline-block;position:relative}.feedback-modal-content{background-color:var(--feedback-modal-content-bg-color);border-color:1px solid var(--feedback-modal-header-text-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-content-text-color);display:flex;flex-direction:column;left:50%;max-width:90%;padding:20px;position:fixed;top:50%;transform:translate(-50%, -50%) scale(0.95);opacity:0;width:100%;z-index:var(--feedback-modal-content-z-index);transition:transform 0.2s ease-out, opacity 0.2s ease-out}.feedback-modal-content--open{transform:translate(-50%, -50%) scale(1);opacity:1}.feedback-modal-header{align-items:center;color:var(--feedback-modal-header-text-color);display:flex;font-size:var(--feedback-header-font-size);font-weight:var(--feedback-modal-header-font-weight);justify-content:space-between;margin-bottom:20px}.feedback-modal-rating-buttons{width:100%;margin-bottom:20px}.feedback-modal-rating-button{padding:0;background-color:transparent;border:transparent;margin-right:5px;cursor:pointer}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button{border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);font-size:var(--feedback-modal-button-font-size);font-weight:500;margin-right:10px;justify-content:center;padding:5px 10px}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover svg,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected svg{stroke:var(--feedback-modal-rating-button-selected-color)}.feedback-modal-rating-buttons svg{stroke:var(--feedback-modal-rating-button-color);cursor:pointer}.feedback-modal-rating-buttons--stars .feedback-modal-rating-button--selected svg{fill:var(--feedback-modal-rating-button-stars-selected-color);stroke:var(--feedback-modal-rating-button-stars-selected-color)}.feedback-modal-text textarea{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:100px;min-height:100px;padding:10px;resize:vertical;width:100%}.feedback-modal-email input{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:40px;padding:10px;width:100%;margin-bottom:20px}.feedback-modal-privacy{font-size:var(--feedback-modal-input-font-size);margin-bottom:20px}.feedback-modal-text textarea:focus,.feedback-modal-email input:focus{border:1px solid var(--feedback-modal-input-border-color-focused);outline:none}.feedback-modal-buttons{display:flex;flex-direction:column}.feedback-modal-buttons .feedback-modal-button{margin-bottom:20px}.feedback-modal-button{align-items:center;background-color:transparent;border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);cursor:pointer;display:flex;font-size:var(--feedback-modal-button-font-size);font-weight:500;justify-content:center;min-height:40px;padding:5px 10px}.feedback-modal-button svg{margin-right:6px}.feedback-modal-button path{fill:var(--feedback-modal-button-icon-color)}.feedback-modal-button:hover path,.feedback-modal-button--active path{fill:var(--feedback-modal-button-icon-color-active)}.feedback-modal-button--submit{background-color:var(--feedback-modal-button-submit-bg-color);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-submit-text-color)}.feedback-modal-button:hover,.feedback-modal-button--active{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-button--submit:hover{background-color:var(--feedback-modal-button-submit-bg-color-hover);border:1px solid var(--feedback-modal-button-submit-border-color-hover);color:var(--feedback-modal-button-submit-text-color-hover)}.feedback-modal-input-heading{display:block;font-size:14px;font-weight:300;padding-bottom:10px}.feedback-modal-footer{font-size:12px;text-align:center}.feedback-modal-footer a{color:var(--feedback-modal-footer-link);font-weight:500;text-decoration:none}.feedback-logo,.feedback-footer-text{display:block;text-align:center;margin-top:5px}.feedback-footer-text{margin-top:10px;line-height:1.5}.feedback-modal-close{background-color:var(--feedback-modal-close-bg-color);border:0;border-radius:50%;cursor:pointer;height:22px;margin-left:auto;padding:0;width:22px}.feedback-modal-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-screenshot{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index)}.feedback-modal-screenshot-header{align-items:center;background-color:var(--feedback-modal-screenshot-header-bg-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-screenshot-header-text-color);cursor:pointer;display:flex;left:50%;top:20px;transform:translateX(-50%);padding:10px;position:fixed;width:max-content;z-index:var(--feedback-modal-screenshot-header-z-index)}.feedback-modal-screenshot-close{height:24px;padding-left:10px;width:24px}.feedback-modal-screenshot-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-message{font-size:var(--feedback-modal-message-font-size);margin-top:0}.feedback-modal-element-hover{background-color:transparent;cursor:pointer;border:1px solid var(--feedback-modal-element-hover-border-color)}.feedback-modal-element-selected{background-color:transparent;border:3px solid var(--feedback-modal-element-selected-border-color) !important;box-shadow:0 0 0 2px rgba(0, 123, 255, 0.3) !important}.screenshot-preview{display:inline-block;width:30px;height:30px;overflow:hidden;border-radius:4px;margin-right:10px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.1);cursor:pointer;transition:transform 0.2s ease}.screenshot-preview:hover{transform:scale(1.1)}.screenshot-preview img{width:100%;height:100%;object-fit:cover}.preview-modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:rgba(0, 0, 0, 0.8);z-index:10000;display:flex;align-items:center;justify-content:center;cursor:pointer}.preview-modal{position:relative;max-width:90vw;max-height:90vh;border-radius:8px;overflow:hidden;cursor:default}.preview-modal img{max-width:100%;max-height:100%;display:block}@media screen and (min-width: 768px){.feedback-modal-content{max-width:var(--feedback-modal-content-max-width)}.feedback-modal-content.feedback-modal-content--bottom-right{bottom:var(--feedback-modal-content-position-bottom);left:initial;right:var(--feedback-modal-content-position-right);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--bottom-left{bottom:var(--feedback-modal-content-position-bottom);left:var(--feedback-modal-content-position-left);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--top-right{right:var(--feedback-modal-content-position-right);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--top-left{left:var(--feedback-modal-content-position-left);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--center-left{left:5px;right:auto;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--center-right{left:auto;right:5px;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--sidebar-left.feedback-modal-content--open,.feedback-modal-content.feedback-modal-content--sidebar-right.feedback-modal-content--open{transform:translateX(0)}.feedback-modal-content.feedback-modal-content--sidebar-left{max-width:var(--feedback-modal-content-sidebar-max-width);left:0;right:auto;height:100vh;top:0;transform:translateX(-100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-content.feedback-modal-content--sidebar-right{max-width:var(--feedback-modal-content-sidebar-max-width);left:auto;right:0;height:100vh;top:0;transform:translateX(100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-text textarea{height:150px;min-height:150px}.feedback-modal-content.feedback-modal-content--bottom-right{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--bottom-left{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-left.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-right{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-left{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-left.feedback-modal-content--open{transform:translateY(0)}}";
|
|
9000
|
+
const feedbackModalCss = ".text-center{flex-grow:1;text-align:center}.feedback-modal-wrapper *{font-family:var(--feedback-font-family)}.feedback-modal-wrapper--custom-font *{font-family:inherit}.feedback-modal-wrapper{position:absolute;z-index:var(--feedback-modal-modal-wrapper-z-index)}.feedback-overlay{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;opacity:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index);transition:opacity 0.2s ease-out}.feedback-overlay--visible{opacity:1}.feedback-modal{display:inline-block;position:relative}.feedback-modal-content{background-color:var(--feedback-modal-content-bg-color);border-color:1px solid var(--feedback-modal-header-text-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-content-text-color);display:flex;flex-direction:column;left:50%;max-width:90%;padding:20px;position:fixed;top:50%;transform:translate(-50%, -50%) scale(0.95);opacity:0;width:100%;z-index:var(--feedback-modal-content-z-index);transition:transform 0.2s ease-out, opacity 0.2s ease-out}.feedback-modal-content--open{transform:translate(-50%, -50%) scale(1);opacity:1}.feedback-modal-header{align-items:center;color:var(--feedback-modal-header-text-color);display:flex;font-size:var(--feedback-header-font-size);font-weight:var(--feedback-modal-header-font-weight);justify-content:space-between;margin-bottom:20px}.feedback-modal-rating-buttons{width:100%;margin-bottom:20px}.feedback-modal-rating-button{padding:0;background-color:transparent;border:transparent;margin-right:5px;cursor:pointer}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button{border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);font-size:var(--feedback-modal-button-font-size);font-weight:500;margin-right:10px;justify-content:center;padding:5px 10px}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button:hover svg,.feedback-modal-rating-buttons--thumbs .feedback-modal-rating-button--selected svg{stroke:var(--feedback-modal-rating-button-selected-color)}.feedback-modal-rating-buttons svg{stroke:var(--feedback-modal-rating-button-color);cursor:pointer}.feedback-modal-rating-buttons--stars .feedback-modal-rating-button--selected svg{fill:var(--feedback-modal-rating-button-stars-selected-color);stroke:var(--feedback-modal-rating-button-stars-selected-color)}.feedback-modal-text textarea{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:100px;min-height:100px;padding:10px;resize:vertical;width:100%}.feedback-modal-email input{background-color:var(--feedback-modal-input-bg-color);border:1px solid var(--feedback-modal-input-border-color);border-radius:var(--feedback-modal-input-border-radius);box-sizing:border-box;color:var(--feedback-modal-input-text-color);font-size:var(--feedback-modal-input-font-size);margin-bottom:20px;height:40px;padding:10px;width:100%;margin-bottom:20px}.feedback-modal-privacy{font-size:var(--feedback-modal-input-font-size);margin-bottom:20px}.feedback-modal-text textarea:focus,.feedback-modal-email input:focus{border:1px solid var(--feedback-modal-input-border-color-focused);outline:none}.feedback-modal-buttons{display:flex;flex-direction:column}.feedback-modal-buttons .feedback-modal-button{margin-bottom:20px}.feedback-modal-button{align-items:center;background-color:transparent;border:1px solid var(--feedback-modal-button-border-color);border-radius:var(--feedback-modal-button-border-radius);color:var(--feedback-modal-button-text-color);cursor:pointer;display:flex;font-size:var(--feedback-modal-button-font-size);font-weight:500;justify-content:center;min-height:40px;padding:5px 10px}.feedback-modal-button svg{margin-right:6px}.feedback-modal-button path{fill:var(--feedback-modal-button-icon-color)}.feedback-modal-button:hover path,.feedback-modal-button--active path{fill:var(--feedback-modal-button-icon-color-active)}.feedback-modal-button--submit{background-color:var(--feedback-modal-button-submit-bg-color);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-submit-text-color)}.feedback-modal-button:hover,.feedback-modal-button--active{background-color:var(--feedback-modal-button-bg-color-active);border:1px solid var(--feedback-modal-button-border-color-active);color:var(--feedback-modal-button-text-color-active)}.feedback-modal-button--submit:hover{background-color:var(--feedback-modal-button-submit-bg-color-hover);border:1px solid var(--feedback-modal-button-submit-border-color-hover);color:var(--feedback-modal-button-submit-text-color-hover)}.feedback-modal-input-heading{display:block;font-size:14px;font-weight:300;padding-bottom:10px}.feedback-modal-footer{font-size:12px;text-align:center}.feedback-modal-footer a{color:var(--feedback-modal-footer-link);font-weight:500;text-decoration:none}.feedback-logo,.feedback-footer-text{display:block;text-align:center;margin-top:5px}.feedback-footer-text{margin-top:10px;line-height:1.5}.feedback-modal-close{background-color:var(--feedback-modal-close-bg-color);border:0;border-radius:50%;cursor:pointer;height:22px;margin-left:auto;padding:0;width:22px}.feedback-modal-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-screenshot{background-color:var(--feedback-modal-screenshot-bg-color);height:100%;left:0;position:fixed;top:0;width:100%;z-index:var(--feedback-modal-screnshot-z-index)}.feedback-modal-screenshot-header{align-items:center;background-color:var(--feedback-modal-screenshot-header-bg-color);border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);box-sizing:border-box;color:var(--feedback-modal-screenshot-header-text-color);cursor:pointer;display:flex;left:50%;top:20px;transform:translateX(-50%);padding:10px;position:fixed;width:max-content;z-index:var(--feedback-modal-screenshot-header-z-index)}.feedback-modal-screenshot-close{height:24px;padding-left:10px;width:24px}.feedback-modal-screenshot-close svg{stroke:var(--feedback-modal-close-color)}.feedback-modal-message{font-size:var(--feedback-modal-message-font-size);margin-top:0}.feedback-modal-element-hover{background-color:transparent;cursor:pointer;border:1px solid var(--feedback-modal-element-hover-border-color)}.feedback-modal-element-selected{background-color:transparent;border:3px solid var(--feedback-modal-element-selected-border-color) !important;box-shadow:0 0 0 2px rgba(0, 123, 255, 0.3) !important}.screenshot-preview{display:inline-block;width:30px;height:30px;overflow:hidden;border-radius:4px;margin-right:10px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.1);cursor:pointer;transition:transform 0.2s ease}.screenshot-preview:hover{transform:scale(1.1)}.screenshot-preview img{width:100%;height:100%;object-fit:cover}.screenshot-loading{display:inline-flex;align-items:center;margin-right:8px}.canvas-editor-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:var(--feedback-modal-screenshot-bg-color);z-index:10001;display:flex;align-items:center;justify-content:center}.canvas-editor-modal{width:95vw;height:98vh;background:var(--feedback-canvas-editor-bg-color);border-radius:var(--feedback-modal-content-border-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15)}.canvas-editor-header{background:var(--feedback-canvas-editor-header-bg-color);border-bottom:1px solid var(--feedback-canvas-editor-border-color);padding:12px 16px;display:flex;flex-direction:column;gap:12px;flex-shrink:0}.canvas-editor-title h3{margin:0;font-size:var(--feedback-modal-header-font-size);font-weight:var(--feedback-modal-header-font-weight);color:var(--feedback-modal-header-text-color);font-family:var(--feedback-modal-header-font-family)}.canvas-editor-toolbar{display:flex;align-items:center;gap:20px;flex-wrap:wrap}.toolbar-section{display:flex;align-items:center}.toolbar-section:last-child{margin-left:auto;gap:10px}.tool-group{display:flex;align-items:center;background:var(--feedback-canvas-editor-tool-bg-color);border:1px solid var(--feedback-canvas-editor-border-color);border-radius:var(--feedback-modal-button-border-radius);padding:4px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .10)}.tool-btn{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:none;border-radius:var(--feedback-modal-button-border-radius);cursor:pointer;color:var(--feedback-canvas-editor-tool-text-color);transition:all 0.2s ease;position:relative}.tool-btn:hover{background:var(--feedback-canvas-editor-tool-bg-hover);color:var(--feedback-modal-button-text-color-active)}.tool-btn.active{background:var(--feedback-canvas-editor-tool-bg-active);color:var(--feedback-canvas-editor-tool-text-active)}.tool-btn:disabled{opacity:0.4;cursor:not-allowed}.tool-btn:disabled:hover{background:none;color:var(--feedback-canvas-editor-tool-text-color)}.toolbar-divider{width:1px;height:20px;background:var(--feedback-canvas-editor-divider-color);margin:0 6px}.undo-btn{background:var(--feedback-canvas-editor-tool-bg-color) !important;border:1px solid var(--feedback-canvas-editor-border-color) !important}.undo-btn:hover:not(:disabled){background:var(--feedback-canvas-editor-tool-bg-hover) !important}.color-palette{display:flex;align-items:center;gap:6px;background:var(--feedback-canvas-editor-tool-bg-color);border:1px solid var(--feedback-canvas-editor-border-color);border-radius:var(--feedback-modal-button-border-radius);padding:6px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .10)}.color-slot-wrapper{position:relative}.color-btn{width:28px;height:28px;border-radius:var(--feedback-modal-button-border-radius);border:2px solid transparent;cursor:pointer;transition:all 0.2s ease;position:relative;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .15);display:flex;align-items:center;justify-content:center}.color-btn:hover{transform:scale(1.05);box-shadow:0px 2px 4px 0px rgba(60, 64, 67, .25)}.color-btn.active{border-color:var(--feedback-primary-color);transform:scale(1.1);box-shadow:0 0 0 2px rgba(0, 112, 244, 0.2)}.color-btn.editing{border-color:var(--feedback-highlight-color);box-shadow:0 0 0 2px rgba(255, 180, 34, 0.3)}.color-btn.editing:hover{border-color:var(--feedback-highlight-color);box-shadow:0 0 0 2px rgba(255, 180, 34, 0.4)}.color-picker-dropdown{position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:6px;background:var(--feedback-canvas-editor-tool-bg-color);border:1px solid var(--feedback-canvas-editor-border-color);border-radius:var(--feedback-modal-button-border-radius);padding:6px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);z-index:1000}.color-picker-dropdown input[type=\"color\"]{width:50px;height:32px;border:none;border-radius:var(--feedback-modal-button-border-radius);cursor:pointer}.size-control{display:flex;align-items:center;gap:10px;background:var(--feedback-canvas-editor-tool-bg-color);border:1px solid var(--feedback-canvas-editor-border-color);border-radius:var(--feedback-modal-button-border-radius);padding:6px 12px;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .10)}.size-slider{width:70px;height:4px;border-radius:2px;background:var(--feedback-canvas-editor-slider-track);outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;border:none}.size-slider::-webkit-slider-track{width:100%;height:4px;cursor:pointer;background:var(--feedback-canvas-editor-slider-track);border-radius:2px;border:none;box-shadow:none}.size-slider::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--feedback-primary-color);cursor:pointer;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .20);border:none;margin-top:-5px;}.size-slider::-moz-range-track{width:100%;height:4px;cursor:pointer;background:var(--feedback-canvas-editor-slider-track);border-radius:2px;border:none;box-shadow:none}.size-slider::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:var(--feedback-primary-color);cursor:pointer;border:none;box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .20)}.size-slider::-moz-range-progress{background:var(--feedback-canvas-editor-slider-track);height:4px;border-radius:2px}.size-slider::-ms-track{width:100%;height:4px;cursor:pointer;background:transparent;border-color:transparent;color:transparent}.size-slider::-ms-fill-lower{background:var(--feedback-canvas-editor-slider-track);border-radius:2px}.size-slider::-ms-fill-upper{background:var(--feedback-canvas-editor-slider-track);border-radius:2px}.size-slider::-ms-thumb{width:14px;height:14px;border-radius:50%;background:var(--feedback-primary-color);cursor:pointer;border:none}.size-value{font-weight:500;color:var(--feedback-canvas-editor-tool-text-color);font-size:var(--feedback-text-font-size);min-width:30px}.action-btn{display:flex;align-items:center;gap:6px;padding:5px 12px;border:1px solid var(--feedback-canvas-editor-action-secondary-border);border-radius:var(--feedback-modal-button-border-radius);cursor:pointer;font-size:var(--feedback-modal-button-font-size);font-weight:500;transition:all 0.2s ease;min-width:65px;justify-content:center;height:36px;font-family:var(--feedback-font-family)}.action-btn.secondary{background:var(--feedback-canvas-editor-action-secondary-bg);color:var(--feedback-canvas-editor-action-secondary-text);border-color:var(--feedback-canvas-editor-action-secondary-border)}.action-btn.secondary:hover{background:var(--feedback-canvas-editor-tool-bg-hover);color:var(--feedback-modal-button-text-color-active);border-color:var(--feedback-modal-button-border-color-active)}.action-btn.primary{background:var(--feedback-canvas-editor-action-primary-bg);color:var(--feedback-canvas-editor-action-primary-text);border-color:var(--feedback-modal-button-border-color-active)}.action-btn.primary:hover{background:var(--feedback-modal-button-submit-bg-color-hover);border-color:var(--feedback-modal-button-submit-border-color-hover)}.canvas-editor-content{flex:1;display:flex;align-items:center;justify-content:center;padding:16px;background:var(--feedback-canvas-editor-content-bg);overflow:hidden;min-height:0;min-width:0}.annotation-canvas{max-width:100%;max-height:100%;width:auto;height:auto;cursor:crosshair;border-radius:var(--feedback-modal-content-border-radius);box-shadow:0px 1px 2px 0px rgba(60, 64, 67, .30), 0px 2px 6px 2px rgba(60, 64, 67, .15);background:var(--feedback-white-color);transition:box-shadow 0.3s ease;object-fit:contain;display:block}.annotation-canvas:hover{box-shadow:0px 2px 4px 0px rgba(60, 64, 67, .35), 0px 4px 12px 4px rgba(60, 64, 67, .20)}@media screen and (min-width: 768px){.feedback-modal-content{max-width:var(--feedback-modal-content-max-width)}.feedback-modal-content.feedback-modal-content--bottom-right{bottom:var(--feedback-modal-content-position-bottom);left:initial;right:var(--feedback-modal-content-position-right);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--bottom-left{bottom:var(--feedback-modal-content-position-bottom);left:var(--feedback-modal-content-position-left);top:initial;transform:initial}.feedback-modal-content.feedback-modal-content--top-right{right:var(--feedback-modal-content-position-right);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--top-left{left:var(--feedback-modal-content-position-left);top:var(--feedback-modal-content-position-top);transform:initial}.feedback-modal-content.feedback-modal-content--center-left{left:5px;right:auto;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--center-right{left:auto;right:5px;top:50%;transform:translateY(-50%)}.feedback-modal-content.feedback-modal-content--sidebar-left.feedback-modal-content--open,.feedback-modal-content.feedback-modal-content--sidebar-right.feedback-modal-content--open{transform:translateX(0)}.feedback-modal-content.feedback-modal-content--sidebar-left{max-width:var(--feedback-modal-content-sidebar-max-width);left:0;right:auto;height:100vh;top:0;transform:translateX(-100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-content.feedback-modal-content--sidebar-right{max-width:var(--feedback-modal-content-sidebar-max-width);left:auto;right:0;height:100vh;top:0;transform:translateX(100%);transition:transform 0.5s ease-in-out;border-radius:0}.feedback-modal-text textarea{height:150px;min-height:150px}.feedback-modal-content.feedback-modal-content--bottom-right{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--bottom-left{transform:translateY(20px)}.feedback-modal-content.feedback-modal-content--bottom-left.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-right{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-right.feedback-modal-content--open{transform:translateY(0)}.feedback-modal-content.feedback-modal-content--top-left{transform:translateY(-20px)}.feedback-modal-content.feedback-modal-content--top-left.feedback-modal-content--open{transform:translateY(0)}}@media (max-width: 768px){.canvas-editor-modal{width:100vw;height:100vh;border-radius:0}.canvas-editor-header{padding:8px 12px;gap:8px}.canvas-editor-toolbar{flex-direction:column;align-items:stretch;gap:12px}.toolbar-section{justify-content:center}.toolbar-section:last-child{margin-left:0;justify-content:stretch;gap:8px}.action-btn{flex:1;min-width:auto}.canvas-editor-content{padding:8px}.tool-group{flex-wrap:wrap;justify-content:center}.color-palette{flex-wrap:wrap;justify-content:center}.size-control{flex-direction:column;gap:6px;text-align:center}.size-slider{width:100px}}";
|
|
8980
9001
|
|
|
8981
9002
|
const FeedbackModal = class {
|
|
8982
9003
|
constructor(hostRef) {
|
|
@@ -9067,144 +9088,634 @@ const FeedbackModal = class {
|
|
|
9067
9088
|
document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
|
|
9068
9089
|
el.classList.remove('feedback-modal-element-selected');
|
|
9069
9090
|
});
|
|
9091
|
+
// Reset canvas editor states
|
|
9070
9092
|
this.takingScreenshot = false;
|
|
9071
|
-
this.
|
|
9072
|
-
this.
|
|
9093
|
+
this.showPreviewModal = false;
|
|
9094
|
+
this.showCanvasEditor = false;
|
|
9095
|
+
this.annotations = [];
|
|
9096
|
+
this.currentAnnotation = null;
|
|
9097
|
+
this.isDrawing = false;
|
|
9098
|
+
this.canvasRef = null;
|
|
9099
|
+
this.canvasContext = null;
|
|
9100
|
+
this.originalImageData = null;
|
|
9101
|
+
// Reset resizing states
|
|
9102
|
+
this.isResizing = false;
|
|
9103
|
+
this.resizingAnnotation = null;
|
|
9104
|
+
this.resizeStartSize = 16;
|
|
9105
|
+
this.hoveredAnnotation = null;
|
|
9106
|
+
this.resizeHandle = false;
|
|
9107
|
+
// Reset form states
|
|
9073
9108
|
this.formSuccess = false;
|
|
9074
9109
|
this.formError = false;
|
|
9075
9110
|
this.formErrorStatus = 500;
|
|
9076
9111
|
this.formMessage = '';
|
|
9077
9112
|
this.formEmail = '';
|
|
9078
|
-
this.showPreviewModal = false;
|
|
9079
9113
|
this.resetOverflow();
|
|
9080
9114
|
}, 200);
|
|
9081
9115
|
};
|
|
9082
|
-
this.openScreenShot = () => {
|
|
9083
|
-
|
|
9084
|
-
this.showModal = false;
|
|
9085
|
-
this.showScreenshotMode = true;
|
|
9086
|
-
this.showScreenshotTopBar = true;
|
|
9087
|
-
// Clear previous screenshot and selection data
|
|
9088
|
-
this.encodedScreenshot = null;
|
|
9089
|
-
this.originalElement = null;
|
|
9090
|
-
this.selectedElementBounds = null;
|
|
9091
|
-
this.hoveredElement = null;
|
|
9092
|
-
this.hoveredElementBounds = null;
|
|
9093
|
-
// NO CSS CLASSES - they cause scroll jumping
|
|
9094
|
-
};
|
|
9095
|
-
this.closeScreenShot = () => {
|
|
9096
|
-
// Remove highlight from ALL selected elements
|
|
9097
|
-
document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
|
|
9098
|
-
el.classList.remove('feedback-modal-element-selected');
|
|
9099
|
-
});
|
|
9100
|
-
// Reset loading state
|
|
9101
|
-
this.takingScreenshot = false;
|
|
9102
|
-
this.showModal = false;
|
|
9103
|
-
this.showScreenshotMode = false;
|
|
9104
|
-
this.showScreenshotTopBar = false;
|
|
9105
|
-
};
|
|
9106
|
-
this.openPreviewModal = (event) => {
|
|
9107
|
-
event.stopPropagation(); // Prevent button click from firing
|
|
9108
|
-
this.showPreviewModal = true;
|
|
9109
|
-
};
|
|
9110
|
-
this.closePreviewModal = () => {
|
|
9111
|
-
this.showPreviewModal = false;
|
|
9112
|
-
};
|
|
9113
|
-
this.handleMouseOverScreenShot = (event) => {
|
|
9114
|
-
event.preventDefault();
|
|
9115
|
-
if (this.hasSelectedElement)
|
|
9116
|
-
return;
|
|
9117
|
-
const borderOffset = 2;
|
|
9118
|
-
this.screenshotModal.style.display = 'none';
|
|
9119
|
-
const elementUnder = document.elementFromPoint(event.clientX, event.clientY);
|
|
9120
|
-
const rect = elementUnder.getBoundingClientRect();
|
|
9121
|
-
this.screenshotModal.style.display = '';
|
|
9122
|
-
// Store the hovered element and its bounds for later use
|
|
9123
|
-
this.hoveredElement = elementUnder;
|
|
9124
|
-
this.hoveredElementBounds = rect;
|
|
9125
|
-
// Get the bounding box of the element selected
|
|
9126
|
-
this.elementSelected.style.position = 'absolute';
|
|
9127
|
-
this.elementSelected.style.left = `${rect.left}px`;
|
|
9128
|
-
this.elementSelected.style.top = `${rect.top}px`;
|
|
9129
|
-
this.elementSelected.style.width = `${rect.width}px`;
|
|
9130
|
-
this.elementSelected.style.height = `${rect.height}px`;
|
|
9131
|
-
this.elementSelected.classList.add('feedback-modal-element-hover');
|
|
9132
|
-
// Set the background color of nonselected areas
|
|
9133
|
-
// Top
|
|
9134
|
-
this.topSide.style.position = 'absolute';
|
|
9135
|
-
this.topSide.style.left = `${rect.left}px`;
|
|
9136
|
-
this.topSide.style.top = '0px';
|
|
9137
|
-
this.topSide.style.width = `${rect.width + borderOffset}px`;
|
|
9138
|
-
this.topSide.style.height = `${rect.top}px`;
|
|
9139
|
-
this.topSide.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
|
|
9140
|
-
// Left
|
|
9141
|
-
this.leftSide.style.position = 'absolute';
|
|
9142
|
-
this.leftSide.style.left = '0px';
|
|
9143
|
-
this.leftSide.style.top = '0px';
|
|
9144
|
-
this.leftSide.style.width = `${rect.left}px`;
|
|
9145
|
-
this.leftSide.style.height = '100vh';
|
|
9146
|
-
this.leftSide.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
|
|
9147
|
-
// Bottom
|
|
9148
|
-
this.bottomSide.style.position = 'absolute';
|
|
9149
|
-
this.bottomSide.style.left = `${rect.left}px`;
|
|
9150
|
-
this.bottomSide.style.top = `${rect.bottom + borderOffset}px`;
|
|
9151
|
-
this.bottomSide.style.width = `${rect.width + borderOffset}px`;
|
|
9152
|
-
this.bottomSide.style.height = '100vh';
|
|
9153
|
-
this.bottomSide.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
|
|
9154
|
-
// Right
|
|
9155
|
-
this.rightSide.style.position = 'absolute';
|
|
9156
|
-
this.rightSide.style.left = `${rect.right + borderOffset}px`;
|
|
9157
|
-
this.rightSide.style.top = '0px';
|
|
9158
|
-
this.rightSide.style.width = '100%';
|
|
9159
|
-
this.rightSide.style.height = '100vh';
|
|
9160
|
-
this.rightSide.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
|
|
9161
|
-
// Restore the visibility of the screenshot-modal
|
|
9162
|
-
this.screenshotModal.style.backgroundColor = 'transparent';
|
|
9163
|
-
};
|
|
9164
|
-
this.handleMouseClickedSelectedElement = async (event) => {
|
|
9165
|
-
event.preventDefault();
|
|
9166
|
-
if (!this.elementSelected || !this.hoveredElement) {
|
|
9167
|
-
return;
|
|
9168
|
-
}
|
|
9169
|
-
this.hasSelectedElement = true;
|
|
9170
|
-
// Remove highlight from ALL previously selected elements
|
|
9171
|
-
document.querySelectorAll('.feedback-modal-element-selected').forEach(el => {
|
|
9172
|
-
el.classList.remove('feedback-modal-element-selected');
|
|
9173
|
-
});
|
|
9174
|
-
// Add highlight to newly selected element
|
|
9175
|
-
this.hoveredElement.classList.add('feedback-modal-element-selected');
|
|
9176
|
-
// Store element bounds in viewport coordinates
|
|
9177
|
-
this.selectedElementBounds = this.hoveredElementBounds;
|
|
9178
|
-
this.originalElement = this.hoveredElement;
|
|
9179
|
-
// Show loading state in top bar
|
|
9116
|
+
this.openScreenShot = async () => {
|
|
9117
|
+
// Show loading state immediately
|
|
9180
9118
|
this.takingScreenshot = true;
|
|
9181
|
-
// Take screenshot FIRST while highlight is still visible
|
|
9182
9119
|
try {
|
|
9183
|
-
|
|
9184
|
-
|
|
9120
|
+
// Capture viewport screenshot immediately
|
|
9121
|
+
const dataUrl = await this.captureViewportScreenshot();
|
|
9185
9122
|
this.encodedScreenshot = dataUrl;
|
|
9123
|
+
this.originalImageData = dataUrl;
|
|
9186
9124
|
// Reset loading state
|
|
9187
9125
|
this.takingScreenshot = false;
|
|
9188
|
-
//
|
|
9189
|
-
this.
|
|
9190
|
-
this.
|
|
9191
|
-
//
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9126
|
+
// Skip preview modal and go directly to canvas editor
|
|
9127
|
+
this.showModal = false;
|
|
9128
|
+
this.showCanvasEditor = true;
|
|
9129
|
+
// Initialize canvas after a short delay to ensure DOM is ready
|
|
9130
|
+
setTimeout(() => {
|
|
9131
|
+
this.initializeCanvas();
|
|
9132
|
+
}, 100);
|
|
9195
9133
|
}
|
|
9196
9134
|
catch (error) {
|
|
9197
9135
|
console.error('Failed to capture screenshot:', error);
|
|
9198
|
-
this.hasSelectedElement = false;
|
|
9199
9136
|
// Reset loading state on error
|
|
9200
9137
|
this.takingScreenshot = false;
|
|
9201
|
-
//
|
|
9202
|
-
this.showScreenshotTopBar = false;
|
|
9203
|
-
this.showScreenshotMode = false;
|
|
9204
|
-
this.resetOverflow();
|
|
9138
|
+
// Show modal anyway
|
|
9205
9139
|
this.showModal = true;
|
|
9206
9140
|
}
|
|
9207
9141
|
};
|
|
9142
|
+
this.openCanvasEditor = (event) => {
|
|
9143
|
+
if (event) {
|
|
9144
|
+
event.stopPropagation();
|
|
9145
|
+
}
|
|
9146
|
+
this.showModal = false;
|
|
9147
|
+
this.showCanvasEditor = true;
|
|
9148
|
+
// Initialize canvas after a short delay to ensure DOM is ready
|
|
9149
|
+
setTimeout(() => {
|
|
9150
|
+
this.initializeCanvas();
|
|
9151
|
+
}, 100);
|
|
9152
|
+
};
|
|
9153
|
+
this.closeCanvasEditor = () => {
|
|
9154
|
+
this.showCanvasEditor = false;
|
|
9155
|
+
this.showModal = true;
|
|
9156
|
+
};
|
|
9157
|
+
this.saveAnnotations = () => {
|
|
9158
|
+
if (this.canvasRef) {
|
|
9159
|
+
// Create final image with annotations
|
|
9160
|
+
const finalDataUrl = this.canvasRef.toDataURL('image/png');
|
|
9161
|
+
this.encodedScreenshot = finalDataUrl;
|
|
9162
|
+
}
|
|
9163
|
+
this.showCanvasEditor = false;
|
|
9164
|
+
this.showModal = true;
|
|
9165
|
+
};
|
|
9166
|
+
this.initializeCanvas = () => {
|
|
9167
|
+
if (!this.canvasRef || !this.originalImageData)
|
|
9168
|
+
return;
|
|
9169
|
+
this.canvasContext = this.canvasRef.getContext('2d');
|
|
9170
|
+
const img = new Image();
|
|
9171
|
+
img.onload = () => {
|
|
9172
|
+
// Set canvas to original image dimensions
|
|
9173
|
+
this.canvasRef.width = img.width;
|
|
9174
|
+
this.canvasRef.height = img.height;
|
|
9175
|
+
// Get available container dimensions
|
|
9176
|
+
const containerWidth = this.canvasRef.parentElement.clientWidth - 32; // Account for reduced padding (16px * 2)
|
|
9177
|
+
const containerHeight = this.canvasRef.parentElement.clientHeight - 32;
|
|
9178
|
+
// Calculate scale factors for both dimensions
|
|
9179
|
+
const scaleX = containerWidth / img.width;
|
|
9180
|
+
const scaleY = containerHeight / img.height;
|
|
9181
|
+
// Use the smaller scale to ensure complete image fits
|
|
9182
|
+
const scale = Math.min(scaleX, scaleY, 1); // Never scale up, only down
|
|
9183
|
+
// Calculate final display dimensions
|
|
9184
|
+
const displayWidth = img.width * scale;
|
|
9185
|
+
const displayHeight = img.height * scale;
|
|
9186
|
+
// Set CSS size for display (this scales the canvas visually)
|
|
9187
|
+
this.canvasRef.style.width = `${displayWidth}px`;
|
|
9188
|
+
this.canvasRef.style.height = `${displayHeight}px`;
|
|
9189
|
+
console.log('Canvas initialized with complete image fit:', {
|
|
9190
|
+
originalWidth: img.width,
|
|
9191
|
+
originalHeight: img.height,
|
|
9192
|
+
displayWidth,
|
|
9193
|
+
displayHeight,
|
|
9194
|
+
scale,
|
|
9195
|
+
scaleX,
|
|
9196
|
+
scaleY,
|
|
9197
|
+
containerWidth,
|
|
9198
|
+
containerHeight,
|
|
9199
|
+
usingScale: scale === scaleX ? 'width-limited' : 'height-limited'
|
|
9200
|
+
});
|
|
9201
|
+
// Draw the original image at full resolution
|
|
9202
|
+
this.canvasContext.drawImage(img, 0, 0);
|
|
9203
|
+
// Redraw existing annotations
|
|
9204
|
+
this.redrawAnnotations();
|
|
9205
|
+
};
|
|
9206
|
+
img.src = this.originalImageData;
|
|
9207
|
+
};
|
|
9208
|
+
this.redrawAnnotations = () => {
|
|
9209
|
+
if (!this.canvasContext)
|
|
9210
|
+
return;
|
|
9211
|
+
// Clear and redraw background image
|
|
9212
|
+
const img = new Image();
|
|
9213
|
+
img.onload = () => {
|
|
9214
|
+
this.canvasContext.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
|
|
9215
|
+
this.canvasContext.drawImage(img, 0, 0);
|
|
9216
|
+
// Draw all annotations
|
|
9217
|
+
this.annotations.forEach(annotation => {
|
|
9218
|
+
this.drawAnnotation(annotation);
|
|
9219
|
+
});
|
|
9220
|
+
};
|
|
9221
|
+
img.src = this.originalImageData;
|
|
9222
|
+
};
|
|
9223
|
+
this.drawAnnotation = (annotation) => {
|
|
9224
|
+
if (!this.canvasContext)
|
|
9225
|
+
return;
|
|
9226
|
+
this.canvasContext.strokeStyle = annotation.color;
|
|
9227
|
+
this.canvasContext.lineWidth = annotation.lineWidth;
|
|
9228
|
+
this.canvasContext.lineCap = 'round';
|
|
9229
|
+
this.canvasContext.lineJoin = 'round';
|
|
9230
|
+
switch (annotation.type) {
|
|
9231
|
+
case 'rectangle':
|
|
9232
|
+
this.canvasContext.strokeRect(annotation.startX, annotation.startY, annotation.width, annotation.height);
|
|
9233
|
+
// Rectangle resize handles disabled for now
|
|
9234
|
+
break;
|
|
9235
|
+
case 'line':
|
|
9236
|
+
this.canvasContext.beginPath();
|
|
9237
|
+
this.canvasContext.moveTo(annotation.startX, annotation.startY);
|
|
9238
|
+
this.canvasContext.lineTo(annotation.endX, annotation.endY);
|
|
9239
|
+
this.canvasContext.stroke();
|
|
9240
|
+
// Draw resize handles if this annotation is hovered
|
|
9241
|
+
if (this.hoveredAnnotation === annotation) {
|
|
9242
|
+
this.drawLineResizeHandles(annotation);
|
|
9243
|
+
}
|
|
9244
|
+
break;
|
|
9245
|
+
case 'arrow':
|
|
9246
|
+
this.drawArrow(annotation.startX, annotation.startY, annotation.endX, annotation.endY);
|
|
9247
|
+
// Draw resize handles if this annotation is hovered
|
|
9248
|
+
if (this.hoveredAnnotation === annotation) {
|
|
9249
|
+
this.drawLineResizeHandles(annotation); // Same as line
|
|
9250
|
+
}
|
|
9251
|
+
break;
|
|
9252
|
+
case 'text':
|
|
9253
|
+
const fontSize = annotation.fontSize || 16;
|
|
9254
|
+
this.canvasContext.fillStyle = annotation.color;
|
|
9255
|
+
this.canvasContext.font = `${fontSize}px Arial`;
|
|
9256
|
+
this.canvasContext.fillText(annotation.text, annotation.x, annotation.y);
|
|
9257
|
+
// Draw resize handle if this annotation is hovered
|
|
9258
|
+
if (this.hoveredAnnotation === annotation) {
|
|
9259
|
+
this.drawTextResizeHandle(annotation);
|
|
9260
|
+
}
|
|
9261
|
+
break;
|
|
9262
|
+
}
|
|
9263
|
+
};
|
|
9264
|
+
// Draw resize handle for text annotation
|
|
9265
|
+
this.drawTextResizeHandle = (annotation) => {
|
|
9266
|
+
if (!this.canvasContext || annotation.type !== 'text')
|
|
9267
|
+
return;
|
|
9268
|
+
const fontSize = annotation.fontSize || 16;
|
|
9269
|
+
const textWidth = this.getTextWidth(annotation.text, fontSize);
|
|
9270
|
+
const handleSize = 8;
|
|
9271
|
+
const handleX = annotation.x + textWidth;
|
|
9272
|
+
const handleY = annotation.y;
|
|
9273
|
+
// Draw resize handle (small square) - using widget primary color
|
|
9274
|
+
this.canvasContext.fillStyle = '#0070F4'; // var(--feedback-primary-color)
|
|
9275
|
+
this.canvasContext.strokeStyle = '#ffffff';
|
|
9276
|
+
this.canvasContext.lineWidth = 2;
|
|
9277
|
+
this.canvasContext.fillRect(handleX - handleSize / 2, handleY - handleSize / 2, handleSize, handleSize);
|
|
9278
|
+
this.canvasContext.strokeRect(handleX - handleSize / 2, handleY - handleSize / 2, handleSize, handleSize);
|
|
9279
|
+
};
|
|
9280
|
+
this.drawArrow = (fromX, fromY, toX, toY) => {
|
|
9281
|
+
const headlen = 15; // Arrow head length
|
|
9282
|
+
const angle = Math.atan2(toY - fromY, toX - fromX);
|
|
9283
|
+
// Draw line
|
|
9284
|
+
this.canvasContext.beginPath();
|
|
9285
|
+
this.canvasContext.moveTo(fromX, fromY);
|
|
9286
|
+
this.canvasContext.lineTo(toX, toY);
|
|
9287
|
+
this.canvasContext.stroke();
|
|
9288
|
+
// Draw arrow head
|
|
9289
|
+
this.canvasContext.beginPath();
|
|
9290
|
+
this.canvasContext.moveTo(toX, toY);
|
|
9291
|
+
this.canvasContext.lineTo(toX - headlen * Math.cos(angle - Math.PI / 6), toY - headlen * Math.sin(angle - Math.PI / 6));
|
|
9292
|
+
this.canvasContext.moveTo(toX, toY);
|
|
9293
|
+
this.canvasContext.lineTo(toX - headlen * Math.cos(angle + Math.PI / 6), toY - headlen * Math.sin(angle + Math.PI / 6));
|
|
9294
|
+
this.canvasContext.stroke();
|
|
9295
|
+
};
|
|
9296
|
+
this.undoLastAnnotation = () => {
|
|
9297
|
+
this.annotations = this.annotations.slice(0, -1);
|
|
9298
|
+
this.redrawAnnotations();
|
|
9299
|
+
};
|
|
9300
|
+
// Handle color slot editing
|
|
9301
|
+
this.handleColorSlotClick = (colorIndex) => {
|
|
9302
|
+
if (this.editingColorIndex === colorIndex) {
|
|
9303
|
+
// If already editing this slot, just select the color
|
|
9304
|
+
this.canvasDrawingColor = this.defaultColors[colorIndex];
|
|
9305
|
+
this.showColorPicker = false;
|
|
9306
|
+
this.editingColorIndex = -1;
|
|
9307
|
+
}
|
|
9308
|
+
else {
|
|
9309
|
+
// Start editing this color slot
|
|
9310
|
+
this.editingColorIndex = colorIndex;
|
|
9311
|
+
this.showColorPicker = true;
|
|
9312
|
+
this.canvasDrawingColor = this.defaultColors[colorIndex];
|
|
9313
|
+
}
|
|
9314
|
+
};
|
|
9315
|
+
// Update color in slot
|
|
9316
|
+
this.updateColorSlot = (newColor) => {
|
|
9317
|
+
if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
|
|
9318
|
+
this.defaultColors[this.editingColorIndex] = newColor;
|
|
9319
|
+
this.canvasDrawingColor = newColor;
|
|
9320
|
+
this.showColorPicker = false;
|
|
9321
|
+
this.editingColorIndex = -1;
|
|
9322
|
+
// Force reactivity
|
|
9323
|
+
this.defaultColors = [...this.defaultColors];
|
|
9324
|
+
}
|
|
9325
|
+
};
|
|
9326
|
+
// Handle color picker input without closing
|
|
9327
|
+
this.handleColorPickerInput = (event) => {
|
|
9328
|
+
event.stopPropagation();
|
|
9329
|
+
const newColor = event.target.value;
|
|
9330
|
+
if (this.editingColorIndex >= 0 && this.editingColorIndex < this.defaultColors.length) {
|
|
9331
|
+
this.defaultColors[this.editingColorIndex] = newColor;
|
|
9332
|
+
this.canvasDrawingColor = newColor;
|
|
9333
|
+
// Force reactivity
|
|
9334
|
+
this.defaultColors = [...this.defaultColors];
|
|
9335
|
+
}
|
|
9336
|
+
};
|
|
9337
|
+
// Handle color picker click to prevent closing
|
|
9338
|
+
this.handleColorPickerClick = (event) => {
|
|
9339
|
+
event.stopPropagation();
|
|
9340
|
+
};
|
|
9341
|
+
// Close color picker
|
|
9342
|
+
this.closeColorPicker = () => {
|
|
9343
|
+
this.showColorPicker = false;
|
|
9344
|
+
this.editingColorIndex = -1;
|
|
9345
|
+
};
|
|
9346
|
+
// Check if point is in resize handle for any annotation type
|
|
9347
|
+
this.isPointInResizeHandle = (x, y, annotation) => {
|
|
9348
|
+
const handleSize = 8;
|
|
9349
|
+
switch (annotation.type) {
|
|
9350
|
+
case 'text':
|
|
9351
|
+
const textWidth = this.getTextWidth(annotation.text, annotation.fontSize || 16);
|
|
9352
|
+
const handleX = annotation.x + textWidth;
|
|
9353
|
+
const handleY = annotation.y;
|
|
9354
|
+
return x >= handleX - handleSize / 2 && x <= handleX + handleSize / 2 &&
|
|
9355
|
+
y >= handleY - handleSize / 2 && y <= handleY + handleSize / 2;
|
|
9356
|
+
case 'rectangle':
|
|
9357
|
+
// Rectangle resizing disabled for now
|
|
9358
|
+
return false;
|
|
9359
|
+
case 'line':
|
|
9360
|
+
case 'arrow':
|
|
9361
|
+
// Check both endpoint handles
|
|
9362
|
+
const lineHandles = [
|
|
9363
|
+
{ x: annotation.startX, y: annotation.startY, point: 'start' },
|
|
9364
|
+
{ x: annotation.endX, y: annotation.endY, point: 'end' }
|
|
9365
|
+
];
|
|
9366
|
+
for (const handle of lineHandles) {
|
|
9367
|
+
if (x >= handle.x - handleSize / 2 && x <= handle.x + handleSize / 2 &&
|
|
9368
|
+
y >= handle.y - handleSize / 2 && y <= handle.y + handleSize / 2) {
|
|
9369
|
+
return handle.point; // Return which endpoint was clicked
|
|
9370
|
+
}
|
|
9371
|
+
}
|
|
9372
|
+
return false;
|
|
9373
|
+
default:
|
|
9374
|
+
return false;
|
|
9375
|
+
}
|
|
9376
|
+
};
|
|
9377
|
+
// Get text width for resize handle positioning
|
|
9378
|
+
this.getTextWidth = (text, fontSize) => {
|
|
9379
|
+
// Approximate text width calculation
|
|
9380
|
+
return text.length * fontSize * 0.6;
|
|
9381
|
+
};
|
|
9382
|
+
// Start text resize
|
|
9383
|
+
this.startTextResize = (annotation, startPos) => {
|
|
9384
|
+
this.isResizing = true;
|
|
9385
|
+
this.resizingAnnotation = annotation;
|
|
9386
|
+
this.resizeStartSize = annotation.fontSize || 16;
|
|
9387
|
+
this.dragStartPos = startPos;
|
|
9388
|
+
};
|
|
9389
|
+
// Handle text resize
|
|
9390
|
+
this.handleTextResize = (currentPos) => {
|
|
9391
|
+
if (!this.resizingAnnotation || !this.dragStartPos)
|
|
9392
|
+
return;
|
|
9393
|
+
const deltaX = currentPos.x - this.dragStartPos.x;
|
|
9394
|
+
const deltaY = currentPos.y - this.dragStartPos.y;
|
|
9395
|
+
const avgDelta = (deltaX + deltaY) / 2;
|
|
9396
|
+
// Calculate new font size (minimum 8px, maximum 72px)
|
|
9397
|
+
const newSize = Math.max(8, Math.min(72, this.resizeStartSize + avgDelta * 0.5));
|
|
9398
|
+
// Update annotation font size
|
|
9399
|
+
const index = this.annotations.findIndex(a => a === this.resizingAnnotation);
|
|
9400
|
+
if (index !== -1) {
|
|
9401
|
+
this.annotations[index] = Object.assign(Object.assign({}, this.resizingAnnotation), { fontSize: Math.round(newSize) });
|
|
9402
|
+
this.resizingAnnotation = this.annotations[index];
|
|
9403
|
+
}
|
|
9404
|
+
this.redrawAnnotations();
|
|
9405
|
+
};
|
|
9406
|
+
// Start resize for any annotation type
|
|
9407
|
+
this.startResize = (annotation, handle, startPos) => {
|
|
9408
|
+
this.isResizing = true;
|
|
9409
|
+
this.resizingAnnotation = annotation;
|
|
9410
|
+
this.resizeHandle = handle;
|
|
9411
|
+
this.dragStartPos = startPos;
|
|
9412
|
+
// Store original values for different annotation types
|
|
9413
|
+
if (annotation.type === 'text') {
|
|
9414
|
+
this.resizeStartSize = annotation.fontSize || 16;
|
|
9415
|
+
}
|
|
9416
|
+
};
|
|
9417
|
+
// Enhanced mouse down handler with resize detection for all annotation types
|
|
9418
|
+
this.handleCanvasMouseDown = (event) => {
|
|
9419
|
+
if (!this.canvasRef)
|
|
9420
|
+
return;
|
|
9421
|
+
// Close color picker if open
|
|
9422
|
+
if (this.showColorPicker) {
|
|
9423
|
+
this.closeColorPicker();
|
|
9424
|
+
}
|
|
9425
|
+
const coords = this.getCanvasCoordinates(event);
|
|
9426
|
+
// Check if clicking on existing annotation first
|
|
9427
|
+
const found = this.findAnnotationAt(coords.x, coords.y);
|
|
9428
|
+
if (found) {
|
|
9429
|
+
// Check if clicking on resize handle for any annotation type
|
|
9430
|
+
const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
|
|
9431
|
+
if (handle) {
|
|
9432
|
+
this.startResize(found.annotation, handle, coords);
|
|
9433
|
+
this.canvasRef.style.cursor = 'nw-resize';
|
|
9434
|
+
return;
|
|
9435
|
+
}
|
|
9436
|
+
// Start dragging existing annotation
|
|
9437
|
+
if (!this.isDrawing) {
|
|
9438
|
+
this.isDragging = true;
|
|
9439
|
+
this.draggedAnnotation = found.annotation;
|
|
9440
|
+
this.dragStartPos = coords;
|
|
9441
|
+
this.canvasRef.style.cursor = 'grabbing';
|
|
9442
|
+
return;
|
|
9443
|
+
}
|
|
9444
|
+
}
|
|
9445
|
+
// Original drawing logic
|
|
9446
|
+
this.isDrawing = true;
|
|
9447
|
+
if (this.canvasDrawingTool === 'text') {
|
|
9448
|
+
const text = prompt('Enter text:');
|
|
9449
|
+
if (text) {
|
|
9450
|
+
const annotation = {
|
|
9451
|
+
type: 'text',
|
|
9452
|
+
x: coords.x,
|
|
9453
|
+
y: coords.y,
|
|
9454
|
+
text,
|
|
9455
|
+
color: this.canvasDrawingColor,
|
|
9456
|
+
fontSize: 16
|
|
9457
|
+
};
|
|
9458
|
+
this.annotations = [...this.annotations, annotation];
|
|
9459
|
+
this.redrawAnnotations();
|
|
9460
|
+
}
|
|
9461
|
+
this.isDrawing = false;
|
|
9462
|
+
}
|
|
9463
|
+
else {
|
|
9464
|
+
this.currentAnnotation = {
|
|
9465
|
+
type: this.canvasDrawingTool,
|
|
9466
|
+
startX: coords.x,
|
|
9467
|
+
startY: coords.y,
|
|
9468
|
+
color: this.canvasDrawingColor,
|
|
9469
|
+
lineWidth: this.canvasLineWidth
|
|
9470
|
+
};
|
|
9471
|
+
}
|
|
9472
|
+
};
|
|
9473
|
+
this.handleCanvasMouseMove = (event) => {
|
|
9474
|
+
if (!this.canvasRef)
|
|
9475
|
+
return;
|
|
9476
|
+
const coords = this.getCanvasCoordinates(event);
|
|
9477
|
+
// Handle resizing for any annotation type
|
|
9478
|
+
if (this.isResizing && this.resizingAnnotation) {
|
|
9479
|
+
this.handleResize(coords);
|
|
9480
|
+
return;
|
|
9481
|
+
}
|
|
9482
|
+
// Handle dragging existing annotation
|
|
9483
|
+
if (this.isDragging && this.draggedAnnotation && this.dragStartPos) {
|
|
9484
|
+
const deltaX = coords.x - this.dragStartPos.x;
|
|
9485
|
+
const deltaY = coords.y - this.dragStartPos.y;
|
|
9486
|
+
// Update annotation position
|
|
9487
|
+
const updatedAnnotation = Object.assign({}, this.draggedAnnotation);
|
|
9488
|
+
switch (updatedAnnotation.type) {
|
|
9489
|
+
case 'rectangle':
|
|
9490
|
+
updatedAnnotation.startX += deltaX;
|
|
9491
|
+
updatedAnnotation.startY += deltaY;
|
|
9492
|
+
break;
|
|
9493
|
+
case 'line':
|
|
9494
|
+
case 'arrow':
|
|
9495
|
+
updatedAnnotation.startX += deltaX;
|
|
9496
|
+
updatedAnnotation.startY += deltaY;
|
|
9497
|
+
updatedAnnotation.endX += deltaX;
|
|
9498
|
+
updatedAnnotation.endY += deltaY;
|
|
9499
|
+
break;
|
|
9500
|
+
case 'text':
|
|
9501
|
+
updatedAnnotation.x += deltaX;
|
|
9502
|
+
updatedAnnotation.y += deltaY;
|
|
9503
|
+
break;
|
|
9504
|
+
}
|
|
9505
|
+
// Update annotation in array
|
|
9506
|
+
const index = this.annotations.findIndex(a => a === this.draggedAnnotation);
|
|
9507
|
+
if (index !== -1) {
|
|
9508
|
+
this.annotations[index] = updatedAnnotation;
|
|
9509
|
+
this.draggedAnnotation = updatedAnnotation;
|
|
9510
|
+
}
|
|
9511
|
+
this.dragStartPos = coords;
|
|
9512
|
+
this.redrawAnnotations();
|
|
9513
|
+
return;
|
|
9514
|
+
}
|
|
9515
|
+
// Handle drawing new annotation
|
|
9516
|
+
if (this.isDrawing && this.currentAnnotation) {
|
|
9517
|
+
if (this.canvasDrawingTool === 'rectangle') {
|
|
9518
|
+
this.currentAnnotation.width = coords.x - this.currentAnnotation.startX;
|
|
9519
|
+
this.currentAnnotation.height = coords.y - this.currentAnnotation.startY;
|
|
9520
|
+
}
|
|
9521
|
+
else {
|
|
9522
|
+
this.currentAnnotation.endX = coords.x;
|
|
9523
|
+
this.currentAnnotation.endY = coords.y;
|
|
9524
|
+
}
|
|
9525
|
+
this.redrawAnnotations();
|
|
9526
|
+
this.drawAnnotation(this.currentAnnotation);
|
|
9527
|
+
return;
|
|
9528
|
+
}
|
|
9529
|
+
// Handle hover states and cursor changes
|
|
9530
|
+
const found = this.findAnnotationAt(coords.x, coords.y);
|
|
9531
|
+
if (found) {
|
|
9532
|
+
// Check if hovering over resize handle for any annotation type
|
|
9533
|
+
const handle = this.isPointInResizeHandle(coords.x, coords.y, found.annotation);
|
|
9534
|
+
if (handle) {
|
|
9535
|
+
this.canvasRef.style.cursor = 'nw-resize';
|
|
9536
|
+
this.hoveredAnnotation = found.annotation;
|
|
9537
|
+
this.redrawAnnotations();
|
|
9538
|
+
return;
|
|
9539
|
+
}
|
|
9540
|
+
// Regular hover over annotation
|
|
9541
|
+
this.canvasRef.style.cursor = 'grab';
|
|
9542
|
+
if (this.hoveredAnnotation !== found.annotation) {
|
|
9543
|
+
this.hoveredAnnotation = found.annotation;
|
|
9544
|
+
this.redrawAnnotations();
|
|
9545
|
+
}
|
|
9546
|
+
}
|
|
9547
|
+
else {
|
|
9548
|
+
// No annotation under cursor
|
|
9549
|
+
this.canvasRef.style.cursor = 'crosshair';
|
|
9550
|
+
if (this.hoveredAnnotation) {
|
|
9551
|
+
this.hoveredAnnotation = null;
|
|
9552
|
+
this.redrawAnnotations();
|
|
9553
|
+
}
|
|
9554
|
+
}
|
|
9555
|
+
};
|
|
9556
|
+
this.handleCanvasMouseUp = () => {
|
|
9557
|
+
// Handle end of text resizing
|
|
9558
|
+
if (this.isResizing) {
|
|
9559
|
+
this.isResizing = false;
|
|
9560
|
+
this.resizingAnnotation = null;
|
|
9561
|
+
this.dragStartPos = null;
|
|
9562
|
+
this.resizeHandle = false;
|
|
9563
|
+
if (this.canvasRef) {
|
|
9564
|
+
this.canvasRef.style.cursor = 'crosshair';
|
|
9565
|
+
}
|
|
9566
|
+
return;
|
|
9567
|
+
}
|
|
9568
|
+
// Handle end of dragging
|
|
9569
|
+
if (this.isDragging) {
|
|
9570
|
+
this.isDragging = false;
|
|
9571
|
+
this.draggedAnnotation = null;
|
|
9572
|
+
this.dragStartPos = null;
|
|
9573
|
+
if (this.canvasRef) {
|
|
9574
|
+
this.canvasRef.style.cursor = 'crosshair';
|
|
9575
|
+
}
|
|
9576
|
+
return;
|
|
9577
|
+
}
|
|
9578
|
+
// Handle end of drawing
|
|
9579
|
+
if (!this.isDrawing || !this.currentAnnotation)
|
|
9580
|
+
return;
|
|
9581
|
+
this.isDrawing = false;
|
|
9582
|
+
this.annotations = [...this.annotations, this.currentAnnotation];
|
|
9583
|
+
this.currentAnnotation = null;
|
|
9584
|
+
this.redrawAnnotations();
|
|
9585
|
+
};
|
|
9586
|
+
// Draw resize handles for rectangle annotation
|
|
9587
|
+
this.drawRectangleResizeHandles = (annotation) => {
|
|
9588
|
+
if (!this.canvasContext || annotation.type !== 'rectangle')
|
|
9589
|
+
return;
|
|
9590
|
+
const handleSize = 8;
|
|
9591
|
+
const left = annotation.startX;
|
|
9592
|
+
const top = annotation.startY;
|
|
9593
|
+
const right = annotation.startX + annotation.width;
|
|
9594
|
+
const bottom = annotation.startY + annotation.height;
|
|
9595
|
+
// Define handle positions (4 corners)
|
|
9596
|
+
const handles = [
|
|
9597
|
+
{ x: left, y: top },
|
|
9598
|
+
{ x: right, y: top },
|
|
9599
|
+
{ x: right, y: bottom },
|
|
9600
|
+
{ x: left, y: bottom } // Bottom-left
|
|
9601
|
+
];
|
|
9602
|
+
// Draw each handle
|
|
9603
|
+
this.canvasContext.fillStyle = '#0070F4'; // Primary color
|
|
9604
|
+
this.canvasContext.strokeStyle = '#ffffff';
|
|
9605
|
+
this.canvasContext.lineWidth = 2;
|
|
9606
|
+
handles.forEach(handle => {
|
|
9607
|
+
this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
|
|
9608
|
+
this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
|
|
9609
|
+
});
|
|
9610
|
+
};
|
|
9611
|
+
// Draw resize handles for line/arrow annotation
|
|
9612
|
+
this.drawLineResizeHandles = (annotation) => {
|
|
9613
|
+
if (!this.canvasContext || (annotation.type !== 'line' && annotation.type !== 'arrow'))
|
|
9614
|
+
return;
|
|
9615
|
+
const handleSize = 8;
|
|
9616
|
+
// Define handle positions (2 endpoints)
|
|
9617
|
+
const handles = [
|
|
9618
|
+
{ x: annotation.startX, y: annotation.startY },
|
|
9619
|
+
{ x: annotation.endX, y: annotation.endY } // End point
|
|
9620
|
+
];
|
|
9621
|
+
// Draw each handle
|
|
9622
|
+
this.canvasContext.fillStyle = '#0070F4'; // Primary color
|
|
9623
|
+
this.canvasContext.strokeStyle = '#ffffff';
|
|
9624
|
+
this.canvasContext.lineWidth = 2;
|
|
9625
|
+
handles.forEach(handle => {
|
|
9626
|
+
this.canvasContext.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
|
|
9627
|
+
this.canvasContext.strokeRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
|
|
9628
|
+
});
|
|
9629
|
+
};
|
|
9630
|
+
// Convert screen coordinates to canvas coordinates
|
|
9631
|
+
this.getCanvasCoordinates = (event) => {
|
|
9632
|
+
if (!this.canvasRef)
|
|
9633
|
+
return { x: 0, y: 0 };
|
|
9634
|
+
const rect = this.canvasRef.getBoundingClientRect();
|
|
9635
|
+
// Calculate the scale factor between display size and actual canvas size
|
|
9636
|
+
const scaleX = this.canvasRef.width / rect.width;
|
|
9637
|
+
const scaleY = this.canvasRef.height / rect.height;
|
|
9638
|
+
const x = (event.clientX - rect.left) * scaleX;
|
|
9639
|
+
const y = (event.clientY - rect.top) * scaleY;
|
|
9640
|
+
return { x, y };
|
|
9641
|
+
};
|
|
9642
|
+
// Find annotation under mouse cursor
|
|
9643
|
+
this.findAnnotationAt = (x, y) => {
|
|
9644
|
+
// Check in reverse order (top to bottom)
|
|
9645
|
+
for (let i = this.annotations.length - 1; i >= 0; i--) {
|
|
9646
|
+
const annotation = this.annotations[i];
|
|
9647
|
+
if (this.isPointInAnnotation(x, y, annotation)) {
|
|
9648
|
+
return { annotation, index: i };
|
|
9649
|
+
}
|
|
9650
|
+
}
|
|
9651
|
+
return null;
|
|
9652
|
+
};
|
|
9653
|
+
// Check if point is within annotation bounds
|
|
9654
|
+
this.isPointInAnnotation = (x, y, annotation) => {
|
|
9655
|
+
const tolerance = 10; // Click tolerance
|
|
9656
|
+
switch (annotation.type) {
|
|
9657
|
+
case 'rectangle':
|
|
9658
|
+
const left = Math.min(annotation.startX, annotation.startX + annotation.width);
|
|
9659
|
+
const right = Math.max(annotation.startX, annotation.startX + annotation.width);
|
|
9660
|
+
const top = Math.min(annotation.startY, annotation.startY + annotation.height);
|
|
9661
|
+
const bottom = Math.max(annotation.startY, annotation.startY + annotation.height);
|
|
9662
|
+
return x >= left - tolerance && x <= right + tolerance &&
|
|
9663
|
+
y >= top - tolerance && y <= bottom + tolerance;
|
|
9664
|
+
case 'line':
|
|
9665
|
+
case 'arrow':
|
|
9666
|
+
// Distance from point to line
|
|
9667
|
+
const A = annotation.endY - annotation.startY;
|
|
9668
|
+
const B = annotation.startX - annotation.endX;
|
|
9669
|
+
const C = annotation.endX * annotation.startY - annotation.startX * annotation.endY;
|
|
9670
|
+
const distance = Math.abs(A * x + B * y + C) / Math.sqrt(A * A + B * B);
|
|
9671
|
+
return distance <= tolerance;
|
|
9672
|
+
case 'text':
|
|
9673
|
+
// Simple bounding box for text
|
|
9674
|
+
return x >= annotation.x - tolerance && x <= annotation.x + 100 &&
|
|
9675
|
+
y >= annotation.y - 20 && y <= annotation.y + tolerance;
|
|
9676
|
+
default:
|
|
9677
|
+
return false;
|
|
9678
|
+
}
|
|
9679
|
+
};
|
|
9680
|
+
// Handle resize for different annotation types
|
|
9681
|
+
this.handleResize = (currentPos) => {
|
|
9682
|
+
if (!this.resizingAnnotation || !this.dragStartPos)
|
|
9683
|
+
return;
|
|
9684
|
+
const annotation = this.resizingAnnotation;
|
|
9685
|
+
const index = this.annotations.findIndex(a => a === annotation);
|
|
9686
|
+
if (index === -1)
|
|
9687
|
+
return;
|
|
9688
|
+
let updatedAnnotation = Object.assign({}, annotation);
|
|
9689
|
+
switch (annotation.type) {
|
|
9690
|
+
case 'text':
|
|
9691
|
+
// Text resize logic (existing)
|
|
9692
|
+
const deltaX = currentPos.x - this.dragStartPos.x;
|
|
9693
|
+
const deltaY = currentPos.y - this.dragStartPos.y;
|
|
9694
|
+
const avgDelta = (deltaX + deltaY) / 2;
|
|
9695
|
+
const newSize = Math.max(8, Math.min(72, this.resizeStartSize + avgDelta * 0.5));
|
|
9696
|
+
updatedAnnotation.fontSize = Math.round(newSize);
|
|
9697
|
+
break;
|
|
9698
|
+
case 'rectangle':
|
|
9699
|
+
// Rectangle resizing disabled for now
|
|
9700
|
+
return;
|
|
9701
|
+
case 'line':
|
|
9702
|
+
case 'arrow':
|
|
9703
|
+
// Line/arrow resize logic - move endpoints
|
|
9704
|
+
if (this.resizeHandle === 'start') {
|
|
9705
|
+
updatedAnnotation.startX = currentPos.x;
|
|
9706
|
+
updatedAnnotation.startY = currentPos.y;
|
|
9707
|
+
}
|
|
9708
|
+
else if (this.resizeHandle === 'end') {
|
|
9709
|
+
updatedAnnotation.endX = currentPos.x;
|
|
9710
|
+
updatedAnnotation.endY = currentPos.y;
|
|
9711
|
+
}
|
|
9712
|
+
break;
|
|
9713
|
+
}
|
|
9714
|
+
// Update annotation in array
|
|
9715
|
+
this.annotations[index] = updatedAnnotation;
|
|
9716
|
+
this.resizingAnnotation = updatedAnnotation;
|
|
9717
|
+
this.redrawAnnotations();
|
|
9718
|
+
};
|
|
9208
9719
|
this.sending = false;
|
|
9209
9720
|
this.formMessage = '';
|
|
9210
9721
|
this.formEmail = '';
|
|
@@ -9218,6 +9729,26 @@ const FeedbackModal = class {
|
|
|
9218
9729
|
this.selectedRating = -1;
|
|
9219
9730
|
this.overlayVisible = false;
|
|
9220
9731
|
this.isAnimating = false;
|
|
9732
|
+
this.takingScreenshot = false;
|
|
9733
|
+
this.showPreviewModal = false;
|
|
9734
|
+
this.showCanvasEditor = false;
|
|
9735
|
+
this.canvasDrawingTool = 'rectangle';
|
|
9736
|
+
this.canvasDrawingColor = '#ff0000';
|
|
9737
|
+
this.canvasLineWidth = 3;
|
|
9738
|
+
this.isDrawing = false;
|
|
9739
|
+
this.annotations = [];
|
|
9740
|
+
this.currentAnnotation = null;
|
|
9741
|
+
this.isDragging = false;
|
|
9742
|
+
this.draggedAnnotation = null;
|
|
9743
|
+
this.dragStartPos = null;
|
|
9744
|
+
this.showColorPicker = false;
|
|
9745
|
+
this.editingColorIndex = -1;
|
|
9746
|
+
this.isResizing = false;
|
|
9747
|
+
this.resizingAnnotation = null;
|
|
9748
|
+
this.resizeStartSize = 16;
|
|
9749
|
+
this.hoveredAnnotation = null;
|
|
9750
|
+
this.resizeHandle = false;
|
|
9751
|
+
this.defaultColors = ['#ff0000', '#00ff00', '#0000ff', '#000000'];
|
|
9221
9752
|
this.customFont = false;
|
|
9222
9753
|
this.emailAddress = '';
|
|
9223
9754
|
this.hideEmail = false;
|
|
@@ -9253,8 +9784,9 @@ const FeedbackModal = class {
|
|
|
9253
9784
|
this.screenshotTakingText = 'Taking screenshot...';
|
|
9254
9785
|
this.screenshotTopbarText = 'Select an element on this page';
|
|
9255
9786
|
this.successMessage = '';
|
|
9256
|
-
this.
|
|
9257
|
-
this.
|
|
9787
|
+
this.canvasEditorTitle = 'Edit screenshot';
|
|
9788
|
+
this.canvasEditorCancelText = 'Cancel';
|
|
9789
|
+
this.canvasEditorSaveText = 'Save';
|
|
9258
9790
|
}
|
|
9259
9791
|
componentWillLoad() {
|
|
9260
9792
|
if (this.fetchData)
|
|
@@ -9289,46 +9821,51 @@ const FeedbackModal = class {
|
|
|
9289
9821
|
handleEmailInput(event) {
|
|
9290
9822
|
this.formEmail = event.target.value;
|
|
9291
9823
|
}
|
|
9292
|
-
|
|
9824
|
+
captureViewportScreenshot() {
|
|
9293
9825
|
return new Promise((resolve, reject) => {
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9826
|
+
requestAnimationFrame(() => {
|
|
9827
|
+
// Get viewport dimensions and scroll position
|
|
9828
|
+
const viewportWidth = window.innerWidth;
|
|
9829
|
+
const viewportHeight = window.innerHeight;
|
|
9830
|
+
const scrollX = window.scrollX || window.pageXOffset || 0;
|
|
9831
|
+
const scrollY = window.scrollY || window.pageYOffset || 0;
|
|
9832
|
+
// Capture exactly what the user sees in their viewport
|
|
9833
|
+
html2canvasPro(document.documentElement, {
|
|
9834
|
+
x: scrollX,
|
|
9835
|
+
y: scrollY,
|
|
9836
|
+
width: viewportWidth,
|
|
9837
|
+
height: viewportHeight,
|
|
9838
|
+
scrollX: 0,
|
|
9839
|
+
scrollY: 0,
|
|
9840
|
+
allowTaint: false,
|
|
9841
|
+
useCORS: true,
|
|
9842
|
+
scale: 1,
|
|
9843
|
+
backgroundColor: '#ffffff',
|
|
9844
|
+
logging: false,
|
|
9845
|
+
foreignObjectRendering: false,
|
|
9846
|
+
imageTimeout: 15000,
|
|
9847
|
+
windowWidth: viewportWidth,
|
|
9848
|
+
windowHeight: viewportHeight,
|
|
9849
|
+
removeContainer: true,
|
|
9850
|
+
ignoreElements: (element) => {
|
|
9851
|
+
// Ignore all feedback modal elements
|
|
9852
|
+
return element.closest('feedback-modal') !== null ||
|
|
9853
|
+
element.classList.contains('feedback-overlay') ||
|
|
9854
|
+
element.classList.contains('feedback-modal-screenshot-header') ||
|
|
9855
|
+
element.tagName === 'FEEDBACK-MODAL' ||
|
|
9856
|
+
element.tagName === 'FEEDBACK-BUTTON';
|
|
9300
9857
|
}
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
useCORS: true,
|
|
9311
|
-
scale: 1,
|
|
9312
|
-
backgroundColor: '#ffffff',
|
|
9313
|
-
logging: true,
|
|
9314
|
-
foreignObjectRendering: false,
|
|
9315
|
-
imageTimeout: 10000,
|
|
9316
|
-
ignoreElements: (element) => {
|
|
9317
|
-
// Only ignore screenshot UI, keep everything else including highlights
|
|
9318
|
-
return element.classList.contains('feedback-modal-screenshot-header') ||
|
|
9319
|
-
element.classList.contains('feedback-overlay');
|
|
9320
|
-
}
|
|
9321
|
-
})
|
|
9322
|
-
.then((canvas) => {
|
|
9323
|
-
const dataUrl = canvas.toDataURL();
|
|
9324
|
-
resolve(dataUrl);
|
|
9325
|
-
})
|
|
9326
|
-
.catch((error) => {
|
|
9327
|
-
console.error('Failed to capture screenshot:', error);
|
|
9328
|
-
reject(error);
|
|
9329
|
-
});
|
|
9858
|
+
})
|
|
9859
|
+
.then((canvas) => {
|
|
9860
|
+
const dataUrl = canvas.toDataURL('image/png');
|
|
9861
|
+
console.log('Screenshot captured successfully, size:', canvas.width, 'x', canvas.height);
|
|
9862
|
+
resolve(dataUrl);
|
|
9863
|
+
})
|
|
9864
|
+
.catch((error) => {
|
|
9865
|
+
console.error('Failed to capture viewport screenshot:', error);
|
|
9866
|
+
reject(error);
|
|
9330
9867
|
});
|
|
9331
|
-
}
|
|
9868
|
+
});
|
|
9332
9869
|
});
|
|
9333
9870
|
}
|
|
9334
9871
|
handleCheckboxChange(event) {
|
|
@@ -9341,7 +9878,7 @@ const FeedbackModal = class {
|
|
|
9341
9878
|
this.selectedRating = newRating;
|
|
9342
9879
|
}
|
|
9343
9880
|
render() {
|
|
9344
|
-
return (index.h("div", { class: `feedback-modal-wrapper ${this.customFont ? 'feedback-modal-wrapper--custom-font' : ''}` }, this.
|
|
9881
|
+
return (index.h("div", { class: `feedback-modal-wrapper ${this.customFont ? 'feedback-modal-wrapper--custom-font' : ''}` }, this.showModal && (index.h("div", { class: `feedback-overlay ${this.isAnimating ? 'feedback-overlay--visible' : ''}` })), this.showModal && (index.h("div", { class: `feedback-modal-content feedback-modal-content--${this.modalPosition} ${this.isAnimating ? 'feedback-modal-content--open' : ''}`, ref: (el) => (this.modalContent = el) }, index.h("div", { class: "feedback-modal-header" }, !this.formSuccess && !this.formError ? (index.h("span", null, this.modalTitle)) : this.formSuccess ? (index.h("span", null, this.modalTitleSuccess)) : (index.h("span", null, this.modalTitleError)), index.h("button", { class: "feedback-modal-close", onClick: this.close }, index.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" }, index.h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), index.h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))), index.h("div", { class: "feedback-modal-body" }, !this.formSuccess && !this.formError ? (index.h("form", { onSubmit: this.handleSubmit }, !this.hideRating && (index.h("div", { class: "feedback-modal-rating" }, this.ratingMode === 'thumbs' ? (index.h("div", { class: "feedback-modal-rating-content" }, index.h("span", { class: "feedback-modal-input-heading" }, this.ratingPlaceholder), index.h("div", { class: "feedback-modal-rating-buttons feedback-modal-rating-buttons--thumbs" }, index.h("button", { title: "Yes", class: `feedback-modal-rating-button ${this.selectedRating === 1
|
|
9345
9882
|
? 'feedback-modal-rating-button--selected'
|
|
9346
9883
|
: ''}`, onClick: (event) => {
|
|
9347
9884
|
event.preventDefault();
|
|
@@ -9356,7 +9893,8 @@ const FeedbackModal = class {
|
|
|
9356
9893
|
: ''}`, onClick: (event) => {
|
|
9357
9894
|
event.preventDefault();
|
|
9358
9895
|
this.handleRatingChange(rating);
|
|
9359
|
-
} }, index.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" }, index.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" })))))))))), index.h("div", { class: "feedback-modal-text" }, index.h("textarea", { placeholder: this.messagePlaceholder, value: this.formMessage, onInput: (event) => this.handleMessageInput(event) })), !this.hideEmail && (index.h("div", { class: "feedback-modal-email" }, index.h("input", { placeholder: this.emailPlaceholder, type: "email", onInput: (event) => this.handleEmailInput(event), value: this.formEmail, required: this.isEmailRequired }))), index.h("div", { class: "feedback-verification" }, index.h("input", { type: "text", name: "verification", style: { display: 'none' }, onInput: (event) => this.handleVerification(event), value: this.formVerification })), !this.hidePrivacyPolicy && (index.h("div", { class: "feedback-modal-privacy" }, index.h("input", { type: "checkbox", id: "privacyPolicy", onChange: (ev) => this.handleCheckboxChange(ev), required: true }), index.h("span", { innerHTML: this.privacyPolicyText }))), index.h("div", { class: `feedback-modal-buttons ${this.hideScreenshotButton ? 'single' : ''}` }, !this.hideScreenshotButton && (index.h("button", { type: "button", class: `feedback-modal-button feedback-modal-button--screenshot ${this.encodedScreenshot ? 'feedback-modal-button--active' : ''}`, onClick: this.openScreenShot, disabled: this.sending }, this.encodedScreenshot && (index.h("div", { class: "screenshot-preview", onClick: this.
|
|
9896
|
+
} }, index.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" }, index.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" })))))))))), index.h("div", { class: "feedback-modal-text" }, index.h("textarea", { placeholder: this.messagePlaceholder, value: this.formMessage, onInput: (event) => this.handleMessageInput(event) })), !this.hideEmail && (index.h("div", { class: "feedback-modal-email" }, index.h("input", { placeholder: this.emailPlaceholder, type: "email", onInput: (event) => this.handleEmailInput(event), value: this.formEmail, required: this.isEmailRequired }))), index.h("div", { class: "feedback-verification" }, index.h("input", { type: "text", name: "verification", style: { display: 'none' }, onInput: (event) => this.handleVerification(event), value: this.formVerification })), !this.hidePrivacyPolicy && (index.h("div", { class: "feedback-modal-privacy" }, index.h("input", { type: "checkbox", id: "privacyPolicy", onChange: (ev) => this.handleCheckboxChange(ev), required: true }), index.h("span", { innerHTML: this.privacyPolicyText }))), index.h("div", { class: `feedback-modal-buttons ${this.hideScreenshotButton ? 'single' : ''}` }, !this.hideScreenshotButton && (index.h("button", { type: "button", class: `feedback-modal-button feedback-modal-button--screenshot ${this.encodedScreenshot ? 'feedback-modal-button--active' : ''}`, onClick: this.openScreenShot, disabled: this.sending || this.takingScreenshot }, this.encodedScreenshot && (index.h("div", { class: "screenshot-preview", onClick: this.openCanvasEditor }, index.h("img", { src: this.encodedScreenshot, alt: "Screenshot Preview" }))), !this.encodedScreenshot && !this.takingScreenshot && (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24", viewBox: "0 -960 960 960", width: "24" }, index.h("path", { d: "M680-80v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-200v-200h80v120h120v80H200Zm0-360v-200h200v80H280v120h-80Zm480 0v-120H560v-80h200v200h-80Z" }))), this.takingScreenshot && (index.h("div", { class: "screenshot-loading" }, index.h("svg", { width: "16", height: "16", viewBox: "0 0 16 16" }, index.h("circle", { cx: "8", cy: "8", r: "6", fill: "none", stroke: "#666", "stroke-width": "2", "stroke-dasharray": "6 6", "transform-origin": "8 8" }, index.h("animateTransform", { attributeName: "transform", type: "rotate", values: "0 8 8;360 8 8", dur: "1s", repeatCount: "indefinite" }))))), this.takingScreenshot ? this.screenshotTakingText :
|
|
9897
|
+
this.encodedScreenshot ? this.screenshotAttachedText : this.screenshotButtonText)), index.h("button", { class: "feedback-modal-button feedback-modal-button--submit", type: "submit", disabled: this.sending }, this.sendButtonText)))) : this.formSuccess && !this.formError ? (index.h("div", { class: "feedback-modal-success" }, index.h("p", { class: "feedback-modal-message" }, this.successMessage))) : this.formError && this.formErrorStatus == 404 ? (index.h("p", { class: "feedback-modal-message" }, this.errorMessage404)) : this.formError && this.formErrorStatus == 403 ? (index.h("p", { class: "feedback-modal-message" }, this.errorMessage403)) : this.formError ? (index.h("p", { class: "feedback-modal-message" }, this.errorMessage)) : (index.h("span", null))), index.h("div", { class: "feedback-modal-footer" }, index.h("div", { class: "feedback-logo", style: { display: this.whitelabel ? 'none' : 'block' } }, "Powered by", ' ', index.h("a", { target: "_blank", href: "https://pushfeedback.com" }, "PushFeedback.com")), this.footerText && (index.h("div", { class: "feedback-footer-text" }, index.h("span", { innerHTML: this.footerText })))))), this.showCanvasEditor && (index.h("div", { class: "canvas-editor-overlay" }, index.h("div", { class: "canvas-editor-modal" }, index.h("div", { class: "canvas-editor-header" }, index.h("div", { class: "canvas-editor-title" }, index.h("h3", null, this.canvasEditorTitle)), index.h("div", { class: "canvas-editor-toolbar" }, index.h("div", { class: "toolbar-section" }, index.h("div", { class: "tool-group" }, index.h("button", { class: `tool-btn ${this.canvasDrawingTool === 'rectangle' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'rectangle', title: "Rectangle" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }))), index.h("button", { class: `tool-btn ${this.canvasDrawingTool === 'line' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'line', title: "Line" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("line", { x1: "5", y1: "12", x2: "19", y2: "12" }))), index.h("button", { class: `tool-btn ${this.canvasDrawingTool === 'arrow' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'arrow', title: "Arrow" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("line", { x1: "7", y1: "17", x2: "17", y2: "7" }), index.h("polyline", { points: "7,7 17,7 17,17" }))), index.h("button", { class: `tool-btn ${this.canvasDrawingTool === 'text' ? 'active' : ''}`, onClick: () => this.canvasDrawingTool = 'text', title: "Text" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("polyline", { points: "4,7 4,4 20,4 20,7" }), index.h("line", { x1: "9", y1: "20", x2: "15", y2: "20" }), index.h("line", { x1: "12", y1: "4", x2: "12", y2: "20" }))), index.h("div", { class: "toolbar-divider" }), index.h("button", { class: "tool-btn undo-btn", onClick: this.undoLastAnnotation, disabled: this.annotations.length === 0, title: "Undo" }, index.h("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, index.h("polyline", { points: "1,4 1,10 7,10" }), index.h("path", { d: "M3.51,15a9,9,0,0,0,14.85-3.36,9,9,0,0,0-9.19-10.15L1.83,10" }))))), index.h("div", { class: "toolbar-section" }, index.h("div", { class: "color-palette" }, this.defaultColors.map((color, index$1) => (index.h("div", { class: "color-slot-wrapper" }, index.h("button", { class: `color-btn ${this.canvasDrawingColor === color ? 'active' : ''} ${this.editingColorIndex === index$1 ? 'editing' : ''}`, style: { backgroundColor: color }, onClick: () => this.handleColorSlotClick(index$1), title: `Color ${index$1 + 1} - Click to customize` }, this.editingColorIndex === index$1 && (index.h("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "white", "stroke-width": "2" }, index.h("path", { d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" })))), this.editingColorIndex === index$1 && this.showColorPicker && (index.h("div", { class: "color-picker-dropdown" }, index.h("input", { type: "color", value: color, onInput: (e) => this.handleColorPickerInput(e), onClick: (e) => this.handleColorPickerClick(e) })))))))), index.h("div", { class: "toolbar-section" }, index.h("div", { class: "size-control" }, index.h("input", { type: "range", min: "1", max: "10", value: this.canvasLineWidth, onInput: (e) => this.canvasLineWidth = parseInt(e.target.value), class: "size-slider" }), index.h("span", { class: "size-value" }, this.canvasLineWidth, "px"))), index.h("div", { class: "toolbar-section" }, index.h("button", { class: "action-btn secondary", onClick: this.closeCanvasEditor }, this.canvasEditorCancelText), index.h("button", { class: "action-btn primary", onClick: this.saveAnnotations }, this.canvasEditorSaveText))), index.h("div", { class: "canvas-editor-content" }, index.h("canvas", { ref: (el) => this.canvasRef = el, class: "annotation-canvas", onMouseDown: this.handleCanvasMouseDown, onMouseMove: this.handleCanvasMouseMove, onMouseUp: this.handleCanvasMouseUp, onMouseLeave: this.handleCanvasMouseUp }))))))));
|
|
9360
9898
|
}
|
|
9361
9899
|
componentDidRender() {
|
|
9362
9900
|
if (this.showModal) {
|