@zoho_apptics/apptics-js-sdk 2.0.0-beta → 2.0.0-beta.2

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 (236) hide show
  1. package/CHANGELOG.md +191 -21
  2. package/README.md +519 -333
  3. package/dist/apptics.esm.min.js +2 -2
  4. package/dist/apptics.esm.min.js.map +1 -1
  5. package/dist/apptics.min.js +2 -2
  6. package/dist/apptics.min.js.map +1 -1
  7. package/dist/chunks/lifecycle-C6m1W7jo.min.js +3 -0
  8. package/dist/chunks/lifecycle-C6m1W7jo.min.js.map +1 -0
  9. package/dist/chunks/send-CgUO82ne.min.js +3 -0
  10. package/dist/chunks/send-CgUO82ne.min.js.map +1 -0
  11. package/dist/cjs/core/attempts.js +1 -1
  12. package/dist/cjs/core/batch.js +2 -2
  13. package/dist/cjs/core/consent.d.ts +18 -4
  14. package/dist/cjs/core/consent.js +31 -15
  15. package/dist/cjs/core/constants.d.ts +57 -27
  16. package/dist/cjs/core/constants.js +52 -33
  17. package/dist/cjs/core/db.d.ts +12 -4
  18. package/dist/cjs/core/db.js +167 -34
  19. package/dist/cjs/core/debug.js +1 -1
  20. package/dist/cjs/core/env.d.ts +0 -3
  21. package/dist/cjs/core/env.js +1 -9
  22. package/dist/cjs/core/framework-id.d.ts +1 -1
  23. package/dist/cjs/core/framework-id.js +3 -3
  24. package/dist/cjs/core/guard.d.ts +9 -0
  25. package/dist/cjs/core/guard.js +27 -13
  26. package/dist/cjs/core/hooks.d.ts +7 -4
  27. package/dist/cjs/core/hooks.js +3 -3
  28. package/dist/cjs/core/locks.d.ts +9 -0
  29. package/dist/cjs/core/locks.js +22 -0
  30. package/dist/cjs/core/logger.d.ts +3 -4
  31. package/dist/cjs/core/logger.js +4 -40
  32. package/dist/cjs/core/state.d.ts +9 -6
  33. package/dist/cjs/core/state.js +3 -5
  34. package/dist/cjs/core/storage.d.ts +20 -5
  35. package/dist/cjs/core/storage.js +115 -20
  36. package/dist/cjs/core/stylesheet.d.ts +8 -0
  37. package/dist/cjs/core/stylesheet.js +29 -0
  38. package/dist/cjs/core/transport.d.ts +2 -0
  39. package/dist/cjs/core/transport.js +30 -18
  40. package/dist/cjs/core/utils.js +1 -1
  41. package/dist/cjs/core/validate.js +2 -2
  42. package/dist/cjs/device/appversion.d.ts +10 -6
  43. package/dist/cjs/device/appversion.js +38 -3
  44. package/dist/cjs/device/index.d.ts +28 -2
  45. package/dist/cjs/device/index.js +312 -44
  46. package/dist/cjs/engagement/api-rules.d.ts +32 -67
  47. package/dist/cjs/engagement/api-rules.js +144 -157
  48. package/dist/cjs/engagement/auto-api.js +2 -2
  49. package/dist/cjs/engagement/auto-screen.d.ts +2 -0
  50. package/dist/cjs/engagement/auto-screen.js +67 -3
  51. package/dist/cjs/engagement/defined-events.js +1 -1
  52. package/dist/cjs/engagement/send.js +12 -3
  53. package/dist/cjs/engagement/session.d.ts +29 -3
  54. package/dist/cjs/engagement/session.js +253 -26
  55. package/dist/cjs/engagement/track.d.ts +4 -4
  56. package/dist/cjs/engagement/track.js +58 -30
  57. package/dist/cjs/errors/send.js +2 -2
  58. package/dist/cjs/errors/track.d.ts +2 -1
  59. package/dist/cjs/errors/track.js +49 -7
  60. package/dist/cjs/feedback/controls.d.ts +12 -0
  61. package/dist/cjs/feedback/controls.js +104 -25
  62. package/dist/cjs/feedback/index.d.ts +8 -7
  63. package/dist/cjs/feedback/index.js +32 -13
  64. package/dist/cjs/feedback/logs.d.ts +13 -11
  65. package/dist/cjs/feedback/logs.js +57 -28
  66. package/dist/cjs/feedback/quartz.d.ts +18 -0
  67. package/dist/cjs/feedback/quartz.js +105 -0
  68. package/dist/cjs/feedback/send.d.ts +5 -2
  69. package/dist/cjs/feedback/send.js +30 -28
  70. package/dist/cjs/feedback/styles.d.ts +10 -0
  71. package/dist/cjs/feedback/styles.js +8 -0
  72. package/dist/cjs/feedback/template.d.ts +1 -1
  73. package/dist/cjs/feedback/template.js +20 -12
  74. package/dist/cjs/feedback/ui.d.ts +21 -6
  75. package/dist/cjs/feedback/ui.js +283 -70
  76. package/dist/cjs/heatmap/send.d.ts +2 -0
  77. package/dist/cjs/heatmap/send.js +3 -5
  78. package/dist/cjs/heatmap/track.d.ts +1 -1
  79. package/dist/cjs/heatmap/track.js +87 -16
  80. package/dist/cjs/index.d.ts +16 -63
  81. package/dist/cjs/index.js +144 -95
  82. package/dist/cjs/lifecycle.d.ts +21 -3
  83. package/dist/cjs/lifecycle.js +353 -89
  84. package/dist/cjs/remoteconfig/country.d.ts +4 -0
  85. package/dist/cjs/remoteconfig/country.js +73 -0
  86. package/dist/cjs/remoteconfig/custom.d.ts +7 -7
  87. package/dist/cjs/remoteconfig/custom.js +31 -51
  88. package/dist/cjs/remoteconfig/evaluate.d.ts +3 -3
  89. package/dist/cjs/remoteconfig/evaluate.js +56 -43
  90. package/dist/cjs/remoteconfig/fetch.d.ts +16 -9
  91. package/dist/cjs/remoteconfig/fetch.js +120 -39
  92. package/dist/cjs/remoteconfig/index.d.ts +19 -8
  93. package/dist/cjs/remoteconfig/index.js +81 -39
  94. package/dist/cjs/remoteconfig/store.d.ts +15 -7
  95. package/dist/cjs/remoteconfig/store.js +68 -35
  96. package/dist/cjs/remoteconfig/tz-countries.d.ts +8 -0
  97. package/dist/cjs/remoteconfig/tz-countries.js +13 -0
  98. package/dist/{esm/core → cjs/remotelog}/callsite.d.ts +11 -4
  99. package/dist/cjs/{core → remotelog}/callsite.js +30 -7
  100. package/dist/cjs/remotelog/gate.d.ts +2 -11
  101. package/dist/cjs/remotelog/gate.js +9 -35
  102. package/dist/cjs/remotelog/index.d.ts +4 -21
  103. package/dist/cjs/remotelog/logger.d.ts +11 -17
  104. package/dist/cjs/remotelog/logger.js +31 -59
  105. package/dist/cjs/remotelog/send.js +11 -11
  106. package/dist/cjs/remotelogger/index.d.ts +12 -0
  107. package/dist/cjs/remotelogger/index.js +18 -0
  108. package/dist/cjs/scheduler.d.ts +3 -1
  109. package/dist/cjs/scheduler.js +25 -22
  110. package/dist/cjs/types.d.ts +208 -90
  111. package/dist/cjs/user/index.js +16 -7
  112. package/dist/esm/core/attempts.js +1 -1
  113. package/dist/esm/core/batch.js +2 -2
  114. package/dist/esm/core/consent.d.ts +18 -4
  115. package/dist/esm/core/consent.js +32 -17
  116. package/dist/esm/core/constants.d.ts +57 -27
  117. package/dist/esm/core/constants.js +51 -33
  118. package/dist/esm/core/db.d.ts +12 -4
  119. package/dist/esm/core/db.js +164 -35
  120. package/dist/esm/core/debug.js +1 -1
  121. package/dist/esm/core/env.d.ts +0 -3
  122. package/dist/esm/core/env.js +2 -9
  123. package/dist/esm/core/framework-id.d.ts +1 -1
  124. package/dist/esm/core/framework-id.js +3 -3
  125. package/dist/esm/core/guard.d.ts +9 -0
  126. package/dist/esm/core/guard.js +27 -14
  127. package/dist/esm/core/hooks.d.ts +7 -4
  128. package/dist/esm/core/hooks.js +3 -3
  129. package/dist/esm/core/locks.d.ts +9 -0
  130. package/dist/esm/core/locks.js +20 -0
  131. package/dist/esm/core/logger.d.ts +3 -4
  132. package/dist/esm/core/logger.js +4 -40
  133. package/dist/esm/core/state.d.ts +9 -6
  134. package/dist/esm/core/state.js +3 -5
  135. package/dist/esm/core/storage.d.ts +20 -5
  136. package/dist/esm/core/storage.js +113 -21
  137. package/dist/esm/core/stylesheet.d.ts +8 -0
  138. package/dist/esm/core/stylesheet.js +27 -0
  139. package/dist/esm/core/transport.d.ts +2 -0
  140. package/dist/esm/core/transport.js +30 -19
  141. package/dist/esm/core/utils.js +1 -1
  142. package/dist/esm/core/validate.js +2 -2
  143. package/dist/esm/device/appversion.d.ts +10 -6
  144. package/dist/esm/device/appversion.js +37 -4
  145. package/dist/esm/device/index.d.ts +28 -2
  146. package/dist/esm/device/index.js +313 -49
  147. package/dist/esm/engagement/api-rules.d.ts +32 -67
  148. package/dist/esm/engagement/api-rules.js +143 -155
  149. package/dist/esm/engagement/auto-api.js +3 -3
  150. package/dist/esm/engagement/auto-screen.d.ts +2 -0
  151. package/dist/esm/engagement/auto-screen.js +67 -4
  152. package/dist/esm/engagement/defined-events.js +1 -1
  153. package/dist/esm/engagement/send.js +12 -3
  154. package/dist/esm/engagement/session.d.ts +29 -3
  155. package/dist/esm/engagement/session.js +251 -30
  156. package/dist/esm/engagement/track.d.ts +4 -4
  157. package/dist/esm/engagement/track.js +65 -37
  158. package/dist/esm/errors/send.js +2 -2
  159. package/dist/esm/errors/track.d.ts +2 -1
  160. package/dist/esm/errors/track.js +49 -7
  161. package/dist/esm/feedback/controls.d.ts +12 -0
  162. package/dist/esm/feedback/controls.js +103 -26
  163. package/dist/esm/feedback/index.d.ts +8 -7
  164. package/dist/esm/feedback/index.js +34 -13
  165. package/dist/esm/feedback/logs.d.ts +13 -11
  166. package/dist/esm/feedback/logs.js +59 -30
  167. package/dist/esm/feedback/quartz.d.ts +18 -0
  168. package/dist/esm/feedback/quartz.js +99 -0
  169. package/dist/esm/feedback/send.d.ts +5 -2
  170. package/dist/esm/feedback/send.js +31 -31
  171. package/dist/esm/feedback/styles.d.ts +10 -0
  172. package/dist/esm/feedback/styles.js +4 -0
  173. package/dist/esm/feedback/template.d.ts +1 -1
  174. package/dist/esm/feedback/template.js +20 -12
  175. package/dist/esm/feedback/ui.d.ts +21 -6
  176. package/dist/esm/feedback/ui.js +283 -71
  177. package/dist/esm/heatmap/send.d.ts +2 -0
  178. package/dist/esm/heatmap/send.js +3 -5
  179. package/dist/esm/heatmap/track.d.ts +1 -1
  180. package/dist/esm/heatmap/track.js +87 -16
  181. package/dist/esm/index.d.ts +16 -63
  182. package/dist/esm/index.js +148 -83
  183. package/dist/esm/lifecycle.d.ts +21 -3
  184. package/dist/esm/lifecycle.js +359 -98
  185. package/dist/esm/remoteconfig/country.d.ts +4 -0
  186. package/dist/esm/remoteconfig/country.js +70 -0
  187. package/dist/esm/remoteconfig/custom.d.ts +7 -7
  188. package/dist/esm/remoteconfig/custom.js +32 -52
  189. package/dist/esm/remoteconfig/evaluate.d.ts +3 -3
  190. package/dist/esm/remoteconfig/evaluate.js +57 -44
  191. package/dist/esm/remoteconfig/fetch.d.ts +16 -9
  192. package/dist/esm/remoteconfig/fetch.js +120 -39
  193. package/dist/esm/remoteconfig/index.d.ts +19 -8
  194. package/dist/esm/remoteconfig/index.js +82 -40
  195. package/dist/esm/remoteconfig/store.d.ts +15 -7
  196. package/dist/esm/remoteconfig/store.js +68 -36
  197. package/dist/esm/remoteconfig/tz-countries.d.ts +8 -0
  198. package/dist/esm/remoteconfig/tz-countries.js +11 -0
  199. package/dist/{cjs/core → esm/remotelog}/callsite.d.ts +11 -4
  200. package/dist/esm/{core → remotelog}/callsite.js +30 -8
  201. package/dist/esm/remotelog/gate.d.ts +2 -11
  202. package/dist/esm/remotelog/gate.js +10 -32
  203. package/dist/esm/remotelog/index.d.ts +4 -21
  204. package/dist/esm/remotelog/logger.d.ts +11 -17
  205. package/dist/esm/remotelog/logger.js +33 -61
  206. package/dist/esm/remotelog/send.js +13 -13
  207. package/dist/esm/remotelogger/index.d.ts +12 -0
  208. package/dist/esm/remotelogger/index.js +13 -0
  209. package/dist/esm/scheduler.d.ts +3 -1
  210. package/dist/esm/scheduler.js +26 -24
  211. package/dist/esm/types.d.ts +208 -90
  212. package/dist/esm/user/index.js +18 -8
  213. package/dist/feedback.esm.min.js +2 -2
  214. package/dist/feedback.esm.min.js.map +1 -1
  215. package/dist/remoteconfig.esm.min.js +3 -0
  216. package/dist/remoteconfig.esm.min.js.map +1 -0
  217. package/dist/remotelogger.esm.min.js +3 -0
  218. package/dist/remotelogger.esm.min.js.map +1 -0
  219. package/package.json +16 -17
  220. package/dist/chunks/batch-BU_mTpm1.min.js +0 -3
  221. package/dist/chunks/batch-BU_mTpm1.min.js.map +0 -1
  222. package/dist/chunks/logs-Bea5zUW_.min.js +0 -3
  223. package/dist/chunks/logs-Bea5zUW_.min.js.map +0 -1
  224. package/dist/cjs/auto-init.d.ts +0 -8
  225. package/dist/cjs/auto-init.js +0 -32
  226. package/dist/cjs/heatmap/index.d.ts +0 -16
  227. package/dist/cjs/heatmap/index.js +0 -22
  228. package/dist/cjs/remotelog/index.js +0 -55
  229. package/dist/esm/auto-init.d.ts +0 -8
  230. package/dist/esm/auto-init.js +0 -29
  231. package/dist/esm/heatmap/index.d.ts +0 -16
  232. package/dist/esm/heatmap/index.js +0 -17
  233. package/dist/esm/remotelog/index.js +0 -51
  234. package/dist/heatmap.esm.min.js +0 -3
  235. package/dist/heatmap.esm.min.js.map +0 -1
  236. package/dist/style.css +0 -1
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var constants = require('../core/constants.js');
@@ -9,6 +9,9 @@ var consent = require('../core/consent.js');
9
9
  var template = require('./template.js');
10
10
  var send = require('./send.js');
11
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');
12
15
 
13
16
  // Quartz is an optional page-level SDK. Without it every call is a no-op (fix #5).
14
17
  const QUARTZ_NOOP = {
@@ -21,6 +24,12 @@ const QUARTZ_NOOP = {
21
24
  submitRecording() { return Promise.resolve({}); }
22
25
  };
23
26
  const QUARTZ_CONSTANTS_NOOP = { ErrorType: {}, FeedbackState: {} };
27
+ /** From Quartz's RECORDING_IN_PROGRESS until the form has come back from it. */
28
+ var recordingInProgress = false;
29
+ /** Send was pressed during a recording: it is sent, recording and all, once the recording has ended. */
30
+ var sendWhenEnded = false;
31
+ /** How long the form takes to shrink away when a recording starts: the stylesheet's transition. */
32
+ const HIDE_MS = 300;
24
33
  function hasQuartz() {
25
34
  return typeof Quartz !== 'undefined' && !!Quartz; // no i18n
26
35
  }
@@ -39,34 +48,55 @@ function submitFeedback(dataobj) {
39
48
  if (!result) {
40
49
  return null;
41
50
  }
42
- feedback.handleStatusmsg(result.ok, result.message);
43
51
  if (result.ok) {
44
- setTimeout(() => {
45
- feedback.close();
46
- }, 2000);
52
+ // sent: the form goes at once rather than holding the page for the success line
53
+ feedback.close();
54
+ }
55
+ else {
56
+ feedback.handleStatusmsg(result.ok, result.message);
47
57
  }
48
58
  return result;
49
59
  });
50
60
  }
51
- function sendFeedback(feedbackType, feedbackMessage, attachments, logsFiles, includeDyninfo, includeLog) {
61
+ /** Whether a value is an options object: a plain object, not a type number or a message string. */
62
+ function isOptions(value) {
63
+ return value !== null && typeof value === 'object' && !Array.isArray(value); // no i18n
64
+ }
65
+ /** Said once: the old one-argument-after-another form of feedbackFormOpen. */
66
+ var saidOpenForm = false;
67
+ function sendFeedback(options) {
68
+ if (options !== undefined && !isOptions(options)) {
69
+ // the old form, sendFeedback(type, message, ...): sending it as it stands would send an
70
+ // empty report, so it is refused, and says what to pass instead
71
+ return Promise.reject(new Error('AppticsFeedback.sendFeedback: takes one options object, as sendFeedback({ type, message, attachments, logFiles, includeDiagnostics, includeLog, isAnonymous })')); // no i18n
72
+ }
73
+ const o = options || {};
52
74
  const dataobj = {
53
- type: !utils.isEmpty(feedbackType) ? feedbackType : 1,
54
- message: feedbackMessage || '', // no i18n
55
- attachment: attachments || null,
56
- logsFiles: logsFiles || null,
75
+ type: !utils.isEmpty(o.type) ? o.type : 1,
76
+ message: o.message || '', // no i18n
77
+ attachment: o.attachments || null,
78
+ logsFiles: o.logFiles || null,
57
79
  // both flags stay as given: unset lets send.ts decide from what is actually stored
58
- includeDyninfo: includeDyninfo,
59
- includeLog: includeLog,
80
+ includeDyninfo: o.includeDiagnostics,
81
+ includeLog: o.includeLog,
60
82
  quartzid: '' // no i18n
61
83
  };
84
+ // from the active user, or from nobody with isAnonymous; the form's own choice is put back after
85
+ var restoreUser = controls.chooseUserForSend(o.isAnonymous === true);
62
86
  // an app awaiting this must be able to tell its user the feedback did not go: resolving on a
63
87
  // failure would have it say "thanks, sent" for a report the server never received
64
88
  return submitFeedback(dataobj).then(function (result) {
89
+ restoreUser();
90
+ return result;
91
+ }, function (err) {
92
+ restoreUser();
93
+ throw err;
94
+ }).then(function (result) {
65
95
  if (!result) {
66
- throw new Error('apptics.sendFeedback: not sent, the browser is offline or Apptics is disabled for this client'); // no i18n
96
+ throw new Error('AppticsFeedback.sendFeedback: not sent, the browser is offline or Apptics is disabled for this client'); // no i18n
67
97
  }
68
98
  if (!result.ok) {
69
- throw new Error('apptics.sendFeedback: not sent, ' + result.message); // no i18n
99
+ throw new Error('AppticsFeedback.sendFeedback: not sent, ' + result.message); // no i18n
70
100
  }
71
101
  });
72
102
  }
@@ -111,23 +141,54 @@ function newTransfer() {
111
141
  return null;
112
142
  }
113
143
  }
114
- function feedbackOpen(type, message, includeLog, includeDyninfo, attachments, logFiles, isAnonymous) {
144
+ function feedbackFormOpen(options) {
145
+ if (options !== undefined && !isOptions(options) && !saidOpenForm) {
146
+ // the old form, feedbackFormOpen(type, message, ...): the form still opens, with its defaults
147
+ saidOpenForm = true;
148
+ logger.warnAlways('AppticsFeedback.feedbackFormOpen: takes one options object, as feedbackFormOpen({ type, message, includeLog, includeDiagnostics, attachments, logFiles, isAnonymous }); opening it with its defaults'); // no i18n
149
+ }
150
+ const o = isOptions(options) ? options : {};
115
151
  const opts = {
116
- includeLog: includeLog === true,
117
- includeDyninfo: includeDyninfo === true,
118
- isAnonymous: isAnonymous === true,
152
+ includeLog: o.includeLog === true,
153
+ includeDyninfo: o.includeDiagnostics === true,
154
+ isAnonymous: o.isAnonymous === true,
119
155
  };
120
- if (typeof type === 'number')
121
- opts.type = type; // no i18n
122
- if (typeof message === 'string' && message.length > 0)
123
- opts.message = message; // no i18n
124
- if (attachments && attachments.length > 0)
125
- opts.attachments = attachments;
126
- if (logFiles && logFiles.length > 0)
127
- opts.logFiles = logFiles;
156
+ if (typeof o.type === 'number')
157
+ opts.type = o.type; // no i18n
158
+ if (typeof o.message === 'string' && o.message.length > 0)
159
+ opts.message = o.message; // no i18n
160
+ if (o.attachments && o.attachments.length > 0)
161
+ opts.attachments = o.attachments;
162
+ if (o.logFiles && o.logFiles.length > 0)
163
+ opts.logFiles = o.logFiles;
164
+ // the form brings its own styles, so an app imports or links no css
165
+ stylesheet.injectStylesheet(styles.default);
128
166
  feedback.init(opts);
129
167
  }
130
- function feedbackClose() {
168
+ /** The themes the form has: 'auto' follows the visitor's system setting. */
169
+ const FEEDBACK_THEMES = ['light', 'dark', 'auto']; // no i18n
170
+ /**
171
+ * Sets the form's theme, for a page with its own light and dark modes: 'auto' follows the
172
+ * operating system, which is not what such a page shows. Restyles a form or recording timer that
173
+ * is open now, and every one opened after; Apptics.init()'s feedback_theme only sets the first.
174
+ */
175
+ function setFeedbackTheme(theme) {
176
+ if (FEEDBACK_THEMES.indexOf(theme) === -1) {
177
+ logger.Console.warn('AppticsFeedback.setFeedbackTheme: takes \'light\', \'dark\' or \'auto\', not ' + JSON.stringify(theme)); // no i18n
178
+ return;
179
+ }
180
+ state._ZAP._config.feedback_theme = theme;
181
+ if (typeof document === 'undefined') { // no i18n
182
+ return;
183
+ }
184
+ ['zasdkFeedbackModal', 'zasdkrectimer'].forEach(function (id) {
185
+ var open = document.getElementById(id);
186
+ if (open) {
187
+ open.setAttribute('data-zasdk-theme', theme); // no i18n
188
+ }
189
+ });
190
+ }
191
+ function feedbackFormClose() {
131
192
  feedback.close();
132
193
  }
133
194
  const feedback = {
@@ -152,31 +213,27 @@ const feedback = {
152
213
  feedback._opts = opts || {};
153
214
  var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
154
215
  if (!utils.isEmpty(modal)) {
216
+ // already open. A recording takes the form out of sight, and one that ended without the
217
+ // form hearing of it would leave it there, every later open a no-op. Asked to open, it
218
+ // comes back; a recording still going carries on, and its end is handled as ever
219
+ if (feedback.isHidden || feedback.isScaled) {
220
+ feedback.showForm();
221
+ }
155
222
  return;
156
223
  }
157
224
  const tempContainer = document.createElement('div'); // no i18n
158
225
  feedback.uploadFileAry = [];
159
226
  tempContainer.id = 'zasdkFeedbackModal'; // no i18n
160
227
  tempContainer.className = 'zasdk-modal'; // no i18n
228
+ tempContainer.setAttribute('data-zasdk-theme', state._ZAP._config.feedback_theme); // no i18n
161
229
  tempContainer.innerHTML = feedback.feedbackUIHtml;
162
230
  document.body.appendChild(tempContainer);
163
231
  var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
164
- var defaultoption = state._ZAP._defaultoptions;
165
- var qz_ws_key = defaultoption.quartz_workspace_key;
166
- var qz_dp_key = defaultoption.quartz_department_key;
167
- var quartz_DC = {
168
- "Local": "https://quartz.localzoho.com", // no i18n
169
- "US": "https://quartz.zoho.com", // no i18n
170
- "EU": "https://quartz.zoho.eu", // no i18n
171
- "IN": "https://quartz.zoho.in", // no i18n
172
- "AU": "https://quartz.zoho.com.au", // no i18n
173
- "CN": "https://quartz.zoho.com.cn", // no i18n
174
- "CA": "https://quartz.zohocloud.ca", // no i18n
175
- "JP": "https://quartz.zoho.jp", // no i18n
176
- "SA": "https://quartz.zoho.sa", // no i18n
177
- "AE": "https://quartz.zoho.ae" // no i18n
178
- };
179
- var qz_dc_key = (!utils.isEmpty(defaultoption.DC) && defaultoption.DC !== '-') ? (quartz_DC[defaultoption.DC] || '') : ''; // no i18n
232
+ // screen recording as the console set it up for this app (getsdkconfig's quartz block)
233
+ var qz = state._ZAP._quartz;
234
+ var qz_ws_key = qz.workspace;
235
+ var qz_dp_key = qz.department;
236
+ var qz_dc_key = quartz$1.recordingDomain(qz.domain);
180
237
  var closeBtn = modal.querySelector("#appticsfeedbackclose"); // no i18n
181
238
  var feedbackTypes = modal.querySelectorAll(".zasdk-feedback-type"); // no i18n
182
239
  feedback.fileInput = modal.querySelector("#zasdkFileInput"); // no i18n
@@ -199,17 +256,37 @@ const feedback = {
199
256
  document.addEventListener('quartz-feedback-state', feedback.bindQuartzEvent); // no i18n
200
257
  document.removeEventListener('quartz-feedback-error', feedback.handleErrorQuartzEvent); // no i18n
201
258
  document.addEventListener('quartz-feedback-error', feedback.handleErrorQuartzEvent); // no i18n
202
- // the consent checkbox and its label only when a recording can actually be made: the Quartz
203
- // script on the page, a DC it knows, and both keys. "-" for any of them turns it off; DC "-"
204
- // has already become '' above. A checkbox that leads only to "unavailable" is not offered
205
- var recordingAvailable = hasQuartz() && !utils.isEmpty(qz_dc_key)
206
- && !utils.isEmpty(qz_ws_key) && qz_ws_key !== "-" && !utils.isEmpty(qz_dp_key) && qz_dp_key !== "-"; // no i18n
207
- modal.querySelector("#zasdkreccheckcnt").style.display = recordingAvailable ? "block" : "none"; // no i18n
259
+ // the consent checkbox and its label only when a recording can actually be made: recording
260
+ // on for the app, its workspace, department and domain, and Quartz on the page. A checkbox
261
+ // that leads only to "unavailable" is not offered. Quartz is loaded here, the first time
262
+ // the form needs it, and the checkbox shows once it has arrived
263
+ var recordingConfigured = qz.enabled && !utils.isEmpty(qz_dc_key) && !utils.isEmpty(qz_ws_key) && !utils.isEmpty(qz_dp_key);
264
+ var recordingBlock = modal.querySelector("#zasdkreccheckcnt"); // no i18n
265
+ recordingBlock.style.display = recordingConfigured && hasQuartz() ? "block" : "none"; // no i18n
266
+ if (recordingConfigured && !hasQuartz()) {
267
+ // quartz_cdn_url, or Zoho's CDN for this serviceUrl when the answer carries none
268
+ quartz$1.loadQuartz(quartz$1.quartzScriptSource(qz.cdnUrl, String(state._ZAP._defaultoptions.serviceUrl || ''))).then(function (loaded) {
269
+ if (loaded && recordingBlock.isConnected) {
270
+ recordingBlock.style.display = "block"; // no i18n
271
+ }
272
+ });
273
+ }
208
274
  feedbackbox.addEventListener('transitionend', function (event) {
209
- if (event.propertyName === 'transform' && feedback.isScaled) { // no i18n
210
- feedback.toggleWindowAnimation();
275
+ if (event.propertyName === 'transform') { // no i18n
276
+ feedback.finishHiding();
211
277
  }
212
278
  });
279
+ // the form, opened again while a recording goes on, says so and can stop it
280
+ const recStop = modal.querySelector('#zasdkRecStatusStop'); // no i18n
281
+ recStop.onclick = function () {
282
+ feedback.stopRecording();
283
+ };
284
+ recStop.onkeydown = function (e) {
285
+ if (e.key === 'Enter' || e.key === ' ') { // no i18n
286
+ e.preventDefault();
287
+ feedback.stopRecording();
288
+ }
289
+ };
213
290
  quartzrecbtn.onclick = function (e) {
214
291
  e.stopImmediatePropagation();
215
292
  let recordingDetails = {
@@ -231,8 +308,16 @@ const feedback = {
231
308
  quartz().startRecording(recordingDetails);
232
309
  };
233
310
  closeBtn.onclick = function () {
234
- feedback.close();
311
+ feedback.dismiss();
312
+ };
313
+ // keyboard: Enter or Space on the close control, and Escape anywhere, close the form
314
+ closeBtn.onkeydown = function (e) {
315
+ if (e.key === 'Enter' || e.key === ' ') { // no i18n
316
+ e.preventDefault();
317
+ feedback.dismiss();
318
+ }
235
319
  };
320
+ document.addEventListener('keydown', feedback.onEscape); // no i18n
236
321
  preivewButton.addEventListener('click', function () {
237
322
  quartz().previewVideo();
238
323
  });
@@ -255,6 +340,12 @@ const feedback = {
255
340
  submitbtncnt.classList.add('zasdkbtndisabled'); // no i18n
256
341
  submitbtn.value = '';
257
342
  try {
343
+ if (recordingInProgress) {
344
+ // sent with the recording: stopped first, and sent once Quartz has stored it
345
+ sendWhenEnded = true;
346
+ feedback.stopRecording();
347
+ return;
348
+ }
258
349
  let videoElement = modal.querySelector('#previewVideoElemId'), // no i18n
259
350
  videoVisible = videoElement && videoElement.offsetParent !== null;
260
351
  if (videoVisible) {
@@ -283,6 +374,11 @@ const feedback = {
283
374
  }
284
375
  });
285
376
  descriptionField.addEventListener('input', feedback.validateFeedbackField); // no i18n
377
+ // keyboard and screen-reader users land in the form, not behind it
378
+ try {
379
+ descriptionField.focus({ preventScroll: true });
380
+ }
381
+ catch (err) { /* focus is a courtesy */ }
286
382
  feedbackTypes.forEach(function (type) {
287
383
  type.addEventListener("click", function () {
288
384
  feedbackTypes.forEach(function (t) {
@@ -291,7 +387,7 @@ const feedback = {
291
387
  this.classList.add("zasdk-selected"); // no i18n
292
388
  });
293
389
  });
294
- // what feedbackOpen() was given: select that type, fill the description
390
+ // what feedbackFormOpen() was given: select that type, fill the description
295
391
  if (typeof feedback._opts.type === 'number') { // no i18n
296
392
  var wanted = Object.keys(feedback.typeObj).filter(function (name) {
297
393
  return feedback.typeObj[name] === feedback._opts.type;
@@ -351,6 +447,10 @@ const feedback = {
351
447
  let counterElem = elem.parentElement ? elem.parentElement.querySelector(".zaleftcharcnt") : null; // no i18n
352
448
  if (counterElem) {
353
449
  counterElem.textContent = String(maxLength - val.length); // Update remaining count
450
+ var unit = counterElem.parentElement ? counterElem.parentElement.querySelector(".zaleftchartxt") : null; // no i18n
451
+ if (unit) {
452
+ unit.textContent = maxLength - val.length === 1 ? 'character left' : 'characters left'; // no i18n
453
+ }
354
454
  }
355
455
  });
356
456
  },
@@ -386,7 +486,14 @@ const feedback = {
386
486
  },
387
487
  bindQuartzEvent: function (event) {
388
488
  let feedbackState = event.detail.feedbackState;
489
+ if (feedbackState == quartzConstants().FeedbackState.RECORDING_COMPLETED) {
490
+ // Quartz's own stop control and the browser's "Stop sharing" end the recording without
491
+ // the SDK's timer; this is the only word of it the form gets
492
+ feedback.recordingEnded();
493
+ return;
494
+ }
389
495
  if (feedbackState == quartzConstants().FeedbackState.RECORDING_IN_PROGRESS) {
496
+ recordingInProgress = true;
390
497
  var feedbacktimer = document.getElementById("zasdkrectimer"); // no i18n
391
498
  if (!utils.isEmpty(feedbacktimer)) {
392
499
  feedbacktimer.remove();
@@ -394,8 +501,11 @@ const feedback = {
394
501
  const tempDiv = document.createElement("div"); // no i18n
395
502
  tempDiv.innerHTML = feedback.timerHtml;
396
503
  const node = tempDiv.firstElementChild;
504
+ node.setAttribute('data-zasdk-theme', state._ZAP._config.feedback_theme); // no i18n
397
505
  document.body.appendChild(node);
398
506
  var feedbacktimer = document.getElementById("zasdkrectimer"); // no i18n
507
+ // draggable anywhere on the page; wired before the click that stops the recording
508
+ controls.wireTimerDrag(feedbacktimer);
399
509
  feedback.timerDisplay = feedbacktimer.querySelector('#zasdkTimerDisplay'); // no i18n
400
510
  feedback.recordButton = feedbacktimer;
401
511
  feedback.TOTAL_TIME = 5 * 60; // 5 minutes in seconds
@@ -403,13 +513,52 @@ const feedback = {
403
513
  feedback.isRecording = true;
404
514
  feedback.recordButton.addEventListener('click', feedback.toggleRecording); // no i18n
405
515
  feedback.startRecording();
516
+ feedback.updateDisplay();
517
+ feedback.showRecordingStatus(true);
406
518
  feedback.toggleWindowAnimation();
407
519
  }
408
520
  },
521
+ onEscape: function (e) {
522
+ if (e.key === 'Escape') { // no i18n
523
+ feedback.dismiss();
524
+ }
525
+ },
526
+ dismiss: function () {
527
+ // the form's own close (its X, Escape) during a recording puts it out of sight rather than
528
+ // throwing away what was typed: the recording goes on, and the next open brings it all back
529
+ if (recordingInProgress) {
530
+ if (!feedback.isScaled && !feedback.isHidden) {
531
+ feedback.toggleWindowAnimation();
532
+ }
533
+ return;
534
+ }
535
+ feedback.close();
536
+ },
537
+ showRecordingStatus: function (on) {
538
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
539
+ if (!modal) {
540
+ return;
541
+ }
542
+ modal.querySelector("#zasdkrecstatus").style.display = on ? "flex" : "none"; // no i18n
543
+ if (on) {
544
+ modal.querySelector("#zasdkreccheckcnt").style.display = "none"; // no i18n
545
+ }
546
+ },
409
547
  close: function () {
410
548
  var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
549
+ document.removeEventListener('keydown', feedback.onEscape); // no i18n
411
550
  document.removeEventListener('quartz-feedback-state', feedback.bindQuartzEvent); // no i18n
412
551
  quartz().clearFeedback();
552
+ // the recording goes with the form: no timer left on the page, and the next form starts clean
553
+ recordingInProgress = false;
554
+ sendWhenEnded = false;
555
+ feedback.isRecording = false;
556
+ clearInterval(feedback.timerInterval || undefined);
557
+ feedback.timerInterval = null;
558
+ var timer = document.getElementById("zasdkrectimer"); // no i18n
559
+ if (timer) {
560
+ timer.remove();
561
+ }
413
562
  if (!utils.isEmpty(modal)) {
414
563
  modal.remove();
415
564
  }
@@ -418,23 +567,29 @@ const feedback = {
418
567
  var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
419
568
  const box = modal.querySelector('#zasdkFeedbackconatiner'); // no i18n
420
569
  if (feedback.isHidden) {
421
- modal.style.display = 'block'; // no i18n
422
- setTimeout(() => {
423
- box.style.transform = 'scale(1)'; // no i18n
424
- feedback.validateFeedbackField();
425
- }, 10);
426
- feedback.isHidden = false;
427
- feedback.isScaled = false;
570
+ feedback.showForm();
428
571
  }
429
572
  else if (feedback.isScaled) {
430
- modal.style.display = 'none'; // no i18n
431
- feedback.isHidden = true;
573
+ feedback.finishHiding();
432
574
  }
433
575
  else {
576
+ // shrinks away (the stylesheet's transition), and is taken off the page once it has;
577
+ // the timeout covers a page where the transition does not run (reduced motion)
434
578
  box.style.transform = 'scale(0)'; // no i18n
579
+ box.style.opacity = '0'; // no i18n
435
580
  feedback.isScaled = true;
581
+ setTimeout(feedback.finishHiding, HIDE_MS + 50);
436
582
  }
437
583
  },
584
+ finishHiding: function () {
585
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
586
+ // once only, and not when the form was brought back meanwhile
587
+ if (!modal || !feedback.isScaled || feedback.isHidden) {
588
+ return;
589
+ }
590
+ modal.style.display = 'none'; // no i18n
591
+ feedback.isHidden = true;
592
+ },
438
593
  fileAttachment: function () {
439
594
  var uploadedFiles = feedback.fileInput.files;
440
595
  feedback.uploadTotalSize = 0;
@@ -548,16 +703,65 @@ const feedback = {
548
703
  }
549
704
  },
550
705
  stopRecording: function () {
551
- var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
706
+ if (!recordingInProgress) {
707
+ // Quartz has ended it already (its RECORDING_COMPLETED came first): asking again
708
+ // only gets a "no recording in progress" error shown in the form
709
+ return;
710
+ }
552
711
  clearInterval(feedback.timerInterval || undefined);
553
712
  feedback.timerInterval = null;
554
- document.querySelector("#zasdkrectimer").remove(); // no i18n
555
- feedback.toggleWindowAnimation();
713
+ // the preview is read from what Quartz stored, so only once the recording has ended
714
+ Promise.resolve(quartz().endRecording()).catch(function (err) {
715
+ logger.Console.log('stopRecording: ' + err); // no i18n
716
+ }).then(feedback.recordingEnded);
717
+ },
718
+ recordingEnded: function () {
719
+ if (!recordingInProgress) {
720
+ return;
721
+ }
722
+ recordingInProgress = false;
723
+ feedback.isRecording = false;
724
+ clearInterval(feedback.timerInterval || undefined);
725
+ feedback.timerInterval = null;
726
+ var timer = document.getElementById("zasdkrectimer"); // no i18n
727
+ if (timer) {
728
+ timer.remove();
729
+ }
730
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
731
+ if (!modal) {
732
+ return; // the form was closed meanwhile
733
+ }
734
+ var send = sendWhenEnded;
735
+ sendWhenEnded = false;
736
+ feedback.showRecordingStatus(false);
737
+ feedback.showForm();
556
738
  modal.querySelector("#editRecordedVideo").style.display = "block"; // no i18n
557
739
  modal.querySelector("#zasdkreccheckcnt").style.display = "none"; // no i18n
558
740
  let videoElem = modal.querySelector('#previewVideoElemId'); // no i18n
559
- quartz().endRecording();
560
- quartz().setVideoContent(videoElem);
741
+ Promise.resolve(quartz().setVideoContent(videoElem)).catch(function (err) {
742
+ logger.Console.warn('AppticsFeedback: the recording could not be shown: ' + err); // no i18n
743
+ }).then(function () {
744
+ if (send && document.getElementById("zasdkFeedbackModal")) { // no i18n
745
+ feedback.submitRecording();
746
+ }
747
+ });
748
+ },
749
+ showForm: function () {
750
+ // shown outright, not toggled: a recording that ends mid-way through the scale-down would
751
+ // otherwise be toggled out of sight instead of back into it
752
+ var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
753
+ if (!modal) {
754
+ return;
755
+ }
756
+ const box = modal.querySelector('#zasdkFeedbackconatiner'); // no i18n
757
+ feedback.isHidden = false;
758
+ feedback.isScaled = false;
759
+ modal.style.display = 'block'; // no i18n
760
+ setTimeout(() => {
761
+ box.style.transform = 'scale(1)'; // no i18n
762
+ box.style.opacity = '1'; // no i18n
763
+ feedback.validateFeedbackField();
764
+ }, 10);
561
765
  },
562
766
  submitRecording: function () {
563
767
  var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
@@ -598,7 +802,15 @@ const feedback = {
598
802
  updateDisplay: function () {
599
803
  const minutes = Math.floor(feedback.remainingTime / 60);
600
804
  const seconds = feedback.remainingTime % 60;
601
- feedback.timerDisplay.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; // no i18n
805
+ const shown = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; // no i18n
806
+ if (feedback.timerDisplay) {
807
+ feedback.timerDisplay.textContent = shown;
808
+ }
809
+ // and in the form, for when it is opened again mid-recording
810
+ var inForm = document.getElementById("zasdkRecStatusTime"); // no i18n
811
+ if (inForm) {
812
+ inForm.textContent = shown;
813
+ }
602
814
  },
603
815
  validateFeedbackField: function () {
604
816
  feedback.updateLeftCount();
@@ -626,6 +838,7 @@ const feedback = {
626
838
  };
627
839
 
628
840
  exports.feedback = feedback;
629
- exports.feedbackClose = feedbackClose;
630
- exports.feedbackOpen = feedbackOpen;
841
+ exports.feedbackFormClose = feedbackFormClose;
842
+ exports.feedbackFormOpen = feedbackFormOpen;
631
843
  exports.sendFeedback = sendFeedback;
844
+ exports.setFeedbackTheme = setFeedbackTheme;
@@ -8,6 +8,8 @@ import type { Dict, ServerResult } from '../types.js';
8
8
  *
9
9
  * Gated on the server's own heatmap flag (getsdkconfig module 18), not on engagement: an app may
10
10
  * want events while declining to have every click's coordinates recorded.
11
+ *
12
+ * The scheduler reaches it through hooks.sendHeatmaps, which src/index.ts sets.
11
13
  */
12
14
  export declare function sendHeatmapData(forget?: boolean): Promise<void>;
13
15
  export declare function requestToSendHeatmaps(_payload: Dict, forget?: boolean): Promise<ServerResult>;
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var state = require('../core/state.js');
@@ -9,7 +9,6 @@ var env = require('../core/env.js');
9
9
  var consent = require('../core/consent.js');
10
10
  var batch = require('../core/batch.js');
11
11
  var transport = require('../core/transport.js');
12
- var hooks = require('../core/hooks.js');
13
12
 
14
13
  /**
15
14
  * Sends queued heatmap records to heatmap/add.
@@ -20,6 +19,8 @@ var hooks = require('../core/hooks.js');
20
19
  *
21
20
  * Gated on the server's own heatmap flag (getsdkconfig module 18), not on engagement: an app may
22
21
  * want events while declining to have every click's coordinates recorded.
22
+ *
23
+ * The scheduler reaches it through hooks.sendHeatmaps, which src/index.ts sets.
23
24
  */
24
25
  function sendHeatmapData(forget) {
25
26
  if (env.is_apptics_disabled() || !consent.shouldTrackOrSendData() || !state._ZAP._heatmapTracking) {
@@ -74,9 +75,6 @@ function requestToSendHeatmaps(_payload, forget) {
74
75
  var label = 'requestToSendHeatmaps'; // no i18n
75
76
  return batch.sendBatch('heatmap', label, _payload, forget); // no i18n
76
77
  }
77
- // the scheduler flushes through this, so importing the heatmap entry is what puts heatmap
78
- // records on the flush timer at all
79
- hooks.hooks.sendHeatmaps = sendHeatmapData;
80
78
 
81
79
  exports.requestToSendHeatmaps = requestToSendHeatmaps;
82
80
  exports.sendHeatmapData = sendHeatmapData;
@@ -1,4 +1,4 @@
1
1
  /** Turns capture on or off. Listeners are passive, so they never delay a click or a scroll. */
2
- export declare function enableHeatmap(status?: boolean): void;
2
+ export declare function trackHeatmap(status?: boolean): void;
3
3
  /** Forgets what this visit recorded. reset() calls it; the cap starts again from zero. */
4
4
  export declare function resetHeatmapSession(): void;