rrweb
Version:
record and replay the web
1,479 lines (1,405 loc) • 74.6 kB
JavaScript
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var NodeType;
(function (NodeType) {
NodeType[NodeType["Document"] = 0] = "Document";
NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
NodeType[NodeType["Element"] = 2] = "Element";
NodeType[NodeType["Text"] = 3] = "Text";
NodeType[NodeType["CDATA"] = 4] = "CDATA";
NodeType[NodeType["Comment"] = 5] = "Comment";
})(NodeType || (NodeType = {}));
var _id = 1;
function genId() {
return _id++;
}
function resetId() {
_id = 1;
}
function getCssRulesString(s) {
try {
var rules = s.rules || s.cssRules;
return rules
? Array.from(rules).reduce(function (prev, cur) { return (prev += cur.cssText); }, '')
: null;
}
catch (error) {
return null;
}
}
function extractOrigin(url) {
var origin;
if (url.indexOf('//') > -1) {
origin = url
.split('/')
.slice(0, 3)
.join('/');
}
else {
origin = url.split('/')[0];
}
origin = origin.split('?')[0];
return origin;
}
var URL_IN_CSS_REF = /url\((?:'([^']*)'|"([^"]*)"|([^)]*))\)/gm;
var RELATIVE_PATH = /^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/).*/;
var DATA_URI = /^(data:)([\w\/\+]+);(charset=[\w-]+|base64).*,(.*)/gi;
function absoluteToStylesheet(cssText, href) {
return cssText.replace(URL_IN_CSS_REF, function (origin, path1, path2, path3) {
var filePath = path1 || path2 || path3;
if (!filePath) {
return origin;
}
if (!RELATIVE_PATH.test(filePath)) {
return "url('" + filePath + "')";
}
if (DATA_URI.test(filePath)) {
return "url(" + filePath + ")";
}
if (filePath[0] === '/') {
return "url('" + (extractOrigin(href) + filePath) + "')";
}
var stack = href.split('/');
var parts = filePath.split('/');
stack.pop();
for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
var part = parts_1[_i];
if (part === '.') {
continue;
}
else if (part === '..') {
stack.pop();
}
else {
stack.push(part);
}
}
return "url('" + stack.join('/') + "')";
});
}
function absoluteToDoc(doc, attributeValue) {
var a = doc.createElement('a');
a.href = attributeValue;
return a.href;
}
function isSVGElement(el) {
return el.tagName === 'svg' || el instanceof SVGElement;
}
function serializeNode(n, doc, blockClass) {
switch (n.nodeType) {
case n.DOCUMENT_NODE:
return {
type: NodeType.Document,
childNodes: []
};
case n.DOCUMENT_TYPE_NODE:
return {
type: NodeType.DocumentType,
name: n.name,
publicId: n.publicId,
systemId: n.systemId
};
case n.ELEMENT_NODE:
var needBlock_1 = false;
if (typeof blockClass === 'string') {
needBlock_1 = n.classList.contains(blockClass);
}
else {
n.classList.forEach(function (className) {
if (blockClass.test(className)) {
needBlock_1 = true;
}
});
}
var tagName = n.tagName.toLowerCase();
var attributes_1 = {};
for (var _i = 0, _a = Array.from(n.attributes); _i < _a.length; _i++) {
var _b = _a[_i], name = _b.name, value = _b.value;
if (name === 'src' || name === 'href') {
attributes_1[name] = absoluteToDoc(doc, value);
}
else if (name === 'style') {
attributes_1[name] = absoluteToStylesheet(value, location.href);
}
else {
attributes_1[name] = value;
}
}
if (tagName === 'link') {
var stylesheet = Array.from(doc.styleSheets).find(function (s) {
return s.href === n.href;
});
var cssText = getCssRulesString(stylesheet);
if (cssText) {
delete attributes_1.rel;
delete attributes_1.href;
attributes_1._cssText = absoluteToStylesheet(cssText, stylesheet.href);
}
}
if (tagName === 'style' &&
n.sheet &&
!n.innerText.trim().length) {
var cssText = getCssRulesString(n
.sheet);
if (cssText) {
attributes_1._cssText = absoluteToStylesheet(cssText, location.href);
}
}
if (tagName === 'input' ||
tagName === 'textarea' ||
tagName === 'select') {
var value = n.value;
if (attributes_1.type !== 'radio' &&
attributes_1.type !== 'checkbox' &&
value) {
attributes_1.value = value;
}
else if (n.checked) {
attributes_1.checked = n.checked;
}
}
if (tagName === 'option') {
var selectValue = n.parentElement;
if (attributes_1.value === selectValue.value) {
attributes_1.selected = n.selected;
}
}
if (needBlock_1) {
var _c = n.getBoundingClientRect(), width = _c.width, height = _c.height;
attributes_1.rr_width = width + "px";
attributes_1.rr_height = height + "px";
}
return {
type: NodeType.Element,
tagName: tagName,
attributes: attributes_1,
childNodes: [],
isSVG: isSVGElement(n) || undefined,
needBlock: needBlock_1
};
case n.TEXT_NODE:
var parentTagName = n.parentNode && n.parentNode.tagName;
var textContent = n.textContent;
var isStyle = parentTagName === 'STYLE' ? true : undefined;
if (isStyle && textContent) {
textContent = absoluteToStylesheet(textContent, location.href);
}
if (parentTagName === 'SCRIPT') {
textContent = 'SCRIPT_PLACEHOLDER';
}
return {
type: NodeType.Text,
textContent: textContent || '',
isStyle: isStyle
};
case n.CDATA_SECTION_NODE:
return {
type: NodeType.CDATA,
textContent: ''
};
case n.COMMENT_NODE:
return {
type: NodeType.Comment,
textContent: n.textContent || ''
};
default:
return false;
}
}
function serializeNodeWithId(n, doc, map, blockClass, skipChild) {
if (skipChild === void 0) { skipChild = false; }
var _serializedNode = serializeNode(n, doc, blockClass);
if (!_serializedNode) {
console.warn(n, 'not serialized');
return null;
}
var serializedNode = Object.assign(_serializedNode, {
id: genId()
});
n.__sn = serializedNode;
map[serializedNode.id] = n;
var recordChild = !skipChild;
if (serializedNode.type === NodeType.Element) {
recordChild = recordChild && !serializedNode.needBlock;
delete serializedNode.needBlock;
}
if ((serializedNode.type === NodeType.Document ||
serializedNode.type === NodeType.Element) &&
recordChild) {
for (var _i = 0, _a = Array.from(n.childNodes); _i < _a.length; _i++) {
var childN = _a[_i];
var serializedChildNode = serializeNodeWithId(childN, doc, map, blockClass);
if (serializedChildNode) {
serializedNode.childNodes.push(serializedChildNode);
}
}
}
return serializedNode;
}
function snapshot(n, blockClass) {
if (blockClass === void 0) { blockClass = 'rr-block'; }
resetId();
var idNodeMap = {};
return [serializeNodeWithId(n, n, idNodeMap, blockClass), idNodeMap];
}
var tagMap = {
script: 'noscript',
altglyph: 'altGlyph',
altglyphdef: 'altGlyphDef',
altglyphitem: 'altGlyphItem',
animatecolor: 'animateColor',
animatemotion: 'animateMotion',
animatetransform: 'animateTransform',
clippath: 'clipPath',
feblend: 'feBlend',
fecolormatrix: 'feColorMatrix',
fecomponenttransfer: 'feComponentTransfer',
fecomposite: 'feComposite',
feconvolvematrix: 'feConvolveMatrix',
fediffuselighting: 'feDiffuseLighting',
fedisplacementmap: 'feDisplacementMap',
fedistantlight: 'feDistantLight',
fedropshadow: 'feDropShadow',
feflood: 'feFlood',
fefunca: 'feFuncA',
fefuncb: 'feFuncB',
fefuncg: 'feFuncG',
fefuncr: 'feFuncR',
fegaussianblur: 'feGaussianBlur',
feimage: 'feImage',
femerge: 'feMerge',
femergenode: 'feMergeNode',
femorphology: 'feMorphology',
feoffset: 'feOffset',
fepointlight: 'fePointLight',
fespecularlighting: 'feSpecularLighting',
fespotlight: 'feSpotLight',
fetile: 'feTile',
feturbulence: 'feTurbulence',
foreignobject: 'foreignObject',
glyphref: 'glyphRef',
lineargradient: 'linearGradient',
radialgradient: 'radialGradient'
};
function getTagName(n) {
var tagName = tagMap[n.tagName] ? tagMap[n.tagName] : n.tagName;
if (tagName === 'link' && n.attributes._cssText) {
tagName = 'style';
}
return tagName;
}
var CSS_SELECTOR = /([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g;
var HOVER_SELECTOR = /([^\\]):hover/g;
function addHoverClass(cssText) {
return cssText.replace(CSS_SELECTOR, function (match, p1, p2) {
if (HOVER_SELECTOR.test(p1)) {
var newSelector = p1.replace(HOVER_SELECTOR, '$1.\\:hover');
return p1.replace(/\s*$/, '') + ", " + newSelector.replace(/^\s*/, '') + p2;
}
else {
return match;
}
});
}
function buildNode(n, doc) {
switch (n.type) {
case NodeType.Document:
return doc.implementation.createDocument(null, '', null);
case NodeType.DocumentType:
return doc.implementation.createDocumentType(n.name, n.publicId, n.systemId);
case NodeType.Element:
var tagName = getTagName(n);
var node = void 0;
if (n.isSVG) {
node = doc.createElementNS('http://www.w3.org/2000/svg', tagName);
}
else {
node = doc.createElement(tagName);
}
for (var name in n.attributes) {
if (n.attributes.hasOwnProperty(name) && !name.startsWith('rr_')) {
var value = n.attributes[name];
value = typeof value === 'boolean' ? '' : value;
var isTextarea = tagName === 'textarea' && name === 'value';
var isRemoteOrDynamicCss = tagName === 'style' && name === '_cssText';
if (isRemoteOrDynamicCss) {
value = addHoverClass(value);
}
if (isTextarea || isRemoteOrDynamicCss) {
var child = doc.createTextNode(value);
node.appendChild(child);
continue;
}
if (tagName === 'iframe' && name === 'src') {
continue;
}
try {
node.setAttribute(name, value);
}
catch (error) {
}
}
else {
if (n.attributes.rr_width) {
node.style.width = n.attributes.rr_width;
}
if (n.attributes.rr_height) {
node.style.height = n.attributes
.rr_height;
}
}
}
return node;
case NodeType.Text:
return doc.createTextNode(n.isStyle ? addHoverClass(n.textContent) : n.textContent);
case NodeType.CDATA:
return doc.createCDATASection(n.textContent);
case NodeType.Comment:
return doc.createComment(n.textContent);
default:
return null;
}
}
function buildNodeWithSN(n, doc, map, skipChild) {
if (skipChild === void 0) { skipChild = false; }
var node = buildNode(n, doc);
if (!node) {
return null;
}
if (n.type === NodeType.Document) {
doc.close();
doc.open();
node = doc;
}
node.__sn = n;
map[n.id] = node;
if ((n.type === NodeType.Document || n.type === NodeType.Element) &&
!skipChild) {
for (var _i = 0, _a = n.childNodes; _i < _a.length; _i++) {
var childN = _a[_i];
var childNode = buildNodeWithSN(childN, doc, map);
if (!childNode) {
console.warn('Failed to rebuild', childN);
}
else {
node.appendChild(childNode);
}
}
}
return node;
}
function rebuild(n, doc) {
var idNodeMap = {};
return [buildNodeWithSN(n, doc, idNodeMap), idNodeMap];
}
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.__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 () {
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) {
var original = Object.getOwnPropertyDescriptor(target, key);
Object.defineProperty(target, key, {
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 || {}); };
}
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) {
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 {
node.classList.forEach(function (className) {
if (blockClass.test(className)) {
needBlock_1 = true;
}
});
}
return needBlock_1 || isBlocked(node.parentNode, blockClass);
}
return isBlocked(node.parentNode, blockClass);
}
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);
}
var EventType;
(function (EventType) {
EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
EventType[EventType["Load"] = 1] = "Load";
EventType[EventType["FullSnapshot"] = 2] = "FullSnapshot";
EventType[EventType["IncrementalSnapshot"] = 3] = "IncrementalSnapshot";
EventType[EventType["Meta"] = 4] = "Meta";
})(EventType || (EventType = {}));
var IncrementalSource;
(function (IncrementalSource) {
IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
IncrementalSource[IncrementalSource["MouseMove"] = 1] = "MouseMove";
IncrementalSource[IncrementalSource["MouseInteraction"] = 2] = "MouseInteraction";
IncrementalSource[IncrementalSource["Scroll"] = 3] = "Scroll";
IncrementalSource[IncrementalSource["ViewportResize"] = 4] = "ViewportResize";
IncrementalSource[IncrementalSource["Input"] = 5] = "Input";
})(IncrementalSource || (IncrementalSource = {}));
var MouseInteractions;
(function (MouseInteractions) {
MouseInteractions[MouseInteractions["MouseUp"] = 0] = "MouseUp";
MouseInteractions[MouseInteractions["MouseDown"] = 1] = "MouseDown";
MouseInteractions[MouseInteractions["Click"] = 2] = "Click";
MouseInteractions[MouseInteractions["ContextMenu"] = 3] = "ContextMenu";
MouseInteractions[MouseInteractions["DblClick"] = 4] = "DblClick";
MouseInteractions[MouseInteractions["Focus"] = 5] = "Focus";
MouseInteractions[MouseInteractions["Blur"] = 6] = "Blur";
MouseInteractions[MouseInteractions["TouchStart"] = 7] = "TouchStart";
MouseInteractions[MouseInteractions["TouchMove"] = 8] = "TouchMove";
MouseInteractions[MouseInteractions["TouchEnd"] = 9] = "TouchEnd";
})(MouseInteractions || (MouseInteractions = {}));
var ReplayerEvents;
(function (ReplayerEvents) {
ReplayerEvents["Start"] = "start";
ReplayerEvents["Pause"] = "pause";
ReplayerEvents["Resume"] = "resume";
ReplayerEvents["Resize"] = "resize";
ReplayerEvents["Finish"] = "finish";
ReplayerEvents["FullsnapshotRebuilded"] = "fullsnapshot-rebuilded";
ReplayerEvents["LoadStylesheetStart"] = "load-stylesheet-start";
ReplayerEvents["LoadStylesheetEnd"] = "load-stylesheet-end";
ReplayerEvents["SkipStart"] = "skip-start";
ReplayerEvents["SkipEnd"] = "skip-end";
ReplayerEvents["MouseInteraction"] = "mouse-interaction";
})(ReplayerEvents || (ReplayerEvents = {}));
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 isParentDropped(droppedSet, n) {
var parentNode = n.parentNode;
if (!parentNode) {
return false;
}
if (droppedSet.has(parentNode)) {
return true;
}
return isParentDropped(droppedSet, parentNode);
}
function initMutationObserver(cb, blockClass) {
var observer = new MutationObserver(function (mutations) {
var texts = [];
var attributes = [];
var removes = [];
var adds = [];
var addsSet = new Set();
var droppedSet = new Set();
var genAdds = function (n) {
if (isBlocked(n, blockClass)) {
return;
}
addsSet.add(n);
droppedSet["delete"](n);
n.childNodes.forEach(function (childN) { return genAdds(childN); });
};
mutations.forEach(function (mutation) {
var type = mutation.type, target = mutation.target, oldValue = mutation.oldValue, addedNodes = mutation.addedNodes, removedNodes = mutation.removedNodes, attributeName = mutation.attributeName;
switch (type) {
case 'characterData': {
var value = target.textContent;
if (!isBlocked(target, blockClass) && value !== oldValue) {
texts.push({
value: value,
node: target
});
}
break;
}
case 'attributes': {
var value = target.getAttribute(attributeName);
if (isBlocked(target, blockClass) || value === oldValue) {
return;
}
var item = attributes.find(function (a) { return a.node === target; });
if (!item) {
item = {
node: target,
attributes: {}
};
attributes.push(item);
}
item.attributes[attributeName] = value;
break;
}
case 'childList': {
addedNodes.forEach(function (n) { return genAdds(n); });
removedNodes.forEach(function (n) {
var nodeId = mirror.getId(n);
var parentId = mirror.getId(target);
if (isBlocked(n, blockClass)) {
return;
}
if (addsSet.has(n)) {
deepDelete(addsSet, n);
droppedSet.add(n);
}
else if (addsSet.has(target) && nodeId === -1) ;
else if (isAncestorRemoved(target)) ;
else {
removes.push({
parentId: parentId,
id: nodeId
});
}
mirror.removeNodeFromMap(n);
});
break;
}
default:
break;
}
});
Array.from(addsSet).forEach(function (n) {
if (!isParentDropped(droppedSet, n) && !isParentRemoved(removes, n)) {
adds.push({
parentId: mirror.getId(n.parentNode),
previousId: !n.previousSibling
? n.previousSibling
: mirror.getId(n.previousSibling),
nextId: !n.nextSibling
? n.nextSibling
: mirror.getId(n.nextSibling),
node: serializeNodeWithId(n, document, mirror.map, blockClass, true)
});
}
else {
droppedSet.add(n);
}
});
var payload = {
texts: texts
.map(function (text) { return ({
id: mirror.getId(text.node),
value: text.value
}); })
.filter(function (text) { return mirror.has(text.id); }),
attributes: attributes
.map(function (attribute) { return ({
id: mirror.getId(attribute.node),
attributes: attribute.attributes
}); })
.filter(function (attribute) { return mirror.has(attribute.id); }),
removes: removes,
adds: adds
};
if (!payload.texts.length &&
!payload.attributes.length &&
!payload.removes.length &&
!payload.adds.length) {
return;
}
cb(payload);
});
observer.observe(document, {
attributes: true,
attributeOldValue: true,
characterData: true,
characterDataOldValue: true,
childList: true,
subtree: true
});
return observer;
}
function initMousemoveObserver(cb) {
var positions = [];
var timeBaseline;
var wrappedCb = throttle(function () {
var totalOffset = Date.now() - timeBaseline;
cb(positions.map(function (p) {
p.timeOffset -= totalOffset;
return p;
}));
positions = [];
timeBaseline = null;
}, 500);
var updatePosition = throttle(function (evt) {
var clientX = evt.clientX, clientY = evt.clientY, target = evt.target;
if (!timeBaseline) {
timeBaseline = Date.now();
}
positions.push({
x: clientX,
y: clientY,
id: mirror.getId(target),
timeOffset: Date.now() - timeBaseline
});
wrappedCb();
}, 50, {
trailing: false
});
return on('mousemove', updatePosition);
}
function initMouseInteractionObserver(cb, blockClass) {
var handlers = [];
var getHandler = function (eventKey) {
return function (event) {
if (isBlocked(event.target, blockClass)) {
return;
}
var id = mirror.getId(event.target);
var clientX = event.clientX, clientY = event.clientY;
cb({
type: MouseInteractions[eventKey],
id: id,
x: clientX,
y: clientY
});
};
};
Object.keys(MouseInteractions)
.filter(function (key) { return Number.isNaN(Number(key)); })
.forEach(function (eventKey) {
var eventName = eventKey.toLowerCase();
var handler = getHandler(eventKey);
handlers.push(on(eventName, handler));
});
return function () {
handlers.forEach(function (h) { return h(); });
};
}
function initScrollObserver(cb, blockClass) {
var updatePosition = throttle(function (evt) {
if (!evt.target || isBlocked(evt.target, blockClass)) {
return;
}
var id = mirror.getId(evt.target);
if (evt.target === document) {
var scrollEl = (document.scrollingElement || document.documentElement);
cb({
id: id,
x: scrollEl.scrollLeft,
y: scrollEl.scrollTop
});
}
else {
cb({
id: id,
x: evt.target.scrollLeft,
y: evt.target.scrollTop
});
}
}, 100);
return on('scroll', updatePosition);
}
function initViewportResizeObserver(cb) {
var updateDimension = throttle(function () {
var height = getWindowHeight();
var width = getWindowWidth();
cb({
width: Number(width),
height: Number(height)
});
}, 200);
return on('resize', updateDimension, window);
}
var INPUT_TAGS = ['INPUT', 'TEXTAREA', 'SELECT'];
var lastInputValueMap = new WeakMap();
function initInputObserver(cb, blockClass, ignoreClass) {
function eventHandler(event) {
var target = event.target;
if (!target ||
!target.tagName ||
INPUT_TAGS.indexOf(target.tagName) < 0 ||
isBlocked(target, blockClass)) {
return;
}
var type = target.type;
if (type === 'password' ||
target.classList.contains(ignoreClass)) {
return;
}
var text = target.value;
var isChecked = false;
if (type === 'radio' || type === 'checkbox') {
isChecked = target.checked;
}
cbWithDedup(target, { text: text, isChecked: isChecked });
var name = target.name;
if (type === 'radio' && name && isChecked) {
document
.querySelectorAll("input[type=\"radio\"][name=\"" + name + "\"]")
.forEach(function (el) {
if (el !== target) {
cbWithDedup(el, {
text: el.value,
isChecked: !isChecked
});
}
});
}
}
function cbWithDedup(target, v) {
var lastInputValue = lastInputValueMap.get(target);
if (!lastInputValue ||
lastInputValue.text !== v.text ||
lastInputValue.isChecked !== v.isChecked) {
lastInputValueMap.set(target, v);
var id = mirror.getId(target);
cb(__assign({}, v, { id: id }));
}
}
var handlers = [
'input',
'change',
].map(function (eventName) { return on(eventName, eventHandler); });
var propertyDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
var hookProperties = [
[HTMLInputElement.prototype, 'value'],
[HTMLInputElement.prototype, 'checked'],
[HTMLSelectElement.prototype, 'value'],
[HTMLTextAreaElement.prototype, 'value'],
];
if (propertyDescriptor && propertyDescriptor.set) {
handlers.push.apply(handlers, hookProperties.map(function (p) {
return hookSetter(p[0], p[1], {
set: function () {
eventHandler({ target: this });
}
});
}));
}
return function () {
handlers.forEach(function (h) { return h(); });
};
}
function initObservers(o) {
var mutationObserver = initMutationObserver(o.mutationCb, o.blockClass);
var mousemoveHandler = initMousemoveObserver(o.mousemoveCb);
var mouseInteractionHandler = initMouseInteractionObserver(o.mouseInteractionCb, o.blockClass);
var scrollHandler = initScrollObserver(o.scrollCb, o.blockClass);
var viewportResizeHandler = initViewportResizeObserver(o.viewportResizeCb);
var inputHandler = initInputObserver(o.inputCb, o.blockClass, o.ignoreClass);
return function () {
mutationObserver.disconnect();
mousemoveHandler();
mouseInteractionHandler();
scrollHandler();
viewportResizeHandler();
inputHandler();
};
}
function wrapEvent(e) {
return __assign({}, e, { timestamp: Date.now() });
}
function record(options) {
if (options === void 0) { options = {}; }
var emit = options.emit, checkoutEveryNms = options.checkoutEveryNms, checkoutEveryNth = options.checkoutEveryNth, _a = options.blockClass, blockClass = _a === void 0 ? 'rr-block' : _a, _b = options.ignoreClass, ignoreClass = _b === void 0 ? 'rr-ignore' : _b;
if (!emit) {
throw new Error('emit function is required');
}
var lastFullSnapshotEvent;
var incrementalSnapshotCount = 0;
var wrappedEmit = function (e, isCheckout) {
emit(e, isCheckout);
if (e.type === EventType.FullSnapshot) {
lastFullSnapshotEvent = e;
incrementalSnapshotCount = 0;
}
else if (e.type === EventType.IncrementalSnapshot) {
incrementalSnapshotCount++;
var exceedCount = checkoutEveryNth && incrementalSnapshotCount >= checkoutEveryNth;
var exceedTime = checkoutEveryNms &&
e.timestamp - lastFullSnapshotEvent.timestamp > checkoutEveryNms;
if (exceedCount || exceedTime) {
takeFullSnapshot(true);
}
}
};
function takeFullSnapshot(isCheckout) {
if (isCheckout === void 0) { isCheckout = false; }
wrappedEmit(wrapEvent({
type: EventType.Meta,
data: {
href: window.location.href,
width: getWindowWidth(),
height: getWindowHeight()
}
}), isCheckout);
var _a = snapshot(document, blockClass), node = _a[0], idNodeMap = _a[1];
if (!node) {
return console.warn('Failed to snapshot the document');
}
mirror.map = idNodeMap;
wrappedEmit(wrapEvent({
type: EventType.FullSnapshot,
data: {
node: node,
initialOffset: {
left: document.documentElement.scrollLeft,
top: document.documentElement.scrollTop
}
}
}));
}
try {
var handlers_1 = [];
handlers_1.push(on('DOMContentLoaded', function () {
wrappedEmit(wrapEvent({
type: EventType.DomContentLoaded,
data: {}
}));
}));
var init_1 = function () {
takeFullSnapshot();
handlers_1.push(initObservers({
mutationCb: function (m) {
return wrappedEmit(wrapEvent({
type: EventType.IncrementalSnapshot,
data: __assign({ source: IncrementalSource.Mutation }, m)
}));
},
mousemoveCb: function (positions) {
return wrappedEmit(wrapEvent({
type: EventType.IncrementalSnapshot,
data: {
source: IncrementalSource.MouseMove,
positions: positions
}
}));
},
mouseInteractionCb: function (d) {
return wrappedEmit(wrapEvent({
type: EventType.IncrementalSnapshot,
data: __assign({ source: IncrementalSource.MouseInteraction }, d)
}));
},
scrollCb: function (p) {
return wrappedEmit(wrapEvent({
type: EventType.IncrementalSnapshot,
data: __assign({ source: IncrementalSource.Scroll }, p)
}));
},
viewportResizeCb: function (d) {
return wrappedEmit(wrapEvent({
type: EventType.IncrementalSnapshot,
data: __assign({ source: IncrementalSource.ViewportResize }, d)
}));
},
inputCb: function (v) {
return wrappedEmit(wrapEvent({
type: EventType.IncrementalSnapshot,
data: __assign({ source: IncrementalSource.Input }, v)
}));
},
blockClass: blockClass,
ignoreClass: ignoreClass
}));
};
if (document.readyState === 'interactive' ||
document.readyState === 'complete') {
init_1();
}
else {
handlers_1.push(on('load', function () {
wrappedEmit(wrapEvent({
type: EventType.Load,
data: {}
}));
init_1();
}, window));
}
return function () {
handlers_1.forEach(function (h) { return h(); });
};
}
catch (error) {
console.warn(error);
}
}
//
// An event handler can take an optional event argument
// and should not return a value
// An array of all currently registered event handlers for a type
// A map of event types and their corresponding event handlers.
/** Mitt: Tiny (~200b) functional event emitter / pubsub.
* @name mitt
* @returns {Mitt}
*/
function mitt(all ) {
all = all || Object.create(null);
return {
/**
* Register an event handler for the given type.
*
* @param {String} type Type of event to listen for, or `"*"` for all events
* @param {Function} handler Function to call in response to given event
* @memberOf mitt
*/
on: function on(type , handler ) {
(all[type] || (all[type] = [])).push(handler);
},
/**
* Remove an event handler for the given type.
*
* @param {String} type Type of event to unregister `handler` from, or `"*"`
* @param {Function} handler Handler function to remove
* @memberOf mitt
*/
off: function off(type , handler ) {
if (all[type]) {
all[type].splice(all[type].indexOf(handler) >>> 0, 1);
}
},
/**
* Invoke all handlers for the given type.
* If present, `"*"` handlers are invoked after type-matched handlers.
*
* @param {String} type The event type to invoke
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
* @memberOf mitt
*/
emit: function emit(type , evt ) {
(all[type] || []).slice().map(function (handler) { handler(evt); });
(all['*'] || []).slice().map(function (handler) { handler(type, evt); });
}
};
}
var mittProxy = /*#__PURE__*/Object.freeze({
default: mitt
});
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var smoothscroll = createCommonjsModule(function (module, exports) {
/* smoothscroll v0.4.4 - 2019 - Dustan Kasten, Jeremias Menichelli - MIT License */
(function () {
// polyfill
function polyfill() {
// aliases
var w = window;
var d = document;
// return if scroll behavior is supported and polyfill is not forced
if (
'scrollBehavior' in d.documentElement.style &&
w.__forceSmoothScrollPolyfill__ !== true
) {
return;
}
// globals
var Element = w.HTMLElement || w.Element;
var SCROLL_TIME = 468;
// object gathering original scroll methods
var original = {
scroll: w.scroll || w.scrollTo,
scrollBy: w.scrollBy,
elementScroll: Element.prototype.scroll || scrollElement,
scrollIntoView: Element.prototype.scrollIntoView
};
// define timing method
var now =
w.performance && w.performance.now
? w.performance.now.bind(w.performance)
: Date.now;
/**
* indicates if a the current browser is made by Microsoft
* @method isMicrosoftBrowser
* @param {String} userAgent
* @returns {Boolean}
*/
function isMicrosoftBrowser(userAgent) {
var userAgentPatterns = ['MSIE ', 'Trident/', 'Edge/'];
return new RegExp(userAgentPatterns.join('|')).test(userAgent);
}
/*
* IE has rounding bug rounding down clientHeight and clientWidth and
* rounding up scrollHeight and scrollWidth causing false positives
* on hasScrollableSpace
*/
var ROUNDING_TOLERANCE = isMicrosoftBrowser(w.navigator.userAgent) ? 1 : 0;
/**
* changes scroll position inside an element
* @method scrollElement
* @param {Number} x
* @param {Number} y
* @returns {undefined}
*/
function scrollElement(x, y) {
this.scrollLeft = x;
this.scrollTop = y;
}
/**
* returns result of applying ease math function to a number
* @method ease
* @param {Number} k
* @returns {Number}
*/
function ease(k) {
return 0.5 * (1 - Math.cos(Math.PI * k));
}
/**
* indicates if a smooth behavior should be applied
* @method shouldBailOut
* @param {Number|Object} firstArg
* @returns {Boolean}
*/
function shouldBailOut(firstArg) {
if (
firstArg === null ||
typeof firstArg !== 'object' ||
firstArg.behavior === undefined ||
firstArg.behavior === 'auto' ||
firstArg.behavior === 'instant'
) {
// first argument is not an object/null
// or behavior is auto, instant or undefined
return true;
}
if (typeof firstArg === 'object' && firstArg.behavior === 'smooth') {
// first argument is an object and behavior is smooth
return false;
}
// throw error when behavior is not supported
throw new TypeError(
'behavior member of ScrollOptions ' +
firstArg.behavior +
' is not a valid value for enumeration ScrollBehavior.'
);
}
/**
* indicates if an element has scrollable space in the provided axis
* @method hasScrollableSpace
* @param {Node} el
* @param {String} axis
* @returns {Boolean}
*/
function hasScrollableSpace(el, axis) {
if (axis === 'Y') {
return el.clientHeight + ROUNDING_TOLERANCE < el.scrollHeight;
}
if (axis === 'X') {
return el.clientWidth + ROUNDING_TOLERANCE < el.scrollWidth;
}
}
/**
* indicates if an element has a scrollable overflow property in the axis
* @method canOverflow
* @param {Node} el
* @param {String} axis
* @returns {Boolean}
*/
function canOverflow(el, axis) {
var overflowValue = w.getComputedStyle(el, null)['overflow' + axis];
return overflowValue === 'auto' || overflowValue === 'scroll';
}
/**
* indicates if an element can be scrolled in either axis
* @method isScrollable
* @param {Node} el
* @param {String} axis
* @returns {Boolean}
*/
function isScrollable(el) {
var isScrollableY = hasScrollableSpace(el, 'Y') && canOverflow(el, 'Y');
var isScrollableX = hasScrollableSpace(el, 'X') && canOverflow(el, 'X');
return isScrollableY || isScrollableX;
}
/**
* finds scrollable parent of an element
* @method findScrollableParent
* @param {Node} el
* @returns {Node} el
*/
function findScrollableParent(el) {
while (el !== d.body && isScrollable(el) === false) {
el = el.parentNode || el.host;
}
return el;
}
/**
* self invoked function that, given a context, steps through scrolling
* @method step
* @param {Object} context
* @returns {undefined}
*/
function step(context) {
var time = now();
var value;
var currentX;
var currentY;
var elapsed = (time - context.startTime) / SCROLL_TIME;
// avoid elapsed times higher than one
elapsed = elapsed > 1 ? 1 : elapsed;
// apply easing to elapsed time
value = ease(elapsed);
currentX = context.startX + (context.x - context.startX) * value;
currentY = context.startY + (context.y - context.startY) * value;
context.method.call(context.scrollable, currentX, currentY);
// scroll more if we have not reached our destination
if (currentX !== context.x || currentY !== context.y) {
w.requestAnimationFrame(step.bind(w, context));
}
}
/**
* scrolls window or element with a smooth behavior
* @method smoothScroll
* @param {Object|Node} el
* @param {Number} x
* @param {Number} y
* @returns {undefined}
*/
function smoothScroll(el, x, y) {
var scrollable;
var startX;
var startY;
var method;
var startTime = now();
// define scroll context
if (el === d.body) {
scrollable = w;
startX = w.scrollX || w.pageXOffset;
startY = w.scrollY || w.pageYOffset;
method = original.scroll;
} else {
scrollable = el;
startX = el.scrollLeft;
startY = el.scrollTop;
method = scrollElement;
}
// scroll looping over a frame
step({
scrollable: scrollable,
method: method,
startTime: startTime,
startX: startX,
startY: startY,
x: x,
y: y
});
}
// ORIGINAL METHODS OVERRIDES
// w.scroll and w.scrollTo
w.scroll = w.scrollTo = function() {
// avoid action when no arguments are passed
if (arguments[0] === undefined) {
return;
}
// avoid smooth behavior if not required
if (shouldBailOut(arguments[0]) === true) {
original.scroll.call(
w,
arguments[0].left !== undefined
? arguments[0].left
: typeof arguments[0] !== 'object'
? arguments[0]
: w.scrollX || w.pageXOffset,
// use top prop, second argument if present or fallback to scrollY
arguments[0].top !== undefined
? arguments[0].top
: arguments[1] !== undefined
? arguments[1]
: w.scrollY || w.pageYOffset
);
return;
}
// LET THE SMOOTHNESS BEGIN!
smoothScroll.call(
w,
d.body,
arguments[0].left !== undefined
? ~~arguments[0].left
: w.scrollX || w.pageXOffset,
arguments[0].top !== undefined
? ~~arguments[0].top
: w.scrollY || w.pageYOffset
);
};
// w.scrollBy
w.scrollBy = function() {
// avoid action when no arguments are passed
if (arguments[0] === undefined) {
return;
}
// avoid smooth behavior if not required
if (shouldBailOut(arguments[0])) {
original.scrollBy.call(
w,
arguments[0].left !== undefined
? arguments[0].left
: typeof arguments[0] !== 'object' ? arguments[0] : 0,
arguments[0].top !== undefined
? arguments[0].top
: arguments[1] !== undefined ? arguments[1] : 0
);
return;
}
// LET THE SMOOTHNESS BEGIN!
smoothScroll.call(
w,
d.body,
~~arguments[0].left + (w.scrollX || w.pageXOffset),
~~arguments[0].top + (w.scrollY || w.pageYOffset)
);
};
// Element.prototype.scroll and Element.prototype.scrollTo
Element.prototype.scroll = Element.prototype.scrollTo = function() {
// avoid action when no arguments are passed
if (arguments[0] === undefined) {
return;
}
// avoid smooth behavior if not required
if (shouldBailOut(arguments[0]) === true) {
// if one number is passed, throw error to match Firefox implementation
if (typeof arguments[0] === 'number' && arguments[1] === undefined) {
throw new SyntaxError('Value could not be converted');
}
original.elementScroll.call(
this,
// use left prop, first number argument or fallback to scrollLeft
arguments[0].left !== undefined
? ~~arguments[0].left
: typeof arguments[0] !== 'object' ? ~~arguments[0] : this.scrollLeft,
// use top prop, second argument or fallback to scrollTop
arguments[0].top !== undefined
? ~~arguments[0].top
: arguments[1] !== undefined ? ~~arguments[1] : this.scrollTop
);
return;
}
var left = arguments[0].left;
var top = arguments[0].top;
// LET THE SMOOTHNESS BEGIN!
smoothScroll.call(
this,
this,
typeof left === 'undefined' ? this.scrollLeft : ~~left,
typeof top === 'undefined' ? this.scrollTop : ~~top
);
};
// Element.prototype.scrollBy
Element.prototype.scrollBy = function() {
// avoid action when no arguments are passed
if (arguments[0] === undefined) {
return;
}
// avoid smooth behavior if not required
if (shouldBailOut(arguments[0]) === true) {
original.elementScroll.call(
this,
arguments[0].left !== undefined
? ~~arguments[0].left + this.scrollLeft
: ~~arguments[0] + this.scrollLeft,
arguments[0].top !== undefined
? ~~arguments[0].top