| LEFT | RIGHT | 
|     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 390 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   401     } |   401     } | 
|   402   }); |   402   }); | 
|   403 } |   403 } | 
|   404  |   404  | 
|   405 exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, |   405 exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, | 
|   406                                                   toRegExp, regexEscape, |   406                                                   toRegExp, regexEscape, | 
|   407                                                   hideElement); |   407                                                   hideElement); | 
|   408  |   408  | 
|   409 /** |   409 /** | 
|   410  * Hides any HTML element or one of its ancestors matching a CSS selector if |   410  * Hides any HTML element or one of its ancestors matching a CSS selector if | 
 |   411  * it matches the provided condition. | 
 |   412  * | 
 |   413  * @param {function} match The function that provides the matching condition. | 
 |   414  * @param {string} selector The CSS selector that an HTML element must match | 
 |   415  *   for it to be hidden. | 
 |   416  * @param {?string} [searchSelector] The CSS selector that an HTML element | 
 |   417  *   containing the given string must match. Defaults to the value of the | 
 |   418  *   <code>selector</code> argument. | 
 |   419  */ | 
 |   420 function hideIfMatches(match, selector, searchSelector) | 
 |   421 { | 
 |   422   if (searchSelector == null) | 
 |   423     searchSelector = selector; | 
 |   424  | 
 |   425   let callback = () => | 
 |   426   { | 
 |   427     for (let element of document.querySelectorAll(searchSelector)) | 
 |   428     { | 
 |   429       let closest = element.closest(selector); | 
 |   430       if (closest && match(element, closest)) | 
 |   431         hideElement(closest); | 
 |   432     } | 
 |   433   }; | 
 |   434   new MutationObserver(callback) | 
 |   435     .observe(document, {childList: true, characterData: true, subtree: true}); | 
 |   436   callback(); | 
 |   437 } | 
 |   438  | 
 |   439 /** | 
 |   440  * Hides any HTML element or one of its ancestors matching a CSS selector if | 
|   411  * the text content of the element contains a given string. |   441  * the text content of the element contains a given string. | 
|   412  * |   442  * | 
|   413  * @param {string} search The string to look for in HTML elements. If the |   443  * @param {string} search The string to look for in HTML elements. If the | 
|   414  *   string begins and ends with a slash (<code>/</code>), the text in between |   444  *   string begins and ends with a slash (<code>/</code>), the text in between | 
|   415  *   is treated as a regular expression. |   445  *   is treated as a regular expression. | 
|   416  * @param {string} selector The CSS selector that an HTML element must match |   446  * @param {string} selector The CSS selector that an HTML element must match | 
|   417  *   for it to be hidden. |   447  *   for it to be hidden. | 
|   418  * @param {string?} [searchSelector] The CSS selector that an HTML element |   448  * @param {?string} [searchSelector] The CSS selector that an HTML element | 
|   419  *   containing the given string must match. Defaults to the value of the |   449  *   containing the given string must match. Defaults to the value of the | 
|   420  *   <code>selector</code> argument. |   450  *   <code>selector</code> argument. | 
|   421  */ |   451  */ | 
|   422 function hideIfContains(search, selector = "*", searchSelector = null) |   452 function hideIfContains(search, selector = "*", searchSelector = null) | 
|   423 { |   453 { | 
|   424   if (searchSelector == null) |  | 
|   425     searchSelector = selector; |  | 
|   426  |  | 
|   427   let re = toRegExp(search); |   454   let re = toRegExp(search); | 
|   428  |   455  | 
|   429   new MutationObserver(() => |   456   hideIfMatches(element => re.test(element.textContent), | 
|   430   { |   457                 selector, searchSelector); | 
|   431     for (let element of document.querySelectorAll(searchSelector)) |   458 } | 
|   432     { |   459  | 
|   433       if (re.test(element.textContent)) |   460 exports["hide-if-contains"] = hideIfContains; | 
 |   461  | 
 |   462 /** | 
 |   463  * Hides any HTML element matching a CSS selector if the visible text content | 
 |   464  * of the element contains a given string. | 
 |   465  * | 
 |   466  * @param {string} search The string to match to the visible text. Is considered | 
 |   467  *   visible text that isn't hidden by CSS properties or other means. | 
 |   468  *   If the string begins and ends with a slash (<code>/</code>), the | 
 |   469  *   text in between is treated as a regular expression. | 
 |   470  * @param {string} selector The CSS selector that an HTML element must match | 
 |   471  *   for it to be hidden. | 
 |   472  * @param {?string} [searchSelector] The CSS selector that an HTML element | 
 |   473  *   containing the given string must match. Defaults to the value of the | 
 |   474  *   <code>selector</code> argument. | 
 |   475  */ | 
 |   476 function hideIfContainsVisibleText(search, selector, searchSelector = null) | 
 |   477 { | 
 |   478   /** | 
 |   479    * Determines if the text inside the element is visible. | 
 |   480    * @param {Element} element The element we are checking. | 
 |   481    * @param {?CSSStyleDeclaration} style The computed style of element. If | 
 |   482    *   falsey it will be queried. | 
 |   483    * @returns {bool} Whether the text is visible. | 
 |   484    */ | 
 |   485   function isTextVisible(element, style) | 
 |   486   { | 
 |   487     if (!style) | 
 |   488       style = window.getComputedStyle(element); | 
 |   489  | 
 |   490     if (style.getPropertyValue("opacity") == "0") | 
 |   491       return false; | 
 |   492     if (style.getPropertyValue("font-size") == "0px") | 
 |   493       return false; | 
 |   494  | 
 |   495     let color = style.getPropertyValue("color"); | 
 |   496     // if color is transparent... | 
 |   497     if (color == "rgba(0, 0, 0, 0)") | 
 |   498       return false; | 
 |   499     if (style.getPropertyValue("background-color") == color) | 
 |   500       return false; | 
 |   501  | 
 |   502     return true; | 
 |   503   } | 
 |   504  | 
 |   505   /** | 
 |   506    * Check if an element is visible | 
 |   507    * @param {Element} element The element to check visibility of. | 
 |   508    * @param {?CSSStyleDeclaration} style The computed style of element. If | 
 |   509    *   falsey it will be queried. | 
 |   510    * @param {?Element} closest The closest parent to reach. | 
 |   511    * @return {bool} Whether the element is visible. | 
 |   512    */ | 
 |   513   function isVisible(element, style, closest) | 
 |   514   { | 
 |   515     if (!style) | 
 |   516       style = window.getComputedStyle(element); | 
 |   517  | 
 |   518     if (style.getPropertyValue("display") == "none") | 
 |   519       return false; | 
 |   520     let visibility = style.getPropertyValue("visibility"); | 
 |   521     if (visibility == "hidden" || visibility == "collapse") | 
 |   522       return false; | 
 |   523  | 
 |   524     if (!closest || element == closest) | 
 |   525       return true; | 
 |   526  | 
 |   527     let parent = element.parentElement; | 
 |   528     if (!parent) | 
 |   529       return true; | 
 |   530  | 
 |   531     return isVisible(parent, null, closest); | 
 |   532   } | 
 |   533  | 
 |   534   /** | 
 |   535    * Returns the visible text content from an element and its descendants. | 
 |   536    * @param {Element} element The element whose visible text we want. | 
 |   537    * @param {Element} closest The closest parent to reach while checking | 
 |   538    *   for visibility. | 
 |   539    * @returns {string} The text that is visible. | 
 |   540    */ | 
 |   541   function getVisibleContent(element, closest) | 
 |   542   { | 
 |   543     let style = window.getComputedStyle(element); | 
 |   544     if (!isVisible(element, style, closest)) | 
 |   545       return ""; | 
 |   546  | 
 |   547     let text = ""; | 
 |   548     for (let node of element.childNodes) | 
 |   549     { | 
 |   550       switch (node.nodeType) | 
|   434       { |   551       { | 
|   435         let closest = element.closest(selector); |   552         case Node.ELEMENT_NODE: | 
|   436         if (closest) |   553           text += getVisibleContent(node, element); | 
|   437           hideElement(closest); |   554           break; | 
 |   555         case Node.TEXT_NODE: | 
 |   556           if (isTextVisible(element, style)) | 
 |   557             text += node.nodeValue; | 
 |   558           break; | 
|   438       } |   559       } | 
|   439     } |   560     } | 
|   440   }) |   561     return text; | 
|   441   .observe(document, {childList: true, characterData: true, subtree: true}); |   562   } | 
|   442 } |   563  | 
|   443  |   564   let re = toRegExp(search); | 
|   444 exports["hide-if-contains"] = hideIfContains; |   565  | 
 |   566   hideIfMatches( | 
 |   567     (element, closest) => re.test(getVisibleContent(element, closest)), | 
 |   568     selector, searchSelector); | 
 |   569 } | 
 |   570  | 
 |   571 exports["hide-if-contains-visible-text"] = hideIfContainsVisibleText; | 
|   445  |   572  | 
|   446 /** |   573 /** | 
|   447  * Hides any HTML element or one of its ancestors matching a CSS selector if |   574  * Hides any HTML element or one of its ancestors matching a CSS selector if | 
|   448  * the text content of the element contains a given string and, optionally, if |   575  * the text content of the element contains a given string and, optionally, if | 
|   449  * the element's computed style contains a given string. |   576  * the element's computed style contains a given string. | 
|   450  * |   577  * | 
|   451  * @param {string} search The string to look for in HTML elements. If the |   578  * @param {string} search The string to look for in HTML elements. If the | 
|   452  *   string begins and ends with a slash (<code>/</code>), the text in between |   579  *   string begins and ends with a slash (<code>/</code>), the text in between | 
|   453  *   is treated as a regular expression. |   580  *   is treated as a regular expression. | 
|   454  * @param {string} selector The CSS selector that an HTML element must match |   581  * @param {string} selector The CSS selector that an HTML element must match | 
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   671 function wrapPropertyAccess(object, property, descriptor) |   798 function wrapPropertyAccess(object, property, descriptor) | 
|   672 { |   799 { | 
|   673   let dotIndex = property.indexOf("."); |   800   let dotIndex = property.indexOf("."); | 
|   674   if (dotIndex == -1) |   801   if (dotIndex == -1) | 
|   675   { |   802   { | 
|   676     // simple property case. |   803     // simple property case. | 
|   677     let currentDescriptor = Object.getOwnPropertyDescriptor(object, property); |   804     let currentDescriptor = Object.getOwnPropertyDescriptor(object, property); | 
|   678     if (currentDescriptor && !currentDescriptor.configurable) |   805     if (currentDescriptor && !currentDescriptor.configurable) | 
|   679       return; |   806       return; | 
|   680  |   807  | 
|   681     descriptor.configurable = true; |   808     // Keep it configurable because the same property can be wrapped via | 
|   682     Object.defineProperty(object, property, descriptor); |   809     // multiple snippet filters (#7373). | 
 |   810     Object.defineProperty(object, property, | 
 |   811                           Object.assign({}, descriptor, {configurable: true})); | 
|   683     return; |   812     return; | 
|   684   } |   813   } | 
|   685  |   814  | 
|   686   let name = property.slice(0, dotIndex); |   815   let name = property.slice(0, dotIndex); | 
|   687   property = property.slice(dotIndex + 1); |   816   property = property.slice(dotIndex + 1); | 
|   688   let value = object[name]; |   817   let value = object[name]; | 
|   689   if (value && (typeof value == "object" || typeof value == "function")) |   818   if (value && (typeof value == "object" || typeof value == "function")) | 
|   690     wrapPropertyAccess(value, property, descriptor); |   819     wrapPropertyAccess(value, property, descriptor); | 
|   691  |   820  | 
|   692   let currentDescriptor = Object.getOwnPropertyDescriptor(object, name); |   821   let currentDescriptor = Object.getOwnPropertyDescriptor(object, name); | 
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   798  *   slash (<code>/</code>), the text in between is treated as a regular |   927  *   slash (<code>/</code>), the text in between is treated as a regular | 
|   799  *   expression. |   928  *   expression. | 
|   800  */ |   929  */ | 
|   801 function abortCurrentInlineScript(api, search = null) |   930 function abortCurrentInlineScript(api, search = null) | 
|   802 { |   931 { | 
|   803   let re = search ? toRegExp(search) : null; |   932   let re = search ? toRegExp(search) : null; | 
|   804  |   933  | 
|   805   let rid = randomId(); |   934   let rid = randomId(); | 
|   806   let us = document.currentScript; |   935   let us = document.currentScript; | 
|   807  |   936  | 
|   808  |  | 
|   809   let object = window; |   937   let object = window; | 
|   810   let path = api.split("."); |   938   let path = api.split("."); | 
|   811   let name = path.pop(); |   939   let name = path.pop(); | 
|   812  |   940  | 
|   813   for (let node of path) |   941   for (let node of path) | 
|   814   { |   942   { | 
|   815     object = object[node]; |   943     object = object[node]; | 
|   816  |   944  | 
|   817     if (!object || !(typeof object == "object" || typeof object == "function")) |   945     if (!object || !(typeof object == "object" || typeof object == "function")) | 
|   818       return; |   946       return; | 
|   819   } |   947   } | 
|   820  |   948  | 
|   821   let prevGetter; |   949   let {get: prevGetter, set: prevSetter} = | 
|   822   let prevSetter; |   950     Object.getOwnPropertyDescriptor(object, name) || {}; | 
|   823   let desc = Object.getOwnPropertyDescriptor(object, name); |  | 
|   824   if (desc) |  | 
|   825   { |  | 
|   826     if (typeof desc.get == "function") |  | 
|   827       prevGetter = desc.get; |  | 
|   828     if (typeof desc.set == "function") |  | 
|   829       prevSetter = desc.set; |  | 
|   830   } |  | 
|   831  |   951  | 
|   832   let currentValue = object[name]; |   952   let currentValue = object[name]; | 
|   833  |   953  | 
|   834   let abort = () => |   954   let abort = () => | 
|   835   { |   955   { | 
|   836     let element = document.currentScript; |   956     let element = document.currentScript; | 
|   837     if (element instanceof HTMLScriptElement && element.src == "" && |   957     if (element instanceof HTMLScriptElement && element.src == "" && | 
|   838         element != us && (!re || re.test(element.textContent))) |   958         element != us && (!re || re.test(element.textContent))) | 
|   839     { |   959     { | 
|   840       throw new ReferenceError(rid); |   960       throw new ReferenceError(rid); | 
|   841     } |   961     } | 
|   842   }; |   962   }; | 
|   843  |   963  | 
|   844   let descriptor = { |   964   let descriptor = { | 
|   845     get() |   965     get() | 
|   846     { |   966     { | 
|   847       abort(); |   967       abort(); | 
 |   968  | 
|   848       if (prevGetter) |   969       if (prevGetter) | 
|   849         return prevGetter.call(this); |   970         return prevGetter.call(this); | 
|   850  |   971  | 
|   851       return currentValue; |   972       return currentValue; | 
|   852     }, |   973     }, | 
|   853     set(value) |   974     set(value) | 
|   854     { |   975     { | 
|   855       abort(); |   976       abort(); | 
 |   977  | 
|   856       if (prevSetter) |   978       if (prevSetter) | 
|   857         prevSetter.call(this, value); |   979         prevSetter.call(this, value); | 
|   858  |   980       else | 
|   859       currentValue = value; |   981         currentValue = value; | 
|   860     } |   982     } | 
|   861   }; |   983   }; | 
|   862  |   984  | 
|   863   wrapPropertyAccess(object, name, descriptor); |   985   wrapPropertyAccess(object, name, descriptor); | 
|   864  |   986  | 
|   865   overrideOnError(rid); |   987   overrideOnError(rid); | 
|   866 } |   988 } | 
|   867  |   989  | 
|   868 exports["abort-current-inline-script"] = |   990 exports["abort-current-inline-script"] = | 
|   869   makeInjector(abortCurrentInlineScript, wrapPropertyAccess, toRegExp, |   991   makeInjector(abortCurrentInlineScript, wrapPropertyAccess, toRegExp, | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
|   898  |  1020  | 
|   899       args[0] = url.href; |  1021       args[0] = url.href; | 
|   900     } |  1022     } | 
|   901  |  1023  | 
|   902     return fetch_.apply(this, args); |  1024     return fetch_.apply(this, args); | 
|   903   }; |  1025   }; | 
|   904 } |  1026 } | 
|   905  |  1027  | 
|   906 exports["strip-fetch-query-parameter"] = makeInjector(stripFetchQueryParameter, |  1028 exports["strip-fetch-query-parameter"] = makeInjector(stripFetchQueryParameter, | 
|   907                                                       toRegExp, regexEscape); |  1029                                                       toRegExp, regexEscape); | 
|   908  |  | 
|   909 function hideIfContainsVisibleText(search, hideSelector, innerSelector = null) |  | 
|   910 { |  | 
|   911   /** |  | 
|   912    * Determine if the text inside the element is visible. |  | 
|   913    * @param {Element} element the leaf element we are checking. |  | 
|   914    * @param {?CSSStyle} style the computed style of element. |  | 
|   915    * @returns {bool} whether the text is visible. |  | 
|   916    */ |  | 
|   917   function isTextVisible(element, style) |  | 
|   918   { |  | 
|   919     if (!style) |  | 
|   920       style = window.getComputedStyle(element); |  | 
|   921  |  | 
|   922     if (style.getPropertyValue("opacity") == "0") |  | 
|   923       return false; |  | 
|   924     if (style.getPropertyValue("font-size") == "0px") |  | 
|   925       return false; |  | 
|   926     if (style.getPropertyValue("color") == |  | 
|   927         style.getPropertyValue("background-color")) |  | 
|   928       return false; |  | 
|   929  |  | 
|   930     return true; |  | 
|   931   } |  | 
|   932  |  | 
|   933   /** |  | 
|   934    * Returns the visible text content from an element and its children. |  | 
|   935    * @param {Element} element the element whose visible text we want. |  | 
|   936    * @returns {String} the text that is visible. |  | 
|   937    */ |  | 
|   938   function getVisibleContent(element) |  | 
|   939   { |  | 
|   940     let style = window.getComputedStyle(element); |  | 
|   941     if (style.getPropertyValue("display") == "none") |  | 
|   942       return ""; |  | 
|   943     let visibility = style.getPropertyValue("visibility"); |  | 
|   944     if (visibility == "hidden" || visibility == "collapse") |  | 
|   945       return ""; |  | 
|   946  |  | 
|   947     let text = ""; |  | 
|   948     for (let node of element.childNodes) |  | 
|   949     { |  | 
|   950       switch (node.nodeType) |  | 
|   951       { |  | 
|   952         case Node.ELEMENT_NODE: |  | 
|   953           text += getVisibleContent(node); |  | 
|   954           break; |  | 
|   955         case Node.TEXT_NODE: |  | 
|   956           if (isTextVisible(element, style)) |  | 
|   957             text += node.nodeValue; |  | 
|   958           break; |  | 
|   959       } |  | 
|   960     } |  | 
|   961     return text; |  | 
|   962   } |  | 
|   963  |  | 
|   964   let re = toRegExp(search); |  | 
|   965  |  | 
|   966   new MutationObserver(() => |  | 
|   967   { |  | 
|   968     for (let element of document.querySelectorAll(hideSelector)) |  | 
|   969     { |  | 
|   970       let inners = |  | 
|   971           innerSelector ? element.querySelectorAll(innerSelector) : [element]; |  | 
|   972       for (let inner of inners) |  | 
|   973       { |  | 
|   974         let content = getVisibleContent(inner); |  | 
|   975         if (re.test(content)) |  | 
|   976           hideElement(element); |  | 
|   977       } |  | 
|   978     } |  | 
|   979   }) |  | 
|   980   .observe(document, {childList: true, characterData: true, subtree: true}); |  | 
|   981 } |  | 
|   982  |  | 
|   983 exports["hide-if-contains-visible-text"] = |  | 
|   984   makeInjector(hideIfContainsVisibleText, hideElement); |  | 
| LEFT | RIGHT |