 Issue 29329663:
  Issue 3222 - Mostly unbreak blockable items  (Closed)
    
  
    Issue 29329663:
  Issue 3222 - Mostly unbreak blockable items  (Closed) 
  | Index: chrome/content/ui/sidebar.js | 
| =================================================================== | 
| --- a/chrome/content/ui/sidebar.js | 
| +++ b/chrome/content/ui/sidebar.js | 
| @@ -109,16 +109,24 @@ function init() { | 
| types.set(type, Utils.getString("type_label_" + type.toLowerCase())); | 
| } | 
| // To be called for a detached window when the main window has been closed | 
| function mainUnload() { | 
| parent.close(); | 
| } | 
| +function getFilter(item) | 
| +{ | 
| + if ("filter" in item && item.filter) | 
| 
tschuster
2015/11/12 15:32:05
"filter" in item is not strictly necessary.
 
Wladimir Palant
2015/11/12 15:46:55
Yes, I know but I didn't feel like changing that.
 | 
| + return Filter.fromText(item.filter); | 
| + else | 
| + return null; | 
| +} | 
| + | 
| // To be called on unload | 
| function cleanUp() { | 
| flasher.stop(); | 
| requestNotifier.shutdown(); | 
| FilterNotifier.removeListener(reloadDisabledFilters); | 
| Prefs.removeListener(onPrefChange); | 
| E("list").view = null; | 
| @@ -195,21 +203,27 @@ function onSelectionChange() { | 
| } | 
| function handleLocationChange() | 
| { | 
| if (requestNotifier) | 
| requestNotifier.shutdown(); | 
| treeView.clearData(); | 
| + | 
| + let {getBrowser, addBrowserLocationListener} = require("appSupport"); | 
| + let browser = getBrowser(mainWin); | 
| + if ("selectedBrowser" in browser) | 
| + browser = browser.selectedBrowser; | 
| + let outerWindowID = browser.outerWindowID; | 
| treeView.itemToSelect = RequestNotifier.getSelection(window.content); | 
| - requestNotifier = new RequestNotifier(window.content, function(wnd, node, item, scanComplete) | 
| + requestNotifier = new RequestNotifier(outerWindowID, function(item, scanComplete) | 
| { | 
| if (item) | 
| - treeView.addItem(node, item, scanComplete); | 
| + treeView.addItem(item, scanComplete); | 
| }); | 
| cacheStorage = null; | 
| } | 
| // Fills a box with text splitting it up into multiple lines if necessary | 
| function setMultilineContent(box, text, noRemove) | 
| { | 
| if (!noRemove) | 
| @@ -240,17 +254,17 @@ function fillInTooltip(e) { | 
| item = treeView.getItemAt(e.clientX, e.clientY); | 
| if (!item) | 
| { | 
| e.preventDefault(); | 
| return; | 
| } | 
| - let filter = ("filter" in item && item.filter ? item.filter : null); | 
| + let filter = getFilter(item); | 
| let size = ("tooltip" in item ? null : getItemSize(item)); | 
| let subscriptions = (filter ? filter.subscriptions.filter(function(subscription) { return !subscription.disabled; }) : []); | 
| E("tooltipDummy").hidden = !("tooltip" in item); | 
| E("tooltipAddressRow").hidden = ("tooltip" in item); | 
| E("tooltipTypeRow").hidden = ("tooltip" in item); | 
| E("tooltipSizeRow").hidden = !size; | 
| E("tooltipDocDomainRow").hidden = ("tooltip" in item || !item.docDomain); | 
| @@ -296,17 +310,17 @@ function fillInTooltip(e) { | 
| sourceElement.removeChild(sourceElement.firstChild); | 
| for (let i = 0; i < subscriptions.length; i++) | 
| setMultilineContent(sourceElement, subscriptions[i].title, true); | 
| } | 
| } | 
| var showPreview = Prefs.previewimages && !("tooltip" in item); | 
| showPreview = showPreview && item.type == "IMAGE"; | 
| - showPreview = showPreview && (!item.filter || item.filter.disabled || item.filter instanceof WhitelistFilter); | 
| + showPreview = showPreview && (!filter || filter.disabled || filter instanceof WhitelistFilter); | 
| E("tooltipPreviewBox").hidden = true; | 
| if (showPreview) | 
| { | 
| if (!cacheStorage) | 
| { | 
| let {Services} = Cu.import("resource://gre/modules/Services.jsm", null); | 
| // Cache v2 API is enabled by default starting with Gecko 32 | 
| if (Services.vc.compare(Utils.platformVersion, "32.0a1") >= 0) | 
| @@ -389,19 +403,19 @@ function fillInContext(/**Event*/ e) | 
| } | 
| if (!item || ("tooltip" in item && !("filter" in item))) | 
| return false; | 
| E("contextDisableFilter").hidden = true; | 
| E("contextEnableFilter").hidden = true; | 
| E("contextDisableOnSite").hidden = true; | 
| - if ("filter" in item && item.filter) | 
| + let filter = getFilter(item); | 
| + if (filter) | 
| { | 
| - let filter = item.filter; | 
| let menuItem = E(filter.disabled ? "contextEnableFilter" : "contextDisableFilter"); | 
| menuItem.setAttribute("label", menuItem.getAttribute("labeltempl").replace(/\?1\?/, filter.text)); | 
| menuItem.hidden = false; | 
| if (filter instanceof ActiveFilter && !filter.disabled && filter.subscriptions.length && !filter.subscriptions.some(subscription => !(subscription instanceof SpecialSubscription))) | 
| { | 
| let domain = null; | 
| try { | 
| @@ -412,38 +426,39 @@ function fillInContext(/**Event*/ e) | 
| { | 
| menuItem = E("contextDisableOnSite"); | 
| menuItem.setAttribute("label", menuItem.getAttribute("labeltempl").replace(/\?1\?/, domain)); | 
| menuItem.hidden = false; | 
| } | 
| } | 
| } | 
| - E("contextWhitelist").hidden = ("tooltip" in item || !item.filter || item.filter.disabled || item.filter instanceof WhitelistFilter || item.type == "ELEMHIDE"); | 
| + E("contextWhitelist").hidden = ("tooltip" in item || !filter || filter.disabled || filter instanceof WhitelistFilter || item.type == "ELEMHIDE"); | 
| E("contextBlock").hidden = !E("contextWhitelist").hidden; | 
| - E("contextBlock").setAttribute("disabled", "filter" in item && item.filter && !item.filter.disabled); | 
| - E("contextEditFilter").setAttribute("disabled", !("filter" in item && item.filter)); | 
| + E("contextBlock").setAttribute("disabled", filter && !filter.disabled); | 
| + E("contextEditFilter").setAttribute("disabled", !filter); | 
| E("contextOpen").setAttribute("disabled", "tooltip" in item || item.type == "ELEMHIDE"); | 
| - E("contextFlash").setAttribute("disabled", "tooltip" in item || !(item.type in visual) || (item.filter && !item.filter.disabled && !(item.filter instanceof WhitelistFilter))); | 
| - E("contextCopyFilter").setAttribute("disabled", !allItems.some(function(item) {return "filter" in item && item.filter})); | 
| + E("contextFlash").setAttribute("disabled", "tooltip" in item || !(item.type in visual) || (filter && !filter.disabled && !(filter instanceof WhitelistFilter))); | 
| + E("contextCopyFilter").setAttribute("disabled", !allItems.some(getFilter)); | 
| return true; | 
| } | 
| /** | 
| * Processed mouse clicks on the item list. | 
| * @param {Event} event | 
| */ | 
| function handleClick(event) | 
| { | 
| let item = treeView.getItemAt(event.clientX, event.clientY); | 
| if (event.button == 0 && treeView.getColumnAt(event.clientX, event.clientY) == "state") | 
| { | 
| - if (item.filter) | 
| - enableFilter(item.filter, item.filter.disabled); | 
| + let filter = getFilter(item); | 
| + if (filter) | 
| + enableFilter(filter, filter.disabled); | 
| event.preventDefault(); | 
| } | 
| else if (event.button == 1) | 
| { | 
| openInTab(item, event); | 
| event.preventDefault(); | 
| } | 
| } | 
| @@ -473,51 +488,49 @@ function openInTab(item, /**Event*/ even | 
| } | 
| } | 
| function doBlock() { | 
| var item = treeView.getSelectedItem(); | 
| if (!item || item.type == "ELEMHIDE") | 
| return; | 
| - var filter = null; | 
| - if (item.filter && !item.filter.disabled) | 
| - filter = item.filter; | 
| - | 
| - if (filter && filter instanceof WhitelistFilter) | 
| + var filter = getFilter(item); | 
| + if (filter && !filter.disabled && filter instanceof WhitelistFilter) | 
| return; | 
| openDialog("chrome://adblockplus/content/ui/composer.xul", "_blank", "chrome,centerscreen,resizable,dialog=no,dependent", item.nodes, item.orig); | 
| } | 
| function editFilter() | 
| { | 
| var item = treeView.getSelectedItem(); | 
| if (treeView.data && !treeView.data.length) | 
| item = treeView.getDummyTooltip(); | 
| - if (!("filter" in item) || !item.filter) | 
| + let filter = getFilter(item); | 
| + if (!filter) | 
| return; | 
| - UI.openFiltersDialog(item.filter); | 
| + UI.openFiltersDialog(filter); | 
| } | 
| function enableFilter(filter, enable) { | 
| filter.disabled = !enable; | 
| treeView.boxObject.invalidate(); | 
| } | 
| /** | 
| * Edits the filter to disable it on a particular domain. | 
| */ | 
| function disableOnSite() | 
| { | 
| let item = treeView.getSelectedItem(); | 
| - let filter = item.filter; | 
| + let filter = getFilter(item); | 
| if (!(filter instanceof ActiveFilter) || filter.disabled || !filter.subscriptions.length || filter.subscriptions.some(subscription => !(subscription instanceof SpecialSubscription))) | 
| return; | 
| let domain; | 
| try { | 
| domain = Utils.effectiveTLD.getBaseDomainFromHost(item.docDomain).toUpperCase(); | 
| } | 
| catch (e) | 
| @@ -581,38 +594,38 @@ function disableOnSite() | 
| let subscription = filter.subscriptions.filter(s => s instanceof SpecialSubscription)[0]; | 
| if (subscription) | 
| FilterStorage.addFilter(newFilter, subscription, subscription.filters.indexOf(filter)); | 
| } | 
| FilterStorage.removeFilter(filter); | 
| // Update display | 
| for (let i = 0; i < treeView.allData.length; i++) | 
| - if (treeView.allData[i].filter == filter) | 
| + if (getFilter(treeView.allData[i]) == filter) | 
| treeView.allData[i].filter = null; | 
| treeView.boxObject.invalidate(); | 
| } | 
| function copyToClipboard() { | 
| var items = treeView.getAllSelectedItems(); | 
| if (!items.length) | 
| return; | 
| Utils.clipboardHelper.copyString(items.map(function(item) {return item.location}).join(IO.lineBreak)); | 
| } | 
| function copyFilter() { | 
| - var items = treeView.getAllSelectedItems().filter(function(item) {return item.filter}); | 
| + var items = treeView.getAllSelectedItems().filter(getFilter); | 
| if (treeView.data && !treeView.data.length) | 
| items = [treeView.getDummyTooltip()]; | 
| if (!items.length) | 
| return; | 
| - Utils.clipboardHelper.copyString(items.map(function(item) {return item.filter.text}).join(IO.lineBreak)); | 
| + Utils.clipboardHelper.copyString(items.map(function(item) {return item.filter}).join(IO.lineBreak)); | 
| } | 
| function selectAll() { | 
| treeView.selectAll(); | 
| } | 
| // Saves sidebar's state before detaching/reattaching | 
| function saveState() { | 
| @@ -651,17 +664,18 @@ function detach(doDetach) | 
| myMainWin.document.getElementById("abp-command-sidebar").doCommand(); | 
| myPrefs.detachsidebar = doDetach; | 
| myMainWin.document.getElementById("abp-command-sidebar").doCommand(); | 
| } | 
| // Returns items size in the document if available | 
| function getItemSize(item) | 
| { | 
| - if (item.filter && !item.filter.disabled && item.filter instanceof BlockingFilter) | 
| + let filter = getFilter(item); | 
| + if (filter && !filter.disabled && filter instanceof BlockingFilter) | 
| return null; | 
| for (let node of item.nodes) | 
| { | 
| if (node instanceof HTMLImageElement && (node.naturalWidth || node.naturalHeight)) | 
| return [node.naturalWidth, node.naturalHeight]; | 
| else if (node instanceof HTMLElement && (node.offsetWidth || node.offsetHeight)) | 
| return [node.offsetWidth, node.offsetHeight]; | 
| @@ -694,27 +708,30 @@ function compareType(item1, item2) { | 
| return 0; | 
| } | 
| function compareFilter(item1, item2) { | 
| var hasFilter1 = (item1.filter ? 1 : 0); | 
| var hasFilter2 = (item2.filter ? 1 : 0); | 
| if (hasFilter1 != hasFilter2) | 
| return hasFilter1 - hasFilter2; | 
| - else if (hasFilter1 && item1.filter.text < item2.filter.text) | 
| + else if (hasFilter1 && item1.filter < item2.filter) | 
| return -1; | 
| - else if (hasFilter1 && item1.filter.text > item2.filter.text) | 
| + else if (hasFilter1 && item1.filter > item2.filter) | 
| return 1; | 
| else | 
| return 0; | 
| } | 
| -function compareState(item1, item2) { | 
| - var state1 = (!item1.filter ? 0 : (item1.filter.disabled ? 1 : (item1.filter instanceof WhitelistFilter ? 2 : 3))); | 
| - var state2 = (!item2.filter ? 0 : (item2.filter.disabled ? 1 : (item2.filter instanceof WhitelistFilter ? 2 : 3))); | 
| +function compareState(item1, item2) | 
| +{ | 
| + let filter1 = getFilter(item1); | 
| + let filter2 = getFilter(item2); | 
| + let state1 = (!filter1 ? 0 : (filter1.disabled ? 1 : (filter1 instanceof WhitelistFilter ? 2 : 3))); | 
| + let state2 = (!filter2 ? 0 : (filter2.disabled ? 1 : (filter2 instanceof WhitelistFilter ? 2 : 3))); | 
| return state1 - state2; | 
| } | 
| function compareSize(item1, item2) { | 
| var size1 = getItemSize(item1); | 
| size1 = size1 ? size1[0] * size1[1] : 0; | 
| var size2 = getItemSize(item2); | 
| @@ -733,18 +750,20 @@ function compareDocDomain(item1, item2) | 
| else if (!item1.thirdParty && item2.thirdParty) | 
| return 1; | 
| else | 
| return 0; | 
| } | 
| function compareFilterSource(item1, item2) | 
| { | 
| - let subs1 = item1.filter ? item1.filter.subscriptions.map(s => s.title).join(", ") : ""; | 
| - let subs2 = item2.filter ? item2.filter.subscriptions.map(s => s.title).join(", ") : ""; | 
| + let filter1 = getFilter(item1); | 
| + let filter2 = getFilter(item2); | 
| + let subs1 = filter1 ? filter1.subscriptions.map(s => s.title).join(", ") : ""; | 
| + let subs2 = filter2 ? filter2.subscriptions.map(s => s.title).join(", ") : ""; | 
| if (subs1 < subs2) | 
| return -1; | 
| else if (subs1 > subs2) | 
| return 1; | 
| else | 
| return 0; | 
| } | 
| @@ -851,30 +870,31 @@ var treeView = { | 
| if (col != "type" && col != "address" && col != "filter" && col != "size" && col != "docDomain" && col != "filterSource") | 
| return ""; | 
| if (this.data && this.data.length) { | 
| if (row >= this.data.length) | 
| return ""; | 
| if (col == "type") | 
| return types.get(this.data[row].type); | 
| else if (col == "filter") | 
| - return (this.data[row].filter ? this.data[row].filter.text : ""); | 
| + return (this.data[row].filter || ""); | 
| else if (col == "size") | 
| { | 
| let size = getItemSize(this.data[row]); | 
| return (size ? size.join(" x ") : ""); | 
| } | 
| else if (col == "docDomain") | 
| return this.data[row].docDomain + " " + (this.data[row].thirdParty ? docDomainThirdParty : docDomainFirstParty); | 
| else if (col == "filterSource") | 
| { | 
| - if (!this.data[row].filter) | 
| + let filter = getFilter(this.data[row]) | 
| + if (!filter) | 
| return ""; | 
| - return this.data[row].filter.subscriptions.filter(s => !s.disabled).map(s => s.title).join(", "); | 
| + return filter.subscriptions.filter(s => !s.disabled).map(s => s.title).join(", "); | 
| } | 
| else | 
| return this.data[row].location; | 
| } | 
| else { | 
| // Empty list, show dummy | 
| if (row > 0 || (col != "address" && col != "filter")) | 
| return ""; | 
| @@ -917,17 +937,17 @@ var treeView = { | 
| let list = []; | 
| list.push("selected-" + this.selection.isSelected(row)); | 
| let state; | 
| if (this.data && this.data.length) { | 
| list.push("dummy-false"); | 
| - let filter = this.data[row].filter; | 
| + let filter = getFilter(this.data[row]); | 
| if (filter) | 
| list.push("filter-disabled-" + filter.disabled); | 
| state = "state-regular"; | 
| if (filter && !filter.disabled) | 
| { | 
| if (filter instanceof WhitelistFilter) | 
| state = "state-whitelisted"; | 
| @@ -1054,41 +1074,44 @@ var treeView = { | 
| this.allData = []; | 
| this.dataMap = Object.create(null); | 
| this.refilter(); | 
| this.boxObject.rowCountChanged(0, -oldRows); | 
| this.boxObject.rowCountChanged(0, this.rowCount); | 
| }, | 
| - addItem: function(/**Node*/ node, /**RequestEntry*/ item, /**Boolean*/ scanComplete) | 
| + addItem: function(/**RequestEntry*/ item, /**Boolean*/ scanComplete) | 
| { | 
| // Merge duplicate entries | 
| let key = item.location + " " + item.type + " " + item.docDomain; | 
| if (key in this.dataMap) | 
| { | 
| // We know this item already - take over the filter if any and be done with it | 
| let existing = this.dataMap[key]; | 
| if (item.filter) | 
| existing.filter = item.filter; | 
| - existing.nodes.push(node); | 
| this.invalidateItem(existing); | 
| return; | 
| } | 
| // Add new item to the list | 
| // Store original item in orig property - reading out prototype is messed up in Gecko 1.9.2 | 
| - item = {__proto__: item, orig: item, nodes: [node]}; | 
| + item = {__proto__: item, orig: item, nodes: []}; | 
| 
Wladimir Palant
2015/11/02 20:01:59
Not having nodes has two side-effects: the Size co
 | 
| this.allData.push(item); | 
| this.dataMap[key] = item; | 
| // Show disabled filters if no other filter applies | 
| if (!item.filter) | 
| - item.filter = disabledMatcher.matchesAny(item.location, RegExpFilter.typeMap[item.type], item.docDomain, item.thirdParty); | 
| + { | 
| + let disabledMatch = disabledMatcher.matchesAny(item.location, RegExpFilter.typeMap[item.type], item.docDomain, item.thirdParty); | 
| + if (disabledMatch) | 
| + item.filter = disabledMatch.text; | 
| + } | 
| if (!this.matchesFilter(item)) | 
| return; | 
| let index = -1; | 
| if (this.sortProc && this.sortColumn && this.sortColumn.id == "size") | 
| { | 
| // Sorting by size requires accessing content document, and that's | 
| @@ -1130,20 +1153,25 @@ var treeView = { | 
| else if (!scanComplete && this.selection.currentIndex >= 0) // Keep selected row visible while scanning | 
| this.boxObject.ensureRowIsVisible(this.selection.currentIndex); | 
| }, | 
| updateFilters: function() | 
| { | 
| for (let item of this.allData) | 
| { | 
| - if (item.filter instanceof RegExpFilter && item.filter.disabled) | 
| + let filter = getFilter(item); | 
| + if (filter instanceof RegExpFilter && filter.disabled) | 
| delete item.filter; | 
| - if (!item.filter) | 
| - item.filter = disabledMatcher.matchesAny(item.location, RegExpFilter.typeMap[item.type], item.docDomain, item.thirdParty); | 
| + if (!filter) | 
| + { | 
| + let disabledMatch = disabledMatcher.matchesAny(item.location, RegExpFilter.typeMap[item.type], item.docDomain, item.thirdParty); | 
| + if (disabledMatch) | 
| + item.filter = disabledMatch.text; | 
| + } | 
| } | 
| this.refilter(); | 
| }, | 
| /** | 
| * Updates the list after a filter or sorting change. | 
| */ | 
| refilter: function() | 
| @@ -1162,17 +1190,17 @@ var treeView = { | 
| * @return {Boolean} true if the item should be shown | 
| */ | 
| matchesFilter: function(item) | 
| { | 
| if (!this.filter) | 
| return true; | 
| return (item.location.toLowerCase().indexOf(this.filter) >= 0 || | 
| - (item.filter && item.filter.text.toLowerCase().indexOf(this.filter) >= 0) || | 
| + (item.filter && item.filter.toLowerCase().indexOf(this.filter) >= 0) || | 
| item.type.toLowerCase().indexOf(this.filter.replace(/-/g, "_")) >= 0 || | 
| types.get(item.type).toLowerCase().indexOf(this.filter) >= 0 || | 
| (item.docDomain && item.docDomain.toLowerCase().indexOf(this.filter) >= 0) || | 
| (item.docDomain && item.thirdParty && docDomainThirdParty.toLowerCase().indexOf(this.filter) >= 0) || | 
| (item.docDomain && !item.thirdParty && docDomainFirstParty.toLowerCase().indexOf(this.filter) >= 0)); | 
| }, | 
| setFilter: function(filter) { | 
| @@ -1241,17 +1269,17 @@ var treeView = { | 
| }, | 
| getDummyTooltip: function() { | 
| if (!this.data || this.data.length) | 
| return null; | 
| var filter = Policy.isWindowWhitelisted(window.content); | 
| if (filter) | 
| - return {tooltip: this.whitelistDummyTooltip, filter: filter}; | 
| + return {tooltip: this.whitelistDummyTooltip, filter: filter.text}; | 
| else | 
| return {tooltip: this.itemsDummyTooltip}; | 
| }, | 
| invalidateItem: function(item) | 
| { | 
| let row = this.data.indexOf(item); | 
| if (row >= 0) |