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

Delta Between Two Patch Sets: lib/contentFilterModule.js

Issue 29784555: Issue 6665 - Abstract element hiding container logic into its own module Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Rebase Created May 17, 2018, 5:31 a.m.
Right Patch Set: Move base class into lib/contentFilterModule.js Created Aug. 15, 2018, 8:56 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | lib/elemHide.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH
4 *
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
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 "use strict";
19
20 /**
21 * @fileOverview Base implementation for content filter modules.
22 */
23
24 const {ElemHideExceptions} = require("./elemHideExceptions");
25
26 /**
27 * Map to be used instead when a filter has a blank domains property.
28 * @type {Map.<string,boolean>}
29 * @const
30 */
31 let defaultDomains = new Map([["", true]]);
32
33 /**
34 * Base class for content filter modules
35 * @class
36 */
37 function ContentFilterModule()
38 {
39 this._filtersByDomain = new Map();
40 this._filterBySelector = new Map();
41 this._unconditionalSelectors = null;
42 this._knownFilters = new Set();
43
44 ElemHideExceptions.on("added", this._onExceptionAdded.bind(this));
45 }
46
47 ContentFilterModule.prototype = {
48 /**
49 * Lookup table, active flag, by filter by domain.
50 * (Only contains filters that aren't unconditionally matched for all
51 * domains.)
52 * @type {Map.<string,Map.<Filter,boolean>>}
53 */
54 _filtersByDomain: null,
55
56 /**
57 * Lookup table, filter by selector. (Only used for selectors that are
58 * unconditionally matched for all domains.)
59 * @type {Map.<string,Filter>}
60 */
61 _filterBySelector: null,
62
63 /**
64 * This array caches the keys of filterBySelector table (selectors
65 * which unconditionally apply on all domains). It will be null if the
66 * cache needs to be rebuilt.
67 * @type {?string[]}
68 */
69 _unconditionalSelectors: null,
70
71 /**
72 * Set containing known content filters
73 * @type {Set.<ContentFilter>}
74 */
75 _knownFilters: null,
76
77 /**
78 * Adds a filter to the lookup table of filters by domain.
79 * @param {Filter} filter
80 */
81 _addToFiltersByDomain(filter)
82 {
83 let domains = filter.domains || defaultDomains;
84 for (let [domain, isIncluded] of domains)
85 {
86 // There's no need to note that a filter is generically disabled.
87 if (!isIncluded && domain == "")
88 continue;
89
90 let filters = this._filtersByDomain.get(domain);
91 if (!filters)
92 this._filtersByDomain.set(domain, filters = new Map());
93 filters.set(filter, isIncluded);
94 }
95 },
96
97 /**
98 * Returns a list of selectors that apply on each website unconditionally.
99 * @returns {string[]}
100 */
101 _getUnconditionalSelectors()
102 {
103 if (!this._unconditionalSelectors)
104 this._unconditionalSelectors = [...this._filterBySelector.keys()];
105
106 return this._unconditionalSelectors;
107 },
108
109 /**
110 * Handles the event when a new element hiding exception has been added
111 * @param {ElemHideException} exception
112 */
113 _onExceptionAdded(exception)
114 {
115 let {selector} = exception;
116
117 // If this is the first exception for a previously unconditionally applied
118 // element hiding selector we need to take care to update the lookups.
119 let unconditionalFilterForSelector = this._filterBySelector.get(selector);
120 if (unconditionalFilterForSelector)
121 {
122 this._addToFiltersByDomain(unconditionalFilterForSelector);
123 this._filterBySelector.delete(selector);
124 this._unconditionalSelectors = null;
125 }
126 },
127
128 /**
129 * Removes all known filters
130 */
131 clear()
132 {
133 for (let collection of [this._filtersByDomain, this._filterBySelector,
134 this._knownFilters])
hub 2018/08/23 16:05:38 I'd be for using forEach() here.
135 {
136 collection.clear();
137 }
138
139 this._unconditionalSelectors = null;
140 },
141
142 /**
143 * Add a new content filter
144 * @param {ContentFilter} filter
145 */
146 add(filter)
147 {
148 if (this._knownFilters.has(filter))
149 return;
150
151 let {selector} = filter;
152
153 if (!(filter.domains || ElemHideExceptions.hasExceptions(selector)))
154 {
155 // The new filter's selector is unconditionally applied to all domains
156 this._filterBySelector.set(selector, filter);
157 this._unconditionalSelectors = null;
158 }
159 else
160 {
161 // The new filter's selector only applies to some domains
162 this._addToFiltersByDomain(filter);
163 }
164
165 this._knownFilters.add(filter);
166 },
167
168 /**
169 * Removes a content filter
170 * @param {ContentFilter} filter
171 */
172 remove(filter)
173 {
174 if (!this._knownFilters.has(filter))
175 return;
176
177 let {selector} = filter;
178
179 // Unconditially applied content filters
180 if (this._filterBySelector.get(selector) == filter)
181 {
182 this._filterBySelector.delete(selector);
183 this._unconditionalSelectors = null;
184 }
185 // Conditionally applied content filters
186 else
187 {
188 let domains = filter.domains || defaultDomains;
189 for (let domain of domains.keys())
190 {
191 let filters = this._filtersByDomain.get(domain);
192 if (filters)
193 filters.delete(filter);
194 }
195 }
196
197 this._knownFilters.delete(filter);
198 }
199 };
200
201 exports.ContentFilterModule = ContentFilterModule;
LEFTRIGHT
« no previous file | lib/elemHide.js » ('j') | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld