@antelopejs/dms-marketing 0.6.1 → 0.7.0
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/dist/config.d.ts +3 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -1
- package/dist/data-api/websites.d.ts +10 -4
- package/dist/data-api/websites.js +79 -3
- package/dist/data-api/websites.js.map +1 -1
- package/dist/db/models/page_snapshots.model.d.ts +2 -0
- package/dist/db/models/page_snapshots.model.js +6 -0
- package/dist/db/models/page_snapshots.model.js.map +1 -1
- package/dist/db/models/websites.model.d.ts +1 -0
- package/dist/db/models/websites.model.js +9 -0
- package/dist/db/models/websites.model.js.map +1 -1
- package/dist/db/tables/page_snapshots.table.d.ts +1 -0
- package/dist/db/tables/page_snapshots.table.js +4 -0
- package/dist/db/tables/page_snapshots.table.js.map +1 -1
- package/dist/db/tables/websites.table.d.ts +2 -0
- package/dist/db/tables/websites.table.js +4 -0
- package/dist/db/tables/websites.table.js.map +1 -1
- package/dist/frontend-module.d.ts +6 -0
- package/dist/frontend-module.js +46 -0
- package/dist/frontend-module.js.map +1 -0
- package/dist/index.js +3 -11
- package/dist/index.js.map +1 -1
- package/dist/pages/acquisition/page.d.ts +1 -0
- package/dist/pages/acquisition/page.js +9 -4
- package/dist/pages/acquisition/page.js.map +1 -1
- package/dist/pages/blocks.d.ts +11 -2
- package/dist/pages/blocks.js +43 -5
- package/dist/pages/blocks.js.map +1 -1
- package/dist/pages/funnel/page.d.ts +1 -0
- package/dist/pages/funnel/page.js +1 -0
- package/dist/pages/funnel/page.js.map +1 -1
- package/dist/pages/funnels/page.d.ts +1 -0
- package/dist/pages/funnels/page.js +4 -2
- package/dist/pages/funnels/page.js.map +1 -1
- package/dist/pages/overview/page.d.ts +1 -0
- package/dist/pages/overview/page.js +5 -6
- package/dist/pages/overview/page.js.map +1 -1
- package/dist/pages/pages/page.d.ts +1 -0
- package/dist/pages/pages/page.js +1 -0
- package/dist/pages/pages/page.js.map +1 -1
- package/dist/pages/settings/form.js +1 -0
- package/dist/pages/settings/form.js.map +1 -1
- package/dist/pages/websites/page.d.ts +2 -3
- package/dist/pages/websites/page.js +63 -5
- package/dist/pages/websites/page.js.map +1 -1
- package/dist/routes/dashboard-tracking.js +5 -1
- package/dist/routes/dashboard-tracking.js.map +1 -1
- package/dist/routes/funnels.d.ts +2 -0
- package/dist/routes/funnels.js +6 -5
- package/dist/routes/funnels.js.map +1 -1
- package/dist/routes/public-endpoints.js +1 -1
- package/dist/routes/public-endpoints.js.map +1 -1
- package/dist/routes/snapshot.d.ts +1 -1
- package/dist/routes/snapshot.js +30 -13
- package/dist/routes/snapshot.js.map +1 -1
- package/dist/routes/stats.d.ts +10 -4
- package/dist/routes/stats.js +77 -23
- package/dist/routes/stats.js.map +1 -1
- package/dist/routes/websites.d.ts +5 -1
- package/dist/routes/websites.js +31 -13
- package/dist/routes/websites.js.map +1 -1
- package/dist/services/acquisition-report.d.ts +1 -0
- package/dist/services/acquisition-report.js +1 -0
- package/dist/services/acquisition-report.js.map +1 -1
- package/dist/services/collect.js +7 -2
- package/dist/services/collect.js.map +1 -1
- package/dist/services/dashboard-tracking.d.ts +7 -14
- package/dist/services/dashboard-tracking.js +42 -26
- package/dist/services/dashboard-tracking.js.map +1 -1
- package/dist/services/funnels-table.d.ts +3 -2
- package/dist/services/funnels-table.js +9 -9
- package/dist/services/funnels-table.js.map +1 -1
- package/dist/services/heatmap.d.ts +6 -0
- package/dist/services/heatmap.js +82 -17
- package/dist/services/heatmap.js.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/prune.js +6 -1
- package/dist/services/prune.js.map +1 -1
- package/dist/services/realtime.d.ts +3 -0
- package/dist/services/realtime.js +49 -0
- package/dist/services/realtime.js.map +1 -0
- package/dist/services/request-body.d.ts +1 -0
- package/dist/services/request-body.js +18 -0
- package/dist/services/request-body.js.map +1 -1
- package/dist/services/sessionize.d.ts +1 -0
- package/dist/services/sessionize.js +9 -0
- package/dist/services/sessionize.js.map +1 -1
- package/dist/services/snapshots.d.ts +28 -1
- package/dist/services/snapshots.js +147 -26
- package/dist/services/snapshots.js.map +1 -1
- package/dist/services/tenant-website.d.ts +11 -0
- package/dist/services/tenant-website.js +27 -5
- package/dist/services/tenant-website.js.map +1 -1
- package/dist/services/website-report.d.ts +5 -0
- package/dist/services/website-report.js +13 -1
- package/dist/services/website-report.js.map +1 -1
- package/dist/services/workspace-scope.d.ts +31 -0
- package/dist/services/workspace-scope.js +72 -0
- package/dist/services/workspace-scope.js.map +1 -0
- package/dist/types/constants.d.ts +7 -0
- package/dist/types/constants.js +8 -1
- package/dist/types/constants.js.map +1 -1
- package/dist/types/events.d.ts +25 -25
- package/dist/types/snapshots.d.ts +29 -29
- package/dist/types/snapshots.js +1 -1
- package/dist/types/snapshots.js.map +1 -1
- package/dist/utils/funnel-steps-type.d.ts +13 -13
- package/frontend-vue/app/components/ChannelsCard.vue +19 -2
- package/frontend-vue/app/components/Context.vue +50 -376
- package/frontend-vue/app/components/FunnelBuilder.vue +28 -22
- package/frontend-vue/app/components/FunnelFigure.vue +15 -2
- package/frontend-vue/app/components/FunnelReport.vue +3 -0
- package/frontend-vue/app/components/FunnelTemplates.vue +15 -13
- package/frontend-vue/app/components/InstallGuide.vue +1 -1
- package/frontend-vue/app/components/PagePreview.vue +330 -74
- package/frontend-vue/app/components/PagesExplorer.vue +230 -85
- package/frontend-vue/app/components/TopListTabs.vue +51 -18
- package/frontend-vue/app/components/WebsiteCard.vue +394 -0
- package/frontend-vue/app/components/WebsiteCreate.vue +159 -0
- package/frontend-vue/app/components/WebsitePicker.vue +210 -0
- package/frontend-vue/app/components/WebsiteSettings.vue +539 -0
- package/frontend-vue/app/components/WorkspaceScope.vue +119 -0
- package/frontend-vue/app/composables/useContextWebsite.ts +105 -0
- package/frontend-vue/app/composables/useCopyDraft.ts +47 -0
- package/frontend-vue/app/composables/useMarketingApi.ts +92 -4
- package/frontend-vue/app/composables/useMarketingReads.ts +32 -23
- package/frontend-vue/app/composables/useMarketingRoutes.ts +25 -2
- package/frontend-vue/app/composables/useRecordCrumb.ts +17 -0
- package/frontend-vue/app/composables/useSnapshotFrame.ts +35 -1
- package/frontend-vue/app/utils/anchor-drift.ts +58 -0
- package/frontend-vue/app/utils/drift-dismissals.ts +20 -0
- package/frontend-vue/app/utils/fill-height.ts +141 -0
- package/frontend-vue/app/utils/format.ts +21 -2
- package/frontend-vue/app/utils/funnel-draft.ts +22 -0
- package/frontend-vue/app/utils/heatmap.ts +17 -0
- package/frontend-vue/app/utils/page-snapshot.ts +75 -0
- package/frontend-vue/app/utils/snapshot-options.ts +148 -0
- package/frontend-vue/app/utils/snapshotScrollRoot.ts +93 -0
- package/frontend-vue/app/utils/website-card.ts +93 -0
- package/frontend-vue/app/utils/website-purge.ts +95 -0
- package/frontend-vue/app/utils/website-settings.ts +121 -0
- package/frontend-vue/app/utils/website-state.ts +93 -0
- package/frontend-vue/app/utils/workspace-scope.ts +51 -0
- package/frontend-vue/i18n/locales/marketing-en-GB.json +112 -36
- package/frontend-vue/i18n/locales/marketing-fr-FR.json +112 -36
- package/frontend-vue/package.json +1 -1
- package/frontend-vue/tests/anchor-drift.test.ts +59 -0
- package/frontend-vue/tests/build-flags.test.ts +38 -0
- package/frontend-vue/tests/context-bar.test.ts +226 -0
- package/frontend-vue/tests/copy-draft.test.ts +64 -0
- package/frontend-vue/tests/drift-dismissals.test.ts +12 -0
- package/frontend-vue/tests/fill-height.test.ts +110 -0
- package/frontend-vue/tests/format.test.ts +14 -0
- package/frontend-vue/tests/funnel-draft.test.ts +37 -0
- package/frontend-vue/tests/heatmap.test.ts +25 -0
- package/frontend-vue/tests/install-guide.test.ts +25 -0
- package/frontend-vue/tests/marketing-reads.test.ts +20 -6
- package/frontend-vue/tests/page-snapshot.test.ts +62 -0
- package/frontend-vue/tests/record-crumb.test.ts +43 -0
- package/frontend-vue/tests/registration.test.ts +4 -1
- package/frontend-vue/tests/routes.test.ts +21 -0
- package/frontend-vue/tests/save-funnel.test.ts +47 -0
- package/frontend-vue/tests/server-parity.test.ts +3 -0
- package/frontend-vue/tests/snapshot-options.test.ts +148 -0
- package/frontend-vue/tests/snapshot-scroll-root.test.ts +84 -0
- package/frontend-vue/tests/stubs/frontend-module.ts +5 -1
- package/frontend-vue/tests/top-list-tabs.test.ts +158 -0
- package/frontend-vue/tests/website-card.test.ts +119 -0
- package/frontend-vue/tests/website-purge.test.ts +70 -0
- package/frontend-vue/tests/website-settings.test.ts +133 -0
- package/frontend-vue/tests/website-state.test.ts +96 -0
- package/frontend-vue/tests/workspace-scope-control.test.ts +113 -0
- package/frontend-vue/tests/workspace-scope.test.ts +55 -0
- package/package.json +5 -4
- package/skills/dms-marketing/SKILL.md +47 -6
- package/static/snapshot.js +539 -48
- package/static/tracker.js +154 -5
- package/frontend-vue/app/components/WebsitesGrid.vue +0 -812
package/static/tracker.js
CHANGED
|
@@ -38,6 +38,15 @@
|
|
|
38
38
|
* (static/snapshot.js) or nothing — so a visit never serializes a page
|
|
39
39
|
* nobody will keep, and a page is captured about once a day however busy
|
|
40
40
|
* it is. Off unless the website opted in.
|
|
41
|
+
*
|
|
42
|
+
* Scroll root: an app shell often keeps its document still and scrolls an
|
|
43
|
+
* inner container instead (a dashboard panel, a sidebar layout). When the
|
|
44
|
+
* document does not scroll, the page's scroll root is the element marked
|
|
45
|
+
* `data-marketing-scroll-root` if there is one, else the largest visible
|
|
46
|
+
* element scrolling vertically (overflow-y auto or scroll, content taller
|
|
47
|
+
* than its box) that covers most of the window; the document otherwise.
|
|
48
|
+
* Scroll depth is measured on it, and click positions are taken in its
|
|
49
|
+
* content, as if the page were unrolled — which is how a capture draws it.
|
|
41
50
|
*/
|
|
42
51
|
(() => {
|
|
43
52
|
/** Global the tracker route injects the module settings through. */
|
|
@@ -69,6 +78,20 @@
|
|
|
69
78
|
const SCROLL_MEASURE_DELAY_MS = 1000;
|
|
70
79
|
/** Where a keyboard-activated click is anchored inside its element. */
|
|
71
80
|
const ELEMENT_CENTER = 0.5;
|
|
81
|
+
/** Names the element that scrolls the page, where the document does not. */
|
|
82
|
+
const SCROLL_ROOT_ATTRIBUTE = "data-marketing-scroll-root";
|
|
83
|
+
/** Share of the window an inner scroll container must cover to stand for
|
|
84
|
+
* the page: less is a list, a code block or a dropdown. */
|
|
85
|
+
const SCROLL_ROOT_COVERAGE = 0.5;
|
|
86
|
+
/** Points of the window (fractions of its width and height) probed for an
|
|
87
|
+
* inner scroll container: one covering most of the window holds several. */
|
|
88
|
+
const SCROLL_ROOT_PROBES = [
|
|
89
|
+
[0.5, 0.5],
|
|
90
|
+
[0.5, 0.25],
|
|
91
|
+
[0.5, 0.75],
|
|
92
|
+
[0.25, 0.5],
|
|
93
|
+
[0.75, 0.5],
|
|
94
|
+
];
|
|
72
95
|
|
|
73
96
|
// --- Public API -----------------------------------------------------------
|
|
74
97
|
|
|
@@ -267,6 +290,7 @@
|
|
|
267
290
|
pageExcluded = isExcludedPath(lastPath);
|
|
268
291
|
scrolledUrl = currentUrl();
|
|
269
292
|
maxScrollDepth = -1;
|
|
293
|
+
scrollRootElement = null;
|
|
270
294
|
if (!websiteId || pageExcluded) {
|
|
271
295
|
return;
|
|
272
296
|
}
|
|
@@ -298,15 +322,97 @@
|
|
|
298
322
|
}
|
|
299
323
|
});
|
|
300
324
|
|
|
325
|
+
// --- Scroll root (see the header) ----------------------------------------
|
|
326
|
+
|
|
327
|
+
function documentScrolls() {
|
|
328
|
+
const root = document.documentElement;
|
|
329
|
+
return root.scrollHeight - root.clientHeight > 1;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function scrollsVertically(element) {
|
|
333
|
+
if (element.scrollHeight - element.clientHeight <= 1) {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
const overflow = getComputedStyle(element).overflowY;
|
|
337
|
+
return overflow === "auto" || overflow === "scroll";
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** Area of the element's box inside the window. */
|
|
341
|
+
function visibleArea(element) {
|
|
342
|
+
const box = element.getBoundingClientRect();
|
|
343
|
+
const width = Math.min(box.right, innerWidth) - Math.max(box.left, 0);
|
|
344
|
+
const height = Math.min(box.bottom, innerHeight) - Math.max(box.top, 0);
|
|
345
|
+
return width > 0 && height > 0 ? width * height : 0;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* The element scrolling the page, or null when it is the document. Found
|
|
350
|
+
* from what lies under a few points of the window, never by walking the
|
|
351
|
+
* whole tree: a container covering most of the window holds them.
|
|
352
|
+
*/
|
|
353
|
+
function findScrollRoot() {
|
|
354
|
+
if (documentScrolls()) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
const marked = document.querySelector(`[${SCROLL_ROOT_ATTRIBUTE}]`);
|
|
358
|
+
if (marked) {
|
|
359
|
+
return marked;
|
|
360
|
+
}
|
|
361
|
+
if (typeof document.elementFromPoint !== "function") {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
const visited = new Set();
|
|
365
|
+
let best = null;
|
|
366
|
+
let bestArea = innerWidth * innerHeight * SCROLL_ROOT_COVERAGE;
|
|
367
|
+
for (const [fx, fy] of SCROLL_ROOT_PROBES) {
|
|
368
|
+
let node = document.elementFromPoint(innerWidth * fx, innerHeight * fy);
|
|
369
|
+
// An ancestor already visited was checked with all of its own.
|
|
370
|
+
for (; node && !visited.has(node); node = node.parentElement) {
|
|
371
|
+
visited.add(node);
|
|
372
|
+
if (
|
|
373
|
+
node === document.body ||
|
|
374
|
+
node === document.documentElement ||
|
|
375
|
+
!scrollsVertically(node)
|
|
376
|
+
) {
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
const area = visibleArea(node);
|
|
380
|
+
if (area > bestArea) {
|
|
381
|
+
best = node;
|
|
382
|
+
bestArea = area;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return best;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Kept while it stays in the page and the document still does not
|
|
390
|
+
* scroll; looked for again otherwise — and on every new view. */
|
|
391
|
+
let scrollRootElement = null;
|
|
392
|
+
|
|
393
|
+
function scrollRoot() {
|
|
394
|
+
if (
|
|
395
|
+
!scrollRootElement ||
|
|
396
|
+
!scrollRootElement.isConnected ||
|
|
397
|
+
documentScrolls()
|
|
398
|
+
) {
|
|
399
|
+
scrollRootElement = findScrollRoot();
|
|
400
|
+
}
|
|
401
|
+
return scrollRootElement;
|
|
402
|
+
}
|
|
403
|
+
|
|
301
404
|
// --- Scroll depth (max reached per page, flushed on leave) ----------------
|
|
302
405
|
|
|
303
406
|
function currentScrollDepth() {
|
|
304
|
-
const
|
|
407
|
+
const inner = scrollRoot();
|
|
408
|
+
const root = inner || document.documentElement;
|
|
305
409
|
const scrollable = root.scrollHeight - root.clientHeight;
|
|
306
410
|
if (scrollable <= 0) {
|
|
307
411
|
return PERCENT_SCALE;
|
|
308
412
|
}
|
|
309
|
-
const scrolled =
|
|
413
|
+
const scrolled = inner
|
|
414
|
+
? inner.scrollTop
|
|
415
|
+
: root.scrollTop || document.body.scrollTop || 0;
|
|
310
416
|
return Math.min(
|
|
311
417
|
PERCENT_SCALE,
|
|
312
418
|
Math.round((scrolled / scrollable) * PERCENT_SCALE),
|
|
@@ -320,7 +426,12 @@
|
|
|
320
426
|
}
|
|
321
427
|
}
|
|
322
428
|
|
|
323
|
-
|
|
429
|
+
// Captured on the document: an element's scroll does not bubble, and the
|
|
430
|
+
// window never hears it.
|
|
431
|
+
document.addEventListener("scroll", measureScrollDepth, {
|
|
432
|
+
capture: true,
|
|
433
|
+
passive: true,
|
|
434
|
+
});
|
|
324
435
|
|
|
325
436
|
/**
|
|
326
437
|
* Every sampled view reports a depth, scrolled or not: what shows without
|
|
@@ -442,6 +553,38 @@
|
|
|
442
553
|
};
|
|
443
554
|
}
|
|
444
555
|
|
|
556
|
+
/**
|
|
557
|
+
* Vertical position of a point in the page's content, and the content's
|
|
558
|
+
* height: with an inner scroll root, the range it hides is unrolled — a
|
|
559
|
+
* click on something inside it moves down by its scroll offset, one on
|
|
560
|
+
* something under it (a footer below the panel) by the whole hidden range
|
|
561
|
+
* — so `dy` reads the same however far the visitor had scrolled it, and
|
|
562
|
+
* lines up with a capture of the whole page. Beside it (a sidebar) or
|
|
563
|
+
* above it (a header), nothing moves.
|
|
564
|
+
*/
|
|
565
|
+
function contentPosition(target, point) {
|
|
566
|
+
const height = document.documentElement.scrollHeight;
|
|
567
|
+
const root = scrollRoot();
|
|
568
|
+
if (!root) {
|
|
569
|
+
return { y: point.pageY, height: height };
|
|
570
|
+
}
|
|
571
|
+
const hidden = root.scrollHeight - root.clientHeight;
|
|
572
|
+
let y = point.pageY;
|
|
573
|
+
if (root.contains(target)) {
|
|
574
|
+
y += root.scrollTop;
|
|
575
|
+
} else {
|
|
576
|
+
const box = root.getBoundingClientRect();
|
|
577
|
+
if (
|
|
578
|
+
point.clientY >= box.bottom &&
|
|
579
|
+
point.clientX >= box.left &&
|
|
580
|
+
point.clientX < box.right
|
|
581
|
+
) {
|
|
582
|
+
y += hidden;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return { y: y, height: height + hidden };
|
|
586
|
+
}
|
|
587
|
+
|
|
445
588
|
document.addEventListener(
|
|
446
589
|
"click",
|
|
447
590
|
(event) => {
|
|
@@ -455,6 +598,7 @@
|
|
|
455
598
|
}
|
|
456
599
|
const doc = document.documentElement;
|
|
457
600
|
const point = clickPoint(target, event);
|
|
601
|
+
const content = contentPosition(target, point);
|
|
458
602
|
enqueue(
|
|
459
603
|
Object.assign(base(), {
|
|
460
604
|
kind: "click",
|
|
@@ -463,7 +607,7 @@
|
|
|
463
607
|
x: normalized(point.clientX, innerWidth),
|
|
464
608
|
y: normalized(point.clientY, innerHeight),
|
|
465
609
|
dx: normalized(point.pageX, doc.scrollWidth),
|
|
466
|
-
dy: normalized(
|
|
610
|
+
dy: normalized(content.y, content.height),
|
|
467
611
|
selector: shortSelector(target),
|
|
468
612
|
},
|
|
469
613
|
elementAnchor(target, point),
|
|
@@ -508,12 +652,17 @@
|
|
|
508
652
|
website: websiteId,
|
|
509
653
|
endpoint: snapshotEndpoint,
|
|
510
654
|
path: path,
|
|
655
|
+
// Looked for at capture time, the page as it is then.
|
|
656
|
+
scrollRoot: findScrollRoot,
|
|
511
657
|
};
|
|
512
658
|
const loader = document.createElement("script");
|
|
513
659
|
loader.async = true;
|
|
514
660
|
loader.src =
|
|
515
661
|
`${hostUrl}/api/marketing/snapshot.js?website=${encodeURIComponent(websiteId)}` +
|
|
516
|
-
`&path=${encodeURIComponent(path)}&width=${innerWidth}
|
|
662
|
+
`&path=${encodeURIComponent(path)}&width=${innerWidth}` +
|
|
663
|
+
// Lets the backend replace a capture taken before captures marked the
|
|
664
|
+
// scroll root, instead of waiting for it to age.
|
|
665
|
+
(scrollRoot() ? "&root=1" : "");
|
|
517
666
|
const settle = () => loader.remove();
|
|
518
667
|
loader.addEventListener("load", settle);
|
|
519
668
|
loader.addEventListener("error", settle);
|