part of rrweb #80, support configure mask input types

This commit is contained in:
Yanzhen Yu
2020-07-18 13:31:32 +08:00
parent 63c3bd744e
commit e4593ff76d
2 changed files with 56 additions and 18 deletions

View File

@@ -5,10 +5,11 @@ import {
attributes, attributes,
INode, INode,
idNodeMap, idNodeMap,
MaskInputOptions,
} from './types'; } from './types';
let _id = 1; let _id = 1;
const symbolAndNumberRegex = RegExp('[^a-z1-6\-]'); const symbolAndNumberRegex = RegExp('[^a-z1-6-]');
function genId(): number { function genId(): number {
return _id++; return _id++;
@@ -32,9 +33,9 @@ function getCssRulesString(s: CSSStyleSheet): string | null {
const rules = s.rules || s.cssRules; const rules = s.rules || s.cssRules;
return rules return rules
? Array.from(rules).reduce( ? Array.from(rules).reduce(
(prev, cur) => prev + getCssRuleString(cur), (prev, cur) => prev + getCssRuleString(cur),
'', '',
) )
: null; : null;
} catch (error) { } catch (error) {
return null; return null;
@@ -54,10 +55,7 @@ function isCSSImportRule(rule: CSSRule): rule is CSSImportRule {
function extractOrigin(url: string): string { function extractOrigin(url: string): string {
let origin; let origin;
if (url.indexOf('//') > -1) { if (url.indexOf('//') > -1) {
origin = url origin = url.split('/').slice(0, 3).join('/');
.split('/')
.slice(0, 3)
.join('/');
} else { } else {
origin = url.split('/')[0]; origin = url.split('/')[0];
} }
@@ -114,7 +112,7 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
// srcset attributes is defined as such: // srcset attributes is defined as such:
// srcset = "url size,url1 size1" // srcset = "url size,url1 size1"
const resultingSrcsetString = srcsetValues const resultingSrcsetString = srcsetValues
.map(srcItem => { .map((srcItem) => {
// removing all but middle spaces // removing all but middle spaces
const trimmedSrcItem = srcItem.trimLeft().trimRight(); const trimmedSrcItem = srcItem.trimLeft().trimRight();
const urlAndSize = trimmedSrcItem.split(' '); const urlAndSize = trimmedSrcItem.split(' ');
@@ -168,7 +166,7 @@ function serializeNode(
doc: Document, doc: Document,
blockClass: string | RegExp, blockClass: string | RegExp,
inlineStylesheet: boolean, inlineStylesheet: boolean,
maskAllInputs: boolean, maskInputOptions: MaskInputOptions = {},
): serializedNode | false { ): serializedNode | false {
switch (n.nodeType) { switch (n.nodeType) {
case n.DOCUMENT_NODE: case n.DOCUMENT_NODE:
@@ -188,7 +186,7 @@ function serializeNode(
if (typeof blockClass === 'string') { if (typeof blockClass === 'string') {
needBlock = (n as HTMLElement).classList.contains(blockClass); needBlock = (n as HTMLElement).classList.contains(blockClass);
} else { } else {
(n as HTMLElement).classList.forEach(className => { (n as HTMLElement).classList.forEach((className) => {
if (blockClass.test(className)) { if (blockClass.test(className)) {
needBlock = true; needBlock = true;
} }
@@ -201,7 +199,7 @@ function serializeNode(
} }
// remote css // remote css
if (tagName === 'link' && inlineStylesheet) { if (tagName === 'link' && inlineStylesheet) {
const stylesheet = Array.from(doc.styleSheets).find(s => { const stylesheet = Array.from(doc.styleSheets).find((s) => {
return s.href === (n as HTMLLinkElement).href; return s.href === (n as HTMLLinkElement).href;
}); });
const cssText = getCssRulesString(stylesheet as CSSStyleSheet); const cssText = getCssRulesString(stylesheet as CSSStyleSheet);
@@ -246,7 +244,11 @@ function serializeNode(
attributes.type !== 'button' && attributes.type !== 'button' &&
value value
) { ) {
attributes.value = maskAllInputs ? '*'.repeat(value.length) : value; attributes.value = maskInputOptions[
attributes.type as keyof MaskInputOptions
]
? '*'.repeat(value.length)
: value;
} else if ((n as HTMLInputElement).checked) { } else if ((n as HTMLInputElement).checked) {
attributes.checked = (n as HTMLInputElement).checked; attributes.checked = (n as HTMLInputElement).checked;
} }
@@ -320,14 +322,14 @@ export function serializeNodeWithId(
blockClass: string | RegExp, blockClass: string | RegExp,
skipChild = false, skipChild = false,
inlineStylesheet = true, inlineStylesheet = true,
maskAllInputs = false, maskInputOptions?: MaskInputOptions,
): serializedNodeWithId | null { ): serializedNodeWithId | null {
const _serializedNode = serializeNode( const _serializedNode = serializeNode(
n, n,
doc, doc,
blockClass, blockClass,
inlineStylesheet, inlineStylesheet,
maskAllInputs, maskInputOptions,
); );
if (!_serializedNode) { if (!_serializedNode) {
// TODO: dev only // TODO: dev only
@@ -363,7 +365,7 @@ export function serializeNodeWithId(
blockClass, blockClass,
skipChild, skipChild,
inlineStylesheet, inlineStylesheet,
maskAllInputs, maskInputOptions,
); );
if (serializedChildNode) { if (serializedChildNode) {
serializedNode.childNodes.push(serializedChildNode); serializedNode.childNodes.push(serializedChildNode);
@@ -377,9 +379,29 @@ function snapshot(
n: Document, n: Document,
blockClass: string | RegExp = 'rr-block', blockClass: string | RegExp = 'rr-block',
inlineStylesheet = true, inlineStylesheet = true,
maskAllInputs = false, maskAllInputsOrOptions: boolean | MaskInputOptions,
): [serializedNodeWithId | null, idNodeMap] { ): [serializedNodeWithId | null, idNodeMap] {
const idNodeMap: idNodeMap = {}; const idNodeMap: idNodeMap = {};
const maskInputOptions: MaskInputOptions =
maskAllInputsOrOptions === true
? {
color: true,
date: true,
'datetime-local': true,
email: true,
month: true,
number: true,
range: true,
search: true,
tel: true,
text: true,
time: true,
url: true,
week: true,
}
: maskAllInputsOrOptions === false
? {}
: maskAllInputsOrOptions;
return [ return [
serializeNodeWithId( serializeNodeWithId(
n, n,
@@ -388,7 +410,7 @@ function snapshot(
blockClass, blockClass,
false, false,
inlineStylesheet, inlineStylesheet,
maskAllInputs, maskInputOptions,
), ),
idNodeMap, idNodeMap,
]; ];

View File

@@ -68,3 +68,19 @@ export interface INode extends Node {
export type idNodeMap = { export type idNodeMap = {
[key: number]: INode; [key: number]: INode;
}; };
export type MaskInputOptions = Partial<{
color: boolean;
date: boolean;
'datetime-local': boolean;
email: boolean;
month: boolean;
number: boolean;
range: boolean;
search: boolean;
tel: boolean;
text: boolean;
time: boolean;
url: boolean;
week: boolean;
}>;