2
* This file is part of Adblock Plus <https://adblockplus.org/>,
3
* Copyright (C) 2006-2015 Eyeo GmbH
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.
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.
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/>.
19
* Fills a list of filter groups and keeps it updated.
20
* @param {Element} list richlistbox element to be filled
21
* @param {Node} template template to use for the groups
22
* @param {Function} filter filter to decide which lists should be included
23
* @param {Function} listener function to be called on changes
26
function ListManager(list, template, filter, listener)
29
this._template = template;
30
this._filter = filter;
31
this._listener = listener || function(){};
33
this._deck = this._list.parentNode;
35
this._list.listManager = this;
39
let proxy = function()
41
return me._onChange.apply(me, arguments);
43
FilterNotifier.addListener(proxy);
44
window.addEventListener("unload", function()
46
FilterNotifier.removeListener(proxy);
49
ListManager.prototype =
52
* List element being managed.
57
* Template used for the groups.
62
* Filter function to decide which subscriptions should be included.
67
* Function to be called whenever list contents change.
72
* Deck switching between list display and "no entries" message.
78
* Completely rebuilds the list.
82
// Remove existing entries if any
83
while (this._list.firstChild)
84
this._list.removeChild(this._list.firstChild);
86
// Now add all subscriptions
87
let subscriptions = FilterStorage.subscriptions.filter(this._filter, this);
88
if (subscriptions.length)
90
for (let subscription of subscriptions)
91
this.addSubscription(subscription, null);
93
// Make sure first list item is selected after list initialization
94
Utils.runAsync(() => this._list.selectItem(this._list.getItemAtIndex(this._list.getIndexOfFirstVisibleRow())));
97
this._deck.selectedIndex = (subscriptions.length ? 1 : 0);
102
* Adds a filter subscription to the list.
104
addSubscription: function(/**Subscription*/ subscription, /**Node*/ insertBefore) /**Node*/
106
let disabledFilters = 0;
107
for (let i = 0, l = subscription.filters.length; i < l; i++)
108
if (subscription.filters[i] instanceof ActiveFilter && subscription.filters[i].disabled)
111
let node = Templater.process(this._template, {
113
subscription: subscription,
114
isExternal: subscription instanceof ExternalSubscription,
115
downloading: Synchronizer.isExecuting(subscription.url),
116
disabledFilters: disabledFilters
119
this._list.insertBefore(node, insertBefore);
121
this._list.appendChild(node);
126
* Map indicating subscriptions that need their "disabledFilters" property to
127
* be updated by next updateDisabled() call.
130
_scheduledUpdateDisabled: null,
133
* Updates subscriptions that had some of their filters enabled/disabled.
135
updateDisabled: function()
137
let list = this._scheduledUpdateDisabled;
138
this._scheduledUpdateDisabled = null;
139
for (let url in list)
141
let subscription = Subscription.fromURL(url);
142
let subscriptionNode = Templater.getNodeForData(this._list, "subscription", subscription);
143
if (subscriptionNode)
145
let data = Templater.getDataForNode(subscriptionNode);
146
let disabledFilters = 0;
147
for (let i = 0, l = subscription.filters.length; i < l; i++)
148
if (subscription.filters[i] instanceof ActiveFilter && subscription.filters[i].disabled)
151
if (disabledFilters != data.disabledFilters)
153
data.disabledFilters = disabledFilters;
154
Templater.update(this._template, subscriptionNode);
156
if (!document.commandDispatcher.focusedElement)
164
* Subscriptions change processing.
165
* @see FilterNotifier.addListener()
167
_onChange: function(action, item, param1, param2)
169
if ((action == "subscription.added" || action == "subscription.removed") && item.url == Prefs.subscriptions_exceptionsurl)
170
E("acceptableAds").checked = FilterStorage.subscriptions.some(s => s.url == Prefs.subscriptions_exceptionsurl);
172
if (action == "filter.disabled")
174
if (this._scheduledUpdateDisabled == null)
176
this._scheduledUpdateDisabled = Object.create(null);
177
Utils.runAsync(() => this.updateDisabled());
179
for (let i = 0; i < item.subscriptions.length; i++)
180
this._scheduledUpdateDisabled[item.subscriptions[i].url] = true;
184
if (action != "load" && !this._filter(item))
194
case "subscription.added":
196
let index = FilterStorage.subscriptions.indexOf(item);
199
let insertBefore = null;
200
for (index++; index < FilterStorage.subscriptions.length && !insertBefore; index++)
201
insertBefore = Templater.getNodeForData(this._list, "subscription", FilterStorage.subscriptions[index]);
202
this.addSubscription(item, insertBefore);
203
this._deck.selectedIndex = 1;
208
case "subscription.removed":
210
let node = Templater.getNodeForData(this._list, "subscription", item);
213
let newSelection = node.nextSibling || node.previousSibling;
214
node.parentNode.removeChild(node);
215
if (!this._list.firstChild)
217
this._deck.selectedIndex = 0;
218
this._list.selectedIndex = -1;
220
else if (newSelection)
222
this._list.ensureElementIsVisible(newSelection);
223
this._list.selectedItem = newSelection;
229
case "subscription.moved":
231
let node = Templater.getNodeForData(this._list, "subscription", item);
234
node.parentNode.removeChild(node);
235
let insertBefore = null;
236
let index = FilterStorage.subscriptions.indexOf(item);
238
for (index++; index < FilterStorage.subscriptions.length && !insertBefore; index++)
239
insertBefore = Templater.getNodeForData(this._list, "subscription", FilterStorage.subscriptions[index]);
240
this._list.insertBefore(node, insertBefore);
241
this._list.ensureElementIsVisible(node);
246
case "subscription.title":
247
case "subscription.disabled":
248
case "subscription.homepage":
249
case "subscription.lastDownload":
250
case "subscription.downloadStatus":
252
let subscriptionNode = Templater.getNodeForData(this._list, "subscription", item);
253
if (subscriptionNode)
255
Templater.getDataForNode(subscriptionNode).downloading = Synchronizer.isExecuting(item.url);
256
Templater.update(this._template, subscriptionNode);
258
if (!document.commandDispatcher.focusedElement)
264
case "subscription.fixedTitle":
266
SubscriptionActions.updateCommands();
269
case "subscription.updated":
271
if (this._scheduledUpdateDisabled == null)
273
this._scheduledUpdateDisabled = Object.create(null);
274
Utils.runAsync(() => this.updateDisabled());
276
this._scheduledUpdateDisabled[item.url] = true;
284
* Attaches list managers to the lists.
286
ListManager.init = function()
288
new ListManager(E("subscriptions"),
289
E("subscriptionTemplate"),
290
s => s instanceof RegularSubscription && !(ListManager.acceptableAdsCheckbox && s.url == Prefs.subscriptions_exceptionsurl),
291
SubscriptionActions.updateCommands);
292
new ListManager(E("groups"),
294
s => s instanceof SpecialSubscription,
295
SubscriptionActions.updateCommands);
296
E("acceptableAds").checked = FilterStorage.subscriptions.some(s => s.url == Prefs.subscriptions_exceptionsurl);
297
E("acceptableAds").parentNode.hidden = !ListManager.acceptableAdsCheckbox;
301
* Defines whether the "acceptable ads" subscription needs special treatment.
304
ListManager.acceptableAdsCheckbox = Prefs.subscriptions_exceptionscheckbox;
307
* Adds or removes filter subscription allowing acceptable ads.
309
ListManager.allowAcceptableAds = function(/**Boolean*/ allow)
311
let subscription = Subscription.fromURL(Prefs.subscriptions_exceptionsurl);
315
subscription.disabled = false;
316
subscription.title = "Allow non-intrusive advertising";
319
FilterStorage.addSubscription(subscription);
320
if (subscription instanceof DownloadableSubscription && !subscription.lastDownload)
321
Synchronizer.execute(subscription);
324
FilterStorage.removeSubscription(subscription);
327
window.addEventListener("load", ListManager.init, false);