From fc3e9d95227a6e52c393f88ba58f587c1aadcfa2 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Tue, 10 Jan 2023 20:56:10 -0500 Subject: [PATCH 1/2] feat: Add `unblockSelector` and `ignoreSelector` Also update README --- guide.md | 5 +++++ packages/rrweb-snapshot/src/snapshot.ts | 16 ++++++++++++++++ packages/rrweb-snapshot/typings/snapshot.d.ts | 4 +++- packages/rrweb/src/record/index.ts | 6 ++++++ packages/rrweb/src/record/mutation.ts | 3 +++ packages/rrweb/src/record/observer.ts | 3 ++- packages/rrweb/src/types.ts | 5 +++++ packages/rrweb/typings/record/mutation.d.ts | 1 + packages/rrweb/typings/types.d.ts | 6 +++++- 9 files changed, 46 insertions(+), 3 deletions(-) diff --git a/guide.md b/guide.md index b95b4c2da3..5e59fe9c4d 100644 --- a/guide.md +++ b/guide.md @@ -142,11 +142,16 @@ The parameter of `rrweb.record` accepts the following options. | checkoutEveryNms | - | take a full snapshot after every N ms
refer to the [checkout](#checkout) chapter | | blockClass | 'rr-block' | Use a string or RegExp to configure which elements should be blocked, refer to the [privacy](#privacy) chapter | | blockSelector | null | Use a string to configure which selector should be blocked, refer to the [privacy](#privacy) chapter | +| unblockSelector | null | Use a string to configure which selector should be unblocked, refer to the [privacy](#privacy) chapter | | ignoreClass | 'rr-ignore' | Use a string or RegExp to configure which elements should be ignored, refer to the [privacy](#privacy) chapter | +| ignoreClass | null | Use a string to configure which selector should be ignored, refer to the [privacy](#privacy) chapter | | maskTextClass | 'rr-mask' | Use a string or RegExp to configure which elements should be masked, refer to the [privacy](#privacy) chapter | | maskTextSelector | null | Use a string to configure which selector should be masked, refer to the [privacy](#privacy) chapter | +| unmaskTextSelector | null | Use a string to configure which selector should be unmasked, refer to the [privacy](#privacy) chapter | | maskAllInputs | false | mask all input content as \* | | maskInputOptions | { password: true } | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L77-L95) | +| maskInputSelector | null | Use a string to configure which selector should be masked, refer to the [privacy](#privacy) chapter | +| unmaskInputSelector | null | Use a string to configure which selector should be unmasked, refer to the [privacy](#privacy) chapter | | maskInputFn | - | customize mask input content recording logic | | maskTextFn | - | customize mask text content recording logic | | slimDOMOptions | {} | remove unnecessary parts of the DOM
refer to the [list](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L97-L108) | diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 7a7602284c..10948ed4f3 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -263,7 +263,12 @@ export function _isBlockedElement( element: HTMLElement, blockClass: string | RegExp, blockSelector: string | null, + unblockSelector: string | null, ): boolean { + if (unblockSelector && element.matches(unblockSelector)) { + return false; + } + if (typeof blockClass === 'string') { if (element.classList.contains(blockClass)) { return true; @@ -387,6 +392,7 @@ function serializeNode( doc: Document; blockClass: string | RegExp; blockSelector: string | null; + unblockSelector: string | null; maskTextClass: string | RegExp; maskTextSelector: string | null; unmaskTextSelector: string | null; @@ -406,6 +412,7 @@ function serializeNode( doc, blockClass, blockSelector, + unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, @@ -455,6 +462,7 @@ function serializeNode( n as HTMLElement, blockClass, blockSelector, + unblockSelector ); const tagName = getValidTagName(n as HTMLElement); let attributes: attributes = {}; @@ -809,6 +817,7 @@ export function serializeNodeWithId( map: idNodeMap; blockClass: string | RegExp; blockSelector: string | null; + unblockSelector: string | null; maskTextClass: string | RegExp; maskTextSelector: string | null; unmaskTextSelector: string | null; @@ -835,6 +844,7 @@ export function serializeNodeWithId( map, blockClass, blockSelector, + unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, @@ -859,6 +869,7 @@ export function serializeNodeWithId( doc, blockClass, blockSelector, + unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, @@ -928,6 +939,7 @@ export function serializeNodeWithId( map, blockClass, blockSelector, + unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, @@ -984,6 +996,7 @@ export function serializeNodeWithId( map, blockClass, blockSelector, + unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, @@ -1022,6 +1035,7 @@ function snapshot( options?: { blockClass?: string | RegExp; blockSelector?: string | null; + unblockSelector?: string | null; maskTextClass?: string | RegExp; maskTextSelector?: string | null; unmaskTextSelector?: string | null; @@ -1045,6 +1059,7 @@ function snapshot( const { blockClass = 'rr-block', blockSelector = null, + unblockSelector = null, maskTextClass = 'rr-mask', maskTextSelector = null, unmaskTextSelector = null, @@ -1114,6 +1129,7 @@ function snapshot( map: idNodeMap, blockClass, blockSelector, + unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, diff --git a/packages/rrweb-snapshot/typings/snapshot.d.ts b/packages/rrweb-snapshot/typings/snapshot.d.ts index 160f4b795f..a49fa7db40 100644 --- a/packages/rrweb-snapshot/typings/snapshot.d.ts +++ b/packages/rrweb-snapshot/typings/snapshot.d.ts @@ -3,13 +3,14 @@ export declare const IGNORED_NODE = -2; export declare function absoluteToStylesheet(cssText: string | null, href: string): string; export declare function absoluteToDoc(doc: Document, attributeValue: string): string; export declare function transformAttribute(doc: Document, tagName: string, name: string, value: string): string; -export declare function _isBlockedElement(element: HTMLElement, blockClass: string | RegExp, blockSelector: string | null): boolean; +export declare function _isBlockedElement(element: HTMLElement, blockClass: string | RegExp, blockSelector: string | null, unblockSelector: string | null): boolean; export declare function needMaskingText(node: Node | null, maskTextClass: string | RegExp, maskTextSelector: string | null, unmaskTextSelector: string | null): boolean; export declare function serializeNodeWithId(n: Node | INode, options: { doc: Document; map: idNodeMap; blockClass: string | RegExp; blockSelector: string | null; + unblockSelector: string | null; maskTextClass: string | RegExp; maskTextSelector: string | null; unmaskTextSelector: string | null; @@ -33,6 +34,7 @@ export declare function serializeNodeWithId(n: Node | INode, options: { declare function snapshot(n: Document, options?: { blockClass?: string | RegExp; blockSelector?: string | null; + unblockSelector?: string | null; maskTextClass?: string | RegExp; maskTextSelector?: string | null; unmaskTextSelector?: string | null; diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 4505cac452..210b0c89cd 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -45,7 +45,9 @@ function record( checkoutEveryNth, blockClass = 'rr-block', blockSelector = null, + unblockSelector = null, ignoreClass = 'rr-ignore', + ignoreSelector =null, maskTextClass = 'rr-mask', maskTextSelector = null, maskInputSelector = null, @@ -225,6 +227,7 @@ function record( bypassOptions: { blockClass, blockSelector, + unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, @@ -261,6 +264,7 @@ function record( const [node, idNodeMap] = snapshot(document, { blockClass, blockSelector, + unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, @@ -422,6 +426,7 @@ function record( ), blockClass, ignoreClass, + ignoreSelector, maskTextClass, maskTextSelector, unmaskTextSelector, @@ -438,6 +443,7 @@ function record( maskInputFn, maskTextFn, blockSelector, + unblockSelector, slimDOMOptions, mirror, iframeManager, diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 244ffd4e00..bcfea6ca6e 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -159,6 +159,7 @@ export default class MutationBuffer { private mutationCb: observerParam['mutationCb']; private blockClass: observerParam['blockClass']; private blockSelector: observerParam['blockSelector']; + private unblockSelector: observerParam['unblockSelector']; private maskTextClass: observerParam['maskTextClass']; private maskTextSelector: observerParam['maskTextSelector']; private unmaskTextSelector: observerParam['unmaskTextSelector']; @@ -182,6 +183,7 @@ export default class MutationBuffer { 'mutationCb', 'blockClass', 'blockSelector', + 'unblockSelector', 'maskTextClass', 'maskTextSelector', 'unmaskTextSelector', @@ -294,6 +296,7 @@ export default class MutationBuffer { map: this.mirror.map, blockClass: this.blockClass, blockSelector: this.blockSelector, + unblockSelector: this.unblockSelector, maskTextClass: this.maskTextClass, maskTextSelector: this.maskTextSelector, unmaskTextSelector: this.unmaskTextSelector, diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 69606c065e..ad2e0b24e2 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -326,6 +326,7 @@ function initInputObserver({ mirror, blockClass, ignoreClass, + ignoreSelector, maskInputSelector, unmaskInputSelector, maskInputOptions, @@ -351,7 +352,7 @@ function initInputObserver({ return; } const type: string | undefined = (target as HTMLInputElement).type; - if ((target as HTMLElement).classList.contains(ignoreClass)) { + if ((target as HTMLElement).classList.contains(ignoreClass) || (ignoreSelector && (target as HTMLElement).matches(ignoreSelector))) { return; } let text = (target as HTMLInputElement).value; diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index 9982c44958..43cec3acff 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -216,7 +216,9 @@ export type recordOptions = { checkoutEveryNms?: number; blockClass?: blockClass; blockSelector?: string; + unblockSelector?: string; ignoreClass?: string; + ignoreSelector?: string; maskTextClass?: maskTextClass; maskTextSelector?: string; maskAllInputs?: boolean; @@ -251,7 +253,9 @@ export type observerParam = { mediaInteractionCb: mediaInteractionCallback; blockClass: blockClass; blockSelector: string | null; + unblockSelector: string | null; ignoreClass: string; + ignoreSelector: string | null; maskTextClass: maskTextClass; maskTextSelector: string | null; unmaskTextSelector: string | null; @@ -288,6 +292,7 @@ export type MutationBufferParam = Pick< | 'mutationCb' | 'blockClass' | 'blockSelector' + | 'unblockSelector' | 'maskTextClass' | 'maskTextSelector' | 'unmaskTextSelector' diff --git a/packages/rrweb/typings/record/mutation.d.ts b/packages/rrweb/typings/record/mutation.d.ts index 485cba0e4b..444ea07c71 100644 --- a/packages/rrweb/typings/record/mutation.d.ts +++ b/packages/rrweb/typings/record/mutation.d.ts @@ -13,6 +13,7 @@ export default class MutationBuffer { private mutationCb; private blockClass; private blockSelector; + private unblockSelector; private maskTextClass; private maskTextSelector; private unmaskTextSelector; diff --git a/packages/rrweb/typings/types.d.ts b/packages/rrweb/typings/types.d.ts index a779ae3f81..bf529fa294 100644 --- a/packages/rrweb/typings/types.d.ts +++ b/packages/rrweb/typings/types.d.ts @@ -137,7 +137,9 @@ export declare type recordOptions = { checkoutEveryNms?: number; blockClass?: blockClass; blockSelector?: string; + unblockSelector?: string; ignoreClass?: string; + ignoreSelector?: string; maskTextClass?: maskTextClass; maskTextSelector?: string; maskAllInputs?: boolean; @@ -170,7 +172,9 @@ export declare type observerParam = { mediaInteractionCb: mediaInteractionCallback; blockClass: blockClass; blockSelector: string | null; + unblockSelector: string | null; ignoreClass: string; + ignoreSelector: string | null; maskTextClass: maskTextClass; maskTextSelector: string | null; unmaskTextSelector: string | null; @@ -201,7 +205,7 @@ export declare type observerParam = { options: unknown; }>; }; -export declare type MutationBufferParam = Pick; +export declare type MutationBufferParam = Pick; export declare type hooksParam = { mutation?: mutationCallBack; mousemove?: mousemoveCallBack; From 648a462c861ff73e8ef7f89e31358f64ca0b137e Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 11 Jan 2023 10:22:22 -0500 Subject: [PATCH 2/2] update