@dotcms/analytics 1.5.6 → 1.6.0-next.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -698,7 +698,7 @@ We offer multiple channels to get help with the dotCMS Analytics SDK:
698
698
  - **GitHub Issues**: For bug reports and feature requests, please [open an issue](https://github.com/dotCMS/core/issues/new/choose) in the GitHub repository.
699
699
  - **Community Forum**: Join our [community discussions](https://community.dotcms.com/) to ask questions and share solutions.
700
700
  - **Stack Overflow**: Use the tag `dotcms-analytics` when posting questions.
701
- - **Enterprise Support**: Enterprise customers can access premium support through the [dotCMS Support Portal](https://helpdesk.dotcms.com/support/).
701
+ - **Enterprise Support**: Enterprise customers can access premium support through the [dotCMS Support Portal](https://www.dotcms.com/support).
702
702
 
703
703
  When reporting issues, please include:
704
704
 
@@ -93,7 +93,10 @@ export interface DotCMSAnalyticsConfig {
93
93
  */
94
94
  logLevel?: LogLevel;
95
95
  /**
96
- * Automatically track page views when set to true.
96
+ * Automatically track page views. Defaults to `true` (opt-out).
97
+ * Set explicitly to `false` to disable automatic page view tracking.
98
+ * Via the HTML `data-analytics-auto-page-view` attribute, only the literal string "false"
99
+ * disables it (any other value, including "", enables it).
97
100
  */
98
101
  autoPageView?: boolean;
99
102
  /**
@@ -92,7 +92,9 @@ export interface AnalyticsConfigResult {
92
92
  * Always returns a config (with defaults if needed).
93
93
  *
94
94
  * - If no data-analytics-server attribute is found, uses the current domain as the server endpoint
95
- * - Both debug and autoPageView default to false (must be explicitly set to "true")
95
+ * - debug defaults to false (opt-in: must be explicitly set to "true")
96
+ * - autoPageView defaults to true (opt-out: only the literal string "false" disables it via
97
+ * `data-analytics-auto-page-view="false"`)
96
98
  *
97
99
  * @returns The analytics configuration object
98
100
  */
@@ -1,16 +1,16 @@
1
- import { jsx as o } from "react/jsx-runtime";
2
- import { Suspense as e, useMemo as i } from "react";
1
+ import { jsx as e } from "react/jsx-runtime";
2
+ import { Suspense as r, useMemo as a } from "react";
3
3
  import { useRouterTracker as l } from "../hook/useRouterTracker.js";
4
- import { initializeAnalytics as u } from "../internal/utils.js";
5
- function a({
4
+ import { initializeAnalytics as i } from "../internal/utils.js";
5
+ function u({
6
6
  config: t
7
7
  }) {
8
- const n = i(() => u(t), [t]), r = !!t.debug;
9
- return n && l(n, r), null;
8
+ const n = a(() => i(t), [t]), o = !!t.debug;
9
+ return l(n, o, t.autoPageView !== !1), null;
10
10
  }
11
- function p({ config: t }) {
12
- return /* @__PURE__ */ o(e, { fallback: null, children: /* @__PURE__ */ o(a, { config: t }) });
11
+ function f({ config: t }) {
12
+ return /* @__PURE__ */ e(r, { fallback: null, children: /* @__PURE__ */ e(u, { config: t }) });
13
13
  }
14
14
  export {
15
- p as DotContentAnalytics
15
+ f as DotContentAnalytics
16
16
  };
@@ -7,5 +7,6 @@ import { DotCMSAnalytics } from '../../core/shared/models';
7
7
  *
8
8
  * @param analytics Analytics singleton instance; if null, does nothing
9
9
  * @param debug When true, logs which tracking path is used
10
+ * @param enabled When false, tracking is disabled even if analytics is present (defaults to true)
10
11
  */
11
- export declare function useRouterTracker(analytics: DotCMSAnalytics | null, debug?: boolean): void;
12
+ export declare function useRouterTracker(analytics: DotCMSAnalytics | null, debug?: boolean, enabled?: boolean): void;
@@ -1,16 +1,16 @@
1
- import { usePathname as f, useSearchParams as u } from "next/navigation";
2
- import { useRef as i, useEffect as a } from "react";
3
- const m = (e, t) => `${e}${t?.toString() ? "?" + t.toString() : ""}`;
4
- function R(e, t = !1) {
5
- const r = i(null), n = f(), o = u();
6
- a(() => {
7
- if (!e) return;
8
- const c = (s) => {
9
- s !== r.current && (r.current = s, e.pageView());
1
+ import { usePathname as c, useSearchParams as i } from "next/navigation";
2
+ import { useRef as a, useEffect as m } from "react";
3
+ const p = (t, e) => `${t}${e?.toString() ? "?" + e.toString() : ""}`;
4
+ function h(t, e = !1, r = !0) {
5
+ const n = a(null), o = c(), u = i();
6
+ m(() => {
7
+ if (!r || !t) return;
8
+ const s = (f) => {
9
+ f !== n.current && (n.current = f, t.pageView());
10
10
  };
11
- t && console.info("DotCMS Analytics [React]: using Next.js App Router tracking"), c(m(n, o));
12
- }, [e, n, o, t]);
11
+ e && console.info("DotCMS Analytics [React]: using Next.js App Router tracking"), s(p(o, u));
12
+ }, [t, o, u, e, r]);
13
13
  }
14
14
  export {
15
- R as useRouterTracker
15
+ h as useRouterTracker
16
16
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotcms/analytics",
3
- "version": "1.5.6",
3
+ "version": "1.6.0-next.36",
4
4
  "description": "Official JavaScript library for Content Analytics with DotCMS.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,192 +1,196 @@
1
- import { UVEEventType as d } from "../../../types/src/lib/editor/public.js";
1
+ import { UVEEventType as u } from "../../../types/src/lib/editor/public.js";
2
2
  import { __DOTCMS_UVE_EVENT__ as f } from "../../../types/src/lib/events/internal.js";
3
- import { DOT_SECTION_ID_PREFIX as g } from "./constants.js";
4
- import { TEMP_EMPTY_CONTENTLET as C, TEMP_EMPTY_CONTENTLET_TYPE as w } from "./contentlet-sentinel.constants.js";
5
- import { findDotCMSElement as _, readContentletDataset as b, findDotCMSVTLData as L, getClosestDotCMSContainerData as O, getDotCMSPageBounds as N } from "../lib/dom/dom.utils.js";
6
- function M(s) {
7
- const e = (t) => {
8
- t.data.name === f.UVE_SET_PAGE_DATA && s(t.data.payload);
9
- };
10
- return window.addEventListener("message", e), {
3
+ import { DOT_SECTION_ID_PREFIX as S } from "./constants.js";
4
+ import { TEMP_EMPTY_CONTENTLET as _, TEMP_EMPTY_CONTENTLET_TYPE as p } from "./contentlet-sentinel.constants.js";
5
+ import { getNativeEventBinder as T, findDotCMSElement as L, readContentletDataset as O, findDotCMSVTLData as g, getClosestDotCMSContainerData as N, getDotCMSPageBounds as D } from "../lib/dom/dom.utils.js";
6
+ function R(a) {
7
+ const e = (o) => {
8
+ o.data.name === f.UVE_SET_PAGE_DATA && a(o.data.payload);
9
+ }, t = T(window);
10
+ return t.addEventListener("message", e), {
11
11
  unsubscribe: () => {
12
- window.removeEventListener("message", e);
12
+ t.removeEventListener("message", e);
13
13
  },
14
- event: d.CONTENT_CHANGES
14
+ event: u.CONTENT_CHANGES
15
15
  };
16
16
  }
17
- function P(s) {
18
- const e = (t) => {
19
- t.data.name === f.UVE_RELOAD_PAGE && s();
20
- };
21
- return window.addEventListener("message", e), {
17
+ function U(a) {
18
+ const e = (o) => {
19
+ o.data.name === f.UVE_RELOAD_PAGE && a();
20
+ }, t = T(window);
21
+ return t.addEventListener("message", e), {
22
22
  unsubscribe: () => {
23
- window.removeEventListener("message", e);
23
+ t.removeEventListener("message", e);
24
24
  },
25
- event: d.PAGE_RELOAD
25
+ event: u.PAGE_RELOAD
26
26
  };
27
27
  }
28
- const S = 100;
29
- function R(s) {
28
+ const w = 100;
29
+ function h(a) {
30
30
  let e = null, t = [];
31
- const a = () => {
31
+ const o = () => {
32
32
  const r = Array.from(
33
33
  document.querySelectorAll('[data-dot-object="container"]')
34
34
  );
35
- s(N(r));
35
+ a(D(r));
36
36
  }, n = () => {
37
37
  e !== null && clearTimeout(e), e = setTimeout(() => {
38
- e = null, a();
39
- }, S);
40
- }, o = new ResizeObserver(() => {
38
+ e = null, o();
39
+ }, w);
40
+ }, s = new ResizeObserver(() => {
41
41
  n();
42
- }), v = () => {
42
+ }), i = () => {
43
43
  for (const r of t)
44
- o.unobserve(r);
44
+ s.unobserve(r);
45
45
  t = Array.from(
46
46
  document.querySelectorAll('[data-dot-object="container"]')
47
- ), o.observe(document.documentElement);
47
+ ), s.observe(document.documentElement);
48
48
  for (const r of t)
49
- o.observe(r);
49
+ s.observe(r);
50
50
  };
51
- v();
52
- const c = (r) => {
53
- for (let i = 0; i < r.length; i++) {
54
- const m = r[i];
55
- if (m.nodeType !== Node.ELEMENT_NODE)
51
+ i();
52
+ const C = (r) => {
53
+ for (let c = 0; c < r.length; c++) {
54
+ const v = r[c];
55
+ if (v.nodeType !== Node.ELEMENT_NODE)
56
56
  continue;
57
- const T = m;
58
- if (T.matches?.('[data-dot-object="container"]') || T.querySelector?.('[data-dot-object="container"]'))
57
+ const b = v;
58
+ if (b.matches?.('[data-dot-object="container"]') || b.querySelector?.('[data-dot-object="container"]'))
59
59
  return !0;
60
60
  }
61
61
  return !1;
62
- }, l = new MutationObserver((r) => {
63
- for (const i of r)
64
- if (i.type === "childList" && (c(i.addedNodes) || c(i.removedNodes))) {
65
- v(), n();
62
+ }, d = new MutationObserver((r) => {
63
+ for (const c of r)
64
+ if (c.type === "childList" && (C(c.addedNodes) || C(c.removedNodes))) {
65
+ i(), n();
66
66
  return;
67
67
  }
68
68
  });
69
- l.observe(document.body ?? document.documentElement, {
69
+ d.observe(document.body ?? document.documentElement, {
70
70
  childList: !0,
71
71
  subtree: !0
72
72
  });
73
- const u = () => n();
74
- window.addEventListener("scroll", u, { passive: !0 });
75
- const E = (r) => {
76
- r?.data?.name === f.UVE_FLUSH_BOUNDS && (e !== null && (clearTimeout(e), e = null), a());
73
+ const l = T(window), E = () => n();
74
+ l.addEventListener("scroll", E, { passive: !0 });
75
+ const m = (r) => {
76
+ r?.data?.name === f.UVE_FLUSH_BOUNDS && (e !== null && (clearTimeout(e), e = null), o());
77
77
  };
78
- return window.addEventListener("message", E), {
78
+ return l.addEventListener("message", m), {
79
79
  unsubscribe: () => {
80
- e !== null && (clearTimeout(e), e = null), o.disconnect(), l.disconnect(), window.removeEventListener("scroll", u), window.removeEventListener("message", E), t = [];
80
+ e !== null && (clearTimeout(e), e = null), s.disconnect(), d.disconnect(), l.removeEventListener("scroll", E), l.removeEventListener("message", m), t = [];
81
81
  },
82
- event: d.AUTO_BOUNDS
82
+ event: u.AUTO_BOUNDS
83
83
  };
84
84
  }
85
- function U(s) {
86
- const e = (t) => {
87
- if (t.data.name === f.UVE_SCROLL_INSIDE_IFRAME) {
88
- const a = t.data.direction;
89
- s(a);
85
+ function V(a) {
86
+ const e = (o) => {
87
+ if (o.data.name === f.UVE_SCROLL_INSIDE_IFRAME) {
88
+ const n = o.data.direction;
89
+ a(n);
90
90
  }
91
- };
92
- return window.addEventListener("message", e), {
91
+ }, t = T(window);
92
+ return t.addEventListener("message", e), {
93
93
  unsubscribe: () => {
94
- window.removeEventListener("message", e);
94
+ t.removeEventListener("message", e);
95
95
  },
96
- event: d.IFRAME_SCROLL
96
+ event: u.IFRAME_SCROLL
97
97
  };
98
98
  }
99
- function h(s) {
100
- const e = (t) => {
101
- if (t.data.name !== f.UVE_SCROLL_TO_SECTION)
99
+ function k(a) {
100
+ const e = (o) => {
101
+ if (o.data.name !== f.UVE_SCROLL_TO_SECTION)
102
102
  return;
103
- const a = t.data.sectionIndex, n = document.querySelector(`#${g}${a}`) ?? document.querySelector(`#section-${a}`);
104
- n && s({ sectionIndex: a, offsetTop: n.offsetTop });
105
- };
106
- return window.addEventListener("message", e), {
103
+ const n = o.data.sectionIndex, s = document.querySelector(`#${S}${n}`) ?? document.querySelector(`#section-${n}`);
104
+ s && a({ sectionIndex: n, offsetTop: s.offsetTop });
105
+ }, t = T(window);
106
+ return t.addEventListener("message", e), {
107
107
  unsubscribe: () => {
108
- window.removeEventListener("message", e);
108
+ t.removeEventListener("message", e);
109
109
  },
110
- event: d.SCROLL_TO_SECTION
110
+ event: u.SCROLL_TO_SECTION
111
111
  };
112
112
  }
113
- function V(s) {
113
+ function B(a) {
114
114
  let e = !1;
115
- const t = (a) => {
116
- const n = _(a.target);
115
+ const t = (o) => {
116
+ const n = L(o.target);
117
117
  if (!n) {
118
- e && (e = !1, s(null));
118
+ e && (e = !1, a(null));
119
119
  return;
120
120
  }
121
- const { x: o, y: v, width: c, height: l } = n.getBoundingClientRect(), u = n.dataset?.dotObject === "container", E = {
122
- identifier: C,
123
- title: C,
124
- contentType: w,
121
+ const { x: s, y: i, width: C, height: d } = n.getBoundingClientRect(), l = n.dataset?.dotObject === "container", E = {
122
+ identifier: _,
123
+ title: _,
124
+ contentType: p,
125
125
  inode: "TEMPY_EMPTY_CONTENTLET_INODE",
126
- widgetTitle: C,
127
- baseType: C,
126
+ widgetTitle: _,
127
+ baseType: _,
128
128
  onNumberOfPages: 1
129
- }, r = b(n), i = L(n), m = {
129
+ }, m = O(n), r = g(n), c = {
130
130
  container: (
131
131
  // Here extract dot-container from contentlet if it is Headless
132
132
  // or search in parent container if it is VTL
133
- n.dataset?.dotContainer ? JSON.parse(n.dataset?.dotContainer) : O(n)
133
+ n.dataset?.dotContainer ? JSON.parse(n.dataset?.dotContainer) : N(n)
134
134
  ),
135
- contentlet: u ? E : r,
136
- vtlFiles: i
137
- }, T = {
138
- x: o,
139
- y: v,
140
- width: c,
141
- height: l,
142
- payload: m
135
+ contentlet: l ? E : m,
136
+ vtlFiles: r
137
+ }, v = {
138
+ x: s,
139
+ y: i,
140
+ width: C,
141
+ height: d,
142
+ payload: c
143
143
  };
144
- e = !0, s(T);
144
+ e = !0, a(v);
145
145
  };
146
- return document.addEventListener("pointermove", t), {
146
+ return document.documentElement.addEventListener("pointermove", t), {
147
147
  unsubscribe: () => {
148
- document.removeEventListener("pointermove", t);
148
+ document.documentElement.removeEventListener("pointermove", t);
149
149
  },
150
- event: d.CONTENTLET_HOVERED
150
+ event: u.CONTENTLET_HOVERED
151
151
  };
152
152
  }
153
- function k(s) {
153
+ function F(a) {
154
154
  let e;
155
- const t = (n) => {
156
- const o = _(n.target);
157
- if (!o || o.dataset?.dotObject === "container") return;
158
- const c = o.dataset?.dotInode;
159
- if (c && c === e)
155
+ const t = (s) => {
156
+ const i = L(s.target);
157
+ if (!i || i.dataset?.dotObject === "container") return;
158
+ const d = i.dataset?.dotInode;
159
+ if (d && d === e)
160
160
  return;
161
- n.preventDefault(), n.stopPropagation(), e = c;
162
- const { x: l, y: u, width: E, height: r } = o.getBoundingClientRect(), i = b(o), m = L(o);
163
- s({
161
+ s.preventDefault(), s.stopPropagation(), e = d;
162
+ const { x: l, y: E, width: m, height: r } = i.getBoundingClientRect(), c = O(i), v = g(i);
163
+ a({
164
164
  x: l,
165
- y: u,
166
- width: E,
165
+ y: E,
166
+ width: m,
167
167
  height: r,
168
168
  payload: {
169
- container: o.dataset?.dotContainer ? JSON.parse(o.dataset?.dotContainer) : O(o),
170
- contentlet: i,
171
- vtlFiles: m
169
+ container: i.dataset?.dotContainer ? JSON.parse(i.dataset?.dotContainer) : N(i),
170
+ contentlet: c,
171
+ vtlFiles: v
172
172
  }
173
173
  });
174
- }, a = (n) => {
175
- n?.data?.name === f.UVE_SELECTION_CLEARED && (e = void 0);
174
+ }, o = (s) => {
175
+ s?.data?.name === f.UVE_SELECTION_CLEARED && (e = void 0);
176
176
  };
177
- return document.addEventListener("click", t, { capture: !0 }), window.addEventListener("message", a), {
177
+ document.documentElement.addEventListener("click", t, { capture: !0 });
178
+ const n = T(window);
179
+ return n.addEventListener("message", o), {
178
180
  unsubscribe: () => {
179
- document.removeEventListener("click", t, { capture: !0 }), window.removeEventListener("message", a);
181
+ document.documentElement.removeEventListener("click", t, {
182
+ capture: !0
183
+ }), n.removeEventListener("message", o);
180
184
  },
181
- event: d.CONTENTLET_CLICKED
185
+ event: u.CONTENTLET_CLICKED
182
186
  };
183
187
  }
184
188
  export {
185
- R as onAutoBounds,
186
- M as onContentChanges,
187
- k as onContentletClicked,
188
- V as onContentletHovered,
189
- U as onIframeScroll,
190
- P as onPageReload,
191
- h as onScrollToSection
189
+ h as onAutoBounds,
190
+ R as onContentChanges,
191
+ F as onContentletClicked,
192
+ B as onContentletHovered,
193
+ V as onIframeScroll,
194
+ U as onPageReload,
195
+ k as onScrollToSection
192
196
  };
@@ -1,5 +1,5 @@
1
1
  import "../../internal/constants.js";
2
- function c(t) {
2
+ function f(t) {
3
3
  return t.map((e) => {
4
4
  const n = e.getBoundingClientRect(), o = Array.from(
5
5
  e.querySelectorAll('[data-dot-object="contentlet"]')
@@ -10,13 +10,13 @@ function c(t) {
10
10
  width: n.width,
11
11
  height: n.height,
12
12
  payload: JSON.stringify({
13
- container: a(e)
13
+ container: r(e)
14
14
  }),
15
- contentlets: d(n, o)
15
+ contentlets: c(n, o)
16
16
  };
17
17
  });
18
18
  }
19
- function d(t, e) {
19
+ function c(t, e) {
20
20
  return e.map((n) => {
21
21
  const o = n.getBoundingClientRect();
22
22
  return {
@@ -25,7 +25,7 @@ function d(t, e) {
25
25
  width: o.width,
26
26
  height: o.height,
27
27
  payload: JSON.stringify({
28
- container: n.dataset?.dotContainer ? JSON.parse(n.dataset?.dotContainer) : r(n),
28
+ container: n.dataset?.dotContainer ? JSON.parse(n.dataset?.dotContainer) : l(n),
29
29
  contentlet: {
30
30
  identifier: n.dataset?.dotIdentifier,
31
31
  title: n.dataset?.dotTitle,
@@ -36,7 +36,7 @@ function d(t, e) {
36
36
  };
37
37
  });
38
38
  }
39
- function a(t) {
39
+ function r(t) {
40
40
  return {
41
41
  acceptTypes: t.dataset?.dotAcceptTypes || "",
42
42
  identifier: t.dataset?.dotIdentifier || "",
@@ -44,18 +44,18 @@ function a(t) {
44
44
  uuid: t.dataset?.dotUuid || ""
45
45
  };
46
46
  }
47
- function r(t) {
47
+ function l(t) {
48
48
  const e = t.closest('[data-dot-object="container"]');
49
- return e ? a(e) : (console.warn("No container found for the contentlet"), null);
49
+ return e ? r(e) : (console.warn("No container found for the contentlet"), null);
50
50
  }
51
- function i(t) {
51
+ function u(t) {
52
52
  if (!t) return null;
53
53
  const e = t.querySelector('[data-dot-object="empty-content"]');
54
54
  return t?.dataset?.dotObject === "contentlet" || // The container inside Headless components have a span with the data-dot-object="container" attribute
55
55
  t?.dataset?.dotObject === "container" && e || // The container inside Traditional have no content inside
56
- t?.dataset?.dotObject === "container" && t.children.length === 0 ? t : i(t?.parentElement);
56
+ t?.dataset?.dotObject === "container" && t.children.length === 0 ? t : u(t?.parentElement);
57
57
  }
58
- function u(t) {
58
+ function p(t) {
59
59
  const e = t.querySelectorAll(
60
60
  '[data-dot-object="vtl-file"]'
61
61
  );
@@ -64,7 +64,7 @@ function u(t) {
64
64
  name: n.dataset?.dotUrl
65
65
  })) : null;
66
66
  }
67
- function l(t) {
67
+ function g(t) {
68
68
  const e = t.dataset ?? {};
69
69
  return {
70
70
  identifier: e.dotIdentifier,
@@ -79,12 +79,20 @@ function l(t) {
79
79
  }
80
80
  };
81
81
  }
82
+ function b(t) {
83
+ const e = globalThis.Zone, n = (a) => typeof e?.__symbol__ == "function" ? e.__symbol__(a) : `__zone_symbol__${a}`, o = t, d = t, i = o[n("addEventListener")], s = o[n("removeEventListener")];
84
+ return {
85
+ addEventListener: (i ?? d.addEventListener).bind(d),
86
+ removeEventListener: (s ?? d.removeEventListener).bind(d)
87
+ };
88
+ }
82
89
  export {
83
- i as findDotCMSElement,
84
- u as findDotCMSVTLData,
85
- r as getClosestDotCMSContainerData,
86
- a as getDotCMSContainerData,
87
- d as getDotCMSContentletsBound,
88
- c as getDotCMSPageBounds,
89
- l as readContentletDataset
90
+ u as findDotCMSElement,
91
+ p as findDotCMSVTLData,
92
+ l as getClosestDotCMSContainerData,
93
+ r as getDotCMSContainerData,
94
+ c as getDotCMSContentletsBound,
95
+ f as getDotCMSPageBounds,
96
+ b as getNativeEventBinder,
97
+ g as readContentletDataset
90
98
  };