@@ -4,6 +4,20 @@ let stackDomains = []
4
4
let matchAllStackDomains = false
5
5
let taintCheck = false
6
6
let initialCreateElement
7
+ let tagModifiers = { }
8
+
9
+ /**
10
+ * @param {string } tagName
11
+ * @param {'property' | 'attribute' | 'handler' | 'listener' } filterName
12
+ * @param {string } key
13
+ * @returns {boolean }
14
+ */
15
+ function shouldFilterKey ( tagName , filterName , key ) {
16
+ if ( filterName === 'attribute' ) {
17
+ key = key . toLowerCase ( )
18
+ }
19
+ return tagModifiers ?. [ tagName ] ?. filters ?. [ filterName ] ?. includes ( key )
20
+ }
7
21
8
22
let elementRemovalTimeout
9
23
const featureName = 'runtimeChecks'
@@ -37,12 +51,15 @@ class DDGRuntimeChecks extends HTMLElement {
37
51
monitorProperties ( el ) {
38
52
// Mutation oberver and observedAttributes don't work on property accessors
39
53
// So instead we need to monitor all properties on the prototypes and forward them to the real element
40
- const propertyNames = [ ]
54
+ let propertyNames = [ ]
41
55
let proto = Object . getPrototypeOf ( el )
42
56
while ( proto && proto !== Object . prototype ) {
43
57
propertyNames . push ( ...Object . getOwnPropertyNames ( proto ) )
44
58
proto = Object . getPrototypeOf ( proto )
45
59
}
60
+ const classMethods = Object . getOwnPropertyNames ( Object . getPrototypeOf ( this ) )
61
+ // Filter away the methods we don't want to monitor from our own class
62
+ propertyNames = propertyNames . filter ( prop => ! classMethods . includes ( prop ) )
46
63
propertyNames . forEach ( prop => {
47
64
if ( prop === 'constructor' ) return
48
65
// May throw, but this is best effort monitoring.
@@ -52,6 +69,7 @@ class DDGRuntimeChecks extends HTMLElement {
52
69
return el [ prop ]
53
70
} ,
54
71
set ( value ) {
72
+ if ( shouldFilterKey ( this . #tagName, 'property' , prop ) ) return
55
73
el [ prop ] = value
56
74
}
57
75
} )
@@ -74,23 +92,27 @@ class DDGRuntimeChecks extends HTMLElement {
74
92
75
93
// Reflect all attrs to the new element
76
94
for ( const attribute of this . getAttributeNames ( ) ) {
95
+ if ( shouldFilterKey ( this . #tagName, 'attribute' , attribute ) ) continue
77
96
el . setAttribute ( attribute , this . getAttribute ( attribute ) )
78
97
}
79
98
80
99
// Reflect all props to the new element
81
100
for ( const param of Object . keys ( this ) ) {
101
+ if ( shouldFilterKey ( this . #tagName, 'property' , param ) ) continue
82
102
el [ param ] = this [ param ]
83
103
}
84
104
85
105
// Reflect all listeners to the new element
86
106
for ( const [ ...args ] of this . #listeners) {
107
+ if ( shouldFilterKey ( this . #tagName, 'listener' , args [ 0 ] ) ) continue
87
108
el . addEventListener ( ...args )
88
109
}
89
110
this . #listeners = [ ]
90
111
91
112
// Reflect all 'on' event handlers to the new element
92
113
for ( const propName in this ) {
93
114
if ( propName . startsWith ( 'on' ) ) {
115
+ if ( shouldFilterKey ( this . #tagName, 'handler' , propName ) ) continue
94
116
const prop = this [ propName ]
95
117
if ( typeof prop === 'function' ) {
96
118
el [ propName ] = prop
@@ -123,6 +145,7 @@ class DDGRuntimeChecks extends HTMLElement {
123
145
}
124
146
125
147
setAttribute ( name , value ) {
148
+ if ( shouldFilterKey ( this . #tagName, 'attribute' , name ) ) return
126
149
const el = this . getElement ( )
127
150
if ( el ) {
128
151
return el . setAttribute ( name , value )
@@ -131,6 +154,7 @@ class DDGRuntimeChecks extends HTMLElement {
131
154
}
132
155
133
156
removeAttribute ( name ) {
157
+ if ( shouldFilterKey ( this . #tagName, 'attribute' , name ) ) return
134
158
const el = this . getElement ( )
135
159
if ( el ) {
136
160
return el . removeAttribute ( name )
@@ -139,6 +163,7 @@ class DDGRuntimeChecks extends HTMLElement {
139
163
}
140
164
141
165
addEventListener ( ...args ) {
166
+ if ( shouldFilterKey ( this . #tagName, 'listener' , args [ 0 ] ) ) return
142
167
const el = this . getElement ( )
143
168
if ( el ) {
144
169
return el . addEventListener ( ...args )
@@ -147,6 +172,7 @@ class DDGRuntimeChecks extends HTMLElement {
147
172
}
148
173
149
174
removeEventListener ( ...args ) {
175
+ if ( shouldFilterKey ( this . #tagName, 'listener' , args [ 0 ] ) ) return
150
176
const el = this . getElement ( )
151
177
if ( el ) {
152
178
return el . removeEventListener ( ...args )
@@ -272,6 +298,7 @@ export function init (args) {
272
298
matchAllStackDomains = getFeatureSettingEnabled ( featureName , args , 'matchAllStackDomains' )
273
299
stackDomains = getFeatureSetting ( featureName , args , 'stackDomains' ) || [ ]
274
300
elementRemovalTimeout = getFeatureSetting ( featureName , args , 'elementRemovalTimeout' ) || 1000
301
+ tagModifiers = getFeatureSetting ( featureName , args , 'tagModifiers' ) || { }
275
302
276
303
overrideCreateElement ( )
277
304
0 commit comments