@xysfe/memento-core
Version:
record and replay the web
482 lines (479 loc) • 17.5 kB
JavaScript
import { __values } from '../node_modules/tslib/tslib.es6.js';
import { EventType, IncrementalSource } from './types.js';
function on(type, fn, target) {
if (target === void 0) { target = document; }
var options = { capture: true, passive: true };
target.addEventListener(type, fn, options);
return function () { return target.removeEventListener(type, fn, options); };
}
var mirror = {
map: {},
getId: function (n) {
if (!n || !n.__sn) {
return -1;
}
return n.__sn.id;
},
getNode: function (id) {
return mirror.map[id] || null;
},
removeNodeFromMap: function (n) {
var id = n.__sn && n.__sn.id;
delete mirror.map[id];
if (n.childNodes) {
n.childNodes.forEach(function (child) {
return mirror.removeNodeFromMap(child);
});
}
},
has: function (id) {
return mirror.map.hasOwnProperty(id);
},
};
function throttle(func, wait, options) {
if (options === void 0) { options = {}; }
var timeout = null;
var previous = 0;
return function (arg) {
var now = Date.now();
if (!previous && options.leading === false) {
previous = now;
}
var remaining = wait - (now - previous);
var context = this;
var args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
window.clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(context, args);
}
else if (!timeout && options.trailing !== false) {
timeout = window.setTimeout(function () {
previous = options.leading === false ? 0 : Date.now();
timeout = null;
func.apply(context, args);
}, remaining);
}
};
}
function hookSetter(target, key, d, isRevoked, win) {
if (win === void 0) { win = window; }
var original = win.Object.getOwnPropertyDescriptor(target, key);
win.Object.defineProperty(target, key, isRevoked
? d
: {
set: function (value) {
var _this = this;
setTimeout(function () {
d.set.call(_this, value);
}, 0);
if (original && original.set) {
original.set.call(this, value);
}
},
});
return function () { return hookSetter(target, key, original || {}, true); };
}
function patch(source, name, replacement) {
if (!(name in source)) {
return function () { };
}
var original = source[name];
var wrapped = replacement(original);
if (typeof wrapped === 'function') {
try {
wrapped.prototype = wrapped.prototype || {};
Object.defineProperties(wrapped, {
__memento_original__: {
enumerable: false,
value: original,
},
});
}
catch (_a) {
}
}
source[name] = wrapped;
return function () {
source[name] = original;
};
}
function getWindowHeight() {
return (window.innerHeight ||
(document.documentElement && document.documentElement.clientHeight) ||
(document.body && document.body.clientHeight));
}
function getWindowWidth() {
return (window.innerWidth ||
(document.documentElement && document.documentElement.clientWidth) ||
(document.body && document.body.clientWidth));
}
function isBlocked(node, blockClass, blockElements) {
var e_1, _a;
if (!node) {
return false;
}
if (node.nodeType === node.ELEMENT_NODE) {
var needBlock_1 = false;
if (typeof blockClass === 'string') {
needBlock_1 = node.classList.contains(blockClass);
}
else if (node.classList && !!(node.classList)) {
node.classList.forEach(function (className) {
if (blockClass.test(className)) {
needBlock_1 = true;
}
});
}
if (!needBlock_1 && node.tagName && blockElements) {
try {
for (var blockElements_1 = __values(blockElements), blockElements_1_1 = blockElements_1.next(); !blockElements_1_1.done; blockElements_1_1 = blockElements_1.next()) {
var blockElement = blockElements_1_1.value;
if (blockElement.tagName === node.tagName.toLowerCase()) {
needBlock_1 = true;
break;
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (blockElements_1_1 && !blockElements_1_1.done && (_a = blockElements_1.return)) _a.call(blockElements_1);
}
finally { if (e_1) throw e_1.error; }
}
}
return needBlock_1 || isBlocked(node.parentNode, blockClass, blockElements);
}
if (node.nodeType === node.TEXT_NODE) {
return isBlocked(node.parentNode, blockClass, blockElements);
}
return isBlocked(node.parentNode, blockClass, blockElements);
}
function isAncestorRemoved(target) {
var id = mirror.getId(target);
if (!mirror.has(id)) {
return true;
}
if (target.parentNode &&
target.parentNode.nodeType === target.DOCUMENT_NODE) {
return false;
}
if (!target.parentNode) {
return true;
}
return isAncestorRemoved(target.parentNode);
}
function isTouchEvent(event) {
return Boolean(event.changedTouches);
}
function polyfill() {
if ('NodeList' in window && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = Array.prototype
.forEach;
}
}
function dateFormat(date, fmt) {
var o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds(),
'q+': Math.floor((date.getMonth() + 3) / 3),
'S': date.getMilliseconds(),
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
}
}
return fmt;
}
function needCastInSyncMode(event) {
switch (event.type) {
case EventType.DomContentLoaded:
case EventType.Load:
case EventType.PageChange:
case EventType.Custom:
return false;
case EventType.FullSnapshot:
case EventType.Meta:
return true;
}
switch (event.data.source) {
case IncrementalSource.MouseMove:
case IncrementalSource.MouseInteraction:
case IncrementalSource.TouchMove:
case IncrementalSource.MediaInteraction:
return false;
case IncrementalSource.ViewportResize:
case IncrementalSource.StyleSheetRule:
case IncrementalSource.Scroll:
case IncrementalSource.Input:
return true;
}
return true;
}
var TreeIndex = (function () {
function TreeIndex() {
this.reset();
}
TreeIndex.prototype.add = function (mutation) {
var parentTreeNode = this.indexes.get(mutation.parentId);
var treeNode = {
id: mutation.node.id,
mutation: mutation,
children: [],
texts: [],
attributes: [],
};
if (!parentTreeNode) {
this.tree[treeNode.id] = treeNode;
}
else {
treeNode.parent = parentTreeNode;
parentTreeNode.children[treeNode.id] = treeNode;
}
this.indexes.set(treeNode.id, treeNode);
};
TreeIndex.prototype.remove = function (mutation) {
var _this = this;
var parentTreeNode = this.indexes.get(mutation.parentId);
var treeNode = this.indexes.get(mutation.id);
var deepRemoveFromMirror = function (id) {
_this.removeIdSet.add(id);
var node = mirror.getNode(id);
node === null || node === void 0 ? void 0 : node.childNodes.forEach(function (childNode) {
return deepRemoveFromMirror(childNode.__sn.id);
});
};
var deepRemoveFromTreeIndex = function (node) {
_this.removeIdSet.add(node.id);
Object.values(node.children).forEach(function (n) { return deepRemoveFromTreeIndex(n); });
var _treeNode = _this.indexes.get(node.id);
if (_treeNode) {
var _parentTreeNode = _treeNode.parent;
if (_parentTreeNode) {
delete _treeNode.parent;
delete _parentTreeNode.children[_treeNode.id];
_this.indexes.delete(mutation.id);
}
}
};
if (!treeNode) {
this.removeNodeMutations.push(mutation);
deepRemoveFromMirror(mutation.id);
}
else if (!parentTreeNode) {
delete this.tree[treeNode.id];
this.indexes.delete(treeNode.id);
deepRemoveFromTreeIndex(treeNode);
}
else {
delete treeNode.parent;
delete parentTreeNode.children[treeNode.id];
this.indexes.delete(mutation.id);
deepRemoveFromTreeIndex(treeNode);
}
};
TreeIndex.prototype.text = function (mutation) {
var treeNode = this.indexes.get(mutation.id);
if (treeNode) {
treeNode.texts.push(mutation);
}
else {
this.textMutations.push(mutation);
}
};
TreeIndex.prototype.attribute = function (mutation) {
var treeNode = this.indexes.get(mutation.id);
if (treeNode) {
treeNode.attributes.push(mutation);
}
else {
this.attributeMutations.push(mutation);
}
};
TreeIndex.prototype.scroll = function (d) {
this.scrollMap.set(d.id, d);
};
TreeIndex.prototype.input = function (d) {
this.inputMap.set(d.id, d);
};
TreeIndex.prototype.flush = function () {
var e_2, _a, e_3, _b;
var _this = this;
var _c = this, tree = _c.tree, removeNodeMutations = _c.removeNodeMutations, textMutations = _c.textMutations, attributeMutations = _c.attributeMutations;
var batchMutationData = {
source: IncrementalSource.Mutation,
removes: removeNodeMutations,
texts: textMutations,
attributes: attributeMutations,
adds: [],
};
var walk = function (treeNode, removed) {
if (removed) {
_this.removeIdSet.add(treeNode.id);
}
batchMutationData.texts = batchMutationData.texts
.concat(removed ? [] : treeNode.texts)
.filter(function (m) { return !_this.removeIdSet.has(m.id); });
batchMutationData.attributes = batchMutationData.attributes
.concat(removed ? [] : treeNode.attributes)
.filter(function (m) { return !_this.removeIdSet.has(m.id); });
if (!_this.removeIdSet.has(treeNode.id) &&
!_this.removeIdSet.has(treeNode.mutation.parentId) &&
!removed) {
batchMutationData.adds.push(treeNode.mutation);
if (treeNode.children) {
Object.values(treeNode.children).forEach(function (n) { return walk(n, false); });
}
}
else {
Object.values(treeNode.children).forEach(function (n) { return walk(n, true); });
}
};
Object.values(tree).forEach(function (n) { return walk(n, false); });
try {
for (var _d = __values(this.scrollMap.keys()), _e = _d.next(); !_e.done; _e = _d.next()) {
var id = _e.value;
if (this.removeIdSet.has(id)) {
this.scrollMap.delete(id);
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_2) throw e_2.error; }
}
try {
for (var _f = __values(this.inputMap.keys()), _g = _f.next(); !_g.done; _g = _f.next()) {
var id = _g.value;
if (this.removeIdSet.has(id)) {
this.inputMap.delete(id);
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
}
finally { if (e_3) throw e_3.error; }
}
var scrollMap = new Map(this.scrollMap);
var inputMap = new Map(this.inputMap);
this.reset();
return {
mutationData: batchMutationData,
scrollMap: scrollMap,
inputMap: inputMap,
};
};
TreeIndex.prototype.reset = function () {
this.tree = [];
this.indexes = new Map();
this.removeNodeMutations = [];
this.textMutations = [];
this.attributeMutations = [];
this.removeIdSet = new Set();
this.scrollMap = new Map();
this.inputMap = new Map();
};
return TreeIndex;
}());
function isNumber(value) {
return Object.prototype.toString.call(value) == '[object Number]';
}
function isString(value) {
return Object.prototype.toString.call(value) == '[object String]';
}
function isArray(value) {
return Object.prototype.toString.call(value) == '[object Array]';
}
function isBoolean(value) {
return Object.prototype.toString.call(value) == '[object Boolean]';
}
function isUndefined(value) {
return value === undefined;
}
function isNull(value) {
return value === null;
}
function isSymbol(value) {
return Object.prototype.toString.call(value) == '[object Symbol]';
}
function isObject(value) {
return (Object.prototype.toString.call(value) == '[object Object]'
||
(!isNumber(value) &&
!isString(value) &&
!isBoolean(value) &&
!isArray(value) &&
!isNull(value) &&
!isFunction(value) &&
!isUndefined(value) &&
!isSymbol(value)));
}
function isFunction(value) {
return Object.prototype.toString.call(value) == '[object Function]';
}
function isElement(value) {
return (typeof HTMLElement === 'object' ? value instanceof HTMLElement :
value && typeof value === "object" && value !== null && value.nodeType === 1 && typeof value.nodeName === "string");
}
function isWindow(value) {
var toString = Object.prototype.toString.call(value);
return toString == '[object global]' || toString == '[object Window]' || toString == '[object DOMWindow]';
}
function isPlainObject(obj) {
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || typeof obj !== 'object' || obj.nodeType || isWindow(obj)) {
return false;
}
try {
if (obj.constructor && !hasOwn.call(obj, 'constructor') && !hasOwn.call(obj.constructor.prototype, 'isPrototypeOf')) {
return false;
}
}
catch (e) {
return false;
}
var key;
for (key in obj) { }
return key === undefined || hasOwn.call(obj, key);
}
function getBaseDimension(node, rootIframe) {
var _a, _b;
var frameElement = (_b = (_a = node.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView) === null || _b === void 0 ? void 0 : _b.frameElement;
if (!frameElement || frameElement === rootIframe) {
return {
x: 0,
y: 0,
relativeScale: 1,
absoluteScale: 1,
};
}
var frameDimension = frameElement.getBoundingClientRect();
var frameBaseDimension = getBaseDimension(frameElement, rootIframe);
var relativeScale = frameDimension.height / frameElement.clientHeight;
return {
x: frameDimension.x * frameBaseDimension.relativeScale +
frameBaseDimension.x,
y: frameDimension.y * frameBaseDimension.relativeScale +
frameBaseDimension.y,
relativeScale: relativeScale,
absoluteScale: frameBaseDimension.absoluteScale * relativeScale,
};
}
export { TreeIndex, dateFormat, getBaseDimension, getWindowHeight, getWindowWidth, hookSetter, isAncestorRemoved, isArray, isBlocked, isBoolean, isElement, isFunction, isNull, isNumber, isObject, isPlainObject, isString, isSymbol, isTouchEvent, isUndefined, isWindow, mirror, needCastInSyncMode, on, patch, polyfill, throttle };