| 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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 90 * | 90 * |
| 91 * @returns {function} The generated injector. | 91 * @returns {function} The generated injector. |
| 92 */ | 92 */ |
| 93 function makeInjector(injectable, ...dependencies) | 93 function makeInjector(injectable, ...dependencies) |
| 94 { | 94 { |
| 95 return (...args) => injectCode(stringifyFunctionCall(injectable, ...args), | 95 return (...args) => injectCode(stringifyFunctionCall(injectable, ...args), |
| 96 dependencies); | 96 dependencies); |
| 97 } | 97 } |
| 98 | 98 |
| 99 /** | 99 /** |
| 100 * Hides an HTML element by settings its <code>style</code> attribute to | 100 * Hides an HTML element by setting its <code>style</code> attribute to |
| 101 * <code>display: none !important</code>. | 101 * <code>display: none !important</code>. |
| 102 * | 102 * |
| 103 * @param {HTMLElement} element The HTML element to hide. | 103 * @param {HTMLElement} element The HTML element to hide. |
| 104 */ | 104 */ |
| 105 function hideElement(element) | 105 function hideElement(element) |
| 106 { | 106 { |
| 107 element.style.setProperty("display", "none", "important"); | 107 element.style.setProperty("display", "none", "important"); |
| 108 | 108 |
| 109 // Listen for changes to the style property and if our values are unset | 109 // Listen for changes to the style property and if our values are unset |
| 110 // then reset them. | 110 // then reset them. |
| 111 new MutationObserver(() => | 111 new MutationObserver(() => |
| 112 { | 112 { |
| 113 if (element.style.getPropertyValue("display") != "none" || | 113 if (element.style.getPropertyValue("display") != "none" || |
| 114 element.style.getPropertyPriority("display") != "important") | 114 element.style.getPropertyPriority("display") != "important") |
| 115 { | 115 { |
| 116 element.style.setProperty("display", "none", "important"); | 116 element.style.setProperty("display", "none", "important"); |
| 117 } | 117 } |
| 118 }) | 118 }) |
| 119 .observe(element, {attributes: true, attributeFilter: ["style"]}); | 119 .observe(element, {attributes: true, attributeFilter: ["style"]}); |
| 120 } | 120 } |
| 121 | 121 |
| 122 /** | 122 /** |
| 123 * Hides an HTML element or one of its ancestors matching a CSS selector by | |
| 124 * setting its <code>style</code> attribute to | |
| 125 * <code>display: none !important</code>. | |
| 126 * | |
| 127 * @param {HTMLElement} element The HTML element or a descendant of the HTML | |
| 128 * element to hide. | |
| 129 * @param {string} [selector] The CSS selector that the HTML element or one of | |
| 130 * its ancestors must match for it to be hidden. | |
| 131 */ | |
| 132 function hideAncestor(element, selector = "*") | |
| 133 { | |
| 134 do | |
| 135 { | |
| 136 if (element.matches(selector)) | |
|
hub
2018/08/10 12:30:41
Wouldn't https://developer.mozilla.org/en-US/docs/
Manish Jethani
2018/08/10 14:57:02
Ah, you're right. Element.closest is perfect.
It'
hub
2018/08/10 19:54:57
We support EdgeHTML 16 and up if I read things cor
| |
| 137 { | |
| 138 hideElement(element); | |
| 139 break; | |
| 140 } | |
| 141 } | |
| 142 while (element = element.parentElement); | |
| 143 } | |
| 144 | |
| 145 /** | |
| 123 * Observes changes to a DOM node using a <code>MutationObserver</code>. | 146 * Observes changes to a DOM node using a <code>MutationObserver</code>. |
| 124 * | 147 * |
| 125 * @param {Node} target The DOM node to observe for changes. | 148 * @param {Node} target The DOM node to observe for changes. |
| 126 * @param {MutationObserverInit?} [options] Options that describe what DOM | 149 * @param {MutationObserverInit?} [options] Options that describe what DOM |
| 127 * mutations should be reported to the callback. | 150 * mutations should be reported to the callback. |
| 128 * @param {function} callback A function that will be called on each DOM | 151 * @param {function} callback A function that will be called on each DOM |
| 129 * mutation, taking a <code>MutationRecord</code> as its parameter. | 152 * mutation, taking a <code>MutationRecord</code> as its parameter. |
| 130 */ | 153 */ |
| 131 function observe(target, options, callback) | 154 function observe(target, options, callback) |
| 132 { | 155 { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 | 232 |
| 210 // Since it's a weak map, it's possible that either the element or its | 233 // Since it's a weak map, it's possible that either the element or its |
| 211 // shadow has been removed. | 234 // shadow has been removed. |
| 212 if (!host || !root) | 235 if (!host || !root) |
| 213 return; | 236 return; |
| 214 | 237 |
| 215 // If the shadow contains the given text, check if the host or one of its | 238 // If the shadow contains the given text, check if the host or one of its |
| 216 // ancestors matches the selector; if a matching element is found, hide | 239 // ancestors matches the selector; if a matching element is found, hide |
| 217 // it. | 240 // it. |
| 218 if (root.textContent.includes(search)) | 241 if (root.textContent.includes(search)) |
| 219 { | 242 hideAncestor(host, selector); |
| 220 let element = host; | |
| 221 | |
| 222 do | |
| 223 { | |
| 224 if (element.matches(selector)) | |
| 225 { | |
| 226 hideElement(element); | |
| 227 break; | |
| 228 } | |
| 229 } | |
| 230 while (element = element.parentElement); | |
| 231 } | |
| 232 } | 243 } |
| 233 | 244 |
| 234 Object.defineProperty(Element.prototype, "attachShadow", { | 245 Object.defineProperty(Element.prototype, "attachShadow", { |
| 235 value(...args) | 246 value(...args) |
| 236 { | 247 { |
| 237 // Create the shadow root first. It doesn't matter if it's a closed | 248 // Create the shadow root first. It doesn't matter if it's a closed |
| 238 // shadow root, we keep the reference in a weak map. | 249 // shadow root, we keep the reference in a weak map. |
| 239 let root = originalAttachShadow.apply(this, args); | 250 let root = originalAttachShadow.apply(this, args); |
| 240 | 251 |
| 241 // Listen for relevant DOM mutations in the shadow. | 252 // Listen for relevant DOM mutations in the shadow. |
| 242 let observer = new MutationObserver(observeShadow); | 253 let observer = new MutationObserver(observeShadow); |
| 243 observer.observe(root, { | 254 observer.observe(root, { |
| 244 childList: true, | 255 childList: true, |
| 245 characterData: true, | 256 characterData: true, |
| 246 subtree: true | 257 subtree: true |
| 247 }); | 258 }); |
| 248 | 259 |
| 249 // Keep references to the shadow root and its host in a weak map. If | 260 // Keep references to the shadow root and its host in a weak map. If |
| 250 // either the shadow is detached or the host itself is removed from the | 261 // either the shadow is detached or the host itself is removed from the |
| 251 // DOM, the mutation observer too will be freed eventually and the entry | 262 // DOM, the mutation observer too will be freed eventually and the entry |
| 252 // will be removed. | 263 // will be removed. |
| 253 shadows.set(observer, {host: this, root}); | 264 shadows.set(observer, {host: this, root}); |
| 254 | 265 |
| 255 return root; | 266 return root; |
| 256 } | 267 } |
| 257 }); | 268 }); |
| 258 } | 269 } |
| 259 | 270 |
| 260 exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, | 271 exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, |
| 261 hideElement); | 272 hideAncestor, hideElement); |
| 262 | 273 |
| 263 /** | 274 /** |
| 264 * Hides any HTML element if the text content of the element contains a given | 275 * Hides any HTML element or one of its ancestors matching a CSS selector if |
| 265 * string. | 276 * the text content of the element contains a given string. |
| 266 * | 277 * |
| 267 * @param {string} search The string to look for in every HTML element. | 278 * @param {string} search The string to look for in HTML elements. |
| 268 * @param {string} selector The CSS selector that an HTML element must match | 279 * @param {string} selector The CSS selector that an HTML element must match |
| 269 * for it to be hidden. | 280 * for it to be hidden. |
| 281 * @param {string?} [searchSelector] The CSS selector that an HTML element | |
| 282 * containing the given string must match. Defaults to the value of the | |
| 283 * <code>selector</code> argument. | |
| 270 */ | 284 */ |
| 271 function hideIfContains(search, selector = "*") | 285 function hideIfContains(search, selector = "*", searchSelector = null) |
| 272 { | 286 { |
| 287 if (searchSelector == null) | |
| 288 searchSelector = selector; | |
| 289 | |
| 273 new MutationObserver(() => | 290 new MutationObserver(() => |
| 274 { | 291 { |
| 275 for (let element of document.querySelectorAll(selector)) | 292 for (let element of document.querySelectorAll(searchSelector)) |
| 276 { | 293 { |
| 277 if (element.textContent.includes(search)) | 294 if (element.textContent.includes(search)) |
| 278 hideElement(element); | 295 hideAncestor(element, selector); |
| 279 } | 296 } |
| 280 }) | 297 }) |
| 281 .observe(document, {childList: true, characterData: true, subtree: true}); | 298 .observe(document, {childList: true, characterData: true, subtree: true}); |
| 282 } | 299 } |
| 283 | 300 |
| 284 exports["hide-if-contains"] = hideIfContains; | 301 exports["hide-if-contains"] = hideIfContains; |
| 285 | 302 |
| 286 /** | 303 /** |
| 287 * Readds to the document any removed HTML elements that match a CSS selector. | 304 * Readds to the document any removed HTML elements that match a CSS selector. |
| 288 * | 305 * |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 306 // We don't have the location of the element in its former parent, | 323 // We don't have the location of the element in its former parent, |
| 307 // but it's usually OK to just add it at the end. | 324 // but it's usually OK to just add it at the end. |
| 308 mutation.target.appendChild(node); | 325 mutation.target.appendChild(node); |
| 309 } | 326 } |
| 310 } | 327 } |
| 311 } | 328 } |
| 312 }); | 329 }); |
| 313 } | 330 } |
| 314 | 331 |
| 315 exports.readd = readd; | 332 exports.readd = readd; |
| OLD | NEW |