4
4
validateType ,
5
5
validateListener ,
6
6
listenerToString ,
7
+ logMessage ,
7
8
} from '../helpers' ;
8
9
9
10
/* eslint-disable max-len */
@@ -21,14 +22,24 @@ import {
21
22
*
22
23
* ### Syntax
23
24
*
25
+ * <!-- markdownlint-disable line-length -->
26
+ *
24
27
* ```text
25
- * example.org#%#//scriptlet('prevent-addEventListener'[, typeSearch[, listenerSearch]])
28
+ * example.org#%#//scriptlet('prevent-addEventListener'[, typeSearch[, listenerSearch[, additionalArgName, additionalArgValue] ]])
26
29
* ```
27
30
*
31
+ * <!-- markdownlint-enable line-length -->
32
+ *
28
33
* - `typeSearch` — optional, string or regular expression matching the type (event name);
29
34
* defaults to match all types; invalid regular expression will cause exit and rule will not work
30
35
* - `listenerSearch` — optional, string or regular expression matching the listener function body;
31
36
* defaults to match all listeners; invalid regular expression will cause exit and rule will not work
37
+ * - `additionalArgName` — optional, string, name of the additional argument to match;
38
+ * currently only `elements` is supported;
39
+ * - `additionalArgValue` — optional, value corresponding to the additional argument name;
40
+ * for `elements` it can be a CSS selector or one of the following values:
41
+ * - `window`
42
+ * - `document`
32
43
*
33
44
* ### Examples
34
45
*
@@ -52,20 +63,84 @@ import {
52
63
* });
53
64
* ```
54
65
*
66
+ * 1. Prevent 'click' listeners with the callback body containing `foo` and only if the element has the class `bar`
67
+ *
68
+ * ```adblock
69
+ * example.org#%#//scriptlet('prevent-addEventListener', 'click', 'foo', 'elements', '.bar')
70
+ * ```
71
+ *
72
+ * For instance, this listener will not be called:
73
+ *
74
+ * ```javascript
75
+ * const el = document.querySelector('.bar');
76
+ * el.addEventListener('click', () => {
77
+ * window.test = 'foo';
78
+ * });
79
+ * ```
80
+ *
81
+ * This listener will be called:
82
+ *
83
+ * ```javascript
84
+ * const el = document.querySelector('.xyz');
85
+ * el.addEventListener('click', () => {
86
+ * window.test = 'foo';
87
+ * });
88
+ * ```
89
+ *
55
90
* @added v1.0.4.
56
91
*/
57
92
/* eslint-enable max-len */
58
- export function preventAddEventListener ( source , typeSearch , listenerSearch ) {
93
+ export function preventAddEventListener ( source , typeSearch , listenerSearch , additionalArgName , additionalArgValue ) {
59
94
const typeSearchRegexp = toRegExp ( typeSearch ) ;
60
95
const listenerSearchRegexp = toRegExp ( listenerSearch ) ;
61
96
97
+ let elementToMatch ;
98
+ if ( additionalArgName ) {
99
+ if ( additionalArgName !== 'elements' ) {
100
+ logMessage ( source , `Invalid "additionalArgName": ${ additionalArgName } \nOnly "elements" is supported.` ) ;
101
+ return ;
102
+ }
103
+
104
+ if ( ! additionalArgValue ) {
105
+ logMessage ( source , '"additionalArgValue" is required.' ) ;
106
+ return ;
107
+ }
108
+
109
+ elementToMatch = additionalArgValue ;
110
+ }
111
+
112
+ /**
113
+ * Checks if an element matches the specified selector or element type.
114
+ *
115
+ * @param {any } element - The element to check
116
+ * @returns {boolean }
117
+ */
118
+ const elementMatches = ( element ) => {
119
+ // If elementToMatch is undefined, it means that the scriptlet was called without the `elements` argument
120
+ // so it should match all elements
121
+ if ( elementToMatch === undefined ) {
122
+ return true ;
123
+ }
124
+ if ( elementToMatch === 'window' ) {
125
+ return element === window ;
126
+ }
127
+ if ( elementToMatch === 'document' ) {
128
+ return element === document ;
129
+ }
130
+ if ( element && element . matches && element . matches ( elementToMatch ) ) {
131
+ return true ;
132
+ }
133
+ return false ;
134
+ } ;
135
+
62
136
const nativeAddEventListener = window . EventTarget . prototype . addEventListener ;
63
137
64
138
function addEventListenerWrapper ( type , listener , ...args ) {
65
139
let shouldPrevent = false ;
66
140
if ( validateType ( type ) && validateListener ( listener ) ) {
67
141
shouldPrevent = typeSearchRegexp . test ( type . toString ( ) )
68
- && listenerSearchRegexp . test ( listenerToString ( listener ) ) ;
142
+ && listenerSearchRegexp . test ( listenerToString ( listener ) )
143
+ && elementMatches ( this ) ;
69
144
}
70
145
71
146
if ( shouldPrevent ) {
@@ -115,4 +190,5 @@ preventAddEventListener.injections = [
115
190
validateType ,
116
191
validateListener ,
117
192
listenerToString ,
193
+ logMessage ,
118
194
] ;
0 commit comments