Call afterAppend for mutations and top level elements (#1012)
This commit is contained in:
@@ -348,6 +348,10 @@ export function buildNodeWithSN(
|
|||||||
mirror: Mirror;
|
mirror: Mirror;
|
||||||
skipChild?: boolean;
|
skipChild?: boolean;
|
||||||
hackCss: boolean;
|
hackCss: boolean;
|
||||||
|
/**
|
||||||
|
* This callback will be called for each of this nodes' `.childNodes` after they are appended to _this_ node.
|
||||||
|
* Caveat: This callback _doesn't_ get called when this node is appended to the DOM.
|
||||||
|
*/
|
||||||
afterAppend?: (n: Node, id: number) => unknown;
|
afterAppend?: (n: Node, id: number) => unknown;
|
||||||
cache: BuildCache;
|
cache: BuildCache;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -754,21 +754,25 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
this.legacy_missingNodeRetryMap = {};
|
this.legacy_missingNodeRetryMap = {};
|
||||||
const collected: AppendedIframe[] = [];
|
const collected: AppendedIframe[] = [];
|
||||||
|
const afterAppend = (builtNode: Node, id: number) => {
|
||||||
|
this.collectIframeAndAttachDocument(collected, builtNode);
|
||||||
|
for (const plugin of this.config.plugins || []) {
|
||||||
|
if (plugin.onBuild)
|
||||||
|
plugin.onBuild(builtNode, {
|
||||||
|
id,
|
||||||
|
replayer: this,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
rebuild(event.data.node, {
|
rebuild(event.data.node, {
|
||||||
doc: this.iframe.contentDocument,
|
doc: this.iframe.contentDocument,
|
||||||
afterAppend: (builtNode: Node, id: number) => {
|
afterAppend,
|
||||||
this.collectIframeAndAttachDocument(collected, builtNode);
|
|
||||||
for (const plugin of this.config.plugins || []) {
|
|
||||||
if (plugin.onBuild)
|
|
||||||
plugin.onBuild(builtNode, {
|
|
||||||
id,
|
|
||||||
replayer: this,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cache: this.cache,
|
cache: this.cache,
|
||||||
mirror: this.mirror,
|
mirror: this.mirror,
|
||||||
});
|
});
|
||||||
|
afterAppend(this.iframe.contentDocument, event.data.node.id);
|
||||||
|
|
||||||
for (const { mutationInQueue, builtNode } of collected) {
|
for (const { mutationInQueue, builtNode } of collected) {
|
||||||
this.attachDocumentToIframe(mutationInQueue, builtNode);
|
this.attachDocumentToIframe(mutationInQueue, builtNode);
|
||||||
this.newDocumentQueue = this.newDocumentQueue.filter(
|
this.newDocumentQueue = this.newDocumentQueue.filter(
|
||||||
@@ -840,35 +844,39 @@ export class Replayer {
|
|||||||
type TMirror = typeof mirror extends Mirror ? Mirror : RRDOMMirror;
|
type TMirror = typeof mirror extends Mirror ? Mirror : RRDOMMirror;
|
||||||
|
|
||||||
const collected: AppendedIframe[] = [];
|
const collected: AppendedIframe[] = [];
|
||||||
|
const afterAppend = (builtNode: Node, id: number) => {
|
||||||
|
this.collectIframeAndAttachDocument(collected, builtNode);
|
||||||
|
const sn = (mirror as TMirror).getMeta((builtNode as unknown) as TNode);
|
||||||
|
if (
|
||||||
|
sn?.type === NodeType.Element &&
|
||||||
|
sn?.tagName.toUpperCase() === 'HTML'
|
||||||
|
) {
|
||||||
|
const { documentElement, head } = iframeEl.contentDocument!;
|
||||||
|
this.insertStyleRules(
|
||||||
|
documentElement as HTMLElement | RRElement,
|
||||||
|
head as HTMLElement | RRElement,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const plugin of this.config.plugins || []) {
|
||||||
|
if (plugin.onBuild)
|
||||||
|
plugin.onBuild(builtNode, {
|
||||||
|
id,
|
||||||
|
replayer: this,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
buildNodeWithSN(mutation.node, {
|
buildNodeWithSN(mutation.node, {
|
||||||
doc: iframeEl.contentDocument! as Document,
|
doc: iframeEl.contentDocument! as Document,
|
||||||
mirror: mirror as Mirror,
|
mirror: mirror as Mirror,
|
||||||
hackCss: true,
|
hackCss: true,
|
||||||
skipChild: false,
|
skipChild: false,
|
||||||
afterAppend: (builtNode, id: number) => {
|
afterAppend,
|
||||||
this.collectIframeAndAttachDocument(collected, builtNode);
|
|
||||||
const sn = (mirror as TMirror).getMeta((builtNode as unknown) as TNode);
|
|
||||||
if (
|
|
||||||
sn?.type === NodeType.Element &&
|
|
||||||
sn?.tagName.toUpperCase() === 'HTML'
|
|
||||||
) {
|
|
||||||
const { documentElement, head } = iframeEl.contentDocument!;
|
|
||||||
this.insertStyleRules(
|
|
||||||
documentElement as HTMLElement | RRElement,
|
|
||||||
head as HTMLElement | RRElement,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const plugin of this.config.plugins || []) {
|
|
||||||
if (plugin.onBuild)
|
|
||||||
plugin.onBuild(builtNode, {
|
|
||||||
id,
|
|
||||||
replayer: this,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cache: this.cache,
|
cache: this.cache,
|
||||||
});
|
});
|
||||||
|
afterAppend(iframeEl.contentDocument! as Document, mutation.node.id);
|
||||||
|
|
||||||
for (const { mutationInQueue, builtNode } of collected) {
|
for (const { mutationInQueue, builtNode } of collected) {
|
||||||
this.attachDocumentToIframe(mutationInQueue, builtNode);
|
this.attachDocumentToIframe(mutationInQueue, builtNode);
|
||||||
this.newDocumentQueue = this.newDocumentQueue.filter(
|
this.newDocumentQueue = this.newDocumentQueue.filter(
|
||||||
@@ -1466,17 +1474,23 @@ export class Replayer {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const afterAppend = (node: Node | RRNode, id: number) => {
|
||||||
|
for (const plugin of this.config.plugins || []) {
|
||||||
|
if (plugin.onBuild) plugin.onBuild(node, { id, replayer: this });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const target = buildNodeWithSN(mutation.node, {
|
const target = buildNodeWithSN(mutation.node, {
|
||||||
doc: targetDoc as Document, // can be Document or RRDocument
|
doc: targetDoc as Document, // can be Document or RRDocument
|
||||||
mirror: mirror as Mirror, // can be this.mirror or virtualDom.mirror
|
mirror: mirror as Mirror, // can be this.mirror or virtualDom.mirror
|
||||||
skipChild: true,
|
skipChild: true,
|
||||||
hackCss: true,
|
hackCss: true,
|
||||||
cache: this.cache,
|
cache: this.cache,
|
||||||
afterAppend: (node: Node | RRNode, id: number) => {
|
/**
|
||||||
for (const plugin of this.config.plugins || []) {
|
* caveat: `afterAppend` only gets called on child nodes of target
|
||||||
if (plugin.onBuild) plugin.onBuild(node, { id, replayer: this });
|
* we have to call it again below when this target was added to the DOM
|
||||||
}
|
*/
|
||||||
},
|
afterAppend,
|
||||||
}) as Node | RRNode;
|
}) as Node | RRNode;
|
||||||
|
|
||||||
// legacy data, we should not have -1 siblings any more
|
// legacy data, we should not have -1 siblings any more
|
||||||
@@ -1536,6 +1550,11 @@ export class Replayer {
|
|||||||
|
|
||||||
(parent as TNode).appendChild(target as TNode);
|
(parent as TNode).appendChild(target as TNode);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* target was added, execute plugin hooks
|
||||||
|
*/
|
||||||
|
afterAppend(target, mutation.node.id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://github.com/rrweb-io/rrweb/pull/887
|
* https://github.com/rrweb-io/rrweb/pull/887
|
||||||
* Remove any virtual style rules for stylesheets if a new text node is appended.
|
* Remove any virtual style rules for stylesheets if a new text node is appended.
|
||||||
|
|||||||
Reference in New Issue
Block a user