23
23
* ***** END LICENSE BLOCK ***** */
25
var effectiveTLD = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
26
var RequestList = abp.RequestList;
25
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
28
27
// Main browser window
29
28
var mainWin = parent;
31
30
// The window handler currently in use
31
var requestNotifier = null;
34
33
var cacheSession = null;
35
34
var noFlash = false;
37
// Matchers for disabled filters
38
var disabledBlacklistMatcher = new abp.Matcher();
39
var disabledWhitelistMatcher = new abp.Matcher();
36
// Matcher for disabled filters
37
var disabledMatcher = new CombinedMatcher();
39
// Cached string values
40
var docDomainThirdParty = null;
41
var docDomainFirstParty = null;
41
43
var abpHooks = null;
44
* Cached value of "enabled" preference, for onPrefChange.
46
var oldEnabled = abp.prefs.enabled;
45
let lastSelectionProp = "abpSelected" + RequestNotifier.getDataSeed();
48
docDomainThirdParty = document.documentElement.getAttribute("docDomainThirdParty");
49
docDomainFirstParty = document.documentElement.getAttribute("docDomainFirstParty");
49
51
var list = E("list");
50
52
list.view = treeView;
52
54
// Restore previous state
53
var params = abp.getParams();
55
var params = Utils.getParams();
54
56
if (params && params.filter)
56
58
E("searchField").value = params.filter;
88
90
abpHooks = mainWin.document.getElementById("abp-hooks");
89
91
window.__defineGetter__("content", function() {return abpHooks.getBrowser().contentWindow;});
91
// Install item listener
92
RequestList.addListener(handleItemChange);
94
// Initialize matchers for disabled filters
93
// Initialize matcher for disabled filters
95
94
reloadDisabledFilters();
96
filterStorage.addFilterObserver(reloadDisabledFilters);
97
filterStorage.addSubscriptionObserver(reloadDisabledFilters);
98
abp.prefs.addListener(onPrefChange);
95
FilterStorage.addFilterObserver(reloadDisabledFilters);
96
FilterStorage.addSubscriptionObserver(reloadDisabledFilters);
97
Prefs.addListener(onPrefChange);
100
99
// Activate flasher
101
100
list.addEventListener("select", onSelectionChange, false);
103
// Retrieve data for the window
104
wndData = RequestList.getDataForWindow(window.content);
105
treeView.setData(wndData.getAllLocations());
106
if (wndData.lastSelection) {
108
treeView.selectItem(wndData.lastSelection);
103
handleLocationChange();
112
// Install a handler for tab changes
113
abpHooks.getBrowser().addEventListener("select", handleTabChange, false);
105
// Install a progress listener to catch location changes
106
abpHooks.getBrowser().addProgressListener(progressListener);
116
109
// To be called for a detached window when the main window has been closed
121
114
// To be called on unload
122
115
function cleanUp() {
127
RequestList.removeListener(handleItemChange);
128
filterStorage.removeFilterObserver(reloadDisabledFilters);
129
filterStorage.removeSubscriptionObserver(reloadDisabledFilters);
130
abp.prefs.removeListener(onPrefChange);
117
requestNotifier.shutdown();
118
FilterStorage.removeFilterObserver(reloadDisabledFilters);
119
FilterStorage.removeSubscriptionObserver(reloadDisabledFilters);
120
Prefs.removeListener(onPrefChange);
132
abpHooks.getBrowser().removeEventListener("select", handleTabChange, false);
122
abpHooks.getBrowser().removeProgressListener(progressListener);
133
123
mainWin.removeEventListener("unload", mainUnload, false);
137
127
* Tracks preference changes, calls reloadDisabledFilters whenever Adblock Plus
138
128
* is enabled/disabled.
140
function onPrefChange()
130
function onPrefChange(name)
142
if (abp.prefs.enabled != oldEnabled)
144
oldEnabled = abp.prefs.enabled;
132
if (name == "enabled")
145
133
reloadDisabledFilters();
150
* Updates matchers for disabled filters (global disabledBlacklistMatcher and
151
* disabledWhitelistMatcher variables), called on each filter change.
137
* Updates matcher for disabled filters (global disabledMatcher variable),
138
* called on each filter change.
153
140
function reloadDisabledFilters()
155
disabledBlacklistMatcher.clear();
156
disabledWhitelistMatcher.clear();
142
disabledMatcher.clear();
158
if (abp.prefs.enabled)
160
for each (let subscription in filterStorage.subscriptions)
146
for each (let subscription in FilterStorage.subscriptions)
162
148
if (subscription.disabled)
165
151
for each (let filter in subscription.filters)
166
if (filter instanceof abp.RegExpFilter && filter.disabled)
167
(filter instanceof abp.BlockingFilter ? disabledBlacklistMatcher : disabledWhitelistMatcher).add(filter);
152
if (filter instanceof RegExpFilter && filter.disabled)
153
disabledMatcher.add(filter);
171
treeView.setData(treeView.allData);
157
treeView.updateFilters();
174
160
// Called whenever list selection changes - triggers flasher
178
164
E("copy-command").removeAttribute("disabled");
180
166
E("copy-command").setAttribute("disabled", "true");
182
wndData.lastSelection = item;
168
if (item && window.content)
170
let key = item.location + " " + item.type + " " + item.docDomain;
171
window.content.document.setUserData(lastSelectionProp, key, null);
172
treeView.itemToSelect = null;
185
176
flasher.flash(item ? item.nodes : null);
188
function handleItemChange(wnd, type, data, item) {
189
// Check whether this applies to us
190
if (wnd != window.content)
193
// Maybe we got called twice
194
if (type == "select" && data == wndData)
197
// If adding something from a new data container - select it
198
if (type == "add" && data != wndData)
202
var filterSuggestions = E("suggestionsList");
203
if (type == "clear") {
204
// Current document has been unloaded, clear list
206
treeView.setData([]);
208
else if (type == "select" || type == "refresh") {
209
// We moved to a different document, reload list
211
treeView.setData(wndData.getAllLocations());
213
else if (type == "invalidate")
214
treeView.boxObject.invalidate();
215
else if (type == "add")
216
treeView.addItem(item);
219
function handleTabChange() {
220
wndData = RequestList.getDataForWindow(window.content);
221
treeView.setData(wndData.getAllLocations());
222
if (wndData.lastSelection) {
224
treeView.selectItem(wndData.lastSelection);
179
function handleLocationChange()
182
requestNotifier.shutdown();
184
treeView.clearData();
185
treeView.itemToSelect = window.content.document.getUserData(lastSelectionProp);
186
requestNotifier = new RequestNotifier(window.content, function(wnd, node, item, scanComplete)
189
treeView.addItem(node, item, scanComplete);
229
193
// Fills a box with text splitting it up into multiple lines if necessary
272
236
setMultilineContent(E("tooltipAddress"), item.location);
274
238
var type = item.localizedDescr;
275
if (filter && filter instanceof abp.WhitelistFilter)
239
if (filter && filter instanceof WhitelistFilter)
276
240
type += " " + E("tooltipType").getAttribute("whitelisted");
277
241
else if (filter && item.typeDescr != "ELEMHIDE")
278
242
type += " " + E("tooltipType").getAttribute("filtered");
282
246
E("tooltipSize").setAttribute("value", size.join(" x "));
284
E("tooltipDocDomain").setAttribute("value", item.docDomain);
248
E("tooltipDocDomain").setAttribute("value", item.docDomain + " " + (item.thirdParty ? docDomainThirdParty : docDomainFirstParty));
289
setMultilineContent(E("tooltipFilter"), filter.text);
253
let filterField = E("tooltipFilter");
254
setMultilineContent(filterField, filter.text);
257
let disabledText = document.createElement("description");
258
disabledText.className = "disabledTextLabel";
259
disabledText.textContent = filterField.getAttribute("disabledText");
260
filterField.appendChild(disabledText);
290
263
if (subscriptions.length)
292
265
let sourceElement = E("tooltipFilterSource");
293
266
while (sourceElement.firstChild)
294
267
sourceElement.removeChild(sourceElement.firstChild);
295
for each (let subscription in subscriptions)
296
setMultilineContent(sourceElement, subscription.title, true);
268
for (let i = 0; i < subscriptions.length; i++)
269
setMultilineContent(sourceElement, subscriptions[i].title, true);
300
var showPreview = prefs.previewimages && !("tooltip" in item);
301
showPreview = showPreview && (item.typeDescr == "IMAGE" || item.typeDescr == "BACKGROUND");
302
showPreview = showPreview && (!item.filter || item.filter instanceof abp.WhitelistFilter);
273
var showPreview = Prefs.previewimages && !("tooltip" in item);
274
showPreview = showPreview && item.typeDescr == "IMAGE";
275
showPreview = showPreview && (!item.filter || item.filter instanceof WhitelistFilter);
303
276
if (showPreview) {
304
277
// Check whether image is in cache (stolen from ImgLikeOpera)
305
278
if (!cacheSession) {
364
337
menuItem.setAttribute("label", menuItem.getAttribute("labeltempl").replace(/\?1\?/, filter.text));
365
338
menuItem.hidden = false;
367
if (filter instanceof abp.ActiveFilter && !filter.disabled && filter.subscriptions.length && !filter.subscriptions.some(function(subscription) !(subscription instanceof abp.SpecialSubscription)))
340
if (filter instanceof ActiveFilter && !filter.disabled && filter.subscriptions.length && !filter.subscriptions.some(function(subscription) !(subscription instanceof SpecialSubscription)))
369
342
let domain = null;
371
344
domain = content.location.host;
372
domain = effectiveTLD.getBaseDomainFromHost(domain);
345
domain = Utils.effectiveTLD.getBaseDomainFromHost(domain);
375
348
if (domain && !filter.isActiveOnlyOnDomain(domain))
387
E("contextWhitelist").hidden = ("tooltip" in item || !item.filter || item.filter.disabled || item.filter instanceof abp.WhitelistFilter || item.typeDescr == "ELEMHIDE");
360
E("contextWhitelist").hidden = ("tooltip" in item || !item.filter || item.filter.disabled || item.filter instanceof WhitelistFilter || item.typeDescr == "ELEMHIDE");
388
361
E("contextBlock").hidden = !E("contextWhitelist").hidden;
389
362
E("contextBlock").setAttribute("disabled", "filter" in item && item.filter && !item.filter.disabled);
390
363
E("contextEditFilter").setAttribute("disabled", !("filter" in item && item.filter));
391
364
E("contextOpen").setAttribute("disabled", "tooltip" in item || item.typeDescr == "ELEMHIDE");
392
E("contextFlash").setAttribute("disabled", "tooltip" in item || !(item.typeDescr in visual) || (item.filter && !item.filter.disabled && !(item.filter instanceof abp.WhitelistFilter)));
365
E("contextFlash").setAttribute("disabled", "tooltip" in item || !(item.typeDescr in visual) || (item.filter && !item.filter.disabled && !(item.filter instanceof WhitelistFilter)));
393
366
E("contextCopyFilter").setAttribute("disabled", !allItems.some(function(item) {return "filter" in item && item.filter}));
433
406
function openInTab(item, /**Event*/ event)
436
item = treeView.getSelectedItem();
437
if (!item || item.typeDescr == "ELEMHIDE")
440
abp.loadInBrowser(item.location, mainWin, event);
408
let items = (item ? [item] : treeView.getAllSelectedItems());
409
for each (let item in items)
411
if (item && item.typeDescr != "ELEMHIDE")
412
Utils.loadInBrowser(item.location, mainWin, event);
443
416
function doBlock() {
447
417
var item = treeView.getSelectedItem();
448
418
if (!item || item.typeDescr == "ELEMHIDE")
451
421
var filter = null;
452
if ("filter" in item && item.filter && !item.filter.disabled)
422
if (item.filter && !item.filter.disabled)
453
423
filter = item.filter;
455
if (filter && filter instanceof abp.WhitelistFilter)
425
if (filter && filter instanceof WhitelistFilter)
458
openDialog("chrome://adblockplus/content/ui/composer.xul", "_blank", "chrome,centerscreen,resizable,dialog=no,dependent", window.content, item);
428
openDialog("chrome://adblockplus/content/ui/composer.xul", "_blank", "chrome,centerscreen,resizable,dialog=no,dependent", item.nodes, item.orig);
461
431
function editFilter() {
465
432
var item = treeView.getSelectedItem();
466
433
if (treeView.data && !treeView.data.length)
467
434
item = treeView.getDummyTooltip();
472
439
if (!("location") in item)
473
440
item.location = undefined
475
abp.openSettingsDialog(item.location, item.filter);
442
Utils.openSettingsDialog(item.location, item.filter);
478
445
function enableFilter(filter, enable) {
482
446
filter.disabled = !enable;
483
filterStorage.triggerFilterObservers(enable ? "enable" : "disable", [filter]);
484
filterStorage.saveToDisk();
447
FilterStorage.triggerFilterObservers(enable ? "enable" : "disable", [filter]);
448
FilterStorage.saveToDisk();
486
450
treeView.boxObject.invalidate();
494
458
// Generate text for new filter that excludes current domain
495
459
domain = domain.toUpperCase();
496
460
let text = filter.text;
497
if (filter instanceof abp.RegExpFilter)
461
if (filter instanceof RegExpFilter)
499
if (abp.Filter.optionsRegExp.test(text))
463
if (Filter.optionsRegExp.test(text))
501
465
let found = false;
502
466
let options = RegExp.$1.toUpperCase().split(",");
515
479
options.push("DOMAIN=~" + domain);
517
text = text.replace(abp.Filter.optionsRegExp, "$" + options.join(",").toLowerCase());
481
text = text.replace(Filter.optionsRegExp, "$" + options.join(",").toLowerCase());
520
484
text += "$domain=~" + domain.toLowerCase();
522
else if (filter instanceof abp.ElemHideFilter)
486
else if (filter instanceof ElemHideFilter)
524
488
if (/^([^#]+)(#.*)/.test(text))
536
500
return; // Just in case, shouldn't happen
538
502
// Insert new filter before the old one and remove the old one then
539
let newFilter = abp.Filter.fromText(text);
503
let newFilter = Filter.fromText(text);
540
504
if (newFilter.disabled && newFilter.subscriptions.length)
542
506
newFilter.disabled = false;
543
filterStorage.triggerFilterObservers("enable", [newFilter]);
507
FilterStorage.triggerFilterObservers("enable", [newFilter]);
545
509
else if (!newFilter.subscriptions.length)
547
511
newFilter.disabled = false;
548
filterStorage.addFilter(newFilter, filter);
512
FilterStorage.addFilter(newFilter, filter);
550
filterStorage.removeFilter(filter);
551
filterStorage.saveToDisk();
514
FilterStorage.removeFilter(filter);
515
FilterStorage.saveToDisk();
553
517
// Update display
554
518
item.filter = null;
558
522
function copyToClipboard() {
562
523
var items = treeView.getAllSelectedItems();
563
524
if (!items.length)
566
527
var clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
567
clipboardHelper.copyString(items.map(function(item) {return item.location}).join(abp.getLineBreak()));
528
clipboardHelper.copyString(items.map(function(item) {return item.location}).join(Utils.getLineBreak()));
570
531
function copyFilter() {
574
532
var items = treeView.getAllSelectedItems().filter(function(item) {return item.filter});
575
533
if (treeView.data && !treeView.data.length)
576
534
items = [treeView.getDummyTooltip()];
616
571
// detaches/reattaches the sidebar
617
572
function detach(doDetach)
624
576
// Store variables locally, global variables will go away when we are closed
626
578
let myMainWin = mainWin;
628
580
// Close sidebar and open detached window
629
581
myMainWin.document.getElementById("abp-command-sidebar").doCommand();
630
582
myPrefs.detachsidebar = doDetach;
631
583
myMainWin.document.getElementById("abp-command-sidebar").doCommand();
637
586
// Returns items size in the document if available
638
587
function getItemSize(item)
640
if (item.filter && !item.filter.disabled && item.filter instanceof abp.BlockingFilter)
589
if (item.filter && !item.filter.disabled && item.filter instanceof BlockingFilter)
643
592
for each (let node in item.nodes)
689
638
function compareState(item1, item2) {
690
var state1 = (!item1.filter ? 0 : (item1.filter.disabled ? 1 : (item1.filter instanceof abp.WhitelistFilter ? 2 : 3)));
691
var state2 = (!item2.filter ? 0 : (item2.filter.disabled ? 1 : (item2.filter instanceof abp.WhitelistFilter ? 2 : 3)));
639
var state1 = (!item1.filter ? 0 : (item1.filter.disabled ? 1 : (item1.filter instanceof WhitelistFilter ? 2 : 3)));
640
var state2 = (!item2.filter ? 0 : (item2.filter.disabled ? 1 : (item2.filter instanceof WhitelistFilter ? 2 : 3)));
692
641
return state1 - state2;
679
var progressListener =
681
onLocationChange: function() handleLocationChange(),
682
onProgressChange: function() {},
683
onSecurityChange: function() {},
684
onStateChange: function() {},
685
onStatusChange: function() {},
686
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference])
726
689
// Item list's tree view object
766
729
this.atoms[atom + "-false"] = atomService.getAtom(atom + "-false");
769
this.itemsDummyTooltip = abp.getString("no_blocking_suggestions");
770
this.whitelistDummyTooltip = abp.getString("whitelisted_page");
732
this.itemsDummyTooltip = Utils.getString("no_blocking_suggestions");
733
this.whitelistDummyTooltip = Utils.getString("whitelisted_page");
772
735
// Check current sort direction
773
736
var cols = document.getElementsByTagName("treecol");
846
809
if (col == "filter") {
847
var filter = abp.policy.isWindowWhitelisted(window.content);
810
var filter = Policy.isWindowWhitelisted(window.content);
848
811
return filter ? filter.text : "";
851
return (abp.policy.isWindowWhitelisted(window.content) ? this.whitelistDummy : this.itemsDummy);
814
return (Policy.isWindowWhitelisted(window.content) ? this.whitelistDummy : this.itemsDummy);
876
839
state = "state-regular";
877
840
if (filter && !filter.disabled)
879
if (filter instanceof abp.WhitelistFilter)
842
if (filter instanceof WhitelistFilter)
880
843
state = "state-whitelisted";
881
else if (filter instanceof abp.BlockingFilter)
844
else if (filter instanceof BlockingFilter)
882
845
state = "state-filtered";
883
else if (filter instanceof abp.ElemHideFilter)
846
else if (filter instanceof ElemHideFilter)
884
847
state = "state-hidden";
888
851
properties.AppendElement(this.atoms["dummy-true"]);
890
853
state = "state-filtered";
891
if (this.data && abp.policy.isWindowWhitelisted(window.content))
854
if (this.data && Policy.isWindowWhitelisted(window.content))
892
855
state = "state-whitelisted";
894
857
properties.AppendElement(this.atoms[state]);
991
956
docDomainDesc: createSortWithFallback(compareDocDomain, sortByAddress, true)
994
setData: function(data) {
959
clearData: function(data) {
995
960
var oldRows = this.rowCount;
998
for each (let item in this.allData)
1000
if (item.filter instanceof abp.RegExpFilter && item.filter.disabled)
1003
item.filter = disabledWhitelistMatcher.matchesAny(item.location, item.typeDescr, item.docDomain, item.thirdParty);
1005
item.filter = disabledBlacklistMatcher.matchesAny(item.location, item.typeDescr, item.docDomain, item.thirdParty);
963
this.dataMap = {__proto__: null};
1007
964
this.refilter();
1009
966
this.boxObject.rowCountChanged(0, -oldRows);
1010
967
this.boxObject.rowCountChanged(0, this.rowCount);
1013
addItem: function(item) {
970
addItem: function(/**Node*/ node, /**RequestEntry*/ item, /**Boolean*/ scanComplete)
972
// Merge duplicate entries
973
let key = item.location + " " + item.type + " " + item.docDomain;
974
if (key in this.dataMap)
976
// We know this item already - take over the filter if any and be done with it
977
let existing = this.dataMap[key];
979
existing.filter = item.filter;
981
existing.nodes.push(node);
982
this.invalidateItem(existing);
986
// Add new item to the list
987
// Store original item in orig property - reading out prototype is messed up in Gecko 1.9.2
988
item = {__proto__: item, orig: item, nodes: [node]};
1014
989
this.allData.push(item);
1016
item.filter = disabledWhitelistMatcher.matchesAny(item.location, item.typeDescr, item.docDomain, item.thirdParty);
1018
item.filter = disabledBlacklistMatcher.matchesAny(item.location, item.typeDescr, item.docDomain, item.thirdParty);
990
this.dataMap[key] = item;
992
// Show disabled filters if no other filter applies
994
item.filter = disabledMatcher.matchesAny(item.location, item.typeDescr, item.docDomain, item.thirdParty);
1020
996
if (!this.matchesFilter(item))
1024
1000
if (this.sortProc && this.sortColumn && this.sortColumn.id == "size")
1026
1002
// Sorting by size requires accessing content document, and that's
1052
1028
this.boxObject.invalidateRow(0);
1054
1030
this.boxObject.rowCountChanged(index, 1);
1032
if (this.itemToSelect == key)
1034
this.selection.select(index);
1035
this.boxObject.ensureRowIsVisible(index);
1036
this.itemToSelect = null;
1038
else if (!scanComplete && this.selection.currentIndex >= 0) // Keep selected row visible while scanning
1039
this.boxObject.ensureRowIsVisible(this.selection.currentIndex);
1042
updateFilters: function()
1044
for each (let item in this.allData)
1046
if (item.filter instanceof RegExpFilter && item.filter.disabled)
1049
item.filter = disabledMatcher.matchesAny(item.location, item.typeDescr, item.docDomain, item.thirdParty);
1080
1077
return (item.location.toLowerCase().indexOf(this.filter) >= 0 ||
1081
1078
(item.filter && item.filter.text.toLowerCase().indexOf(this.filter) >= 0) ||
1082
item.localizedDescr.toLowerCase().indexOf(this.filter) >= 0);
1079
item.localizedDescr.toLowerCase().indexOf(this.filter) >= 0 ||
1080
(item.docDomain && item.docDomain.toLowerCase().indexOf(this.filter) >= 0) ||
1081
(item.docDomain && item.thirdParty && docDomainThirdParty.toLowerCase().indexOf(this.filter) >= 0) ||
1082
(item.docDomain && !item.thirdParty && docDomainFirstParty.toLowerCase().indexOf(this.filter) >= 0));
1085
1085
setFilter: function(filter) {
1152
1152
if (!this.data || this.data.length)
1155
var filter = abp.policy.isWindowWhitelisted(window.content);
1155
var filter = Policy.isWindowWhitelisted(window.content);
1157
1157
return {tooltip: this.whitelistDummyTooltip, filter: filter};
1159
1159
return {tooltip: this.itemsDummyTooltip};
1162
selectItem: function(item) {
1164
for (var i = 0; row < 0 && i < this.data.length; i++)
1165
if (this.data[i] == item)
1171
this.selection.select(row);
1172
this.boxObject.ensureRowIsVisible(row);
1162
invalidateItem: function(item)
1164
let row = this.data.indexOf(item);
1166
this.boxObject.invalidateRow(row);