Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use window.top and window.top.document #294

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
42 changes: 24 additions & 18 deletions packages/rrweb/src/record/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { snapshot, MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot';
import { initObservers, mutationBuffers } from './observer';
import {
on,
getTopWindow,
getWindowWidth,
getWindowHeight,
polyfill,
Expand All @@ -18,6 +19,7 @@ import {
listenerHandler,
mutationCallbackParam,
scrollCallback,
IWindow,
} from '../types';
import { IframeManager } from './iframe-manager';
import { ShadowDomManager } from './shadow-dom-manager';
Expand Down Expand Up @@ -66,6 +68,10 @@ function record<T = eventWithTime>(
if (!emit) {
throw new Error('emit function is required');
}

const twindow = getTopWindow();
const tdoc = twindow.document;

// move departed options to new options
if (mousemoveWait !== undefined && sampling.mousemove === undefined) {
sampling.mousemove = mousemoveWait;
Expand Down Expand Up @@ -209,7 +215,7 @@ function record<T = eventWithTime>(
wrapEvent({
type: EventType.Meta,
data: {
href: window.location.href,
href: twindow.location.href,
width: getWindowWidth(),
height: getWindowHeight(),
},
Expand All @@ -218,7 +224,7 @@ function record<T = eventWithTime>(
);

mutationBuffers.forEach((buf) => buf.lock()); // don't allow any mirror modifications during snapshotting
const [node, idNodeMap] = snapshot(document, {
const [node, idNodeMap] = snapshot(tdoc, {
blockClass,
blockSelector,
maskTextClass,
Expand All @@ -233,7 +239,7 @@ function record<T = eventWithTime>(
iframeManager.addIframe(n);
}
if (hasShadowRoot(n)) {
shadowDomManager.addShadowRoot(n.shadowRoot, document);
shadowDomManager.addShadowRoot(n.shadowRoot, tdoc);
}
},
onIframeLoad: (iframe, childSn) => {
Expand All @@ -254,18 +260,18 @@ function record<T = eventWithTime>(
node,
initialOffset: {
left:
window.pageXOffset !== undefined
? window.pageXOffset
: document?.documentElement.scrollLeft ||
document?.body?.parentElement?.scrollLeft ||
document?.body.scrollLeft ||
twindow.pageXOffset !== undefined
? twindow.pageXOffset
: tdoc?.documentElement.scrollLeft ||
tdoc?.body?.parentElement?.scrollLeft ||
tdoc?.body.scrollLeft ||
0,
top:
window.pageYOffset !== undefined
? window.pageYOffset
: document?.documentElement.scrollTop ||
document?.body?.parentElement?.scrollTop ||
document?.body.scrollTop ||
twindow.pageYOffset !== undefined
? twindow.pageYOffset
: tdoc?.documentElement.scrollTop ||
tdoc?.body?.parentElement?.scrollTop ||
tdoc?.body.scrollTop ||
0,
},
},
Expand All @@ -284,7 +290,7 @@ function record<T = eventWithTime>(
data: {},
}),
);
}),
}, tdoc),
);

const observe = (doc: Document) => {
Expand Down Expand Up @@ -426,11 +432,11 @@ function record<T = eventWithTime>(

const init = () => {
takeFullSnapshot();
handlers.push(observe(document));
handlers.push(observe(tdoc));
};
if (
document.readyState === 'interactive' ||
document.readyState === 'complete'
tdoc.readyState === 'interactive' ||
tdoc.readyState === 'complete'
) {
init();
} else {
Expand All @@ -446,7 +452,7 @@ function record<T = eventWithTime>(
);
init();
},
window,
twindow as IWindow,
),
);
}
Expand Down
12 changes: 7 additions & 5 deletions packages/rrweb/src/record/observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,8 +682,9 @@ function initStyleDeclarationObserver(

function initMediaInteractionObserver(
mediaInteractionCb: mediaInteractionCallback,
blockClass: blockClass,
doc: Document,
mirror: Mirror,
blockClass: blockClass,
): listenerHandler {
const handler = (type: MediaInteractions) => (event: Event) => {
const target = getEventTarget(event);
Expand All @@ -697,9 +698,9 @@ function initMediaInteractionObserver(
});
};
const handlers = [
on('play', handler(MediaInteractions.Play)),
on('pause', handler(MediaInteractions.Pause)),
on('seeked', handler(MediaInteractions.Seeked)),
on('play', handler(MediaInteractions.Play), doc),
on('pause', handler(MediaInteractions.Pause), doc),
on('seeked', handler(MediaInteractions.Seeked), doc),
];
return () => {
handlers.forEach((h) => h());
Expand Down Expand Up @@ -985,8 +986,9 @@ export function initObservers(
);
const mediaInteractionHandler = initMediaInteractionObserver(
o.mediaInteractionCb,
o.blockClass,
o.doc,
o.mirror,
o.blockClass,
);

const styleSheetObserver = initStyleSheetObserver(
Expand Down
32 changes: 25 additions & 7 deletions packages/rrweb/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
export function on(
type: string,
fn: EventListenerOrEventListenerObject,
target: Document | IWindow = document,
target: Document | IWindow,
): listenerHandler {
const options = { capture: true, passive: true };
target.addEventListener(type, fn, options);
Expand Down Expand Up @@ -207,19 +207,37 @@ export function patch(
}
}

export function getTopWindow(): Window {
let twindow: Window = window;
while (twindow.parent && twindow.parent != twindow) {
// check each parent in case the window.top.document fails, but an intermediary one would succeed
try {
let tdoc = twindow.parent.document; // this can fail apparently: https://stackoverflow.com/questions/2937118
twindow = twindow.parent as Window;
} catch (err) {
break;
}
}
return twindow;
}

export function getWindowHeight(): number {
const twindow = getTopWindow();
const tdoc = twindow.document;
return (
window.innerHeight ||
(document.documentElement && document.documentElement.clientHeight) ||
(document.body && document.body.clientHeight)
twindow.innerHeight ||
(tdoc.documentElement && tdoc.documentElement.clientHeight) ||
(tdoc.body && tdoc.body.clientHeight)
);
}

export function getWindowWidth(): number {
const twindow = getTopWindow();
const tdoc = twindow.document;
return (
window.innerWidth ||
(document.documentElement && document.documentElement.clientWidth) ||
(document.body && document.body.clientWidth)
twindow.innerWidth ||
(tdoc.documentElement && tdoc.documentElement.clientWidth) ||
(tdoc.body && tdoc.body.clientWidth)
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/rrweb/test/__snapshots__/integration.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2024,7 +2024,7 @@ exports[`iframe 1`] = `
{
\\"type\\": 4,
\\"data\\": {
\\"href\\": \\"about:blank\\",
\\"href\\": \\"http://localhost:3030/html\\",
\\"width\\": 1920,
\\"height\\": 1080
}
Expand Down
166 changes: 166 additions & 0 deletions packages/rrweb/test/__snapshots__/record.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,172 @@ exports[`iframe-stylesheet-mutations 1`] = `
]"
`;

exports[`loaded-from-iframe 1`] = `
"[
{
\\"type\\": 4,
\\"data\\": {
\\"href\\": \\"about:blank?outer\\",
\\"width\\": 1920,
\\"height\\": 1080
}
},
{
\\"type\\": 2,
\\"data\\": {
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"id\\": 3
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"id\\": 5
},
{
\\"type\\": 2,
\\"tagName\\": \\"input\\",
\\"attributes\\": {
\\"type\\": \\"text\\",
\\"size\\": \\"40\\"
},
\\"childNodes\\": [],
\\"id\\": 6
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"id\\": 7
},
{
\\"type\\": 2,
\\"tagName\\": \\"iframe\\",
\\"attributes\\": {
\\"srcdoc\\": \\"<div>rrweb loaded in here!</div>\\"
},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n </body>\\\\n </html>\\\\n \\",
\\"id\\": 9
}
],
\\"id\\": 8
}
],
\\"id\\": 4
}
],
\\"id\\": 2
}
],
\\"id\\": 1
},
\\"initialOffset\\": {
\\"left\\": 0,
\\"top\\": 0
}
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"adds\\": [
{
\\"parentId\\": 8,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 10,
\\"id\\": 12
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"div\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"rrweb loaded in here!\\",
\\"rootId\\": 10,
\\"id\\": 15
}
],
\\"rootId\\": 10,
\\"id\\": 14
}
],
\\"rootId\\": 10,
\\"id\\": 13
}
],
\\"rootId\\": 10,
\\"id\\": 11
}
],
\\"id\\": 10
}
}
],
\\"removes\\": [],
\\"texts\\": [],
\\"attributes\\": [],
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 2,
\\"type\\": 5,
\\"id\\": 6
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 5,
\\"text\\": \\"a\\",
\\"isChecked\\": false,
\\"id\\": 6
}
}
]"
`;

exports[`nested-stylesheet-rules 1`] = `
"[
{
Expand Down
1 change: 1 addition & 0 deletions packages/rrweb/test/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ describe('record integration tests', function (this: ISuite) {
it('should nest record iframe', async () => {
const page: puppeteer.Page = await this.browser.newPage();
await page.goto(`http://localhost:3030/html`);
await page.waitForTimeout(10);
await page.setContent(getHtml.call(this, 'main.html'));

await page.waitForTimeout(500);
Expand Down
Loading