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

Side by Side Diff: lib/elemHide.js

Issue 29893618: Issue 6957 - Return common style sheet for unknown domains (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Maintain only known exception domains Created Sept. 28, 2018, 8:51 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 let unconditionalSelectors = null; 56 let unconditionalSelectors = null;
57 57
58 /** 58 /**
59 * The default style sheet that applies on all domains. This is based on the 59 * The default style sheet that applies on all domains. This is based on the
60 * value of <code>{@link unconditionalSelectors}</code>. 60 * value of <code>{@link unconditionalSelectors}</code>.
61 * @type {?string} 61 * @type {?string}
62 */ 62 */
63 let defaultStyleSheet = null; 63 let defaultStyleSheet = null;
64 64
65 /** 65 /**
66 * The common style sheet that applies on all unknown domains. This is a
67 * concatenation of the default style sheet and an additional style sheet based
68 * on selectors from all generic filters that are not in the
69 * <code>{@link unconditionalSelectors}</code> list.
70 * @type {?string}
71 */
72 let commonStyleSheet = null;
73
74 /**
66 * Map to be used instead when a filter has a blank domains property. 75 * Map to be used instead when a filter has a blank domains property.
67 * @type {Map.<string,boolean>} 76 * @type {Map.<string,boolean>}
68 * @const 77 * @const
69 */ 78 */
70 let defaultDomains = new Map([["", true]]); 79 let defaultDomains = new Map([["", true]]);
71 80
72 /** 81 /**
73 * Set containing known element hiding filters 82 * Set containing known element hiding filters
74 * @type {Set.<ElemHideFilter>} 83 * @type {Set.<ElemHideFilter>}
75 */ 84 */
76 let knownFilters = new Set(); 85 let knownFilters = new Set();
77 86
78 /** 87 /**
88 * All domains known to occur in exceptions
89 * @type {Set.<string>}
90 */
91 let knownExceptionDomains = new Set();
92
93 /**
94 * Returns the suffix of the given domain that is known. If no suffix is known,
95 * an empty string is returned.
96 * @param {?string} domain
97 * @returns {string}
98 */
99 function getKnownSuffix(domain)
100 {
101 if (domain[domain.length - 1] == ".")
102 domain = domain.replace(/\.+$/, "");
103
104 domain = domain.toLowerCase();
105
106 while (domain && !filtersByDomain.has(domain) &&
107 !knownExceptionDomains.has(domain))
108 {
109 let index = domain.indexOf(".");
110 domain = index == -1 ? "" : domain.substring(index + 1);
111 }
112
113 return domain;
114 }
115
116 /**
79 * Adds a filter to the lookup table of filters by domain. 117 * Adds a filter to the lookup table of filters by domain.
80 * @param {Filter} filter 118 * @param {Filter} filter
81 */ 119 */
82 function addToFiltersByDomain(filter) 120 function addToFiltersByDomain(filter)
83 { 121 {
84 let domains = filter.domains || defaultDomains; 122 let domains = filter.domains || defaultDomains;
85 for (let [domain, isIncluded] of domains) 123 for (let [domain, isIncluded] of domains)
86 { 124 {
87 // There's no need to note that a filter is generically disabled. 125 // There's no need to note that a filter is generically disabled.
88 if (!isIncluded && domain == "") 126 if (!isIncluded && domain == "")
(...skipping 13 matching lines...) Expand all
102 function getUnconditionalSelectors() 140 function getUnconditionalSelectors()
103 { 141 {
104 if (!unconditionalSelectors) 142 if (!unconditionalSelectors)
105 unconditionalSelectors = [...filterBySelector.keys()]; 143 unconditionalSelectors = [...filterBySelector.keys()];
106 144
107 return unconditionalSelectors; 145 return unconditionalSelectors;
108 } 146 }
109 147
110 /** 148 /**
111 * Returns the list of selectors that apply on a given domain from the subset 149 * Returns the list of selectors that apply on a given domain from the subset
112 * of filters that do not apply unconditionally on all domains. 150 * of filters that do not apply unconditionally on all domains. If no domain is
151 * given, includes only selectors from generic filters.
113 * 152 *
114 * @param {string} domain The domain. 153 * @param {string} [domain] The domain.
115 * @param {boolean} [specificOnly=false] Whether selectors from generic filters 154 * @param {boolean} [specificOnly=false] Whether selectors from generic filters
116 * should be included. 155 * should be included.
117 * 156 *
118 * @returns {Array.<string>} The list of selectors. 157 * @returns {Array.<string>} The list of selectors.
119 */ 158 */
120 function getConditionalSelectorsForDomain(domain, specificOnly = false) 159 function getConditionalSelectors(domain = "", specificOnly = false)
121 { 160 {
122 let selectors = []; 161 let selectors = [];
123 162
124 let excluded = new Set(); 163 let excluded = new Set();
125 let currentDomain = domain ? domain.replace(/\.+$/, "").toLowerCase() : ""; 164 let currentDomain = domain;
126 165
127 // This code is a performance hot-spot, which is why we've made certain 166 // This code is a performance hot-spot, which is why we've made certain
128 // micro-optimisations. Please be careful before making changes. 167 // micro-optimisations. Please be careful before making changes.
129 while (true) 168 while (true)
130 { 169 {
131 if (specificOnly && currentDomain == "") 170 if (specificOnly && currentDomain == "")
132 break; 171 break;
133 172
134 let filters = filtersByDomain.get(currentDomain); 173 let filters = filtersByDomain.get(currentDomain);
135 if (filters) 174 if (filters)
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 * @returns {string} 206 * @returns {string}
168 */ 207 */
169 function getDefaultStyleSheet() 208 function getDefaultStyleSheet()
170 { 209 {
171 if (!defaultStyleSheet) 210 if (!defaultStyleSheet)
172 defaultStyleSheet = createStyleSheet(getUnconditionalSelectors()); 211 defaultStyleSheet = createStyleSheet(getUnconditionalSelectors());
173 212
174 return defaultStyleSheet; 213 return defaultStyleSheet;
175 } 214 }
176 215
177 ElemHideExceptions.on("added", ({selector}) => 216 /**
217 * Returns the common style sheet that applies on all unknown domains.
218 * @returns {string}
219 */
220 function getCommonStyleSheet()
178 { 221 {
222 if (!commonStyleSheet)
223 {
224 commonStyleSheet = getDefaultStyleSheet() +
225 createStyleSheet(getConditionalSelectors());
226 }
227
228 return commonStyleSheet;
229 }
230
231 ElemHideExceptions.on("added", ({domains, selector}) =>
232 {
233 commonStyleSheet = null;
234
235 if (domains)
236 {
237 for (let domain of domains.keys())
238 {
239 // Note: Once an exception domain is known it never becomes unknown, even
240 // when all the exceptions containing that domain are removed. This is a
241 // best-case optimization.
242 if (domain != "")
243 knownExceptionDomains.add(domain);
244 }
245 }
246
179 // If this is the first exception for a previously unconditionally applied 247 // If this is the first exception for a previously unconditionally applied
180 // element hiding selector we need to take care to update the lookups. 248 // element hiding selector we need to take care to update the lookups.
181 let unconditionalFilterForSelector = filterBySelector.get(selector); 249 let unconditionalFilterForSelector = filterBySelector.get(selector);
182 if (unconditionalFilterForSelector) 250 if (unconditionalFilterForSelector)
183 { 251 {
184 addToFiltersByDomain(unconditionalFilterForSelector); 252 addToFiltersByDomain(unconditionalFilterForSelector);
185 filterBySelector.delete(selector); 253 filterBySelector.delete(selector);
186 unconditionalSelectors = null; 254 unconditionalSelectors = null;
187 defaultStyleSheet = null; 255 defaultStyleSheet = null;
188 } 256 }
189 }); 257 });
190 258
191 /** 259 /**
192 * Container for element hiding filters 260 * Container for element hiding filters
193 * @class 261 * @class
194 */ 262 */
195 exports.ElemHide = { 263 exports.ElemHide = {
196 /** 264 /**
197 * Removes all known filters 265 * Removes all known filters
198 */ 266 */
199 clear() 267 clear()
200 { 268 {
201 for (let collection of [filtersByDomain, filterBySelector, knownFilters]) 269 commonStyleSheet = null;
270
271 for (let collection of [filtersByDomain, filterBySelector, knownFilters,
272 knownExceptionDomains])
273 {
202 collection.clear(); 274 collection.clear();
275 }
203 276
204 unconditionalSelectors = null; 277 unconditionalSelectors = null;
205 defaultStyleSheet = null; 278 defaultStyleSheet = null;
206 279
207 filterNotifier.emit("elemhideupdate"); 280 filterNotifier.emit("elemhideupdate");
208 }, 281 },
209 282
210 /** 283 /**
211 * Add a new element hiding filter 284 * Add a new element hiding filter
212 * @param {ElemHideFilter} filter 285 * @param {ElemHideFilter} filter
213 */ 286 */
214 add(filter) 287 add(filter)
215 { 288 {
216 if (knownFilters.has(filter)) 289 if (knownFilters.has(filter))
217 return; 290 return;
218 291
292 commonStyleSheet = null;
293
219 let {selector} = filter; 294 let {selector} = filter;
220 295
221 if (!(filter.domains || ElemHideExceptions.hasExceptions(selector))) 296 if (!(filter.domains || ElemHideExceptions.hasExceptions(selector)))
222 { 297 {
223 // The new filter's selector is unconditionally applied to all domains 298 // The new filter's selector is unconditionally applied to all domains
224 filterBySelector.set(selector, filter); 299 filterBySelector.set(selector, filter);
225 unconditionalSelectors = null; 300 unconditionalSelectors = null;
226 defaultStyleSheet = null; 301 defaultStyleSheet = null;
227 } 302 }
228 else 303 else
229 { 304 {
230 // The new filter's selector only applies to some domains 305 // The new filter's selector only applies to some domains
231 addToFiltersByDomain(filter); 306 addToFiltersByDomain(filter);
232 } 307 }
233 308
234 knownFilters.add(filter); 309 knownFilters.add(filter);
235 filterNotifier.emit("elemhideupdate"); 310 filterNotifier.emit("elemhideupdate");
236 }, 311 },
237 312
238 /** 313 /**
239 * Removes an element hiding filter 314 * Removes an element hiding filter
240 * @param {ElemHideFilter} filter 315 * @param {ElemHideFilter} filter
241 */ 316 */
242 remove(filter) 317 remove(filter)
243 { 318 {
244 if (!knownFilters.has(filter)) 319 if (!knownFilters.has(filter))
245 return; 320 return;
246 321
322 commonStyleSheet = null;
323
247 let {selector} = filter; 324 let {selector} = filter;
248 325
249 // Unconditially applied element hiding filters 326 // Unconditially applied element hiding filters
250 if (filterBySelector.get(selector) == filter) 327 if (filterBySelector.get(selector) == filter)
251 { 328 {
252 filterBySelector.delete(selector); 329 filterBySelector.delete(selector);
253 unconditionalSelectors = null; 330 unconditionalSelectors = null;
254 defaultStyleSheet = null; 331 defaultStyleSheet = null;
255 } 332 }
256 // Conditionally applied element hiding filters 333 // Conditionally applied element hiding filters
(...skipping 29 matching lines...) Expand all
286 * 363 *
287 * @param {string} domain The domain. 364 * @param {string} domain The domain.
288 * @param {boolean} [specificOnly=false] Whether selectors from generic 365 * @param {boolean} [specificOnly=false] Whether selectors from generic
289 * filters should be included. 366 * filters should be included.
290 * 367 *
291 * @returns {ElemHideStyleSheet} An object containing the CSS code and the 368 * @returns {ElemHideStyleSheet} An object containing the CSS code and the
292 * list of selectors. 369 * list of selectors.
293 */ 370 */
294 generateStyleSheetForDomain(domain, specificOnly = false) 371 generateStyleSheetForDomain(domain, specificOnly = false)
295 { 372 {
296 let selectors = getConditionalSelectorsForDomain(domain, specificOnly); 373 let knownSuffix = domain ? getKnownSuffix(domain) : "";
374
375 let selectors = getConditionalSelectors(knownSuffix, specificOnly);
297 let code = specificOnly ? createStyleSheet(selectors) : 376 let code = specificOnly ? createStyleSheet(selectors) :
298 (getDefaultStyleSheet() + createStyleSheet(selectors)); 377 knownSuffix == "" ? getCommonStyleSheet() :
378 (getDefaultStyleSheet() + createStyleSheet(selectors));
299 379
300 if (!specificOnly) 380 if (!specificOnly)
301 selectors = getUnconditionalSelectors().concat(selectors); 381 selectors = getUnconditionalSelectors().concat(selectors);
302 382
303 return {code, selectors}; 383 return {code, selectors};
304 } 384 }
305 }; 385 };
306 386
307 /** 387 /**
308 * Splits a list of selectors into groups determined by the value of 388 * Splits a list of selectors into groups determined by the value of
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 { 435 {
356 let styleSheet = ""; 436 let styleSheet = "";
357 437
358 for (let selectorGroup of splitSelectors(selectors)) 438 for (let selectorGroup of splitSelectors(selectors))
359 styleSheet += createRule(selectorGroup); 439 styleSheet += createRule(selectorGroup);
360 440
361 return styleSheet; 441 return styleSheet;
362 } 442 }
363 443
364 exports.createStyleSheet = createStyleSheet; 444 exports.createStyleSheet = createStyleSheet;
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld