rrweb
Version:
record and replay the web
228 lines (225 loc) • 8.81 kB
JavaScript
import { __values } from '../../node_modules/tslib/tslib.es6.js';
import { transformAttribute, serializeNodeWithId } from '../../node_modules/rrweb-snapshot/es/rrweb-snapshot.js';
import { mirror, isBlocked, isAncestorRemoved } from '../utils.js';
var moveKey = function (id, parentId) { return id + "@" + parentId; };
function isINode(n) {
return '__sn' in n;
}
var MutationBuffer = (function () {
function MutationBuffer(cb, blockClass, inlineStylesheet, maskInputOptions) {
var _this = this;
this.texts = [];
this.attributes = [];
this.removes = [];
this.adds = [];
this.movedMap = {};
this.addedSet = new Set();
this.movedSet = new Set();
this.droppedSet = new Set();
this.processMutations = function (mutations) {
var e_1, _a, e_2, _b;
mutations.forEach(_this.processMutation);
var addQueue = [];
var pushAdd = function (n) {
if (!n.parentNode) {
return;
}
var parentId = mirror.getId(n.parentNode);
var nextId = n.nextSibling && mirror.getId(n.nextSibling);
if (parentId === -1 || nextId === -1) {
return addQueue.push(n);
}
_this.adds.push({
parentId: parentId,
nextId: nextId,
node: serializeNodeWithId(n, document, mirror.map, _this.blockClass, true, _this.inlineStylesheet, _this.maskInputOptions),
});
};
try {
for (var _c = __values(_this.movedSet), _d = _c.next(); !_d.done; _d = _c.next()) {
var n = _d.value;
pushAdd(n);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_1) throw e_1.error; }
}
try {
for (var _e = __values(_this.addedSet), _f = _e.next(); !_f.done; _f = _e.next()) {
var n = _f.value;
if (!isAncestorInSet(_this.droppedSet, n) &&
!isParentRemoved(_this.removes, n)) {
pushAdd(n);
}
else if (isAncestorInSet(_this.movedSet, n)) {
pushAdd(n);
}
else {
_this.droppedSet.add(n);
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
}
finally { if (e_2) throw e_2.error; }
}
while (addQueue.length) {
if (addQueue.every(function (n) { return mirror.getId(n.parentNode) === -1; })) {
break;
}
pushAdd(addQueue.shift());
}
_this.emit();
};
this.emit = function () {
var payload = {
texts: _this.texts
.map(function (text) { return ({
id: mirror.getId(text.node),
value: text.value,
}); })
.filter(function (text) { return mirror.has(text.id); }),
attributes: _this.attributes
.map(function (attribute) { return ({
id: mirror.getId(attribute.node),
attributes: attribute.attributes,
}); })
.filter(function (attribute) { return mirror.has(attribute.id); }),
removes: _this.removes,
adds: _this.adds,
};
if (!payload.texts.length &&
!payload.attributes.length &&
!payload.removes.length &&
!payload.adds.length) {
return;
}
_this.emissionCallback(payload);
_this.texts = [];
_this.attributes = [];
_this.removes = [];
_this.adds = [];
_this.addedSet = new Set();
_this.movedSet = new Set();
_this.droppedSet = new Set();
_this.movedMap = {};
};
this.processMutation = function (m) {
switch (m.type) {
case 'characterData': {
var value = m.target.textContent;
if (!isBlocked(m.target, _this.blockClass) && value !== m.oldValue) {
_this.texts.push({
value: value,
node: m.target,
});
}
break;
}
case 'attributes': {
var value = m.target.getAttribute(m.attributeName);
if (isBlocked(m.target, _this.blockClass) || value === m.oldValue) {
return;
}
var item = _this.attributes.find(function (a) { return a.node === m.target; });
if (!item) {
item = {
node: m.target,
attributes: {},
};
_this.attributes.push(item);
}
item.attributes[m.attributeName] = transformAttribute(document, m.attributeName, value);
break;
}
case 'childList': {
m.addedNodes.forEach(function (n) { return _this.genAdds(n, m.target); });
m.removedNodes.forEach(function (n) {
var nodeId = mirror.getId(n);
var parentId = mirror.getId(m.target);
if (isBlocked(n, _this.blockClass) ||
isBlocked(m.target, _this.blockClass)) {
return;
}
if (_this.addedSet.has(n)) {
deepDelete(_this.addedSet, n);
_this.droppedSet.add(n);
}
else if (_this.addedSet.has(m.target) && nodeId === -1) ;
else if (isAncestorRemoved(m.target)) ;
else if (_this.movedSet.has(n) &&
_this.movedMap[moveKey(nodeId, parentId)]) {
deepDelete(_this.movedSet, n);
}
else {
_this.removes.push({
parentId: parentId,
id: nodeId,
});
}
mirror.removeNodeFromMap(n);
});
break;
}
}
};
this.genAdds = function (n, target) {
if (isBlocked(n, _this.blockClass)) {
return;
}
if (isINode(n)) {
_this.movedSet.add(n);
var targetId = null;
if (target && isINode(target)) {
targetId = target.__sn.id;
}
if (targetId) {
_this.movedMap[moveKey(n.__sn.id, targetId)] = true;
}
}
else {
_this.addedSet.add(n);
_this.droppedSet.delete(n);
}
n.childNodes.forEach(function (childN) { return _this.genAdds(childN); });
};
this.blockClass = blockClass;
this.inlineStylesheet = inlineStylesheet;
this.maskInputOptions = maskInputOptions;
this.emissionCallback = cb;
}
return MutationBuffer;
}());
function deepDelete(addsSet, n) {
addsSet.delete(n);
n.childNodes.forEach(function (childN) { return deepDelete(addsSet, childN); });
}
function isParentRemoved(removes, n) {
var parentNode = n.parentNode;
if (!parentNode) {
return false;
}
var parentId = mirror.getId(parentNode);
if (removes.some(function (r) { return r.id === parentId; })) {
return true;
}
return isParentRemoved(removes, parentNode);
}
function isAncestorInSet(set, n) {
var parentNode = n.parentNode;
if (!parentNode) {
return false;
}
if (set.has(parentNode)) {
return true;
}
return isAncestorInSet(set, parentNode);
}
export default MutationBuffer;