@gemx-dev/clarity-visualize 3.5.3 → 3.5.4
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/CHANGELOG.md +6 -0
- package/package.json +2 -1
- package/src/heatmap.ts +25 -68
- package/src/layout.ts +151 -283
- package/src/visualizer.ts +15 -40
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @gemx-dev/clarity-visualize
|
|
2
2
|
|
|
3
|
+
## 3.5.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#34](https://github.com/ducky0209/gemx-sdk/pull/34) [`ee65886`](https://github.com/ducky0209/gemx-sdk/commit/ee6588699a5be630fe8b688806f51c8417b73c4c) Thanks [@ducky0209](https://github.com/ducky0209)! - Update logic show heatmap
|
|
8
|
+
|
|
3
9
|
## 3.5.3
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gemx-dev/clarity-visualize",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.4",
|
|
4
4
|
"description": "GemX Heatmap Visualize (Clarity) fork",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "build/clarity.visualize.js",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "yarn build:clean && yarn build:main",
|
|
29
29
|
"build:main": "rollup -c rollup.config.ts --configPlugin @rollup/plugin-typescript",
|
|
30
|
+
"build:main:watch": "rollup -c rollup.config.ts --configPlugin @rollup/plugin-typescript --watch",
|
|
30
31
|
"build:clean": "del-cli build/*",
|
|
31
32
|
"tslint": "tslint --project ./",
|
|
32
33
|
"tslint:fix": "tslint --fix --project ./ --force",
|
package/src/heatmap.ts
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Heatmap,
|
|
5
|
-
Setting,
|
|
6
|
-
ScrollMapInfo,
|
|
7
|
-
PlaybackState,
|
|
8
|
-
} from '@clarity-types/visualize';
|
|
9
|
-
import { Data } from 'clarity-js';
|
|
10
|
-
import { LayoutHelper } from './layout';
|
|
1
|
+
import { Activity, Constant, Heatmap, Setting, ScrollMapInfo, PlaybackState } from "@clarity-types/visualize";
|
|
2
|
+
import { Data } from "clarity-js";
|
|
3
|
+
import { LayoutHelper } from "./layout";
|
|
11
4
|
|
|
12
5
|
export class HeatmapHelper {
|
|
13
|
-
static COLORS = [
|
|
6
|
+
static COLORS = ["blue", "cyan", "lime", "yellow", "red"];
|
|
14
7
|
data: Activity = null;
|
|
15
8
|
scrollData: ScrollMapInfo[] = null;
|
|
16
9
|
max: number = null;
|
|
@@ -45,8 +38,8 @@ export class HeatmapHelper {
|
|
|
45
38
|
// Remove scroll and resize event listeners
|
|
46
39
|
if (this.state && this.state.window) {
|
|
47
40
|
let win = this.state.window;
|
|
48
|
-
win.removeEventListener(
|
|
49
|
-
win.removeEventListener(
|
|
41
|
+
win.removeEventListener("scroll", this.redraw, true);
|
|
42
|
+
win.removeEventListener("resize", this.redraw, true);
|
|
50
43
|
}
|
|
51
44
|
};
|
|
52
45
|
|
|
@@ -75,23 +68,18 @@ export class HeatmapHelper {
|
|
|
75
68
|
let doc = this.state.window.document;
|
|
76
69
|
var body = doc.body;
|
|
77
70
|
var de = doc.documentElement;
|
|
78
|
-
var height = Math.max(
|
|
79
|
-
body.scrollHeight,
|
|
80
|
-
body.offsetHeight,
|
|
81
|
-
de.clientHeight,
|
|
82
|
-
de.scrollHeight,
|
|
83
|
-
de.offsetHeight,
|
|
84
|
-
);
|
|
71
|
+
var height = Math.max(body.scrollHeight, body.offsetHeight, de.clientHeight, de.scrollHeight, de.offsetHeight);
|
|
85
72
|
canvas.height = Math.min(height, Setting.ScrollCanvasMaxHeight);
|
|
86
73
|
canvas.style.top = 0 + Constant.Pixel;
|
|
87
74
|
if (canvas.width > 0 && canvas.height > 0) {
|
|
88
75
|
if (this.scrollData) {
|
|
89
76
|
const grd = context.createLinearGradient(0, 0, 0, canvas.height);
|
|
90
77
|
for (const currentCombination of this.scrollData) {
|
|
91
|
-
const huePercentView =
|
|
92
|
-
|
|
78
|
+
const huePercentView = 1 - currentCombination.cumulativeSum / this.scrollData[0].cumulativeSum;
|
|
79
|
+
console.log(`🚀 🐥 ~ HeatmapHelper ~ huePercentView:`, huePercentView);
|
|
93
80
|
const percentView = (currentCombination.scrollReachY / 100) * (height / canvas.height);
|
|
94
81
|
const hue = huePercentView * Setting.MaxHue;
|
|
82
|
+
console.log(`🚀 🐥 ~ HeatmapHelper ~ hue:`, hue);
|
|
95
83
|
if (percentView <= 1) {
|
|
96
84
|
grd.addColorStop(percentView, `hsla(${hue}, 100%, 50%, 0.6)`);
|
|
97
85
|
}
|
|
@@ -101,52 +89,27 @@ export class HeatmapHelper {
|
|
|
101
89
|
context.fillStyle = grd;
|
|
102
90
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
103
91
|
if (this.addScrollMakers) {
|
|
104
|
-
this.addInfoMarkers(
|
|
105
|
-
context,
|
|
106
|
-
this.scrollData,
|
|
107
|
-
canvas.width,
|
|
108
|
-
canvas.height,
|
|
109
|
-
this.scrollAvgFold,
|
|
110
|
-
);
|
|
92
|
+
this.addInfoMarkers(context, this.scrollData, canvas.width, canvas.height, this.scrollAvgFold);
|
|
111
93
|
}
|
|
112
94
|
}
|
|
113
95
|
}
|
|
114
96
|
};
|
|
115
97
|
|
|
116
|
-
private addInfoMarkers = (
|
|
117
|
-
context: CanvasRenderingContext2D,
|
|
118
|
-
scrollMapInfo: ScrollMapInfo[],
|
|
119
|
-
width: number,
|
|
120
|
-
height: number,
|
|
121
|
-
avgFold: number,
|
|
122
|
-
): void => {
|
|
98
|
+
private addInfoMarkers = (context: CanvasRenderingContext2D, scrollMapInfo: ScrollMapInfo[], width: number, height: number, avgFold: number): void => {
|
|
123
99
|
this.addMarker(context, width, Constant.AverageFold, avgFold, Setting.MarkerMediumWidth);
|
|
124
100
|
const markers = [75, 50, 25];
|
|
125
101
|
for (const marker of markers) {
|
|
126
|
-
const closest = scrollMapInfo.reduce(
|
|
127
|
-
(prev
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
: prev;
|
|
131
|
-
},
|
|
132
|
-
);
|
|
133
|
-
if (
|
|
134
|
-
closest.percUsers >= marker - Setting.MarkerRange &&
|
|
135
|
-
closest.percUsers <= marker + Setting.MarkerRange
|
|
136
|
-
) {
|
|
102
|
+
const closest = scrollMapInfo.reduce((prev: ScrollMapInfo, curr: ScrollMapInfo): ScrollMapInfo => {
|
|
103
|
+
return Math.abs(curr.percUsers - marker) < Math.abs(prev.percUsers - marker) ? curr : prev;
|
|
104
|
+
});
|
|
105
|
+
if (closest.percUsers >= marker - Setting.MarkerRange && closest.percUsers <= marker + Setting.MarkerRange) {
|
|
137
106
|
const markerLine = (closest.scrollReachY / 100) * height;
|
|
138
107
|
this.addMarker(context, width, `${marker}%`, markerLine, Setting.MarkerSmallWidth);
|
|
139
108
|
}
|
|
140
109
|
}
|
|
141
110
|
};
|
|
142
111
|
|
|
143
|
-
private addMarker = (
|
|
144
|
-
context: CanvasRenderingContext2D,
|
|
145
|
-
heatmapWidth: number,
|
|
146
|
-
label: string,
|
|
147
|
-
markerY: number,
|
|
148
|
-
markerWidth: number,
|
|
149
|
-
): void => {
|
|
112
|
+
private addMarker = (context: CanvasRenderingContext2D, heatmapWidth: number, label: string, markerY: number, markerWidth: number): void => {
|
|
150
113
|
context.beginPath();
|
|
151
114
|
context.moveTo(0, markerY);
|
|
152
115
|
context.lineTo(heatmapWidth, markerY);
|
|
@@ -213,9 +176,9 @@ export class HeatmapHelper {
|
|
|
213
176
|
canvas.style.position = Constant.Absolute;
|
|
214
177
|
canvas.style.zIndex = `${Setting.ZIndex}`;
|
|
215
178
|
de.appendChild(canvas);
|
|
216
|
-
win.addEventListener(
|
|
217
|
-
win.addEventListener(
|
|
218
|
-
this.observer = this.state.window[
|
|
179
|
+
win.addEventListener("scroll", this.redraw, true);
|
|
180
|
+
win.addEventListener("resize", this.redraw, true);
|
|
181
|
+
this.observer = this.state.window["ResizeObserver"] ? new ResizeObserver(this.redraw) : null;
|
|
219
182
|
|
|
220
183
|
if (this.observer) {
|
|
221
184
|
this.observer.observe(doc.body);
|
|
@@ -276,7 +239,7 @@ export class HeatmapHelper {
|
|
|
276
239
|
}
|
|
277
240
|
this.timeout = setTimeout(this.click, Setting.Interval);
|
|
278
241
|
} else if (this.scrollData) {
|
|
279
|
-
if (event.type !=
|
|
242
|
+
if (event.type != "scroll") {
|
|
280
243
|
if (this.timeout) {
|
|
281
244
|
clearTimeout(this.timeout);
|
|
282
245
|
}
|
|
@@ -289,15 +252,12 @@ export class HeatmapHelper {
|
|
|
289
252
|
let output: Heatmap[] = [];
|
|
290
253
|
let points: { [key: string]: number } = {};
|
|
291
254
|
let localMax = 0;
|
|
292
|
-
let height =
|
|
293
|
-
this.state.window && this.state.window.document
|
|
294
|
-
? this.state.window.document.documentElement.clientHeight
|
|
295
|
-
: 0;
|
|
255
|
+
let height = this.state.window && this.state.window.document ? this.state.window.document.documentElement.clientHeight : 0;
|
|
296
256
|
|
|
297
257
|
for (let element of this.data) {
|
|
298
258
|
let el = this.layout.get(element.hash) as HTMLElement;
|
|
299
259
|
el && console.log(`🚀 🐥 ~ HeatmapHelper ~ el:`, el);
|
|
300
|
-
if (el && typeof el.getBoundingClientRect ===
|
|
260
|
+
if (el && typeof el.getBoundingClientRect === "function") {
|
|
301
261
|
let r = el.getBoundingClientRect();
|
|
302
262
|
let v = this.visible(el, r, height);
|
|
303
263
|
// Process clicks for only visible elements
|
|
@@ -320,7 +280,7 @@ export class HeatmapHelper {
|
|
|
320
280
|
for (let coordinates of Object.keys(points)) {
|
|
321
281
|
let parts = coordinates.split(Constant.Separator);
|
|
322
282
|
let alpha = Math.min(points[coordinates] / this.max + Setting.AlphaBoost, 1);
|
|
323
|
-
if (parts[2] ===
|
|
283
|
+
if (parts[2] === "1") {
|
|
324
284
|
output.push({ x: parseInt(parts[0], 10), y: parseInt(parts[1], 10), a: alpha });
|
|
325
285
|
}
|
|
326
286
|
}
|
|
@@ -337,10 +297,7 @@ export class HeatmapHelper {
|
|
|
337
297
|
let elements = doc.elementsFromPoint(r.left + r.width / 2, r.top + r.height / 2);
|
|
338
298
|
for (let e of elements) {
|
|
339
299
|
// Ignore if top element ends up being the canvas element we added for heatmap visualization
|
|
340
|
-
if (
|
|
341
|
-
e.tagName === Constant.Canvas ||
|
|
342
|
-
(e.id && e.id.indexOf(Constant.ClarityPrefix) === 0)
|
|
343
|
-
) {
|
|
300
|
+
if (e.tagName === Constant.Canvas || (e.id && e.id.indexOf(Constant.ClarityPrefix) === 0)) {
|
|
344
301
|
continue;
|
|
345
302
|
}
|
|
346
303
|
visibility = e === el;
|
package/src/layout.ts
CHANGED
|
@@ -1,114 +1,107 @@
|
|
|
1
|
-
import { Data, Layout } from
|
|
2
|
-
import type { Layout as DecodedLayout } from
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type PlaybackState,
|
|
9
|
-
Setting,
|
|
10
|
-
} from '@clarity-types/visualize';
|
|
11
|
-
import { StyleSheetOperation } from 'clarity-js/types/layout';
|
|
12
|
-
import { AnimationOperation } from 'clarity-js/types/layout';
|
|
13
|
-
import { Constant as LayoutConstants } from 'clarity-js/types/layout';
|
|
14
|
-
import sharedStyle from './styles/shared.css';
|
|
1
|
+
import { Data, Layout } from "clarity-js";
|
|
2
|
+
import type { Layout as DecodedLayout } from "clarity-decode";
|
|
3
|
+
import { Asset, Constant, type LinkHandler, NodeType, type PlaybackState, Setting } from "@clarity-types/visualize";
|
|
4
|
+
import { StyleSheetOperation } from "clarity-js/types/layout";
|
|
5
|
+
import { AnimationOperation } from "clarity-js/types/layout";
|
|
6
|
+
import { Constant as LayoutConstants } from "clarity-js/types/layout";
|
|
7
|
+
import sharedStyle from "./styles/shared.css";
|
|
15
8
|
|
|
16
9
|
/* BEGIN blobUnavailableSvgs */
|
|
17
|
-
import blobUnavailableSvgEnglish from
|
|
18
|
-
import blobUnavailableSvgSmall from
|
|
19
|
-
import blobUnavailableSvgChineseSimplified from
|
|
20
|
-
import blobUnavailableSvgChineseTraditional from
|
|
21
|
-
import blobUnavailableSvgJapanese from
|
|
22
|
-
import blobUnavailableSvgKorean from
|
|
23
|
-
import blobUnavailableSvgRussian from
|
|
24
|
-
import blobUnavailableSvgSpanish from
|
|
25
|
-
import blobUnavailableSvgTurkish from
|
|
26
|
-
import blobUnavailableSvgDutch from
|
|
27
|
-
import blobUnavailableSvgFrench from
|
|
28
|
-
import blobUnavailableSvgGerman from
|
|
29
|
-
import blobUnavailableSvgItalian from
|
|
30
|
-
import blobUnavailableSvgPortuguese from
|
|
10
|
+
import blobUnavailableSvgEnglish from "./styles/blobUnavailable/english.svg";
|
|
11
|
+
import blobUnavailableSvgSmall from "./styles/blobUnavailable/iconOnly.svg";
|
|
12
|
+
import blobUnavailableSvgChineseSimplified from "./styles/blobUnavailable/chineseSimplified.svg";
|
|
13
|
+
import blobUnavailableSvgChineseTraditional from "./styles/blobUnavailable/chineseTraditional.svg";
|
|
14
|
+
import blobUnavailableSvgJapanese from "./styles/blobUnavailable/japanese.svg";
|
|
15
|
+
import blobUnavailableSvgKorean from "./styles/blobUnavailable/korean.svg";
|
|
16
|
+
import blobUnavailableSvgRussian from "./styles/blobUnavailable/russian.svg";
|
|
17
|
+
import blobUnavailableSvgSpanish from "./styles/blobUnavailable/spanish.svg";
|
|
18
|
+
import blobUnavailableSvgTurkish from "./styles/blobUnavailable/turkish.svg";
|
|
19
|
+
import blobUnavailableSvgDutch from "./styles/blobUnavailable/dutch.svg";
|
|
20
|
+
import blobUnavailableSvgFrench from "./styles/blobUnavailable/french.svg";
|
|
21
|
+
import blobUnavailableSvgGerman from "./styles/blobUnavailable/german.svg";
|
|
22
|
+
import blobUnavailableSvgItalian from "./styles/blobUnavailable/italian.svg";
|
|
23
|
+
import blobUnavailableSvgPortuguese from "./styles/blobUnavailable/portuguese.svg";
|
|
31
24
|
const blobUnavailableSvg = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
25
|
+
"de-de": blobUnavailableSvgGerman,
|
|
26
|
+
"en-gb": blobUnavailableSvgEnglish,
|
|
27
|
+
"en-us": blobUnavailableSvgEnglish,
|
|
28
|
+
"es-es": blobUnavailableSvgSpanish,
|
|
29
|
+
"fr-fr": blobUnavailableSvgFrench,
|
|
30
|
+
"it-it": blobUnavailableSvgItalian,
|
|
31
|
+
"ja-jp": blobUnavailableSvgJapanese,
|
|
32
|
+
"ko-kr": blobUnavailableSvgKorean,
|
|
33
|
+
"nl-nl": blobUnavailableSvgDutch,
|
|
34
|
+
"pt-br": blobUnavailableSvgPortuguese,
|
|
35
|
+
"ru-ru": blobUnavailableSvgRussian,
|
|
36
|
+
"tr-tr": blobUnavailableSvgTurkish,
|
|
37
|
+
"zh-hans": blobUnavailableSvgChineseSimplified,
|
|
38
|
+
"zh-hant": blobUnavailableSvgChineseTraditional,
|
|
46
39
|
};
|
|
47
40
|
/* END blobUnavailableSvgs */
|
|
48
41
|
|
|
49
42
|
/* BEGIN iframeUnavailableSvgs */
|
|
50
|
-
import iframeUnavailableSvgEnglish from
|
|
51
|
-
import iframeUnavailableSvgSmall from
|
|
52
|
-
import iframeUnavailableSvgChineseSimplified from
|
|
53
|
-
import iframeUnavailableSvgChineseTraditional from
|
|
54
|
-
import iframeUnavailableSvgJapanese from
|
|
55
|
-
import iframeUnavailableSvgKorean from
|
|
56
|
-
import iframeUnavailableSvgRussian from
|
|
57
|
-
import iframeUnavailableSvgSpanish from
|
|
58
|
-
import iframeUnavailableSvgTurkish from
|
|
59
|
-
import iframeUnavailableSvgDutch from
|
|
60
|
-
import iframeUnavailableSvgFrench from
|
|
61
|
-
import iframeUnavailableSvgGerman from
|
|
62
|
-
import iframeUnavailableSvgItalian from
|
|
63
|
-
import iframeUnavailableSvgPortuguese from
|
|
43
|
+
import iframeUnavailableSvgEnglish from "./styles/iframeUnavailable/english.svg";
|
|
44
|
+
import iframeUnavailableSvgSmall from "./styles/iframeUnavailable/iconOnly.svg";
|
|
45
|
+
import iframeUnavailableSvgChineseSimplified from "./styles/iframeUnavailable/chineseSimplified.svg";
|
|
46
|
+
import iframeUnavailableSvgChineseTraditional from "./styles/iframeUnavailable/chineseTraditional.svg";
|
|
47
|
+
import iframeUnavailableSvgJapanese from "./styles/iframeUnavailable/japanese.svg";
|
|
48
|
+
import iframeUnavailableSvgKorean from "./styles/iframeUnavailable/korean.svg";
|
|
49
|
+
import iframeUnavailableSvgRussian from "./styles/iframeUnavailable/russian.svg";
|
|
50
|
+
import iframeUnavailableSvgSpanish from "./styles/iframeUnavailable/spanish.svg";
|
|
51
|
+
import iframeUnavailableSvgTurkish from "./styles/iframeUnavailable/turkish.svg";
|
|
52
|
+
import iframeUnavailableSvgDutch from "./styles/iframeUnavailable/dutch.svg";
|
|
53
|
+
import iframeUnavailableSvgFrench from "./styles/iframeUnavailable/french.svg";
|
|
54
|
+
import iframeUnavailableSvgGerman from "./styles/iframeUnavailable/german.svg";
|
|
55
|
+
import iframeUnavailableSvgItalian from "./styles/iframeUnavailable/italian.svg";
|
|
56
|
+
import iframeUnavailableSvgPortuguese from "./styles/iframeUnavailable/portuguese.svg";
|
|
64
57
|
const iframeUnavailableSvg = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
58
|
+
"de-de": iframeUnavailableSvgGerman,
|
|
59
|
+
"en-gb": iframeUnavailableSvgEnglish,
|
|
60
|
+
"en-us": iframeUnavailableSvgEnglish,
|
|
61
|
+
"es-es": iframeUnavailableSvgSpanish,
|
|
62
|
+
"fr-fr": iframeUnavailableSvgFrench,
|
|
63
|
+
"it-it": iframeUnavailableSvgItalian,
|
|
64
|
+
"ja-jp": iframeUnavailableSvgJapanese,
|
|
65
|
+
"ko-kr": iframeUnavailableSvgKorean,
|
|
66
|
+
"nl-nl": iframeUnavailableSvgDutch,
|
|
67
|
+
"pt-br": iframeUnavailableSvgPortuguese,
|
|
68
|
+
"ru-ru": iframeUnavailableSvgRussian,
|
|
69
|
+
"tr-tr": iframeUnavailableSvgTurkish,
|
|
70
|
+
"zh-hans": iframeUnavailableSvgChineseSimplified,
|
|
71
|
+
"zh-hant": iframeUnavailableSvgChineseTraditional,
|
|
79
72
|
};
|
|
80
73
|
/* END iframeUnavailableSvgs */
|
|
81
74
|
|
|
82
75
|
/* BEGIN imageMaskedSvgs */
|
|
83
|
-
import imageMaskedSvgEnglish from
|
|
84
|
-
import imageMaskedSvgSmall from
|
|
85
|
-
import imageMaskedSvgChineseSimplified from
|
|
86
|
-
import imageMaskedSvgChineseTraditional from
|
|
87
|
-
import imageMaskedSvgJapanese from
|
|
88
|
-
import imageMaskedSvgKorean from
|
|
89
|
-
import imageMaskedSvgRussian from
|
|
90
|
-
import imageMaskedSvgSpanish from
|
|
91
|
-
import imageMaskedSvgTurkish from
|
|
92
|
-
import imageMaskedSvgDutch from
|
|
93
|
-
import imageMaskedSvgFrench from
|
|
94
|
-
import imageMaskedSvgGerman from
|
|
95
|
-
import imageMaskedSvgItalian from
|
|
96
|
-
import imageMaskedSvgPortuguese from
|
|
76
|
+
import imageMaskedSvgEnglish from "./styles/imageMasked/english.svg";
|
|
77
|
+
import imageMaskedSvgSmall from "./styles/imageMasked/iconOnly.svg";
|
|
78
|
+
import imageMaskedSvgChineseSimplified from "./styles/imageMasked/chineseSimplified.svg";
|
|
79
|
+
import imageMaskedSvgChineseTraditional from "./styles/imageMasked/chineseTraditional.svg";
|
|
80
|
+
import imageMaskedSvgJapanese from "./styles/imageMasked/japanese.svg";
|
|
81
|
+
import imageMaskedSvgKorean from "./styles/imageMasked/korean.svg";
|
|
82
|
+
import imageMaskedSvgRussian from "./styles/imageMasked/russian.svg";
|
|
83
|
+
import imageMaskedSvgSpanish from "./styles/imageMasked/spanish.svg";
|
|
84
|
+
import imageMaskedSvgTurkish from "./styles/imageMasked/turkish.svg";
|
|
85
|
+
import imageMaskedSvgDutch from "./styles/imageMasked/dutch.svg";
|
|
86
|
+
import imageMaskedSvgFrench from "./styles/imageMasked/french.svg";
|
|
87
|
+
import imageMaskedSvgGerman from "./styles/imageMasked/german.svg";
|
|
88
|
+
import imageMaskedSvgItalian from "./styles/imageMasked/italian.svg";
|
|
89
|
+
import imageMaskedSvgPortuguese from "./styles/imageMasked/portuguese.svg";
|
|
97
90
|
const imageMaskedSvg = {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
91
|
+
"de-de": imageMaskedSvgGerman,
|
|
92
|
+
"en-gb": imageMaskedSvgEnglish,
|
|
93
|
+
"en-us": imageMaskedSvgEnglish,
|
|
94
|
+
"es-es": imageMaskedSvgSpanish,
|
|
95
|
+
"fr-fr": imageMaskedSvgFrench,
|
|
96
|
+
"it-it": imageMaskedSvgItalian,
|
|
97
|
+
"ja-jp": imageMaskedSvgJapanese,
|
|
98
|
+
"ko-kr": imageMaskedSvgKorean,
|
|
99
|
+
"nl-nl": imageMaskedSvgDutch,
|
|
100
|
+
"pt-br": imageMaskedSvgPortuguese,
|
|
101
|
+
"ru-ru": imageMaskedSvgRussian,
|
|
102
|
+
"tr-tr": imageMaskedSvgTurkish,
|
|
103
|
+
"zh-hans": imageMaskedSvgChineseSimplified,
|
|
104
|
+
"zh-hant": imageMaskedSvgChineseTraditional,
|
|
112
105
|
};
|
|
113
106
|
/* END imageMaskedSvgs */
|
|
114
107
|
|
|
@@ -127,23 +120,12 @@ export class LayoutHelper {
|
|
|
127
120
|
animations = {};
|
|
128
121
|
state: PlaybackState = null;
|
|
129
122
|
stylesToApply: { [id: string]: string[] } = {};
|
|
130
|
-
BackgroundImageEligibleElements = [
|
|
131
|
-
'DIV',
|
|
132
|
-
'SECTION',
|
|
133
|
-
'ARTICLE',
|
|
134
|
-
'HEADER',
|
|
135
|
-
'FOOTER',
|
|
136
|
-
'ASIDE',
|
|
137
|
-
'NAV',
|
|
138
|
-
'SPAN',
|
|
139
|
-
'P',
|
|
140
|
-
'MAIN',
|
|
141
|
-
];
|
|
123
|
+
BackgroundImageEligibleElements = ["DIV", "SECTION", "ARTICLE", "HEADER", "FOOTER", "ASIDE", "NAV", "SPAN", "P", "MAIN"];
|
|
142
124
|
MaskedBackgroundImageStyle = `#CCC no-repeat center url("${Asset.Hide}")`;
|
|
143
125
|
vNext: boolean;
|
|
144
126
|
locale: string;
|
|
145
127
|
|
|
146
|
-
constructor(state: PlaybackState, isMobile = false, vNext = false, locale =
|
|
128
|
+
constructor(state: PlaybackState, isMobile = false, vNext = false, locale = "en-us") {
|
|
147
129
|
this.state = state;
|
|
148
130
|
this.isMobile = isMobile;
|
|
149
131
|
this.vNext = vNext;
|
|
@@ -199,10 +181,7 @@ export class LayoutHelper {
|
|
|
199
181
|
let target = this.element(event.data.targetId);
|
|
200
182
|
// only create the animation if we successfully found the target, an animation without a target will throw an error
|
|
201
183
|
if (target) {
|
|
202
|
-
this.animations[event.data.id] = (target as HTMLElement).animate(
|
|
203
|
-
JSON.parse(event.data.keyFrames),
|
|
204
|
-
JSON.parse(event.data.timing),
|
|
205
|
-
);
|
|
184
|
+
this.animations[event.data.id] = (target as HTMLElement).animate(JSON.parse(event.data.keyFrames), JSON.parse(event.data.timing));
|
|
206
185
|
}
|
|
207
186
|
break;
|
|
208
187
|
case AnimationOperation.Cancel:
|
|
@@ -267,16 +246,12 @@ export class LayoutHelper {
|
|
|
267
246
|
|
|
268
247
|
public customElement = (event: DecodedLayout.CustomElementEvent): void => {
|
|
269
248
|
if (!this.state.window.customElements.get(event.data.name)) {
|
|
270
|
-
this.state.window.customElements.define(
|
|
271
|
-
event.data.name,
|
|
272
|
-
class extends (this.state.window as typeof window).HTMLElement {},
|
|
273
|
-
);
|
|
249
|
+
this.state.window.customElements.define(event.data.name, class extends (this.state.window as typeof window).HTMLElement {});
|
|
274
250
|
}
|
|
275
251
|
};
|
|
276
252
|
|
|
277
253
|
private setDocumentStyles(documentId: number, styleIds: string[]) {
|
|
278
|
-
let targetDocument =
|
|
279
|
-
documentId === -1 ? this.state.window.document : (this.element(documentId) as Document);
|
|
254
|
+
let targetDocument = documentId === -1 ? this.state.window.document : (this.element(documentId) as Document);
|
|
280
255
|
|
|
281
256
|
if (!targetDocument) {
|
|
282
257
|
if (!this.stylesToApply[documentId]) {
|
|
@@ -325,7 +300,7 @@ export class LayoutHelper {
|
|
|
325
300
|
if (tag && tag.indexOf(Layout.Constant.IFramePrefix) === 0) {
|
|
326
301
|
tag = node.tag.substr(Layout.Constant.IFramePrefix.length);
|
|
327
302
|
}
|
|
328
|
-
if (parent === null && node.parent !== null && node.parent > -1 && tag !==
|
|
303
|
+
if (parent === null && node.parent !== null && node.parent > -1 && tag !== "HTML") {
|
|
329
304
|
// We are referencing a parent for this node that hasn't been created yet. Push it to a list of nodes to
|
|
330
305
|
// try once we are finished with other nodes within this event. Though we don't require HTML tags to
|
|
331
306
|
// have a parent as they are typically the root.
|
|
@@ -334,26 +309,13 @@ export class LayoutHelper {
|
|
|
334
309
|
}
|
|
335
310
|
switch (tag) {
|
|
336
311
|
case Layout.Constant.DocumentTag:
|
|
337
|
-
let tagDoc =
|
|
338
|
-
tag !== node.tag
|
|
339
|
-
? parent
|
|
340
|
-
? (parent as HTMLIFrameElement).contentDocument
|
|
341
|
-
: null
|
|
342
|
-
: doc;
|
|
312
|
+
let tagDoc = tag !== node.tag ? (parent ? (parent as HTMLIFrameElement).contentDocument : null) : doc;
|
|
343
313
|
if (tagDoc && tagDoc === doc && type === Data.Event.Discover) {
|
|
344
314
|
this.reset();
|
|
345
315
|
}
|
|
346
|
-
if (typeof XMLSerializer !==
|
|
316
|
+
if (typeof XMLSerializer !== "undefined" && tagDoc) {
|
|
347
317
|
tagDoc.open();
|
|
348
|
-
tagDoc.write(
|
|
349
|
-
new XMLSerializer().serializeToString(
|
|
350
|
-
tagDoc.implementation.createDocumentType(
|
|
351
|
-
node.attributes['name'],
|
|
352
|
-
node.attributes['publicId'],
|
|
353
|
-
node.attributes['systemId'],
|
|
354
|
-
),
|
|
355
|
-
),
|
|
356
|
-
);
|
|
318
|
+
tagDoc.write(new XMLSerializer().serializeToString(tagDoc.implementation.createDocumentType(node.attributes["name"], node.attributes["publicId"], node.attributes["systemId"])));
|
|
357
319
|
tagDoc.close();
|
|
358
320
|
}
|
|
359
321
|
break;
|
|
@@ -366,9 +328,7 @@ export class LayoutHelper {
|
|
|
366
328
|
case Layout.Constant.ShadowDomTag:
|
|
367
329
|
if (parent) {
|
|
368
330
|
let shadowRoot = this.element(node.id);
|
|
369
|
-
shadowRoot = shadowRoot
|
|
370
|
-
? shadowRoot
|
|
371
|
-
: (parent as HTMLElement).attachShadow({ mode: 'open' });
|
|
331
|
+
shadowRoot = shadowRoot ? shadowRoot : (parent as HTMLElement).attachShadow({ mode: "open" });
|
|
372
332
|
this.nodes[node.id] = shadowRoot;
|
|
373
333
|
this.addToHashMap(node, shadowRoot);
|
|
374
334
|
this.addStyles(node.id);
|
|
@@ -386,7 +346,7 @@ export class LayoutHelper {
|
|
|
386
346
|
(suspendedElement as HTMLElement).setAttribute(Constant.Suspend, Layout.Constant.Empty);
|
|
387
347
|
}
|
|
388
348
|
break;
|
|
389
|
-
case
|
|
349
|
+
case "HTML":
|
|
390
350
|
if (this.primaryHtmlNodeId === null) {
|
|
391
351
|
this.primaryHtmlNodeId = node.id;
|
|
392
352
|
}
|
|
@@ -398,11 +358,7 @@ export class LayoutHelper {
|
|
|
398
358
|
this.insertDefaultElement(node, parent, pivot, doc, insert);
|
|
399
359
|
break;
|
|
400
360
|
}
|
|
401
|
-
let htmlDoc = isIframe
|
|
402
|
-
? parent
|
|
403
|
-
? (parent as HTMLIFrameElement).contentDocument
|
|
404
|
-
: null
|
|
405
|
-
: doc;
|
|
361
|
+
let htmlDoc = isIframe ? (parent ? (parent as HTMLIFrameElement).contentDocument : null) : doc;
|
|
406
362
|
if (htmlDoc !== null) {
|
|
407
363
|
let docElement = this.element(node.id) as HTMLElement;
|
|
408
364
|
if (docElement === null) {
|
|
@@ -421,75 +377,60 @@ export class LayoutHelper {
|
|
|
421
377
|
// If we are still processing discover events, keep the markup hidden until we are done
|
|
422
378
|
if (type === Data.Event.Discover && !parent) {
|
|
423
379
|
htmlDoc.documentElement.style.visibility = Constant.Hidden;
|
|
380
|
+
htmlDoc.documentElement.style.opacity = `${Constant.VisibleOpacity} !important`;
|
|
424
381
|
}
|
|
425
382
|
this.nodes[node.id] = htmlDoc.documentElement;
|
|
426
383
|
this.addToHashMap(node, htmlDoc.documentElement);
|
|
427
384
|
}
|
|
428
385
|
break;
|
|
429
|
-
case
|
|
386
|
+
case "HEAD":
|
|
430
387
|
let headElement = this.element(node.id);
|
|
431
388
|
if (headElement === null) {
|
|
432
389
|
headElement = doc.createElement(node.tag);
|
|
433
390
|
if (node.attributes && Layout.Constant.Base in node.attributes) {
|
|
434
|
-
let base = doc.createElement(
|
|
391
|
+
let base = doc.createElement("base");
|
|
435
392
|
base.href = node.attributes[Layout.Constant.Base];
|
|
436
393
|
headElement.appendChild(base);
|
|
437
394
|
}
|
|
438
395
|
|
|
439
396
|
// Add custom styles to assist with visualization
|
|
440
|
-
let custom = doc.createElement(
|
|
441
|
-
custom.setAttribute(Constant.CustomStyleTag,
|
|
397
|
+
let custom = doc.createElement("style");
|
|
398
|
+
custom.setAttribute(Constant.CustomStyleTag, "true");
|
|
442
399
|
custom.innerText = this.getCustomStyle();
|
|
443
400
|
headElement.appendChild(custom);
|
|
444
401
|
}
|
|
445
402
|
this.setAttributes(headElement as HTMLElement, node);
|
|
446
403
|
insert(node, parent, headElement, pivot);
|
|
447
404
|
break;
|
|
448
|
-
case
|
|
405
|
+
case "LINK":
|
|
449
406
|
let linkElement = this.element(node.id) as HTMLLinkElement;
|
|
450
|
-
linkElement = linkElement
|
|
451
|
-
? linkElement
|
|
452
|
-
: (this.createElement(doc, node.tag) as HTMLLinkElement);
|
|
407
|
+
linkElement = linkElement ? linkElement : (this.createElement(doc, node.tag) as HTMLLinkElement);
|
|
453
408
|
if (!node.attributes) {
|
|
454
409
|
node.attributes = {};
|
|
455
410
|
}
|
|
456
411
|
this.setAttributes(linkElement, node);
|
|
457
|
-
if (
|
|
458
|
-
if (node.attributes[
|
|
412
|
+
if ("rel" in node.attributes) {
|
|
413
|
+
if (node.attributes["rel"] === Constant.StyleSheet) {
|
|
459
414
|
this.stylesheets.push(
|
|
460
415
|
new Promise((resolve: () => void): void => {
|
|
461
416
|
const proxy = useproxy ?? this.state.options.useproxy;
|
|
462
417
|
if (proxy) {
|
|
463
418
|
if (linkElement.integrity) {
|
|
464
|
-
linkElement.removeAttribute(
|
|
419
|
+
linkElement.removeAttribute("integrity");
|
|
465
420
|
}
|
|
466
421
|
|
|
467
422
|
linkElement.href = proxy(linkElement.href, linkElement.id, Constant.StyleSheet);
|
|
468
423
|
}
|
|
469
|
-
linkElement.onload = linkElement.onerror = this.style.bind(
|
|
470
|
-
this,
|
|
471
|
-
linkElement,
|
|
472
|
-
resolve,
|
|
473
|
-
);
|
|
424
|
+
linkElement.onload = linkElement.onerror = this.style.bind(this, linkElement, resolve);
|
|
474
425
|
setTimeout(resolve, LayoutHelper.TIMEOUT);
|
|
475
426
|
}),
|
|
476
427
|
);
|
|
477
|
-
} else if (
|
|
478
|
-
(node.attributes['rel'].includes('preload') ||
|
|
479
|
-
node.attributes['rel'].includes('preconnect')) &&
|
|
480
|
-
(node.attributes?.as === 'style' || node.attributes?.as === 'font')
|
|
481
|
-
) {
|
|
428
|
+
} else if ((node.attributes["rel"].includes("preload") || node.attributes["rel"].includes("preconnect")) && (node.attributes?.as === "style" || node.attributes?.as === "font")) {
|
|
482
429
|
this.fonts.push(
|
|
483
430
|
new Promise((resolve: () => void): void => {
|
|
484
431
|
const proxy = useproxy ?? this.state.options.useproxy;
|
|
485
|
-
linkElement.href = proxy
|
|
486
|
-
|
|
487
|
-
: linkElement.href;
|
|
488
|
-
linkElement.onload = linkElement.onerror = this.style.bind(
|
|
489
|
-
this,
|
|
490
|
-
linkElement,
|
|
491
|
-
resolve,
|
|
492
|
-
);
|
|
432
|
+
linkElement.href = proxy ? proxy(linkElement.href, linkElement.id, node.attributes.as) : linkElement.href;
|
|
433
|
+
linkElement.onload = linkElement.onerror = this.style.bind(this, linkElement, resolve);
|
|
493
434
|
setTimeout(resolve, LayoutHelper.TIMEOUT);
|
|
494
435
|
}),
|
|
495
436
|
);
|
|
@@ -498,35 +439,25 @@ export class LayoutHelper {
|
|
|
498
439
|
insert(node, parent, linkElement, pivot);
|
|
499
440
|
break;
|
|
500
441
|
case Layout.Constant.ImageTag:
|
|
501
|
-
let imgElement =
|
|
502
|
-
(this.element(node.id) as HTMLImageElement) ??
|
|
503
|
-
(this.createElement(doc, node.tag) as HTMLImageElement);
|
|
442
|
+
let imgElement = (this.element(node.id) as HTMLImageElement) ?? (this.createElement(doc, node.tag) as HTMLImageElement);
|
|
504
443
|
const proxy = useproxy ?? this.state.options.useproxy;
|
|
505
444
|
if (proxy && !!node.attributes?.src) {
|
|
506
|
-
node.attributes.src = proxy(
|
|
507
|
-
node.attributes.src,
|
|
508
|
-
node.attributes.id,
|
|
509
|
-
Layout.Constant.ImageTag,
|
|
510
|
-
);
|
|
445
|
+
node.attributes.src = proxy(node.attributes.src, node.attributes.id, Layout.Constant.ImageTag);
|
|
511
446
|
}
|
|
512
447
|
this.setAttributes(imgElement, node);
|
|
513
448
|
this.resize(imgElement, node.width, node.height);
|
|
514
449
|
insert(node, parent, imgElement, pivot);
|
|
515
450
|
break;
|
|
516
|
-
case
|
|
517
|
-
let styleElement =
|
|
518
|
-
(this.element(node.id) as HTMLStyleElement) ??
|
|
519
|
-
(doc.createElement(node.tag) as HTMLStyleElement);
|
|
451
|
+
case "STYLE":
|
|
452
|
+
let styleElement = (this.element(node.id) as HTMLStyleElement) ?? (doc.createElement(node.tag) as HTMLStyleElement);
|
|
520
453
|
this.setAttributes(styleElement, node);
|
|
521
454
|
styleElement.textContent = node.value;
|
|
522
455
|
insert(node, parent, styleElement, pivot);
|
|
523
456
|
this.style(styleElement);
|
|
524
457
|
break;
|
|
525
|
-
case
|
|
458
|
+
case "IFRAME":
|
|
526
459
|
let iframeElement = this.element(node.id) as HTMLIFrameElement;
|
|
527
|
-
iframeElement = iframeElement
|
|
528
|
-
? iframeElement
|
|
529
|
-
: (this.createElement(doc, node.tag) as HTMLIFrameElement);
|
|
460
|
+
iframeElement = iframeElement ? iframeElement : (this.createElement(doc, node.tag) as HTMLIFrameElement);
|
|
530
461
|
if (!node.attributes) {
|
|
531
462
|
node.attributes = {};
|
|
532
463
|
}
|
|
@@ -549,13 +480,7 @@ export class LayoutHelper {
|
|
|
549
480
|
}
|
|
550
481
|
};
|
|
551
482
|
|
|
552
|
-
private insertDefaultElement = (
|
|
553
|
-
node: DecodedLayout.DomData,
|
|
554
|
-
parent: Node,
|
|
555
|
-
pivot: Node,
|
|
556
|
-
doc: Document,
|
|
557
|
-
insert: (data: DecodedLayout.DomData, parent: Node, node: Node, previous: Node) => void,
|
|
558
|
-
): void => {
|
|
483
|
+
private insertDefaultElement = (node: DecodedLayout.DomData, parent: Node, pivot: Node, doc: Document, insert: (data: DecodedLayout.DomData, parent: Node, node: Node, previous: Node) => void): void => {
|
|
559
484
|
let domElement = this.element(node.id) as HTMLElement;
|
|
560
485
|
domElement = domElement ? domElement : this.createElement(doc, node.tag);
|
|
561
486
|
this.setAttributes(domElement as HTMLElement, node);
|
|
@@ -596,10 +521,7 @@ export class LayoutHelper {
|
|
|
596
521
|
|
|
597
522
|
private createElement = (doc: Document, tag: string): HTMLElement => {
|
|
598
523
|
if (tag && tag.indexOf(Layout.Constant.SvgPrefix) === 0) {
|
|
599
|
-
return doc.createElementNS(
|
|
600
|
-
Layout.Constant.SvgNamespace as string,
|
|
601
|
-
tag.substr(Layout.Constant.SvgPrefix.length),
|
|
602
|
-
) as HTMLElement;
|
|
524
|
+
return doc.createElementNS(Layout.Constant.SvgNamespace as string, tag.substr(Layout.Constant.SvgPrefix.length)) as HTMLElement;
|
|
603
525
|
}
|
|
604
526
|
try {
|
|
605
527
|
return doc.createElement(tag);
|
|
@@ -610,26 +532,14 @@ export class LayoutHelper {
|
|
|
610
532
|
}
|
|
611
533
|
};
|
|
612
534
|
|
|
613
|
-
private insertAfter = (
|
|
614
|
-
data: DecodedLayout.DomData,
|
|
615
|
-
parent: Node,
|
|
616
|
-
node: Node,
|
|
617
|
-
previous: Node,
|
|
618
|
-
): void => {
|
|
535
|
+
private insertAfter = (data: DecodedLayout.DomData, parent: Node, node: Node, previous: Node): void => {
|
|
619
536
|
// Skip over no-op changes where parent and previous element is still the same
|
|
620
537
|
// In case of IFRAME, re-adding DOM at the exact same place will lead to loss of state and the markup inside will be destroyed
|
|
621
|
-
if (
|
|
622
|
-
this.events[data.id] &&
|
|
623
|
-
this.events[data.id].parent === data.parent &&
|
|
624
|
-
this.events[data.id].previous === data.previous
|
|
625
|
-
) {
|
|
538
|
+
if (this.events[data.id] && this.events[data.id].parent === data.parent && this.events[data.id].previous === data.previous) {
|
|
626
539
|
return;
|
|
627
540
|
}
|
|
628
541
|
// In case parent is a Shadow DOM, previous.parentElement will return null but previous.parentNode will return a valid node
|
|
629
|
-
let next =
|
|
630
|
-
previous && (previous.parentElement === parent || previous.parentNode === parent)
|
|
631
|
-
? previous.nextSibling
|
|
632
|
-
: null;
|
|
542
|
+
let next = previous && (previous.parentElement === parent || previous.parentNode === parent) ? previous.nextSibling : null;
|
|
633
543
|
next = previous === null && parent ? this.firstChild(parent) : next;
|
|
634
544
|
this.insertBefore(data, parent, node, next);
|
|
635
545
|
};
|
|
@@ -637,12 +547,8 @@ export class LayoutHelper {
|
|
|
637
547
|
private firstChild = (node: Node): ChildNode => {
|
|
638
548
|
let child = node.firstChild;
|
|
639
549
|
// BASE tag should always be the first child to ensure resources with relative URLs are loaded correctly
|
|
640
|
-
if (
|
|
641
|
-
child
|
|
642
|
-
child.nodeType === NodeType.ELEMENT_NODE &&
|
|
643
|
-
(child as HTMLElement).tagName === Layout.Constant.BaseTag
|
|
644
|
-
) {
|
|
645
|
-
if ((child.nextSibling as HTMLElement)?.hasAttribute('clarity-custom-styles')) {
|
|
550
|
+
if (child && child.nodeType === NodeType.ELEMENT_NODE && (child as HTMLElement).tagName === Layout.Constant.BaseTag) {
|
|
551
|
+
if ((child.nextSibling as HTMLElement)?.hasAttribute("clarity-custom-styles")) {
|
|
646
552
|
// Keep the custom style tag on top of the head to let client tags override its values.
|
|
647
553
|
return child.nextSibling.nextSibling;
|
|
648
554
|
}
|
|
@@ -653,17 +559,10 @@ export class LayoutHelper {
|
|
|
653
559
|
|
|
654
560
|
// Mask images within a masked ancestor element in the node has a background image.
|
|
655
561
|
private mask = (node: HTMLElement) => {
|
|
656
|
-
if (
|
|
657
|
-
node &&
|
|
658
|
-
this.BackgroundImageEligibleElements.includes(node.nodeName) &&
|
|
659
|
-
'getComputedStyle' in window &&
|
|
660
|
-
'closest' in node
|
|
661
|
-
) {
|
|
562
|
+
if (node && this.BackgroundImageEligibleElements.includes(node.nodeName) && "getComputedStyle" in window && "closest" in node) {
|
|
662
563
|
const urlPattern = /url\(['"]?([^'")]+)['"]?\)/;
|
|
663
564
|
const computedStyles = window.getComputedStyle(node);
|
|
664
|
-
const hasBackgroundImage =
|
|
665
|
-
computedStyles.backgroundImage?.match(urlPattern) ||
|
|
666
|
-
computedStyles.background?.match(urlPattern);
|
|
565
|
+
const hasBackgroundImage = computedStyles.backgroundImage?.match(urlPattern) || computedStyles.background?.match(urlPattern);
|
|
667
566
|
const masked = node.closest?.(`[${LayoutConstants.MaskData}]`);
|
|
668
567
|
|
|
669
568
|
if (hasBackgroundImage && masked) {
|
|
@@ -672,12 +571,7 @@ export class LayoutHelper {
|
|
|
672
571
|
}
|
|
673
572
|
};
|
|
674
573
|
|
|
675
|
-
private insertBefore = (
|
|
676
|
-
data: DecodedLayout.DomData,
|
|
677
|
-
parent: Node,
|
|
678
|
-
node: Node,
|
|
679
|
-
next: Node,
|
|
680
|
-
): void => {
|
|
574
|
+
private insertBefore = (data: DecodedLayout.DomData, parent: Node, node: Node, next: Node): void => {
|
|
681
575
|
if (parent !== null) {
|
|
682
576
|
// Compare against both parentNode and parentElement to ensure visualization works correctly for shadow DOMs
|
|
683
577
|
next = next && next.parentElement !== parent && next.parentNode !== parent ? null : next;
|
|
@@ -685,8 +579,8 @@ export class LayoutHelper {
|
|
|
685
579
|
parent.insertBefore(node, next);
|
|
686
580
|
this.mask(node as HTMLElement);
|
|
687
581
|
} catch (ex) {
|
|
688
|
-
console.warn(
|
|
689
|
-
console.warn(
|
|
582
|
+
console.warn("Node: " + node + " | Parent: " + parent + " | Data: " + JSON.stringify(data));
|
|
583
|
+
console.warn("Exception encountered while inserting node: " + ex);
|
|
690
584
|
}
|
|
691
585
|
} else if (parent === null && node.parentElement !== null) {
|
|
692
586
|
node.parentElement.removeChild(node);
|
|
@@ -725,25 +619,17 @@ export class LayoutHelper {
|
|
|
725
619
|
if (attributes[attribute] !== undefined) {
|
|
726
620
|
try {
|
|
727
621
|
let v = attributes[attribute];
|
|
728
|
-
if (attribute.indexOf(
|
|
729
|
-
node.setAttributeNS(
|
|
622
|
+
if (attribute.indexOf("xlink:") === 0) {
|
|
623
|
+
node.setAttributeNS("http://www.w3.org/1999/xlink", attribute, v);
|
|
730
624
|
} else if (attribute.indexOf(Layout.Constant.SameOrigin) === 0) {
|
|
731
625
|
sameorigin = true;
|
|
732
|
-
} else if (attribute.indexOf(
|
|
626
|
+
} else if (attribute.indexOf("*") === 0) {
|
|
733
627
|
// Do nothing if we encounter internal Clarity attributes
|
|
734
|
-
} else if (
|
|
735
|
-
(tag === Constant.IFrameTag &&
|
|
736
|
-
(attribute.indexOf('src') === 0 || attribute.indexOf('allow') === 0)) ||
|
|
737
|
-
attribute === 'sandbox'
|
|
738
|
-
) {
|
|
628
|
+
} else if ((tag === Constant.IFrameTag && (attribute.indexOf("src") === 0 || attribute.indexOf("allow") === 0)) || attribute === "sandbox") {
|
|
739
629
|
node.setAttribute(`data-clarity-${attribute}`, v);
|
|
740
|
-
} else if (
|
|
741
|
-
tag === Constant.ImageTag &&
|
|
742
|
-
attribute.indexOf('src') === 0 &&
|
|
743
|
-
(v === null || v.length === 0 || v?.startsWith('blob:'))
|
|
744
|
-
) {
|
|
630
|
+
} else if (tag === Constant.ImageTag && attribute.indexOf("src") === 0 && (v === null || v.length === 0 || v?.startsWith("blob:"))) {
|
|
745
631
|
if (this.vNext) {
|
|
746
|
-
if (v.startsWith(
|
|
632
|
+
if (v.startsWith("blob:")) {
|
|
747
633
|
if (data.width >= Setting.LargeSvg && data.height >= Setting.LargeSvg) {
|
|
748
634
|
node.setAttribute(Constant.BlobUnavailable, `${Constant.Large}${Constant.Beta}`);
|
|
749
635
|
} else {
|
|
@@ -760,12 +646,7 @@ export class LayoutHelper {
|
|
|
760
646
|
node.setAttribute(attribute, Asset.Transparent);
|
|
761
647
|
let size = Constant.Large;
|
|
762
648
|
if (data.width) {
|
|
763
|
-
size =
|
|
764
|
-
data.width <= Setting.Medium
|
|
765
|
-
? Constant.Medium
|
|
766
|
-
: data.width <= Setting.Small
|
|
767
|
-
? Constant.Small
|
|
768
|
-
: size;
|
|
649
|
+
size = data.width <= Setting.Medium ? Constant.Medium : data.width <= Setting.Small ? Constant.Small : size;
|
|
769
650
|
}
|
|
770
651
|
node.setAttribute(Constant.Hide, size);
|
|
771
652
|
}
|
|
@@ -773,17 +654,13 @@ export class LayoutHelper {
|
|
|
773
654
|
node.setAttribute(attribute, v);
|
|
774
655
|
}
|
|
775
656
|
} catch (ex) {
|
|
776
|
-
console.warn(
|
|
777
|
-
console.warn(
|
|
657
|
+
console.warn("Node: " + node + " | " + JSON.stringify(attributes));
|
|
658
|
+
console.warn("Exception encountered while adding attributes: " + ex);
|
|
778
659
|
}
|
|
779
660
|
}
|
|
780
661
|
}
|
|
781
662
|
|
|
782
|
-
if (
|
|
783
|
-
sameorigin === false &&
|
|
784
|
-
tag === Constant.IFrameTag &&
|
|
785
|
-
typeof node.setAttribute === Constant.Function
|
|
786
|
-
) {
|
|
663
|
+
if (sameorigin === false && tag === Constant.IFrameTag && typeof node.setAttribute === Constant.Function) {
|
|
787
664
|
if (this.svgFitsText(node)) {
|
|
788
665
|
node.setAttribute(Constant.Unavailable, Layout.Constant.Empty);
|
|
789
666
|
} else {
|
|
@@ -810,7 +687,7 @@ export class LayoutHelper {
|
|
|
810
687
|
return `*{scrollbar-width: none; scrollbar-gutter: unset;};`;
|
|
811
688
|
}
|
|
812
689
|
|
|
813
|
-
return
|
|
690
|
+
return "";
|
|
814
691
|
};
|
|
815
692
|
|
|
816
693
|
private getCustomStyle = (): string => {
|
|
@@ -835,10 +712,7 @@ export class LayoutHelper {
|
|
|
835
712
|
|
|
836
713
|
private getIframeUnavailableCss = (): string => {
|
|
837
714
|
if (this.vNext) {
|
|
838
|
-
return
|
|
839
|
-
`${Constant.IFrameTag}[${Constant.UnavailableSmall}] { ${iframeUnavailableSvgSmall} }` +
|
|
840
|
-
`${Constant.IFrameTag}[${Constant.Unavailable}] { ${iframeUnavailableSvg[this.locale]} }`
|
|
841
|
-
);
|
|
715
|
+
return `${Constant.IFrameTag}[${Constant.UnavailableSmall}] { ${iframeUnavailableSvgSmall} }` + `${Constant.IFrameTag}[${Constant.Unavailable}] { ${iframeUnavailableSvg[this.locale]} }`;
|
|
842
716
|
} else {
|
|
843
717
|
return `${Constant.IFrameTag}[${Constant.Unavailable}] { background: url(${Asset.Unavailable}) no-repeat center center, url('${Asset.Cross}'); }`;
|
|
844
718
|
}
|
|
@@ -846,20 +720,14 @@ export class LayoutHelper {
|
|
|
846
720
|
|
|
847
721
|
private getBlobUnavailableCss = (): string => {
|
|
848
722
|
if (this.vNext) {
|
|
849
|
-
return
|
|
850
|
-
`${Constant.ImageTag}[${Constant.BlobUnavailable}=${Constant.Small}${Constant.Beta}] { ${blobUnavailableSvgSmall} }` +
|
|
851
|
-
`${Constant.ImageTag}[${Constant.BlobUnavailable}=${Constant.Large}${Constant.Beta}] { ${blobUnavailableSvg[this.locale]} }`
|
|
852
|
-
);
|
|
723
|
+
return `${Constant.ImageTag}[${Constant.BlobUnavailable}=${Constant.Small}${Constant.Beta}] { ${blobUnavailableSvgSmall} }` + `${Constant.ImageTag}[${Constant.BlobUnavailable}=${Constant.Large}${Constant.Beta}] { ${blobUnavailableSvg[this.locale]} }`;
|
|
853
724
|
}
|
|
854
|
-
return
|
|
725
|
+
return "";
|
|
855
726
|
};
|
|
856
727
|
|
|
857
728
|
private getImageHiddenCss = (): string => {
|
|
858
729
|
if (this.vNext) {
|
|
859
|
-
return
|
|
860
|
-
`${Constant.ImageTag}[${Constant.Hide}=${Constant.Small}${Constant.Beta}] { ${imageMaskedSvgSmall} }` +
|
|
861
|
-
`${Constant.ImageTag}[${Constant.Hide}=${Constant.Large}${Constant.Beta}] { ${imageMaskedSvg[this.locale]} }`
|
|
862
|
-
);
|
|
730
|
+
return `${Constant.ImageTag}[${Constant.Hide}=${Constant.Small}${Constant.Beta}] { ${imageMaskedSvgSmall} }` + `${Constant.ImageTag}[${Constant.Hide}=${Constant.Large}${Constant.Beta}] { ${imageMaskedSvg[this.locale]} }`;
|
|
863
731
|
} else {
|
|
864
732
|
return (
|
|
865
733
|
`${Constant.ImageTag}[${Constant.Hide}] { background-color: #CCC; background-image: url(${Asset.Hide}); background-repeat:no-repeat; background-position: center; }` +
|
|
@@ -874,6 +742,6 @@ export class LayoutHelper {
|
|
|
874
742
|
if (this.vNext) {
|
|
875
743
|
return sharedStyle;
|
|
876
744
|
}
|
|
877
|
-
return
|
|
745
|
+
return "";
|
|
878
746
|
};
|
|
879
747
|
}
|
package/src/visualizer.ts
CHANGED
|
@@ -1,24 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Setting,
|
|
11
|
-
ShortCircuitStrategy,
|
|
12
|
-
Visualizer as VisualizerType,
|
|
13
|
-
} from '@clarity-types/visualize';
|
|
14
|
-
import { Data } from 'clarity-js';
|
|
15
|
-
import type { Data as DecodedData, Interaction, Layout } from 'clarity-decode';
|
|
16
|
-
import { DataHelper } from './data';
|
|
17
|
-
import { EnrichHelper } from './enrich';
|
|
18
|
-
import { HeatmapHelper } from './heatmap';
|
|
19
|
-
import { InteractionHelper } from './interaction';
|
|
20
|
-
import { LayoutHelper } from './layout';
|
|
21
|
-
import { Dimension } from 'clarity-js/types/data';
|
|
1
|
+
import { Activity, Constant, ErrorLogger, LinkHandler, MergedPayload, Options, PlaybackState, ScrollMapInfo, Setting, ShortCircuitStrategy, Visualizer as VisualizerType } from "@clarity-types/visualize";
|
|
2
|
+
import { Data } from "clarity-js";
|
|
3
|
+
import type { Data as DecodedData, Interaction, Layout } from "clarity-decode";
|
|
4
|
+
import { DataHelper } from "./data";
|
|
5
|
+
import { EnrichHelper } from "./enrich";
|
|
6
|
+
import { HeatmapHelper } from "./heatmap";
|
|
7
|
+
import { InteractionHelper } from "./interaction";
|
|
8
|
+
import { LayoutHelper } from "./layout";
|
|
9
|
+
import { Dimension } from "clarity-js/types/data";
|
|
22
10
|
|
|
23
11
|
export class Visualizer implements VisualizerType {
|
|
24
12
|
_state: PlaybackState = null;
|
|
@@ -43,11 +31,7 @@ export class Visualizer implements VisualizerType {
|
|
|
43
31
|
return this.layout?.get(hash);
|
|
44
32
|
};
|
|
45
33
|
|
|
46
|
-
private shortCircuitRendering = (
|
|
47
|
-
strategy: ShortCircuitStrategy,
|
|
48
|
-
domEvent: Layout.DomEvent,
|
|
49
|
-
hash: string,
|
|
50
|
-
) => {
|
|
34
|
+
private shortCircuitRendering = (strategy: ShortCircuitStrategy, domEvent: Layout.DomEvent, hash: string) => {
|
|
51
35
|
switch (strategy) {
|
|
52
36
|
case ShortCircuitStrategy.HashFirstTimestamp:
|
|
53
37
|
return this.layout.exists(hash);
|
|
@@ -55,10 +39,7 @@ export class Visualizer implements VisualizerType {
|
|
|
55
39
|
if (this.hashFoundTime === -1 && this.layout.exists(hash)) {
|
|
56
40
|
this.hashFoundTime = domEvent.time;
|
|
57
41
|
}
|
|
58
|
-
return
|
|
59
|
-
this.hashFoundTime > -1 &&
|
|
60
|
-
domEvent.time > this.hashFoundTime + Setting.VisualizationSettleBuffer
|
|
61
|
-
);
|
|
42
|
+
return this.hashFoundTime > -1 && domEvent.time > this.hashFoundTime + Setting.VisualizationSettleBuffer;
|
|
62
43
|
case ShortCircuitStrategy.HashBeforeDeleted:
|
|
63
44
|
for (let node of domEvent.data) {
|
|
64
45
|
if ((node.hashAlpha === hash || node.hashBeta === hash) && node.parent === null) {
|
|
@@ -72,14 +53,7 @@ export class Visualizer implements VisualizerType {
|
|
|
72
53
|
}
|
|
73
54
|
};
|
|
74
55
|
|
|
75
|
-
public html = async (
|
|
76
|
-
decoded: DecodedData.DecodedPayload[],
|
|
77
|
-
target: Window,
|
|
78
|
-
hash: string = null,
|
|
79
|
-
useproxy?: LinkHandler,
|
|
80
|
-
logerror?: ErrorLogger,
|
|
81
|
-
shortCircuitStrategy: ShortCircuitStrategy = ShortCircuitStrategy.None,
|
|
82
|
-
): Promise<Visualizer> => {
|
|
56
|
+
public html = async (decoded: DecodedData.DecodedPayload[], target: Window, hash: string = null, useproxy?: LinkHandler, logerror?: ErrorLogger, shortCircuitStrategy: ShortCircuitStrategy = ShortCircuitStrategy.None): Promise<Visualizer> => {
|
|
83
57
|
if (decoded && decoded.length > 0 && target) {
|
|
84
58
|
try {
|
|
85
59
|
// Flatten the payload and parse all events out of them, sorted by time
|
|
@@ -132,6 +106,7 @@ export class Visualizer implements VisualizerType {
|
|
|
132
106
|
};
|
|
133
107
|
|
|
134
108
|
public clearmap = (): void => {
|
|
109
|
+
console.log(`🚀 🐥 ~ Visualizer ~ this.state:`, this.state);
|
|
135
110
|
if (this.state === null) {
|
|
136
111
|
throw new Error(`Initialize heatmap by calling "html" or "setup" prior to making this call.`);
|
|
137
112
|
}
|
|
@@ -185,8 +160,8 @@ export class Visualizer implements VisualizerType {
|
|
|
185
160
|
public setup = async (target: Window, options: Options): Promise<Visualizer> => {
|
|
186
161
|
this.reset();
|
|
187
162
|
// Infer options
|
|
188
|
-
options.canvas =
|
|
189
|
-
options.keyframes =
|
|
163
|
+
options.canvas = "canvas" in options ? options.canvas : true;
|
|
164
|
+
options.keyframes = "keyframes" in options ? options.keyframes : false;
|
|
190
165
|
|
|
191
166
|
// Set visualization state
|
|
192
167
|
this._state = { window: target, options };
|