Left: | ||
Right: |
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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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(() => |
kzar
2018/07/19 13:02:09
I wonder if we should just remove the element, ins
Manish Jethani
2018/07/19 13:30:09
I think it's probably best to mess as little as re
kzar
2018/07/19 13:38:11
Acknowledged.
| |
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 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
153 * Hides any HTML element or one of its ancestors matching a CSS selector if | 153 * Hides any HTML element or one of its ancestors matching a CSS selector if |
154 * the text content of the element's shadow contains a given string. | 154 * the text content of the element's shadow contains a given string. |
155 * | 155 * |
156 * @param {string} search The string to look for in every HTML element's | 156 * @param {string} search The string to look for in every HTML element's |
157 * shadow. | 157 * shadow. |
158 * @param {string} selector The CSS selector that an HTML element must match | 158 * @param {string} selector The CSS selector that an HTML element must match |
159 * for it to be hidden. | 159 * for it to be hidden. |
160 */ | 160 */ |
161 function hideIfShadowContains(search, selector = "*") | 161 function hideIfShadowContains(search, selector = "*") |
162 { | 162 { |
163 let originalAttachShadow = Element.prototype.attachShadow; | 163 let originalAttachShadow = Element.prototype.attachShadow; |
kzar
2018/07/19 16:11:41
With my suggestions below we can remove this line
| |
164 | 164 |
165 // If there's no Element.attachShadow API present then we don't care, it must | 165 // If there's no Element.attachShadow API present then we don't care, it must |
166 // be Firefox or an older version of Chrome. | 166 // be Firefox or an older version of Chrome. |
167 if (!originalAttachShadow) | 167 if (!originalAttachShadow) |
kzar
2018/07/19 16:11:41
`if (!Element.prototype.attachShadow)`
| |
168 return; | 168 return; |
169 | |
170 let applyOriginalAttachShadow = | |
171 originalAttachShadow.apply.bind(originalAttachShadow); | |
kzar
2018/07/19 13:02:09
This looks like an attempt at hardening the code t
Manish Jethani
2018/07/19 13:30:09
Yeah, I'm not really sure why this is needed. Even
kzar
2018/07/19 13:38:11
This reply kind of implies that you didn't write t
Manish Jethani
2018/07/19 14:20:54
No, it does not apply anything like that. I did wr
kzar
2018/07/19 15:02:52
Gotya, if the idea/code came from our inject.prelo
Manish Jethani
2018/07/19 15:28:34
OK, but why can't you just do this:
originalFun
kzar
2018/07/19 15:33:33
In case the website messes with `Function.prototyp
Manish Jethani
2018/07/19 15:39:57
I see, in that case I'd like to keep it. Reason: o
kzar
2018/07/19 15:52:40
Well, in that case, what about all the other APIs
Manish Jethani
2018/07/19 16:04:58
Fair enough, let's keep it simple for now and let'
| |
172 | 169 |
173 // Mutation observers mapped to their corresponding shadow roots and their | 170 // Mutation observers mapped to their corresponding shadow roots and their |
174 // hosts. | 171 // hosts. |
175 let shadows = new WeakMap(); | 172 let shadows = new WeakMap(); |
176 | 173 |
177 function observe(mutations, observer) | 174 function observe(mutations, observer) |
178 { | 175 { |
179 let {host, root} = shadows.get(observer) || {}; | 176 let {host, root} = shadows.get(observer) || {}; |
180 | 177 |
181 // Since it's a weak map, it's possible that either the element or its | 178 // Since it's a weak map, it's possible that either the element or its |
182 // shadow has been removed. | 179 // shadow has been removed. |
183 if (!host || !root) | 180 if (!host || !root) |
kzar
2018/07/19 13:02:09
I thought WeakMap just avoided memory leaks if the
Manish Jethani
2018/07/19 13:30:09
This is just a hypothesis, but I think that if eit
| |
184 return; | 181 return; |
185 | 182 |
186 // If the shadow contains the given text, check if the host or one of its | 183 // If the shadow contains the given text, check if the host or one of its |
187 // ancestors matches the selector; if a matching element is found, hide | 184 // ancestors matches the selector; if a matching element is found, hide |
188 // it. | 185 // it. |
189 if (root.textContent.includes(search)) | 186 if (root.textContent.includes(search)) |
190 { | 187 { |
191 let element = host; | 188 let element = host; |
192 | 189 |
193 do | 190 do |
194 { | 191 { |
195 if (element.matches(selector)) | 192 if (element.matches(selector)) |
196 { | 193 { |
197 hideElement(element); | 194 hideElement(element); |
198 break; | 195 break; |
199 } | 196 } |
200 } | 197 } |
201 while (element = element.parentElement); | 198 while (element = element.parentElement); |
202 } | 199 } |
203 } | 200 } |
204 | 201 |
205 Object.defineProperty(Element.prototype, "attachShadow", { | 202 Object.defineProperty(Element.prototype, "attachShadow", { |
206 value(...args) | 203 value(...args) |
207 { | 204 { |
208 // Create the shadow root first. It doesn't matter if it's a closed | 205 // Create the shadow root first. It doesn't matter if it's a closed |
209 // shadow root, we keep the reference in a weak map. | 206 // shadow root, we keep the reference in a weak map. |
210 let root = applyOriginalAttachShadow(this, args); | 207 let root = originalAttachShadow.apply(this, args); |
kzar
2018/07/19 16:11:41
`let root = this.attachShadow(...args);`
Manish Jethani
2018/07/19 16:15:10
Isn't this going to be an infinite loop? this.atta
kzar
2018/07/19 16:28:51
Oh yea, good point we're overwriting it ourselves.
| |
211 | 208 |
212 // Listen for relevant DOM mutations in the shadow. | 209 // Listen for relevant DOM mutations in the shadow. |
213 let observer = new MutationObserver(observe); | 210 let observer = new MutationObserver(observe); |
214 observer.observe(root, { | 211 observer.observe(root, { |
215 childList: true, | 212 childList: true, |
216 characterData: true, | 213 characterData: true, |
217 subtree: true | 214 subtree: true |
218 }); | 215 }); |
219 | 216 |
220 // Keep references to the shadow root and its host in a weak map. If | 217 // Keep references to the shadow root and its host in a weak map. If |
221 // either the shadow is detached or the host itself is removed from the | 218 // either the shadow is detached or the host itself is removed from the |
222 // DOM, the mutation observer too will be freed eventually and the entry | 219 // DOM, the mutation observer too will be freed eventually and the entry |
223 // will be removed. | 220 // will be removed. |
224 shadows.set(observer, {host: this, root}); | 221 shadows.set(observer, {host: this, root}); |
225 | 222 |
226 return root; | 223 return root; |
227 } | 224 } |
228 }); | 225 }); |
229 } | 226 } |
230 | 227 |
231 exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, | 228 exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, |
232 hideElement); | 229 hideElement); |
LEFT | RIGHT |