Skip to content

Commit

Permalink
Enable external pausing of mutation buffer emissions
Browse files Browse the repository at this point in the history
 - no automatic pausing based on e.g. pageVisibility yet, assuming such a thing is desirable
   https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
 - user code has to call new API method `freezePage` e.g. when page is hidden or after a timeout
 - automatically unpauses when the next user initiated event occurs
   (am assuming everything that isn't a mutation event counts as 'user initiated'
   either way think this is the correct thing to do until I see a counterexample
   of an event that shouldn't cause the mutations to be unbufferred)
  • Loading branch information
eoghanmurray committed May 28, 2020
1 parent cfb1f88 commit e3b7425
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 14 deletions.
19 changes: 18 additions & 1 deletion src/record/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { snapshot } from 'rrweb-snapshot';
import initObservers from './observer';
import { initObservers, mutationBuffer } from './observer';
import {
mirror,
on,
Expand Down Expand Up @@ -50,6 +50,19 @@ function record<T = eventWithTime>(
let lastFullSnapshotEvent: eventWithTime;
let incrementalSnapshotCount = 0;
wrappedEmit = (e: eventWithTime, isCheckout?: boolean) => {
if (
mutationBuffer.paused &&
!(
e.type == EventType.IncrementalSnapshot &&
e.data.source == IncrementalSource.Mutation
)
) {
// we've got a user initiated event so first we need to apply
// all DOM changes that have been buffering during paused state
mutationBuffer.emit();
mutationBuffer.paused = false;
}

emit(((packFn ? packFn(e) : e) as unknown) as T, isCheckout);
if (e.type === EventType.FullSnapshot) {
lastFullSnapshotEvent = e;
Expand Down Expand Up @@ -271,4 +284,8 @@ record.addCustomEvent = <T>(tag: string, payload: T) => {
);
};

record.freezePage = () => {
mutationBuffer.paused = true;
};

export default record;
8 changes: 6 additions & 2 deletions src/record/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ function isINode(n: Node | INode): n is INode {
* controls behaviour of a MutationObserver
*/
export default class MutationBuffer {
public paused: boolean = false;

private texts: textCursor[] = [];
private attributes: attributeCursor[] = [];
private removes: removedNodeMutation[] = [];
Expand Down Expand Up @@ -52,7 +54,7 @@ export default class MutationBuffer {
private inlineStylesheet: boolean;
private maskAllInputs: boolean;

constructor(
public init(
cb: mutationCallBack,
blockClass: blockClass,
inlineStylesheet: boolean,
Expand Down Expand Up @@ -127,7 +129,9 @@ export default class MutationBuffer {
pushAdd(addQueue.shift()!);
}

this.emit();
if (!this.paused) {
this.emit();
}
};

private processMutation = (m: mutationRecord) => {
Expand Down
11 changes: 4 additions & 7 deletions src/record/observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,16 @@ import {
} from '../types';
import MutationBuffer from './mutation';

export const mutationBuffer = new MutationBuffer();

function initMutationObserver(
cb: mutationCallBack,
blockClass: blockClass,
inlineStylesheet: boolean,
maskAllInputs: boolean,
): MutationObserver {
// see mutation.ts for details
const mutationBuffer = new MutationBuffer(
cb,
blockClass,
inlineStylesheet,
maskAllInputs,
);
mutationBuffer.init(cb, blockClass, inlineStylesheet, maskAllInputs);
const observer = new MutationObserver(mutationBuffer.processMutations);
observer.observe(document, {
attributes: true,
Expand Down Expand Up @@ -405,7 +402,7 @@ function mergeHooks(o: observerParam, hooks: hooksParam) {
};
}

export default function initObservers(
export function initObservers(
o: observerParam,
hooks: hooksParam = {},
): listenerHandler {
Expand Down
1 change: 1 addition & 0 deletions typings/record/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ import { eventWithTime, recordOptions, listenerHandler } from '../types';
declare function record<T = eventWithTime>(options?: recordOptions<T>): listenerHandler | undefined;
declare namespace record {
var addCustomEvent: <T>(tag: string, payload: T) => void;
var freezePage: () => void;
}
export default record;
7 changes: 4 additions & 3 deletions typings/record/mutation.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { mutationRecord, blockClass, mutationCallBack } from '../types';
export default class MutationBuffer {
paused: boolean;
private texts;
private attributes;
private removes;
Expand All @@ -12,9 +13,9 @@ export default class MutationBuffer {
private blockClass;
private inlineStylesheet;
private maskAllInputs;
constructor(cb: mutationCallBack, blockClass: blockClass, inlineStylesheet: boolean, maskAllInputs: boolean);
processMutations(mutations: mutationRecord[]): void;
init(cb: mutationCallBack, blockClass: blockClass, inlineStylesheet: boolean, maskAllInputs: boolean): void;
processMutations: (mutations: mutationRecord[]) => void;
private processMutation;
private genAdds;
emit(): void;
emit: () => void;
}
4 changes: 3 additions & 1 deletion typings/record/observer.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import { observerParam, listenerHandler, hooksParam } from '../types';
export default function initObservers(o: observerParam, hooks?: hooksParam): listenerHandler;
import MutationBuffer from './mutation';
export declare const mutationBuffer: MutationBuffer;
export declare function initObservers(o: observerParam, hooks?: hooksParam): listenerHandler;

0 comments on commit e3b7425

Please sign in to comment.