mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-06 09:37:12 +02:00
parent
5f8fd22920
commit
f2ff0edfaf
@ -55,6 +55,8 @@ vAPI.app.restart = function() {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// chrome.storage.local.get(null, function(bin){ console.debug('%o', bin); });
|
||||||
|
|
||||||
vAPI.storage = chrome.storage.local;
|
vAPI.storage = chrome.storage.local;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -74,6 +76,7 @@ vAPI.noTabId = '-1';
|
|||||||
vAPI.tabs.registerListeners = function() {
|
vAPI.tabs.registerListeners = function() {
|
||||||
var onNavigationClient = this.onNavigation || noopFunc;
|
var onNavigationClient = this.onNavigation || noopFunc;
|
||||||
var onPopupClient = this.onPopup || noopFunc;
|
var onPopupClient = this.onPopup || noopFunc;
|
||||||
|
var onUpdatedClient = this.onUpdated || noopFunc;
|
||||||
|
|
||||||
// https://developer.chrome.com/extensions/webNavigation
|
// https://developer.chrome.com/extensions/webNavigation
|
||||||
// [onCreatedNavigationTarget ->]
|
// [onCreatedNavigationTarget ->]
|
||||||
@ -160,6 +163,13 @@ vAPI.tabs.registerListeners = function() {
|
|||||||
popupCandidateTest(details);
|
popupCandidateTest(details);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var onUpdated = function(tabId, changeInfo, tab) {
|
||||||
|
if ( changeInfo.url && popupCandidateTest({ tabId: tabId, url: changeInfo.url }) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onUpdatedClient(tabId, changeInfo, tab);
|
||||||
|
};
|
||||||
|
|
||||||
var onCommitted = function(details) {
|
var onCommitted = function(details) {
|
||||||
if ( details.frameId !== 0 ) {
|
if ( details.frameId !== 0 ) {
|
||||||
return;
|
return;
|
||||||
@ -175,10 +185,7 @@ vAPI.tabs.registerListeners = function() {
|
|||||||
chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget);
|
chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget);
|
||||||
chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigate);
|
chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigate);
|
||||||
chrome.webNavigation.onCommitted.addListener(onCommitted);
|
chrome.webNavigation.onCommitted.addListener(onCommitted);
|
||||||
|
chrome.tabs.onUpdated.addListener(onUpdated);
|
||||||
if ( typeof this.onUpdated === 'function' ) {
|
|
||||||
chrome.tabs.onUpdated.addListener(this.onUpdated);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( typeof this.onClosed === 'function' ) {
|
if ( typeof this.onClosed === 'function' ) {
|
||||||
chrome.tabs.onRemoved.addListener(this.onClosed);
|
chrome.tabs.onRemoved.addListener(this.onClosed);
|
||||||
@ -308,6 +315,37 @@ vAPI.tabs.open = function(details) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Replace the URL of a tab. Noop if the tab does not exist.
|
||||||
|
|
||||||
|
vAPI.tabs.replace = function(tabId, url) {
|
||||||
|
var targetURL = url;
|
||||||
|
if ( typeof targetURL !== 'string' || targetURL === '' ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extension pages
|
||||||
|
if ( /^[\w-]{2,}:/.test(targetURL) !== true ) {
|
||||||
|
targetURL = vAPI.getURL(targetURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( typeof tabId !== 'number' ) {
|
||||||
|
tabId = parseInt(tabId, 10);
|
||||||
|
if ( isNaN(tabId) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.tabs.update(tabId, { url: targetURL }, function() {
|
||||||
|
// this prevent console error
|
||||||
|
if ( chrome.runtime.lastError ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.tabs.remove = function(tabId) {
|
vAPI.tabs.remove = function(tabId) {
|
||||||
var onTabRemoved = function() {
|
var onTabRemoved = function() {
|
||||||
if ( vAPI.lastError() ) {
|
if ( vAPI.lastError() ) {
|
||||||
|
@ -710,6 +710,24 @@ vAPI.tabs.open = function(details) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Replace the URL of a tab. Noop if the tab does not exist.
|
||||||
|
|
||||||
|
vAPI.tabs.replace = function(tabId, url) {
|
||||||
|
var targetURL = url;
|
||||||
|
|
||||||
|
// extension pages
|
||||||
|
if ( /^[\w-]{2,}:/.test(targetURL) !== true ) {
|
||||||
|
targetURL = vAPI.getURL(targetURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tab = this.getTabsForIds(tabId);
|
||||||
|
if ( tab ) {
|
||||||
|
getBrowserForTab(tab).loadURI(targetURL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.tabs._remove = function(tab, tabBrowser) {
|
vAPI.tabs._remove = function(tab, tabBrowser) {
|
||||||
if ( vAPI.fennec ) {
|
if ( vAPI.fennec ) {
|
||||||
tabBrowser.closeTab(tab);
|
tabBrowser.closeTab(tab);
|
||||||
@ -1138,18 +1156,13 @@ var httpObserver = {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( result.redirectUrl ) {
|
/*if ( result.redirectUrl ) {
|
||||||
if ( type === 'main_frame' ) {
|
channel.redirectionLimit = 1;
|
||||||
channel.cancel(this.ABORT);
|
|
||||||
vAPI.tabs.open({ tabId: details.tabId, url: result.redirectUrl });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/*channel.redirectionLimit = 1;
|
|
||||||
channel.redirectTo(
|
channel.redirectTo(
|
||||||
Services.io.newURI(result.redirectUrl, null, null)
|
Services.io.newURI(result.redirectUrl, null, null)
|
||||||
);
|
);
|
||||||
return true;*/
|
return true;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
@ -75,85 +75,13 @@
|
|||||||
"message":"Go to request log",
|
"message":"Go to request log",
|
||||||
"description":"English: Go to request log"
|
"description":"English: Go to request log"
|
||||||
},
|
},
|
||||||
"popupSiteInlineScriptEnabled":{
|
"popupTipDoBlockAllPopups":{
|
||||||
"message":"Inline <code>script<\/code> tags are <b>allowed<\/b> on this site",
|
"message":"Block all popups for this site",
|
||||||
"description":""
|
"description":"English: Block all popups for this site"
|
||||||
},
|
},
|
||||||
"popupSiteInlineScriptDisabled":{
|
"popupTipDontBlockDoc":{
|
||||||
"message":"Inline <code>script<\/code> tags are <b>blocked<\/b> on this site",
|
"message":"Disable strict blocking for this site",
|
||||||
"description":""
|
"description":"English: Disable strict blocking for this site"
|
||||||
},
|
|
||||||
"popupSite1pScriptEnabled":{
|
|
||||||
"message":"1st-party scripts are <b>allowed<\/b> on this site",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupSite1pScriptDisabled":{
|
|
||||||
"message":"1st-party scripts are <b>blocked<\/b> on this site",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupSite3pScriptEnabled":{
|
|
||||||
"message":"3rd-party scripts are <b>allowed<\/b> on this site",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupSite3pScriptDisabled":{
|
|
||||||
"message":"3rd-party scripts are <b>blocked<\/b> on this site",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupSite1pFrameEnabled":{
|
|
||||||
"message":"1st-party frames are <b>allowed<\/b> on this site",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupSite1pFrameDisabled":{
|
|
||||||
"message":"1st-party frames are <b>blocked<\/b> on this site",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupSite3pFrameEnabled":{
|
|
||||||
"message":"3rd-party frames are <b>allowed<\/b> on this site",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupSite3pFrameDisabled":{
|
|
||||||
"message":"3rd-party frames are <b>blocked<\/b> on this site",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefaultInlineScriptEnabled":{
|
|
||||||
"message":"Inline <code>script</code> tags are <b>allowed<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefaultInlineScriptDisabled":{
|
|
||||||
"message":"Inline <code>script</code> tags are <b>blocked<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefault1pScriptEnabled":{
|
|
||||||
"message":"1st-party scripts are <b>allowed<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefault1pScriptDisabled":{
|
|
||||||
"message":"1st-party scripts are <b>blocked<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefault3pScriptEnabled":{
|
|
||||||
"message":"3rd-party scripts are <b>allowed<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefault3pScriptDisabled":{
|
|
||||||
"message":"3rd-party scripts are <b>blocked<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefault1pFrameEnabled":{
|
|
||||||
"message":"1st-party frames are <b>allowed<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefault1pFrameDisabled":{
|
|
||||||
"message":"1st-party frames are <b>blocked<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefault3pFrameEnabled":{
|
|
||||||
"message":"3rd-party frames are <b>allowed<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
|
||||||
"popupDefault3pFrameDisabled":{
|
|
||||||
"message":"3rd-party frames are <b>blocked<\/b> everywhere by default",
|
|
||||||
"description":""
|
|
||||||
},
|
},
|
||||||
"popupAnyRulePrompt":{
|
"popupAnyRulePrompt":{
|
||||||
"message":"all",
|
"message":"all",
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
<script src="js/dynamic-net-filtering.js"></script>
|
<script src="js/dynamic-net-filtering.js"></script>
|
||||||
<script src="js/static-net-filtering.js"></script>
|
<script src="js/static-net-filtering.js"></script>
|
||||||
<script src="js/cosmetic-filtering.js"></script>
|
<script src="js/cosmetic-filtering.js"></script>
|
||||||
|
<script src="js/hnswitches.js"></script>
|
||||||
<script src="js/ublock.js"></script>
|
<script src="js/ublock.js"></script>
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
<script src="js/profiler.js"></script>
|
<script src="js/profiler.js"></script>
|
||||||
|
@ -25,6 +25,7 @@ body:not(.advancedUser) [data-tip]:after {
|
|||||||
box-shadow: 1px 1px 3px gray;
|
box-shadow: 1px 1px 3px gray;
|
||||||
color: black;
|
color: black;
|
||||||
content: attr(data-tip);
|
content: attr(data-tip);
|
||||||
|
display: none;
|
||||||
font: 12px sans-serif;
|
font: 12px sans-serif;
|
||||||
left: 0;
|
left: 0;
|
||||||
line-height: 130%;
|
line-height: 130%;
|
||||||
@ -38,7 +39,8 @@ body:not(.advancedUser) [data-tip]:after {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
[data-tip]:hover:after {
|
body [data-tip]:hover:after {
|
||||||
|
display: initial;
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
-webkit-transition: opacity 0.2s 0.4s;
|
-webkit-transition: opacity 0.2s 0.4s;
|
||||||
transition: opacity 0.2s 0.4s;
|
transition: opacity 0.2s 0.4s;
|
||||||
@ -60,6 +62,13 @@ body[dir=rtl] [data-tip][data-tip-anchor="top"]:hover:after {
|
|||||||
right: -500%;
|
right: -500%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body [data-tip][data-tip-anchor="topcenter"]:hover:after {
|
||||||
|
bottom: 140%;
|
||||||
|
left: -225%;
|
||||||
|
right: -225%;
|
||||||
|
top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.hiddenFileInput {
|
.hiddenFileInput {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
width: 0;
|
width: 0;
|
||||||
|
@ -80,7 +80,7 @@ body[dir="rtl"] #panes > div:nth-of-type(2) {
|
|||||||
}
|
}
|
||||||
#panes > div:nth-of-type(1) {
|
#panes > div:nth-of-type(1) {
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
padding: 4px 1px;
|
padding: 0;
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -131,6 +131,33 @@ body.off #switch .fa {
|
|||||||
.tool:hover {
|
.tool:hover {
|
||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
|
#extraTools {
|
||||||
|
background-color: #eee;
|
||||||
|
border: 0;
|
||||||
|
color: #aaa;
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 1em 0 0 0;
|
||||||
|
padding: 4px 0 2px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#extraTools > span {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 0 0.5em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#extraTools > span.on > span {
|
||||||
|
color: #e00;
|
||||||
|
font-size: 20px;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#extraTools > span.on > span:after {
|
||||||
|
content: '\2715';
|
||||||
|
}
|
||||||
|
|
||||||
body.advancedUser h2 {
|
body.advancedUser h2 {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title></title>
|
<title></title>
|
||||||
|
<link rel="stylesheet" href="css/common.css" type="text/css">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
@ -33,21 +34,22 @@ button {
|
|||||||
padding: 0.25em 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
}
|
}
|
||||||
img {
|
#warningSign {
|
||||||
height: 60vh;
|
margin: 1e, 0;
|
||||||
left: 10vw;
|
opacity: 1;
|
||||||
opacity: 0.05;
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: fixed;
|
width: 100%;
|
||||||
bottom: 5vh;
|
}
|
||||||
width: 80vw;
|
#warningSign > span {
|
||||||
|
color: #f2a500;
|
||||||
|
font-size: 180px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- http://commons.wikimedia.org/wiki/File:Caution_sign_used_on_roads_pn.svg
|
<!-- http://commons.wikimedia.org/wiki/File:Caution_sign_used_on_roads_pn.svg
|
||||||
Public domain. I removed the shadow.
|
Public domain. I removed the shadow.
|
||||||
--><img src="img/Caution_sign_used_on_roads_pn.svg" />
|
--><div id="warningSign"><span class="fa"></span></div>
|
||||||
<div>
|
<div>
|
||||||
<p data-i18n="docblockedPrompt1"></p>
|
<p data-i18n="docblockedPrompt1"></p>
|
||||||
<p class="what code"></p>
|
<p class="what code"></p>
|
||||||
|
@ -57,7 +57,6 @@ return {
|
|||||||
autoUpdate: true,
|
autoUpdate: true,
|
||||||
collapseBlocked: true,
|
collapseBlocked: true,
|
||||||
contextMenuEnabled: true,
|
contextMenuEnabled: true,
|
||||||
dynamicFilteringString: '',
|
|
||||||
dynamicFilteringEnabled: false,
|
dynamicFilteringEnabled: false,
|
||||||
experimentalEnabled: false,
|
experimentalEnabled: false,
|
||||||
externalLists: defaultExternalLists,
|
externalLists: defaultExternalLists,
|
||||||
@ -88,7 +87,7 @@ return {
|
|||||||
|
|
||||||
// read-only
|
// read-only
|
||||||
systemSettings: {
|
systemSettings: {
|
||||||
compiledMagic: 'squafjaywuba',
|
compiledMagic: 'perhodsoahya',
|
||||||
selfieMagic: 'spqmeuaftfra'
|
selfieMagic: 'spqmeuaftfra'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
283
src/js/hnswitches.js
Normal file
283
src/js/hnswitches.js
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock - a Chromium browser extension to black/white list requests.
|
||||||
|
Copyright (C) 2015 Raymond Hill
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
|
|
||||||
|
Home: https://github.com/gorhill/uBlock
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* global punycode, µBlock */
|
||||||
|
/* jshint bitwise: false */
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µBlock.HnSwitches = (function() {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var HnSwitches = function() {
|
||||||
|
this.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var switchBitOffsets = {
|
||||||
|
'dontBlockDoc': 0,
|
||||||
|
'doBlockAllPopups': 2
|
||||||
|
};
|
||||||
|
|
||||||
|
var switchStateToNameMap = {
|
||||||
|
'1': 'true',
|
||||||
|
'2': 'false'
|
||||||
|
};
|
||||||
|
|
||||||
|
var nameToSwitchStateMap = {
|
||||||
|
'true': 1,
|
||||||
|
'false': 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// For performance purpose, as simple tests as possible
|
||||||
|
var reHostnameVeryCoarse = /[g-z_-]/;
|
||||||
|
var reIPv4VeryCoarse = /\.\d+$/;
|
||||||
|
|
||||||
|
// http://tools.ietf.org/html/rfc5952
|
||||||
|
// 4.3: "MUST be represented in lowercase"
|
||||||
|
// Also: http://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_network_resource_identifiers
|
||||||
|
|
||||||
|
var isIPAddress = function(hostname) {
|
||||||
|
if ( reHostnameVeryCoarse.test(hostname) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( reIPv4VeryCoarse.test(hostname) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return hostname.charAt(0) === '[';
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var toBroaderHostname = function(hostname) {
|
||||||
|
if ( hostname === '*' ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if ( isIPAddress(hostname) ) {
|
||||||
|
return '*';
|
||||||
|
}
|
||||||
|
var pos = hostname.indexOf('.');
|
||||||
|
if ( pos === -1 ) {
|
||||||
|
return '*';
|
||||||
|
}
|
||||||
|
return hostname.slice(pos + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
HnSwitches.toBroaderHostname = toBroaderHostname;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
HnSwitches.prototype.reset = function() {
|
||||||
|
this.switches = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// If value is undefined, the switch is removed
|
||||||
|
|
||||||
|
HnSwitches.prototype.toggle = function(switchName, hostname, newVal) {
|
||||||
|
var bitOffset = switchBitOffsets[switchName];
|
||||||
|
if ( bitOffset === undefined ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( newVal === this.evaluate(switchName, hostname) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var bits = this.switches[hostname] || 0;
|
||||||
|
bits &= ~(3 << bitOffset);
|
||||||
|
bits |= newVal << bitOffset;
|
||||||
|
if ( bits === 0 ) {
|
||||||
|
delete this.switches[hostname];
|
||||||
|
} else {
|
||||||
|
this.switches[hostname] = bits;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
HnSwitches.prototype.toggleZ = function(switchName, hostname, newState) {
|
||||||
|
var bitOffset = switchBitOffsets[switchName];
|
||||||
|
if ( bitOffset === undefined ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var state = this.evaluateZ(switchName, hostname);
|
||||||
|
if ( newState === state ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( newState === undefined ) {
|
||||||
|
newState = !state;
|
||||||
|
}
|
||||||
|
var bits = this.switches[hostname] || 0;
|
||||||
|
bits &= ~(3 << bitOffset);
|
||||||
|
if ( bits === 0 ) {
|
||||||
|
delete this.switches[hostname];
|
||||||
|
} else {
|
||||||
|
this.switches[hostname] = bits;
|
||||||
|
}
|
||||||
|
state = this.evaluateZ(switchName, hostname);
|
||||||
|
if ( state === newState ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.switches[hostname] = bits | ((newState ? 1 : 2) << bitOffset);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// 0 = inherit from broader scope, up to default state
|
||||||
|
// 1 = non-default state
|
||||||
|
// 2 = forced default state (to override a broader non-default state)
|
||||||
|
|
||||||
|
HnSwitches.prototype.evaluate = function(switchName, hostname) {
|
||||||
|
var bits = this.switches[hostname] || 0;
|
||||||
|
if ( bits === 0 ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
var bitOffset = switchBitOffsets[switchName];
|
||||||
|
if ( bitOffset === undefined ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (bits >> bitOffset) & 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
HnSwitches.prototype.evaluateZ = function(switchName, hostname) {
|
||||||
|
var bitOffset = switchBitOffsets[switchName];
|
||||||
|
if ( bitOffset === undefined ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var bits;
|
||||||
|
var s = hostname;
|
||||||
|
for (;;) {
|
||||||
|
bits = this.switches[s] || 0;
|
||||||
|
if ( bits !== 0 ) {
|
||||||
|
bits = bits >> bitOffset & 3;
|
||||||
|
if ( bits !== 0 ) {
|
||||||
|
return bits === 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s = toBroaderHostname(s);
|
||||||
|
if ( s === '' ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
HnSwitches.prototype.toString = function() {
|
||||||
|
var out = [];
|
||||||
|
var switchName, val;
|
||||||
|
var hostname;
|
||||||
|
for ( hostname in this.switches ) {
|
||||||
|
if ( this.switches.hasOwnProperty(hostname) === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for ( switchName in switchBitOffsets ) {
|
||||||
|
if ( switchBitOffsets.hasOwnProperty(switchName) === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
val = this.evaluate(switchName, hostname);
|
||||||
|
if ( val === 0 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out.push(switchName + ': ' + hostname + ' ' + switchStateToNameMap[val]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
HnSwitches.prototype.fromString = function(text) {
|
||||||
|
var textEnd = text.length;
|
||||||
|
var lineBeg = 0, lineEnd;
|
||||||
|
var line, pos;
|
||||||
|
var fields;
|
||||||
|
var switchName, hostname, state;
|
||||||
|
|
||||||
|
while ( lineBeg < textEnd ) {
|
||||||
|
lineEnd = text.indexOf('\n', lineBeg);
|
||||||
|
if ( lineEnd < 0 ) {
|
||||||
|
lineEnd = text.indexOf('\r', lineBeg);
|
||||||
|
if ( lineEnd < 0 ) {
|
||||||
|
lineEnd = textEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line = text.slice(lineBeg, lineEnd).trim();
|
||||||
|
lineBeg = lineEnd + 1;
|
||||||
|
|
||||||
|
pos = line.indexOf('# ');
|
||||||
|
if ( pos !== -1 ) {
|
||||||
|
line = line.slice(0, pos).trim();
|
||||||
|
}
|
||||||
|
if ( line === '' ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = line.split(/\s+/);
|
||||||
|
if ( fields.length !== 3 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switchName = fields[0];
|
||||||
|
pos = switchName.indexOf(':');
|
||||||
|
if ( pos === -1 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switchName = switchName.slice(0, pos);
|
||||||
|
if ( switchBitOffsets.hasOwnProperty(switchName) === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname = punycode.toASCII(fields[1]);
|
||||||
|
|
||||||
|
state = fields[2];
|
||||||
|
if ( nameToSwitchStateMap.hasOwnProperty(state) === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toggle(switchName, hostname, nameToSwitchStateMap[state]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
return HnSwitches;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µBlock.hnSwitches = new µBlock.HnSwitches();
|
||||||
|
|
||||||
|
/******************************************************************************/
|
@ -88,6 +88,10 @@ var onMessage = function(request, sender, callback) {
|
|||||||
µb.selectFilterLists(request.switches);
|
µb.selectFilterLists(request.switches);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'toggleHostnameSwitch':
|
||||||
|
µb.toggleHostnameSwitch(request);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'userSettings':
|
case 'userSettings':
|
||||||
response = µb.changeUserSettings(request.name, request.value);
|
response = µb.changeUserSettings(request.name, request.value);
|
||||||
break;
|
break;
|
||||||
@ -229,6 +233,8 @@ var getStats = function(tabId, tabTitle) {
|
|||||||
r.firewallRules = getFirewallRules(pageStore.pageHostname, r.hostnameDict);
|
r.firewallRules = getFirewallRules(pageStore.pageHostname, r.hostnameDict);
|
||||||
r.canElementPicker = r.pageHostname.indexOf('.') !== -1;
|
r.canElementPicker = r.pageHostname.indexOf('.') !== -1;
|
||||||
r.canRequestLog = canRequestLog;
|
r.canRequestLog = canRequestLog;
|
||||||
|
r.doBlockAllPopups = µb.hnSwitches.evaluateZ('doBlockAllPopups', r.pageHostname);
|
||||||
|
r.dontBlockDoc = µb.hnSwitches.evaluateZ('dontBlockDoc', r.pageHostname);
|
||||||
} else {
|
} else {
|
||||||
r.hostnameDict = {};
|
r.hostnameDict = {};
|
||||||
r.firewallRules = getFirewallRules();
|
r.firewallRules = getFirewallRules();
|
||||||
@ -1007,6 +1013,8 @@ var backupUserData = function(callback) {
|
|||||||
userSettings: µb.userSettings,
|
userSettings: µb.userSettings,
|
||||||
filterLists: µb.remoteBlacklists,
|
filterLists: µb.remoteBlacklists,
|
||||||
netWhitelist: µb.stringFromWhitelist(µb.netWhitelist),
|
netWhitelist: µb.stringFromWhitelist(µb.netWhitelist),
|
||||||
|
dynamicFilteringString: µb.permanentFirewall.toString(),
|
||||||
|
hostnameSwitchesString: µb.hnSwitches.toString(),
|
||||||
userFilters: details.content
|
userFilters: details.content
|
||||||
};
|
};
|
||||||
var now = new Date();
|
var now = new Date();
|
||||||
@ -1033,7 +1041,7 @@ var backupUserData = function(callback) {
|
|||||||
|
|
||||||
var restoreUserData = function(request) {
|
var restoreUserData = function(request) {
|
||||||
var userData = request.userData;
|
var userData = request.userData;
|
||||||
var countdown = 5;
|
var countdown = 7;
|
||||||
var onCountdown = function() {
|
var onCountdown = function() {
|
||||||
countdown -= 1;
|
countdown -= 1;
|
||||||
if ( countdown === 0 ) {
|
if ( countdown === 0 ) {
|
||||||
@ -1047,9 +1055,15 @@ var restoreUserData = function(request) {
|
|||||||
µBlock.saveLocalSettings(true);
|
µBlock.saveLocalSettings(true);
|
||||||
µb.XAL.keyvalSetMany(userData.userSettings, onCountdown);
|
µb.XAL.keyvalSetMany(userData.userSettings, onCountdown);
|
||||||
µb.XAL.keyvalSetOne('remoteBlacklists', userData.filterLists, onCountdown);
|
µb.XAL.keyvalSetOne('remoteBlacklists', userData.filterLists, onCountdown);
|
||||||
µb.XAL.keyvalSetOne('netWhitelist', userData.netWhitelist, onCountdown);
|
µb.XAL.keyvalSetOne('netWhitelist', userData.netWhitelist || '', onCountdown);
|
||||||
µb.assets.put('assets/user/filters.txt', userData.userFilters, onCountdown);
|
|
||||||
|
|
||||||
|
// With versions 0.9.2.4-, dynamic rules were saved within the
|
||||||
|
// `userSettings` object. No longer the case.
|
||||||
|
var s = userData.dynamicFilteringString || userData.userSettings.dynamicFilteringString || '';
|
||||||
|
µb.XAL.keyvalSetOne('dynamicFilteringString', s, onCountdown);
|
||||||
|
|
||||||
|
µb.XAL.keyvalSetOne('hostnameSwitchesString', userData.hostnameSwitchesString || '', onCountdown);
|
||||||
|
µb.assets.put('assets/user/filters.txt', userData.userFilters, onCountdown);
|
||||||
µb.XAL.keyvalSetMany({
|
µb.XAL.keyvalSetMany({
|
||||||
lastRestoreFile: request.file || '',
|
lastRestoreFile: request.file || '',
|
||||||
lastRestoreTime: Date.now(),
|
lastRestoreTime: Date.now(),
|
||||||
|
@ -429,6 +429,10 @@ var renderPopup = function() {
|
|||||||
// This will collate all domains, touched or not
|
// This will collate all domains, touched or not
|
||||||
renderPrivacyExposure();
|
renderPrivacyExposure();
|
||||||
|
|
||||||
|
// Extra tools
|
||||||
|
uDom('#doBlockAllPopups').toggleClass('on', popupData.doBlockAllPopups === true);
|
||||||
|
uDom('#dontBlockDoc').toggleClass('on', popupData.dontBlockDoc === true);
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/470
|
// https://github.com/gorhill/uBlock/issues/470
|
||||||
// This must be done here, to be sure the popup is resized properly
|
// This must be done here, to be sure the popup is resized properly
|
||||||
var dfPaneVisible = popupData.dfEnabled && popupData.advancedUserEnabled;
|
var dfPaneVisible = popupData.dfEnabled && popupData.advancedUserEnabled;
|
||||||
@ -651,6 +655,23 @@ var saveFirewallRules = function() {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var toggleHostnameSwitch = function() {
|
||||||
|
var elem = uDom(this);
|
||||||
|
var switchName = elem.attr('id');
|
||||||
|
if ( !switchName ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elem.toggleClass('on');
|
||||||
|
messager.send({
|
||||||
|
what: 'toggleHostnameSwitch',
|
||||||
|
name: switchName,
|
||||||
|
hostname: popupData.pageHostname,
|
||||||
|
state: elem.hasClass('on')
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
// Poll for changes.
|
// Poll for changes.
|
||||||
//
|
//
|
||||||
// I couldn't find a better way to be notified of changes which can affect
|
// I couldn't find a better way to be notified of changes which can affect
|
||||||
@ -733,6 +754,7 @@ uDom.onLoad(function () {
|
|||||||
uDom('a[href]').on('click', gotoURL);
|
uDom('a[href]').on('click', gotoURL);
|
||||||
uDom('h2').on('click', toggleFirewallPane);
|
uDom('h2').on('click', toggleFirewallPane);
|
||||||
uDom('#refresh').on('click', reloadTab);
|
uDom('#refresh').on('click', reloadTab);
|
||||||
|
uDom('.hnSwitch').on('click', toggleHostnameSwitch);
|
||||||
uDom('#saveRules').on('click', saveFirewallRules);
|
uDom('#saveRules').on('click', saveFirewallRules);
|
||||||
uDom('[data-i18n="popupAnyRulePrompt"]').on('click', toggleMinimize);
|
uDom('[data-i18n="popupAnyRulePrompt"]').on('click', toggleMinimize);
|
||||||
});
|
});
|
||||||
|
@ -135,8 +135,9 @@ var onUserSettingsReady = function(fetched) {
|
|||||||
µb.mirrors.toggle(false /* userSettings.experimentalEnabled */);
|
µb.mirrors.toggle(false /* userSettings.experimentalEnabled */);
|
||||||
|
|
||||||
µb.contextMenu.toggle(userSettings.contextMenuEnabled);
|
µb.contextMenu.toggle(userSettings.contextMenuEnabled);
|
||||||
µb.permanentFirewall.fromString(userSettings.dynamicFilteringString);
|
µb.permanentFirewall.fromString(fetched.dynamicFilteringString);
|
||||||
µb.sessionFirewall.assign(µb.permanentFirewall);
|
µb.sessionFirewall.assign(µb.permanentFirewall);
|
||||||
|
µb.hnSwitches.fromString(fetched.hostnameSwitchesString);
|
||||||
|
|
||||||
// Remove obsolete setting
|
// Remove obsolete setting
|
||||||
delete userSettings.logRequests;
|
delete userSettings.logRequests;
|
||||||
@ -214,6 +215,8 @@ return function() {
|
|||||||
|
|
||||||
var fetchableProps = {
|
var fetchableProps = {
|
||||||
'compiledMagic': '',
|
'compiledMagic': '',
|
||||||
|
'dynamicFilteringString': '',
|
||||||
|
'hostnameSwitchesString': '',
|
||||||
'lastRestoreFile': '',
|
'lastRestoreFile': '',
|
||||||
'lastRestoreTime': 0,
|
'lastRestoreTime': 0,
|
||||||
'lastBackupFile': '',
|
'lastBackupFile': '',
|
||||||
|
@ -63,7 +63,6 @@ var typeNameToTypeValue = {
|
|||||||
'xmlhttprequest': 5 << 4,
|
'xmlhttprequest': 5 << 4,
|
||||||
'sub_frame': 6 << 4,
|
'sub_frame': 6 << 4,
|
||||||
'other': 7 << 4,
|
'other': 7 << 4,
|
||||||
'main_frame': 12 << 4,
|
|
||||||
'cosmetic-filtering': 13 << 4,
|
'cosmetic-filtering': 13 << 4,
|
||||||
'inline-script': 14 << 4,
|
'inline-script': 14 << 4,
|
||||||
'popup': 15 << 4
|
'popup': 15 << 4
|
||||||
@ -2117,7 +2116,7 @@ FilterContainer.prototype.matchString = function(context) {
|
|||||||
// Use exact type match for anything beyond `other`
|
// Use exact type match for anything beyond `other`
|
||||||
// Also, be prepared to support unknown types
|
// Also, be prepared to support unknown types
|
||||||
var type = typeNameToTypeValue[context.requestType] || typeOtherValue;
|
var type = typeNameToTypeValue[context.requestType] || typeOtherValue;
|
||||||
if ( type > (7 << 4) ) {
|
if ( type > typeOtherValue ) {
|
||||||
return this.matchStringExactType(context, context.requestURL, context.requestType);
|
return this.matchStringExactType(context, context.requestURL, context.requestType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +70,13 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
µBlock.savePermanentFirewallRules = function() {
|
µBlock.savePermanentFirewallRules = function() {
|
||||||
this.userSettings.dynamicFilteringString = this.permanentFirewall.toString();
|
this.XAL.keyvalSetOne('dynamicFilteringString', this.permanentFirewall.toString());
|
||||||
this.XAL.keyvalSetOne('dynamicFilteringString', this.userSettings.dynamicFilteringString);
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µBlock.saveHostnameSwitches = function() {
|
||||||
|
this.XAL.keyvalSetOne('hostnameSwitchesString', this.hnSwitches.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -111,11 +111,26 @@ vAPI.tabs.onPopup = function(details) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var targetURL = details.targetURL;
|
var targetURL = details.targetURL;
|
||||||
|
|
||||||
|
// If the page URL is that of our "blocked page" URL, extract the URL of
|
||||||
|
// the page which was blocked.
|
||||||
|
if ( targetURL.lastIndexOf(vAPI.getURL('document-blocked.html'), 0) === 0 ) {
|
||||||
|
var matches = /details=([^&]+)/.exec(targetURL);
|
||||||
|
if ( matches !== null ) {
|
||||||
|
targetURL = JSON.parse(atob(matches[1])).url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var result = '';
|
var result = '';
|
||||||
|
|
||||||
|
// Check user switch first
|
||||||
|
if ( µb.hnSwitches.evaluateZ('doBlockAllPopups', openerHostname) ) {
|
||||||
|
result = 'ub:doBlockAllPopups true';
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/323
|
// https://github.com/gorhill/uBlock/issues/323
|
||||||
// If popup URL is whitelisted, do not block it
|
// If popup URL is whitelisted, do not block it
|
||||||
if ( µb.getNetFilteringSwitch(targetURL) ) {
|
if ( result === '' && µb.getNetFilteringSwitch(targetURL) ) {
|
||||||
result = µb.staticNetFilteringEngine.matchStringExactType(context, targetURL, 'popup');
|
result = µb.staticNetFilteringEngine.matchStringExactType(context, targetURL, 'popup');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,11 +199,18 @@ var onBeforeRootFrameRequest = function(details) {
|
|||||||
|
|
||||||
var result = '';
|
var result = '';
|
||||||
|
|
||||||
|
// Permanently unrestricted?
|
||||||
|
if ( result === '' && µb.hnSwitches.evaluateZ('dontBlockDoc', requestHostname) ) {
|
||||||
|
result = 'ua:dontBlockDoc true';
|
||||||
|
}
|
||||||
|
|
||||||
// Temporarily whitelisted?
|
// Temporarily whitelisted?
|
||||||
var obsolete = documentWhitelists[requestHostname];
|
var obsolete = documentWhitelists[requestHostname];
|
||||||
if ( obsolete !== undefined ) {
|
if ( obsolete !== undefined ) {
|
||||||
if ( obsolete > Date.now() ) {
|
if ( obsolete > Date.now() ) {
|
||||||
result = 'da:*' + ' ' + requestHostname + ' doc allow';
|
if ( result === '' ) {
|
||||||
|
result = 'ta:*' + ' ' + requestHostname + ' doc allow';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
delete documentWhitelists[requestHostname];
|
delete documentWhitelists[requestHostname];
|
||||||
}
|
}
|
||||||
@ -211,15 +218,7 @@ var onBeforeRootFrameRequest = function(details) {
|
|||||||
|
|
||||||
// Filtering
|
// Filtering
|
||||||
if ( result === '' && µb.getNetFilteringSwitch(requestURL) ) {
|
if ( result === '' && µb.getNetFilteringSwitch(requestURL) ) {
|
||||||
if ( µb.userSettings.advancedUserEnabled ) {
|
result = µb.staticNetFilteringEngine.matchString(context);
|
||||||
var df = µb.sessionFirewall.evaluateCellZY(requestHostname, requestHostname, '*');
|
|
||||||
if ( df.mustBlockOrAllow() ) {
|
|
||||||
result = df.toFilterString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( result === '' ) {
|
|
||||||
result = µb.staticNetFilteringEngine.matchString(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
@ -236,9 +235,12 @@ var onBeforeRootFrameRequest = function(details) {
|
|||||||
// Blocked
|
// Blocked
|
||||||
var query = btoa(JSON.stringify({
|
var query = btoa(JSON.stringify({
|
||||||
url: requestURL,
|
url: requestURL,
|
||||||
why: result + '$document'
|
why: result
|
||||||
}));
|
}));
|
||||||
return { redirectUrl: vAPI.getURL('document-blocked.html?details=') + query };
|
|
||||||
|
vAPI.tabs.replace(details.tabId, vAPI.getURL('document-blocked.html?details=') + query);
|
||||||
|
|
||||||
|
return { cancel: true };
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -318,4 +318,12 @@ var matchWhitelistDirective = function(url, hostname, directive) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µBlock.toggleHostnameSwitch = function(details) {
|
||||||
|
if ( this.hnSwitches.toggleZ(details.name, details.hostname, details.state) ) {
|
||||||
|
this.saveHostnameSwitches();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
<p class="statValue" id="total-blocked">?</p>
|
<p class="statValue" id="total-blocked">?</p>
|
||||||
<h2 data-i18n="popupHitDomainCountPrompt"> </h2>
|
<h2 data-i18n="popupHitDomainCountPrompt"> </h2>
|
||||||
<p class="statValue" id="popupHitDomainCount"> </p>
|
<p class="statValue" id="popupHitDomainCount"> </p>
|
||||||
|
<div id="extraTools">
|
||||||
|
<span id="doBlockAllPopups" class="hnSwitch fa" data-i18n-tip="popupTipDoBlockAllPopups" data-tip-anchor="topcenter"><span></span></span>
|
||||||
|
<span id="dontBlockDoc" class="hnSwitch fa" data-i18n-tip="popupTipDontBlockDoc" data-tip-anchor="topcenter"><span></span></span>
|
||||||
|
</div>
|
||||||
<div id="refresh" class="fa"></div>
|
<div id="refresh" class="fa"></div>
|
||||||
</div><!-- DO NOT REMOVE --><div>
|
</div><!-- DO NOT REMOVE --><div>
|
||||||
<div id="firewallContainer">
|
<div id="firewallContainer">
|
||||||
|
Loading…
Reference in New Issue
Block a user