Left: | ||
Right: |
OLD | NEW |
---|---|
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
139 } | 139 } |
140 // Just in case the getSelectors() generator above had to run some heavy | 140 // Just in case the getSelectors() generator above had to run some heavy |
141 // document.querySelectorAll() call which didn't produce any results, make | 141 // document.querySelectorAll() call which didn't produce any results, make |
142 // sure there is at least one point where execution can pause. | 142 // sure there is at least one point where execution can pause. |
143 yield null; | 143 yield null; |
144 } | 144 } |
145 | 145 |
146 function PlainSelector(selector) | 146 function PlainSelector(selector) |
147 { | 147 { |
148 this._selector = selector; | 148 this._selector = selector; |
149 this.maybeDependsOnAttributes = /[#.]|\[.+\]/.test(selector); | |
149 } | 150 } |
150 | 151 |
151 PlainSelector.prototype = { | 152 PlainSelector.prototype = { |
152 /** | 153 /** |
153 * Generator function returning a pair of selector | 154 * Generator function returning a pair of selector |
154 * string and subtree. | 155 * string and subtree. |
155 * @param {string} prefix the prefix for the selector. | 156 * @param {string} prefix the prefix for the selector. |
156 * @param {Node} subtree the subtree we work on. | 157 * @param {Node} subtree the subtree we work on. |
157 * @param {StringifiedStyle[]} styles the stringified style objects. | 158 * @param {StringifiedStyle[]} styles the stringified style objects. |
158 */ | 159 */ |
(...skipping 12 matching lines...) Expand all Loading... | |
171 } | 172 } |
172 | 173 |
173 HasSelector.prototype = { | 174 HasSelector.prototype = { |
174 requiresHiding: true, | 175 requiresHiding: true, |
175 | 176 |
176 get dependsOnStyles() | 177 get dependsOnStyles() |
177 { | 178 { |
178 return this._innerSelectors.some(selector => selector.dependsOnStyles); | 179 return this._innerSelectors.some(selector => selector.dependsOnStyles); |
179 }, | 180 }, |
180 | 181 |
182 get dependsOnCharacterData() | |
183 { | |
184 return this._innerSelectors.some( | |
185 selector => selector.dependsOnCharacterData | |
186 ); | |
187 }, | |
188 | |
189 get maybeDependsOnAttributes() | |
190 { | |
191 return this._innerSelectors.some( | |
192 selector => selector.maybeDependsOnAttributes | |
193 ); | |
194 }, | |
195 | |
181 *getSelectors(prefix, subtree, styles) | 196 *getSelectors(prefix, subtree, styles) |
182 { | 197 { |
183 for (let element of this.getElements(prefix, subtree, styles)) | 198 for (let element of this.getElements(prefix, subtree, styles)) |
184 yield [makeSelector(element, ""), element]; | 199 yield [makeSelector(element, ""), element]; |
185 }, | 200 }, |
186 | 201 |
187 /** | 202 /** |
188 * Generator function returning selected elements. | 203 * Generator function returning selected elements. |
189 * @param {string} prefix the prefix for the selector. | 204 * @param {string} prefix the prefix for the selector. |
190 * @param {Node} subtree the subtree we work on. | 205 * @param {Node} subtree the subtree we work on. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
222 } | 237 } |
223 }; | 238 }; |
224 | 239 |
225 function ContainsSelector(textContent) | 240 function ContainsSelector(textContent) |
226 { | 241 { |
227 this._text = textContent; | 242 this._text = textContent; |
228 } | 243 } |
229 | 244 |
230 ContainsSelector.prototype = { | 245 ContainsSelector.prototype = { |
231 requiresHiding: true, | 246 requiresHiding: true, |
247 dependsOnCharacterData: true, | |
232 | 248 |
233 *getSelectors(prefix, subtree, stylesheet) | 249 *getSelectors(prefix, subtree, stylesheet) |
234 { | 250 { |
235 for (let element of this.getElements(prefix, subtree, stylesheet)) | 251 for (let element of this.getElements(prefix, subtree, stylesheet)) |
236 yield [makeSelector(element, ""), subtree]; | 252 yield [makeSelector(element, ""), subtree]; |
237 }, | 253 }, |
238 | 254 |
239 *getElements(prefix, subtree, stylesheet) | 255 *getElements(prefix, subtree, stylesheet) |
240 { | 256 { |
241 let actualPrefix = (!prefix || incompletePrefixRegexp.test(prefix)) ? | 257 let actualPrefix = (!prefix || incompletePrefixRegexp.test(prefix)) ? |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
295 yield [selector, subtree]; | 311 yield [selector, subtree]; |
296 } | 312 } |
297 }; | 313 }; |
298 | 314 |
299 function isSelectorHidingOnlyPattern(pattern) | 315 function isSelectorHidingOnlyPattern(pattern) |
300 { | 316 { |
301 return pattern.selectors.some(s => s.preferHideWithSelector) && | 317 return pattern.selectors.some(s => s.preferHideWithSelector) && |
302 !pattern.selectors.some(s => s.requiresHiding); | 318 !pattern.selectors.some(s => s.requiresHiding); |
303 } | 319 } |
304 | 320 |
321 function shouldObserveAttributes(patterns) | |
322 { | |
323 // Observe changes to attributes if either there's a plain selector that | |
324 // looks like an ID selector, class selector, or attribute selector in one of | |
325 // the patterns (e.g. "a[href='https://example.com/']") | |
326 // or there's a properties selector nested inside a has selector | |
327 // (e.g. "div:-abp-has(:-abp-properties(color: blue))") | |
328 return patterns.some( | |
329 pattern => pattern.selectors.some( | |
330 selector => selector.maybeDependsOnAttributes || | |
331 selector instanceof HasSelector && | |
332 selector.dependsOnStyles | |
hub
2018/02/21 18:12:27
I'm always forgetting operator precedence. Should
Manish Jethani
2018/02/22 07:14:32
Done.
| |
333 ) | |
334 ); | |
335 } | |
336 | |
337 function shouldObserveCharacterData(patterns) | |
338 { | |
339 // Observe changes to character data only if there's a contains selector in | |
340 // one of the patterns. | |
341 return patterns.some( | |
342 pattern => pattern.selectors.some( | |
343 selector => selector.dependsOnCharacterData | |
344 ) | |
345 ); | |
346 } | |
347 | |
305 function ElemHideEmulation(addSelectorsFunc, hideElemsFunc) | 348 function ElemHideEmulation(addSelectorsFunc, hideElemsFunc) |
306 { | 349 { |
307 this.document = document; | 350 this.document = document; |
308 this.addSelectorsFunc = addSelectorsFunc; | 351 this.addSelectorsFunc = addSelectorsFunc; |
309 this.hideElemsFunc = hideElemsFunc; | 352 this.hideElemsFunc = hideElemsFunc; |
310 this.observer = new MutationObserver(this.observe.bind(this)); | 353 this.observer = new MutationObserver(this.observe.bind(this)); |
311 } | 354 } |
312 | 355 |
313 ElemHideEmulation.prototype = { | 356 ElemHideEmulation.prototype = { |
314 isSameOrigin(stylesheet) | 357 isSameOrigin(stylesheet) |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
580 this.patterns.push({selectors, text: pattern.text}); | 623 this.patterns.push({selectors, text: pattern.text}); |
581 } | 624 } |
582 | 625 |
583 if (this.patterns.length > 0) | 626 if (this.patterns.length > 0) |
584 { | 627 { |
585 this.queueFiltering(); | 628 this.queueFiltering(); |
586 this.observer.observe( | 629 this.observer.observe( |
587 this.document, | 630 this.document, |
588 { | 631 { |
589 childList: true, | 632 childList: true, |
590 attributes: true, | 633 attributes: shouldObserveAttributes(this.patterns), |
591 characterData: true, | 634 characterData: shouldObserveCharacterData(this.patterns), |
592 subtree: true | 635 subtree: true |
593 } | 636 } |
594 ); | 637 ); |
595 this.document.addEventListener("load", this.onLoad.bind(this), true); | 638 this.document.addEventListener("load", this.onLoad.bind(this), true); |
596 } | 639 } |
597 } | 640 } |
598 }; | 641 }; |
599 | 642 |
600 exports.ElemHideEmulation = ElemHideEmulation; | 643 exports.ElemHideEmulation = ElemHideEmulation; |
OLD | NEW |