UNPKG

rrweb

Version:
1,479 lines (1,405 loc) 74.6 kB
/*! ***************************************************************************** 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