@@ -310,24 +310,29 @@ export function needMaskingText(
310310 node : Node ,
311311 maskTextClass : string | RegExp ,
312312 maskTextSelector : string | null ,
313+ checkAncestors : boolean ,
313314) : boolean {
314315 try {
315316 const el : HTMLElement | null =
316317 node . nodeType === node . ELEMENT_NODE
317318 ? ( node as HTMLElement )
318319 : node . parentElement ;
319320 if ( el === null ) return false ;
320-
321321 if ( typeof maskTextClass === 'string' ) {
322- if ( el . classList . contains ( maskTextClass ) ) return true ;
323- if ( el . closest ( `.${ maskTextClass } ` ) ) return true ;
322+ if ( checkAncestors ) {
323+ if ( el . closest ( `.${ maskTextClass } ` ) ) return true ;
324+ } else {
325+ if ( el . classList . contains ( maskTextClass ) ) return true ;
326+ }
324327 } else {
325- if ( classMatchesRegex ( el , maskTextClass , true ) ) return true ;
328+ if ( classMatchesRegex ( el , maskTextClass , checkAncestors ) ) return true ;
326329 }
327-
328330 if ( maskTextSelector ) {
329- if ( el . matches ( maskTextSelector ) ) return true ;
330- if ( el . closest ( maskTextSelector ) ) return true ;
331+ if ( checkAncestors ) {
332+ if ( el . closest ( maskTextSelector ) ) return true ;
333+ } else {
334+ if ( el . matches ( maskTextSelector ) ) return true ;
335+ }
331336 }
332337 } catch ( e ) {
333338 //
@@ -426,8 +431,7 @@ function serializeNode(
426431 mirror : Mirror ;
427432 blockClass : string | RegExp ;
428433 blockSelector : string | null ;
429- maskTextClass : string | RegExp ;
430- maskTextSelector : string | null ;
434+ needsMask : boolean | undefined ;
431435 inlineStylesheet : boolean ;
432436 maskInputOptions : MaskInputOptions ;
433437 maskTextFn : MaskTextFn | undefined ;
@@ -447,8 +451,7 @@ function serializeNode(
447451 mirror,
448452 blockClass,
449453 blockSelector,
450- maskTextClass,
451- maskTextSelector,
454+ needsMask,
452455 inlineStylesheet,
453456 maskInputOptions = { } ,
454457 maskTextFn,
@@ -500,8 +503,7 @@ function serializeNode(
500503 } ) ;
501504 case n . TEXT_NODE :
502505 return serializeTextNode ( n as Text , {
503- maskTextClass,
504- maskTextSelector,
506+ needsMask,
505507 maskTextFn,
506508 rootId,
507509 } ) ;
@@ -531,13 +533,12 @@ function getRootId(doc: Document, mirror: Mirror): number | undefined {
531533function serializeTextNode (
532534 n : Text ,
533535 options : {
534- maskTextClass : string | RegExp ;
535- maskTextSelector : string | null ;
536+ needsMask : boolean | undefined ;
536537 maskTextFn : MaskTextFn | undefined ;
537538 rootId : number | undefined ;
538539 } ,
539540) : serializedNode {
540- const { maskTextClass , maskTextSelector , maskTextFn, rootId } = options ;
541+ const { needsMask , maskTextFn, rootId } = options ;
541542 // The parent node may not be a html element which has a tagName attribute.
542543 // So just let it be undefined which is ok in this use case.
543544 const parentTagName = n . parentNode && ( n . parentNode as HTMLElement ) . tagName ;
@@ -568,12 +569,7 @@ function serializeTextNode(
568569 if ( isScript ) {
569570 textContent = 'SCRIPT_PLACEHOLDER' ;
570571 }
571- if (
572- ! isStyle &&
573- ! isScript &&
574- textContent &&
575- needMaskingText ( n , maskTextClass , maskTextSelector )
576- ) {
572+ if ( ! isStyle && ! isScript && textContent && needsMask ) {
577573 textContent = maskTextFn
578574 ? maskTextFn ( textContent , n . parentElement )
579575 : textContent . replace ( / [ \S ] / g, '*' ) ;
@@ -935,6 +931,7 @@ export function serializeNodeWithId(
935931 inlineStylesheet : boolean ;
936932 newlyAddedElement ?: boolean ;
937933 maskInputOptions ?: MaskInputOptions ;
934+ needsMask ?: boolean ;
938935 maskTextFn : MaskTextFn | undefined ;
939936 maskInputFn : MaskInputFn | undefined ;
940937 slimDOMOptions : SlimDOMOptions ;
@@ -980,14 +977,29 @@ export function serializeNodeWithId(
980977 keepIframeSrcFn = ( ) => false ,
981978 newlyAddedElement = false ,
982979 } = options ;
980+ let { needsMask } = options ;
983981 let { preserveWhiteSpace = true } = options ;
982+
983+ if (
984+ ! needsMask &&
985+ n . childNodes // we can avoid the check on leaf elements, as masking is applied to child text nodes only
986+ ) {
987+ // perf: if needsMask = true, children won't also need to check
988+ const checkAncestors = needsMask === undefined ; // if false, we've already checked ancestors
989+ needsMask = needMaskingText (
990+ n as Element ,
991+ maskTextClass ,
992+ maskTextSelector ,
993+ checkAncestors ,
994+ ) ;
995+ }
996+
984997 const _serializedNode = serializeNode ( n , {
985998 doc,
986999 mirror,
9871000 blockClass,
9881001 blockSelector,
989- maskTextClass,
990- maskTextSelector,
1002+ needsMask,
9911003 inlineStylesheet,
9921004 maskInputOptions,
9931005 maskTextFn,
@@ -1058,6 +1070,7 @@ export function serializeNodeWithId(
10581070 mirror,
10591071 blockClass,
10601072 blockSelector,
1073+ needsMask,
10611074 maskTextClass,
10621075 maskTextSelector,
10631076 skipChild,
@@ -1118,6 +1131,7 @@ export function serializeNodeWithId(
11181131 mirror,
11191132 blockClass,
11201133 blockSelector,
1134+ needsMask,
11211135 maskTextClass,
11221136 maskTextSelector,
11231137 skipChild : false ,
@@ -1165,6 +1179,7 @@ export function serializeNodeWithId(
11651179 mirror,
11661180 blockClass,
11671181 blockSelector,
1182+ needsMask,
11681183 maskTextClass,
11691184 maskTextSelector,
11701185 skipChild : false ,
0 commit comments