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