@zoho_apptics/apptics-js-sdk 1.0.2 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/LICENSE +13 -0
  3. package/README.md +846 -11
  4. package/dist/apptics.esm.min.js +3 -0
  5. package/dist/apptics.esm.min.js.map +1 -0
  6. package/dist/apptics.min.js +3 -0
  7. package/dist/apptics.min.js.map +1 -0
  8. package/dist/chunks/lifecycle-VYr43KcB.min.js +3 -0
  9. package/dist/chunks/lifecycle-VYr43KcB.min.js.map +1 -0
  10. package/dist/cjs/auto-init.d.ts +8 -0
  11. package/dist/cjs/auto-init.js +32 -0
  12. package/dist/cjs/core/attempts.d.ts +28 -0
  13. package/dist/cjs/core/attempts.js +113 -0
  14. package/dist/cjs/core/batch.d.ts +32 -0
  15. package/dist/cjs/core/batch.js +116 -0
  16. package/dist/cjs/core/callsite.d.ts +34 -0
  17. package/dist/cjs/core/callsite.js +115 -0
  18. package/dist/cjs/core/consent.d.ts +27 -0
  19. package/dist/cjs/core/consent.js +132 -0
  20. package/dist/cjs/core/constants.d.ts +237 -0
  21. package/dist/cjs/core/constants.js +315 -0
  22. package/dist/cjs/core/db.d.ts +48 -0
  23. package/dist/cjs/core/db.js +467 -0
  24. package/dist/cjs/core/debug.d.ts +22 -0
  25. package/dist/cjs/core/debug.js +88 -0
  26. package/dist/cjs/core/env.d.ts +28 -0
  27. package/dist/cjs/core/env.js +267 -0
  28. package/dist/cjs/core/framework-id.d.ts +1 -0
  29. package/dist/cjs/core/framework-id.js +9 -0
  30. package/dist/cjs/core/guard.d.ts +11 -0
  31. package/dist/cjs/core/guard.js +86 -0
  32. package/dist/cjs/core/hooks.d.ts +39 -0
  33. package/dist/cjs/core/hooks.js +22 -0
  34. package/dist/cjs/core/locks.d.ts +9 -0
  35. package/dist/cjs/core/locks.js +22 -0
  36. package/dist/cjs/core/logger.d.ts +15 -0
  37. package/dist/cjs/core/logger.js +50 -0
  38. package/dist/cjs/core/state.d.ts +70 -0
  39. package/dist/cjs/core/state.js +78 -0
  40. package/dist/cjs/core/storage.d.ts +61 -0
  41. package/dist/cjs/core/storage.js +327 -0
  42. package/dist/cjs/core/stylesheet.d.ts +8 -0
  43. package/dist/cjs/core/stylesheet.js +29 -0
  44. package/dist/cjs/core/transport.d.ts +85 -0
  45. package/dist/cjs/core/transport.js +456 -0
  46. package/dist/cjs/core/utils.d.ts +26 -0
  47. package/dist/cjs/core/utils.js +175 -0
  48. package/dist/cjs/core/validate.d.ts +18 -0
  49. package/dist/cjs/core/validate.js +233 -0
  50. package/dist/cjs/device/appversion.d.ts +15 -0
  51. package/dist/cjs/device/appversion.js +170 -0
  52. package/dist/cjs/device/index.d.ts +34 -0
  53. package/dist/cjs/device/index.js +472 -0
  54. package/dist/cjs/engagement/api-rules.d.ts +49 -0
  55. package/dist/cjs/engagement/api-rules.js +206 -0
  56. package/dist/cjs/engagement/auto-api.d.ts +7 -0
  57. package/dist/cjs/engagement/auto-api.js +200 -0
  58. package/dist/cjs/engagement/auto-screen.d.ts +18 -0
  59. package/dist/cjs/engagement/auto-screen.js +305 -0
  60. package/dist/cjs/engagement/defined-events.d.ts +23 -0
  61. package/dist/cjs/engagement/defined-events.js +58 -0
  62. package/dist/cjs/engagement/send.d.ts +6 -0
  63. package/dist/cjs/engagement/send.js +104 -0
  64. package/dist/cjs/engagement/session.d.ts +51 -0
  65. package/dist/cjs/engagement/session.js +463 -0
  66. package/dist/cjs/engagement/track.d.ts +56 -0
  67. package/dist/cjs/engagement/track.js +375 -0
  68. package/dist/cjs/errors/send.d.ts +6 -0
  69. package/dist/cjs/errors/send.js +73 -0
  70. package/dist/cjs/errors/track.d.ts +4 -0
  71. package/dist/cjs/errors/track.js +167 -0
  72. package/dist/cjs/feedback/controls.d.ts +37 -0
  73. package/dist/cjs/feedback/controls.js +316 -0
  74. package/dist/cjs/feedback/index.d.ts +9 -0
  75. package/dist/cjs/feedback/index.js +56 -0
  76. package/dist/cjs/feedback/logs.d.ts +45 -0
  77. package/dist/cjs/feedback/logs.js +241 -0
  78. package/dist/cjs/feedback/quartz.d.ts +18 -0
  79. package/dist/cjs/feedback/quartz.js +105 -0
  80. package/dist/cjs/feedback/send.d.ts +28 -0
  81. package/dist/cjs/feedback/send.js +203 -0
  82. package/dist/cjs/feedback/styles.d.ts +10 -0
  83. package/dist/cjs/feedback/styles.js +8 -0
  84. package/dist/cjs/feedback/template.d.ts +2 -0
  85. package/dist/cjs/feedback/template.js +162 -0
  86. package/dist/cjs/feedback/ui.d.ts +63 -0
  87. package/dist/cjs/feedback/ui.js +709 -0
  88. package/dist/cjs/heatmap/send.d.ts +13 -0
  89. package/dist/cjs/heatmap/send.js +82 -0
  90. package/dist/cjs/heatmap/track.d.ts +4 -0
  91. package/dist/cjs/heatmap/track.js +448 -0
  92. package/dist/cjs/index.d.ts +22 -0
  93. package/dist/cjs/index.js +162 -0
  94. package/dist/cjs/lifecycle.d.ts +21 -0
  95. package/dist/cjs/lifecycle.js +734 -0
  96. package/dist/cjs/package.json +3 -0
  97. package/dist/cjs/remoteconfig/country.d.ts +4 -0
  98. package/dist/cjs/remoteconfig/country.js +73 -0
  99. package/dist/cjs/remoteconfig/custom.d.ts +10 -0
  100. package/dist/cjs/remoteconfig/custom.js +58 -0
  101. package/dist/cjs/remoteconfig/evaluate.d.ts +24 -0
  102. package/dist/cjs/remoteconfig/evaluate.js +184 -0
  103. package/dist/cjs/remoteconfig/fetch.d.ts +24 -0
  104. package/dist/cjs/remoteconfig/fetch.js +200 -0
  105. package/dist/cjs/remoteconfig/index.d.ts +15 -0
  106. package/dist/cjs/remoteconfig/index.js +116 -0
  107. package/dist/cjs/remoteconfig/store.d.ts +18 -0
  108. package/dist/cjs/remoteconfig/store.js +98 -0
  109. package/dist/cjs/remoteconfig/tz-countries.d.ts +8 -0
  110. package/dist/cjs/remoteconfig/tz-countries.js +13 -0
  111. package/dist/cjs/remotelog/gate.d.ts +2 -0
  112. package/dist/cjs/remotelog/gate.js +28 -0
  113. package/dist/cjs/remotelog/index.d.ts +8 -0
  114. package/dist/cjs/remotelog/logger.d.ts +22 -0
  115. package/dist/cjs/remotelog/logger.js +111 -0
  116. package/dist/cjs/remotelog/send.d.ts +13 -0
  117. package/dist/cjs/remotelog/send.js +153 -0
  118. package/dist/cjs/remotelogger/index.d.ts +12 -0
  119. package/dist/cjs/remotelogger/index.js +18 -0
  120. package/dist/cjs/scheduler.d.ts +8 -0
  121. package/dist/cjs/scheduler.js +78 -0
  122. package/dist/cjs/types.d.ts +385 -0
  123. package/dist/cjs/user/index.d.ts +33 -0
  124. package/dist/cjs/user/index.js +183 -0
  125. package/dist/esm/auto-init.d.ts +8 -0
  126. package/dist/esm/auto-init.js +29 -0
  127. package/dist/esm/core/attempts.d.ts +28 -0
  128. package/dist/esm/core/attempts.js +106 -0
  129. package/dist/esm/core/batch.d.ts +32 -0
  130. package/dist/esm/core/batch.js +109 -0
  131. package/dist/esm/core/callsite.d.ts +34 -0
  132. package/dist/esm/core/callsite.js +110 -0
  133. package/dist/esm/core/consent.d.ts +27 -0
  134. package/dist/esm/core/consent.js +122 -0
  135. package/dist/esm/core/constants.d.ts +237 -0
  136. package/dist/esm/core/constants.js +292 -0
  137. package/dist/esm/core/db.d.ts +48 -0
  138. package/dist/esm/core/db.js +453 -0
  139. package/dist/esm/core/debug.d.ts +22 -0
  140. package/dist/esm/core/debug.js +81 -0
  141. package/dist/esm/core/env.d.ts +28 -0
  142. package/dist/esm/core/env.js +251 -0
  143. package/dist/esm/core/framework-id.d.ts +1 -0
  144. package/dist/esm/core/framework-id.js +7 -0
  145. package/dist/esm/core/guard.d.ts +11 -0
  146. package/dist/esm/core/guard.js +83 -0
  147. package/dist/esm/core/hooks.d.ts +39 -0
  148. package/dist/esm/core/hooks.js +20 -0
  149. package/dist/esm/core/locks.d.ts +9 -0
  150. package/dist/esm/core/locks.js +20 -0
  151. package/dist/esm/core/logger.d.ts +15 -0
  152. package/dist/esm/core/logger.js +46 -0
  153. package/dist/esm/core/state.d.ts +70 -0
  154. package/dist/esm/core/state.js +73 -0
  155. package/dist/esm/core/storage.d.ts +61 -0
  156. package/dist/esm/core/storage.js +314 -0
  157. package/dist/esm/core/stylesheet.d.ts +8 -0
  158. package/dist/esm/core/stylesheet.js +27 -0
  159. package/dist/esm/core/transport.d.ts +85 -0
  160. package/dist/esm/core/transport.js +439 -0
  161. package/dist/esm/core/utils.d.ts +26 -0
  162. package/dist/esm/core/utils.js +161 -0
  163. package/dist/esm/core/validate.d.ts +18 -0
  164. package/dist/esm/core/validate.js +226 -0
  165. package/dist/esm/device/appversion.d.ts +15 -0
  166. package/dist/esm/device/appversion.js +164 -0
  167. package/dist/esm/device/index.d.ts +34 -0
  168. package/dist/esm/device/index.js +461 -0
  169. package/dist/esm/engagement/api-rules.d.ts +49 -0
  170. package/dist/esm/engagement/api-rules.js +199 -0
  171. package/dist/esm/engagement/auto-api.d.ts +7 -0
  172. package/dist/esm/engagement/auto-api.js +198 -0
  173. package/dist/esm/engagement/auto-screen.d.ts +18 -0
  174. package/dist/esm/engagement/auto-screen.js +301 -0
  175. package/dist/esm/engagement/defined-events.d.ts +23 -0
  176. package/dist/esm/engagement/defined-events.js +55 -0
  177. package/dist/esm/engagement/send.d.ts +6 -0
  178. package/dist/esm/engagement/send.js +101 -0
  179. package/dist/esm/engagement/session.d.ts +51 -0
  180. package/dist/esm/engagement/session.js +448 -0
  181. package/dist/esm/engagement/track.d.ts +56 -0
  182. package/dist/esm/engagement/track.js +365 -0
  183. package/dist/esm/errors/send.d.ts +6 -0
  184. package/dist/esm/errors/send.js +70 -0
  185. package/dist/esm/errors/track.d.ts +4 -0
  186. package/dist/esm/errors/track.js +163 -0
  187. package/dist/esm/feedback/controls.d.ts +37 -0
  188. package/dist/esm/feedback/controls.js +309 -0
  189. package/dist/esm/feedback/index.d.ts +9 -0
  190. package/dist/esm/feedback/index.js +51 -0
  191. package/dist/esm/feedback/logs.d.ts +45 -0
  192. package/dist/esm/feedback/logs.js +227 -0
  193. package/dist/esm/feedback/quartz.d.ts +18 -0
  194. package/dist/esm/feedback/quartz.js +99 -0
  195. package/dist/esm/feedback/send.d.ts +28 -0
  196. package/dist/esm/feedback/send.js +198 -0
  197. package/dist/esm/feedback/styles.d.ts +10 -0
  198. package/dist/esm/feedback/styles.js +4 -0
  199. package/dist/esm/feedback/template.d.ts +2 -0
  200. package/dist/esm/feedback/template.js +159 -0
  201. package/dist/esm/feedback/ui.d.ts +63 -0
  202. package/dist/esm/feedback/ui.js +703 -0
  203. package/dist/esm/heatmap/send.d.ts +13 -0
  204. package/dist/esm/heatmap/send.js +79 -0
  205. package/dist/esm/heatmap/track.d.ts +4 -0
  206. package/dist/esm/heatmap/track.js +445 -0
  207. package/dist/esm/index.d.ts +22 -0
  208. package/dist/esm/index.js +150 -0
  209. package/dist/esm/lifecycle.d.ts +21 -0
  210. package/dist/esm/lifecycle.js +729 -0
  211. package/dist/esm/package.json +3 -0
  212. package/dist/esm/remoteconfig/country.d.ts +4 -0
  213. package/dist/esm/remoteconfig/country.js +70 -0
  214. package/dist/esm/remoteconfig/custom.d.ts +10 -0
  215. package/dist/esm/remoteconfig/custom.js +54 -0
  216. package/dist/esm/remoteconfig/evaluate.d.ts +24 -0
  217. package/dist/esm/remoteconfig/evaluate.js +179 -0
  218. package/dist/esm/remoteconfig/fetch.d.ts +24 -0
  219. package/dist/esm/remoteconfig/fetch.js +196 -0
  220. package/dist/esm/remoteconfig/index.d.ts +15 -0
  221. package/dist/esm/remoteconfig/index.js +111 -0
  222. package/dist/esm/remoteconfig/store.d.ts +18 -0
  223. package/dist/esm/remoteconfig/store.js +91 -0
  224. package/dist/esm/remoteconfig/tz-countries.d.ts +8 -0
  225. package/dist/esm/remoteconfig/tz-countries.js +11 -0
  226. package/dist/esm/remotelog/gate.d.ts +2 -0
  227. package/dist/esm/remotelog/gate.js +26 -0
  228. package/dist/esm/remotelog/index.d.ts +8 -0
  229. package/dist/esm/remotelog/logger.d.ts +22 -0
  230. package/dist/esm/remotelog/logger.js +108 -0
  231. package/dist/esm/remotelog/send.d.ts +13 -0
  232. package/dist/esm/remotelog/send.js +149 -0
  233. package/dist/esm/remotelogger/index.d.ts +12 -0
  234. package/dist/esm/remotelogger/index.js +13 -0
  235. package/dist/esm/scheduler.d.ts +8 -0
  236. package/dist/esm/scheduler.js +74 -0
  237. package/dist/esm/types.d.ts +385 -0
  238. package/dist/esm/user/index.d.ts +33 -0
  239. package/dist/esm/user/index.js +176 -0
  240. package/dist/feedback.esm.min.js +3 -0
  241. package/dist/feedback.esm.min.js.map +1 -0
  242. package/package.json +122 -7
  243. package/src/appticssdk.js +0 -1
@@ -0,0 +1,709 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ 'use strict';
3
+
4
+ var constants = require('../core/constants.js');
5
+ var state = require('../core/state.js');
6
+ var logger = require('../core/logger.js');
7
+ var utils = require('../core/utils.js');
8
+ var consent = require('../core/consent.js');
9
+ var template = require('./template.js');
10
+ var send = require('./send.js');
11
+ var controls = require('./controls.js');
12
+ var stylesheet = require('../core/stylesheet.js');
13
+ var quartz$1 = require('./quartz.js');
14
+ var styles = require('./styles.js');
15
+
16
+ // Quartz is an optional page-level SDK. Without it every call is a no-op (fix #5).
17
+ const QUARTZ_NOOP = {
18
+ startRecording() { },
19
+ previewVideo() { },
20
+ editVideo() { },
21
+ clearFeedback() { },
22
+ endRecording() { },
23
+ setVideoContent() { },
24
+ submitRecording() { return Promise.resolve({}); }
25
+ };
26
+ const QUARTZ_CONSTANTS_NOOP = { ErrorType: {}, FeedbackState: {} };
27
+ function hasQuartz() {
28
+ return typeof Quartz !== 'undefined' && !!Quartz; // no i18n
29
+ }
30
+ function quartz() {
31
+ return typeof Quartz !== 'undefined' && Quartz ? Quartz : QUARTZ_NOOP; // no i18n
32
+ }
33
+ function quartzConstants() {
34
+ return typeof QuartzConstants !== 'undefined' && QuartzConstants ? QuartzConstants : QUARTZ_CONSTANTS_NOOP; // no i18n
35
+ }
36
+ /**
37
+ * Sends feedback and reflects the outcome in the modal (if open). Resolves with the outcome, or
38
+ * null when nothing was attempted (offline, or Apptics is disabled for this client).
39
+ */
40
+ function submitFeedback(dataobj) {
41
+ return send.sendFeedbackData(dataobj).then(function (result) {
42
+ if (!result) {
43
+ return null;
44
+ }
45
+ feedback.handleStatusmsg(result.ok, result.message);
46
+ if (result.ok) {
47
+ setTimeout(() => {
48
+ feedback.close();
49
+ }, 2000);
50
+ }
51
+ return result;
52
+ });
53
+ }
54
+ /** Whether a value is an options object: a plain object, not a type number or a message string. */
55
+ function isOptions(value) {
56
+ return value !== null && typeof value === 'object' && !Array.isArray(value); // no i18n
57
+ }
58
+ /** Said once: the old one-argument-after-another form of feedbackFormOpen. */
59
+ var saidOpenForm = false;
60
+ function sendFeedback(options) {
61
+ if (options !== undefined && !isOptions(options)) {
62
+ // the old form, sendFeedback(type, message, ...): sending it as it stands would send an
63
+ // empty report, so it is refused, and says what to pass instead
64
+ return Promise.reject(new Error('AppticsFeedback.sendFeedback: takes one options object, as sendFeedback({ type, message, attachments, logFiles, includeDiagnostics, includeLog, isAnonymous })')); // no i18n
65
+ }
66
+ const o = options || {};
67
+ const dataobj = {
68
+ type: !utils.isEmpty(o.type) ? o.type : 1,
69
+ message: o.message || '', // no i18n
70
+ attachment: o.attachments || null,
71
+ logsFiles: o.logFiles || null,
72
+ // both flags stay as given: unset lets send.ts decide from what is actually stored
73
+ includeDyninfo: o.includeDiagnostics,
74
+ includeLog: o.includeLog,
75
+ quartzid: '' // no i18n
76
+ };
77
+ // from the active user, or from nobody with isAnonymous; the form's own choice is put back after
78
+ var restoreUser = controls.chooseUserForSend(o.isAnonymous === true);
79
+ // an app awaiting this must be able to tell its user the feedback did not go: resolving on a
80
+ // failure would have it say "thanks, sent" for a report the server never received
81
+ return submitFeedback(dataobj).then(function (result) {
82
+ restoreUser();
83
+ return result;
84
+ }, function (err) {
85
+ restoreUser();
86
+ throw err;
87
+ }).then(function (result) {
88
+ if (!result) {
89
+ throw new Error('AppticsFeedback.sendFeedback: not sent, the browser is offline or Apptics is disabled for this client'); // no i18n
90
+ }
91
+ if (!result.ok) {
92
+ throw new Error('AppticsFeedback.sendFeedback: not sent, ' + result.message); // no i18n
93
+ }
94
+ });
95
+ }
96
+ /**
97
+ * The request both submit buttons send. A recording only adds its quartzid; everything else — the
98
+ * chosen type, the attachments, the log and diagnostics toggles — is read the same way, so one
99
+ * builder keeps the recording path from quietly falling behind the plain one.
100
+ */
101
+ function buildFeedbackRequest(modal, message, quartzid) {
102
+ var seltype = modal.querySelector('.zasdk-selected').getAttribute('data-type'); // no i18n
103
+ var fileInput = modal.querySelector("#zasdkFileInput"); // no i18n
104
+ var files = fileInput.files;
105
+ return {
106
+ type: !utils.isEmpty(seltype) ? feedback.typeObj[seltype] : 1,
107
+ message: message,
108
+ attachment: (files && files.length > 0) ? files : (feedback._opts.attachments || null),
109
+ logsFiles: feedback._opts.logFiles || null,
110
+ includeLog: controls.logChoice.includeLog,
111
+ includeDyninfo: controls.logChoice.includeDyninfo,
112
+ quartzid: quartzid
113
+ };
114
+ }
115
+ /**
116
+ * Opens the form, optionally pre-filled. `isAnonymous` starts the user picker on Anonymous even
117
+ * when a user is registered; the include flags start their toggles on.
118
+ */
119
+ /**
120
+ * A DataTransfer to hold the chosen attachments, or null where one cannot be made.
121
+ *
122
+ * It is the only way to build a FileList, which is what an <input type="file"> will accept back,
123
+ * so the attachment list is kept in one. The constructor is newer than the rest of the modal -
124
+ * Safari only gained it in 14.1 - and a plain `new DataTransfer()` throws on anything older,
125
+ * which took the whole form down with it on open. Feedback without attachments is worth far more
126
+ * than no feedback at all, so the form opens either way and the file input is left alone.
127
+ */
128
+ function newTransfer() {
129
+ try {
130
+ return typeof DataTransfer === 'function' ? new DataTransfer() : null; // no i18n
131
+ }
132
+ catch (err) {
133
+ logger.Console.warn('apptics.feedback: this browser cannot build a file list, attachments are off'); // no i18n
134
+ return null;
135
+ }
136
+ }
137
+ function feedbackFormOpen(options) {
138
+ if (options !== undefined && !isOptions(options) && !saidOpenForm) {
139
+ // the old form, feedbackFormOpen(type, message, ...): the form still opens, with its defaults
140
+ saidOpenForm = true;
141
+ logger.warnAlways('AppticsFeedback.feedbackFormOpen: takes one options object, as feedbackFormOpen({ type, message, includeLog, includeDiagnostics, attachments, logFiles, isAnonymous }); opening it with its defaults'); // no i18n
142
+ }
143
+ const o = isOptions(options) ? options : {};
144
+ const opts = {
145
+ includeLog: o.includeLog === true,
146
+ includeDyninfo: o.includeDiagnostics === true,
147
+ isAnonymous: o.isAnonymous === true,
148
+ };
149
+ if (typeof o.type === 'number')
150
+ opts.type = o.type; // no i18n
151
+ if (typeof o.message === 'string' && o.message.length > 0)
152
+ opts.message = o.message; // no i18n
153
+ if (o.attachments && o.attachments.length > 0)
154
+ opts.attachments = o.attachments;
155
+ if (o.logFiles && o.logFiles.length > 0)
156
+ opts.logFiles = o.logFiles;
157
+ // the form brings its own styles, so an app imports or links no css
158
+ stylesheet.injectStylesheet(styles.default);
159
+ feedback.init(opts);
160
+ }
161
+ /** The themes the form has: 'auto' follows the visitor's system setting. */
162
+ const FEEDBACK_THEMES = ['light', 'dark', 'auto']; // no i18n
163
+ /**
164
+ * Sets the form's theme, for a page with its own light and dark modes: 'auto' follows the
165
+ * operating system, which is not what such a page shows. Restyles a form or recording timer that
166
+ * is open now, and every one opened after; Apptics.init()'s feedback_theme only sets the first.
167
+ */
168
+ function setFeedbackTheme(theme) {
169
+ if (FEEDBACK_THEMES.indexOf(theme) === -1) {
170
+ logger.Console.warn('AppticsFeedback.setFeedbackTheme: takes \'light\', \'dark\' or \'auto\', not ' + JSON.stringify(theme)); // no i18n
171
+ return;
172
+ }
173
+ state._ZAP._config.feedback_theme = theme;
174
+ if (typeof document === 'undefined') { // no i18n
175
+ return;
176
+ }
177
+ ['zasdkFeedbackModal', 'zasdkrectimer'].forEach(function (id) {
178
+ var open = document.getElementById(id);
179
+ if (open) {
180
+ open.setAttribute('data-zasdk-theme', theme); // no i18n
181
+ }
182
+ });
183
+ }
184
+ function feedbackFormClose() {
185
+ feedback.close();
186
+ }
187
+ const feedback = {
188
+ feedbackUIHtml: template.feedbackUIHtml,
189
+ timerHtml: template.timerHtml,
190
+ uploadFileAry: [],
191
+ fileInput: null,
192
+ selectedFiles: null,
193
+ isScaled: false,
194
+ isHidden: false,
195
+ timerDisplay: null,
196
+ recordButton: null,
197
+ TOTAL_TIME: 5 * 60,
198
+ remainingTime: 5 * 60,
199
+ isRecording: false,
200
+ timerInterval: null,
201
+ uploadTotalSize: 0,
202
+ MaxFileSize: 10 * 1024 * 1024,
203
+ _opts: {},
204
+ typeObj: { 'bug': 0, 'feedback': 1, 'help': 2, 'report': 3 }, // no i18n
205
+ init: function (opts) {
206
+ feedback._opts = opts || {};
207
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
208
+ if (!utils.isEmpty(modal)) {
209
+ return;
210
+ }
211
+ const tempContainer = document.createElement('div'); // no i18n
212
+ feedback.uploadFileAry = [];
213
+ tempContainer.id = 'zasdkFeedbackModal'; // no i18n
214
+ tempContainer.className = 'zasdk-modal'; // no i18n
215
+ tempContainer.setAttribute('data-zasdk-theme', state._ZAP._config.feedback_theme); // no i18n
216
+ tempContainer.innerHTML = feedback.feedbackUIHtml;
217
+ document.body.appendChild(tempContainer);
218
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
219
+ // screen recording as the console set it up for this app (getsdkconfig's quartz block)
220
+ var qz = state._ZAP._quartz;
221
+ var qz_ws_key = qz.workspace;
222
+ var qz_dp_key = qz.department;
223
+ var qz_dc_key = quartz$1.recordingDomain(qz.domain);
224
+ var closeBtn = modal.querySelector("#appticsfeedbackclose"); // no i18n
225
+ var feedbackTypes = modal.querySelectorAll(".zasdk-feedback-type"); // no i18n
226
+ feedback.fileInput = modal.querySelector("#zasdkFileInput"); // no i18n
227
+ var quartzrecbtn = modal.querySelector("#zasdkqz_rec_button"); // no i18n
228
+ var submitbtn = modal.querySelector("#zasdk_submit_btn"); // no i18n
229
+ var submitbtncnt = modal.querySelector("#zasdk_submit_btnsubcnt"); // no i18n
230
+ const checkbox = modal.querySelector('#zasdkqz-consent'); // no i18n
231
+ const content = modal.querySelector('#zasdkqz-content'); // no i18n
232
+ const preivewButton = modal.querySelector('#preivewPlayButton'); // no i18n
233
+ const videoEditButton = modal.querySelector('#videoEditButton'); // no i18n
234
+ const deleteVideoButton = modal.querySelector('#videoDelButton'); // no i18n
235
+ const feedbackbox = modal.querySelector('#zasdkFeedbackconatiner'); // no i18n
236
+ const descriptionField = modal.querySelector('#zasdkDescription'); // no i18n
237
+ controls.wireDrag(feedbackbox);
238
+ controls.wireUserPicker(modal, feedback._opts.isAnonymous === true);
239
+ controls.wireLogControls(modal, feedback._opts);
240
+ feedback.isScaled = false;
241
+ feedback.isHidden = false;
242
+ document.removeEventListener('quartz-feedback-state', feedback.bindQuartzEvent); // no i18n
243
+ document.addEventListener('quartz-feedback-state', feedback.bindQuartzEvent); // no i18n
244
+ document.removeEventListener('quartz-feedback-error', feedback.handleErrorQuartzEvent); // no i18n
245
+ document.addEventListener('quartz-feedback-error', feedback.handleErrorQuartzEvent); // no i18n
246
+ // the consent checkbox and its label only when a recording can actually be made: recording
247
+ // on for the app, its workspace, department and domain, and Quartz on the page. A checkbox
248
+ // that leads only to "unavailable" is not offered. Quartz is loaded here, the first time
249
+ // the form needs it, and the checkbox shows once it has arrived
250
+ var recordingConfigured = qz.enabled && !utils.isEmpty(qz_dc_key) && !utils.isEmpty(qz_ws_key) && !utils.isEmpty(qz_dp_key);
251
+ var recordingBlock = modal.querySelector("#zasdkreccheckcnt"); // no i18n
252
+ recordingBlock.style.display = recordingConfigured && hasQuartz() ? "block" : "none"; // no i18n
253
+ if (recordingConfigured && !hasQuartz()) {
254
+ // quartz_cdn_url, or Zoho's CDN for this serviceUrl when the answer carries none
255
+ quartz$1.loadQuartz(quartz$1.quartzScriptSource(qz.cdnUrl, String(state._ZAP._defaultoptions.serviceUrl || ''))).then(function (loaded) {
256
+ if (loaded && recordingBlock.isConnected) {
257
+ recordingBlock.style.display = "block"; // no i18n
258
+ }
259
+ });
260
+ }
261
+ feedbackbox.addEventListener('transitionend', function (event) {
262
+ if (event.propertyName === 'transform' && feedback.isScaled) { // no i18n
263
+ feedback.toggleWindowAnimation();
264
+ }
265
+ });
266
+ quartzrecbtn.onclick = function (e) {
267
+ e.stopImmediatePropagation();
268
+ let recordingDetails = {
269
+ workspaceLinkName: qz_ws_key,
270
+ departmentLinkName: qz_dp_key,
271
+ recordingDomain: qz_dc_key
272
+ };
273
+ feedback.handleStatusmsg();
274
+ // 1.x pressed on regardless and the button did nothing anyone could explain; the rest
275
+ // of the form still works, so say what is missing and leave it usable
276
+ if (!hasQuartz()) {
277
+ feedback.handleStatusmsg(false, 'Screen recording is unavailable on this page.'); // no i18n
278
+ return;
279
+ }
280
+ if (utils.isEmpty(qz_ws_key) || utils.isEmpty(qz_dp_key) || utils.isEmpty(qz_dc_key)) {
281
+ feedback.handleStatusmsg(false, 'Screen recording is not configured for this app.'); // no i18n
282
+ return;
283
+ }
284
+ quartz().startRecording(recordingDetails);
285
+ };
286
+ closeBtn.onclick = function () {
287
+ feedback.close();
288
+ };
289
+ // keyboard: Enter or Space on the close control, and Escape anywhere, close the form
290
+ closeBtn.onkeydown = function (e) {
291
+ if (e.key === 'Enter' || e.key === ' ') { // no i18n
292
+ e.preventDefault();
293
+ feedback.close();
294
+ }
295
+ };
296
+ document.addEventListener('keydown', feedback.onEscape); // no i18n
297
+ preivewButton.addEventListener('click', function () {
298
+ quartz().previewVideo();
299
+ });
300
+ videoEditButton.addEventListener('click', function () {
301
+ quartz().editVideo({ quartzBranding: false });
302
+ });
303
+ deleteVideoButton.addEventListener('click', function () {
304
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
305
+ quartz().clearFeedback();
306
+ checkbox.checked = false;
307
+ content.classList.remove('zasdkqz-show'); // no i18n
308
+ modal.querySelector("#editRecordedVideo").style.display = "none"; // no i18n
309
+ modal.querySelector("#zasdkreccheckcnt").style.display = "block"; // no i18n
310
+ feedback.validateFeedbackField();
311
+ });
312
+ submitbtn.addEventListener('click', async () => {
313
+ // Disable button and show loader
314
+ feedback.validateFeedbackField();
315
+ submitbtn.disabled = true;
316
+ submitbtncnt.classList.add('zasdkbtndisabled'); // no i18n
317
+ submitbtn.value = '';
318
+ try {
319
+ let videoElement = modal.querySelector('#previewVideoElemId'), // no i18n
320
+ videoVisible = videoElement && videoElement.offsetParent !== null;
321
+ if (videoVisible) {
322
+ feedback.submitRecording();
323
+ }
324
+ else {
325
+ let message = modal.querySelector('#zasdkDescription').value.trim(); // no i18n
326
+ if (message.length > 0) {
327
+ submitFeedback(buildFeedbackRequest(modal, message, '')); // no i18n
328
+ }
329
+ else {
330
+ feedback.handleStatusmsg(false, 'Please provide more details for us to help you better.'); // no i18n
331
+ }
332
+ }
333
+ }
334
+ catch (error) {
335
+ logger.Console.error("sendFeedbackData : " + error); // no i18n
336
+ }
337
+ });
338
+ checkbox.addEventListener('change', function () {
339
+ if (this.checked) {
340
+ content.classList.add('zasdkqz-show'); // no i18n
341
+ }
342
+ else {
343
+ content.classList.remove('zasdkqz-show'); // no i18n
344
+ }
345
+ });
346
+ descriptionField.addEventListener('input', feedback.validateFeedbackField); // no i18n
347
+ // keyboard and screen-reader users land in the form, not behind it
348
+ try {
349
+ descriptionField.focus({ preventScroll: true });
350
+ }
351
+ catch (err) { /* focus is a courtesy */ }
352
+ feedbackTypes.forEach(function (type) {
353
+ type.addEventListener("click", function () {
354
+ feedbackTypes.forEach(function (t) {
355
+ t.classList.remove("zasdk-selected"); // no i18n
356
+ });
357
+ this.classList.add("zasdk-selected"); // no i18n
358
+ });
359
+ });
360
+ // what feedbackFormOpen() was given: select that type, fill the description
361
+ if (typeof feedback._opts.type === 'number') { // no i18n
362
+ var wanted = Object.keys(feedback.typeObj).filter(function (name) {
363
+ return feedback.typeObj[name] === feedback._opts.type;
364
+ })[0];
365
+ var wantedTab = wanted ? modal.querySelector('.zasdk-feedback-type[data-type="' + wanted + '"]') : null; // no i18n
366
+ if (wantedTab) {
367
+ feedbackTypes.forEach(function (t) { t.classList.remove("zasdk-selected"); }); // no i18n
368
+ wantedTab.classList.add("zasdk-selected"); // no i18n
369
+ }
370
+ }
371
+ if (!utils.isEmpty(feedback._opts.message)) {
372
+ descriptionField.value = String(feedback._opts.message);
373
+ feedback.updateLeftCount();
374
+ feedback.validateFeedbackField();
375
+ }
376
+ feedback.selectedFiles = newTransfer();
377
+ feedback.fileInput.onchange = function () {
378
+ const self = this;
379
+ var chosen = feedback.selectedFiles;
380
+ if (chosen === null) {
381
+ return; // no file list on this browser; see newTransfer()
382
+ }
383
+ if (chosen.files.length + self.files.length > 5) {
384
+ feedback.handleStatusmsg(false, 'Maximum 5 attachments is allowed'); // no i18n
385
+ feedback.fileInput.files = chosen.files;
386
+ self.files = chosen.files;
387
+ return;
388
+ }
389
+ if (self.files.length > 0) {
390
+ let filesize = 0;
391
+ for (let file of self.files) {
392
+ filesize = filesize + file.size;
393
+ if (filesize > 10485760) {
394
+ feedback.handleStatusmsg(false, 'Maximum limit reached. The total file size cannot exceed 10MB.'); // no i18n
395
+ self.files = chosen.files;
396
+ return;
397
+ }
398
+ else {
399
+ chosen.items.add(file); // Add new files
400
+ }
401
+ }
402
+ self.files = chosen.files; // Update input with all files
403
+ feedback.fileAttachment(); // Update UI
404
+ }
405
+ else if (chosen.files.length > 0) {
406
+ // Restore previous files if the user cancels
407
+ self.files = chosen.files;
408
+ }
409
+ };
410
+ feedback.handleStatusmsg();
411
+ feedback.updateLeftCount();
412
+ },
413
+ updateLeftCount: function () {
414
+ document.querySelectorAll("[reqname]").forEach(function (elem) {
415
+ let val = elem.value;
416
+ let maxLength = parseInt(elem.getAttribute("maxlength") || '', 10); // no i18n
417
+ let counterElem = elem.parentElement ? elem.parentElement.querySelector(".zaleftcharcnt") : null; // no i18n
418
+ if (counterElem) {
419
+ counterElem.textContent = String(maxLength - val.length); // Update remaining count
420
+ var unit = counterElem.parentElement ? counterElem.parentElement.querySelector(".zaleftchartxt") : null; // no i18n
421
+ if (unit) {
422
+ unit.textContent = maxLength - val.length === 1 ? 'character left' : 'characters left'; // no i18n
423
+ }
424
+ }
425
+ });
426
+ },
427
+ handleStatusmsg: function (isSuccess, stsmsg) {
428
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
429
+ if (utils.isEmpty(modal)) {
430
+ return;
431
+ }
432
+ var stscnt = modal.querySelector("#zasdksubmitstatus"); // no i18n
433
+ var submitbtn = modal.querySelector("#zasdk_submit_btn"); // no i18n
434
+ var submitbtncnt = modal.querySelector("#zasdk_submit_btnsubcnt"); // no i18n
435
+ var successmsgclass = ''; // no i18n
436
+ var successmsg = ''; // no i18n
437
+ stscnt.style.display = "none"; // no i18n
438
+ if (!utils.isEmpty(isSuccess)) {
439
+ successmsgclass = isSuccess ? 'zasdkstssucs' : 'zasdkstserror'; // no i18n
440
+ successmsg = !utils.isEmpty(stsmsg) ? stsmsg : ''; // no i18n
441
+ stscnt.textContent = successmsg;
442
+ stscnt.classList.add(successmsgclass);
443
+ stscnt.style.display = "block"; // no i18n
444
+ submitbtncnt.classList.remove('zasdkbtndisabled'); // no i18n
445
+ submitbtn.disabled = false;
446
+ submitbtn.value = 'Send'; // no i18n
447
+ }
448
+ },
449
+ handleErrorQuartzEvent: function (event) {
450
+ let errorType = event.detail.error.name;
451
+ let errorMessage = event.detail.error.message;
452
+ if (errorType == quartzConstants().ErrorType.RECORDING_INTERRUPTED || errorType == quartzConstants().ErrorType.FEEDBACK_TIMEOUT) {
453
+ feedback.stopRecording();
454
+ }
455
+ feedback.handleStatusmsg(false, errorMessage);
456
+ },
457
+ bindQuartzEvent: function (event) {
458
+ let feedbackState = event.detail.feedbackState;
459
+ if (feedbackState == quartzConstants().FeedbackState.RECORDING_IN_PROGRESS) {
460
+ var feedbacktimer = document.getElementById("zasdkrectimer"); // no i18n
461
+ if (!utils.isEmpty(feedbacktimer)) {
462
+ feedbacktimer.remove();
463
+ }
464
+ const tempDiv = document.createElement("div"); // no i18n
465
+ tempDiv.innerHTML = feedback.timerHtml;
466
+ const node = tempDiv.firstElementChild;
467
+ node.setAttribute('data-zasdk-theme', state._ZAP._config.feedback_theme); // no i18n
468
+ document.body.appendChild(node);
469
+ var feedbacktimer = document.getElementById("zasdkrectimer"); // no i18n
470
+ feedback.timerDisplay = feedbacktimer.querySelector('#zasdkTimerDisplay'); // no i18n
471
+ feedback.recordButton = feedbacktimer;
472
+ feedback.TOTAL_TIME = 5 * 60; // 5 minutes in seconds
473
+ feedback.remainingTime = feedback.TOTAL_TIME;
474
+ feedback.isRecording = true;
475
+ feedback.recordButton.addEventListener('click', feedback.toggleRecording); // no i18n
476
+ feedback.startRecording();
477
+ feedback.toggleWindowAnimation();
478
+ }
479
+ },
480
+ onEscape: function (e) {
481
+ if (e.key === 'Escape') { // no i18n
482
+ feedback.close();
483
+ }
484
+ },
485
+ close: function () {
486
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
487
+ document.removeEventListener('keydown', feedback.onEscape); // no i18n
488
+ document.removeEventListener('quartz-feedback-state', feedback.bindQuartzEvent); // no i18n
489
+ quartz().clearFeedback();
490
+ if (!utils.isEmpty(modal)) {
491
+ modal.remove();
492
+ }
493
+ },
494
+ toggleWindowAnimation: function () {
495
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
496
+ const box = modal.querySelector('#zasdkFeedbackconatiner'); // no i18n
497
+ if (feedback.isHidden) {
498
+ modal.style.display = 'block'; // no i18n
499
+ setTimeout(() => {
500
+ box.style.transform = 'scale(1)'; // no i18n
501
+ feedback.validateFeedbackField();
502
+ }, 10);
503
+ feedback.isHidden = false;
504
+ feedback.isScaled = false;
505
+ }
506
+ else if (feedback.isScaled) {
507
+ modal.style.display = 'none'; // no i18n
508
+ feedback.isHidden = true;
509
+ }
510
+ else {
511
+ box.style.transform = 'scale(0)'; // no i18n
512
+ feedback.isScaled = true;
513
+ }
514
+ },
515
+ fileAttachment: function () {
516
+ var uploadedFiles = feedback.fileInput.files;
517
+ feedback.uploadTotalSize = 0;
518
+ feedback.MaxFileSize = 10 * 1024 * 1024; //10 MB
519
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
520
+ var sizeInfo = modal.querySelector("#zasdkfilesizeinfo"); // no i18n
521
+ var fileUl = modal.querySelector("#zasakfileList"); // no i18n
522
+ sizeInfo.textContent = ""; // no i18n
523
+ if ((uploadedFiles.length) > 5) {
524
+ feedback.fileLimitExceeded(false, true);
525
+ feedback.validateFeedbackField();
526
+ return;
527
+ }
528
+ fileUl.innerHTML = ''; // no i18n
529
+ if (uploadedFiles.length > 0) {
530
+ var totalSize = 0;
531
+ for (var i = 0; i < uploadedFiles.length; i++) {
532
+ var fileName = uploadedFiles[i].name;
533
+ var fName = fileName.substring(0, fileName.lastIndexOf('.')); // no i18n
534
+ var extension = fileName.substring(fileName.lastIndexOf('.') + 1); // no i18n
535
+ var bytes = uploadedFiles[i].size;
536
+ totalSize += bytes;
537
+ var fileLi = feedback.elementCreator("li"); // no i18n
538
+ fileLi.title = fileName;
539
+ var span1 = feedback.elementCreator("span"); // no i18n
540
+ span1.className = "zaskFdBckFlName"; // no i18n
541
+ span1.innerText = (fName.length > 10) ? fName.slice(0, 3) + "..." + fName.slice(-3) : fName; // no i18n
542
+ var span2 = feedback.elementCreator("span"); // no i18n
543
+ span2.innerText = "." + extension; // no i18n
544
+ var span3 = feedback.elementCreator("span"); // no i18n
545
+ span3.className = "zasdkFdBckFlCls"; // no i18n
546
+ span3.setAttribute("data-name", fileName); // no i18n
547
+ span3.innerHTML = "&times;"; // no i18N
548
+ fileLi.appendChild(span1);
549
+ fileLi.appendChild(span2);
550
+ fileLi.appendChild(span3);
551
+ fileUl.appendChild(fileLi);
552
+ }
553
+ var limitReached = totalSize > feedback.MaxFileSize;
554
+ feedback.fileLimitExceeded(limitReached);
555
+ sizeInfo.textContent = `${feedback.formatFileSize(totalSize)} Used / 10 MB`; // no i18n
556
+ const clearFile = modal.querySelectorAll('.zasdkFdBckFlCls'); // no i18n
557
+ Array.from(clearFile).forEach(function (element) {
558
+ element.addEventListener('click', function () {
559
+ feedback.handleStatusmsg();
560
+ feedback.removeFileFromList(this);
561
+ feedback.fileAttachment();
562
+ });
563
+ });
564
+ }
565
+ feedback.validateFeedbackField();
566
+ },
567
+ elementCreator: function (elType) {
568
+ return document.createElement(elType);
569
+ },
570
+ fileLimitExceeded: function (limitReached, filesLengthReached) {
571
+ var infoMsg = "";
572
+ if (filesLengthReached || limitReached) {
573
+ infoMsg = filesLengthReached ? 'Maximum 5 attachments is allowed' : 'Maximum limit reached. The total file size cannot exceed 10MB.'; // no i18n
574
+ }
575
+ feedback.handleStatusmsg(false, infoMsg);
576
+ },
577
+ removeFileFromList: function (elem) {
578
+ elem.getAttribute('data-name'); // no i18n
579
+ const listItem = elem.parentElement; // the <li> holding this file
580
+ // Find the index of the element in the file preview list
581
+ const indexToRemove = Array.from(listItem.parentElement.children).indexOf(listItem);
582
+ listItem.remove(); // Remove the file preview
583
+ let newFiles = newTransfer();
584
+ feedback.selectedFiles = newTransfer();
585
+ if (newFiles === null || feedback.selectedFiles === null) {
586
+ return; // no file list to rebuild; the preview row is already gone
587
+ }
588
+ for (let i = 0; i < feedback.fileInput.files.length; i++) {
589
+ if (i !== indexToRemove) {
590
+ newFiles.items.add(feedback.fileInput.files[i]);
591
+ feedback.selectedFiles.items.add(feedback.fileInput.files[i]);
592
+ }
593
+ }
594
+ feedback.fileInput.files = newFiles.files;
595
+ },
596
+ formatFileSize: function (bytes) {
597
+ if (bytes === 0)
598
+ return '0 KB'; // no i18n
599
+ const k = 1024;
600
+ const sizeInKB = bytes / k;
601
+ const sizeInMB = bytes / (k * k);
602
+ const sizeInGB = bytes / (k * k * k);
603
+ if (sizeInGB >= 1) {
604
+ return sizeInGB.toFixed(2) + ' GB'; // no i18n
605
+ }
606
+ else if (sizeInMB >= 1) {
607
+ return sizeInMB.toFixed(2) + ' MB'; // no i18n
608
+ }
609
+ else {
610
+ return sizeInKB.toFixed(2) + ' KB'; // no i18n
611
+ }
612
+ },
613
+ toggleRecording: function () {
614
+ feedback.isRecording = !feedback.isRecording;
615
+ if (feedback.isRecording) {
616
+ feedback.startRecording();
617
+ }
618
+ else {
619
+ feedback.stopRecording();
620
+ }
621
+ },
622
+ startRecording: function () {
623
+ if (!feedback.timerInterval) {
624
+ feedback.timerInterval = setInterval(feedback.updateTimer, 1000);
625
+ }
626
+ },
627
+ stopRecording: function () {
628
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
629
+ clearInterval(feedback.timerInterval || undefined);
630
+ feedback.timerInterval = null;
631
+ document.querySelector("#zasdkrectimer").remove(); // no i18n
632
+ feedback.toggleWindowAnimation();
633
+ modal.querySelector("#editRecordedVideo").style.display = "block"; // no i18n
634
+ modal.querySelector("#zasdkreccheckcnt").style.display = "none"; // no i18n
635
+ let videoElem = modal.querySelector('#previewVideoElemId'); // no i18n
636
+ quartz().endRecording();
637
+ quartz().setVideoContent(videoElem);
638
+ },
639
+ submitRecording: function () {
640
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
641
+ // the recording is filed for whoever the form's picker selected, falling back to the
642
+ // registered user; an anonymous report, a non-email id or a PII opt-out all send the
643
+ // placeholder instead, so Quartz never receives an address the user did not offer
644
+ let testEmail = 'user@example.com', // no i18n
645
+ testMessage = '-', picked = controls.userChoice.anonymous ? '' : String(controls.userChoice.userid || ''), // no i18n
646
+ active = !utils.isEmpty(state._ZAP._user_info.userid) ? String(state._ZAP._user_info.userid) : '', // no i18n
647
+ userEmail = !utils.isEmpty(picked) ? picked : active, subject = modal.querySelector('#zasdkDescription').value.trim() || testMessage, // no i18n
648
+ emailRegex = /^[\w]([\w\-\.\+\'=]*)@([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,22}$/;
649
+ userEmail = (emailRegex.test(userEmail) && consent.opt_in_status() == constants.AP_TRACKING_STATUS.USAGE_TRACKING_WITH_PII) ? userEmail : testEmail;
650
+ // Submit the recording
651
+ quartz().submitRecording({
652
+ email: userEmail,
653
+ subject: subject,
654
+ })
655
+ .then((response) => {
656
+ var zqrecid = !utils.isEmptyObj(response) && response && response.hasOwnProperty('feedbackLink') ? (response.feedbackLink || '') : ''; // no i18n
657
+ submitFeedback(buildFeedbackRequest(modal, subject, zqrecid));
658
+ })
659
+ .catch((error) => {
660
+ // the upload is Quartz's to do; if it fails, hand the form back rather than leaving
661
+ // the submit button spinning with nothing said
662
+ logger.Console.error("submitRecording : " + error); // no i18n
663
+ feedback.handleStatusmsg(false, 'Could not upload the recording. Please try again.'); // no i18n
664
+ });
665
+ },
666
+ updateTimer: function () {
667
+ if (feedback.remainingTime > 0) {
668
+ feedback.remainingTime--;
669
+ feedback.updateDisplay();
670
+ }
671
+ else {
672
+ feedback.stopRecording();
673
+ }
674
+ },
675
+ updateDisplay: function () {
676
+ const minutes = Math.floor(feedback.remainingTime / 60);
677
+ const seconds = feedback.remainingTime % 60;
678
+ feedback.timerDisplay.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; // no i18n
679
+ },
680
+ validateFeedbackField: function () {
681
+ feedback.updateLeftCount();
682
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
683
+ const descriptionField = modal.querySelector('#zasdkDescription'); // no i18n
684
+ const attachmentField = modal.querySelector('#zasdkFileInput'); // no i18n
685
+ const videoElement = modal.querySelector('#previewVideoElemId'); // no i18n
686
+ const sendButton = modal.querySelector('#zasdk_submit_btn'); // no i18n
687
+ const descriptionFilled = descriptionField && descriptionField.value.trim() !== '' && descriptionField.value.trim().length > 0; // no i18n
688
+ attachmentField && attachmentField.files && attachmentField.files.length > 0;
689
+ videoElement && videoElement.offsetParent !== null; // Check if visible
690
+ const errorElements = modal.querySelectorAll('.zasdkmaxerror'); // no i18n
691
+ const hasErrors = feedback.getVisibleErrorCount(errorElements) > 0;
692
+ if (!hasErrors && descriptionFilled) {
693
+ sendButton.classList.remove('zasdkbtndisableclr'); // no i18n
694
+ feedback.handleStatusmsg();
695
+ }
696
+ else {
697
+ sendButton.classList.add('zasdkbtndisableclr'); // no i18n
698
+ }
699
+ },
700
+ getVisibleErrorCount: function (elements) {
701
+ return Array.from(elements).filter(element => element.offsetParent !== null).length;
702
+ }
703
+ };
704
+
705
+ exports.feedback = feedback;
706
+ exports.feedbackFormClose = feedbackFormClose;
707
+ exports.feedbackFormOpen = feedbackFormOpen;
708
+ exports.sendFeedback = sendFeedback;
709
+ exports.setFeedbackTheme = setFeedbackTheme;