From 113c2e11a51860506d0aaee43424ce21adff440b Mon Sep 17 00:00:00 2001 From: gorhill Date: Wed, 10 Jun 2015 09:23:48 -0400 Subject: [PATCH] this (indirectly) fixes #15: let uBlock block remote fonts globally or on a site-basis --- src/_locales/en/messages.json | 4 +++ src/js/hnswitches.js | 17 +++++++++++- src/js/messaging.js | 2 ++ src/js/pagestore.js | 43 +++++++++++++++++++++++------- src/js/popup.js | 50 ++++++++++++++++++++--------------- src/popup.html | 1 + 6 files changed, 85 insertions(+), 32 deletions(-) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index c6818bf10..abb08357d 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -87,6 +87,10 @@ "message":"Toggle cosmetic filtering for this site", "description":"English: Toggle cosmetic filtering for this site" }, + "popupTipNoRemoteFonts":{ + "message":"Toggle the blocking of remote fonts for this site", + "description":"English: Toggle the blocking of remote fonts for this site" + }, "popupAnyRulePrompt":{ "message":"all", "description":"" diff --git a/src/js/hnswitches.js b/src/js/hnswitches.js index cd1317773..b6d5e7a14 100644 --- a/src/js/hnswitches.js +++ b/src/js/hnswitches.js @@ -39,7 +39,8 @@ var HnSwitches = function() { var switchBitOffsets = { 'no-strict-blocking': 0, 'no-popups': 2, - 'no-cosmetic-filtering': 4 + 'no-cosmetic-filtering': 4, + 'no-remote-fonts': 6 }; var fromLegacySwitchNames = { @@ -104,7 +105,9 @@ HnSwitches.toBroaderHostname = toBroaderHostname; HnSwitches.prototype.reset = function() { this.switches = {}; + this.n = ''; this.z = ''; + this.r = 0; }; /******************************************************************************/ @@ -221,8 +224,10 @@ HnSwitches.prototype.evaluate = function(switchName, hostname) { HnSwitches.prototype.evaluateZ = function(switchName, hostname) { var bitOffset = switchBitOffsets[switchName]; if ( bitOffset === undefined ) { + this.r = 0; return false; } + this.n = switchName; var bits; var s = hostname; for (;;) { @@ -231,6 +236,7 @@ HnSwitches.prototype.evaluateZ = function(switchName, hostname) { bits = bits >> bitOffset & 3; if ( bits !== 0 ) { this.z = s; + this.r = bits; return bits === 1; } } @@ -239,11 +245,20 @@ HnSwitches.prototype.evaluateZ = function(switchName, hostname) { break; } } + this.r = 0; return false; }; /******************************************************************************/ +HnSwitches.prototype.toResultString = function() { + return this.r !== 1 ? + '' : + 'ub:' + this.n + ': ' + this.z + ' true'; +}; + +/******************************************************************************/ + HnSwitches.prototype.toString = function() { var out = []; var switchName, val; diff --git a/src/js/messaging.js b/src/js/messaging.js index 6dfecb713..174a965c4 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -287,6 +287,8 @@ var popupDataFromTabId = function(tabId, tabTitle) { r.noPopups = µb.hnSwitches.evaluateZ('no-popups', tabContext.rootHostname); r.noStrictBlocking = µb.hnSwitches.evaluateZ('no-strict-blocking', tabContext.rootHostname); r.noCosmeticFiltering = µb.hnSwitches.evaluateZ('no-cosmetic-filtering', tabContext.rootHostname); + r.noRemoteFonts = µb.hnSwitches.evaluateZ('no-remote-fonts', tabContext.rootHostname); + r.remoteFontCount = pageStore.remoteFontCount; } else { r.hostnameDict = {}; r.firewallRules = getFirewallRules(); diff --git a/src/js/pagestore.js b/src/js/pagestore.js index 0b332a604..378072cd6 100644 --- a/src/js/pagestore.js +++ b/src/js/pagestore.js @@ -305,6 +305,7 @@ PageStore.prototype.init = function(tabId) { this.perLoadBlockedRequestCount = 0; this.perLoadAllowedRequestCount = 0; this.hiddenElementCount = ''; // Empty string means "unknown" + this.remoteFontCount = 0; this.netFilteringCache = NetFilteringResultCache.factory(); // Support `elemhide` filter option. Called at this point so the required @@ -495,9 +496,10 @@ PageStore.prototype.toggleNetFilteringSwitch = function(url, scope, state) { /******************************************************************************/ PageStore.prototype.filterRequest = function(context) { + var requestType = context.requestType; if ( this.getNetFilteringSwitch() === false ) { - if ( collapsibleRequestTypes.indexOf(context.requestType) !== -1 ) { + if ( collapsibleRequestTypes.indexOf(requestType) !== -1 ) { this.netFilteringCache.add(context, ''); } return ''; @@ -509,8 +511,19 @@ PageStore.prototype.filterRequest = function(context) { return entry.result; } - µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, context.requestType); - var result = µb.sessionURLFiltering.toFilterString(); + var result = ''; + + if ( requestType === 'font' ) { + if ( µb.hnSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) { + result = µb.hnSwitches.toResultString(); + } + this.remoteFontCount += 1; + } + + if ( result === '' ) { + µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType); + result = µb.sessionURLFiltering.toFilterString(); + } // Given that: // - Dynamic filtering override static filtering @@ -518,7 +531,7 @@ PageStore.prototype.filterRequest = function(context) { // We evaluate dynamic filtering first, and hopefully we can skip // evaluation of static filtering. if ( result === '' && µb.userSettings.advancedUserEnabled ) { - µb.sessionFirewall.evaluateCellZY( context.rootHostname, context.requestHostname, context.requestType); + µb.sessionFirewall.evaluateCellZY( context.rootHostname, context.requestHostname, requestType); if ( µb.sessionFirewall.mustBlockOrAllow() ) { result = µb.sessionFirewall.toFilterString(); } @@ -532,11 +545,11 @@ PageStore.prototype.filterRequest = function(context) { } //console.debug('cache MISS: PageStore.filterRequest("%s")', context.requestURL); - if ( collapsibleRequestTypes.indexOf(context.requestType) !== -1 ) { + if ( collapsibleRequestTypes.indexOf(requestType) !== -1 ) { this.netFilteringCache.add(context, result); } - // console.debug('[%s, %s] = "%s"', context.requestHostname, context.requestType, result); + // console.debug('[%s, %s] = "%s"', context.requestHostname, requestType, result); return result; }; @@ -551,8 +564,20 @@ PageStore.prototype.filterRequestNoCache = function(context) { return ''; } - µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, context.requestType); - var result = µb.sessionURLFiltering.toFilterString(); + var requestType = context.requestType; + var result = ''; + + if ( requestType === 'font' ) { + if ( µb.hnSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) { + result = µb.hnSwitches.toResultString(); + } + this.remoteFontCount += 1; + } + + if ( result === '' ) { + µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType); + result = µb.sessionURLFiltering.toFilterString(); + } // Given that: // - Dynamic filtering override static filtering @@ -560,7 +585,7 @@ PageStore.prototype.filterRequestNoCache = function(context) { // We evaluate dynamic filtering first, and hopefully we can skip // evaluation of static filtering. if ( result === '' && µb.userSettings.advancedUserEnabled ) { - µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, context.requestType); + µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, requestType); if ( µb.sessionFirewall.mustBlockOrAllow() ) { result = µb.sessionFirewall.toFilterString(); } diff --git a/src/js/popup.js b/src/js/popup.js index a46287eec..309753667 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -153,7 +153,8 @@ var hashFromPopupData = function(reset) { } hasher.sort(); hasher.push(uDom('body').hasClass('off')); - hasher.push(uDom('#no-cosmetic-filtering').hasClass('on')); + hasher.push(uDom.nodeFromId('no-cosmetic-filtering').classList.contains('on')); + hasher.push(uDom.nodeFromId('no-remote-fonts').classList.contains('on')); var hash = hasher.join(''); if ( reset ) { @@ -301,7 +302,7 @@ var updateAllFirewallCells = function() { positionRulesetTools(); - uDom('#firewallContainer').toggleClass( + uDom.nodeFromId('firewallContainer').classList.toggle( 'dirty', popupData.matrixIsDirty === true ); @@ -385,7 +386,7 @@ var renderPrivacyExposure = function() { var summary = domainsHitStr.replace('{{count}}', touchedDomainCount.toLocaleString()) .replace('{{total}}', allDomainCount.toLocaleString()); - uDom('#popupHitDomainCount').text(summary); + uDom.nodeFromId('popupHitDomainCount').textContent = summary; }; /******************************************************************************/ @@ -397,8 +398,8 @@ var renderPopup = function() { document.title = popupData.appName + ' - ' + popupData.tabTitle; } - uDom('#appname').text(popupData.appName); - uDom('#version').text(popupData.appVersion); + uDom.nodeFromId('appname').textContent = popupData.appName; + uDom.nodeFromId('version').textContent = popupData.appVersion; uDom('body') .toggleClass('advancedUser', popupData.advancedUserEnabled) .toggleClass( @@ -409,7 +410,7 @@ var renderPopup = function() { ); // If you think the `=== true` is pointless, you are mistaken - uDom('#gotoPick').toggleClass('enabled', popupData.canElementPicker === true); + uDom.nodeFromId('gotoPick').classList.toggle('enabled', popupData.canElementPicker === true); var text; var blocked = popupData.pageBlockedRequestCount; @@ -420,7 +421,7 @@ var renderPopup = function() { text = statsStr.replace('{{count}}', formatNumber(blocked)) .replace('{{percent}}', formatNumber(Math.floor(blocked * 100 / total))); } - uDom('#page-blocked').text(text); + uDom.nodeFromId('page-blocked').textContent = text; blocked = popupData.globalBlockedRequestCount; total = popupData.globalAllowedRequestCount + blocked; @@ -430,15 +431,21 @@ var renderPopup = function() { text = statsStr.replace('{{count}}', formatNumber(blocked)) .replace('{{percent}}', formatNumber(Math.floor(blocked * 100 / total))); } - uDom('#total-blocked').text(text); + uDom.nodeFromId('total-blocked').textContent = text; // This will collate all domains, touched or not renderPrivacyExposure(); // Extra tools - uDom('#no-popups').toggleClass('on', popupData.noPopups === true); - uDom('#no-strict-blocking').toggleClass('on', popupData.noStrictBlocking === true); - uDom('#no-cosmetic-filtering').toggleClass('on', popupData.noCosmeticFiltering === true); + uDom.nodeFromId('no-popups').classList.toggle('on', popupData.noPopups === true); + uDom.nodeFromId('no-strict-blocking').classList.toggle('on', popupData.noStrictBlocking === true); + uDom.nodeFromId('no-cosmetic-filtering').classList.toggle('on', popupData.noCosmeticFiltering === true); + uDom.nodeFromId('no-remote-fonts').classList.toggle('on', popupData.noRemoteFonts === true); + + // Report remote font count on badge + total = popupData.remoteFontCount; + uDom.nodeFromSelector('#no-remote-fonts > span.badge') + .textContent = total ? total.toLocaleString() : ''; // https://github.com/chrisaljoudi/uBlock/issues/470 // This must be done here, to be sure the popup is resized properly @@ -453,7 +460,7 @@ var renderPopup = function() { vAPI.localStorage.setItem('popupFirewallPane', dfPaneVisibleStored); } - uDom('#panes').toggleClass('dfEnabled', dfPaneVisible); + uDom.nodeFromId('panes').classList.toggle('dfEnabled', dfPaneVisible); uDom('#firewallContainer') .toggleClass('minimized', popupData.firewallPaneMinimized) .toggleClass('colorBlind', popupData.colorBlindFriendly); @@ -469,9 +476,8 @@ var renderPopup = function() { var renderPopupLazy = function() { var onDataReady = function(data) { var v = data.hiddenElementCount || ''; - uDom('#no-cosmetic-filtering > span.badge').text( - typeof v === 'number' ? v.toLocaleString() : v - ); + uDom.nodeFromSelector('#no-cosmetic-filtering > span.badge') + .textContent = typeof v === 'number' ? v.toLocaleString() : v; }; messager.send({ @@ -554,7 +560,7 @@ var toggleFirewallPane = function() { vAPI.localStorage.setItem('popupFirewallPane', dfPaneVisibleStored); // Dynamic filtering pane may not have been built yet - uDom('#panes').toggleClass('dfEnabled', popupData.dfEnabled); + uDom.nodeFromId('panes').classList.toggle('dfEnabled', popupData.dfEnabled); if ( popupData.dfEnabled && dfPaneBuilt === false ) { buildAllFirewallRows(); } @@ -656,9 +662,9 @@ var reloadTab = function() { /******************************************************************************/ var toggleMinimize = function() { - var elem = uDom('#firewallContainer'); - elem.toggleClass('minimized'); - popupData.firewallPaneMinimized = elem.hasClass('minimized'); + popupData.firewallPaneMinimized = uDom.nodeFromId('firewallContainer') + .classList + .toggle('minimized'); messager.send({ what: 'userSettings', name: 'firewallPaneMinimized', @@ -675,7 +681,7 @@ var saveFirewallRules = function() { srcHostname: popupData.pageHostname, desHostnames: popupData.hostnameDict }); - uDom('#firewallContainer').removeClass('dirty'); + uDom.nodeFromId('firewallContainer').classList.remove('dirty'); }; /******************************************************************************/ @@ -692,7 +698,7 @@ var revertFirewallRules = function() { desHostnames: popupData.hostnameDict, tabId: popupData.tabId }, onFirewallRuleChanged); - uDom('#firewallContainer').removeClass('dirty'); + uDom.nodeFromId('firewallContainer').classList.remove('dirty'); }; /******************************************************************************/ @@ -810,7 +816,7 @@ var onShowTooltip = function() { }; var onHideTooltip = function() { - uDom('#tooltip').removeClass('show'); + uDom.nodeFromId('tooltip').classList.remove('show'); }; /******************************************************************************/ diff --git a/src/popup.html b/src/popup.html index f8defb1af..3e91b2a8f 100644 --- a/src/popup.html +++ b/src/popup.html @@ -29,6 +29,7 @@ +