@zoho_apptics/apptics-js-sdk 2.0.0-beta → 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 (220) hide show
  1. package/CHANGELOG.md +111 -5
  2. package/README.md +399 -300
  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-VYr43KcB.min.js +3 -0
  8. package/dist/chunks/lifecycle-VYr43KcB.min.js.map +1 -0
  9. package/dist/cjs/auto-init.d.ts +3 -3
  10. package/dist/cjs/auto-init.js +1 -1
  11. package/dist/cjs/core/attempts.js +1 -1
  12. package/dist/cjs/core/batch.js +2 -1
  13. package/dist/cjs/core/callsite.d.ts +6 -0
  14. package/dist/cjs/core/callsite.js +25 -3
  15. package/dist/cjs/core/consent.d.ts +5 -1
  16. package/dist/cjs/core/consent.js +8 -6
  17. package/dist/cjs/core/constants.d.ts +35 -10
  18. package/dist/cjs/core/constants.js +31 -15
  19. package/dist/cjs/core/db.d.ts +12 -4
  20. package/dist/cjs/core/db.js +167 -34
  21. package/dist/cjs/core/debug.js +1 -1
  22. package/dist/cjs/core/env.js +1 -1
  23. package/dist/cjs/core/framework-id.d.ts +1 -1
  24. package/dist/cjs/core/framework-id.js +3 -3
  25. package/dist/cjs/core/guard.d.ts +9 -0
  26. package/dist/cjs/core/guard.js +27 -13
  27. package/dist/cjs/core/hooks.d.ts +2 -4
  28. package/dist/cjs/core/hooks.js +2 -3
  29. package/dist/cjs/core/locks.d.ts +9 -0
  30. package/dist/cjs/core/locks.js +22 -0
  31. package/dist/cjs/core/logger.d.ts +3 -4
  32. package/dist/cjs/core/logger.js +4 -40
  33. package/dist/cjs/core/state.d.ts +3 -2
  34. package/dist/cjs/core/state.js +2 -2
  35. package/dist/cjs/core/storage.d.ts +20 -5
  36. package/dist/cjs/core/storage.js +115 -17
  37. package/dist/cjs/core/stylesheet.d.ts +8 -0
  38. package/dist/cjs/core/stylesheet.js +29 -0
  39. package/dist/cjs/core/transport.d.ts +2 -0
  40. package/dist/cjs/core/transport.js +19 -4
  41. package/dist/cjs/core/utils.js +1 -1
  42. package/dist/cjs/core/validate.js +2 -2
  43. package/dist/cjs/device/appversion.d.ts +1 -6
  44. package/dist/cjs/device/appversion.js +13 -1
  45. package/dist/cjs/device/index.d.ts +11 -0
  46. package/dist/cjs/device/index.js +120 -20
  47. package/dist/cjs/engagement/api-rules.d.ts +32 -67
  48. package/dist/cjs/engagement/api-rules.js +144 -157
  49. package/dist/cjs/engagement/auto-api.js +2 -2
  50. package/dist/cjs/engagement/auto-screen.d.ts +2 -0
  51. package/dist/cjs/engagement/auto-screen.js +67 -3
  52. package/dist/cjs/engagement/defined-events.js +1 -1
  53. package/dist/cjs/engagement/send.js +6 -1
  54. package/dist/cjs/engagement/session.d.ts +12 -3
  55. package/dist/cjs/engagement/session.js +161 -25
  56. package/dist/cjs/engagement/track.js +45 -20
  57. package/dist/cjs/errors/send.js +1 -1
  58. package/dist/cjs/errors/track.d.ts +1 -1
  59. package/dist/cjs/errors/track.js +46 -6
  60. package/dist/cjs/feedback/controls.d.ts +6 -0
  61. package/dist/cjs/feedback/controls.js +31 -1
  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 +10 -5
  65. package/dist/cjs/feedback/logs.js +52 -13
  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 +3 -0
  69. package/dist/cjs/feedback/send.js +28 -3
  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 +12 -12
  74. package/dist/cjs/feedback/ui.d.ts +14 -6
  75. package/dist/cjs/feedback/ui.js +126 -48
  76. package/dist/cjs/heatmap/send.js +1 -1
  77. package/dist/cjs/heatmap/track.d.ts +1 -1
  78. package/dist/cjs/heatmap/track.js +87 -16
  79. package/dist/cjs/index.d.ts +17 -63
  80. package/dist/cjs/index.js +104 -92
  81. package/dist/cjs/lifecycle.d.ts +8 -1
  82. package/dist/cjs/lifecycle.js +258 -62
  83. package/dist/cjs/remoteconfig/country.d.ts +4 -0
  84. package/dist/cjs/remoteconfig/country.js +73 -0
  85. package/dist/cjs/remoteconfig/custom.d.ts +7 -7
  86. package/dist/cjs/remoteconfig/custom.js +31 -51
  87. package/dist/cjs/remoteconfig/evaluate.d.ts +3 -3
  88. package/dist/cjs/remoteconfig/evaluate.js +56 -43
  89. package/dist/cjs/remoteconfig/fetch.d.ts +3 -3
  90. package/dist/cjs/remoteconfig/fetch.js +9 -23
  91. package/dist/cjs/remoteconfig/index.d.ts +10 -8
  92. package/dist/cjs/remoteconfig/index.js +65 -39
  93. package/dist/cjs/remoteconfig/store.js +1 -1
  94. package/dist/cjs/remoteconfig/tz-countries.d.ts +8 -0
  95. package/dist/cjs/remoteconfig/tz-countries.js +13 -0
  96. package/dist/cjs/remotelog/gate.d.ts +2 -11
  97. package/dist/cjs/remotelog/gate.js +9 -35
  98. package/dist/cjs/remotelog/index.d.ts +4 -21
  99. package/dist/cjs/remotelog/logger.d.ts +11 -17
  100. package/dist/cjs/remotelog/logger.js +30 -58
  101. package/dist/cjs/remotelog/send.js +10 -10
  102. package/dist/cjs/remotelogger/index.d.ts +12 -0
  103. package/dist/cjs/remotelogger/index.js +18 -0
  104. package/dist/cjs/scheduler.js +2 -2
  105. package/dist/cjs/types.d.ts +155 -82
  106. package/dist/cjs/user/index.js +11 -6
  107. package/dist/esm/auto-init.d.ts +3 -3
  108. package/dist/esm/auto-init.js +1 -1
  109. package/dist/esm/core/attempts.js +1 -1
  110. package/dist/esm/core/batch.js +2 -1
  111. package/dist/esm/core/callsite.d.ts +6 -0
  112. package/dist/esm/core/callsite.js +25 -4
  113. package/dist/esm/core/consent.d.ts +5 -1
  114. package/dist/esm/core/consent.js +9 -7
  115. package/dist/esm/core/constants.d.ts +35 -10
  116. package/dist/esm/core/constants.js +30 -15
  117. package/dist/esm/core/db.d.ts +12 -4
  118. package/dist/esm/core/db.js +164 -35
  119. package/dist/esm/core/debug.js +1 -1
  120. package/dist/esm/core/env.js +1 -1
  121. package/dist/esm/core/framework-id.d.ts +1 -1
  122. package/dist/esm/core/framework-id.js +3 -3
  123. package/dist/esm/core/guard.d.ts +9 -0
  124. package/dist/esm/core/guard.js +27 -14
  125. package/dist/esm/core/hooks.d.ts +2 -4
  126. package/dist/esm/core/hooks.js +2 -3
  127. package/dist/esm/core/locks.d.ts +9 -0
  128. package/dist/esm/core/locks.js +20 -0
  129. package/dist/esm/core/logger.d.ts +3 -4
  130. package/dist/esm/core/logger.js +4 -40
  131. package/dist/esm/core/state.d.ts +3 -2
  132. package/dist/esm/core/state.js +2 -2
  133. package/dist/esm/core/storage.d.ts +20 -5
  134. package/dist/esm/core/storage.js +113 -18
  135. package/dist/esm/core/stylesheet.d.ts +8 -0
  136. package/dist/esm/core/stylesheet.js +27 -0
  137. package/dist/esm/core/transport.d.ts +2 -0
  138. package/dist/esm/core/transport.js +19 -5
  139. package/dist/esm/core/utils.js +1 -1
  140. package/dist/esm/core/validate.js +2 -2
  141. package/dist/esm/device/appversion.d.ts +1 -6
  142. package/dist/esm/device/appversion.js +13 -2
  143. package/dist/esm/device/index.d.ts +11 -0
  144. package/dist/esm/device/index.js +123 -24
  145. package/dist/esm/engagement/api-rules.d.ts +32 -67
  146. package/dist/esm/engagement/api-rules.js +143 -155
  147. package/dist/esm/engagement/auto-api.js +3 -3
  148. package/dist/esm/engagement/auto-screen.d.ts +2 -0
  149. package/dist/esm/engagement/auto-screen.js +67 -4
  150. package/dist/esm/engagement/defined-events.js +1 -1
  151. package/dist/esm/engagement/send.js +6 -1
  152. package/dist/esm/engagement/session.d.ts +12 -3
  153. package/dist/esm/engagement/session.js +162 -29
  154. package/dist/esm/engagement/track.js +52 -27
  155. package/dist/esm/errors/send.js +1 -1
  156. package/dist/esm/errors/track.d.ts +1 -1
  157. package/dist/esm/errors/track.js +46 -6
  158. package/dist/esm/feedback/controls.d.ts +6 -0
  159. package/dist/esm/feedback/controls.js +31 -2
  160. package/dist/esm/feedback/index.d.ts +8 -7
  161. package/dist/esm/feedback/index.js +34 -13
  162. package/dist/esm/feedback/logs.d.ts +10 -5
  163. package/dist/esm/feedback/logs.js +54 -15
  164. package/dist/esm/feedback/quartz.d.ts +18 -0
  165. package/dist/esm/feedback/quartz.js +99 -0
  166. package/dist/esm/feedback/send.d.ts +3 -0
  167. package/dist/esm/feedback/send.js +28 -5
  168. package/dist/esm/feedback/styles.d.ts +10 -0
  169. package/dist/esm/feedback/styles.js +4 -0
  170. package/dist/esm/feedback/template.d.ts +1 -1
  171. package/dist/esm/feedback/template.js +12 -12
  172. package/dist/esm/feedback/ui.d.ts +14 -6
  173. package/dist/esm/feedback/ui.js +126 -49
  174. package/dist/esm/heatmap/send.js +1 -1
  175. package/dist/esm/heatmap/track.d.ts +1 -1
  176. package/dist/esm/heatmap/track.js +87 -16
  177. package/dist/esm/index.d.ts +17 -63
  178. package/dist/esm/index.js +108 -80
  179. package/dist/esm/lifecycle.d.ts +8 -1
  180. package/dist/esm/lifecycle.js +266 -71
  181. package/dist/esm/remoteconfig/country.d.ts +4 -0
  182. package/dist/esm/remoteconfig/country.js +70 -0
  183. package/dist/esm/remoteconfig/custom.d.ts +7 -7
  184. package/dist/esm/remoteconfig/custom.js +32 -52
  185. package/dist/esm/remoteconfig/evaluate.d.ts +3 -3
  186. package/dist/esm/remoteconfig/evaluate.js +57 -44
  187. package/dist/esm/remoteconfig/fetch.d.ts +3 -3
  188. package/dist/esm/remoteconfig/fetch.js +9 -23
  189. package/dist/esm/remoteconfig/index.d.ts +10 -8
  190. package/dist/esm/remoteconfig/index.js +66 -40
  191. package/dist/esm/remoteconfig/store.js +1 -1
  192. package/dist/esm/remoteconfig/tz-countries.d.ts +8 -0
  193. package/dist/esm/remoteconfig/tz-countries.js +11 -0
  194. package/dist/esm/remotelog/gate.d.ts +2 -11
  195. package/dist/esm/remotelog/gate.js +10 -32
  196. package/dist/esm/remotelog/index.d.ts +4 -21
  197. package/dist/esm/remotelog/logger.d.ts +11 -17
  198. package/dist/esm/remotelog/logger.js +32 -60
  199. package/dist/esm/remotelog/send.js +12 -12
  200. package/dist/esm/remotelogger/index.d.ts +12 -0
  201. package/dist/esm/remotelogger/index.js +13 -0
  202. package/dist/esm/scheduler.js +2 -2
  203. package/dist/esm/types.d.ts +155 -82
  204. package/dist/esm/user/index.js +12 -6
  205. package/dist/feedback.esm.min.js +2 -2
  206. package/dist/feedback.esm.min.js.map +1 -1
  207. package/package.json +14 -16
  208. package/dist/chunks/batch-BU_mTpm1.min.js +0 -3
  209. package/dist/chunks/batch-BU_mTpm1.min.js.map +0 -1
  210. package/dist/chunks/logs-Bea5zUW_.min.js +0 -3
  211. package/dist/chunks/logs-Bea5zUW_.min.js.map +0 -1
  212. package/dist/cjs/heatmap/index.d.ts +0 -16
  213. package/dist/cjs/heatmap/index.js +0 -22
  214. package/dist/cjs/remotelog/index.js +0 -55
  215. package/dist/esm/heatmap/index.d.ts +0 -16
  216. package/dist/esm/heatmap/index.js +0 -17
  217. package/dist/esm/remotelog/index.js +0 -51
  218. package/dist/heatmap.esm.min.js +0 -3
  219. package/dist/heatmap.esm.min.js.map +0 -1
  220. package/dist/style.css +0 -1
@@ -1,23 +1,23 @@
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.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  // Feedback modal markup (moved from js/apptics.js).
3
- const feedbackUIHtml = `<div id="zasdkFeedbackconatiner" class="zasdk-modal-content">
3
+ const feedbackUIHtml = `<div id="zasdkFeedbackconatiner" class="zasdk-modal-content" role="dialog" aria-modal="true" aria-labelledby="zasdkFeedbackTitle">
4
4
  <div class="zasdk-header">
5
- <h2 class="zasdk-title">Share feedback</h2>
6
- <span id="appticsfeedbackclose" class="zasdk-close"><svg viewBox="0 0 24 24" style=" width: 20px; "><path d="M19.92,19.08c.23.23.23.61,0,.85-.12.12-.27.18-.42.18s-.31-.06-.42-.18l-7.08-7.08-7.08,7.08c-.12.12-.27.18-.42.18s-.31-.06-.42-.18c-.23-.23-.23-.61,0-.85l7.08-7.08-7.08-7.08c-.23-.23-.23-.61,0-.85s.61-.23.85,0l7.08,7.08,7.08-7.08c.23-.23.61-.23.85,0s.23.61,0,.85l-7.08,7.08,7.08,7.08Z"/></svg></span>
5
+ <h2 id="zasdkFeedbackTitle" class="zasdk-title">Share feedback</h2>
6
+ <span id="appticsfeedbackclose" class="zasdk-close" role="button" tabindex="0" aria-label="Close"><svg viewBox="0 0 24 24" style=" width: 20px; "><path d="M19.92,19.08c.23.23.23.61,0,.85-.12.12-.27.18-.42.18s-.31-.06-.42-.18l-7.08-7.08-7.08,7.08c-.12.12-.27.18-.42.18s-.31-.06-.42-.18c-.23-.23-.23-.61,0-.85l7.08-7.08-7.08-7.08c-.23-.23-.23-.61,0-.85s.61-.23.85,0l7.08,7.08,7.08-7.08c.23-.23.61-.23.85,0s.23.61,0,.85l-7.08,7.08,7.08,7.08Z"/></svg></span>
7
7
  </div>
8
8
  <div class="zasdk-feedback-types" data-type="">
9
- <div class="zasdk-feedback-type zasdk-selected" data-type="bug">
10
- <div class="zasdk-iconcnt zasdkfeedback__icon-report">
11
- <i class="zasdkfeedback__icon"><svg viewBox="0 0 24 24"><path d="M15.6,6.58c-.13-.37-.3-.7-.5-.97l1.23-1.18c.24-.23.25-.61.02-.85-.23-.24-.61-.25-.85-.02l-1.26,1.21c-.66-.45-1.37-.62-1.79-.68-.25-.04-.51-.04-.76-.02-.83.08-1.45.35-1.93.7l-1.22-1.2c-.24-.23-.62-.23-.85,0-.23.24-.23.62,0,.85l1.21,1.19c-.24.34-.41.68-.51.96-2.02,1.37-3.27,3.82-3.27,6.44,0,4.18,3.08,7.58,6.87,7.58s6.87-3.4,6.87-7.58c0-2.62-1.25-5.06-3.26-6.44ZM11.82,5.27c.15-.02.31-.01.47.01.69.1,1.86.48,2.26,1.9-.17.17-.51.44-1.14.65-1.08.36-2.31.28-3.36-.23-.24-.11-.44-.23-.6-.36,0-.01,0-.03.01-.04.18-.65.73-1.77,2.36-1.93ZM12,19.4c-3.12,0-5.67-2.86-5.67-6.38,0-1.98.82-3.82,2.19-5.02.26.25.59.48,1.01.68.78.38,1.65.57,2.5.57.6,0,1.19-.09,1.76-.28.88-.29,1.39-.7,1.67-1,1.38,1.2,2.21,3.06,2.21,5.05,0,3.52-2.54,6.38-5.67,6.38ZM9.12,9.86c-.92,0-1.67.75-1.67,1.67s.75,1.67,1.67,1.67,1.67-.75,1.67-1.67-.75-1.67-1.67-1.67ZM9.12,11.99c-.26,0-.47-.21-.47-.47s.21-.47.47-.47.47.21.47.47-.21.47-.47.47ZM14.88,9.86c-.92,0-1.67.75-1.67,1.67s.75,1.67,1.67,1.67,1.67-.75,1.67-1.67-.75-1.67-1.67-1.67ZM14.88,11.99c-.26,0-.47-.21-.47-.47s.21-.47.47-.47.47.21.47.47-.21.47-.47.47ZM12,14.49c-.92,0-1.67.75-1.67,1.67s.75,1.67,1.67,1.67,1.67-.75,1.67-1.67-.75-1.67-1.67-1.67ZM12,16.62c-.26,0-.47-.21-.47-.47s.21-.47.47-.47.47.21.47.47-.21.47-.47.47Z"/></svg></i>
12
- </div>
13
- <div>Bug</div>
14
- </div>
15
- <div class="zasdk-feedback-type" data-type="feedback">
9
+ <div class="zasdk-feedback-type zasdk-selected" data-type="feedback">
16
10
  <div class="zasdk-iconcnt zasdkfeedback__icon-reqest">
17
11
  <i class="zasdkfeedback__icon"><svg viewBox="0 0 24 24"><path d="M6.69,9.25h10.81c.41,0,.75-.34.75-.75s-.34-.75-.75-.75H6.69c-.41,0-.75.34-.75.75s.34.75.75.75Z"/><path d="M6.69,13.07h8.11c.41,0,.75-.34.75-.75s-.34-.75-.75-.75H6.69c-.41,0-.75.34-.75.75s.34.75.75.75Z"/><path d="M20.72,5.17c0-.68-.55-1.23-1.23-1.23H4.48c-.68,0-1.23.55-1.23,1.23v11.84c0,.68.55,1.23,1.23,1.23h13.49l1.25,1.51c.17.2.41.31.67.31.1,0,.2-.02.3-.05.34-.13.57-.46.56-.83l-.03-14.01ZM19.22,17.39l-.17-.2c-.24-.29-.58-.45-.95-.45H4.75V5.44h14.47v11.95Z"/></svg></i>
18
12
  </div>
19
13
  <div>Feedback</div>
20
14
  </div>
15
+ <div class="zasdk-feedback-type" data-type="bug">
16
+ <div class="zasdk-iconcnt zasdkfeedback__icon-report">
17
+ <i class="zasdkfeedback__icon"><svg viewBox="0 0 24 24"><path d="M15.6,6.58c-.13-.37-.3-.7-.5-.97l1.23-1.18c.24-.23.25-.61.02-.85-.23-.24-.61-.25-.85-.02l-1.26,1.21c-.66-.45-1.37-.62-1.79-.68-.25-.04-.51-.04-.76-.02-.83.08-1.45.35-1.93.7l-1.22-1.2c-.24-.23-.62-.23-.85,0-.23.24-.23.62,0,.85l1.21,1.19c-.24.34-.41.68-.51.96-2.02,1.37-3.27,3.82-3.27,6.44,0,4.18,3.08,7.58,6.87,7.58s6.87-3.4,6.87-7.58c0-2.62-1.25-5.06-3.26-6.44ZM11.82,5.27c.15-.02.31-.01.47.01.69.1,1.86.48,2.26,1.9-.17.17-.51.44-1.14.65-1.08.36-2.31.28-3.36-.23-.24-.11-.44-.23-.6-.36,0-.01,0-.03.01-.04.18-.65.73-1.77,2.36-1.93ZM12,19.4c-3.12,0-5.67-2.86-5.67-6.38,0-1.98.82-3.82,2.19-5.02.26.25.59.48,1.01.68.78.38,1.65.57,2.5.57.6,0,1.19-.09,1.76-.28.88-.29,1.39-.7,1.67-1,1.38,1.2,2.21,3.06,2.21,5.05,0,3.52-2.54,6.38-5.67,6.38ZM9.12,9.86c-.92,0-1.67.75-1.67,1.67s.75,1.67,1.67,1.67,1.67-.75,1.67-1.67-.75-1.67-1.67-1.67ZM9.12,11.99c-.26,0-.47-.21-.47-.47s.21-.47.47-.47.47.21.47.47-.21.47-.47.47ZM14.88,9.86c-.92,0-1.67.75-1.67,1.67s.75,1.67,1.67,1.67,1.67-.75,1.67-1.67-.75-1.67-1.67-1.67ZM14.88,11.99c-.26,0-.47-.21-.47-.47s.21-.47.47-.47.47.21.47.47-.21.47-.47.47ZM12,14.49c-.92,0-1.67.75-1.67,1.67s.75,1.67,1.67,1.67,1.67-.75,1.67-1.67-.75-1.67-1.67-1.67ZM12,16.62c-.26,0-.47-.21-.47-.47s.21-.47.47-.47.47.21.47.47-.21.47-.47.47Z"/></svg></i>
18
+ </div>
19
+ <div>Bug</div>
20
+ </div>
21
21
  <div class="zasdk-feedback-type" data-type="help">
22
22
  <div class="zasdk-iconcnt zasdkfeedback__icon-help">
23
23
  <i class="zasdkfeedback__icon"><svg viewBox="0 0 24 24"><path d="M12.45,16.47c-.33,0-.6-.27-.6-.6v-2.7c0-.43.25-.82.64-.99.95-.42,3.15-1.62,3.15-3.51,0-1.6-1.01-3.03-2.51-3.55-.95-.33-1.97-.28-2.87.16-.91.43-1.59,1.2-1.92,2.14-.11.31-.45.48-.77.37-.31-.11-.48-.45-.37-.77.44-1.25,1.34-2.25,2.54-2.83,1.2-.57,2.54-.65,3.79-.21,1.99.7,3.32,2.58,3.31,4.69,0,2.46-2.34,3.91-3.79,4.57v2.63c0,.33-.27.6-.6.6ZM13.21,19.1c0-.66-.54-1.2-1.2-1.2h-.03c-.66,0-1.19.54-1.19,1.2s.55,1.2,1.21,1.2,1.2-.54,1.2-1.2Z"/></svg></i>
@@ -42,7 +42,7 @@ const feedbackUIHtml = `<div id="zasdkFeedbackconatiner" class="zasdk-modal-cont
42
42
  <ul id="zasdkEmailList" class="zasdk-select-list"></ul>
43
43
  </div>
44
44
  </div>
45
- <label class="zasdkdesclbl" for="zasdkDescription">Add details here<span class="zasdkmadfeld">*</span> <span class="zaleftcharspan"><span class="zaleftcharcnt">5000</span><span class="zaleftchartxt">character left</span></span></label>
45
+ <label class="zasdkdesclbl" for="zasdkDescription">Add details here<span class="zasdkmadfeld">*</span> <span class="zaleftcharspan"><span class="zaleftcharcnt">5000</span><span class="zaleftchartxt">characters left</span></span></label>
46
46
  <textarea id="zasdkDescription" name="description" placeholder="Please provide more details for us to help you better." reqname="name" maxlength="5000"></textarea>
47
47
  <div id="zasdkreccheckcnt" class="zasdkqz-container">
48
48
  <div class="zasdkqz-checkbox-wrapper">
@@ -1,8 +1,14 @@
1
- import type { FeedbackType } from '../types.js';
2
- export declare function sendFeedback(feedbackType?: FeedbackType, feedbackMessage?: string, attachments?: FileList | File[] | null, logsFiles?: FileList | File[] | null, includeDyninfo?: boolean, includeLog?: boolean): Promise<void>;
3
- export declare function feedbackOpen(type?: FeedbackType, message?: string, includeLog?: boolean, includeDyninfo?: boolean, attachments?: FileList | File[] | null, logFiles?: FileList | File[] | null, isAnonymous?: boolean): void;
4
- export declare function feedbackClose(): void;
5
- /** What feedbackOpen() may pre-set on the form. */
1
+ import type { FeedbackOpenOptions as PublicFeedbackOpenOptions, FeedbackType, SendFeedbackOptions } from '../types.js';
2
+ export declare function sendFeedback(options?: SendFeedbackOptions): Promise<void>;
3
+ export declare function feedbackFormOpen(options?: PublicFeedbackOpenOptions): void;
4
+ /**
5
+ * Sets the form's theme, for a page with its own light and dark modes: 'auto' follows the
6
+ * operating system, which is not what such a page shows. Restyles a form or recording timer that
7
+ * is open now, and every one opened after; Apptics.init()'s feedback_theme only sets the first.
8
+ */
9
+ export declare function setFeedbackTheme(theme: 'light' | 'dark' | 'auto'): void;
10
+ export declare function feedbackFormClose(): void;
11
+ /** What the form is built with, from the options feedbackFormOpen() was given. */
6
12
  export interface FeedbackOpenOptions {
7
13
  type?: FeedbackType;
8
14
  message?: string;
@@ -29,7 +35,7 @@ export interface FeedbackUI {
29
35
  timerInterval: ReturnType<typeof setInterval> | null;
30
36
  uploadTotalSize: number;
31
37
  MaxFileSize: number;
32
- /** What the last feedbackOpen() asked for; the form reads it as it is built. */
38
+ /** What the last feedbackFormOpen() asked for; the form reads it as it is built. */
33
39
  _opts: FeedbackOpenOptions;
34
40
  init(opts?: FeedbackOpenOptions): void;
35
41
  updateLeftCount(): void;
@@ -37,6 +43,8 @@ export interface FeedbackUI {
37
43
  handleErrorQuartzEvent(event: Event): void;
38
44
  bindQuartzEvent(event: Event): void;
39
45
  close(): void;
46
+ /** Escape closes the form; listened for from open to close. */
47
+ onEscape(e: KeyboardEvent): void;
40
48
  toggleWindowAnimation(): void;
41
49
  fileAttachment(): void;
42
50
  elementCreator<K extends keyof HTMLElementTagNameMap>(elType: K): HTMLElementTagNameMap[K];
@@ -1,12 +1,15 @@
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.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  import { AP_TRACKING_STATUS } from '../core/constants.js';
3
3
  import { _ZAP } from '../core/state.js';
4
- import { Console } from '../core/logger.js';
4
+ import { Console, warnAlways } from '../core/logger.js';
5
5
  import { isEmpty, isEmptyObj } from '../core/utils.js';
6
6
  import { opt_in_status } from '../core/consent.js';
7
7
  import { timerHtml, feedbackUIHtml } from './template.js';
8
8
  import { sendFeedbackData } from './send.js';
9
- import { wireDrag, wireUserPicker, wireLogControls, logChoice, userChoice } from './controls.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';
10
13
 
11
14
  // Quartz is an optional page-level SDK. Without it every call is a no-op (fix #5).
12
15
  const QUARTZ_NOOP = {
@@ -46,25 +49,45 @@ function submitFeedback(dataobj) {
46
49
  return result;
47
50
  });
48
51
  }
49
- function sendFeedback(feedbackType, feedbackMessage, attachments, logsFiles, includeDyninfo, includeLog) {
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 || {};
50
65
  const dataobj = {
51
- type: !isEmpty(feedbackType) ? feedbackType : 1,
52
- message: feedbackMessage || '', // no i18n
53
- attachment: attachments || null,
54
- logsFiles: logsFiles || null,
66
+ type: !isEmpty(o.type) ? o.type : 1,
67
+ message: o.message || '', // no i18n
68
+ attachment: o.attachments || null,
69
+ logsFiles: o.logFiles || null,
55
70
  // both flags stay as given: unset lets send.ts decide from what is actually stored
56
- includeDyninfo: includeDyninfo,
57
- includeLog: includeLog,
71
+ includeDyninfo: o.includeDiagnostics,
72
+ includeLog: o.includeLog,
58
73
  quartzid: '' // no i18n
59
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);
60
77
  // an app awaiting this must be able to tell its user the feedback did not go: resolving on a
61
78
  // failure would have it say "thanks, sent" for a report the server never received
62
79
  return submitFeedback(dataobj).then(function (result) {
80
+ restoreUser();
81
+ return result;
82
+ }, function (err) {
83
+ restoreUser();
84
+ throw err;
85
+ }).then(function (result) {
63
86
  if (!result) {
64
- throw new Error('apptics.sendFeedback: not sent, the browser is offline or Apptics is disabled for this client'); // no i18n
87
+ throw new Error('AppticsFeedback.sendFeedback: not sent, the browser is offline or Apptics is disabled for this client'); // no i18n
65
88
  }
66
89
  if (!result.ok) {
67
- throw new Error('apptics.sendFeedback: not sent, ' + result.message); // no i18n
90
+ throw new Error('AppticsFeedback.sendFeedback: not sent, ' + result.message); // no i18n
68
91
  }
69
92
  });
70
93
  }
@@ -109,23 +132,54 @@ function newTransfer() {
109
132
  return null;
110
133
  }
111
134
  }
112
- function feedbackOpen(type, message, includeLog, includeDyninfo, attachments, logFiles, isAnonymous) {
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 : {};
113
142
  const opts = {
114
- includeLog: includeLog === true,
115
- includeDyninfo: includeDyninfo === true,
116
- isAnonymous: isAnonymous === true,
143
+ includeLog: o.includeLog === true,
144
+ includeDyninfo: o.includeDiagnostics === true,
145
+ isAnonymous: o.isAnonymous === true,
117
146
  };
118
- if (typeof type === 'number')
119
- opts.type = type; // no i18n
120
- if (typeof message === 'string' && message.length > 0)
121
- opts.message = message; // no i18n
122
- if (attachments && attachments.length > 0)
123
- opts.attachments = attachments;
124
- if (logFiles && logFiles.length > 0)
125
- opts.logFiles = logFiles;
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);
126
157
  feedback.init(opts);
127
158
  }
128
- function feedbackClose() {
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() {
129
183
  feedback.close();
130
184
  }
131
185
  const feedback = {
@@ -156,25 +210,15 @@ const feedback = {
156
210
  feedback.uploadFileAry = [];
157
211
  tempContainer.id = 'zasdkFeedbackModal'; // no i18n
158
212
  tempContainer.className = 'zasdk-modal'; // no i18n
213
+ tempContainer.setAttribute('data-zasdk-theme', _ZAP._config.feedback_theme); // no i18n
159
214
  tempContainer.innerHTML = feedback.feedbackUIHtml;
160
215
  document.body.appendChild(tempContainer);
161
216
  var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
162
- var defaultoption = _ZAP._defaultoptions;
163
- var qz_ws_key = defaultoption.quartz_workspace_key;
164
- var qz_dp_key = defaultoption.quartz_department_key;
165
- var quartz_DC = {
166
- "Local": "https://quartz.localzoho.com", // no i18n
167
- "US": "https://quartz.zoho.com", // no i18n
168
- "EU": "https://quartz.zoho.eu", // no i18n
169
- "IN": "https://quartz.zoho.in", // no i18n
170
- "AU": "https://quartz.zoho.com.au", // no i18n
171
- "CN": "https://quartz.zoho.com.cn", // no i18n
172
- "CA": "https://quartz.zohocloud.ca", // no i18n
173
- "JP": "https://quartz.zoho.jp", // no i18n
174
- "SA": "https://quartz.zoho.sa", // no i18n
175
- "AE": "https://quartz.zoho.ae" // no i18n
176
- };
177
- var qz_dc_key = (!isEmpty(defaultoption.DC) && defaultoption.DC !== '-') ? (quartz_DC[defaultoption.DC] || '') : ''; // 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);
178
222
  var closeBtn = modal.querySelector("#appticsfeedbackclose"); // no i18n
179
223
  var feedbackTypes = modal.querySelectorAll(".zasdk-feedback-type"); // no i18n
180
224
  feedback.fileInput = modal.querySelector("#zasdkFileInput"); // no i18n
@@ -197,12 +241,21 @@ const feedback = {
197
241
  document.addEventListener('quartz-feedback-state', feedback.bindQuartzEvent); // no i18n
198
242
  document.removeEventListener('quartz-feedback-error', feedback.handleErrorQuartzEvent); // no i18n
199
243
  document.addEventListener('quartz-feedback-error', feedback.handleErrorQuartzEvent); // no i18n
200
- // the consent checkbox and its label only when a recording can actually be made: the Quartz
201
- // script on the page, a DC it knows, and both keys. "-" for any of them turns it off; DC "-"
202
- // has already become '' above. A checkbox that leads only to "unavailable" is not offered
203
- var recordingAvailable = hasQuartz() && !isEmpty(qz_dc_key)
204
- && !isEmpty(qz_ws_key) && qz_ws_key !== "-" && !isEmpty(qz_dp_key) && qz_dp_key !== "-"; // no i18n
205
- modal.querySelector("#zasdkreccheckcnt").style.display = recordingAvailable ? "block" : "none"; // 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
+ }
206
259
  feedbackbox.addEventListener('transitionend', function (event) {
207
260
  if (event.propertyName === 'transform' && feedback.isScaled) { // no i18n
208
261
  feedback.toggleWindowAnimation();
@@ -231,6 +284,14 @@ const feedback = {
231
284
  closeBtn.onclick = function () {
232
285
  feedback.close();
233
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
234
295
  preivewButton.addEventListener('click', function () {
235
296
  quartz().previewVideo();
236
297
  });
@@ -281,6 +342,11 @@ const feedback = {
281
342
  }
282
343
  });
283
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 */ }
284
350
  feedbackTypes.forEach(function (type) {
285
351
  type.addEventListener("click", function () {
286
352
  feedbackTypes.forEach(function (t) {
@@ -289,7 +355,7 @@ const feedback = {
289
355
  this.classList.add("zasdk-selected"); // no i18n
290
356
  });
291
357
  });
292
- // what feedbackOpen() was given: select that type, fill the description
358
+ // what feedbackFormOpen() was given: select that type, fill the description
293
359
  if (typeof feedback._opts.type === 'number') { // no i18n
294
360
  var wanted = Object.keys(feedback.typeObj).filter(function (name) {
295
361
  return feedback.typeObj[name] === feedback._opts.type;
@@ -349,6 +415,10 @@ const feedback = {
349
415
  let counterElem = elem.parentElement ? elem.parentElement.querySelector(".zaleftcharcnt") : null; // no i18n
350
416
  if (counterElem) {
351
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
+ }
352
422
  }
353
423
  });
354
424
  },
@@ -392,6 +462,7 @@ const feedback = {
392
462
  const tempDiv = document.createElement("div"); // no i18n
393
463
  tempDiv.innerHTML = feedback.timerHtml;
394
464
  const node = tempDiv.firstElementChild;
465
+ node.setAttribute('data-zasdk-theme', _ZAP._config.feedback_theme); // no i18n
395
466
  document.body.appendChild(node);
396
467
  var feedbacktimer = document.getElementById("zasdkrectimer"); // no i18n
397
468
  feedback.timerDisplay = feedbacktimer.querySelector('#zasdkTimerDisplay'); // no i18n
@@ -404,8 +475,14 @@ const feedback = {
404
475
  feedback.toggleWindowAnimation();
405
476
  }
406
477
  },
478
+ onEscape: function (e) {
479
+ if (e.key === 'Escape') { // no i18n
480
+ feedback.close();
481
+ }
482
+ },
407
483
  close: function () {
408
484
  var modal = document.getElementById("zasdkFeedbackModal"); // no i18n
485
+ document.removeEventListener('keydown', feedback.onEscape); // no i18n
409
486
  document.removeEventListener('quartz-feedback-state', feedback.bindQuartzEvent); // no i18n
410
487
  quartz().clearFeedback();
411
488
  if (!isEmpty(modal)) {
@@ -623,4 +700,4 @@ const feedback = {
623
700
  }
624
701
  };
625
702
 
626
- export { feedback, feedbackClose, feedbackOpen, sendFeedback };
703
+ export { feedback, feedbackFormClose, feedbackFormOpen, sendFeedback, setFeedbackTheme };
@@ -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.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  import { _ZAP } from '../core/state.js';
3
3
  import { Console, warnAlways } from '../core/logger.js';
4
4
  import { cloneObject } from '../core/utils.js';
@@ -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;
@@ -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.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  import { AP_LOG_MODULE, AP_CONFIG, AP_TRACKING_STATUS } from '../core/constants.js';
3
3
  import { getConfig, _ZAP } from '../core/state.js';
4
4
  import { Console, logFailure } from '../core/logger.js';
@@ -22,6 +22,12 @@ import { noteDebugActivity } from '../core/debug.js';
22
22
  */
23
23
  /** How long the page must be still before a scroll burst counts as one finished gesture. */
24
24
  const SCROLL_IDLE_MS = 150;
25
+ /**
26
+ * How much of the viewport, each way, an element must cover for its scrolling to be the page's.
27
+ * An app whose layout scrolls a content pane instead of the window (most dashboards do) still
28
+ * gets a scroll map; a dropdown list or a small table scrolling on its own is not the page moving.
29
+ */
30
+ const PAGE_SCROLLER_SHARE = 0.5;
25
31
  /** Clicks closer than this in time and space count as one angry repetition. */
26
32
  const RAGE_WINDOW_MS = 1000;
27
33
  const RAGE_RADIUS_PX = 30;
@@ -40,6 +46,10 @@ var scrollStart = 0;
40
46
  var scrollStartX = 0;
41
47
  var scrollStartY = 0;
42
48
  var scrollTimer = null;
49
+ /** What the gesture in progress scrolls: null for the window, else the page's content pane. */
50
+ var scrolling = null;
51
+ /** Where each content pane was after its last gesture, as lastX / lastY are for the window. */
52
+ var paneAt = new WeakMap();
43
53
  /**
44
54
  * Where the page was before the current gesture began.
45
55
  *
@@ -122,7 +132,7 @@ function labelFor(node) {
122
132
  if (!node) {
123
133
  return ''; // no i18n
124
134
  }
125
- var attributes = ['data-ap-label', 'apeventaction', 'aria-label', 'name', 'id', 'title']; // no i18n
135
+ var attributes = ['data-ap-label', 'apeventaction', 'data-apeventaction', 'aria-label', 'name', 'id', 'title']; // no i18n
126
136
  for (var i = 0; i < attributes.length; i++) {
127
137
  var value = node.getAttribute ? node.getAttribute(attributes[i]) : null;
128
138
  if (!isEmpty(value)) {
@@ -278,14 +288,57 @@ function watchForDeadClick(record, target) {
278
288
  }
279
289
  }, DEAD_CLICK_MS);
280
290
  }
281
- function onScroll() {
291
+ /**
292
+ * What a scroll event moved, as a gesture counts it: null for the window (the event's target is
293
+ * the document), the element when it is big enough to be the page's own scrolling, and undefined
294
+ * for anything smaller, which is not recorded.
295
+ */
296
+ function scrollerOf(target) {
297
+ var doc = document;
298
+ // the window and the document are not elements: either is the page itself scrolling
299
+ if (!target || target.nodeType !== 1 || target === doc.documentElement || target === doc.body) {
300
+ return null;
301
+ }
302
+ var el = target;
303
+ var big = el.clientHeight >= (window.innerHeight || 0) * PAGE_SCROLLER_SHARE
304
+ && el.clientWidth >= viewportWidth() * PAGE_SCROLLER_SHARE;
305
+ return big ? el : undefined;
306
+ }
307
+ /** Where a scroller is now. */
308
+ function positionOf(scroller) {
309
+ return scroller === null
310
+ ? { x: Math.round(window.scrollX || window.pageXOffset || 0), y: Math.round(window.scrollY || window.pageYOffset || 0) }
311
+ : { x: Math.round(scroller.scrollLeft || 0), y: Math.round(scroller.scrollTop || 0) };
312
+ }
313
+ /**
314
+ * Where a scroller was before this gesture: what the last one left. A content pane seen for the
315
+ * first time is taken to have been at its top, which is where a pane starts.
316
+ */
317
+ function startOf(scroller) {
318
+ if (scroller === null) {
319
+ return { x: lastX, y: lastY };
320
+ }
321
+ return paneAt.get(scroller) || { x: 0, y: 0 };
322
+ }
323
+ function onScroll(event) {
282
324
  if (!canTrackHeatmap('heatmap') || !underCap()) { // no i18n
283
325
  return;
284
326
  }
327
+ var scroller = scrollerOf(event ? event.target : null);
328
+ if (scroller === undefined) {
329
+ return;
330
+ }
331
+ if (scrollTimer !== null && scroller !== scrolling) {
332
+ // another scroller started moving: the gesture on the first one is over
333
+ clearTimeout(scrollTimer);
334
+ endScrollGesture();
335
+ }
285
336
  if (scrollTimer === null) {
337
+ scrolling = scroller;
338
+ var start = startOf(scroller);
286
339
  scrollStart = nowMs();
287
- scrollStartX = lastX;
288
- scrollStartY = lastY;
340
+ scrollStartX = start.x;
341
+ scrollStartY = start.y;
289
342
  }
290
343
  else {
291
344
  clearTimeout(scrollTimer);
@@ -295,13 +348,21 @@ function onScroll() {
295
348
  /** One record for the whole burst, once the page has been still for SCROLL_IDLE_MS. */
296
349
  function endScrollGesture() {
297
350
  scrollTimer = null;
351
+ var scroller = scrolling;
352
+ scrolling = null;
298
353
  try {
299
- var endX = Math.round(window.scrollX || 0);
300
- var endY = Math.round(window.scrollY || 0);
354
+ var end = positionOf(scroller);
355
+ var endX = end.x;
356
+ var endY = end.y;
301
357
  var dx = endX - scrollStartX;
302
358
  var dy = endY - scrollStartY;
303
- lastX = endX;
304
- lastY = endY;
359
+ if (scroller === null) {
360
+ lastX = endX;
361
+ lastY = endY;
362
+ }
363
+ else {
364
+ paneAt.set(scroller, end);
365
+ }
305
366
  if (dx === 0 && dy === 0) {
306
367
  return;
307
368
  }
@@ -310,8 +371,14 @@ function endScrollGesture() {
310
371
  var direction = Math.abs(dy) >= Math.abs(dx)
311
372
  ? (dy > 0 ? 'down-scroll' : 'up-scroll') // no i18n
312
373
  : (dx > 0 ? 'right-scroll' : 'left-scroll'); // no i18n
313
- var height = contentHeight() || 1;
314
- store(Object.assign(common(), {
374
+ // the depth is of what scrolled: the document, or the content pane and its own content
375
+ var height = (scroller === null ? contentHeight() : scroller.scrollHeight) || 1;
376
+ var visible = scroller === null ? (window.innerHeight || 0) : scroller.clientHeight;
377
+ store(Object.assign(common(), scroller === null ? {} : {
378
+ content_height: scroller.scrollHeight,
379
+ scroll_offset_x: endX,
380
+ scroll_offset_y: endY,
381
+ }, {
315
382
  // the server accepts only event|default|buttonclick here; what kind of movement it
316
383
  // was belongs in gesture_type. input_type is left off rather than invented: a wheel
317
384
  // carries no pointer type, and the intended vocabulary has no value for "unknown"
@@ -324,7 +391,7 @@ function endScrollGesture() {
324
391
  coordinate_y: endY,
325
392
  normalized_x: 0,
326
393
  // how far down the page the gesture left them, which is what a scroll map reads
327
- normalized_y: fraction(endY + (window.innerHeight || 0), height),
394
+ normalized_y: fraction(endY + visible, height),
328
395
  velocity: Math.round((distance / duration) * 1000),
329
396
  is_clickable: 0,
330
397
  is_rage_click: 0,
@@ -336,7 +403,7 @@ function endScrollGesture() {
336
403
  }
337
404
  }
338
405
  /** Turns capture on or off. Listeners are passive, so they never delay a click or a scroll. */
339
- function enableHeatmap(status) {
406
+ function trackHeatmap(status) {
340
407
  var wanted = typeof status === 'boolean' ? status : true; // no i18n
341
408
  if (wanted === installed) {
342
409
  return;
@@ -353,10 +420,13 @@ function enableHeatmap(status) {
353
420
  }
354
421
  window.removeEventListener('pointerdown', onPointerDown, true); // no i18n
355
422
  window.removeEventListener('scroll', onScroll, true); // no i18n
423
+ // a gesture still settling when capture stops (a single-page app leaving a heatmap page) is
424
+ // recorded as it stands, not dropped: it was the visitor's last scroll on that page
356
425
  if (scrollTimer !== null) {
357
426
  clearTimeout(scrollTimer);
358
- scrollTimer = null;
427
+ endScrollGesture();
359
428
  }
429
+ scrolling = null;
360
430
  installed = false;
361
431
  Console.log('apptics.heatmap: capture stopped'); // no i18n
362
432
  }
@@ -366,9 +436,10 @@ function resetHeatmapSession() {
366
436
  recentClicks = [];
367
437
  lastX = 0;
368
438
  lastY = 0;
439
+ paneAt = new WeakMap();
369
440
  }
370
441
  // init() and reset() drive capture through these, so neither has to import this module
371
- hooks.enableHeatmap = enableHeatmap;
442
+ hooks.trackHeatmap = trackHeatmap;
372
443
  hooks.resetHeatmap = resetHeatmapSession;
373
444
 
374
- export { enableHeatmap, resetHeatmapSession };
445
+ export { resetHeatmapSession, trackHeatmap };