mirror of
https://github.com/PostHog/posthog.git
synced 2024-11-27 16:26:50 +01:00
813 lines
34 KiB
Diff
813 lines
34 KiB
Diff
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/src/replay/media/index.js b/es/rrweb/packages/rrweb/src/replay/media/index.js
|
|
index 22fee601e786c1d8dfb5c01d2e359c8bcbac7c42..6d80d33030c601fa74f1b95573cb1590c3a0116b 100644
|
|
--- a/es/rrweb/packages/rrweb/src/replay/media/index.js
|
|
+++ b/es/rrweb/packages/rrweb/src/replay/media/index.js
|
|
@@ -21,7 +21,7 @@ class MediaManager {
|
|
this.mediaMap.forEach((mediaState, target) => {
|
|
this.syncTargetWithState(target);
|
|
if (options.pause) {
|
|
- target.pause();
|
|
+ target?.pause();
|
|
}
|
|
});
|
|
}
|
|
@@ -49,7 +49,7 @@ class MediaManager {
|
|
target.currentTime = seekToTime;
|
|
}
|
|
else {
|
|
- target.pause();
|
|
+ target?.pause();
|
|
target.currentTime = mediaState.currentTimeAtLastInteraction;
|
|
}
|
|
}
|
|
@@ -117,7 +117,7 @@ class MediaManager {
|
|
void target.play();
|
|
}
|
|
else {
|
|
- target.pause();
|
|
+ target?.pause();
|
|
}
|
|
}
|
|
catch (error) {
|
|
@@ -141,7 +141,7 @@ class MediaManager {
|
|
isPlaying = target.getAttribute('autoplay') !== null;
|
|
}
|
|
if (isPlaying && playerIsPaused)
|
|
- target.pause();
|
|
+ target?.pause();
|
|
let playbackRate = 1;
|
|
if (typeof mediaAttributes.rr_mediaPlaybackRate === 'number') {
|
|
playbackRate = mediaAttributes.rr_mediaPlaybackRate;
|
|
@@ -180,6 +180,8 @@ class MediaManager {
|
|
this.syncTargetWithState(target);
|
|
}
|
|
mediaMutation({ target, timeOffset, mutation, }) {
|
|
+ if (!['AUDIO', 'VIDEO'].includes(target.nodeName))
|
|
+ return;
|
|
this.mediaMap.set(target, this.getMediaStateFromMutation({
|
|
target,
|
|
timeOffset,
|
|
diff --git a/es/rrweb/packages/rrweb-snapshot/es/css.js b/es/rrweb/packages/rrweb-snapshot/es/css.js
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0a6c5930c017852afd3d7f0170f6eca821619dd3
|
|
--- /dev/null
|
|
+++ b/es/rrweb/packages/rrweb-snapshot/es/css.js
|
|
@@ -0,0 +1,87 @@
|
|
+import postcss from '../../../../../../../../../postcss/lib/postcss.js'
|
|
+
|
|
+const MEDIA_SELECTOR = /(max|min)-device-(width|height)/
|
|
+const MEDIA_SELECTOR_GLOBAL = new RegExp(MEDIA_SELECTOR.source, 'g')
|
|
+
|
|
+export const mutate = (cssText) => {
|
|
+ const ast = postcss([mediaSelectorPlugin, pseudoClassPlugin]).process(cssText)
|
|
+ return ast.css
|
|
+}
|
|
+
|
|
+const mediaSelectorPlugin = {
|
|
+ postcssPlugin: 'postcss-custom-selectors',
|
|
+ prepare() {
|
|
+ return {
|
|
+ postcssPlugin: 'postcss-custom-selectors',
|
|
+ AtRule: function (atrule) {
|
|
+ if (atrule.params.match(MEDIA_SELECTOR_GLOBAL)) {
|
|
+ atrule.params = atrule.params.replace(MEDIA_SELECTOR_GLOBAL, '$1-$2')
|
|
+ }
|
|
+ },
|
|
+ }
|
|
+ },
|
|
+}
|
|
+
|
|
+// Adapted from https://github.com/giuseppeg/postcss-pseudo-classes/blob/master/index.js
|
|
+const pseudoClassPlugin = {
|
|
+ postcssPlugin: 'postcss-hover-classes',
|
|
+ prepare: function () {
|
|
+ const fixed = []
|
|
+ return {
|
|
+ Rule: function (rule) {
|
|
+ if (fixed.indexOf(rule) !== -1) {
|
|
+ return
|
|
+ }
|
|
+ fixed.push(rule)
|
|
+
|
|
+ rule.selectors.forEach(function (selector) {
|
|
+ if (!selector.includes(':')) {
|
|
+ return
|
|
+ }
|
|
+
|
|
+ const selectorParts = selector.replace(/\n/g, ' ').split(' ')
|
|
+ const pseudoedSelectorParts = []
|
|
+
|
|
+ selectorParts.forEach(function (selectorPart) {
|
|
+ const pseudos = selectorPart.match(/::?([^:]+)/g)
|
|
+
|
|
+ if (!pseudos) {
|
|
+ pseudoedSelectorParts.push(selectorPart)
|
|
+ return
|
|
+ }
|
|
+
|
|
+ const baseSelector = selectorPart.substr(0, selectorPart.length - pseudos.join('').length)
|
|
+
|
|
+ const classPseudos = pseudos.map(function (pseudo) {
|
|
+ const pseudoToCheck = pseudo.replace(/\(.*/g, '')
|
|
+ if (pseudoToCheck !== ':hover') {
|
|
+ return pseudo
|
|
+ }
|
|
+
|
|
+ // Ignore pseudo-elements!
|
|
+ if (pseudo.match(/^::/)) {
|
|
+ return pseudo
|
|
+ }
|
|
+
|
|
+ // Kill the colon
|
|
+ pseudo = pseudo.substr(1)
|
|
+
|
|
+ // Replace left and right parens
|
|
+ pseudo = pseudo.replace(/\(/g, '\\(')
|
|
+ pseudo = pseudo.replace(/\)/g, '\\)')
|
|
+
|
|
+ return '.' + '\\:' + pseudo
|
|
+ })
|
|
+
|
|
+ pseudoedSelectorParts.push(baseSelector + classPseudos.join(''))
|
|
+ })
|
|
+
|
|
+ const newSelector = pseudoedSelectorParts.join(' ')
|
|
+ if (newSelector && newSelector !== selector) {
|
|
+ rule.selector += ',\n' + newSelector
|
|
+ }
|
|
+ })
|
|
+ },
|
|
+ }
|
|
+ },
|
|
+}
|
|
diff --git a/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js b/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js
|
|
index 38a23aaae8d683fa584329eced277dd8de55d1ff..8aeee467a3bab9baeefb1a97f2b131bedbd0fa3c 100644
|
|
--- a/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js
|
|
+++ b/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js
|
|
@@ -1,3 +1,5 @@
|
|
+import {mutate} from './css.js';
|
|
+
|
|
var NodeType;
|
|
(function (NodeType) {
|
|
NodeType[NodeType["Document"] = 0] = "Document";
|
|
@@ -1255,54 +1257,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();
|
|
@@ -1662,56 +1629,60 @@ function adaptCssForReplay(cssText, cache) {
|
|
const cachedStyle = cache === null || cache === void 0 ? void 0 : cache.stylesWithHoverClass.get(cssText);
|
|
if (cachedStyle)
|
|
return cachedStyle;
|
|
- const ast = parse(cssText, {
|
|
- silent: true,
|
|
- });
|
|
- if (!ast.stylesheet) {
|
|
- return cssText;
|
|
- }
|
|
- const selectors = [];
|
|
- const medias = [];
|
|
- function getSelectors(rule) {
|
|
- if ('selectors' in rule && rule.selectors) {
|
|
- rule.selectors.forEach((selector) => {
|
|
- if (HOVER_SELECTOR.test(selector)) {
|
|
- selectors.push(selector);
|
|
- }
|
|
- });
|
|
+ let result = cssText;
|
|
+ try {
|
|
+ result = mutate(cssText)
|
|
+ } catch (error) {
|
|
+ const ast = parse(cssText, {
|
|
+ silent: true,
|
|
+ });
|
|
+ if (!ast.stylesheet) {
|
|
+ return cssText;
|
|
+ }
|
|
+ const selectors = [];
|
|
+ const medias = [];
|
|
+ function getSelectors(rule) {
|
|
+ if ('selectors' in rule && rule.selectors) {
|
|
+ rule.selectors.forEach((selector) => {
|
|
+ if (HOVER_SELECTOR.test(selector)) {
|
|
+ selectors.push(selector);
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+ if ('media' in rule && rule.media && MEDIA_SELECTOR.test(rule.media)) {
|
|
+ medias.push(rule.media);
|
|
+ }
|
|
+ if ('rules' in rule && rule.rules) {
|
|
+ rule.rules.forEach(getSelectors);
|
|
+ }
|
|
}
|
|
- if ('media' in rule && rule.media && MEDIA_SELECTOR.test(rule.media)) {
|
|
- medias.push(rule.media);
|
|
+ getSelectors(ast.stylesheet);
|
|
+ if (selectors.length > 0) {
|
|
+ const selectorMatcher = new RegExp(selectors
|
|
+ .filter((selector, index) => selectors.indexOf(selector) === index)
|
|
+ .sort((a, b) => b.length - a.length)
|
|
+ .map((selector) => {
|
|
+ return escapeRegExp(selector);
|
|
+ })
|
|
+ .join('|'), 'g');
|
|
+ result = result.replace(selectorMatcher, (selector) => {
|
|
+ const newSelector = selector.replace(HOVER_SELECTOR_GLOBAL, '$1.\\:hover');
|
|
+ return `${selector}, ${newSelector}`;
|
|
+ });
|
|
}
|
|
- if ('rules' in rule && rule.rules) {
|
|
- rule.rules.forEach(getSelectors);
|
|
+ if (medias.length > 0) {
|
|
+ const mediaMatcher = new RegExp(medias
|
|
+ .filter((media, index) => medias.indexOf(media) === index)
|
|
+ .sort((a, b) => b.length - a.length)
|
|
+ .map((media) => {
|
|
+ return escapeRegExp(media);
|
|
+ })
|
|
+ .join('|'), 'g');
|
|
+ result = result.replace(mediaMatcher, (media) => {
|
|
+ return media.replace(MEDIA_SELECTOR_GLOBAL, '$1-$2');
|
|
+ });
|
|
}
|
|
}
|
|
- getSelectors(ast.stylesheet);
|
|
- let result = cssText;
|
|
- if (selectors.length > 0) {
|
|
- const selectorMatcher = new RegExp(selectors
|
|
- .filter((selector, index) => selectors.indexOf(selector) === index)
|
|
- .sort((a, b) => b.length - a.length)
|
|
- .map((selector) => {
|
|
- return escapeRegExp(selector);
|
|
- })
|
|
- .join('|'), 'g');
|
|
- result = result.replace(selectorMatcher, (selector) => {
|
|
- const newSelector = selector.replace(HOVER_SELECTOR_GLOBAL, '$1.\\:hover');
|
|
- return `${selector}, ${newSelector}`;
|
|
- });
|
|
- }
|
|
- if (medias.length > 0) {
|
|
- const mediaMatcher = new RegExp(medias
|
|
- .filter((media, index) => medias.indexOf(media) === index)
|
|
- .sort((a, b) => b.length - a.length)
|
|
- .map((media) => {
|
|
- return escapeRegExp(media);
|
|
- })
|
|
- .join('|'), 'g');
|
|
- result = result.replace(mediaMatcher, (media) => {
|
|
- return media.replace(MEDIA_SELECTOR_GLOBAL, '$1-$2');
|
|
- });
|
|
- }
|
|
cache === null || cache === void 0 ? void 0 : cache.stylesWithHoverClass.set(cssText, result);
|
|
return result;
|
|
}
|