update mutation observer handler

1. deep delete from adds set when node was dropped
2. remove node from dropped set when node was added again
This commit is contained in:
Yanzhen Yu
2019-02-03 23:07:35 +08:00
parent a69bf87f7f
commit 406e7a8d39
5 changed files with 348 additions and 29 deletions

41
src/record/collection.ts Normal file
View File

@@ -0,0 +1,41 @@
/**
* Some utils to handle the mutation observer DOM records.
* It should be more clear to extend the native data structure
* like Set and Map, but currently Typescript does not support
* that.
*/
import { INode } from 'rrweb-snapshot';
import { removedNodeMutation } from '../types';
import { mirror } from '../utils';
export function deepDelete(addsSet: Set<Node>, n: Node) {
addsSet.delete(n);
n.childNodes.forEach(childN => deepDelete(addsSet, childN));
}
export function isParentRemoved(
removes: removedNodeMutation[],
n: Node,
): boolean {
const { parentNode } = n;
if (!parentNode) {
return false;
}
const parentId = mirror.getId((parentNode as Node) as INode);
if (removes.some(r => r.id === parentId)) {
return true;
}
return isParentRemoved(removes, parentNode);
}
export function isParentDropped(droppedSet: Set<Node>, n: Node): boolean {
const { parentNode } = n;
if (!parentNode) {
return false;
}
if (droppedSet.has(parentNode)) {
return true;
}
return isParentDropped(droppedSet, parentNode);
}

View File

@@ -27,6 +27,7 @@ import {
textCursor,
attributeCursor,
} from '../types';
import { deepDelete, isParentRemoved, isParentDropped } from './collection';
/**
* Mutation observer will merge several mutations into an array and pass
@@ -49,16 +50,18 @@ function initMutationObserver(cb: mutationCallBack): MutationObserver {
const observer = new MutationObserver(mutations => {
const texts: textCursor[] = [];
const attributes: attributeCursor[] = [];
let removes: removedNodeMutation[] = [];
const removes: removedNodeMutation[] = [];
const adds: addedNodeMutation[] = [];
const dropped: Node[] = [];
const addsSet = new Set<Node>();
const droppedSet = new Set<Node>();
const genAdds = (n: Node) => {
if (isBlocked(n)) {
return;
}
addsSet.add(n);
droppedSet.delete(n);
n.childNodes.forEach(childN => genAdds(childN));
};
mutations.forEach(mutation => {
@@ -110,8 +113,8 @@ function initMutationObserver(cb: mutationCallBack): MutationObserver {
}
// removed node has not been serialized yet, just remove it from the Set
if (addsSet.has(n)) {
addsSet.delete(n);
dropped.push(n);
deepDelete(addsSet, n);
droppedSet.add(n);
} else if (addsSet.has(target) && nodeId === -1) {
/**
* If target was newly added and removed child node was
@@ -141,31 +144,8 @@ function initMutationObserver(cb: mutationCallBack): MutationObserver {
}
});
const isDropped = (n: Node): boolean => {
const { parentNode } = n;
if (!parentNode) {
return false;
}
if (dropped.some(d => d === parentNode)) {
return true;
}
return isDropped(parentNode);
};
const isRemoved = (n: Node): boolean => {
const { parentNode } = n;
if (!parentNode) {
return false;
}
const parentId = mirror.getId((parentNode as Node) as INode);
if (removes.some(r => r.id === parentId)) {
return true;
}
return isRemoved(parentNode);
};
Array.from(addsSet).forEach(n => {
if (!isDropped(n) && !isRemoved(n)) {
if (!isParentDropped(droppedSet, n) && !isParentRemoved(removes, n)) {
adds.push({
parentId: mirror.getId((n.parentNode as Node) as INode),
previousId: !n.previousSibling
@@ -177,7 +157,7 @@ function initMutationObserver(cb: mutationCallBack): MutationObserver {
node: serializeNodeWithId(n, document, mirror.map, true)!,
});
} else {
dropped.push(n);
droppedSet.add(n);
}
});