diff --git a/src/replay/index.ts b/src/replay/index.ts index fd922e43..134f55af 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -11,6 +11,7 @@ import { playerConfig, playerMetaData, viewportResizeDimention, + missingNextNodeMap, } from '../types'; import { mirror } from '../utils'; @@ -216,6 +217,8 @@ export class Replayer { parent.removeChild(target); } }); + + const missingNextNodeMap: missingNextNodeMap = {}; d.adds.forEach(mutation => { const target = buildNodeWithSN( mutation.node, @@ -233,6 +236,14 @@ export class Replayer { next = mirror.getNode(mutation.nextId) as Node; } + if (mutation.nextId === -1) { + missingNextNodeMap[mutation.node.id] = { + node: target, + mutation, + }; + return; + } + if (previous && previous.nextSibling) { parent.insertBefore(target, previous.nextSibling); } else if (next) { @@ -240,7 +251,18 @@ export class Replayer { } else { parent.appendChild(target); } + + if (mutation.previousId) { + this.resolveMissingNode( + missingNextNodeMap, + parent, + target, + mutation.previousId, + ); + } }); + // TODO: assert missingNextNodeMap has no key after resolve + d.texts.forEach(mutation => { const target = (mirror.getNode(mutation.id) as Node) as Text; target.textContent = mutation.value; @@ -320,6 +342,22 @@ export class Replayer { } } + private resolveMissingNode( + map: missingNextNodeMap, + parent: Node, + target: Node, + previousId: number, + ) { + if (map[previousId]) { + const { node, mutation } = map[previousId]; + parent.insertBefore(node, target); + delete map[mutation.node.id]; + if (mutation.previousId) { + this.resolveMissingNode(map, parent, node as Node, mutation.previousId); + } + } + } + private hoverElements(el: Element) { this.iframe .contentDocument!.querySelectorAll('.\\:hover') diff --git a/src/types.ts b/src/types.ts index c3275322..df29c00e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -231,3 +231,10 @@ export type playerConfig = { export type playerMetaData = { totalTime: number; }; + +export type missingNextNodeMap = { + [id: number]: { + node: Node; + mutation: addedNodeMutation; + }; +}; diff --git a/src/utils.ts b/src/utils.ts index 66e5c85c..afaa1d6a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -18,7 +18,11 @@ export function on( export const mirror: Mirror = { map: {}, getId(n) { - return n.__sn && n.__sn.id; + // if n is not a serialized INode, use -1 as its id. + if (!n.__sn) { + return -1; + } + return n.__sn.id; }, getNode(id) { return mirror.map[id] || null;