| 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 |