Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: lib/content/snippets.js

Issue 29833630: Issue 6798 - Implement hide-if-shadow-contains snippet (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Created July 19, 2018, 2:29 a.m.
Right Patch Set: Remove premature hardening Created July 19, 2018, 4:03 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
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
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);
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld