mirror of
https://github.com/hangwin/mcp-chrome.git
synced 2026-09-24 23:24:04 +08:00
fix: recorder bug fix(scroll)
This commit is contained in:
@@ -263,7 +263,6 @@ const registry: Partial<Record<Step['type'], NodeRuntime<any>>> = {
|
||||
const s: any = expandTemplatesDeep(step as any, ctx.vars);
|
||||
const located = await locateElement(tabId, s.target, ctx.frameId);
|
||||
const frameId = (located as any)?.frameId ?? ctx.frameId;
|
||||
const frameId = (located as any)?.frameId ?? ctx.frameId;
|
||||
const first = s.target?.candidates?.[0]?.type;
|
||||
const resolvedBy = (located as any)?.resolvedBy || ((located as any)?.ref ? 'ref' : '');
|
||||
const fallbackUsed = resolvedBy && first && resolvedBy !== 'ref' && resolvedBy !== first;
|
||||
|
||||
@@ -257,7 +257,8 @@
|
||||
zIndex: 2147483645,
|
||||
});
|
||||
document.documentElement.appendChild(this._box);
|
||||
if (rec.highlightEnabled) document.addEventListener('mousemove', rec._onMouseMove, true);
|
||||
if (rec.highlightEnabled)
|
||||
document.addEventListener('mousemove', rec._onMouseMove, { capture: true, passive: true });
|
||||
this.updateStatus();
|
||||
}
|
||||
remove() {
|
||||
@@ -306,6 +307,30 @@
|
||||
if (container) container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
|
||||
// Efficiently apply a full timeline update by only appending the delta
|
||||
applyTimelineUpdate(steps) {
|
||||
try {
|
||||
if (window !== window.top) return;
|
||||
const list = Array.isArray(steps) ? steps : [];
|
||||
const total = list.length;
|
||||
// Ensure UI exists
|
||||
if (!this._timeline) this.ensure();
|
||||
if (!this._timeline) return;
|
||||
if (total === 0) {
|
||||
this.resetTimeline();
|
||||
return;
|
||||
}
|
||||
// If timeline shrank (e.g., new session), rebuild from tail window
|
||||
if (total < this._count) {
|
||||
this.resetTimeline();
|
||||
}
|
||||
const startIdx = Math.max(this._count, total - CONFIG.UI_MAX_STEPS);
|
||||
for (let i = startIdx; i < total; i++) {
|
||||
this.appendStep(list[i]);
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// Create a short, human-readable text for a recorded step
|
||||
_formatStepText(step, _idx) {
|
||||
try {
|
||||
@@ -442,8 +467,8 @@
|
||||
document.addEventListener('focusin', this._onFocusIn, true);
|
||||
document.addEventListener('focusout', this._onFocusOut, true);
|
||||
document.addEventListener('change', this._onChange, true);
|
||||
// capture-phase scroll to catch non-bubbling events on any container
|
||||
document.addEventListener('scroll', this._onScroll, true);
|
||||
// capture-phase scroll to catch non-bubbling events on any container (passive to avoid jank)
|
||||
document.addEventListener('scroll', this._onScroll, { capture: true, passive: true });
|
||||
// Keyboard: record Enter and modifier combos
|
||||
document.addEventListener('keydown', this._onKeyDown, true);
|
||||
document.addEventListener('keyup', this._onKeyUp, true);
|
||||
@@ -457,10 +482,10 @@
|
||||
document.removeEventListener('focusin', this._onFocusIn, true);
|
||||
document.removeEventListener('focusout', this._onFocusOut, true);
|
||||
document.removeEventListener('change', this._onChange, true);
|
||||
document.removeEventListener('scroll', this._onScroll, true);
|
||||
document.removeEventListener('scroll', this._onScroll, { capture: true });
|
||||
document.removeEventListener('keydown', this._onKeyDown, true);
|
||||
document.removeEventListener('keyup', this._onKeyUp, true);
|
||||
document.removeEventListener('mousemove', this._onMouseMove, true);
|
||||
document.removeEventListener('mousemove', this._onMouseMove, { capture: true });
|
||||
if (window === window.top) window.removeEventListener('message', this._onWindowMessage, true);
|
||||
// Detach per-element input listener if any
|
||||
if (this._focusedEl) this._focusedEl.removeEventListener('input', this._onInput, true);
|
||||
@@ -476,9 +501,9 @@
|
||||
|
||||
_updateHoverListener() {
|
||||
if (window !== window.top) return;
|
||||
document.removeEventListener('mousemove', this._onMouseMove, true);
|
||||
document.removeEventListener('mousemove', this._onMouseMove, { capture: true });
|
||||
if (this.isRecording && !this.isPaused && this.highlightEnabled) {
|
||||
document.addEventListener('mousemove', this._onMouseMove, true);
|
||||
document.addEventListener('mousemove', this._onMouseMove, { capture: true, passive: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,7 +630,6 @@
|
||||
const tt = String(t).toLowerCase();
|
||||
if (tt === 'checkbox' || tt === 'radio' || tt === 'file') return;
|
||||
} catch {}
|
||||
const target = SelectorEngine.buildTarget(el);
|
||||
const elRef = this._getElRef(el);
|
||||
const isSensitive =
|
||||
this.hideInputValues ||
|
||||
@@ -625,6 +649,7 @@
|
||||
this.lastFill.ts = nowTs;
|
||||
return;
|
||||
}
|
||||
const target = SelectorEngine.buildTarget(el);
|
||||
const newStep = { type: 'fill', target, value, screenshotOnFail: true };
|
||||
// attach recording-time identity only in memory (not persisted)
|
||||
newStep._recordingRef = elRef;
|
||||
@@ -636,7 +661,6 @@
|
||||
if (!this.isRecording || this.isPaused) return;
|
||||
const el = e.target;
|
||||
if (el instanceof HTMLSelectElement) {
|
||||
const target = SelectorEngine.buildTarget(el);
|
||||
const val = el.value;
|
||||
const nowTs = Date.now();
|
||||
const elRef = this._getElRef(el);
|
||||
@@ -648,6 +672,7 @@
|
||||
this.lastFill.ts = nowTs;
|
||||
return;
|
||||
}
|
||||
const target = SelectorEngine.buildTarget(el);
|
||||
const st = { type: 'fill', target, value: val, screenshotOnFail: true };
|
||||
st._recordingRef = elRef;
|
||||
this._pushStep(st);
|
||||
@@ -740,6 +765,21 @@
|
||||
|
||||
_onScroll(e) {
|
||||
if (!this.isRecording || this.isPaused) return;
|
||||
try {
|
||||
const overlay = document.getElementById('__rr_rec_overlay');
|
||||
if (overlay) {
|
||||
// Use composedPath for shadow DOM compatibility, fallback to target
|
||||
const path = typeof e.composedPath === 'function' ? e.composedPath() : [e.target];
|
||||
for (const element of path) {
|
||||
// If the event path contains our overlay, ignore this scroll event
|
||||
if (element === overlay) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
// Determine scroll source and positions
|
||||
const isDoc = e.target === document;
|
||||
const el = isDoc ? document.documentElement : e.target instanceof Element ? e.target : null;
|
||||
@@ -935,8 +975,7 @@
|
||||
}
|
||||
// Replace entire timeline to avoid divergence across tabs
|
||||
const steps = Array.isArray(request.steps) ? request.steps : [];
|
||||
rec.ui.resetTimeline();
|
||||
for (const st of steps) rec.ui.appendStep(st);
|
||||
rec.ui.applyTimelineUpdate(steps);
|
||||
sendResponse({ ok: true });
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user