mirror of
https://github.com/gorhill/uMatrix.git
synced 2024-09-28 15:21:49 +12:00
work on many things, need more
This commit is contained in:
parent
65a8000657
commit
2b41bc8087
24 changed files with 1539 additions and 661 deletions
|
@ -66,34 +66,12 @@ table td:first-child {
|
||||||
<div>
|
<div>
|
||||||
<p><button type="button" id="backupUserDataButton" data-i18n="aboutUserDataBackupButton"></button>
|
<p><button type="button" id="backupUserDataButton" data-i18n="aboutUserDataBackupButton"></button>
|
||||||
<button type="button" id="restoreUserDataButton" data-i18n="aboutUserDataRestoreButton"></button>
|
<button type="button" id="restoreUserDataButton" data-i18n="aboutUserDataRestoreButton"></button>
|
||||||
|
<input id="restoreFilePicker" type="file" accept="text/plain" style="display:none;">
|
||||||
<p style="margin-left: 2em;" data-i18n="aboutUserDataOr">
|
<p style="margin-left: 2em;" data-i18n="aboutUserDataOr">
|
||||||
<p><button type="button" id="resetUserDataButton" data-i18n="aboutUserDataResetButton"></button>
|
<p><button type="button" id="resetUserDataButton" data-i18n="aboutUserDataResetButton"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 data-i18n="aboutExtensionDataHeader"></h2>
|
<script src="js/udom.js"></script>
|
||||||
<div>
|
|
||||||
<p class="para" data-i18n="aboutAssetsUpdatePrompt"></p>
|
|
||||||
<div id="assetList">
|
|
||||||
<!--
|
|
||||||
Let's define 'abc' as bit 0 to 2
|
|
||||||
Where bit can be '0' or '1'
|
|
||||||
Bit 0: list => o=absent, x=present
|
|
||||||
Bit 1: list => o=clean, x=dirty
|
|
||||||
Bit 2: update => o=idle, x=updating
|
|
||||||
Therefore:
|
|
||||||
List visible: oox oxx xox
|
|
||||||
Etc.
|
|
||||||
-->
|
|
||||||
<table class="ooo">
|
|
||||||
<tr><th data-i18n="aboutAssetsUpdateColPath"><th data-i18n="aboutAssetsUpdateColStatus">
|
|
||||||
</table>
|
|
||||||
<p class="ooo" style="color:red" data-i18n="aboutAssetsUpdateGetListError"></p>
|
|
||||||
<p class="oxx"><button type="button" id="aboutAssetsUpdateButton" data-i18n="aboutAssetsUpdateButton"></button></p>
|
|
||||||
<p class="xxx"><button type="button" disabled data-i18n="aboutAssetsUpdatingButton"></button></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="lib/jquery-2.min.js"></script>
|
|
||||||
<script src="js/i18n.js"></script>
|
<script src="js/i18n.js"></script>
|
||||||
<script src="js/dashboard-common.js"></script>
|
<script src="js/dashboard-common.js"></script>
|
||||||
<script src="js/messaging-client.js"></script>
|
<script src="js/messaging-client.js"></script>
|
||||||
|
|
19
src/asset-viewer.html
Normal file
19
src/asset-viewer.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<title>µMatrix — Asset</title>
|
||||||
|
<style>
|
||||||
|
#content {
|
||||||
|
font: 12px monospace;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content"></div>
|
||||||
|
<script src="js/udom.js"></script>
|
||||||
|
<script src="js/messaging-client.js"></script>
|
||||||
|
<script src="js/asset-viewer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -17,7 +17,6 @@
|
||||||
<script src="js/matrix.js"></script>
|
<script src="js/matrix.js"></script>
|
||||||
<script src="js/utils.js"></script>
|
<script src="js/utils.js"></script>
|
||||||
<script src="js/assets.js"></script>
|
<script src="js/assets.js"></script>
|
||||||
<script src="js/asset-updater.js"></script>
|
|
||||||
<script src="js/httpsb.js"></script>
|
<script src="js/httpsb.js"></script>
|
||||||
<script src="js/reqstats.js"></script>
|
<script src="js/reqstats.js"></script>
|
||||||
<script src="js/cookies.js"></script>
|
<script src="js/cookies.js"></script>
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 0.5em 5em 0.5em;
|
padding: 0 0.5em 5em 0.5em;
|
||||||
font: 15px httpsb,sans-serif;
|
font: 15px sans-serif;
|
||||||
|
}
|
||||||
|
body > *:first-child {
|
||||||
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
h2, h3 {
|
h2, h3 {
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
|
@ -24,7 +27,7 @@ a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
padding: 0.4em;
|
padding: 0.3em 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.para {
|
.para {
|
||||||
|
@ -49,6 +52,7 @@ button {
|
||||||
.whatisthis-expandable {
|
.whatisthis-expandable {
|
||||||
margin: 0.5em 0 1em 1.25em;
|
margin: 0.5em 0 1em 1.25em;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
font-size: smaller;
|
||||||
display: none;
|
display: none;
|
||||||
border: 1px dotted black;
|
border: 1px dotted black;
|
||||||
background-color: #F8F8F8;
|
background-color: #F8F8F8;
|
||||||
|
|
115
src/css/hosts-files.css
Normal file
115
src/css/hosts-files.css
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
ul#options {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
ul#options li {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
ul#lists {
|
||||||
|
margin: 0.5em 0 0 0;
|
||||||
|
padding-__MSG_@@bidi_end_edge__: 0em;
|
||||||
|
padding-__MSG_@@bidi_start_edge__: 1em;
|
||||||
|
}
|
||||||
|
li.listDetails {
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0 auto 0 auto;
|
||||||
|
margin-__MSG_@@bidi_start_edge__: 1em;
|
||||||
|
margin-__MSG_@@bidi_end_edge__: 0em;
|
||||||
|
}
|
||||||
|
li.listDetails > * {
|
||||||
|
unicode-bidi: embed;
|
||||||
|
}
|
||||||
|
li.listDetails > a:nth-of-type(2) {
|
||||||
|
font-size: 13px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.dim {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
/* I designed the button with: http://charliepark.org/bootstrap_buttons/ */
|
||||||
|
button.custom {
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-color: #80b3ff #80b3ff hsl(216, 100%, 75%);
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: hsl(216, 100%, 75%);
|
||||||
|
background-image: linear-gradient(#a8cbff, #80b3ff);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
color: #222;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
button.custom.disabled {
|
||||||
|
border-color: #dddddd #dddddd hsl(36, 0%, 85%);
|
||||||
|
background-color: hsl(36, 0%, 72%);
|
||||||
|
background-image: linear-gradient(#f2f2f2, #dddddd);
|
||||||
|
color: #aaa;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
button.custom:hover {
|
||||||
|
opacity: 1.0;
|
||||||
|
}
|
||||||
|
button.custom.reloadAll:not(.disabled) {
|
||||||
|
border-color: #ffcc7f #ffcc7f hsl(36, 100%, 73%);
|
||||||
|
background-color: hsl(36, 100%, 75%);
|
||||||
|
background-image: linear-gradient(#ffdca8, #ffcc7f);
|
||||||
|
}
|
||||||
|
#buttonApply {
|
||||||
|
position: fixed;
|
||||||
|
display: initial;
|
||||||
|
top: 1em;
|
||||||
|
__MSG_@@bidi_end_edge__: 1em;
|
||||||
|
}
|
||||||
|
#buttonApply.disabled {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
span.status {
|
||||||
|
margin: 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: 1px 2px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 11px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
span.purge {
|
||||||
|
border-color: #ddd;
|
||||||
|
color: #444;
|
||||||
|
background-color: #eee;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
span.purge:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
span.obsolete {
|
||||||
|
border-color: hsl(36, 100%, 73%);
|
||||||
|
color: #222;
|
||||||
|
background-color: hsl(36, 100%, 75%);
|
||||||
|
}
|
||||||
|
#externalListsDiv {
|
||||||
|
margin: 2em auto 0 auto;
|
||||||
|
margin-__MSG_@@bidi_start_edge__: 2em;
|
||||||
|
}
|
||||||
|
#externalHostsFiles {
|
||||||
|
font-size: smaller;
|
||||||
|
width: 48em;
|
||||||
|
height: 12em;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
body #busyOverlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: white;
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: wait;
|
||||||
|
display: none;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
body.busy #busyOverlay {
|
||||||
|
display: block;
|
||||||
|
}
|
|
@ -438,12 +438,12 @@ body.colorblind .t82 {
|
||||||
body.colorblind .t1 {
|
body.colorblind .t1 {
|
||||||
border-color: #333;
|
border-color: #333;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #555;
|
background-color: #666;
|
||||||
}
|
}
|
||||||
body.colorblind .t2 {
|
body.colorblind .t2 {
|
||||||
border-color: #aaa;
|
border-color: #aaa;
|
||||||
color: black;
|
color: black;
|
||||||
background-color: #ddd;
|
background-color: #ccc;
|
||||||
}
|
}
|
||||||
body.colorblind .matCell.p81 {
|
body.colorblind .matCell.p81 {
|
||||||
background-image: url('/img/permanent-black-small-cb.png');
|
background-image: url('/img/permanent-black-small-cb.png');
|
||||||
|
|
|
@ -8,7 +8,7 @@ body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font: 15px httpsb,sans-serif;
|
font: 15px sans-serif;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
@ -18,7 +18,6 @@ body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
@ -27,7 +26,8 @@ body {
|
||||||
#dashboard-nav-widgets {
|
#dashboard-nav-widgets {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
padding: 4px 0 3px 0;
|
padding: 4px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ body {
|
||||||
border-top-left-radius: 3px;
|
border-top-left-radius: 3px;
|
||||||
border-top-right-radius: 3px;
|
border-top-right-radius: 3px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
color: black;
|
color: black;
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
|
@ -79,7 +80,7 @@ iframe {
|
||||||
<a class="tabButton" id="settings" href="#settings" data-dashboard-panel-url="settings.html" data-i18n="settingsPageName"></a>
|
<a class="tabButton" id="settings" href="#settings" data-dashboard-panel-url="settings.html" data-i18n="settingsPageName"></a>
|
||||||
<a class="tabButton" id="privacy" href="#privacy" data-dashboard-panel-url="privacy.html" data-i18n="privacyPageName"></a>
|
<a class="tabButton" id="privacy" href="#privacy" data-dashboard-panel-url="privacy.html" data-i18n="privacyPageName"></a>
|
||||||
<a class="tabButton" id="user-rules" href="#user-rules" data-dashboard-panel-url="user-rules.html" data-i18n="userRulesPageName"></a>
|
<a class="tabButton" id="user-rules" href="#user-rules" data-dashboard-panel-url="user-rules.html" data-i18n="userRulesPageName"></a>
|
||||||
<a class="tabButton" id="ubiquitous-rules" href="#ubiquitous-rules" data-dashboard-panel-url="ubiquitous-rules.html" data-i18n="ubiquitousRulesPageName"></a>
|
<a class="tabButton" id="hosts-files" href="#hosts-files" data-dashboard-panel-url="hosts-files.html" data-i18n="ubiquitousRulesPageName"></a>
|
||||||
<a class="tabButton" id="statistics" href="#statistics" data-dashboard-panel-url="info.html" data-i18n="statsPageName"></a>
|
<a class="tabButton" id="statistics" href="#statistics" data-dashboard-panel-url="info.html" data-i18n="statsPageName"></a>
|
||||||
<a class="tabButton" id="about" href="#about" data-dashboard-panel-url="about.html" data-i18n="aboutPageName"></a>
|
<a class="tabButton" id="about" href="#about" data-dashboard-panel-url="about.html" data-i18n="aboutPageName"></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,55 +2,39 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<title>µMatrix — Ubiquitous rules</title>
|
<title>HTTP Switchboard — Ubiquitous rules</title>
|
||||||
<link rel="stylesheet" type="text/css" href="css/common.css">
|
<link rel="stylesheet" type="text/css" href="css/common.css">
|
||||||
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css">
|
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css">
|
||||||
<style>
|
<link rel="stylesheet" type="text/css" href="css/hosts-files.css">
|
||||||
div > p:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
div > p:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
ul > li {
|
|
||||||
margin: 0 0 0 1em;
|
|
||||||
}
|
|
||||||
.dim {
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2 data-i18n="ubiquitousWhatIsThisHeader"></h2>
|
<p data-i18n="hostsFilesPrompt"></p>
|
||||||
<div>
|
<ul id="options">
|
||||||
<p data-i18n="ubiquitousWhatIsThisPrompt"></p>
|
<li><input type="checkbox" id="autoUpdate"><label data-i18n="hostsFilesAutoUpdatePrompt" for="autoUpdate"></label>
|
||||||
|
<button class="custom reloadAll disabled" id="buttonUpdate" data-i18n="hostsFilesUpdateNow"></button>
|
||||||
|
<button id="buttonPurgeAll" class="custom disabled" data-i18n="hostsFilesPurgeAll"></button>
|
||||||
|
<li><p id="listsOfBlockedHostsPrompt"></p>
|
||||||
|
</ul>
|
||||||
|
<button id="buttonApply" class="custom reloadAll disabled" data-i18n="hostsFilesApplyChanges"></button>
|
||||||
|
<ul id="lists">
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div id="externalListsDiv">
|
||||||
|
<p data-i18n="hostsFilesExternalListsHint" style="margin: 0 0 0.25em 0; font-size: 13px;"></p>
|
||||||
|
<textarea id="externalHostsFiles" dir="ltr" spellcheck="false"></textarea>
|
||||||
|
<p style="margin: 0.25em 0 0 0"><button id="externalListsParse" disabled="true" data-i18n="hostsFilesExternalListsParse"></button></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 data-i18n="ubiquitousListsOfBlockedHostsHeader"></h2>
|
<div id="busyOverlay"></div>
|
||||||
<div>
|
|
||||||
<p data-i18n="ubiquitousListsOfBlockedHostsPrompt1"></p>
|
|
||||||
<p id="ubiquitousListsOfBlockedHostsPrompt2"></p>
|
|
||||||
<ul id="blacklistTemplate" style="display:none">
|
|
||||||
<li class="blacklistDetails"><input type="checkbox"> <a href="" type="text/plain"></a>:
|
|
||||||
<span class="dim" data-i18n="ubiquitousListsOfBlockedHostsPerListStats"></span>
|
|
||||||
</ul>
|
|
||||||
<ul id="blacklists" style="margin:0.5em 0 0 0;padding-left:1em;list-style-type:none">
|
|
||||||
<li style="margin-top:0.75em"><button id="blacklistsApply" disabled="true" data-i18n="ubiquitousApplyChanges"></button>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="lib/jquery-2.min.js"></script>
|
|
||||||
<script src="js/udom.js"></script>
|
<script src="js/udom.js"></script>
|
||||||
<script src="js/i18n.js"></script>
|
<script src="js/i18n.js"></script>
|
||||||
<script src="js/dashboard-common.js"></script>
|
<script src="js/dashboard-common.js"></script>
|
||||||
<script src="js/messaging-client.js"></script>
|
<script src="js/messaging-client.js"></script>
|
||||||
<script src="js/ubiquitous-rules.js"></script>
|
<script src="js/hosts-files.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
142
src/js/about.js
142
src/js/about.js
|
@ -19,17 +19,11 @@
|
||||||
Home: https://github.com/gorhill/uMatrix
|
Home: https://github.com/gorhill/uMatrix
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* global chrome, $ */
|
/* global chrome, uDom */
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
$(function() {
|
uDom.onLoad(function() {
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var updateList = {};
|
|
||||||
var assetListSwitches = ['o', 'o', 'o'];
|
|
||||||
var commitHistoryURLPrefix = 'https://github.com/gorhill/httpswitchboard/commits/master/';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -75,12 +69,7 @@ var backupUserDataToFile = function() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var restoreUserDataFromFile = function() {
|
function restoreUserDataFromFile() {
|
||||||
var input = $('<input />').attr({
|
|
||||||
type: 'file',
|
|
||||||
accept: 'text/plain'
|
|
||||||
});
|
|
||||||
|
|
||||||
var restartCountdown = 4;
|
var restartCountdown = 4;
|
||||||
var doCountdown = function() {
|
var doCountdown = function() {
|
||||||
restartCountdown -= 1;
|
restartCountdown -= 1;
|
||||||
|
@ -151,23 +140,27 @@ var restoreUserDataFromFile = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var filePickerOnChangeHandler = function() {
|
var file = this.files[0];
|
||||||
$(this).off('change', filePickerOnChangeHandler);
|
if ( file === undefined || file.name === '' ) {
|
||||||
var file = this.files[0];
|
return;
|
||||||
if ( !file ) {
|
}
|
||||||
return;
|
if ( file.type.indexOf('text') !== 0 ) {
|
||||||
}
|
return;
|
||||||
if ( file.type.indexOf('text') !== 0 ) {
|
}
|
||||||
return;
|
var fr = new FileReader();
|
||||||
}
|
fr.onload = fileReaderOnLoadHandler;
|
||||||
var fr = new FileReader();
|
fr.readAsText(file);
|
||||||
fr.onload = fileReaderOnLoadHandler;
|
}
|
||||||
fr.readAsText(file);
|
|
||||||
input.off('change', filePickerOnChangeHandler);
|
|
||||||
};
|
|
||||||
|
|
||||||
input.on('change', filePickerOnChangeHandler);
|
/******************************************************************************/
|
||||||
input.trigger('click');
|
|
||||||
|
var startRestoreFilePicker = function() {
|
||||||
|
var input = document.getElementById('restoreFilePicker');
|
||||||
|
// Reset to empty string, this will ensure an change event is properly
|
||||||
|
// triggered if the user pick a file, even if it is the same as the last
|
||||||
|
// one picked.
|
||||||
|
input.value = '';
|
||||||
|
input.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -181,106 +174,29 @@ var resetUserData = function() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var setAssetListClassBit = function(bit, state) {
|
|
||||||
assetListSwitches[assetListSwitches.length-1-bit] = !state ? 'o' : 'x';
|
|
||||||
$('#assetList')
|
|
||||||
.removeClass()
|
|
||||||
.addClass(assetListSwitches.join(''));
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var renderAssetList = function(details) {
|
|
||||||
var dirty = false;
|
|
||||||
var paths = Object.keys(details.list).sort();
|
|
||||||
if ( paths.length > 0 ) {
|
|
||||||
$('#assetList .assetEntry').remove();
|
|
||||||
var assetTable = $('#assetList table');
|
|
||||||
var i = 0;
|
|
||||||
var path, status, html;
|
|
||||||
while ( path = paths[i++] ) {
|
|
||||||
status = details.list[path].status;
|
|
||||||
dirty = dirty || status !== 'Unchanged';
|
|
||||||
html = [];
|
|
||||||
html.push('<tr class="assetEntry ' + status.toLowerCase().replace(/ +/g, '-') + '">');
|
|
||||||
html.push('<td>');
|
|
||||||
html.push('<a href="' + commitHistoryURLPrefix + path + '">');
|
|
||||||
html.push(path.replace(/^(assets\/[^/]+\/)(.+)$/, '$1<b>$2</b>'));
|
|
||||||
html.push('</a>');
|
|
||||||
html.push('<td>');
|
|
||||||
html.push(chrome.i18n.getMessage('aboutAssetsUpdateStatus' + status));
|
|
||||||
assetTable.append(html.join(''));
|
|
||||||
}
|
|
||||||
$('#assetList a').attr('target', '_blank');
|
|
||||||
updateList = details.list;
|
|
||||||
}
|
|
||||||
setAssetListClassBit(0, paths.length !== 0);
|
|
||||||
setAssetListClassBit(1, dirty);
|
|
||||||
setAssetListClassBit(2, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var updateAssets = function() {
|
|
||||||
setAssetListClassBit(2, true);
|
|
||||||
var onDone = function(details) {
|
|
||||||
if ( details.changedCount !== 0 ) {
|
|
||||||
messaging.tell({ what: 'loadUpdatableAssets' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
messaging.ask({ what: 'launchAssetUpdater', list: updateList }, onDone);
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var updateAssetsList = function() {
|
|
||||||
messaging.ask({ what: 'getAssetUpdaterList' }, renderAssetList);
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// Updating all assets could be done from elsewhere and if so the
|
|
||||||
// list here needs to be updated.
|
|
||||||
|
|
||||||
var onAnnounce = function(msg) {
|
|
||||||
switch ( msg.what ) {
|
|
||||||
case 'allLocalAssetsUpdated':
|
|
||||||
updateAssetsList();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
messaging.start('about.js');
|
messaging.start('about.js');
|
||||||
messaging.listen(onAnnounce);
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
$('#aboutVersion').html(chrome.runtime.getManifest().version);
|
uDom('#aboutVersion').html(chrome.runtime.getManifest().version);
|
||||||
var renderStats = function(details) {
|
var renderStats = function(details) {
|
||||||
var template = chrome.i18n.getMessage('aboutStorageUsed');
|
var template = chrome.i18n.getMessage('aboutStorageUsed');
|
||||||
var percent = 0;
|
var percent = 0;
|
||||||
if ( details.storageQuota ) {
|
if ( details.storageQuota ) {
|
||||||
percent = (details.storageUsed / details.storageQuota * 100).toFixed(1);
|
percent = (details.storageUsed / details.storageQuota * 100).toFixed(1);
|
||||||
}
|
}
|
||||||
$('#aboutStorageUsed').html(template.replace('{{storageUsed}}', percent));
|
uDom('#aboutStorageUsed').html(template.replace('{{storageUsed}}', percent));
|
||||||
};
|
};
|
||||||
messaging.ask({ what: 'getSomeStats' }, renderStats);
|
messaging.ask({ what: 'getSomeStats' }, renderStats);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
$('#aboutAssetsUpdateButton').on('click', updateAssets);
|
uDom('#backupUserDataButton').on('click', backupUserDataToFile);
|
||||||
$('#backupUserDataButton').on('click', backupUserDataToFile);
|
uDom('#restoreUserDataButton').on('click', startRestoreFilePicker);
|
||||||
$('#restoreUserDataButton').on('click', restoreUserDataFromFile);
|
uDom('#restoreFilePicker').on('change', restoreUserDataFromFile);
|
||||||
$('#resetUserDataButton').on('click', resetUserData);
|
uDom('#resetUserDataButton').on('click', resetUserData);
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
updateAssetsList();
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
880
src/js/assets.js
880
src/js/assets.js
File diff suppressed because it is too large
Load diff
|
@ -45,6 +45,7 @@ return {
|
||||||
manifest: chrome.runtime.getManifest(),
|
manifest: chrome.runtime.getManifest(),
|
||||||
|
|
||||||
userSettings: {
|
userSettings: {
|
||||||
|
autoUpdate: false,
|
||||||
clearBrowserCache: true,
|
clearBrowserCache: true,
|
||||||
clearBrowserCacheAfter: 60,
|
clearBrowserCacheAfter: 60,
|
||||||
colorBlindFriendly: false,
|
colorBlindFriendly: false,
|
||||||
|
@ -53,11 +54,12 @@ return {
|
||||||
deleteUnusedSessionCookiesAfter: 60,
|
deleteUnusedSessionCookiesAfter: 60,
|
||||||
deleteLocalStorage: false,
|
deleteLocalStorage: false,
|
||||||
displayTextSize: '13px',
|
displayTextSize: '13px',
|
||||||
|
externalHostsFiles: '',
|
||||||
maxLoggedRequests: 50,
|
maxLoggedRequests: 50,
|
||||||
popupCollapseDomains: false,
|
popupCollapseDomains: false,
|
||||||
popupCollapseSpecificDomains: {},
|
popupCollapseSpecificDomains: {},
|
||||||
popupHideBlacklisted: false,
|
popupHideBlacklisted: false,
|
||||||
popupScopeLevel: '*',
|
popupScopeLevel: 'domain',
|
||||||
processBehindTheSceneRequests: false,
|
processBehindTheSceneRequests: false,
|
||||||
processHyperlinkAuditing: true,
|
processHyperlinkAuditing: true,
|
||||||
processReferer: false,
|
processReferer: false,
|
||||||
|
@ -74,13 +76,17 @@ return {
|
||||||
updateAssetsEvery: 5 * 24 * 60 * 60 * 1000,
|
updateAssetsEvery: 5 * 24 * 60 * 60 * 1000,
|
||||||
projectServerRoot: 'https://raw.githubusercontent.com/gorhill/umatrix/master/',
|
projectServerRoot: 'https://raw.githubusercontent.com/gorhill/umatrix/master/',
|
||||||
|
|
||||||
// list of remote blacklist locations
|
// permanent hosts files
|
||||||
remoteBlacklists: {
|
permanentHostsFiles: {
|
||||||
// uMatrix
|
// µMatrix
|
||||||
'assets/umatrix/blacklist.txt': { title: 'uMatrix' },
|
'assets/umatrix/blacklist.txt': {
|
||||||
|
title: 'µMatrix hosts file'
|
||||||
// 3rd-party lists now fetched dynamically
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// list of live hosts files
|
||||||
|
liveHostsFiles: {
|
||||||
|
},
|
||||||
|
|
||||||
// urls stats are kept on the back burner while waiting to be reactivated
|
// urls stats are kept on the back burner while waiting to be reactivated
|
||||||
// in a tab or another.
|
// in a tab or another.
|
||||||
|
@ -99,10 +105,7 @@ return {
|
||||||
tMatrix: null,
|
tMatrix: null,
|
||||||
pMatrix: null,
|
pMatrix: null,
|
||||||
|
|
||||||
// Current entries from ubiquitous lists --
|
|
||||||
// just hostnames, '*/' is implied, this saves significantly on memory.
|
|
||||||
ubiquitousBlacklist: null,
|
ubiquitousBlacklist: null,
|
||||||
ubiquitousWhitelist: null,
|
|
||||||
|
|
||||||
// various stats
|
// various stats
|
||||||
requestStats: new WebRequestStats(),
|
requestStats: new WebRequestStats(),
|
||||||
|
@ -128,6 +131,8 @@ return {
|
||||||
noopCSSURL: chrome.runtime.getURL('css/noop.css'),
|
noopCSSURL: chrome.runtime.getURL('css/noop.css'),
|
||||||
fontCSSURL: chrome.runtime.getURL('css/fonts/Roboto_Condensed/RobotoCondensed-Regular.ttf'),
|
fontCSSURL: chrome.runtime.getURL('css/fonts/Roboto_Condensed/RobotoCondensed-Regular.ttf'),
|
||||||
|
|
||||||
|
noopFunc: function(){},
|
||||||
|
|
||||||
// so that I don't have to care for last comma
|
// so that I don't have to care for last comma
|
||||||
dummy: 0
|
dummy: 0
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
Home: https://github.com/gorhill/uMatrix
|
Home: https://github.com/gorhill/uMatrix
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* global chrome, $ */
|
/* global chrome, messaging, uDom */
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -27,17 +27,23 @@
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var selectedBlacklistsHash = '';
|
var listDetails = {};
|
||||||
|
var externalHostsFiles = '';
|
||||||
|
var cacheWasPurged = false;
|
||||||
|
var needUpdate = false;
|
||||||
|
var hasCachedContent = false;
|
||||||
|
|
||||||
|
var re3rdPartyExternalAsset = /^https?:\/\/[a-z0-9]+/;
|
||||||
|
var re3rdPartyRepoAsset = /^assets\/thirdparties\/([^\/]+)/;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
messaging.start('ubiquitous-rules.js');
|
messaging.start('hosts-files.js');
|
||||||
|
|
||||||
var onMessage = function(msg) {
|
var onMessage = function(msg) {
|
||||||
switch ( msg.what ) {
|
switch ( msg.what ) {
|
||||||
case 'loadUbiquitousBlacklistCompleted':
|
case 'loadHostsFilesCompleted':
|
||||||
renderBlacklists();
|
renderBlacklists();
|
||||||
selectedBlacklistsChanged();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -49,152 +55,352 @@ messaging.listen(onMessage);
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
function getµm() {
|
|
||||||
return chrome.extension.getBackgroundPage().µMatrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
function changeUserSettings(name, value) {
|
|
||||||
messaging.tell({
|
|
||||||
what: 'userSettings',
|
|
||||||
name: name,
|
|
||||||
value: value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// TODO: get rid of background page dependencies
|
// TODO: get rid of background page dependencies
|
||||||
|
|
||||||
function renderBlacklists() {
|
var renderBlacklists = function() {
|
||||||
// empty list first
|
uDom('body').toggleClass('busy', true);
|
||||||
$('#blacklists .blacklistDetails').remove();
|
|
||||||
|
|
||||||
var µm = getµm();
|
|
||||||
|
|
||||||
$('#ubiquitousListsOfBlockedHostsPrompt2').text(
|
|
||||||
chrome.i18n.getMessage('ubiquitousListsOfBlockedHostsPrompt2')
|
|
||||||
.replace('{{ubiquitousBlacklistCount}}', µm.ubiquitousBlacklist.count.toLocaleString())
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assemble a pretty blacklist name if possible
|
// Assemble a pretty blacklist name if possible
|
||||||
var prettifyListName = function(blacklistTitle, blacklistHref) {
|
var listNameFromListKey = function(listKey) {
|
||||||
if ( !blacklistTitle ) {
|
var list = listDetails.current[listKey] || listDetails.available[listKey];
|
||||||
return blacklistHref;
|
var listTitle = list ? list.title : '';
|
||||||
|
if ( listTitle === '' ) {
|
||||||
|
return listKey;
|
||||||
}
|
}
|
||||||
|
return listTitle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assemble a pretty blacklist name if possible
|
||||||
|
var htmlFromHomeURL = function(blacklistHref) {
|
||||||
if ( blacklistHref.indexOf('assets/thirdparties/') !== 0 ) {
|
if ( blacklistHref.indexOf('assets/thirdparties/') !== 0 ) {
|
||||||
return blacklistTitle;
|
return '';
|
||||||
}
|
}
|
||||||
var matches = blacklistHref.match(/^assets\/thirdparties\/([^\/]+)/);
|
var matches = re3rdPartyRepoAsset.exec(blacklistHref);
|
||||||
if ( matches === null || matches.length !== 2 ) {
|
if ( matches === null || matches.length !== 2 ) {
|
||||||
return blacklistTitle;
|
return '';
|
||||||
}
|
}
|
||||||
var hostname = matches[1];
|
var hostname = matches[1];
|
||||||
var domain = µm.URI.domainFromHostname(hostname);
|
var domain = hostname;
|
||||||
if ( domain === '' ) {
|
if ( domain === '' ) {
|
||||||
return blacklistTitle;
|
return '';
|
||||||
}
|
}
|
||||||
var html = [
|
var html = [
|
||||||
blacklistTitle,
|
' <a href="http://',
|
||||||
' <i>(<a href="http://',
|
|
||||||
hostname,
|
hostname,
|
||||||
'" target="_blank">',
|
'" target="_blank">(',
|
||||||
domain,
|
domain,
|
||||||
'</a>)</i>'
|
')</a>'
|
||||||
];
|
];
|
||||||
return html.join('');
|
return html.join('');
|
||||||
};
|
};
|
||||||
|
|
||||||
var blacklists = µm.remoteBlacklists;
|
var purgeButtontext = chrome.i18n.getMessage('hostsFilesExternalListPurge');
|
||||||
var ul = $('#blacklists');
|
var updateButtontext = chrome.i18n.getMessage('hostsFilesExternalListNew');
|
||||||
var keys = Object.keys(blacklists);
|
var obsoleteButtontext = chrome.i18n.getMessage('hostsFilesExternalListObsolete');
|
||||||
var i = keys.length;
|
var liTemplate = [
|
||||||
var blacklist, blacklistHref;
|
'<li class="listDetails">',
|
||||||
var liTemplate = $('#blacklistTemplate .blacklistDetails').first();
|
'<input type="checkbox" {{checked}}>',
|
||||||
var li, child, text;
|
' ',
|
||||||
while ( i-- ) {
|
'<a href="{{URL}}" type="text/plain">',
|
||||||
blacklistHref = keys[i];
|
'{{name}}',
|
||||||
blacklist = blacklists[blacklistHref];
|
'\u200E</a>',
|
||||||
li = liTemplate.clone();
|
'{{homeURL}}',
|
||||||
child = $('input', li);
|
': ',
|
||||||
child.prop('checked', !blacklist.off);
|
'<span class="dim">',
|
||||||
child = $('a', li);
|
chrome.i18n.getMessage('hostsFilesPerFileStats'),
|
||||||
child.attr('href', encodeURI(blacklistHref));
|
'</span>'
|
||||||
child.html(prettifyListName(blacklist.title, blacklistHref));
|
].join('');
|
||||||
child = $('span', li);
|
|
||||||
text = child.text()
|
var htmlFromLeaf = function(listKey) {
|
||||||
.replace('{{used}}', !blacklist.off && !isNaN(+blacklist.entryUsedCount) ? blacklist.entryUsedCount.toLocaleString() : '0')
|
var html = [];
|
||||||
.replace('{{total}}', !isNaN(+blacklist.entryCount) ? blacklist.entryCount.toLocaleString() : '?')
|
var hostsEntry = listDetails.available[listKey];
|
||||||
;
|
var li = liTemplate
|
||||||
child.text(text);
|
.replace('{{checked}}', hostsEntry.off ? '' : 'checked')
|
||||||
ul.prepend(li);
|
.replace('{{URL}}', encodeURI(listKey))
|
||||||
}
|
.replace('{{name}}', listNameFromListKey(listKey))
|
||||||
selectedBlacklistsHash = getSelectedBlacklistsHash();
|
.replace('{{homeURL}}', htmlFromHomeURL(listKey))
|
||||||
}
|
.replace('{{used}}', !hostsEntry.off && !isNaN(+hostsEntry.entryUsedCount) ? hostsEntry.entryUsedCount.toLocaleString() : '0')
|
||||||
|
.replace('{{total}}', !isNaN(+hostsEntry.entryCount) ? hostsEntry.entryCount.toLocaleString() : '?');
|
||||||
|
html.push(li);
|
||||||
|
// https://github.com/gorhill/uBlock/issues/104
|
||||||
|
var asset = listDetails.cache[listKey];
|
||||||
|
if ( asset === undefined ) {
|
||||||
|
return html.join('\n');
|
||||||
|
}
|
||||||
|
// Update status
|
||||||
|
if ( hostsEntry.off !== true ) {
|
||||||
|
var obsolete = asset.repoObsolete ||
|
||||||
|
asset.cacheObsolete ||
|
||||||
|
asset.cached !== true && re3rdPartyExternalAsset.test(listKey);
|
||||||
|
if ( obsolete ) {
|
||||||
|
html.push(
|
||||||
|
' ',
|
||||||
|
'<span class="status obsolete">',
|
||||||
|
asset.repoObsolete ? updateButtontext : obsoleteButtontext,
|
||||||
|
'</span>'
|
||||||
|
);
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// In cache
|
||||||
|
if ( asset.cached ) {
|
||||||
|
html.push(
|
||||||
|
' ',
|
||||||
|
'<span class="status purge">',
|
||||||
|
purgeButtontext,
|
||||||
|
'</span>'
|
||||||
|
);
|
||||||
|
hasCachedContent = true;
|
||||||
|
}
|
||||||
|
return html.join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
var onListsReceived = function(details) {
|
||||||
|
// Before all, set context vars
|
||||||
|
listDetails = details;
|
||||||
|
needUpdate = false;
|
||||||
|
hasCachedContent = false;
|
||||||
|
|
||||||
|
// Visually split the filter lists in two groups: built-in and external
|
||||||
|
var html = [];
|
||||||
|
var hostsPaths = Object.keys(details.available);
|
||||||
|
var hostsEntry;
|
||||||
|
for ( i = 0; i < hostsPaths.length; i++ ) {
|
||||||
|
hostsPath = hostsPaths[i];
|
||||||
|
hostsEntry = details.available[hostsPath];
|
||||||
|
if ( !hostsEntry.external ) {
|
||||||
|
html.push(htmlFromLeaf(hostsPath, hostsEntry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( i = 0; i < hostsPaths.length; i++ ) {
|
||||||
|
hostsPath = hostsPaths[i];
|
||||||
|
hostsEntry = details.available[hostsPath];
|
||||||
|
if ( hostsEntry.external ) {
|
||||||
|
html.push(htmlFromLeaf(hostsPath, hostsEntry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uDom('#listsOfBlockedHostsPrompt').text(
|
||||||
|
chrome.i18n.getMessage('hostsFilesStats')
|
||||||
|
.replace('{{blockedHostnameCount}}', details.blockedHostnameCount.toLocaleString())
|
||||||
|
);
|
||||||
|
uDom('#autoUpdate').prop('checked', listDetails.autoUpdate === true);
|
||||||
|
uDom('#lists').html(html.join(''));
|
||||||
|
uDom('a').attr('target', '_blank');
|
||||||
|
|
||||||
|
updateWidgets();
|
||||||
|
};
|
||||||
|
|
||||||
|
messaging.ask({ what: 'getLists' }, onListsReceived);
|
||||||
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// Create a hash so that we know whether the selection of preset blacklists
|
// Return whether selection of lists changed.
|
||||||
// has changed.
|
|
||||||
|
|
||||||
function getSelectedBlacklistsHash() {
|
var listsSelectionChanged = function() {
|
||||||
var hash = '';
|
if ( cacheWasPurged ) {
|
||||||
var inputs = $('#blacklists .blacklistDetails > input');
|
return true;
|
||||||
var i = inputs.length;
|
|
||||||
var input, entryHash;
|
|
||||||
while ( i-- ) {
|
|
||||||
input = $(inputs[i]);
|
|
||||||
entryHash = input.prop('checked').toString();
|
|
||||||
hash += entryHash;
|
|
||||||
}
|
}
|
||||||
|
var availableLists = listDetails.available;
|
||||||
|
var currentLists = listDetails.current;
|
||||||
|
var location, availableOff, currentOff;
|
||||||
|
// This check existing entries
|
||||||
|
for ( location in availableLists ) {
|
||||||
|
if ( availableLists.hasOwnProperty(location) === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
availableOff = availableLists[location].off === true;
|
||||||
|
currentOff = currentLists[location] === undefined || currentLists[location].off === true;
|
||||||
|
if ( availableOff !== currentOff ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This check removed entries
|
||||||
|
for ( location in currentLists ) {
|
||||||
|
if ( currentLists.hasOwnProperty(location) === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
currentOff = currentLists[location].off === true;
|
||||||
|
availableOff = availableLists[location] === undefined || availableLists[location].off === true;
|
||||||
|
if ( availableOff !== currentOff ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
return hash;
|
/******************************************************************************/
|
||||||
}
|
|
||||||
|
// Return whether content need update.
|
||||||
|
|
||||||
|
var listsContentChanged = function() {
|
||||||
|
return needUpdate;
|
||||||
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// This is to give a visual hint that the selection of blacklists has changed.
|
// This is to give a visual hint that the selection of blacklists has changed.
|
||||||
|
|
||||||
function selectedBlacklistsChanged() {
|
var updateWidgets = function() {
|
||||||
$('#blacklistsApply').attr(
|
uDom('#buttonApply').toggleClass('disabled', !listsSelectionChanged());
|
||||||
'disabled',
|
uDom('#buttonUpdate').toggleClass('disabled', !listsContentChanged());
|
||||||
getSelectedBlacklistsHash() === selectedBlacklistsHash
|
uDom('#buttonPurgeAll').toggleClass('disabled', !hasCachedContent);
|
||||||
);
|
uDom('body').toggleClass('busy', false);
|
||||||
}
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
function blacklistsApplyHandler() {
|
var onListCheckboxChanged = function() {
|
||||||
var newHash = getSelectedBlacklistsHash();
|
var href = uDom(this).parent().descendants('a').first().attr('href');
|
||||||
if ( newHash === selectedBlacklistsHash ) {
|
if ( typeof href !== 'string' ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ( listDetails.available[href] === undefined ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listDetails.available[href].off = !this.checked;
|
||||||
|
updateWidgets();
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var onListLinkClicked = function(ev) {
|
||||||
|
messaging.tell({
|
||||||
|
what: 'gotoExtensionURL',
|
||||||
|
url: 'asset-viewer.html?url=' + uDom(this).attr('href')
|
||||||
|
});
|
||||||
|
ev.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var onPurgeClicked = function() {
|
||||||
|
var button = uDom(this);
|
||||||
|
var li = button.parent();
|
||||||
|
var href = li.descendants('a').first().attr('href');
|
||||||
|
if ( !href ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
messaging.tell({ what: 'purgeCache', path: href });
|
||||||
|
button.remove();
|
||||||
|
if ( li.descendants('input').first().prop('checked') ) {
|
||||||
|
cacheWasPurged = true;
|
||||||
|
updateWidgets();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var reloadAll = function(update) {
|
||||||
|
// Loading may take a while when resources are fetched from remote
|
||||||
|
// servers. We do not want the user to force reload while we are reloading.
|
||||||
|
uDom('body').toggleClass('busy', true);
|
||||||
|
|
||||||
// Reload blacklists
|
// Reload blacklists
|
||||||
var switches = [];
|
var switches = [];
|
||||||
var lis = $('#blacklists .blacklistDetails');
|
var lis = uDom('#lists .listDetails');
|
||||||
var i = lis.length;
|
var i = lis.length;
|
||||||
var path;
|
var path;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
path = $(lis[i]).children('a').attr('href');
|
path = lis
|
||||||
|
.subset(i)
|
||||||
|
.descendants('a')
|
||||||
|
.attr('href');
|
||||||
switches.push({
|
switches.push({
|
||||||
location: path,
|
location: path,
|
||||||
off: $(lis[i]).children('input').prop('checked') === false
|
off: lis.subset(i).descendants('input').prop('checked') === false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
messaging.tell({
|
messaging.tell({
|
||||||
what: 'reloadPresetBlacklists',
|
what: 'reloadHostsFiles',
|
||||||
switches: switches
|
switches: switches,
|
||||||
|
update: update
|
||||||
});
|
});
|
||||||
$('#blacklistsApply').attr('disabled', true );
|
cacheWasPurged = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
$(function() {
|
var buttonApplyHandler = function() {
|
||||||
$('#blacklists').on('change', '.blacklistDetails', selectedBlacklistsChanged);
|
reloadAll(false);
|
||||||
$('#blacklistsApply').on('click', blacklistsApplyHandler);
|
uDom('#buttonApply').toggleClass('enabled', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var buttonUpdateHandler = function() {
|
||||||
|
if ( needUpdate ) {
|
||||||
|
reloadAll(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var buttonPurgeAllHandler = function() {
|
||||||
|
var onCompleted = function() {
|
||||||
|
renderBlacklists();
|
||||||
|
};
|
||||||
|
messaging.ask({ what: 'purgeAllCaches' }, onCompleted);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var autoUpdateCheckboxChanged = function() {
|
||||||
|
messaging.tell({
|
||||||
|
what: 'userSettings',
|
||||||
|
name: 'autoUpdate',
|
||||||
|
value: this.checked
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var renderExternalLists = function() {
|
||||||
|
var onReceived = function(details) {
|
||||||
|
uDom('#externalHostsFiles').val(details);
|
||||||
|
externalHostsFiles = details;
|
||||||
|
};
|
||||||
|
messaging.ask({ what: 'userSettings', name: 'externalHostsFiles' }, onReceived);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var externalListsChangeHandler = function() {
|
||||||
|
uDom('#externalListsParse').prop(
|
||||||
|
'disabled',
|
||||||
|
this.value.trim() === externalHostsFiles
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var externalListsApplyHandler = function() {
|
||||||
|
externalHostsFiles = uDom('#externalHostsFiles').val();
|
||||||
|
messaging.tell({
|
||||||
|
what: 'userSettings',
|
||||||
|
name: 'externalHostsFiles',
|
||||||
|
value: externalHostsFiles
|
||||||
|
});
|
||||||
renderBlacklists();
|
renderBlacklists();
|
||||||
|
uDom('#externalListsParse').prop('disabled', true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
uDom.onLoad(function() {
|
||||||
|
uDom('#autoUpdate').on('change', autoUpdateCheckboxChanged);
|
||||||
|
uDom('#buttonApply').on('click', buttonApplyHandler);
|
||||||
|
uDom('#buttonUpdate').on('click', buttonUpdateHandler);
|
||||||
|
uDom('#buttonPurgeAll').on('click', buttonPurgeAllHandler);
|
||||||
|
uDom('#lists').on('change', '.listDetails > input', onListCheckboxChanged);
|
||||||
|
uDom('#lists').on('click', '.listDetails > a:nth-of-type(1)', onListLinkClicked);
|
||||||
|
uDom('#lists').on('click', 'span.purge', onPurgeClicked);
|
||||||
|
uDom('#externalHostsFiles').on('input', externalListsChangeHandler);
|
||||||
|
uDom('#externalListsParse').on('click', externalListsApplyHandler);
|
||||||
|
|
||||||
|
renderBlacklists();
|
||||||
|
renderExternalLists();
|
||||||
});
|
});
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
µm.pMatrix.setSwitch('chrome-scheme', false);
|
µm.pMatrix.setSwitch('chrome-scheme', false);
|
||||||
µm.pMatrix.setSwitch(µm.behindTheSceneScope, false);
|
µm.pMatrix.setSwitch(µm.behindTheSceneScope, false);
|
||||||
µm.pMatrix.setSwitch('opera-scheme', false);
|
µm.pMatrix.setSwitch('opera-scheme', false);
|
||||||
µm.pMatrix.setCell('*', '*', '*', µm.Matrix.Green);
|
µm.pMatrix.setCell('*', '*', '*', µm.Matrix.Red);
|
||||||
µm.pMatrix.setCell('*', '*', 'css', µm.Matrix.Green);
|
µm.pMatrix.setCell('*', '*', 'css', µm.Matrix.Green);
|
||||||
µm.pMatrix.setCell('*', '*', 'image', µm.Matrix.Green);
|
µm.pMatrix.setCell('*', '*', 'image', µm.Matrix.Green);
|
||||||
µm.pMatrix.setCell('*', '*', 'frame', µm.Matrix.Red);
|
µm.pMatrix.setCell('*', '*', 'frame', µm.Matrix.Red);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
var LiquidDict = function() {
|
var LiquidDict = function() {
|
||||||
this.dict = {};
|
this.dict = {};
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
|
this.duplicateCount = 0;
|
||||||
this.bucketCount = 0;
|
this.bucketCount = 0;
|
||||||
this.frozenBucketCount = 0;
|
this.frozenBucketCount = 0;
|
||||||
|
|
||||||
|
@ -160,6 +161,7 @@ LiquidDict.prototype.add = function(word) {
|
||||||
this.count += 1;
|
this.count += 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
this.duplicateCount += 1;
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -181,6 +183,7 @@ LiquidDict.prototype.freeze = function() {
|
||||||
LiquidDict.prototype.reset = function() {
|
LiquidDict.prototype.reset = function() {
|
||||||
this.dict = {};
|
this.dict = {};
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
|
this.duplicateCount = 0;
|
||||||
this.bucketCount = 0;
|
this.bucketCount = 0;
|
||||||
this.frozenBucketCount = 0;
|
this.frozenBucketCount = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -474,15 +474,46 @@ var onMessage = function(request, sender, callback) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// ubiquitous-rules.js
|
// hosts-files.js
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
var µm = µMatrix;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var getLists = function(callback) {
|
||||||
|
var r = {
|
||||||
|
available: null,
|
||||||
|
cache: null,
|
||||||
|
current: µm.liveHostsFiles,
|
||||||
|
blockedHostnameCount: µm.ubiquitousBlacklist.count,
|
||||||
|
autoUpdate: µm.userSettings.autoUpdate
|
||||||
|
};
|
||||||
|
var onMetadataReady = function(entries) {
|
||||||
|
r.cache = entries;
|
||||||
|
callback(r);
|
||||||
|
};
|
||||||
|
var onAvailableHostsFilesReady = function(lists) {
|
||||||
|
r.available = lists;
|
||||||
|
µm.assets.metadata(onMetadataReady);
|
||||||
|
};
|
||||||
|
µm.getAvailableHostsFiles(onAvailableHostsFilesReady);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
var onMessage = function(request, sender, callback) {
|
var onMessage = function(request, sender, callback) {
|
||||||
var µm = µMatrix;
|
var µm = µMatrix;
|
||||||
|
|
||||||
// Async
|
// Async
|
||||||
switch ( request.what ) {
|
switch ( request.what ) {
|
||||||
|
case 'getLists':
|
||||||
|
return getLists(callback);
|
||||||
|
|
||||||
|
case 'purgeAllCaches':
|
||||||
|
return µm.assets.purgeAll(callback);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -491,6 +522,10 @@ var onMessage = function(request, sender, callback) {
|
||||||
var response;
|
var response;
|
||||||
|
|
||||||
switch ( request.what ) {
|
switch ( request.what ) {
|
||||||
|
case 'purgeCache':
|
||||||
|
µm.assets.purge(request.path);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return µm.messaging.defaultHandler(request, sender, callback);
|
return µm.messaging.defaultHandler(request, sender, callback);
|
||||||
}
|
}
|
||||||
|
@ -498,7 +533,7 @@ var onMessage = function(request, sender, callback) {
|
||||||
callback(response);
|
callback(response);
|
||||||
};
|
};
|
||||||
|
|
||||||
µMatrix.messaging.listen('ubiquitous-rules.js', onMessage);
|
µMatrix.messaging.listen('hosts-files.js', onMessage);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -600,12 +635,6 @@ var onMessage = function(request, sender, callback) {
|
||||||
|
|
||||||
// Async
|
// Async
|
||||||
switch ( request.what ) {
|
switch ( request.what ) {
|
||||||
case 'getAssetUpdaterList':
|
|
||||||
return µm.assetUpdater.getList(callback);
|
|
||||||
|
|
||||||
case 'launchAssetUpdater':
|
|
||||||
return µm.assetUpdater.update(request.list, callback);
|
|
||||||
|
|
||||||
case 'readUserSettings':
|
case 'readUserSettings':
|
||||||
return chrome.storage.local.get(µm.userSettings, callback);
|
return chrome.storage.local.get(µm.userSettings, callback);
|
||||||
|
|
||||||
|
@ -617,10 +646,6 @@ var onMessage = function(request, sender, callback) {
|
||||||
var response;
|
var response;
|
||||||
|
|
||||||
switch ( request.what ) {
|
switch ( request.what ) {
|
||||||
case 'loadUpdatableAssets':
|
|
||||||
response = µm.loadUpdatableAssets();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'getSomeStats':
|
case 'getSomeStats':
|
||||||
response = {
|
response = {
|
||||||
storageQuota: µm.storageQuota,
|
storageQuota: µm.storageQuota,
|
||||||
|
|
|
@ -138,8 +138,8 @@ var onMessage = function(request, port) {
|
||||||
function defaultHandler(request, sender, callback) {
|
function defaultHandler(request, sender, callback) {
|
||||||
// Async
|
// Async
|
||||||
switch ( request.what ) {
|
switch ( request.what ) {
|
||||||
case 'loadUbiquitousAllowRules':
|
case 'getAssetContent':
|
||||||
return µm.loadUbiquitousWhitelists();
|
return µm.assets.getLocal(request.url, callback);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -165,8 +165,8 @@ function defaultHandler(request, sender, callback) {
|
||||||
µm.utils.gotoURL(request);
|
µm.utils.gotoURL(request);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'reloadPresetBlacklists':
|
case 'reloadHostsFiles':
|
||||||
µm.reloadPresetBlacklists(request.switches);
|
µm.reloadHostsFiles(request.switches);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'userSettings':
|
case 'userSettings':
|
||||||
|
|
|
@ -91,134 +91,181 @@
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
µMatrix.loadUbiquitousBlacklists = function() {
|
µMatrix.getAvailableHostsFiles = function(callback) {
|
||||||
var µm = µMatrix;
|
var availableHostsFiles = {};
|
||||||
var blacklists;
|
var redirections = {};
|
||||||
var blacklistLoadCount;
|
var µm = this;
|
||||||
var obsoleteBlacklists = [];
|
|
||||||
|
|
||||||
var removeObsoleteBlacklistsHandler = function(store) {
|
// selected lists
|
||||||
if ( !store.remoteBlacklists ) {
|
var onSelectedHostsFilesLoaded = function(store) {
|
||||||
return;
|
var lists = store.liveHostsFiles;
|
||||||
|
var locations = Object.keys(lists);
|
||||||
|
var oldLocation, newLocation;
|
||||||
|
var availableEntry, storedEntry;
|
||||||
|
|
||||||
|
while ( oldLocation = locations.pop() ) {
|
||||||
|
newLocation = redirections[oldLocation] || oldLocation;
|
||||||
|
availableEntry = availableHostsFiles[newLocation];
|
||||||
|
if ( availableEntry === undefined ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
storedEntry = lists[oldLocation];
|
||||||
|
availableEntry.off = storedEntry.off || false;
|
||||||
|
µm.assets.setHomeURL(newLocation, availableEntry.homeURL);
|
||||||
|
if ( storedEntry.entryCount !== undefined ) {
|
||||||
|
availableEntry.entryCount = storedEntry.entryCount;
|
||||||
|
}
|
||||||
|
if ( storedEntry.entryUsedCount !== undefined ) {
|
||||||
|
availableEntry.entryUsedCount = storedEntry.entryUsedCount;
|
||||||
|
}
|
||||||
|
// This may happen if the list name was pulled from the list content
|
||||||
|
if ( availableEntry.title === '' && storedEntry.title !== '' ) {
|
||||||
|
availableEntry.title = storedEntry.title;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var location;
|
callback(availableHostsFiles);
|
||||||
while ( location = obsoleteBlacklists.pop() ) {
|
|
||||||
delete store.remoteBlacklists[location];
|
|
||||||
}
|
|
||||||
chrome.storage.local.set(store);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var removeObsoleteBlacklists = function() {
|
// built-in lists
|
||||||
if ( obsoleteBlacklists.length === 0 ) {
|
var onBuiltinHostsFilesLoaded = function(details) {
|
||||||
return;
|
var location, locations;
|
||||||
|
try {
|
||||||
|
locations = JSON.parse(details.content);
|
||||||
|
} catch (e) {
|
||||||
|
locations = {};
|
||||||
}
|
}
|
||||||
|
var hostsFileEntry;
|
||||||
|
for ( location in locations ) {
|
||||||
|
if ( locations.hasOwnProperty(location) === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
hostsFileEntry = locations[location];
|
||||||
|
availableHostsFiles['assets/thirdparties/' + location] = hostsFileEntry;
|
||||||
|
if ( hostsFileEntry.old !== undefined ) {
|
||||||
|
redirections[hostsFileEntry.old] = location;
|
||||||
|
delete hostsFileEntry.old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now get user's selection of lists
|
||||||
chrome.storage.local.get(
|
chrome.storage.local.get(
|
||||||
{ 'remoteBlacklists': µm.remoteBlacklists },
|
{ 'liveHostsFiles': availableHostsFiles },
|
||||||
removeObsoleteBlacklistsHandler
|
onSelectedHostsFilesLoaded
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
var mergeBlacklist = function(details) {
|
// permanent hosts files
|
||||||
µm.mergeUbiquitousBlacklist(details);
|
var location;
|
||||||
blacklistLoadCount -= 1;
|
var lists = this.permanentHostsFiles;
|
||||||
if ( blacklistLoadCount === 0 ) {
|
for ( location in lists ) {
|
||||||
loadBlacklistsEnd();
|
if ( lists.hasOwnProperty(location) === false ) {
|
||||||
}
|
continue;
|
||||||
};
|
|
||||||
|
|
||||||
var loadBlacklistsEnd = function() {
|
|
||||||
µm.ubiquitousBlacklist.freeze();
|
|
||||||
removeObsoleteBlacklists();
|
|
||||||
µm.messaging.announce({ what: 'loadUbiquitousBlacklistCompleted' });
|
|
||||||
};
|
|
||||||
|
|
||||||
var loadBlacklistsStart = function(store) {
|
|
||||||
// rhill 2013-12-10: set all existing entries to `false`.
|
|
||||||
µm.ubiquitousBlacklist.reset();
|
|
||||||
blacklists = store.remoteBlacklists;
|
|
||||||
var blacklistLocations = Object.keys(store.remoteBlacklists);
|
|
||||||
|
|
||||||
blacklistLoadCount = blacklistLocations.length;
|
|
||||||
if ( blacklistLoadCount === 0 ) {
|
|
||||||
loadBlacklistsEnd();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load each preset blacklist which is not disabled.
|
|
||||||
var location;
|
|
||||||
while ( location = blacklistLocations.pop() ) {
|
|
||||||
// If loaded list location is not part of default list locations,
|
|
||||||
// remove its entry from local storage.
|
|
||||||
if ( !µm.remoteBlacklists[location] ) {
|
|
||||||
obsoleteBlacklists.push(location);
|
|
||||||
blacklistLoadCount -= 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/218
|
|
||||||
// Transfer potentially existing list title into restored list data.
|
|
||||||
if ( store.remoteBlacklists[location].title !== µm.remoteBlacklists[location].title ) {
|
|
||||||
store.remoteBlacklists[location].title = µm.remoteBlacklists[location].title;
|
|
||||||
}
|
|
||||||
// Store details of this preset blacklist
|
|
||||||
µm.remoteBlacklists[location] = store.remoteBlacklists[location];
|
|
||||||
// rhill 2013-12-09:
|
|
||||||
// Ignore list if disabled
|
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/78
|
|
||||||
if ( store.remoteBlacklists[location].off ) {
|
|
||||||
blacklistLoadCount -= 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
µm.assets.get(location, mergeBlacklist);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var onListOfBlockListsLoaded = function(details) {
|
|
||||||
// Initialize built-in list of 3rd-party block lists.
|
|
||||||
var lists = JSON.parse(details.content);
|
|
||||||
for ( var location in lists ) {
|
|
||||||
if ( lists.hasOwnProperty(location) === false ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
µm.remoteBlacklists['assets/thirdparties/' + location] = lists[location];
|
|
||||||
}
|
|
||||||
// Now get user's selection of list of block lists.
|
|
||||||
chrome.storage.local.get(
|
|
||||||
{ 'remoteBlacklists': µm.remoteBlacklists },
|
|
||||||
loadBlacklistsStart
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Reset list of 3rd-party block lists.
|
|
||||||
for ( var location in this.remoteBlacklists ) {
|
|
||||||
if ( location.indexOf('assets/thirdparties/') === 0 ) {
|
|
||||||
delete this.remoteBlacklists[location];
|
|
||||||
}
|
}
|
||||||
|
availableHostsFiles[location] = lists[location];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get new list of 3rd-party block lists.
|
// custom lists
|
||||||
this.assets.get('assets/umatrix/ubiquitous-block-lists.json', onListOfBlockListsLoaded);
|
var c;
|
||||||
|
var locations = this.userSettings.externalHostsFiles.split('\n');
|
||||||
|
for ( var i = 0; i < locations.length; i++ ) {
|
||||||
|
location = locations[i].trim();
|
||||||
|
c = location.charAt(0);
|
||||||
|
if ( location === '' || c === '!' || c === '#' ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Coarse validation
|
||||||
|
if ( /[^0-9A-Za-z!*'();:@&=+$,\/?%#\[\]_.~-]/.test(location) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
availableHostsFiles[location] = {
|
||||||
|
title: '',
|
||||||
|
external: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// get built-in block lists.
|
||||||
|
this.assets.get('assets/umatrix/hosts-files.json', onBuiltinHostsFilesLoaded);
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
µMatrix.mergeUbiquitousBlacklist = function(details) {
|
µMatrix.loadHostsFiles = function(callback) {
|
||||||
// console.log('storage.js > mergeUbiquitousBlacklist from "%s": "%s..."', details.path, details.content.slice(0, 40));
|
var µm = µMatrix;
|
||||||
|
var hostsFileLoadCount;
|
||||||
|
|
||||||
|
if ( typeof callback !== 'function' ) {
|
||||||
|
callback = this.noopFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
var loadHostsFilesEnd = function() {
|
||||||
|
µm.ubiquitousBlacklist.freeze();
|
||||||
|
chrome.storage.local.set({ 'liveHostsFiles': µm.liveHostsFiles });
|
||||||
|
µm.messaging.announce({ what: 'loadHostsFilesCompleted' });
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
var mergeHostsFile = function(details) {
|
||||||
|
µm.mergeHostsFile(details);
|
||||||
|
hostsFileLoadCount -= 1;
|
||||||
|
if ( hostsFileLoadCount === 0 ) {
|
||||||
|
loadHostsFilesEnd();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var loadHostsFilesStart = function(hostsFiles) {
|
||||||
|
µm.liveHostsFiles = hostsFiles;
|
||||||
|
µm.ubiquitousBlacklist.reset();
|
||||||
|
var locations = Object.keys(hostsFiles);
|
||||||
|
hostsFileLoadCount = locations.length;
|
||||||
|
if ( hostsFileLoadCount === 0 ) {
|
||||||
|
loadHostsFilesEnd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load all hosts file which are not disabled.
|
||||||
|
var location;
|
||||||
|
while ( location = locations.pop() ) {
|
||||||
|
if ( hostsFiles[location].off ) {
|
||||||
|
hostsFileLoadCount -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
µm.assets.get(location, mergeHostsFile);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getAvailableHostsFiles(loadHostsFilesStart);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µMatrix.mergeHostsFile = function(details) {
|
||||||
|
// console.log('storage.js > mergeHostsFile from "%s": "%s..."', details.path, details.content.slice(0, 40));
|
||||||
|
|
||||||
|
var usedCount = this.ubiquitousBlacklist.count;
|
||||||
|
var duplicateCount = this.ubiquitousBlacklist.duplicateCount;
|
||||||
|
|
||||||
|
this.mergeHostsFileContent(details.content);
|
||||||
|
|
||||||
|
usedCount = this.ubiquitousBlacklist.count - usedCount;
|
||||||
|
duplicateCount = this.ubiquitousBlacklist.duplicateCount - duplicateCount;
|
||||||
|
|
||||||
|
var hostsFilesMeta = this.liveHostsFiles[details.path];
|
||||||
|
hostsFilesMeta.entryCount = usedCount + duplicateCount;
|
||||||
|
hostsFilesMeta.entryUsedCount = usedCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µMatrix.mergeHostsFileContent = function(rawText) {
|
||||||
|
// console.log('storage.js > mergeHostsFileContent from "%s": "%s..."', details.path, details.content.slice(0, 40));
|
||||||
|
|
||||||
var rawText = details.content;
|
|
||||||
var rawEnd = rawText.length;
|
var rawEnd = rawText.length;
|
||||||
|
|
||||||
// rhill 2013-10-21: No need to prefix with '* ', the hostname is just what
|
|
||||||
// we need for preset blacklists. The prefix '* ' is ONLY needed when
|
|
||||||
// used as a filter in temporary blacklist.
|
|
||||||
|
|
||||||
var ubiquitousBlacklist = this.ubiquitousBlacklist;
|
var ubiquitousBlacklist = this.ubiquitousBlacklist;
|
||||||
var thisListCount = 0;
|
|
||||||
var thisListUsedCount = 0;
|
|
||||||
var reLocalhost = /(^|\s)(localhost\.localdomain|localhost|local|broadcasthost|0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)(?=\s|$)/g;
|
var reLocalhost = /(^|\s)(localhost\.localdomain|localhost|local|broadcasthost|0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)(?=\s|$)/g;
|
||||||
var reAsciiSegment = /^[\x21-\x7e]+$/;
|
var reAsciiSegment = /^[\x21-\x7e]+$/;
|
||||||
var matches;
|
var matches;
|
||||||
var lineBeg = 0, lineEnd;
|
var lineBeg = 0, lineEnd;
|
||||||
var line, c;
|
var line;
|
||||||
|
|
||||||
while ( lineBeg < rawEnd ) {
|
while ( lineBeg < rawEnd ) {
|
||||||
lineEnd = rawText.indexOf('\n', lineBeg);
|
lineEnd = rawText.indexOf('\n', lineBeg);
|
||||||
|
@ -235,20 +282,10 @@
|
||||||
line = rawText.slice(lineBeg, lineEnd).trim();
|
line = rawText.slice(lineBeg, lineEnd).trim();
|
||||||
lineBeg = lineEnd + 1;
|
lineBeg = lineEnd + 1;
|
||||||
|
|
||||||
// Strip comments
|
|
||||||
c = line.charAt(0);
|
|
||||||
if ( c === '!' || c === '[' ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( c === '#' ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/15
|
// https://github.com/gorhill/httpswitchboard/issues/15
|
||||||
// Ensure localhost et al. don't end up in the ubiquitous blacklist.
|
// Ensure localhost et al. don't end up in the ubiquitous blacklist.
|
||||||
line = line
|
line = line
|
||||||
.replace(/\s+#.*$/, '')
|
.replace(/#.*$/, '')
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(reLocalhost, '')
|
.replace(reLocalhost, '')
|
||||||
.trim();
|
.trim();
|
||||||
|
@ -273,16 +310,8 @@
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
thisListCount++;
|
ubiquitousBlacklist.add(line);
|
||||||
if ( ubiquitousBlacklist.add(line) ) {
|
|
||||||
thisListUsedCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For convenience, store the number of entries for this
|
|
||||||
// blacklist, user might be happy to know this information.
|
|
||||||
this.remoteBlacklists[details.path].entryCount = thisListCount;
|
|
||||||
this.remoteBlacklists[details.path].entryUsedCount = thisListUsedCount;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -290,26 +319,23 @@
|
||||||
// `switches` contains the preset blacklists for which the switch must be
|
// `switches` contains the preset blacklists for which the switch must be
|
||||||
// revisited.
|
// revisited.
|
||||||
|
|
||||||
µMatrix.reloadPresetBlacklists = function(switches) {
|
µMatrix.reloadHostsFiles = function(switches) {
|
||||||
var presetBlacklists = this.remoteBlacklists;
|
var liveHostsFiles = this.liveHostsFiles;
|
||||||
|
|
||||||
// Toggle switches
|
// Toggle switches
|
||||||
var i = switches.length;
|
var i = switches.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
if ( !presetBlacklists[switches[i].location] ) {
|
if ( !liveHostsFiles[switches[i].location] ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
presetBlacklists[switches[i].location].off = !!switches[i].off;
|
liveHostsFiles[switches[i].location].off = !!switches[i].off;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save switch states
|
// Save switch states
|
||||||
chrome.storage.local.set(
|
chrome.storage.local.set(
|
||||||
{ 'remoteBlacklists': presetBlacklists },
|
{ 'liveHostsFiles': liveHostsFiles },
|
||||||
this.getBytesInUse.bind(this)
|
this.loadHostsFiles.bind(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Now force reload
|
|
||||||
this.loadUbiquitousBlacklists();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -333,7 +359,7 @@
|
||||||
// Load updatable assets
|
// Load updatable assets
|
||||||
|
|
||||||
µMatrix.loadUpdatableAssets = function() {
|
µMatrix.loadUpdatableAssets = function() {
|
||||||
this.loadUbiquitousBlacklists();
|
this.loadHostsFiles();
|
||||||
this.loadPublicSuffixList();
|
this.loadPublicSuffixList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -342,12 +368,9 @@
|
||||||
// Load all
|
// Load all
|
||||||
|
|
||||||
µMatrix.load = function() {
|
µMatrix.load = function() {
|
||||||
// user
|
|
||||||
this.loadUserSettings();
|
this.loadUserSettings();
|
||||||
this.loadMatrix();
|
this.loadMatrix();
|
||||||
|
this.loadUpdatableAssets();
|
||||||
// load updatable assets -- after updating them if needed
|
|
||||||
this.assetUpdater.update(null, this.loadUpdatableAssets.bind(this));
|
|
||||||
|
|
||||||
this.getBytesInUse();
|
this.getBytesInUse();
|
||||||
};
|
};
|
||||||
|
|
|
@ -883,7 +883,7 @@ chrome.webRequest.onBeforeRequest.addListener(
|
||||||
[ "blocking" ]
|
[ "blocking" ]
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('HTTP Switchboard> Beginning to intercept net requests at %s', (new Date()).toISOString());
|
console.log('µMatrix > Beginning to intercept net requests at %s', (new Date()).toISOString());
|
||||||
|
|
||||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||||
onBeforeSendHeadersHandler,
|
onBeforeSendHeadersHandler,
|
||||||
|
|
|
@ -166,6 +166,18 @@ var isDescendantOf = function(descendant, ancestor) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var nodeInNodeList = function(node, nodeList) {
|
||||||
|
var i = nodeList.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
if ( nodeList[i] === node ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
var doesMatchSelector = function(node, selector) {
|
var doesMatchSelector = function(node, selector) {
|
||||||
if ( !node ) {
|
if ( !node ) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -599,8 +611,13 @@ DOMList.prototype.toggleClass = function(className, targetState) {
|
||||||
|
|
||||||
var makeEventHandler = function(selector, callback) {
|
var makeEventHandler = function(selector, callback) {
|
||||||
return function(event) {
|
return function(event) {
|
||||||
if ( doesMatchSelector(event.target, selector) ) {
|
var dispatcher = event.currentTarget;
|
||||||
callback.call(event.target, event);
|
if ( !dispatcher || typeof dispatcher.querySelectorAll !== 'function' ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var receiver = event.target;
|
||||||
|
if ( nodeInNodeList(receiver, dispatcher.querySelectorAll(selector)) ) {
|
||||||
|
callback.call(receiver, event);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -609,14 +626,13 @@ DOMList.prototype.on = function(etype, selector, callback) {
|
||||||
if ( typeof selector === 'function' ) {
|
if ( typeof selector === 'function' ) {
|
||||||
callback = selector;
|
callback = selector;
|
||||||
selector = undefined;
|
selector = undefined;
|
||||||
|
} else {
|
||||||
|
callback = makeEventHandler(selector, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = this.nodes.length;
|
var i = this.nodes.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
if ( selector !== undefined ) {
|
this.nodes[i].addEventListener(etype, callback, selector !== undefined);
|
||||||
this.nodes[i].addEventListener(etype, makeEventHandler(selector, callback), true);
|
|
||||||
} else {
|
|
||||||
this.nodes[i].addEventListener(etype, callback);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
|
@ -409,14 +409,6 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"ubiquitousWhatIsThisHeader" : {
|
|
||||||
"message": "Was ist das?",
|
|
||||||
"description": "English: What is this?"
|
|
||||||
},
|
|
||||||
"ubiquitousWhatIsThisPrompt" : {
|
|
||||||
"message": "“Omnipräsente Regeln” sind Regeln, die überall gelten, d.h. in allen Geltungsbereichen.",
|
|
||||||
"description": "English: “Ubiquitous rules” are rules which applies everywhere, i.e. in all scopes."
|
|
||||||
},
|
|
||||||
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
||||||
"message": "Alle Listen blockierter Hostnamen werden als omnipräsente Regeln geladen, womit diese Hostnamen in allen Geltungsbereichen auf der Blacklist stehen.",
|
"message": "Alle Listen blockierter Hostnamen werden als omnipräsente Regeln geladen, womit diese Hostnamen in allen Geltungsbereichen auf der Blacklist stehen.",
|
||||||
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"description": "appears as tab name in dashboard."
|
"description": "appears as tab name in dashboard."
|
||||||
},
|
},
|
||||||
"ubiquitousRulesPageName" : {
|
"ubiquitousRulesPageName" : {
|
||||||
"message": "Ubiquitous rules",
|
"message": "Hosts files",
|
||||||
"description": "appears as tab name in dashboard."
|
"description": "appears as tab name in dashboard."
|
||||||
},
|
},
|
||||||
"aboutPageName": {
|
"aboutPageName": {
|
||||||
|
@ -409,57 +409,53 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"ubiquitousWhatIsThisHeader" : {
|
"hostsFilesPrompt" : {
|
||||||
"message": "What is this?",
|
"message": "All hostnames in a hosts file are loaded as blacklisted hostnames in the global scope.",
|
||||||
"description": "English: What is this?"
|
"description": "English: All hostnames in a hosts file are loaded as blacklisted hostnames in the global scope."
|
||||||
},
|
},
|
||||||
"ubiquitousWhatIsThisPrompt" : {
|
"hostsFilesStats" : {
|
||||||
"message": "“Ubiquitous rules” are rules which apply everywhere, i.e. in all scopes. A ubiquitous rule can be overridden by any scoped rule for the same element.",
|
"message": "{{blockedHostnameCount}} distinct blocked hostnames from:",
|
||||||
"description": "English: “Ubiquitous rules” are rules which apply everywhere, i.e. in all scopes. A ubiquitous rule can be overridden by any scoped rule for the same element."
|
"description": "English: {{blockedHostnameCount}} distinct blocked hostnames from:"
|
||||||
},
|
},
|
||||||
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
"hostsFilesPerFileStats" : {
|
||||||
"message": "All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes.",
|
|
||||||
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
|
||||||
},
|
|
||||||
"ubiquitousListsOfBlockedHostsPrompt2" : {
|
|
||||||
"message": "{{ubiquitousBlacklistCount}} distinct blocked hostnames from:",
|
|
||||||
"description": "English: {{ubiquitousBlacklistCount}} distinct blocked hostnames from:"
|
|
||||||
},
|
|
||||||
"ubiquitousListsOfBlockedHostsPerListStats" : {
|
|
||||||
"message": "{{used}} used out of {{total}}",
|
"message": "{{used}} used out of {{total}}",
|
||||||
"description": "English: {{used}} used out of {{total}}"
|
"description": "English: {{used}} used out of {{total}}"
|
||||||
},
|
},
|
||||||
"ubiquitousListsOfBlockedHostsHeader" : {
|
"hostsFilesApplyChanges" : {
|
||||||
"message": "Lists of blocked hosts",
|
|
||||||
"description": "English: Lists of blocked hosts"
|
|
||||||
},
|
|
||||||
"userUbiquitousBlacklistHeader" : {
|
|
||||||
"message": "Your block rules",
|
|
||||||
"description": "English: Your block rules"
|
|
||||||
},
|
|
||||||
"userUbiquitousWhitelistHeader" : {
|
|
||||||
"message": "Your allow rules",
|
|
||||||
"description": "English: Your allow rules"
|
|
||||||
},
|
|
||||||
"ubiquitousApplyChanges" : {
|
|
||||||
"message": "Apply changes",
|
"message": "Apply changes",
|
||||||
"description": "English: Apply changes"
|
"description": "English: Apply changes"
|
||||||
},
|
},
|
||||||
"ubiquitousFormatHint" : {
|
"hostsFilesAutoUpdatePrompt":{
|
||||||
"message": "One rule per line. A rule can be a plain hostname, or an <a href='https://adblockplus.org/en/filters'>Adblock Plus-compatible filter</a>. Lines prefixed with ‘#’ will be ignored.",
|
"message":"Auto-update filter lists.",
|
||||||
"description": "English: One rule per line. A rule can be a plain hostname, or an Adblock Plus-compatible filter. Lines prefixed with ‘#’ will be ignored."
|
"description":"English: Auto-update filter lists."
|
||||||
},
|
},
|
||||||
"ubiquitousAllowFormatHint" : {
|
"hostsFilesUpdateNow":{
|
||||||
"message": "One rule per line. A rule can be a plain hostname, or an Adblock Plus-compatible exception filter (prefixed with ‘@@’). Lines prefixed with ‘#’ will be ignored.",
|
"message":"Update now",
|
||||||
"description": "English: One rule per line. A rule can be a plain hostname, or an Adblock Plus-compatible exception filter (prefixed with ‘@@’). Lines prefixed with ‘#’ will be ignored."
|
"description":"English: Update now"
|
||||||
},
|
},
|
||||||
"ubiquitousImport" : {
|
"hostsFilesPurgeAll":{
|
||||||
"message": "Import and append",
|
"message":"Purge all caches",
|
||||||
"description": "English: Import and append"
|
"description":"English: Purge all caches"
|
||||||
},
|
},
|
||||||
"ubiquitousExport" : {
|
"hostsFilesExternalListsHint":{
|
||||||
"message": "Export",
|
"message":"One URL per line. Lines prefixed with ‘!’ will be ignored. Invalid URLs will be silently ignored.",
|
||||||
"description": "English: Export"
|
"description":"English: One URL per line. Lines prefixed with ‘!’ will be ignored. Invalid URLs will be silently ignored."
|
||||||
|
},
|
||||||
|
"hostsFilesExternalListsParse":{
|
||||||
|
"message":"Parse",
|
||||||
|
"description":"English: Parse"
|
||||||
|
},
|
||||||
|
"hostsFilesExternalListPurge":{
|
||||||
|
"message":"purge cache",
|
||||||
|
"description":"English: purge cache"
|
||||||
|
},
|
||||||
|
"hostsFilesExternalListNew":{
|
||||||
|
"message":"new version available",
|
||||||
|
"description":"English: new version available"
|
||||||
|
},
|
||||||
|
"hostsFilesExternalListObsolete":{
|
||||||
|
"message":"outdated",
|
||||||
|
"description":"English: outdated"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -409,14 +409,6 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"ubiquitousWhatIsThisHeader" : {
|
|
||||||
"message": "De quoi s'agit-il ?",
|
|
||||||
"description": "English: What is this?"
|
|
||||||
},
|
|
||||||
"ubiquitousWhatIsThisPrompt" : {
|
|
||||||
"message": "Les “règles à portée universelle” sont des règles qui s'appliquent dans TOUS les contextes.",
|
|
||||||
"description": "English: “Ubiquitous rules” are rules which applies everywhere, i.e. in all scopes."
|
|
||||||
},
|
|
||||||
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
||||||
"message": "Tous les hôtes des listes prédéfinies sont traités comme étant des règles universelles. Elles sont intégrées au sein de l'extension et peuvent être mises à jour dans l'onglet À propos.",
|
"message": "Tous les hôtes des listes prédéfinies sont traités comme étant des règles universelles. Elles sont intégrées au sein de l'extension et peuvent être mises à jour dans l'onglet À propos.",
|
||||||
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
||||||
|
|
|
@ -409,14 +409,6 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"ubiquitousWhatIsThisHeader" : {
|
|
||||||
"message": "Что это?",
|
|
||||||
"description": "English: What is this?"
|
|
||||||
},
|
|
||||||
"ubiquitousWhatIsThisPrompt" : {
|
|
||||||
"message": "“Глобальные правила” правила, применяемые везде, во всех областях.",
|
|
||||||
"description": "English: “Ubiquitous rules” are rules which applies everywhere, i.e. in all scopes."
|
|
||||||
},
|
|
||||||
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
||||||
"message": "Все списки заблокированных хостов загружаются, как глобальные правила, в связи с чем их владельцы находятся в черном списке для всех областей.",
|
"message": "Все списки заблокированных хостов загружаются, как глобальные правила, в связи с чем их владельцы находятся в черном списке для всех областей.",
|
||||||
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
||||||
|
|
|
@ -409,14 +409,6 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"ubiquitousWhatIsThisHeader" : {
|
|
||||||
"message": "这是什么?",
|
|
||||||
"description": "English: What is this?"
|
|
||||||
},
|
|
||||||
"ubiquitousWhatIsThisPrompt" : {
|
|
||||||
"message": "“普适规则”是应用到所有地方,即所有作用域,的规则。一条普适规则可以被任何针对同一元素的作用域规则所覆盖。",
|
|
||||||
"description": "English: “Ubiquitous rules” are rules which apply everywhere, i.e. in all scopes. A ubiquitous rule can be overridden by any scoped rule for the same element."
|
|
||||||
},
|
|
||||||
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
||||||
"message": "所有屏蔽站点的列表都作为普适规则被加载,所以这些站点将在所有作用域的黑名单中。",
|
"message": "所有屏蔽站点的列表都作为普适规则被加载,所以这些站点将在所有作用域的黑名单中。",
|
||||||
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
"description": "English: All lists of blocked hosts are loaded as ubiquitous rules, hence these hosts are blacklisted in all scopes."
|
||||||
|
|
Loading…
Reference in a new issue