diff --git a/es/rrweb/packages/rrweb/src/replay/index.js b/es/rrweb/packages/rrweb/src/replay/index.js index 0d49411b1f6d31103bed898c0e81d1d74ab51234..0b2160ef08aa3ae5310f63c295abc0a560332b22 100644 --- a/es/rrweb/packages/rrweb/src/replay/index.js +++ b/es/rrweb/packages/rrweb/src/replay/index.js @@ -203,6 +203,10 @@ class Replayer { mouseTail: defaultMouseTailConfig, useVirtualDom: true, logger: console, + onError: (e) => { + // maintain the existing behaviour of throwing if no handler is provided + throw e; + }, }; this.config = Object.assign({}, defaultConfig, config); this.handleResize = this.handleResize.bind(this); @@ -755,255 +759,259 @@ class Replayer { applyIncremental(e, isSync) { var _a, _b, _c; const { data: d } = e; - switch (d.source) { - case IncrementalSource.Mutation: { - try { - this.applyMutation(d, isSync); - } - catch (error) { - this.warn(`Exception in mutation ${error.message || error}`, d); - } - break; - } - case IncrementalSource.Drag: - case IncrementalSource.TouchMove: - case IncrementalSource.MouseMove: - if (isSync) { - const lastPosition = d.positions[d.positions.length - 1]; - this.mousePos = { - x: lastPosition.x, - y: lastPosition.y, - id: lastPosition.id, - debugData: d, - }; + try { + switch (d.source) { + case IncrementalSource.Mutation: { + try { + this.applyMutation(d, isSync); + } + catch (error) { + this.warn(`Exception in mutation ${error.message || error}`, d); + } + break; } - else { - d.positions.forEach((p) => { - const action = { - doAction: () => { - this.moveAndHover(p.x, p.y, p.id, isSync, d); - }, - delay: p.timeOffset + - e.timestamp - - this.service.state.context.baselineTime, + case IncrementalSource.Drag: + case IncrementalSource.TouchMove: + case IncrementalSource.MouseMove: + if (isSync) { + const lastPosition = d.positions[d.positions.length - 1]; + this.mousePos = { + x: lastPosition.x, + y: lastPosition.y, + id: lastPosition.id, + debugData: d, }; - this.timer.addAction(action); - }); - this.timer.addAction({ - doAction() { - }, - delay: e.delay - ((_a = d.positions[0]) === null || _a === void 0 ? void 0 : _a.timeOffset), - }); - } - break; - case IncrementalSource.MouseInteraction: { - if (d.id === -1) { + } + else { + d.positions.forEach((p) => { + const action = { + doAction: () => { + this.moveAndHover(p.x, p.y, p.id, isSync, d); + }, + delay: p.timeOffset + + e.timestamp - + this.service.state.context.baselineTime, + }; + this.timer.addAction(action); + }); + this.timer.addAction({ + doAction() { + }, + delay: e.delay - ((_a = d.positions[0]) === null || _a === void 0 ? void 0 : _a.timeOffset), + }); + } break; - } - const event = new Event(toLowerCase(MouseInteractions[d.type])); - const target = this.mirror.getNode(d.id); - if (!target) { - return this.debugNodeNotFound(d, d.id); - } - this.emitter.emit(ReplayerEvents.MouseInteraction, { - type: d.type, - target, - }); - const { triggerFocus } = this.config; - switch (d.type) { - case MouseInteractions.Blur: - if ('blur' in target) { - target.blur(); - } - break; - case MouseInteractions.Focus: - if (triggerFocus && target.focus) { - target.focus({ - preventScroll: true, - }); - } + case IncrementalSource.MouseInteraction: { + if (d.id === -1) { break; - case MouseInteractions.Click: - case MouseInteractions.TouchStart: - case MouseInteractions.TouchEnd: - case MouseInteractions.MouseDown: - case MouseInteractions.MouseUp: - if (isSync) { - if (d.type === MouseInteractions.TouchStart) { - this.touchActive = true; - } - else if (d.type === MouseInteractions.TouchEnd) { - this.touchActive = false; - } - if (d.type === MouseInteractions.MouseDown) { - this.lastMouseDownEvent = [target, event]; - } - else if (d.type === MouseInteractions.MouseUp) { - this.lastMouseDownEvent = null; + } + const event = new Event(toLowerCase(MouseInteractions[d.type])); + const target = this.mirror.getNode(d.id); + if (!target) { + return this.debugNodeNotFound(d, d.id); + } + this.emitter.emit(ReplayerEvents.MouseInteraction, { + type: d.type, + target, + }); + const { triggerFocus } = this.config; + switch (d.type) { + case MouseInteractions.Blur: + if ('blur' in target) { + target.blur(); } - this.mousePos = { - x: d.x || 0, - y: d.y || 0, - id: d.id, - debugData: d, - }; - } - else { - if (d.type === MouseInteractions.TouchStart) { - this.tailPositions.length = 0; + break; + case MouseInteractions.Focus: + if (triggerFocus && target.focus) { + target.focus({ + preventScroll: true, + }); } - this.moveAndHover(d.x || 0, d.y || 0, d.id, isSync, d); - if (d.type === MouseInteractions.Click) { - this.mouse.classList.remove('active'); - void this.mouse.offsetWidth; - this.mouse.classList.add('active'); + break; + case MouseInteractions.Click: + case MouseInteractions.TouchStart: + case MouseInteractions.TouchEnd: + case MouseInteractions.MouseDown: + case MouseInteractions.MouseUp: + if (isSync) { + if (d.type === MouseInteractions.TouchStart) { + this.touchActive = true; + } + else if (d.type === MouseInteractions.TouchEnd) { + this.touchActive = false; + } + if (d.type === MouseInteractions.MouseDown) { + this.lastMouseDownEvent = [target, event]; + } + else if (d.type === MouseInteractions.MouseUp) { + this.lastMouseDownEvent = null; + } + this.mousePos = { + x: d.x || 0, + y: d.y || 0, + id: d.id, + debugData: d, + }; } - else if (d.type === MouseInteractions.TouchStart) { - void this.mouse.offsetWidth; - this.mouse.classList.add('touch-active'); + else { + if (d.type === MouseInteractions.TouchStart) { + this.tailPositions.length = 0; + } + this.moveAndHover(d.x || 0, d.y || 0, d.id, isSync, d); + if (d.type === MouseInteractions.Click) { + this.mouse.classList.remove('active'); + void this.mouse.offsetWidth; + this.mouse.classList.add('active'); + } + else if (d.type === MouseInteractions.TouchStart) { + void this.mouse.offsetWidth; + this.mouse.classList.add('touch-active'); + } + else if (d.type === MouseInteractions.TouchEnd) { + this.mouse.classList.remove('touch-active'); + } + else { + target.dispatchEvent(event); + } } - else if (d.type === MouseInteractions.TouchEnd) { - this.mouse.classList.remove('touch-active'); + break; + case MouseInteractions.TouchCancel: + if (isSync) { + this.touchActive = false; } else { - target.dispatchEvent(event); + this.mouse.classList.remove('touch-active'); } - } + break; + default: + target.dispatchEvent(event); + } + break; + } + case IncrementalSource.Scroll: { + if (d.id === -1) { break; - case MouseInteractions.TouchCancel: - if (isSync) { - this.touchActive = false; - } - else { - this.mouse.classList.remove('touch-active'); + } + if (this.usingVirtualDom) { + const target = this.virtualDom.mirror.getNode(d.id); + if (!target) { + return this.debugNodeNotFound(d, d.id); } + target.scrollData = d; break; - default: - target.dispatchEvent(event); - } - break; - } - case IncrementalSource.Scroll: { - if (d.id === -1) { - break; - } - if (this.usingVirtualDom) { - const target = this.virtualDom.mirror.getNode(d.id); - if (!target) { - return this.debugNodeNotFound(d, d.id); } - target.scrollData = d; + this.applyScroll(d, isSync); break; } - this.applyScroll(d, isSync); - break; - } - case IncrementalSource.ViewportResize: - this.emitter.emit(ReplayerEvents.Resize, { - width: d.width, - height: d.height, - }); - break; - case IncrementalSource.Input: { - if (d.id === -1) { + case IncrementalSource.ViewportResize: + this.emitter.emit(ReplayerEvents.Resize, { + width: d.width, + height: d.height, + }); break; - } - if (this.usingVirtualDom) { - const target = this.virtualDom.mirror.getNode(d.id); - if (!target) { - return this.debugNodeNotFound(d, d.id); + case IncrementalSource.Input: { + if (d.id === -1) { + break; } - target.inputData = d; + if (this.usingVirtualDom) { + const target = this.virtualDom.mirror.getNode(d.id); + if (!target) { + return this.debugNodeNotFound(d, d.id); + } + target.inputData = d; + break; + } + this.applyInput(d); break; } - this.applyInput(d); - break; - } - case IncrementalSource.MediaInteraction: { - const target = this.usingVirtualDom - ? this.virtualDom.mirror.getNode(d.id) - : this.mirror.getNode(d.id); - if (!target) { - return this.debugNodeNotFound(d, d.id); - } - const mediaEl = target; - const { events } = this.service.state.context; - this.mediaManager.mediaMutation({ - target: mediaEl, - timeOffset: e.timestamp - events[0].timestamp, - mutation: d, - }); - break; - } - case IncrementalSource.StyleSheetRule: - case IncrementalSource.StyleDeclaration: { - if (this.usingVirtualDom) { - if (d.styleId) - this.constructedStyleMutations.push(d); - else if (d.id) - (_b = this.virtualDom.mirror.getNode(d.id)) === null || _b === void 0 ? void 0 : _b.rules.push(d); - } - else - this.applyStyleSheetMutation(d); - break; - } - case IncrementalSource.CanvasMutation: { - if (!this.config.UNSAFE_replayCanvas) { - return; - } - if (this.usingVirtualDom) { - const target = this.virtualDom.mirror.getNode(d.id); + case IncrementalSource.MediaInteraction: { + const target = this.usingVirtualDom + ? this.virtualDom.mirror.getNode(d.id) + : this.mirror.getNode(d.id); if (!target) { return this.debugNodeNotFound(d, d.id); } - target.canvasMutations.push({ - event: e, + const mediaEl = target; + const { events } = this.service.state.context; + this.mediaManager.mediaMutation({ + target: mediaEl, + timeOffset: e.timestamp - events[0].timestamp, mutation: d, }); + break; } - else { - const target = this.mirror.getNode(d.id); - if (!target) { - return this.debugNodeNotFound(d, d.id); + case IncrementalSource.StyleSheetRule: + case IncrementalSource.StyleDeclaration: { + if (this.usingVirtualDom) { + if (d.styleId) + this.constructedStyleMutations.push(d); + else if (d.id) + (_b = this.virtualDom.mirror.getNode(d.id)) === null || _b === void 0 ? void 0 : _b.rules.push(d); } - void canvasMutation({ - event: e, - mutation: d, - target: target, - imageMap: this.imageMap, - canvasEventMap: this.canvasEventMap, - errorHandler: this.warnCanvasMutationFailed.bind(this), - }); + else + this.applyStyleSheetMutation(d); + break; } - break; - } - case IncrementalSource.Font: { - try { - const fontFace = new FontFace(d.family, d.buffer - ? new Uint8Array(JSON.parse(d.fontSource)) - : d.fontSource, d.descriptors); - (_c = this.iframe.contentDocument) === null || _c === void 0 ? void 0 : _c.fonts.add(fontFace); + case IncrementalSource.CanvasMutation: { + if (!this.config.UNSAFE_replayCanvas) { + return; + } + if (this.usingVirtualDom) { + const target = this.virtualDom.mirror.getNode(d.id); + if (!target) { + return this.debugNodeNotFound(d, d.id); + } + target.canvasMutations.push({ + event: e, + mutation: d, + }); + } + else { + const target = this.mirror.getNode(d.id); + if (!target) { + return this.debugNodeNotFound(d, d.id); + } + void canvasMutation({ + event: e, + mutation: d, + target: target, + imageMap: this.imageMap, + canvasEventMap: this.canvasEventMap, + errorHandler: this.warnCanvasMutationFailed.bind(this), + }); + } + break; } - catch (error) { - this.warn(error); + case IncrementalSource.Font: { + try { + const fontFace = new FontFace(d.family, d.buffer + ? new Uint8Array(JSON.parse(d.fontSource)) + : d.fontSource, d.descriptors); + (_c = this.iframe.contentDocument) === null || _c === void 0 ? void 0 : _c.fonts.add(fontFace); + } + catch (error) { + this.warn(error); + } + break; } - break; - } - case IncrementalSource.Selection: { - if (isSync) { - this.lastSelectionData = d; + case IncrementalSource.Selection: { + if (isSync) { + this.lastSelectionData = d; + break; + } + this.applySelection(d); + break; + } + case IncrementalSource.AdoptedStyleSheet: { + if (this.usingVirtualDom) + this.adoptedStyleSheets.push(d); + else + this.applyAdoptedStyleSheet(d); break; } - this.applySelection(d); - break; - } - case IncrementalSource.AdoptedStyleSheet: { - if (this.usingVirtualDom) - this.adoptedStyleSheets.push(d); - else - this.applyAdoptedStyleSheet(d); - break; } + } catch (error) { + this.config.onError(error); } } applyMutation(d, isSync) { diff --git a/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js b/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js index 38a23aaae8d683fa584329eced277dd8de55d1ff..278e06bc6c8c964581d461405a0f0a4544344fa1 100644 --- a/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js +++ b/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js @@ -1255,54 +1255,19 @@ function parse(css, options = {}) { }); } function selector() { - whitespace(); - while (css[0] == '}') { - error('extra closing bracket'); - css = css.slice(1); - whitespace(); - } - const m = match(/^(("(?:\\"|[^"])*"|'(?:\\'|[^'])*'|[^{])+)/); + const m = match(/^([^{]+)/); if (!m) { return; } - const cleanedInput = m[0] - .trim() + return trim(m[0]) .replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, '') .replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, (m) => { - return m.replace(/,/g, '\u200C'); - }); - return customSplit(cleanedInput).map((s) => s.replace(/\u200C/g, ',').trim()); - } - function customSplit(input) { - const result = []; - let currentSegment = ''; - let depthParentheses = 0; - let depthBrackets = 0; - for (const char of input) { - if (char === '(') { - depthParentheses++; - } - else if (char === ')') { - depthParentheses--; - } - else if (char === '[') { - depthBrackets++; - } - else if (char === ']') { - depthBrackets--; - } - if (char === ',' && depthParentheses === 0 && depthBrackets === 0) { - result.push(currentSegment); - currentSegment = ''; - } - else { - currentSegment += char; - } - } - if (currentSegment) { - result.push(currentSegment); - } - return result; + return m.replace(/,/g, '\u200C'); + }) + .split(/\s*(?![^(]*\)),\s*/) + .map((s) => { + return s.replace(/\u200C/g, ','); + }); } function declaration() { const pos = position();