@@ -24,29 +24,44 @@ import { registerScriptlet } from './base.js';
2424import { safeSelf } from './safe-self.js' ;
2525
2626/**
27- * @scriptlet prevent-innerHTML
27+ * @scriptlet freeze-element-property
2828 *
2929 * @description
30- * Conditionally prevent assignment to `innerHTML` property.
30+ * Conditionally prevent assignment to an element property.
31+ *
32+ * @param property
33+ * The property name to freeze.
3134 *
3235 * @param [selector]
3336 * Optional. The element must matches `selector` for the prevention to take
3437 * place.
3538 *
3639 * @param [pattern]
37- * Optional. A pattern to match against the assigned value. The pattern can be
38- * a plain string, or a regex. Prepend with `!` to reverse the match condition.
40+ * Optional. A pattern to match against the stringified assigned value. The
41+ * pattern can be a plain string, or a regex. Prepend with `!` to reverse the
42+ * match condition.
3943 *
4044 * */
4145
42- export function preventInnerHTML (
46+ function freezeElementProperty (
47+ property = '' ,
4348 selector = '' ,
4449 pattern = ''
4550) {
4651 const safe = safeSelf ( ) ;
47- const logPrefix = safe . makeLogPrefix ( 'prevent-innerHTML' , selector , pattern ) ;
52+ const logPrefix = safe . makeLogPrefix ( 'freeze-element-property' , property , selector , pattern ) ;
4853 const matcher = safe . initPattern ( pattern , { canNegate : true } ) ;
49- const current = safe . Object_getOwnPropertyDescriptor ( Element . prototype , 'innerHTML' ) ;
54+ const owner = ( ( ) => {
55+ if ( Object . hasOwn ( Element . prototype , property ) ) {
56+ return Element . prototype ;
57+ }
58+ if ( Object . hasOwn ( HTMLElement . prototype , property ) ) {
59+ return HTMLElement . prototype ;
60+ }
61+ return null ;
62+ } ) ( ) ;
63+ if ( owner === null ) { return ; }
64+ const current = safe . Object_getOwnPropertyDescriptor ( owner , property ) ;
5065 if ( current === undefined ) { return ; }
5166 const shouldPreventSet = ( elem , a ) => {
5267 if ( selector !== '' ) {
@@ -55,15 +70,15 @@ export function preventInnerHTML(
5570 }
5671 return safe . testPattern ( matcher , `${ a } ` ) ;
5772 } ;
58- Object . defineProperty ( Element . prototype , 'innerHTML' , {
73+ Object . defineProperty ( owner , property , {
5974 get : function ( ) {
6075 return current . get
6176 ? current . get . call ( this )
6277 : current . value ;
6378 } ,
6479 set : function ( a ) {
6580 if ( shouldPreventSet ( this , a ) ) {
66- safe . uboLog ( logPrefix , 'Prevented ' ) ;
81+ safe . uboLog ( logPrefix , 'Assignment prevented ' ) ;
6782 } else if ( current . set ) {
6883 current . set . call ( this , a ) ;
6984 }
@@ -74,18 +89,18 @@ export function preventInnerHTML(
7489 } ,
7590 } ) ;
7691}
77- registerScriptlet ( preventInnerHTML , {
78- name : 'prevent-innerHTML .js' ,
92+ registerScriptlet ( freezeElementProperty , {
93+ name : 'freeze-element-property .js' ,
7994 dependencies : [
8095 safeSelf ,
8196 ] ,
8297} ) ;
8398
8499/**
85- * @scriptlet prevent-textContent
100+ * @scriptlet prevent-innerHTML
86101 *
87102 * @description
88- * Conditionally prevent assignment to `textContent ` property.
103+ * Conditionally prevent assignment to `innerHTML ` property.
89104 *
90105 * @param [selector]
91106 * Optional. The element must matches `selector` for the prevention to take
@@ -97,44 +112,15 @@ registerScriptlet(preventInnerHTML, {
97112 *
98113 * */
99114
100- export function preventTextContent (
115+ function preventInnerHTML (
101116 selector = '' ,
102117 pattern = ''
103118) {
104- const safe = safeSelf ( ) ;
105- const logPrefix = safe . makeLogPrefix ( 'prevent-textContent' , selector , pattern ) ;
106- const matcher = safe . initPattern ( pattern , { canNegate : true } ) ;
107- const current = safe . Object_getOwnPropertyDescriptor ( Element . prototype , 'textContent' ) ;
108- if ( current === undefined ) { return ; }
109- const shouldPreventSet = ( elem , a ) => {
110- if ( selector !== '' ) {
111- if ( typeof elem . matches !== 'function' ) { return false ; }
112- if ( elem . matches ( selector ) === false ) { return false ; }
113- }
114- return safe . testPattern ( matcher , `${ a } ` ) ;
115- } ;
116- Object . defineProperty ( Element . prototype , 'textContent' , {
117- get : function ( ) {
118- return current . get
119- ? current . get . call ( this )
120- : current . value ;
121- } ,
122- set : function ( a ) {
123- if ( shouldPreventSet ( this , a ) ) {
124- safe . uboLog ( logPrefix , 'Prevented' ) ;
125- } else if ( current . set ) {
126- current . set . call ( this , a ) ;
127- }
128- if ( safe . logLevel > 1 ) {
129- safe . uboLog ( logPrefix , `Assigned:\n${ a } ` ) ;
130- }
131- current . value = a ;
132- } ,
133- } ) ;
119+ freezeElementProperty ( 'innerHTML' , selector , pattern ) ;
134120}
135121registerScriptlet ( preventInnerHTML , {
136- name : 'prevent-textContent .js' ,
122+ name : 'prevent-innerHTML .js' ,
137123 dependencies : [
138- safeSelf ,
124+ freezeElementProperty ,
139125 ] ,
140126} ) ;
0 commit comments