mirror of
https://github.com/gorhill/uMatrix.git
synced 2024-06-22 04:00:37 +12:00
work on many things, need more
This commit is contained in:
parent
65a8000657
commit
2b41bc8087
|
@ -66,34 +66,12 @@ table td:first-child {
|
|||
<div>
|
||||
<p><button type="button" id="backupUserDataButton" data-i18n="aboutUserDataBackupButton"></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><button type="button" id="resetUserDataButton" data-i18n="aboutUserDataResetButton"></button>
|
||||
</div>
|
||||
|
||||
<h2 data-i18n="aboutExtensionDataHeader"></h2>
|
||||
<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/udom.js"></script>
|
||||
<script src="js/i18n.js"></script>
|
||||
<script src="js/dashboard-common.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/utils.js"></script>
|
||||
<script src="js/assets.js"></script>
|
||||
<script src="js/asset-updater.js"></script>
|
||||
<script src="js/httpsb.js"></script>
|
||||
<script src="js/reqstats.js"></script>
|
||||
<script src="js/cookies.js"></script>
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
body {
|
||||
margin: 0;
|
||||
padding: 0 0.5em 5em 0.5em;
|
||||
font: 15px httpsb,sans-serif;
|
||||
font: 15px sans-serif;
|
||||
}
|
||||
body > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
h2, h3 {
|
||||
margin: 1em 0;
|
||||
|
@ -24,7 +27,7 @@ a {
|
|||
text-decoration: none;
|
||||
}
|
||||
button {
|
||||
padding: 0.4em;
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
|
||||
.para {
|
||||
|
@ -49,6 +52,7 @@ button {
|
|||
.whatisthis-expandable {
|
||||
margin: 0.5em 0 1em 1.25em;
|
||||
padding: 0.5em;
|
||||
font-size: smaller;
|
||||
display: none;
|
||||
border: 1px dotted black;
|
||||
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 {
|
||||
border-color: #333;
|
||||
color: white;
|
||||
background-color: #555;
|
||||
background-color: #666;
|
||||
}
|
||||
body.colorblind .t2 {
|
||||
border-color: #aaa;
|
||||
color: black;
|
||||
background-color: #ddd;
|
||||
background-color: #ccc;
|
||||
}
|
||||
body.colorblind .matCell.p81 {
|
||||
background-image: url('/img/permanent-black-small-cb.png');
|
||||
|
|
|
@ -8,7 +8,7 @@ body {
|
|||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
font: 15px httpsb,sans-serif;
|
||||
font: 15px sans-serif;
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
@ -18,7 +18,6 @@ body {
|
|||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 50px;
|
||||
|
@ -27,7 +26,8 @@ body {
|
|||
#dashboard-nav-widgets {
|
||||
margin: 0;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 4px 0 3px 0;
|
||||
padding: 4px 0;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
background-color: white;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ body {
|
|||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
padding: 4px;
|
||||
box-sizing: border-box;
|
||||
color: black;
|
||||
background-color: #eee;
|
||||
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="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="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="about" href="#about" data-dashboard-panel-url="about.html" data-i18n="aboutPageName"></a>
|
||||
</div>
|
||||
|
|
|
@ -2,55 +2,39 @@
|
|||
<html>
|
||||
<head>
|
||||
<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/dashboard-common.css">
|
||||
<style>
|
||||
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>
|
||||
<link rel="stylesheet" type="text/css" href="css/hosts-files.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h2 data-i18n="ubiquitousWhatIsThisHeader"></h2>
|
||||
<div>
|
||||
<p data-i18n="ubiquitousWhatIsThisPrompt"></p>
|
||||
<p data-i18n="hostsFilesPrompt"></p>
|
||||
<ul id="options">
|
||||
<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>
|
||||
|
||||
<h2 data-i18n="ubiquitousListsOfBlockedHostsHeader"></h2>
|
||||
<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>
|
||||
<div id="busyOverlay"></div>
|
||||
|
||||
<script src="lib/jquery-2.min.js"></script>
|
||||
<script src="js/udom.js"></script>
|
||||
<script src="js/i18n.js"></script>
|
||||
<script src="js/dashboard-common.js"></script>
|
||||
<script src="js/messaging-client.js"></script>
|
||||
<script src="js/ubiquitous-rules.js"></script>
|
||||
<script src="js/hosts-files.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
142
src/js/about.js
142
src/js/about.js
|
@ -19,17 +19,11 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global chrome, $ */
|
||||
/* global chrome, uDom */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
$(function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var updateList = {};
|
||||
var assetListSwitches = ['o', 'o', 'o'];
|
||||
var commitHistoryURLPrefix = 'https://github.com/gorhill/httpswitchboard/commits/master/';
|
||||
uDom.onLoad(function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -75,12 +69,7 @@ var backupUserDataToFile = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var restoreUserDataFromFile = function() {
|
||||
var input = $('<input />').attr({
|
||||
type: 'file',
|
||||
accept: 'text/plain'
|
||||
});
|
||||
|
||||
function restoreUserDataFromFile() {
|
||||
var restartCountdown = 4;
|
||||
var doCountdown = function() {
|
||||
restartCountdown -= 1;
|
||||
|
@ -151,23 +140,27 @@ var restoreUserDataFromFile = function() {
|
|||
}
|
||||
};
|
||||
|
||||
var filePickerOnChangeHandler = function() {
|
||||
$(this).off('change', filePickerOnChangeHandler);
|
||||
var file = this.files[0];
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
if ( file.type.indexOf('text') !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var fr = new FileReader();
|
||||
fr.onload = fileReaderOnLoadHandler;
|
||||
fr.readAsText(file);
|
||||
input.off('change', filePickerOnChangeHandler);
|
||||
};
|
||||
var file = this.files[0];
|
||||
if ( file === undefined || file.name === '' ) {
|
||||
return;
|
||||
}
|
||||
if ( file.type.indexOf('text') !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var fr = new FileReader();
|
||||
fr.onload = fileReaderOnLoadHandler;
|
||||
fr.readAsText(file);
|
||||
}
|
||||
|
||||
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.listen(onAnnounce);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
$('#aboutVersion').html(chrome.runtime.getManifest().version);
|
||||
uDom('#aboutVersion').html(chrome.runtime.getManifest().version);
|
||||
var renderStats = function(details) {
|
||||
var template = chrome.i18n.getMessage('aboutStorageUsed');
|
||||
var percent = 0;
|
||||
if ( details.storageQuota ) {
|
||||
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);
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
$('#aboutAssetsUpdateButton').on('click', updateAssets);
|
||||
$('#backupUserDataButton').on('click', backupUserDataToFile);
|
||||
$('#restoreUserDataButton').on('click', restoreUserDataFromFile);
|
||||
$('#resetUserDataButton').on('click', resetUserData);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
updateAssetsList();
|
||||
uDom('#backupUserDataButton').on('click', backupUserDataToFile);
|
||||
uDom('#restoreUserDataButton').on('click', startRestoreFilePicker);
|
||||
uDom('#restoreFilePicker').on('change', restoreUserDataFromFile);
|
||||
uDom('#resetUserDataButton').on('click', resetUserData);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
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(),
|
||||
|
||||
userSettings: {
|
||||
autoUpdate: false,
|
||||
clearBrowserCache: true,
|
||||
clearBrowserCacheAfter: 60,
|
||||
colorBlindFriendly: false,
|
||||
|
@ -53,11 +54,12 @@ return {
|
|||
deleteUnusedSessionCookiesAfter: 60,
|
||||
deleteLocalStorage: false,
|
||||
displayTextSize: '13px',
|
||||
externalHostsFiles: '',
|
||||
maxLoggedRequests: 50,
|
||||
popupCollapseDomains: false,
|
||||
popupCollapseSpecificDomains: {},
|
||||
popupHideBlacklisted: false,
|
||||
popupScopeLevel: '*',
|
||||
popupScopeLevel: 'domain',
|
||||
processBehindTheSceneRequests: false,
|
||||
processHyperlinkAuditing: true,
|
||||
processReferer: false,
|
||||
|
@ -74,13 +76,17 @@ return {
|
|||
updateAssetsEvery: 5 * 24 * 60 * 60 * 1000,
|
||||
projectServerRoot: 'https://raw.githubusercontent.com/gorhill/umatrix/master/',
|
||||
|
||||
// list of remote blacklist locations
|
||||
remoteBlacklists: {
|
||||
// uMatrix
|
||||
'assets/umatrix/blacklist.txt': { title: 'uMatrix' },
|
||||
|
||||
// 3rd-party lists now fetched dynamically
|
||||
},
|
||||
// permanent hosts files
|
||||
permanentHostsFiles: {
|
||||
// µMatrix
|
||||
'assets/umatrix/blacklist.txt': {
|
||||
title: 'µMatrix hosts file'
|
||||
}
|
||||
},
|
||||
|
||||
// list of live hosts files
|
||||
liveHostsFiles: {
|
||||
},
|
||||
|
||||
// urls stats are kept on the back burner while waiting to be reactivated
|
||||
// in a tab or another.
|
||||
|
@ -99,10 +105,7 @@ return {
|
|||
tMatrix: null,
|
||||
pMatrix: null,
|
||||
|
||||
// Current entries from ubiquitous lists --
|
||||
// just hostnames, '*/' is implied, this saves significantly on memory.
|
||||
ubiquitousBlacklist: null,
|
||||
ubiquitousWhitelist: null,
|
||||
|
||||
// various stats
|
||||
requestStats: new WebRequestStats(),
|
||||
|
@ -128,6 +131,8 @@ return {
|
|||
noopCSSURL: chrome.runtime.getURL('css/noop.css'),
|
||||
fontCSSURL: chrome.runtime.getURL('css/fonts/Roboto_Condensed/RobotoCondensed-Regular.ttf'),
|
||||
|
||||
noopFunc: function(){},
|
||||
|
||||
// so that I don't have to care for last comma
|
||||
dummy: 0
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
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) {
|
||||
switch ( msg.what ) {
|
||||
case 'loadUbiquitousBlacklistCompleted':
|
||||
case 'loadHostsFilesCompleted':
|
||||
renderBlacklists();
|
||||
selectedBlacklistsChanged();
|
||||
break;
|
||||
|
||||
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
|
||||
|
||||
function renderBlacklists() {
|
||||
// empty list first
|
||||
$('#blacklists .blacklistDetails').remove();
|
||||
|
||||
var µm = getµm();
|
||||
|
||||
$('#ubiquitousListsOfBlockedHostsPrompt2').text(
|
||||
chrome.i18n.getMessage('ubiquitousListsOfBlockedHostsPrompt2')
|
||||
.replace('{{ubiquitousBlacklistCount}}', µm.ubiquitousBlacklist.count.toLocaleString())
|
||||
);
|
||||
var renderBlacklists = function() {
|
||||
uDom('body').toggleClass('busy', true);
|
||||
|
||||
// Assemble a pretty blacklist name if possible
|
||||
var prettifyListName = function(blacklistTitle, blacklistHref) {
|
||||
if ( !blacklistTitle ) {
|
||||
return blacklistHref;
|
||||
var listNameFromListKey = function(listKey) {
|
||||
var list = listDetails.current[listKey] || listDetails.available[listKey];
|
||||
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 ) {
|
||||
return blacklistTitle;
|
||||
return '';
|
||||
}
|
||||
var matches = blacklistHref.match(/^assets\/thirdparties\/([^\/]+)/);
|
||||
var matches = re3rdPartyRepoAsset.exec(blacklistHref);
|
||||
if ( matches === null || matches.length !== 2 ) {
|
||||
return blacklistTitle;
|
||||
return '';
|
||||
}
|
||||
var hostname = matches[1];
|
||||
var domain = µm.URI.domainFromHostname(hostname);
|
||||
var domain = hostname;
|
||||
if ( domain === '' ) {
|
||||
return blacklistTitle;
|
||||
return '';
|
||||
}
|
||||
var html = [
|
||||
blacklistTitle,
|
||||
' <i>(<a href="http://',
|
||||
' <a href="http://',
|
||||
hostname,
|
||||
'" target="_blank">',
|
||||
'" target="_blank">(',
|
||||
domain,
|
||||
'</a>)</i>'
|
||||
')</a>'
|
||||
];
|
||||
return html.join('');
|
||||
};
|
||||
|
||||
var blacklists = µm.remoteBlacklists;
|
||||
var ul = $('#blacklists');
|
||||
var keys = Object.keys(blacklists);
|
||||
var i = keys.length;
|
||||
var blacklist, blacklistHref;
|
||||
var liTemplate = $('#blacklistTemplate .blacklistDetails').first();
|
||||
var li, child, text;
|
||||
while ( i-- ) {
|
||||
blacklistHref = keys[i];
|
||||
blacklist = blacklists[blacklistHref];
|
||||
li = liTemplate.clone();
|
||||
child = $('input', li);
|
||||
child.prop('checked', !blacklist.off);
|
||||
child = $('a', li);
|
||||
child.attr('href', encodeURI(blacklistHref));
|
||||
child.html(prettifyListName(blacklist.title, blacklistHref));
|
||||
child = $('span', li);
|
||||
text = child.text()
|
||||
.replace('{{used}}', !blacklist.off && !isNaN(+blacklist.entryUsedCount) ? blacklist.entryUsedCount.toLocaleString() : '0')
|
||||
.replace('{{total}}', !isNaN(+blacklist.entryCount) ? blacklist.entryCount.toLocaleString() : '?')
|
||||
;
|
||||
child.text(text);
|
||||
ul.prepend(li);
|
||||
}
|
||||
selectedBlacklistsHash = getSelectedBlacklistsHash();
|
||||
}
|
||||
var purgeButtontext = chrome.i18n.getMessage('hostsFilesExternalListPurge');
|
||||
var updateButtontext = chrome.i18n.getMessage('hostsFilesExternalListNew');
|
||||
var obsoleteButtontext = chrome.i18n.getMessage('hostsFilesExternalListObsolete');
|
||||
var liTemplate = [
|
||||
'<li class="listDetails">',
|
||||
'<input type="checkbox" {{checked}}>',
|
||||
' ',
|
||||
'<a href="{{URL}}" type="text/plain">',
|
||||
'{{name}}',
|
||||
'\u200E</a>',
|
||||
'{{homeURL}}',
|
||||
': ',
|
||||
'<span class="dim">',
|
||||
chrome.i18n.getMessage('hostsFilesPerFileStats'),
|
||||
'</span>'
|
||||
].join('');
|
||||
|
||||
var htmlFromLeaf = function(listKey) {
|
||||
var html = [];
|
||||
var hostsEntry = listDetails.available[listKey];
|
||||
var li = liTemplate
|
||||
.replace('{{checked}}', hostsEntry.off ? '' : 'checked')
|
||||
.replace('{{URL}}', encodeURI(listKey))
|
||||
.replace('{{name}}', listNameFromListKey(listKey))
|
||||
.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
|
||||
// has changed.
|
||||
// Return whether selection of lists changed.
|
||||
|
||||
function getSelectedBlacklistsHash() {
|
||||
var hash = '';
|
||||
var inputs = $('#blacklists .blacklistDetails > input');
|
||||
var i = inputs.length;
|
||||
var input, entryHash;
|
||||
while ( i-- ) {
|
||||
input = $(inputs[i]);
|
||||
entryHash = input.prop('checked').toString();
|
||||
hash += entryHash;
|
||||
var listsSelectionChanged = function() {
|
||||
if ( cacheWasPurged ) {
|
||||
return true;
|
||||
}
|
||||
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.
|
||||
|
||||
function selectedBlacklistsChanged() {
|
||||
$('#blacklistsApply').attr(
|
||||
'disabled',
|
||||
getSelectedBlacklistsHash() === selectedBlacklistsHash
|
||||
);
|
||||
}
|
||||
var updateWidgets = function() {
|
||||
uDom('#buttonApply').toggleClass('disabled', !listsSelectionChanged());
|
||||
uDom('#buttonUpdate').toggleClass('disabled', !listsContentChanged());
|
||||
uDom('#buttonPurgeAll').toggleClass('disabled', !hasCachedContent);
|
||||
uDom('body').toggleClass('busy', false);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function blacklistsApplyHandler() {
|
||||
var newHash = getSelectedBlacklistsHash();
|
||||
if ( newHash === selectedBlacklistsHash ) {
|
||||
var onListCheckboxChanged = function() {
|
||||
var href = uDom(this).parent().descendants('a').first().attr('href');
|
||||
if ( typeof href !== 'string' ) {
|
||||
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
|
||||
var switches = [];
|
||||
var lis = $('#blacklists .blacklistDetails');
|
||||
var lis = uDom('#lists .listDetails');
|
||||
var i = lis.length;
|
||||
var path;
|
||||
while ( i-- ) {
|
||||
path = $(lis[i]).children('a').attr('href');
|
||||
path = lis
|
||||
.subset(i)
|
||||
.descendants('a')
|
||||
.attr('href');
|
||||
switches.push({
|
||||
location: path,
|
||||
off: $(lis[i]).children('input').prop('checked') === false
|
||||
off: lis.subset(i).descendants('input').prop('checked') === false
|
||||
});
|
||||
}
|
||||
messaging.tell({
|
||||
what: 'reloadPresetBlacklists',
|
||||
switches: switches
|
||||
what: 'reloadHostsFiles',
|
||||
switches: switches,
|
||||
update: update
|
||||
});
|
||||
$('#blacklistsApply').attr('disabled', true );
|
||||
}
|
||||
cacheWasPurged = false;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
$(function() {
|
||||
$('#blacklists').on('change', '.blacklistDetails', selectedBlacklistsChanged);
|
||||
$('#blacklistsApply').on('click', blacklistsApplyHandler);
|
||||
var buttonApplyHandler = function() {
|
||||
reloadAll(false);
|
||||
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();
|
||||
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(µm.behindTheSceneScope, 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('*', '*', 'image', µm.Matrix.Green);
|
||||
µm.pMatrix.setCell('*', '*', 'frame', µm.Matrix.Red);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
var LiquidDict = function() {
|
||||
this.dict = {};
|
||||
this.count = 0;
|
||||
this.duplicateCount = 0;
|
||||
this.bucketCount = 0;
|
||||
this.frozenBucketCount = 0;
|
||||
|
||||
|
@ -160,6 +161,7 @@ LiquidDict.prototype.add = function(word) {
|
|||
this.count += 1;
|
||||
return true;
|
||||
}
|
||||
this.duplicateCount += 1;
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -181,6 +183,7 @@ LiquidDict.prototype.freeze = function() {
|
|||
LiquidDict.prototype.reset = function() {
|
||||
this.dict = {};
|
||||
this.count = 0;
|
||||
this.duplicateCount = 0;
|
||||
this.bucketCount = 0;
|
||||
this.frozenBucketCount = 0;
|
||||
};
|
||||
|
|
|
@ -474,15 +474,46 @@ var onMessage = function(request, sender, callback) {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// ubiquitous-rules.js
|
||||
// hosts-files.js
|
||||
|
||||
(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 µm = µMatrix;
|
||||
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
case 'getLists':
|
||||
return getLists(callback);
|
||||
|
||||
case 'purgeAllCaches':
|
||||
return µm.assets.purgeAll(callback);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -491,6 +522,10 @@ var onMessage = function(request, sender, callback) {
|
|||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'purgeCache':
|
||||
µm.assets.purge(request.path);
|
||||
break;
|
||||
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
@ -498,7 +533,7 @@ var onMessage = function(request, sender, callback) {
|
|||
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
|
||||
switch ( request.what ) {
|
||||
case 'getAssetUpdaterList':
|
||||
return µm.assetUpdater.getList(callback);
|
||||
|
||||
case 'launchAssetUpdater':
|
||||
return µm.assetUpdater.update(request.list, callback);
|
||||
|
||||
case 'readUserSettings':
|
||||
return chrome.storage.local.get(µm.userSettings, callback);
|
||||
|
||||
|
@ -617,10 +646,6 @@ var onMessage = function(request, sender, callback) {
|
|||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'loadUpdatableAssets':
|
||||
response = µm.loadUpdatableAssets();
|
||||
break;
|
||||
|
||||
case 'getSomeStats':
|
||||
response = {
|
||||
storageQuota: µm.storageQuota,
|
||||
|
|
|
@ -138,8 +138,8 @@ var onMessage = function(request, port) {
|
|||
function defaultHandler(request, sender, callback) {
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
case 'loadUbiquitousAllowRules':
|
||||
return µm.loadUbiquitousWhitelists();
|
||||
case 'getAssetContent':
|
||||
return µm.assets.getLocal(request.url, callback);
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -165,8 +165,8 @@ function defaultHandler(request, sender, callback) {
|
|||
µm.utils.gotoURL(request);
|
||||
break;
|
||||
|
||||
case 'reloadPresetBlacklists':
|
||||
µm.reloadPresetBlacklists(request.switches);
|
||||
case 'reloadHostsFiles':
|
||||
µm.reloadHostsFiles(request.switches);
|
||||
break;
|
||||
|
||||
case 'userSettings':
|
||||
|
|
|
@ -91,134 +91,181 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µMatrix.loadUbiquitousBlacklists = function() {
|
||||
var µm = µMatrix;
|
||||
var blacklists;
|
||||
var blacklistLoadCount;
|
||||
var obsoleteBlacklists = [];
|
||||
µMatrix.getAvailableHostsFiles = function(callback) {
|
||||
var availableHostsFiles = {};
|
||||
var redirections = {};
|
||||
var µm = this;
|
||||
|
||||
var removeObsoleteBlacklistsHandler = function(store) {
|
||||
if ( !store.remoteBlacklists ) {
|
||||
return;
|
||||
// selected lists
|
||||
var onSelectedHostsFilesLoaded = function(store) {
|
||||
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;
|
||||
while ( location = obsoleteBlacklists.pop() ) {
|
||||
delete store.remoteBlacklists[location];
|
||||
}
|
||||
chrome.storage.local.set(store);
|
||||
callback(availableHostsFiles);
|
||||
};
|
||||
|
||||
var removeObsoleteBlacklists = function() {
|
||||
if ( obsoleteBlacklists.length === 0 ) {
|
||||
return;
|
||||
// built-in lists
|
||||
var onBuiltinHostsFilesLoaded = function(details) {
|
||||
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(
|
||||
{ 'remoteBlacklists': µm.remoteBlacklists },
|
||||
removeObsoleteBlacklistsHandler
|
||||
{ 'liveHostsFiles': availableHostsFiles },
|
||||
onSelectedHostsFilesLoaded
|
||||
);
|
||||
};
|
||||
|
||||
var mergeBlacklist = function(details) {
|
||||
µm.mergeUbiquitousBlacklist(details);
|
||||
blacklistLoadCount -= 1;
|
||||
if ( blacklistLoadCount === 0 ) {
|
||||
loadBlacklistsEnd();
|
||||
}
|
||||
};
|
||||
|
||||
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];
|
||||
// permanent hosts files
|
||||
var location;
|
||||
var lists = this.permanentHostsFiles;
|
||||
for ( location in lists ) {
|
||||
if ( lists.hasOwnProperty(location) === false ) {
|
||||
continue;
|
||||
}
|
||||
availableHostsFiles[location] = lists[location];
|
||||
}
|
||||
|
||||
// Get new list of 3rd-party block lists.
|
||||
this.assets.get('assets/umatrix/ubiquitous-block-lists.json', onListOfBlockListsLoaded);
|
||||
// custom lists
|
||||
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) {
|
||||
// console.log('storage.js > mergeUbiquitousBlacklist from "%s": "%s..."', details.path, details.content.slice(0, 40));
|
||||
µMatrix.loadHostsFiles = function(callback) {
|
||||
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;
|
||||
|
||||
// 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 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 reAsciiSegment = /^[\x21-\x7e]+$/;
|
||||
var matches;
|
||||
var lineBeg = 0, lineEnd;
|
||||
var line, c;
|
||||
var line;
|
||||
|
||||
while ( lineBeg < rawEnd ) {
|
||||
lineEnd = rawText.indexOf('\n', lineBeg);
|
||||
|
@ -235,20 +282,10 @@
|
|||
line = rawText.slice(lineBeg, lineEnd).trim();
|
||||
lineBeg = lineEnd + 1;
|
||||
|
||||
// Strip comments
|
||||
c = line.charAt(0);
|
||||
if ( c === '!' || c === '[' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( c === '#' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/15
|
||||
// Ensure localhost et al. don't end up in the ubiquitous blacklist.
|
||||
line = line
|
||||
.replace(/\s+#.*$/, '')
|
||||
.replace(/#.*$/, '')
|
||||
.toLowerCase()
|
||||
.replace(reLocalhost, '')
|
||||
.trim();
|
||||
|
@ -273,16 +310,8 @@
|
|||
continue;
|
||||
}
|
||||
|
||||
thisListCount++;
|
||||
if ( ubiquitousBlacklist.add(line) ) {
|
||||
thisListUsedCount++;
|
||||
}
|
||||
ubiquitousBlacklist.add(line);
|
||||
}
|
||||
|
||||
// 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
|
||||
// revisited.
|
||||
|
||||
µMatrix.reloadPresetBlacklists = function(switches) {
|
||||
var presetBlacklists = this.remoteBlacklists;
|
||||
µMatrix.reloadHostsFiles = function(switches) {
|
||||
var liveHostsFiles = this.liveHostsFiles;
|
||||
|
||||
// Toggle switches
|
||||
var i = switches.length;
|
||||
while ( i-- ) {
|
||||
if ( !presetBlacklists[switches[i].location] ) {
|
||||
if ( !liveHostsFiles[switches[i].location] ) {
|
||||
continue;
|
||||
}
|
||||
presetBlacklists[switches[i].location].off = !!switches[i].off;
|
||||
liveHostsFiles[switches[i].location].off = !!switches[i].off;
|
||||
}
|
||||
|
||||
// Save switch states
|
||||
chrome.storage.local.set(
|
||||
{ 'remoteBlacklists': presetBlacklists },
|
||||
this.getBytesInUse.bind(this)
|
||||
{ 'liveHostsFiles': liveHostsFiles },
|
||||
this.loadHostsFiles.bind(this)
|
||||
);
|
||||
|
||||
// Now force reload
|
||||
this.loadUbiquitousBlacklists();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -333,7 +359,7 @@
|
|||
// Load updatable assets
|
||||
|
||||
µMatrix.loadUpdatableAssets = function() {
|
||||
this.loadUbiquitousBlacklists();
|
||||
this.loadHostsFiles();
|
||||
this.loadPublicSuffixList();
|
||||
};
|
||||
|
||||
|
@ -342,12 +368,9 @@
|
|||
// Load all
|
||||
|
||||
µMatrix.load = function() {
|
||||
// user
|
||||
this.loadUserSettings();
|
||||
this.loadMatrix();
|
||||
|
||||
// load updatable assets -- after updating them if needed
|
||||
this.assetUpdater.update(null, this.loadUpdatableAssets.bind(this));
|
||||
this.loadUpdatableAssets();
|
||||
|
||||
this.getBytesInUse();
|
||||
};
|
||||
|
|
|
@ -883,7 +883,7 @@ chrome.webRequest.onBeforeRequest.addListener(
|
|||
[ "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(
|
||||
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) {
|
||||
if ( !node ) {
|
||||
return false;
|
||||
|
@ -599,8 +611,13 @@ DOMList.prototype.toggleClass = function(className, targetState) {
|
|||
|
||||
var makeEventHandler = function(selector, callback) {
|
||||
return function(event) {
|
||||
if ( doesMatchSelector(event.target, selector) ) {
|
||||
callback.call(event.target, event);
|
||||
var dispatcher = event.currentTarget;
|
||||
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' ) {
|
||||
callback = selector;
|
||||
selector = undefined;
|
||||
} else {
|
||||
callback = makeEventHandler(selector, callback);
|
||||
}
|
||||
|
||||
var i = this.nodes.length;
|
||||
while ( i-- ) {
|
||||
if ( selector !== undefined ) {
|
||||
this.nodes[i].addEventListener(etype, makeEventHandler(selector, callback), true);
|
||||
} else {
|
||||
this.nodes[i].addEventListener(etype, callback);
|
||||
}
|
||||
this.nodes[i].addEventListener(etype, callback, selector !== undefined);
|
||||
}
|
||||
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" : {
|
||||
"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."
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"description": "appears as tab name in dashboard."
|
||||
},
|
||||
"ubiquitousRulesPageName" : {
|
||||
"message": "Ubiquitous rules",
|
||||
"message": "Hosts files",
|
||||
"description": "appears as tab name in dashboard."
|
||||
},
|
||||
"aboutPageName": {
|
||||
|
@ -409,57 +409,53 @@
|
|||
},
|
||||
|
||||
|
||||
"ubiquitousWhatIsThisHeader" : {
|
||||
"message": "What is this?",
|
||||
"description": "English: What is this?"
|
||||
"hostsFilesPrompt" : {
|
||||
"message": "All hostnames in a hosts file are loaded as blacklisted hostnames in the global scope.",
|
||||
"description": "English: All hostnames in a hosts file are loaded as blacklisted hostnames in the global scope."
|
||||
},
|
||||
"ubiquitousWhatIsThisPrompt" : {
|
||||
"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.",
|
||||
"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."
|
||||
"hostsFilesStats" : {
|
||||
"message": "{{blockedHostnameCount}} distinct blocked hostnames from:",
|
||||
"description": "English: {{blockedHostnameCount}} distinct blocked hostnames from:"
|
||||
},
|
||||
"ubiquitousListsOfBlockedHostsPrompt1" : {
|
||||
"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" : {
|
||||
"hostsFilesPerFileStats" : {
|
||||
"message": "{{used}} used out of {{total}}",
|
||||
"description": "English: {{used}} used out of {{total}}"
|
||||
},
|
||||
"ubiquitousListsOfBlockedHostsHeader" : {
|
||||
"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" : {
|
||||
"hostsFilesApplyChanges" : {
|
||||
"message": "Apply changes",
|
||||
"description": "English: Apply changes"
|
||||
},
|
||||
"ubiquitousFormatHint" : {
|
||||
"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.",
|
||||
"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."
|
||||
"hostsFilesAutoUpdatePrompt":{
|
||||
"message":"Auto-update filter lists.",
|
||||
"description":"English: Auto-update filter lists."
|
||||
},
|
||||
"ubiquitousAllowFormatHint" : {
|
||||
"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.",
|
||||
"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."
|
||||
"hostsFilesUpdateNow":{
|
||||
"message":"Update now",
|
||||
"description":"English: Update now"
|
||||
},
|
||||
"ubiquitousImport" : {
|
||||
"message": "Import and append",
|
||||
"description": "English: Import and append"
|
||||
"hostsFilesPurgeAll":{
|
||||
"message":"Purge all caches",
|
||||
"description":"English: Purge all caches"
|
||||
},
|
||||
"ubiquitousExport" : {
|
||||
"message": "Export",
|
||||
"description": "English: Export"
|
||||
"hostsFilesExternalListsHint":{
|
||||
"message":"One URL per line. Lines prefixed with ‘!’ will be ignored. Invalid URLs will be silently ignored.",
|
||||
"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" : {
|
||||
"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."
|
||||
|
|
|
@ -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" : {
|
||||
"message": "Все списки заблокированных хостов загружаются, как глобальные правила, в связи с чем их владельцы находятся в черном списке для всех областей.",
|
||||
"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" : {
|
||||
"message": "所有屏蔽站点的列表都作为普适规则被加载,所以这些站点将在所有作用域的黑名单中。",
|
||||
"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