UNPKG

rrweb

Version:
361 lines (358 loc) 12.9 kB
import { __spread, __assign } from '../../node_modules/tslib/tslib.es6.js'; import { IncrementalSource, MouseInteractions, MediaInteractions } from '../types.js'; import { on, throttle, isTouchEvent, mirror, isBlocked, getWindowHeight, getWindowWidth, hookSetter } from '../utils.js'; import MutationBuffer from './mutation.js'; function initMutationObserver(cb, blockClass, inlineStylesheet, maskInputOptions) { var mutationBuffer = new MutationBuffer(cb, blockClass, inlineStylesheet, maskInputOptions); var observer = new MutationObserver(mutationBuffer.processMutations); observer.observe(document, { attributes: true, attributeOldValue: true, characterData: true, characterDataOldValue: true, childList: true, subtree: true, }); return observer; } function initMoveObserver(cb, sampling) { if (sampling.mousemove === false) { return function () { }; } var threshold = typeof sampling.mousemove === 'number' ? sampling.mousemove : 50; var positions = []; var timeBaseline; var wrappedCb = throttle(function (isTouch) { var totalOffset = Date.now() - timeBaseline; cb(positions.map(function (p) { p.timeOffset -= totalOffset; return p; }), isTouch ? IncrementalSource.TouchMove : IncrementalSource.MouseMove); positions = []; timeBaseline = null; }, 500); var updatePosition = throttle(function (evt) { var target = evt.target; var _a = isTouchEvent(evt) ? evt.changedTouches[0] : evt, clientX = _a.clientX, clientY = _a.clientY; if (!timeBaseline) { timeBaseline = Date.now(); } positions.push({ x: clientX, y: clientY, id: mirror.getId(target), timeOffset: Date.now() - timeBaseline, }); wrappedCb(isTouchEvent(evt)); }, threshold, { trailing: false, }); var handlers = [ on('mousemove', updatePosition), on('touchmove', updatePosition), ]; return function () { handlers.forEach(function (h) { return h(); }); }; } function initMouseInteractionObserver(cb, blockClass, sampling) { if (sampling.mouseInteraction === false) { return function () { }; } var disableMap = sampling.mouseInteraction === true || sampling.mouseInteraction === undefined ? {} : sampling.mouseInteraction; var handlers = []; var getHandler = function (eventKey) { return function (event) { if (isBlocked(event.target, blockClass)) { return; } var id = mirror.getId(event.target); var _a = isTouchEvent(event) ? event.changedTouches[0] : event, clientX = _a.clientX, clientY = _a.clientY; cb({ type: MouseInteractions[eventKey], id: id, x: clientX, y: clientY, }); }; }; Object.keys(MouseInteractions) .filter(function (key) { return Number.isNaN(Number(key)) && !key.endsWith('_Departed') && disableMap[key] !== false; }) .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, sampling) { 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, }); } }, sampling.scroll || 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, maskInputOptions, sampling) { 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; } else if (maskInputOptions[target.tagName.toLowerCase()] || maskInputOptions[type]) { text = '*'.repeat(text.length); } 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(__assign({}, v), { id: id })); } } var events = sampling.input === 'last' ? ['change'] : ['input', 'change']; var handlers = events.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, __spread(hookProperties.map(function (p) { return hookSetter(p[0], p[1], { set: function () { eventHandler({ target: this }); }, }); }))); } return function () { handlers.forEach(function (h) { return h(); }); }; } function initStyleSheetObserver(cb) { var insertRule = CSSStyleSheet.prototype.insertRule; CSSStyleSheet.prototype.insertRule = function (rule, index) { var id = mirror.getId(this.ownerNode); if (id !== -1) { cb({ id: id, adds: [{ rule: rule, index: index }], }); } return insertRule.apply(this, arguments); }; var deleteRule = CSSStyleSheet.prototype.deleteRule; CSSStyleSheet.prototype.deleteRule = function (index) { var id = mirror.getId(this.ownerNode); if (id !== -1) { cb({ id: id, removes: [{ index: index }], }); } return deleteRule.apply(this, arguments); }; return function () { CSSStyleSheet.prototype.insertRule = insertRule; CSSStyleSheet.prototype.deleteRule = deleteRule; }; } function initMediaInteractionObserver(mediaInteractionCb, blockClass) { var handler = function (type) { return function (event) { var target = event.target; if (!target || isBlocked(target, blockClass)) { return; } mediaInteractionCb({ type: type === 'play' ? MediaInteractions.Play : MediaInteractions.Pause, id: mirror.getId(target), }); }; }; var handlers = [on('play', handler('play')), on('pause', handler('pause'))]; return function () { handlers.forEach(function (h) { return h(); }); }; } function mergeHooks(o, hooks) { var mutationCb = o.mutationCb, mousemoveCb = o.mousemoveCb, mouseInteractionCb = o.mouseInteractionCb, scrollCb = o.scrollCb, viewportResizeCb = o.viewportResizeCb, inputCb = o.inputCb, mediaInteractionCb = o.mediaInteractionCb, styleSheetRuleCb = o.styleSheetRuleCb; o.mutationCb = function () { var p = []; for (var _i = 0; _i < arguments.length; _i++) { p[_i] = arguments[_i]; } if (hooks.mutation) { hooks.mutation.apply(hooks, __spread(p)); } mutationCb.apply(void 0, __spread(p)); }; o.mousemoveCb = function () { var p = []; for (var _i = 0; _i < arguments.length; _i++) { p[_i] = arguments[_i]; } if (hooks.mousemove) { hooks.mousemove.apply(hooks, __spread(p)); } mousemoveCb.apply(void 0, __spread(p)); }; o.mouseInteractionCb = function () { var p = []; for (var _i = 0; _i < arguments.length; _i++) { p[_i] = arguments[_i]; } if (hooks.mouseInteraction) { hooks.mouseInteraction.apply(hooks, __spread(p)); } mouseInteractionCb.apply(void 0, __spread(p)); }; o.scrollCb = function () { var p = []; for (var _i = 0; _i < arguments.length; _i++) { p[_i] = arguments[_i]; } if (hooks.scroll) { hooks.scroll.apply(hooks, __spread(p)); } scrollCb.apply(void 0, __spread(p)); }; o.viewportResizeCb = function () { var p = []; for (var _i = 0; _i < arguments.length; _i++) { p[_i] = arguments[_i]; } if (hooks.viewportResize) { hooks.viewportResize.apply(hooks, __spread(p)); } viewportResizeCb.apply(void 0, __spread(p)); }; o.inputCb = function () { var p = []; for (var _i = 0; _i < arguments.length; _i++) { p[_i] = arguments[_i]; } if (hooks.input) { hooks.input.apply(hooks, __spread(p)); } inputCb.apply(void 0, __spread(p)); }; o.mediaInteractionCb = function () { var p = []; for (var _i = 0; _i < arguments.length; _i++) { p[_i] = arguments[_i]; } if (hooks.mediaInteaction) { hooks.mediaInteaction.apply(hooks, __spread(p)); } mediaInteractionCb.apply(void 0, __spread(p)); }; o.styleSheetRuleCb = function () { var p = []; for (var _i = 0; _i < arguments.length; _i++) { p[_i] = arguments[_i]; } if (hooks.styleSheetRule) { hooks.styleSheetRule.apply(hooks, __spread(p)); } styleSheetRuleCb.apply(void 0, __spread(p)); }; } function initObservers(o, hooks) { if (hooks === void 0) { hooks = {}; } mergeHooks(o, hooks); var mutationObserver = initMutationObserver(o.mutationCb, o.blockClass, o.inlineStylesheet, o.maskInputOptions); var mousemoveHandler = initMoveObserver(o.mousemoveCb, o.sampling); var mouseInteractionHandler = initMouseInteractionObserver(o.mouseInteractionCb, o.blockClass, o.sampling); var scrollHandler = initScrollObserver(o.scrollCb, o.blockClass, o.sampling); var viewportResizeHandler = initViewportResizeObserver(o.viewportResizeCb); var inputHandler = initInputObserver(o.inputCb, o.blockClass, o.ignoreClass, o.maskInputOptions, o.sampling); var mediaInteractionHandler = initMediaInteractionObserver(o.mediaInteractionCb, o.blockClass); var styleSheetObserver = initStyleSheetObserver(o.styleSheetRuleCb); return function () { mutationObserver.disconnect(); mousemoveHandler(); mouseInteractionHandler(); scrollHandler(); viewportResizeHandler(); inputHandler(); mediaInteractionHandler(); styleSheetObserver(); }; } export default initObservers; export { INPUT_TAGS };