@midscene/recorder 1.0.2 → 1.0.3-beta-20251221011051.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/recorder-iife.js +49 -7
- package/dist/recorder.js +49 -7
- package/dist/types/src/recorder.d.ts +3 -0
- package/package.json +2 -2
package/dist/recorder-iife.js
CHANGED
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
}
|
|
115
115
|
function generateHashId(type, elementRect) {
|
|
116
116
|
const rectStr = elementRect ? `${elementRect.left}_${elementRect.top}_${elementRect.width}_${elementRect.height}${void 0 !== elementRect.x ? `_${elementRect.x}` : ''}${void 0 !== elementRect.y ? `_${elementRect.y}` : ''}` : 'no_rect';
|
|
117
|
-
const combined = `${type}_${rectStr}`;
|
|
117
|
+
const combined = `${type}_${rectStr}_${Date.now()}`;
|
|
118
118
|
let hash = 0;
|
|
119
119
|
for(let i = 0; i < combined.length; i++){
|
|
120
120
|
const char = combined.charCodeAt(i);
|
|
@@ -131,16 +131,19 @@
|
|
|
131
131
|
if ('click' === event.type && event.isLabelClick) return event;
|
|
132
132
|
}
|
|
133
133
|
};
|
|
134
|
+
function isElementScrollable(el) {
|
|
135
|
+
const style = window.getComputedStyle(el);
|
|
136
|
+
const overflowY = style.overflowY;
|
|
137
|
+
const overflowX = style.overflowX;
|
|
138
|
+
const isScrollableY = ('auto' === overflowY || 'scroll' === overflowY) && el.scrollHeight > el.clientHeight;
|
|
139
|
+
const isScrollableX = ('auto' === overflowX || 'scroll' === overflowX) && el.scrollWidth > el.clientWidth;
|
|
140
|
+
return isScrollableY || isScrollableX;
|
|
141
|
+
}
|
|
134
142
|
function getAllScrollableElements() {
|
|
135
143
|
const elements = [];
|
|
136
144
|
const all = document.querySelectorAll('body *');
|
|
137
145
|
all.forEach((el)=>{
|
|
138
|
-
|
|
139
|
-
const overflowY = style.overflowY;
|
|
140
|
-
const overflowX = style.overflowX;
|
|
141
|
-
const isScrollableY = ('auto' === overflowY || 'scroll' === overflowY) && el.scrollHeight > el.clientHeight;
|
|
142
|
-
const isScrollableX = ('auto' === overflowX || 'scroll' === overflowX) && el.scrollWidth > el.clientWidth;
|
|
143
|
-
if (isScrollableY || isScrollableX) elements.push(el);
|
|
146
|
+
if (isElementScrollable(el)) elements.push(el);
|
|
144
147
|
});
|
|
145
148
|
return elements;
|
|
146
149
|
}
|
|
@@ -154,6 +157,7 @@
|
|
|
154
157
|
lastViewportScroll = null;
|
|
155
158
|
scrollTargets = [];
|
|
156
159
|
sessionId;
|
|
160
|
+
mutationObserver = null;
|
|
157
161
|
constructor(eventCallback, sessionId){
|
|
158
162
|
this.eventCallback = eventCallback;
|
|
159
163
|
this.sessionId = sessionId;
|
|
@@ -171,6 +175,33 @@
|
|
|
171
175
|
hashId: `navigation_${Date.now()}`
|
|
172
176
|
};
|
|
173
177
|
}
|
|
178
|
+
checkAndAddScrollListeners(element) {
|
|
179
|
+
if (isElementScrollable(element) && !this.scrollTargets.includes(element)) {
|
|
180
|
+
element.addEventListener('scroll', this.handleScroll, {
|
|
181
|
+
passive: true
|
|
182
|
+
});
|
|
183
|
+
this.scrollTargets.push(element);
|
|
184
|
+
debugLog('Added scroll listener to dynamic element:', element);
|
|
185
|
+
}
|
|
186
|
+
const descendants = element.querySelectorAll('*');
|
|
187
|
+
descendants.forEach((descendant)=>{
|
|
188
|
+
if (isElementScrollable(descendant) && !this.scrollTargets.includes(descendant)) {
|
|
189
|
+
descendant.addEventListener('scroll', this.handleScroll, {
|
|
190
|
+
passive: true
|
|
191
|
+
});
|
|
192
|
+
this.scrollTargets.push(descendant);
|
|
193
|
+
debugLog('Added scroll listener to dynamic descendant:', descendant);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
handleMutations = (mutations)=>{
|
|
198
|
+
if (!this.isRecording) return;
|
|
199
|
+
mutations.forEach((mutation)=>{
|
|
200
|
+
mutation.addedNodes.forEach((node)=>{
|
|
201
|
+
if (node instanceof HTMLElement) this.checkAndAddScrollListeners(node);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
};
|
|
174
205
|
start() {
|
|
175
206
|
if (this.isRecording) return void debugLog('Recording already active, ignoring start request');
|
|
176
207
|
this.isRecording = true;
|
|
@@ -196,6 +227,12 @@
|
|
|
196
227
|
passive: true
|
|
197
228
|
});
|
|
198
229
|
});
|
|
230
|
+
this.mutationObserver = new MutationObserver(this.handleMutations);
|
|
231
|
+
this.mutationObserver.observe(document.body, {
|
|
232
|
+
childList: true,
|
|
233
|
+
subtree: true
|
|
234
|
+
});
|
|
235
|
+
debugLog('MutationObserver started to detect dynamic scrollable elements');
|
|
199
236
|
}
|
|
200
237
|
stop() {
|
|
201
238
|
if (!this.isRecording) return void debugLog('Recording not active, ignoring stop request');
|
|
@@ -214,6 +251,11 @@
|
|
|
214
251
|
this.scrollTargets.forEach((target)=>{
|
|
215
252
|
target.removeEventListener('scroll', this.handleScroll);
|
|
216
253
|
});
|
|
254
|
+
if (this.mutationObserver) {
|
|
255
|
+
this.mutationObserver.disconnect();
|
|
256
|
+
this.mutationObserver = null;
|
|
257
|
+
debugLog('MutationObserver stopped');
|
|
258
|
+
}
|
|
217
259
|
debugLog('Removed all event listeners');
|
|
218
260
|
}
|
|
219
261
|
handleClick = (event)=>{
|
package/dist/recorder.js
CHANGED
|
@@ -5,7 +5,7 @@ function debugLog(...args) {
|
|
|
5
5
|
}
|
|
6
6
|
function generateHashId(type, elementRect) {
|
|
7
7
|
const rectStr = elementRect ? `${elementRect.left}_${elementRect.top}_${elementRect.width}_${elementRect.height}${void 0 !== elementRect.x ? `_${elementRect.x}` : ''}${void 0 !== elementRect.y ? `_${elementRect.y}` : ''}` : 'no_rect';
|
|
8
|
-
const combined = `${type}_${rectStr}`;
|
|
8
|
+
const combined = `${type}_${rectStr}_${Date.now()}`;
|
|
9
9
|
let hash = 0;
|
|
10
10
|
for(let i = 0; i < combined.length; i++){
|
|
11
11
|
const char = combined.charCodeAt(i);
|
|
@@ -22,16 +22,19 @@ const getLastLabelClick = (events)=>{
|
|
|
22
22
|
if ('click' === event.type && event.isLabelClick) return event;
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
+
function isElementScrollable(el) {
|
|
26
|
+
const style = window.getComputedStyle(el);
|
|
27
|
+
const overflowY = style.overflowY;
|
|
28
|
+
const overflowX = style.overflowX;
|
|
29
|
+
const isScrollableY = ('auto' === overflowY || 'scroll' === overflowY) && el.scrollHeight > el.clientHeight;
|
|
30
|
+
const isScrollableX = ('auto' === overflowX || 'scroll' === overflowX) && el.scrollWidth > el.clientWidth;
|
|
31
|
+
return isScrollableY || isScrollableX;
|
|
32
|
+
}
|
|
25
33
|
function getAllScrollableElements() {
|
|
26
34
|
const elements = [];
|
|
27
35
|
const all = document.querySelectorAll('body *');
|
|
28
36
|
all.forEach((el)=>{
|
|
29
|
-
|
|
30
|
-
const overflowY = style.overflowY;
|
|
31
|
-
const overflowX = style.overflowX;
|
|
32
|
-
const isScrollableY = ('auto' === overflowY || 'scroll' === overflowY) && el.scrollHeight > el.clientHeight;
|
|
33
|
-
const isScrollableX = ('auto' === overflowX || 'scroll' === overflowX) && el.scrollWidth > el.clientWidth;
|
|
34
|
-
if (isScrollableY || isScrollableX) elements.push(el);
|
|
37
|
+
if (isElementScrollable(el)) elements.push(el);
|
|
35
38
|
});
|
|
36
39
|
return elements;
|
|
37
40
|
}
|
|
@@ -45,6 +48,7 @@ class EventRecorder {
|
|
|
45
48
|
lastViewportScroll = null;
|
|
46
49
|
scrollTargets = [];
|
|
47
50
|
sessionId;
|
|
51
|
+
mutationObserver = null;
|
|
48
52
|
constructor(eventCallback, sessionId){
|
|
49
53
|
this.eventCallback = eventCallback;
|
|
50
54
|
this.sessionId = sessionId;
|
|
@@ -62,6 +66,33 @@ class EventRecorder {
|
|
|
62
66
|
hashId: `navigation_${Date.now()}`
|
|
63
67
|
};
|
|
64
68
|
}
|
|
69
|
+
checkAndAddScrollListeners(element) {
|
|
70
|
+
if (isElementScrollable(element) && !this.scrollTargets.includes(element)) {
|
|
71
|
+
element.addEventListener('scroll', this.handleScroll, {
|
|
72
|
+
passive: true
|
|
73
|
+
});
|
|
74
|
+
this.scrollTargets.push(element);
|
|
75
|
+
debugLog('Added scroll listener to dynamic element:', element);
|
|
76
|
+
}
|
|
77
|
+
const descendants = element.querySelectorAll('*');
|
|
78
|
+
descendants.forEach((descendant)=>{
|
|
79
|
+
if (isElementScrollable(descendant) && !this.scrollTargets.includes(descendant)) {
|
|
80
|
+
descendant.addEventListener('scroll', this.handleScroll, {
|
|
81
|
+
passive: true
|
|
82
|
+
});
|
|
83
|
+
this.scrollTargets.push(descendant);
|
|
84
|
+
debugLog('Added scroll listener to dynamic descendant:', descendant);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
handleMutations = (mutations)=>{
|
|
89
|
+
if (!this.isRecording) return;
|
|
90
|
+
mutations.forEach((mutation)=>{
|
|
91
|
+
mutation.addedNodes.forEach((node)=>{
|
|
92
|
+
if (node instanceof HTMLElement) this.checkAndAddScrollListeners(node);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
};
|
|
65
96
|
start() {
|
|
66
97
|
if (this.isRecording) return void debugLog('Recording already active, ignoring start request');
|
|
67
98
|
this.isRecording = true;
|
|
@@ -87,6 +118,12 @@ class EventRecorder {
|
|
|
87
118
|
passive: true
|
|
88
119
|
});
|
|
89
120
|
});
|
|
121
|
+
this.mutationObserver = new MutationObserver(this.handleMutations);
|
|
122
|
+
this.mutationObserver.observe(document.body, {
|
|
123
|
+
childList: true,
|
|
124
|
+
subtree: true
|
|
125
|
+
});
|
|
126
|
+
debugLog('MutationObserver started to detect dynamic scrollable elements');
|
|
90
127
|
}
|
|
91
128
|
stop() {
|
|
92
129
|
if (!this.isRecording) return void debugLog('Recording not active, ignoring stop request');
|
|
@@ -105,6 +142,11 @@ class EventRecorder {
|
|
|
105
142
|
this.scrollTargets.forEach((target)=>{
|
|
106
143
|
target.removeEventListener('scroll', this.handleScroll);
|
|
107
144
|
});
|
|
145
|
+
if (this.mutationObserver) {
|
|
146
|
+
this.mutationObserver.disconnect();
|
|
147
|
+
this.mutationObserver = null;
|
|
148
|
+
debugLog('MutationObserver stopped');
|
|
149
|
+
}
|
|
108
150
|
debugLog('Removed all event listeners');
|
|
109
151
|
}
|
|
110
152
|
handleClick = (event)=>{
|
|
@@ -49,8 +49,11 @@ export declare class EventRecorder {
|
|
|
49
49
|
private lastViewportScroll;
|
|
50
50
|
private scrollTargets;
|
|
51
51
|
private sessionId;
|
|
52
|
+
private mutationObserver;
|
|
52
53
|
constructor(eventCallback: EventCallback, sessionId: string);
|
|
53
54
|
createNavigationEvent(url: string, title: string): ChromeRecordedEvent;
|
|
55
|
+
private checkAndAddScrollListeners;
|
|
56
|
+
private handleMutations;
|
|
54
57
|
start(): void;
|
|
55
58
|
stop(): void;
|
|
56
59
|
private handleClick;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/recorder",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3-beta-20251221011051.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"antd": "^5.21.6",
|
|
25
25
|
"dayjs": "^1.11.11",
|
|
26
26
|
"react-dom": "18.3.1",
|
|
27
|
-
"@midscene/shared": "1.0.
|
|
27
|
+
"@midscene/shared": "1.0.3-beta-20251221011051.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"react": "18.3.1",
|