mirror of
https://github.com/gorhill/uMatrix.git
synced 2024-05-17 18:53:33 +12:00
first pass
This commit is contained in:
parent
a5d051de3f
commit
ed67045360
Before Width: | Height: | Size: 777 B After Width: | Height: | Size: 777 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
"browser_action": {
|
||||
"default_icon": {
|
||||
"19": "img/browsericons/icon19.png"
|
||||
"19": "img/browsericons/icon19-off.png"
|
||||
},
|
||||
"default_title": "__MSG_extName__",
|
||||
"default_popup": "popup.html"
|
||||
|
@ -52,7 +52,7 @@
|
|||
"content_scripts": [
|
||||
{
|
||||
"matches": ["http://*/*", "https://*/*"],
|
||||
"js": ["js/contentscript-start.js"],
|
||||
"js": ["js/vapi-client.js", "js/contentscript-start.js"],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*******************************************************************************
|
||||
|
||||
µBlock - a browser extension to block requests.
|
||||
Copyright (C) 2014 The µBlock authors
|
||||
µMatrix - a browser extension to block requests.
|
||||
Copyright (C) 2014 The uBlock authors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,7 +19,7 @@
|
|||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
/* global self, µBlock */
|
||||
/* global self, µMatrix */
|
||||
|
||||
// For background page
|
||||
|
||||
|
@ -49,6 +49,34 @@ vAPI.app = {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.app.start = function() {
|
||||
// rhill 2013-12-07:
|
||||
// Relinquish control over javascript execution to the user.
|
||||
// https://github.com/gorhill/httpswitchboard/issues/74
|
||||
chrome.contentSettings.javascript.clear({});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.app.stop = function() {
|
||||
chrome.contentSettings.javascript.clear({});
|
||||
|
||||
// rhill 2013-12-07:
|
||||
// Tell Chromium to allow all javascript: µMatrix will control whether
|
||||
// javascript execute through `Content-Policy-Directive` and webRequest.
|
||||
// https://github.com/gorhill/httpswitchboard/issues/74
|
||||
chrome.contentSettings.javascript.set({
|
||||
primaryPattern: 'https://*/*',
|
||||
setting: 'allow'
|
||||
});
|
||||
chrome.contentSettings.javascript.set({
|
||||
primaryPattern: 'http://*/*',
|
||||
setting: 'allow'
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.app.restart = function() {
|
||||
chrome.runtime.reload();
|
||||
};
|
||||
|
@ -114,7 +142,8 @@ vAPI.tabs.registerListeners = function() {
|
|||
if ( popup !== undefined ) {
|
||||
return;
|
||||
}
|
||||
return popupCandidates[details.tabId] = new PopupCandidate(details);
|
||||
popup = popupCandidates[details.tabId] = new PopupCandidate(details);
|
||||
return popup;
|
||||
};
|
||||
|
||||
var popupCandidateTest = function(details) {
|
||||
|
@ -190,11 +219,12 @@ vAPI.tabs.registerListeners = function() {
|
|||
if ( typeof this.onClosed === 'function' ) {
|
||||
chrome.tabs.onRemoved.addListener(this.onClosed);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// tabId: null, // active tab
|
||||
|
||||
vAPI.tabs.get = function(tabId, callback) {
|
||||
var onTabReady = function(tab) {
|
||||
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
|
||||
|
@ -223,6 +253,12 @@ vAPI.tabs.get = function(tabId, callback) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.tabs.getAll = function(callback) {
|
||||
chrome.tabs.query({ url: '<all_urls>' }, callback);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// properties of the details object:
|
||||
// url: 'URL', // the address that will be opened
|
||||
// tabId: 1, // the tab is used if set, instead of creating a new one
|
||||
|
@ -356,6 +392,9 @@ vAPI.tabs.reload = function(tabId /*, flags*/) {
|
|||
if ( typeof tabId === 'string' ) {
|
||||
tabId = parseInt(tabId, 10);
|
||||
}
|
||||
if ( isNaN(tabId) ) {
|
||||
return;
|
||||
}
|
||||
chrome.tabs.reload(tabId);
|
||||
};
|
||||
|
||||
|
@ -387,8 +426,11 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
|
|||
// Since we may be called asynchronously, the tab id may not exist
|
||||
// anymore, so this ensures it does still exist.
|
||||
|
||||
vAPI.setIcon = function(tabId, iconStatus, badge) {
|
||||
vAPI.setIcon = function(tabId, iconId, badge) {
|
||||
tabId = parseInt(tabId, 10);
|
||||
if ( isNaN(tabId) || tabId <= 0 ) {
|
||||
return;
|
||||
}
|
||||
var onIconReady = function() {
|
||||
if ( vAPI.lastError() ) {
|
||||
return;
|
||||
|
@ -397,14 +439,16 @@ vAPI.setIcon = function(tabId, iconStatus, badge) {
|
|||
if ( badge !== '' ) {
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
tabId: tabId,
|
||||
color: '#666'
|
||||
color: '#000'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var iconPaths = iconStatus === 'on' ?
|
||||
{ '19': 'img/browsericons/icon19.png', '38': 'img/browsericons/icon38.png' } :
|
||||
{ '19': 'img/browsericons/icon19-off.png', '38': 'img/browsericons/icon38-off.png' };
|
||||
var iconSelector = typeof iconId === 'number' ? iconId : 'off';
|
||||
var iconPaths = {
|
||||
'19': 'img/browsericons/icon19-' + iconSelector + '.png'/* ,
|
||||
'38': 'img/browsericons/icon38-' + iconSelector + '.png' */
|
||||
};
|
||||
|
||||
chrome.browserAction.setIcon({ tabId: tabId, path: iconPaths }, onIconReady);
|
||||
};
|
||||
|
@ -449,7 +493,7 @@ vAPI.messaging.onPortMessage = function(request, port) {
|
|||
return;
|
||||
}
|
||||
|
||||
console.error('µBlock> messaging > unknown request: %o', request);
|
||||
console.error('µMatrix> messaging > unknown request: %o', request);
|
||||
|
||||
// Unhandled:
|
||||
// Need to callback anyways in case caller expected an answer, or
|
||||
|
@ -568,21 +612,21 @@ vAPI.net = {};
|
|||
/******************************************************************************/
|
||||
|
||||
vAPI.net.registerListeners = function() {
|
||||
var µb = µBlock;
|
||||
var µburi = µb.URI;
|
||||
var µm = µMatrix;
|
||||
var µmuri = µm.URI;
|
||||
|
||||
var normalizeRequestDetails = function(details) {
|
||||
µburi.set(details.url);
|
||||
µmuri.set(details.url);
|
||||
|
||||
details.tabId = details.tabId.toString();
|
||||
details.hostname = µburi.hostnameFromURI(details.url);
|
||||
details.hostname = µmuri.hostnameFromURI(details.url);
|
||||
|
||||
// The rest of the function code is to normalize type
|
||||
if ( details.type !== 'other' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tail = µburi.path.slice(-6);
|
||||
var tail = µmuri.path.slice(-6);
|
||||
var pos = tail.lastIndexOf('.');
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/862
|
||||
|
@ -628,6 +672,20 @@ vAPI.net.registerListeners = function() {
|
|||
this.onBeforeRequest.extra
|
||||
);
|
||||
|
||||
var onBeforeSendHeadersClient = this.onBeforeSendHeaders.callback;
|
||||
var onBeforeSendHeaders = function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
return onBeforeSendHeadersClient(details);
|
||||
};
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||
onBeforeSendHeaders,
|
||||
{
|
||||
'urls': this.onBeforeSendHeaders.urls || ['<all_urls>'],
|
||||
'types': this.onBeforeSendHeaders.types || []
|
||||
},
|
||||
this.onBeforeSendHeaders.extra
|
||||
);
|
||||
|
||||
var onHeadersReceivedClient = this.onHeadersReceived.callback;
|
||||
var onHeadersReceived = function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
|
@ -641,6 +699,13 @@ vAPI.net.registerListeners = function() {
|
|||
},
|
||||
this.onHeadersReceived.extra
|
||||
);
|
||||
|
||||
chrome.webRequest.onErrorOccurred.addListener(
|
||||
this.onErrorOccurred.callback,
|
||||
{
|
||||
'urls': this.onErrorOccurred.urls || ['<all_urls>']
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -672,48 +737,6 @@ vAPI.lastError = function() {
|
|||
// the web pages before uBlock was ready.
|
||||
|
||||
vAPI.onLoadAllCompleted = function() {
|
||||
// http://code.google.com/p/chromium/issues/detail?id=410868#c11
|
||||
// Need to be sure to access `vAPI.lastError()` to prevent
|
||||
// spurious warnings in the console.
|
||||
var scriptDone = function() {
|
||||
vAPI.lastError();
|
||||
};
|
||||
var scriptEnd = function(tabId) {
|
||||
if ( vAPI.lastError() ) {
|
||||
return;
|
||||
}
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
file: 'js/contentscript-end.js',
|
||||
allFrames: true,
|
||||
runAt: 'document_idle'
|
||||
}, scriptDone);
|
||||
};
|
||||
var scriptStart = function(tabId) {
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
file: 'js/vapi-client.js',
|
||||
allFrames: true,
|
||||
runAt: 'document_start'
|
||||
}, function(){ });
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
file: 'js/contentscript-start.js',
|
||||
allFrames: true,
|
||||
runAt: 'document_start'
|
||||
}, function(){ scriptEnd(tabId); });
|
||||
};
|
||||
var bindToTabs = function(tabs) {
|
||||
var µb = µBlock;
|
||||
var i = tabs.length, tab;
|
||||
while ( i-- ) {
|
||||
tab = tabs[i];
|
||||
µb.tabContextManager.commit(tab.id, tab.url);
|
||||
µb.bindTabToPageStats(tab.id);
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/129
|
||||
scriptStart(tab.id);
|
||||
}
|
||||
};
|
||||
|
||||
chrome.tabs.query({ url: 'http://*/*' }, bindToTabs);
|
||||
chrome.tabs.query({ url: 'https://*/*' }, bindToTabs);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -728,6 +751,43 @@ vAPI.punycodeURL = function(url) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.browserCache = {};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.browserCache.clearByTime = function(since) {
|
||||
chrome.browsingData.removeCache({ since: 0 });
|
||||
};
|
||||
|
||||
vAPI.browserCache.clearByOrigin = function(/* domain */) {
|
||||
// unsupported on Chromium
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.cookies = {};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.cookies.registerListeners = function() {
|
||||
if ( typeof this.onChanged === 'function' ) {
|
||||
chrome.cookies.onChanged.addListener(this.onChanged);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.cookies.getAll = function(callback) {
|
||||
chrome.cookies.getAll({}, callback);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.cookies.remove = function(details, callback) {
|
||||
chrome.cookies.remove(details, callback || noopFunc);
|
||||
};
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -38,8 +38,8 @@ if ( vAPI.vapiClientInjected ) {
|
|||
//console.debug('vapi-client.js already injected: skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
vAPI.vapiClientInjected = true;
|
||||
|
||||
vAPI.sessionId = String.fromCharCode(Date.now() % 25 + 97) +
|
||||
Math.random().toString(36).slice(2);
|
||||
vAPI.chrome = true;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
µBlock - a browser extension to block requests.
|
||||
µMatrix - a browser extension to block requests.
|
||||
Copyright (C) 2014 The µBlock authors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
@ -16,7 +16,7 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
// For background page or non-background pages
|
||||
|
|
|
@ -47,10 +47,11 @@ ul {
|
|||
<span style="display: none;" data-i18n="aboutResetConfirm"></span>
|
||||
|
||||
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.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/about.js"></script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script src="js/vapi-client.js"></script>
|
||||
<script src="js/udom.js"></script>
|
||||
<script src="js/messaging-client.js"></script>
|
||||
<script src="js/asset-viewer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
<script src="lib/punycode.min.js"></script>
|
||||
<script src="lib/publicsuffixlist.min.js"></script>
|
||||
<script src="lib/yamd5.min.js"></script>
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-background.js"></script>
|
||||
<script src="js/types.js"></script>
|
||||
<script src="js/background.js"></script>
|
||||
<script src="js/xal.js"></script>
|
||||
|
@ -25,11 +27,10 @@
|
|||
<script src="js/profiler.js"></script>
|
||||
<script src="js/storage.js"></script>
|
||||
<script src="js/pagestats.js"></script>
|
||||
<script src="js/tab.js"></script>
|
||||
<script src="js/uritools.js"></script>
|
||||
<script src="js/tab.js"></script>
|
||||
<script src="js/traffic.js"></script>
|
||||
<script src="js/useragent.js"></script>
|
||||
<script src="js/messaging-handlers.js"></script>
|
||||
<script src="js/start.js"></script>
|
||||
<script src="js/commands.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -90,6 +90,8 @@ iframe {
|
|||
|
||||
<iframe src=""></iframe>
|
||||
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.js"></script>
|
||||
<script src="js/udom.js"></script>
|
||||
<script src="js/i18n.js"></script>
|
||||
<script src="js/dashboard.js"></script>
|
||||
|
|
|
@ -29,10 +29,11 @@
|
|||
|
||||
<div id="busyOverlay"></div>
|
||||
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.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/hosts-files.js"></script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -109,10 +109,11 @@
|
|||
|
||||
</div> <!-- end of detailed stats -->
|
||||
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.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/info.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -19,24 +19,29 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global chrome, messaging, uDom */
|
||||
/* global vAPI, uDom */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
uDom.onLoad(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var messager = vAPI.messaging.channel('about.js');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var backupUserDataToFile = function() {
|
||||
var userDataReady = function(userData) {
|
||||
chrome.downloads.download({
|
||||
vAPI.download({
|
||||
'url': 'data:text/plain,' + encodeURIComponent(JSON.stringify(userData)),
|
||||
'filename': uDom('[data-i18n="aboutBackupFilename"]').text(),
|
||||
'saveAs': true
|
||||
'filename': uDom('[data-i18n="aboutBackupFilename"]').text()
|
||||
});
|
||||
};
|
||||
|
||||
messaging.ask({ what: 'getAllUserData' }, userDataReady);
|
||||
messager.send({ what: 'getAllUserData' }, userDataReady);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -75,7 +80,7 @@ function restoreUserDataFromFile() {
|
|||
.replace('{{time}}', time.toLocaleString());
|
||||
var proceed = window.confirm(msg);
|
||||
if ( proceed ) {
|
||||
messaging.tell({ what: 'restoreAllUserData', userData: userData });
|
||||
messager.send({ what: 'restoreAllUserData', userData: userData });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -107,7 +112,7 @@ var startRestoreFilePicker = function() {
|
|||
var resetUserData = function() {
|
||||
var proceed = window.confirm(uDom('[data-i18n="aboutResetConfirm"]').text());
|
||||
if ( proceed ) {
|
||||
messaging.tell({ what: 'resetAllUserData' });
|
||||
messager.send({ what: 'resetAllUserData' });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -123,8 +128,7 @@ var resetUserData = function() {
|
|||
}
|
||||
uDom('#aboutStorageUsed').html(template.replace('{{storageUsed}}', storageUsed));
|
||||
};
|
||||
messaging.start('about.js');
|
||||
messaging.ask({ what: 'getSomeStats' }, renderStats);
|
||||
messager.send({ what: 'getSomeStats' }, renderStats);
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -19,15 +19,17 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global chrome, messaging, uDom */
|
||||
/* global vAPI, uDom */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
messaging.start('asset-viewer.js');
|
||||
var messager = vAPI.messaging.channel('asset-viewer.js');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -43,7 +45,7 @@ if ( !matches || matches.length !== 2 ) {
|
|||
return;
|
||||
}
|
||||
|
||||
messaging.ask({ what : 'getAssetContent', url: matches[1] }, onAssetContentReceived);
|
||||
messager.send({ what : 'getAssetContent', url: matches[1] }, onAssetContentReceived);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
785
src/js/assets.js
785
src/js/assets.js
File diff suppressed because it is too large
Load diff
|
@ -145,11 +145,7 @@ return asyncJobManager;
|
|||
pageStore.updateBadge(tabId);
|
||||
return;
|
||||
}
|
||||
µm.XAL.setIcon(
|
||||
tabId,
|
||||
{ '19': 'img/browsericons/icon19.png' },
|
||||
'?'
|
||||
);
|
||||
vAPI.setIcon(tabId, null, '?');
|
||||
};
|
||||
|
||||
var updateBadgeAsync = function(tabId) {
|
||||
|
@ -172,7 +168,7 @@ return asyncJobManager;
|
|||
// does not exist. I suspect this could be related to
|
||||
// https://github.com/gorhill/httpswitchboard/issues/58
|
||||
var urlStatsChangedCallback = function(pageUrl) {
|
||||
µMatrix.messaging.tell('popup.js', {
|
||||
vAPI.messaging.broadcast({
|
||||
what: 'urlStatsChanged',
|
||||
pageURL: pageUrl
|
||||
});
|
||||
|
|
|
@ -49,8 +49,6 @@ var defaultUserAgentStrings = [
|
|||
/******************************************************************************/
|
||||
|
||||
return {
|
||||
manifest: chrome.runtime.getManifest(),
|
||||
|
||||
userSettings: {
|
||||
autoUpdate: false,
|
||||
clearBrowserCache: true,
|
||||
|
@ -125,7 +123,6 @@ return {
|
|||
refererHeaderFoiledCounter: 0,
|
||||
hyperlinkAuditingFoiledCounter: 0,
|
||||
browserCacheClearedCounter: 0,
|
||||
storageQuota: chrome.storage.local.QUOTA_BYTES,
|
||||
storageUsed: 0,
|
||||
userAgentReplaceStr: '',
|
||||
userAgentReplaceStrBirth: 0,
|
||||
|
@ -138,8 +135,8 @@ return {
|
|||
|
||||
// Commonly encountered strings
|
||||
chromeExtensionURLPrefix: 'chrome-extension://',
|
||||
noopCSSURL: chrome.runtime.getURL('css/noop.css'),
|
||||
fontCSSURL: chrome.runtime.getURL('css/fonts/Roboto_Condensed/RobotoCondensed-Regular.ttf'),
|
||||
noopCSSURL: vAPI.getURL('css/noop.css'),
|
||||
fontCSSURL: vAPI.getURL('css/fonts/Roboto_Condensed/RobotoCondensed-Regular.ttf'),
|
||||
|
||||
noopFunc: function(){},
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ var onCommand = function(command) {
|
|||
µMatrix.revertAllRules();
|
||||
break;
|
||||
case 'whitelist-all':
|
||||
chrome.tabs.query({ active: true }, whitelistAll);
|
||||
vAPI.tabs.get(null, whitelistAll);
|
||||
break;
|
||||
case 'open-dashboard':
|
||||
µMatrix.utils.gotoExtensionURL('dashboard.html');
|
||||
|
@ -59,7 +59,7 @@ var onCommand = function(command) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
chrome.commands.onCommand.addListener(onCommand);
|
||||
// chrome.commands.onCommand.addListener(onCommand);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
@ -19,113 +19,49 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* jshint multistr: true */
|
||||
/* global chrome */
|
||||
/* global vAPI */
|
||||
/* jshint multistr: true, boss: true */
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// Injected into content pages
|
||||
|
||||
/******************************************************************************/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/345
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/464
|
||||
if ( document instanceof HTMLDocument === false ) {
|
||||
//console.debug('contentscript-end.js > not a HTLMDocument');
|
||||
return false;
|
||||
}
|
||||
|
||||
var messaging = (function(name){
|
||||
var port = null;
|
||||
var requestId = 1;
|
||||
var requestIdToCallbackMap = {};
|
||||
var listenCallback = null;
|
||||
// This can happen
|
||||
if ( !vAPI ) {
|
||||
//console.debug('contentscript-end.js > vAPI not found');
|
||||
return;
|
||||
}
|
||||
|
||||
var onPortMessage = function(details) {
|
||||
if ( typeof details.id !== 'number' ) {
|
||||
return;
|
||||
}
|
||||
// Announcement?
|
||||
if ( details.id < 0 ) {
|
||||
if ( listenCallback ) {
|
||||
listenCallback(details.msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var callback = requestIdToCallbackMap[details.id];
|
||||
if ( !callback ) {
|
||||
return;
|
||||
}
|
||||
// Must be removed before calling client to be sure to not execute
|
||||
// callback again if the client stops the messaging service.
|
||||
delete requestIdToCallbackMap[details.id];
|
||||
callback(details.msg);
|
||||
};
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/587
|
||||
// Pointless to execute without the start script having done its job.
|
||||
if ( !vAPI.contentscriptStartInjected ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var start = function(name) {
|
||||
port = chrome.runtime.connect({ name: name });
|
||||
port.onMessage.addListener(onPortMessage);
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/456
|
||||
// Already injected?
|
||||
if ( vAPI.contentscriptEndInjected ) {
|
||||
//console.debug('contentscript-end.js > content script already injected');
|
||||
return;
|
||||
}
|
||||
vAPI.contentscriptEndInjected = true;
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/193
|
||||
port.onDisconnect.addListener(stop);
|
||||
};
|
||||
/******************************************************************************/
|
||||
|
||||
var stop = function() {
|
||||
listenCallback = null;
|
||||
port.disconnect();
|
||||
port = null;
|
||||
flushCallbacks();
|
||||
};
|
||||
|
||||
if ( typeof name === 'string' && name !== '' ) {
|
||||
start(name);
|
||||
}
|
||||
|
||||
var ask = function(msg, callback) {
|
||||
if ( port === null ) {
|
||||
if ( typeof callback === 'function' ) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( callback === undefined ) {
|
||||
tell(msg);
|
||||
return;
|
||||
}
|
||||
var id = requestId++;
|
||||
port.postMessage({ id: id, msg: msg });
|
||||
requestIdToCallbackMap[id] = callback;
|
||||
};
|
||||
|
||||
var tell = function(msg) {
|
||||
if ( port !== null ) {
|
||||
port.postMessage({ id: 0, msg: msg });
|
||||
}
|
||||
};
|
||||
|
||||
var listen = function(callback) {
|
||||
listenCallback = callback;
|
||||
};
|
||||
|
||||
var flushCallbacks = function() {
|
||||
var callback;
|
||||
for ( var id in requestIdToCallbackMap ) {
|
||||
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
|
||||
continue;
|
||||
}
|
||||
callback = requestIdToCallbackMap[id];
|
||||
if ( !callback ) {
|
||||
continue;
|
||||
}
|
||||
// Must be removed before calling client to be sure to not execute
|
||||
// callback again if the client stops the messaging service.
|
||||
delete requestIdToCallbackMap[id];
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
start: start,
|
||||
stop: stop,
|
||||
ask: ask,
|
||||
tell: tell,
|
||||
listen: listen
|
||||
};
|
||||
})('contentscript-end.js');
|
||||
var localMessager = vAPI.messaging.channel('contentscript-end.js');
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
@ -154,12 +90,10 @@ var checkScriptBlacklistedHandler = function(response) {
|
|||
}
|
||||
};
|
||||
|
||||
messaging.ask({
|
||||
localMessager.send({
|
||||
what: 'checkScriptBlacklisted',
|
||||
url: window.location.href
|
||||
},
|
||||
checkScriptBlacklistedHandler
|
||||
);
|
||||
}, checkScriptBlacklistedHandler);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -179,12 +113,10 @@ try {
|
|||
var hasLocalStorage = window.localStorage && window.localStorage.length;
|
||||
var hasSessionStorage = window.sessionStorage && window.sessionStorage.length;
|
||||
if ( hasLocalStorage || hasSessionStorage ) {
|
||||
messaging.ask({
|
||||
localMessager.send({
|
||||
what: 'contentScriptHasLocalStorage',
|
||||
url: window.location.href
|
||||
},
|
||||
localStorageHandler
|
||||
);
|
||||
}, localStorageHandler);
|
||||
}
|
||||
|
||||
// TODO: indexedDB
|
||||
|
@ -291,28 +223,12 @@ var nodeListsAddedHandler = function(nodeLists) {
|
|||
nodesAddedHandler(nodeLists[i], summary);
|
||||
}
|
||||
if ( summary.mustReport ) {
|
||||
messaging.tell(summary);
|
||||
localMessager.send(summary);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// rhill 2013-11-09: Weird... This code is executed from HTTP Switchboard
|
||||
// context first time extension is launched. Avoid this.
|
||||
// TODO: Investigate if this was a fluke or if it can really happen.
|
||||
// I suspect this could only happen when I was using chrome.tabs.executeScript(),
|
||||
// because now a delarative content script is used, along with "http{s}" URL
|
||||
// pattern matching.
|
||||
|
||||
// console.debug('contentscript-end.js > window.location.href = "%s"', window.location.href);
|
||||
|
||||
if ( /^https?:\/\/./.test(window.location.href) === false ) {
|
||||
console.debug("Huh?");
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
var summary = {
|
||||
what: 'contentScriptSummary',
|
||||
|
@ -329,7 +245,7 @@ if ( /^https?:\/\/./.test(window.location.href) === false ) {
|
|||
|
||||
//console.debug('contentscript-end.js > firstObservationHandler(): found %d script tags in "%s"', Object.keys(summary.scriptSources).length, window.location.href);
|
||||
|
||||
messaging.tell(summary);
|
||||
localMessager.send(summary);
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -379,3 +295,8 @@ if ( document.body ) {
|
|||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
|
|
@ -19,124 +19,43 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global vAPI */
|
||||
/* jshint multistr: true */
|
||||
/* global chrome */
|
||||
|
||||
// Injected into content pages
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// OK, I keep changing my mind whether a closure should be used or not. This
|
||||
// will be the rule: if there are any variables directly accessed on a regular
|
||||
// basis, use a closure so that they are cached. Otherwise I don't think the
|
||||
// overhead of a closure is worth it. That's my understanding.
|
||||
|
||||
(function() {
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/345
|
||||
|
||||
var messaging = (function(name){
|
||||
var port = null;
|
||||
var requestId = 1;
|
||||
var requestIdToCallbackMap = {};
|
||||
var listenCallback = null;
|
||||
|
||||
var onPortMessage = function(details) {
|
||||
if ( typeof details.id !== 'number' ) {
|
||||
return;
|
||||
}
|
||||
// Announcement?
|
||||
if ( details.id < 0 ) {
|
||||
if ( listenCallback ) {
|
||||
listenCallback(details.msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var callback = requestIdToCallbackMap[details.id];
|
||||
if ( !callback ) {
|
||||
return;
|
||||
}
|
||||
// Must be removed before calling client to be sure to not execute
|
||||
// callback again if the client stops the messaging service.
|
||||
delete requestIdToCallbackMap[details.id];
|
||||
callback(details.msg);
|
||||
};
|
||||
|
||||
var start = function(name) {
|
||||
port = chrome.runtime.connect({ name: name });
|
||||
port.onMessage.addListener(onPortMessage);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/193
|
||||
port.onDisconnect.addListener(stop);
|
||||
};
|
||||
|
||||
var stop = function() {
|
||||
listenCallback = null;
|
||||
port.disconnect();
|
||||
port = null;
|
||||
flushCallbacks();
|
||||
};
|
||||
|
||||
if ( typeof name === 'string' && name !== '' ) {
|
||||
start(name);
|
||||
}
|
||||
|
||||
var ask = function(msg, callback) {
|
||||
if ( port === null ) {
|
||||
if ( typeof callback === 'function' ) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( callback === undefined ) {
|
||||
tell(msg);
|
||||
return;
|
||||
}
|
||||
var id = requestId++;
|
||||
port.postMessage({ id: id, msg: msg });
|
||||
requestIdToCallbackMap[id] = callback;
|
||||
};
|
||||
|
||||
var tell = function(msg) {
|
||||
if ( port !== null ) {
|
||||
port.postMessage({ id: 0, msg: msg });
|
||||
}
|
||||
};
|
||||
|
||||
var listen = function(callback) {
|
||||
listenCallback = callback;
|
||||
};
|
||||
|
||||
var flushCallbacks = function() {
|
||||
var callback;
|
||||
for ( var id in requestIdToCallbackMap ) {
|
||||
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
|
||||
continue;
|
||||
}
|
||||
callback = requestIdToCallbackMap[id];
|
||||
if ( !callback ) {
|
||||
continue;
|
||||
}
|
||||
// Must be removed before calling client to be sure to not execute
|
||||
// callback again if the client stops the messaging service.
|
||||
delete requestIdToCallbackMap[id];
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
start: start,
|
||||
stop: stop,
|
||||
ask: ask,
|
||||
tell: tell,
|
||||
listen: listen
|
||||
};
|
||||
})('contentscript-start.js');
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/464
|
||||
if ( document instanceof HTMLDocument === false ) {
|
||||
//console.debug('contentscript-start.js > not a HTLMDocument');
|
||||
return false;
|
||||
}
|
||||
|
||||
// This can happen
|
||||
if ( !vAPI ) {
|
||||
//console.debug('contentscript-start.js > vAPI not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/456
|
||||
// Already injected?
|
||||
if ( vAPI.contentscriptStartInjected ) {
|
||||
//console.debug('contentscript-end.js > content script already injected');
|
||||
return;
|
||||
}
|
||||
vAPI.contentscriptStartInjected = true;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var localMessager = vAPI.messaging.channel('contentscript-start.js');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// If you play with this code, mind:
|
||||
|
@ -193,14 +112,13 @@ var injectNavigatorSpoofer = function(spoofedUserAgent) {
|
|||
|
||||
// The port will never be used again at this point, disconnecting allows
|
||||
// to browser to flush this script from memory.
|
||||
messaging.stop();
|
||||
localMessager.close();
|
||||
};
|
||||
|
||||
var requestDetails = {
|
||||
localMessager.send({
|
||||
what: 'getUserAgentReplaceStr',
|
||||
hostname: window.location.hostname
|
||||
};
|
||||
messaging.ask(requestDetails, injectNavigatorSpoofer);
|
||||
}, injectNavigatorSpoofer);
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -301,7 +301,7 @@ var chromeCookieRemove = function(url, name) {
|
|||
}
|
||||
};
|
||||
|
||||
chrome.cookies.remove({ url: url, name: name }, callback);
|
||||
vAPI.cookies.remove({ url: url, name: name }, callback);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -485,7 +485,7 @@ var canRemoveCookie = function(cookieKey, srcHostnames) {
|
|||
|
||||
// Listen to any change in cookieland, we will update page stats accordingly.
|
||||
|
||||
var onChromeCookieChanged = function(changeInfo) {
|
||||
vAPI.cookies.onChanged = function(changeInfo) {
|
||||
if ( changeInfo.removed ) {
|
||||
return;
|
||||
}
|
||||
|
@ -524,8 +524,8 @@ var onChromeCookieChanged = function(changeInfo) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
chrome.cookies.getAll({}, addCookiesToDict);
|
||||
chrome.cookies.onChanged.addListener(onChromeCookieChanged);
|
||||
vAPI.cookies.getAll(addCookiesToDict);
|
||||
vAPI.cookies.registerListeners();
|
||||
|
||||
µm.asyncJobs.add('cookieHunterRemove', null, processRemoveQueue, 2 * 60 * 1000, true);
|
||||
µm.asyncJobs.add('cookieHunterClean', null, processClean, 10 * 60 * 1000, true);
|
||||
|
|
|
@ -25,10 +25,14 @@
|
|||
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var loadDashboardPanel = function(hash) {
|
||||
var button = uDom(hash);
|
||||
var url = button.attr('data-dashboard-panel-url');
|
||||
uDom('iframe').nodeAt(0).src = url;
|
||||
uDom('iframe').attr('src', url);
|
||||
uDom('.tabButton').forEach(function(button){
|
||||
button.toggleClass('selected', button.attr('data-dashboard-panel-url') === url);
|
||||
});
|
||||
|
|
|
@ -19,27 +19,16 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global chrome, messaging, uDom */
|
||||
/* global vAPI, uDom */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var listDetails = {};
|
||||
var externalHostsFiles = '';
|
||||
var cacheWasPurged = false;
|
||||
var needUpdate = false;
|
||||
var hasCachedContent = false;
|
||||
|
||||
var re3rdPartyExternalAsset = /^https?:\/\/[a-z0-9]+/;
|
||||
var re3rdPartyRepoAsset = /^assets\/thirdparties\/([^\/]+)/;
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
messaging.start('hosts-files.js');
|
||||
|
||||
var onMessage = function(msg) {
|
||||
switch ( msg.what ) {
|
||||
case 'loadHostsFilesCompleted':
|
||||
|
@ -51,7 +40,18 @@ var onMessage = function(msg) {
|
|||
}
|
||||
};
|
||||
|
||||
messaging.listen(onMessage);
|
||||
var messager = vAPI.messaging.channel('hosts-files.js', onMessage);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var listDetails = {};
|
||||
var externalHostsFiles = '';
|
||||
var cacheWasPurged = false;
|
||||
var needUpdate = false;
|
||||
var hasCachedContent = false;
|
||||
|
||||
var re3rdPartyExternalAsset = /^https?:\/\/[a-z0-9]+/;
|
||||
var re3rdPartyRepoAsset = /^assets\/thirdparties\/([^\/]+)/;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -94,9 +94,9 @@ var renderBlacklists = function() {
|
|||
return html.join('');
|
||||
};
|
||||
|
||||
var purgeButtontext = chrome.i18n.getMessage('hostsFilesExternalListPurge');
|
||||
var updateButtontext = chrome.i18n.getMessage('hostsFilesExternalListNew');
|
||||
var obsoleteButtontext = chrome.i18n.getMessage('hostsFilesExternalListObsolete');
|
||||
var purgeButtontext = vAPI.i18n('hostsFilesExternalListPurge');
|
||||
var updateButtontext = vAPI.i18n('hostsFilesExternalListNew');
|
||||
var obsoleteButtontext = vAPI.i18n('hostsFilesExternalListObsolete');
|
||||
var liTemplate = [
|
||||
'<li class="listDetails">',
|
||||
'<input type="checkbox" {{checked}}>',
|
||||
|
@ -107,7 +107,7 @@ var renderBlacklists = function() {
|
|||
'{{homeURL}}',
|
||||
': ',
|
||||
'<span class="dim">',
|
||||
chrome.i18n.getMessage('hostsFilesPerFileStats'),
|
||||
vAPI.i18n('hostsFilesPerFileStats'),
|
||||
'</span>'
|
||||
].join('');
|
||||
|
||||
|
@ -181,7 +181,7 @@ var renderBlacklists = function() {
|
|||
var html = htmlBuiltin.concat(htmlExternal);
|
||||
|
||||
uDom('#listsOfBlockedHostsPrompt').text(
|
||||
chrome.i18n.getMessage('hostsFilesStats')
|
||||
vAPI.i18n('hostsFilesStats')
|
||||
.replace('{{blockedHostnameCount}}', details.blockedHostnameCount.toLocaleString())
|
||||
);
|
||||
uDom('#autoUpdate').prop('checked', listDetails.autoUpdate === true);
|
||||
|
@ -191,7 +191,7 @@ var renderBlacklists = function() {
|
|||
updateWidgets();
|
||||
};
|
||||
|
||||
messaging.ask({ what: 'getLists' }, onListsReceived);
|
||||
messager.send({ what: 'getLists' }, onListsReceived);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -266,7 +266,7 @@ var onListCheckboxChanged = function() {
|
|||
/******************************************************************************/
|
||||
|
||||
var onListLinkClicked = function(ev) {
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'gotoExtensionURL',
|
||||
url: 'asset-viewer.html?url=' + uDom(this).attr('href')
|
||||
});
|
||||
|
@ -282,7 +282,7 @@ var onPurgeClicked = function() {
|
|||
if ( !href ) {
|
||||
return;
|
||||
}
|
||||
messaging.tell({ what: 'purgeCache', path: href });
|
||||
messager.send({ what: 'purgeCache', path: href });
|
||||
button.remove();
|
||||
if ( li.descendants('input').first().prop('checked') ) {
|
||||
cacheWasPurged = true;
|
||||
|
@ -312,7 +312,7 @@ var reloadAll = function(update) {
|
|||
off: lis.subset(i, 1).descendants('input').prop('checked') === false
|
||||
});
|
||||
}
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'reloadHostsFiles',
|
||||
switches: switches,
|
||||
update: update
|
||||
|
@ -341,13 +341,13 @@ var buttonPurgeAllHandler = function() {
|
|||
var onCompleted = function() {
|
||||
renderBlacklists();
|
||||
};
|
||||
messaging.ask({ what: 'purgeAllCaches' }, onCompleted);
|
||||
messager.send({ what: 'purgeAllCaches' }, onCompleted);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var autoUpdateCheckboxChanged = function() {
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'userSettings',
|
||||
name: 'autoUpdate',
|
||||
value: this.checked
|
||||
|
@ -361,7 +361,7 @@ var renderExternalLists = function() {
|
|||
uDom('#externalHostsFiles').val(details);
|
||||
externalHostsFiles = details;
|
||||
};
|
||||
messaging.ask({ what: 'userSettings', name: 'externalHostsFiles' }, onReceived);
|
||||
messager.send({ what: 'userSettings', name: 'externalHostsFiles' }, onReceived);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -377,7 +377,7 @@ var externalListsChangeHandler = function() {
|
|||
|
||||
var externalListsApplyHandler = function() {
|
||||
externalHostsFiles = uDom('#externalHostsFiles').val();
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'userSettings',
|
||||
name: 'externalHostsFiles',
|
||||
value: externalHostsFiles
|
||||
|
|
|
@ -198,27 +198,11 @@
|
|||
/******************************************************************************/
|
||||
|
||||
µMatrix.turnOff = function() {
|
||||
// rhill 2013-12-07:
|
||||
// Relinquish control over javascript execution to the user.
|
||||
// https://github.com/gorhill/httpswitchboard/issues/74
|
||||
chrome.contentSettings.javascript.clear({});
|
||||
vAPI.app.start();
|
||||
};
|
||||
|
||||
µMatrix.turnOn = function() {
|
||||
chrome.contentSettings.javascript.clear({});
|
||||
|
||||
// rhill 2013-12-07:
|
||||
// Tell Chromium to allow all javascript: µMatrix will control whether
|
||||
// javascript execute through `Content-Policy-Directive` and webRequest.
|
||||
// https://github.com/gorhill/httpswitchboard/issues/74
|
||||
chrome.contentSettings.javascript.set({
|
||||
primaryPattern: 'https://*/*',
|
||||
setting: 'allow'
|
||||
});
|
||||
chrome.contentSettings.javascript.set({
|
||||
primaryPattern: 'http://*/*',
|
||||
setting: 'allow'
|
||||
});
|
||||
vAPI.app.stop();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -37,7 +37,7 @@ window.addEventListener('load', function() {
|
|||
var node;
|
||||
while ( i-- ) {
|
||||
node = nodeList[i];
|
||||
node.innerHTML = chrome.i18n.getMessage(node.getAttribute('data-i18n'));
|
||||
node.innerHTML = vAPI.i18n(node.getAttribute('data-i18n'));
|
||||
}
|
||||
// copy text of <h1> if any to document title
|
||||
node = document.querySelector('h1');
|
||||
|
@ -49,6 +49,6 @@ window.addEventListener('load', function() {
|
|||
i = nodeList.length;
|
||||
while ( i-- ) {
|
||||
node = nodeList[i];
|
||||
node.setAttribute('data-tip', chrome.i18n.getMessage(node.getAttribute('data-i18n-tip')));
|
||||
node.setAttribute('data-tip', vAPI.i18n(node.getAttribute('data-i18n-tip')));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -19,15 +19,17 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global messaging, uDom */
|
||||
/* global vAPI, uDom */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
messaging.start('info.js');
|
||||
var messager = vAPI.messaging.channel('info.js');
|
||||
|
||||
var targetUrl = 'all';
|
||||
var maxRequests = 500;
|
||||
|
@ -55,7 +57,7 @@ function updateRequestData(callback) {
|
|||
what: 'getRequestLogs',
|
||||
pageURL: targetUrl !== 'all' ? targetUrl : null
|
||||
};
|
||||
messaging.ask(request, onResponseReceived);
|
||||
messager.send(request, onResponseReceived);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -65,7 +67,7 @@ function clearRequestData() {
|
|||
what: 'clearRequestLogs',
|
||||
pageURL: targetUrl !== 'all' ? targetUrl : null
|
||||
};
|
||||
messaging.tell(request);
|
||||
messager.send(request);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -93,7 +95,7 @@ function renderNumbers(set) {
|
|||
|
||||
var renderLocalized = function(id, map) {
|
||||
var uElem = uDom('#' + id);
|
||||
var msg = chrome.i18n.getMessage(id);
|
||||
var msg = vAPI.i18n(id);
|
||||
for ( var k in map ) {
|
||||
if ( map.hasOwnProperty(k) === false ) {
|
||||
continue;
|
||||
|
@ -144,7 +146,7 @@ function renderPageUrls() {
|
|||
// Select whatever needs to be selected
|
||||
//uDom('#selectPageUrls > option[value="'+targetUrl+'"]').prop('selected', true);
|
||||
};
|
||||
messaging.ask({ what: 'getPageURLs' }, onResponseReceived);
|
||||
messager.send({ what: 'getPageURLs' }, onResponseReceived);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -193,7 +195,7 @@ function renderStats() {
|
|||
uDom('a').attr('target', '_blank');
|
||||
};
|
||||
|
||||
messaging.ask({
|
||||
messager.send({
|
||||
what: 'getStats',
|
||||
pageURL: targetUrl === 'all' ? null : targetUrl
|
||||
},
|
||||
|
@ -285,7 +287,7 @@ var clearRequests = function() {
|
|||
|
||||
function changeUserSettings(name, value) {
|
||||
cachedUserSettings[name] = value;
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'userSettings',
|
||||
name: name,
|
||||
value: value
|
||||
|
@ -404,7 +406,7 @@ uDom.onLoad(function(){
|
|||
|
||||
installEventHandlers();
|
||||
};
|
||||
messaging.ask({ what: 'getUserSettings' }, onResponseReceived);
|
||||
messager.send({ what: 'getUserSettings' }, onResponseReceived);
|
||||
|
||||
renderTransientData(true);
|
||||
updateRequests();
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
µMatrix - a Chromium browser extension to black/white list requests.
|
||||
Copyright (C) 2014 Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
// This is the reference client-side implementation of µBlock's messaging
|
||||
// infrastructure. The "server"-side implementation is in messaging.js.
|
||||
|
||||
// The client-side implementation creates a port in order to connect to
|
||||
// µBlock's background page. With this port we can "ask", "tell" or "announce":
|
||||
//
|
||||
// "ask": send a request and expect an answer using a callback.
|
||||
// "tell": send a request with no expectation of an answer.
|
||||
// "announce": send a request to be relayed to all connections -- no answer
|
||||
// expected.
|
||||
//
|
||||
// The tricky part in this implementation is to ensure all the requests are
|
||||
// uniquely identified, so that the background-page can keep track of these
|
||||
// until it is ready to send back an answer, which will be tagged with the
|
||||
// same id. The uniqueness must be true for all ports which connect to the
|
||||
// background page at any given time.
|
||||
//
|
||||
// Currently using Math.random() to generate this id... I don't know about the
|
||||
// implementation of Math.random(), but as long as I have a good expectation
|
||||
// of uniqueness, it's ok, we are not dealing with critical stuff here.
|
||||
|
||||
/* global chrome */
|
||||
|
||||
var messaging = (function(name){
|
||||
var port = null;
|
||||
var requestId = 1;
|
||||
var requestIdToCallbackMap = {};
|
||||
var listenCallback = null;
|
||||
|
||||
var onPortMessage = function(details) {
|
||||
if ( typeof details.id !== 'number' ) {
|
||||
return;
|
||||
}
|
||||
// Announcement?
|
||||
if ( details.id < 0 ) {
|
||||
if ( listenCallback ) {
|
||||
listenCallback(details.msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var callback = requestIdToCallbackMap[details.id];
|
||||
if ( !callback ) {
|
||||
return;
|
||||
}
|
||||
// Must be removed before calling client to be sure to not execute
|
||||
// callback again if the client stops the messaging service.
|
||||
delete requestIdToCallbackMap[details.id];
|
||||
callback(details.msg);
|
||||
};
|
||||
|
||||
var start = function(name) {
|
||||
port = chrome.runtime.connect({ name: name });
|
||||
port.onMessage.addListener(onPortMessage);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/193
|
||||
port.onDisconnect.addListener(stop);
|
||||
};
|
||||
|
||||
var stop = function() {
|
||||
listenCallback = null;
|
||||
port.disconnect();
|
||||
port = null;
|
||||
flushCallbacks();
|
||||
};
|
||||
|
||||
if ( typeof name === 'string' && name !== '' ) {
|
||||
start(name);
|
||||
}
|
||||
|
||||
var ask = function(msg, callback) {
|
||||
if ( port === null ) {
|
||||
if ( typeof callback === 'function' ) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( callback === undefined ) {
|
||||
tell(msg);
|
||||
return;
|
||||
}
|
||||
var id = requestId++;
|
||||
port.postMessage({ id: id, msg: msg });
|
||||
requestIdToCallbackMap[id] = callback;
|
||||
};
|
||||
|
||||
var tell = function(msg) {
|
||||
if ( port !== null ) {
|
||||
port.postMessage({ id: 0, msg: msg });
|
||||
}
|
||||
};
|
||||
|
||||
var listen = function(callback) {
|
||||
listenCallback = callback;
|
||||
};
|
||||
|
||||
var flushCallbacks = function() {
|
||||
var callback;
|
||||
for ( var id in requestIdToCallbackMap ) {
|
||||
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
|
||||
continue;
|
||||
}
|
||||
callback = requestIdToCallbackMap[id];
|
||||
if ( !callback ) {
|
||||
continue;
|
||||
}
|
||||
// Must be removed before calling client to be sure to not execute
|
||||
// callback again if the client stops the messaging service.
|
||||
delete requestIdToCallbackMap[id];
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
start: start,
|
||||
stop: stop,
|
||||
ask: ask,
|
||||
tell: tell,
|
||||
listen: listen
|
||||
};
|
||||
})();
|
|
@ -1,816 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
µMatrix - a Chromium browser extension to black/white list requests.
|
||||
Copyright (C) 2014 Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global chrome, µMatrix */
|
||||
/* jshint boss: true */
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
// popup.js
|
||||
|
||||
var µm = µMatrix;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var smartReload = function(tabs) {
|
||||
var i = tabs.length;
|
||||
while ( i-- ) {
|
||||
µm.smartReloadTabs(µm.userSettings.smartAutoReload, tabs[i].id);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Constructor is faster than object literal
|
||||
|
||||
var RowSnapshot = function(srcHostname, desHostname, desDomain) {
|
||||
this.domain = desDomain;
|
||||
this.temporary = µm.tMatrix.evaluateRowZXY(srcHostname, desHostname);
|
||||
this.permanent = µm.pMatrix.evaluateRowZXY(srcHostname, desHostname);
|
||||
this.counts = RowSnapshot.counts.slice();
|
||||
this.totals = RowSnapshot.counts.slice();
|
||||
};
|
||||
|
||||
RowSnapshot.counts = (function() {
|
||||
var i = Object.keys(µm.Matrix.getColumnHeaders()).length;
|
||||
var aa = new Array(i);
|
||||
while ( i-- ) {
|
||||
aa[i] = 0;
|
||||
}
|
||||
return aa;
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var matrixSnapshot = function(details) {
|
||||
var µmuser = µm.userSettings;
|
||||
var r = {
|
||||
tabId: details.tabId,
|
||||
url: '',
|
||||
hostname: '',
|
||||
domain: '',
|
||||
blockedCount: 0,
|
||||
scope: '*',
|
||||
headers: µm.Matrix.getColumnHeaders(),
|
||||
tSwitches: {},
|
||||
pSwitches: {},
|
||||
rows: {},
|
||||
rowCount: 0,
|
||||
diff: [],
|
||||
userSettings: {
|
||||
colorBlindFriendly: µmuser.colorBlindFriendly,
|
||||
displayTextSize: µmuser.displayTextSize,
|
||||
popupCollapseDomains: µmuser.popupCollapseDomains,
|
||||
popupCollapseSpecificDomains: µmuser.popupCollapseSpecificDomains,
|
||||
popupHideBlacklisted: µmuser.popupHideBlacklisted,
|
||||
popupScopeLevel: µmuser.popupScopeLevel
|
||||
}
|
||||
};
|
||||
|
||||
// Allow examination of behind-the-scene requests
|
||||
// TODO: Not portable
|
||||
if ( details.tabURL ) {
|
||||
if ( details.tabURL.indexOf('chrome-extension://' + chrome.runtime.id + '/') === 0 ) {
|
||||
details.tabId = µm.behindTheSceneTabId;
|
||||
} else if ( details.tabURL === µm.behindTheSceneURL ) {
|
||||
details.tabId = µm.behindTheSceneTabId;
|
||||
}
|
||||
}
|
||||
|
||||
var pageStore = µm.pageStatsFromTabId(details.tabId);
|
||||
if ( !pageStore ) {
|
||||
return r;
|
||||
}
|
||||
|
||||
var headers = r.headers;
|
||||
|
||||
r.url = pageStore.pageUrl;
|
||||
r.hostname = pageStore.pageHostname;
|
||||
r.domain = pageStore.pageDomain;
|
||||
r.blockedCount = pageStore.requestStats.blocked.all;
|
||||
|
||||
if ( µmuser.popupScopeLevel === 'site' ) {
|
||||
r.scope = r.hostname;
|
||||
} else if ( µmuser.popupScopeLevel === 'domain' ) {
|
||||
r.scope = r.domain;
|
||||
}
|
||||
|
||||
var switchNames = µm.Matrix.getSwitchNames();
|
||||
for ( var switchName in switchNames ) {
|
||||
if ( switchNames.hasOwnProperty(switchName) === false ) {
|
||||
continue;
|
||||
}
|
||||
r.tSwitches[switchName] = µm.tMatrix.evaluateSwitchZ(switchName, r.scope);
|
||||
r.pSwitches[switchName] = µm.pMatrix.evaluateSwitchZ(switchName, r.scope);
|
||||
}
|
||||
|
||||
// These rows always exist
|
||||
r.rows['*'] = new RowSnapshot(r.scope, '*', '*');
|
||||
r.rows['1st-party'] = new RowSnapshot(r.scope, '1st-party', '1st-party');
|
||||
r.rowCount += 1;
|
||||
|
||||
var µmuri = µm.URI;
|
||||
var reqKey, reqType, reqHostname, reqDomain;
|
||||
var desHostname;
|
||||
var row, typeIndex;
|
||||
var anyIndex = headers['*'];
|
||||
|
||||
var pageRequests = pageStore.requests;
|
||||
var reqKeys = pageRequests.getRequestKeys();
|
||||
var iReqKey = reqKeys.length;
|
||||
var pos;
|
||||
|
||||
while ( iReqKey-- ) {
|
||||
reqKey = reqKeys[iReqKey];
|
||||
reqType = pageRequests.typeFromRequestKey(reqKey);
|
||||
reqHostname = pageRequests.hostnameFromRequestKey(reqKey);
|
||||
// rhill 2013-10-23: hostname can be empty if the request is a data url
|
||||
// https://github.com/gorhill/httpswitchboard/issues/26
|
||||
if ( reqHostname === '' ) {
|
||||
reqHostname = pageStore.pageHostname;
|
||||
}
|
||||
reqDomain = µmuri.domainFromHostname(reqHostname) || reqHostname;
|
||||
|
||||
// We want rows of self and ancestors
|
||||
desHostname = reqHostname;
|
||||
for ( ;; ) {
|
||||
// If row exists, ancestors exist
|
||||
if ( r.rows.hasOwnProperty(desHostname) !== false ) {
|
||||
break;
|
||||
}
|
||||
r.rows[desHostname] = new RowSnapshot(r.scope, desHostname, reqDomain);
|
||||
r.rowCount += 1;
|
||||
if ( desHostname === reqDomain ) {
|
||||
break;
|
||||
}
|
||||
pos = desHostname.indexOf('.');
|
||||
if ( pos === -1 ) {
|
||||
break;
|
||||
}
|
||||
desHostname = desHostname.slice(pos + 1);
|
||||
}
|
||||
|
||||
typeIndex = headers[reqType];
|
||||
|
||||
row = r.rows[reqHostname];
|
||||
row.counts[typeIndex] += 1;
|
||||
row.counts[anyIndex] += 1;
|
||||
|
||||
row = r.rows[reqDomain];
|
||||
row.totals[typeIndex] += 1;
|
||||
row.totals[anyIndex] += 1;
|
||||
|
||||
row = r.rows['*'];
|
||||
row.totals[typeIndex] += 1;
|
||||
row.totals[anyIndex] += 1;
|
||||
}
|
||||
|
||||
r.diff = µm.tMatrix.diff(µm.pMatrix, r.hostname, Object.keys(r.rows));
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'disconnected':
|
||||
// https://github.com/gorhill/httpswitchboard/issues/94
|
||||
if ( µm.userSettings.smartAutoReload ) {
|
||||
chrome.tabs.query({ active: true }, smartReload);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'matrixSnapshot':
|
||||
response = matrixSnapshot(request);
|
||||
break;
|
||||
|
||||
case 'toggleMatrixSwitch':
|
||||
µm.tMatrix.setSwitchZ(
|
||||
request.switchName,
|
||||
request.srcHostname,
|
||||
µm.tMatrix.evaluateSwitchZ(request.switchName, request.srcHostname) === false
|
||||
);
|
||||
break;
|
||||
|
||||
case 'blacklistMatrixCell':
|
||||
µm.tMatrix.blacklistCell(
|
||||
request.srcHostname,
|
||||
request.desHostname,
|
||||
request.type
|
||||
);
|
||||
break;
|
||||
|
||||
case 'whitelistMatrixCell':
|
||||
µm.tMatrix.whitelistCell(
|
||||
request.srcHostname,
|
||||
request.desHostname,
|
||||
request.type
|
||||
);
|
||||
break;
|
||||
|
||||
case 'graylistMatrixCell':
|
||||
µm.tMatrix.graylistCell(
|
||||
request.srcHostname,
|
||||
request.desHostname,
|
||||
request.type
|
||||
);
|
||||
break;
|
||||
|
||||
case 'applyDiffToPermanentMatrix': // aka "persist"
|
||||
if ( µm.pMatrix.applyDiff(request.diff, µm.tMatrix) ) {
|
||||
µm.saveMatrix();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'applyDiffToTemporaryMatrix': // aka "revert"
|
||||
µm.tMatrix.applyDiff(request.diff, µm.pMatrix);
|
||||
break;
|
||||
|
||||
case 'revertTemporaryMatrix':
|
||||
µm.tMatrix.assign(µm.pMatrix);
|
||||
break;
|
||||
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
µm.messaging.listen('popup.js', onMessage);
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// content scripts
|
||||
|
||||
(function() {
|
||||
|
||||
var µm = µMatrix;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var contentScriptSummaryHandler = function(tabId, details) {
|
||||
// TODO: Investigate "Error in response to tabs.executeScript: TypeError:
|
||||
// Cannot read property 'locationURL' of null" (2013-11-12). When can this
|
||||
// happens?
|
||||
if ( !details || !details.locationURL ) {
|
||||
return;
|
||||
}
|
||||
var pageURL = µm.pageUrlFromTabId(tabId);
|
||||
var pageStats = µm.pageStatsFromPageUrl(pageURL);
|
||||
var µmuri = µm.URI.set(details.locationURL);
|
||||
var frameURL = µmuri.normalizedURI();
|
||||
var frameHostname = µmuri.hostname;
|
||||
var urls, url, r;
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/333
|
||||
// Look-up here whether inline scripting is blocked for the frame.
|
||||
var inlineScriptBlocked = µm.mustBlock(µm.scopeFromURL(pageURL), frameHostname, 'script');
|
||||
|
||||
// scripts
|
||||
// https://github.com/gorhill/httpswitchboard/issues/25
|
||||
if ( pageStats && inlineScriptBlocked ) {
|
||||
urls = details.scriptSources;
|
||||
for ( url in urls ) {
|
||||
if ( !urls.hasOwnProperty(url) ) {
|
||||
continue;
|
||||
}
|
||||
if ( url === '{inline_script}' ) {
|
||||
url = frameURL + '{inline_script}';
|
||||
}
|
||||
r = µm.filterRequest(pageURL, 'script', url);
|
||||
pageStats.recordRequest('script', url, r !== false, r);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: as of 2014-05-26, not sure this is needed anymore, since µMatrix
|
||||
// no longer uses chrome.contentSettings API (I think that was the reason
|
||||
// this code was put in).
|
||||
// plugins
|
||||
// https://github.com/gorhill/httpswitchboard/issues/25
|
||||
if ( pageStats ) {
|
||||
urls = details.pluginSources;
|
||||
for ( url in urls ) {
|
||||
if ( !urls.hasOwnProperty(url) ) {
|
||||
continue;
|
||||
}
|
||||
r = µm.filterRequest(pageURL, 'plugin', url);
|
||||
pageStats.recordRequest('plugin', url, r !== false, r);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/181
|
||||
µm.onPageLoadCompleted(pageURL);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var contentScriptLocalStorageHandler = function(pageURL) {
|
||||
var µmuri = µm.URI.set(pageURL);
|
||||
var response = µm.mustBlock(µm.scopeFromURL(pageURL), µmuri.hostname, 'cookie');
|
||||
µm.recordFromPageUrl(
|
||||
pageURL,
|
||||
'cookie',
|
||||
µmuri.rootURL() + '/{localStorage}',
|
||||
response
|
||||
);
|
||||
response = response && µm.userSettings.deleteLocalStorage;
|
||||
if ( response ) {
|
||||
µm.localStorageRemovedCounter++;
|
||||
}
|
||||
return response;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
var tabId = sender.tab.id;
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'contentScriptHasLocalStorage':
|
||||
response = contentScriptLocalStorageHandler(request.url);
|
||||
µm.updateBadgeAsync(tabId);
|
||||
break;
|
||||
|
||||
case 'contentScriptSummary':
|
||||
contentScriptSummaryHandler(tabId, request);
|
||||
µm.updateBadgeAsync(tabId);
|
||||
break;
|
||||
|
||||
case 'checkScriptBlacklisted':
|
||||
response = {
|
||||
scriptBlacklisted: µm.mustBlock(
|
||||
µm.scopeFromURL(request.url),
|
||||
µm.hostnameFromURL(request.url),
|
||||
'script'
|
||||
)
|
||||
};
|
||||
break;
|
||||
|
||||
case 'getUserAgentReplaceStr':
|
||||
response = µm.tMatrix.evaluateSwitchZ('ua-spoof', request.hostname) ?
|
||||
µm.userAgentReplaceStr :
|
||||
undefined;
|
||||
break;
|
||||
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
µMatrix.messaging.listen('contentscript-start.js', onMessage);
|
||||
µMatrix.messaging.listen('contentscript-end.js', onMessage);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// settings.js
|
||||
|
||||
(function() {
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
var µm = µMatrix;
|
||||
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
µMatrix.messaging.listen('settings.js', onMessage);
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// privacy.js
|
||||
|
||||
(function() {
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
var µm = µMatrix;
|
||||
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'getPrivacySettings':
|
||||
response = {
|
||||
userSettings: µm.userSettings,
|
||||
matrixSwitches: {
|
||||
'https-strict': µm.pMatrix.evaluateSwitch('https-strict', '*') === 1,
|
||||
'ua-spoof': µm.pMatrix.evaluateSwitch('ua-spoof', '*') === 1,
|
||||
'referrer-spoof': µm.pMatrix.evaluateSwitch('referrer-spoof', '*') === 1
|
||||
}
|
||||
};
|
||||
break;
|
||||
|
||||
case 'setMatrixSwitch':
|
||||
µm.tMatrix.setSwitch(request.switchName, '*', request.state);
|
||||
if ( µm.pMatrix.setSwitch(request.switchName, '*', request.state) ) {
|
||||
µm.saveMatrix();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
µMatrix.messaging.listen('privacy.js', onMessage);
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// user-rules.js
|
||||
|
||||
(function() {
|
||||
|
||||
var µm = µMatrix;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'getUserRules':
|
||||
response = {
|
||||
temporaryRules: µm.tMatrix.toString(),
|
||||
permanentRules: µm.pMatrix.toString()
|
||||
};
|
||||
break;
|
||||
|
||||
case 'setUserRules':
|
||||
if ( typeof request.temporaryRules === 'string' ) {
|
||||
µm.tMatrix.fromString(request.temporaryRules);
|
||||
}
|
||||
if ( typeof request.permanentRules === 'string' ) {
|
||||
µm.pMatrix.fromString(request.permanentRules);
|
||||
µm.saveMatrix();
|
||||
}
|
||||
response = {
|
||||
temporaryRules: µm.tMatrix.toString(),
|
||||
permanentRules: µm.pMatrix.toString()
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
µMatrix.messaging.listen('user-rules.js', onMessage);
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'purgeCache':
|
||||
µm.assets.purge(request.path);
|
||||
break;
|
||||
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
µMatrix.messaging.listen('hosts-files.js', onMessage);
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// info.js
|
||||
|
||||
(function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// map(pageURL) => array of request log entries
|
||||
|
||||
var getRequestLog = function(pageURL) {
|
||||
var requestLogs = {};
|
||||
var pageStores = µMatrix.pageStats;
|
||||
var pageURLs = pageURL ? [pageURL] : Object.keys(pageStores);
|
||||
var pageStore, pageRequestLog, logEntries, j, logEntry;
|
||||
|
||||
for ( var i = 0; i < pageURLs.length; i++ ) {
|
||||
pageURL = pageURLs[i];
|
||||
pageStore = pageStores[pageURL];
|
||||
if ( !pageStore ) {
|
||||
continue;
|
||||
}
|
||||
pageRequestLog = [];
|
||||
logEntries = pageStore.requests.getLoggedRequests();
|
||||
j = logEntries.length;
|
||||
while ( j-- ) {
|
||||
// rhill 2013-12-04: `logEntry` can be null since a ring buffer is
|
||||
// now used, and it might not have been filled yet.
|
||||
if ( logEntry = logEntries[j] ) {
|
||||
pageRequestLog.push(logEntry);
|
||||
}
|
||||
}
|
||||
requestLogs[pageURL] = pageRequestLog;
|
||||
}
|
||||
|
||||
return requestLogs;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var clearRequestLog = function(pageURL) {
|
||||
var pageStores = µMatrix.pageStats;
|
||||
var pageURLs = pageURL ? [pageURL] : Object.keys(pageStores);
|
||||
var pageStore;
|
||||
|
||||
for ( var i = 0; i < pageURLs.length; i++ ) {
|
||||
if ( pageStore = pageStores[pageURLs[i]] ) {
|
||||
pageStore.requests.clearLogBuffer();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
var µm = µMatrix;
|
||||
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'getPageURLs':
|
||||
response = {
|
||||
pageURLs: Object.keys(µm.pageUrlToTabId),
|
||||
behindTheSceneURL: µm.behindTheSceneURL
|
||||
};
|
||||
break;
|
||||
|
||||
case 'getStats':
|
||||
var pageStore = µm.pageStats[request.pageURL];
|
||||
response = {
|
||||
globalNetStats: µm.requestStats,
|
||||
pageNetStats: pageStore ? pageStore.requestStats : null,
|
||||
cookieHeaderFoiledCounter: µm.cookieHeaderFoiledCounter,
|
||||
refererHeaderFoiledCounter: µm.refererHeaderFoiledCounter,
|
||||
hyperlinkAuditingFoiledCounter: µm.hyperlinkAuditingFoiledCounter,
|
||||
cookieRemovedCounter: µm.cookieRemovedCounter,
|
||||
localStorageRemovedCounter: µm.localStorageRemovedCounter,
|
||||
browserCacheClearedCounter: µm.browserCacheClearedCounter
|
||||
};
|
||||
break;
|
||||
|
||||
case 'getRequestLogs':
|
||||
response = getRequestLog(request.pageURL);
|
||||
break;
|
||||
|
||||
case 'clearRequestLogs':
|
||||
clearRequestLog(request.pageURL);
|
||||
break;
|
||||
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
µMatrix.messaging.listen('info.js', onMessage);
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// about.js
|
||||
|
||||
(function() {
|
||||
|
||||
var µm = µMatrix;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var restoreUserData = function(userData) {
|
||||
var countdown = 3;
|
||||
var onCountdown = function() {
|
||||
countdown -= 1;
|
||||
if ( countdown === 0 ) {
|
||||
µm.XAL.restart();
|
||||
}
|
||||
};
|
||||
|
||||
var onAllRemoved = function() {
|
||||
// Be sure to adjust `countdown` if adding/removing anything below
|
||||
µm.XAL.keyvalSetMany(userData.settings, onCountdown);
|
||||
µm.XAL.keyvalSetOne('userMatrix', userData.rules, onCountdown);
|
||||
µm.XAL.keyvalSetOne('liveHostsFiles', userData.hostsFiles, onCountdown);
|
||||
};
|
||||
|
||||
// If we are going to restore all, might as well wipe out clean local
|
||||
// storage
|
||||
µm.XAL.keyvalRemoveAll(onAllRemoved);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var resetUserData = function() {
|
||||
var onAllRemoved = function() {
|
||||
µm.XAL.restart();
|
||||
};
|
||||
µm.XAL.keyvalRemoveAll(onAllRemoved);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'getAllUserData':
|
||||
response = {
|
||||
app: 'µMatrix',
|
||||
version: µm.manifest.version,
|
||||
when: Date.now(),
|
||||
settings: µm.userSettings,
|
||||
rules: µm.pMatrix.toString(),
|
||||
hostsFiles: µm.liveHostsFiles
|
||||
};
|
||||
break;
|
||||
|
||||
case 'getSomeStats':
|
||||
response = {
|
||||
version: µm.manifest.version,
|
||||
storageQuota: µm.storageQuota,
|
||||
storageUsed: µm.storageUsed
|
||||
};
|
||||
break;
|
||||
|
||||
case 'restoreAllUserData':
|
||||
restoreUserData(request.userData);
|
||||
break;
|
||||
|
||||
case 'resetAllUserData':
|
||||
resetUserData();
|
||||
break;
|
||||
|
||||
default:
|
||||
return µm.messaging.defaultHandler(request, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
µMatrix.messaging.listen('about.js', onMessage);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
1014
src/js/messaging.js
1014
src/js/messaging.js
File diff suppressed because it is too large
Load diff
|
@ -436,6 +436,8 @@ return {
|
|||
|
||||
µMatrix.PageStore = (function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var µm = µMatrix;
|
||||
|
@ -555,20 +557,16 @@ PageStore.prototype.recordRequest = function(type, url, block) {
|
|||
// notifying me, and this causes internal cached state to be out of sync.
|
||||
|
||||
PageStore.prototype.updateBadge = function(tabId) {
|
||||
// Icon
|
||||
var iconPath;
|
||||
var iconId = null;
|
||||
var badgeStr = '';
|
||||
var total = this.perLoadAllowedRequestCount + this.perLoadBlockedRequestCount;
|
||||
if ( total ) {
|
||||
var squareSize = 19;
|
||||
var greenSize = squareSize * Math.sqrt(this.perLoadAllowedRequestCount / total);
|
||||
greenSize = greenSize < squareSize/2 ? Math.ceil(greenSize) : Math.floor(greenSize);
|
||||
iconPath = 'img/browsericons/icon19-' + greenSize + '.png';
|
||||
iconId = greenSize < squareSize/2 ? Math.ceil(greenSize) : Math.floor(greenSize);
|
||||
badgeStr = µm.formatCount(this.distinctRequestCount);
|
||||
} else {
|
||||
iconPath = 'img/browsericons/icon19.png';
|
||||
}
|
||||
µm.XAL.setIcon(tabId, iconPath, badgeStr);
|
||||
vAPI.setIcon(tabId, iconId, badgeStr);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -577,6 +575,8 @@ return {
|
|||
factory: pageStoreFactory
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global punycode, uDom, messaging */
|
||||
/* global punycode, vAPI, uDom */
|
||||
/* jshint esnext: true, bitwise: false */
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -27,6 +27,8 @@
|
|||
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -71,8 +73,6 @@ var blacklistedHostnamesLabel = '';
|
|||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/345
|
||||
|
||||
messaging.start('popup.js');
|
||||
|
||||
var onMessage = function(msg) {
|
||||
if ( msg.what !== 'urlStatsChanged' ) {
|
||||
return;
|
||||
|
@ -83,7 +83,7 @@ var onMessage = function(msg) {
|
|||
queryMatrixSnapshot(makeMenu);
|
||||
};
|
||||
|
||||
messaging.listen(onMessage);
|
||||
var messager = vAPI.messaging.channel('popup.js', onMessage);
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
@ -94,7 +94,7 @@ function getUserSetting(setting) {
|
|||
|
||||
function setUserSetting(setting, value) {
|
||||
matrixSnapshot.userSettings[setting] = value;
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'userSettings',
|
||||
name: setting,
|
||||
value: value
|
||||
|
@ -405,7 +405,7 @@ function handleFilter(button, leaning) {
|
|||
desHostname: desHostname,
|
||||
type: type
|
||||
};
|
||||
messaging.ask(request, updateMatrixSnapshot);
|
||||
messager.send(request, updateMatrixSnapshot);
|
||||
}
|
||||
|
||||
function handleWhitelistFilter(button) {
|
||||
|
@ -950,7 +950,7 @@ function initMenuEnvironment() {
|
|||
while ( i-- ) {
|
||||
key = keys[i];
|
||||
cell = uDom('#matHead .matCell[data-req-type="'+ key +'"]');
|
||||
text = chrome.i18n.getMessage(key + 'PrettyName');
|
||||
text = vAPI.i18n(key + 'PrettyName');
|
||||
cell.text(text);
|
||||
prettyNames[key] = text;
|
||||
}
|
||||
|
@ -1043,7 +1043,7 @@ function toggleMatrixSwitch() {
|
|||
switchName: switchName,
|
||||
srcHostname: matrixSnapshot.scope
|
||||
};
|
||||
messaging.ask(request, updateMatrixSnapshot);
|
||||
messager.send(request, updateMatrixSnapshot);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -1068,7 +1068,7 @@ function persistMatrix() {
|
|||
what: 'applyDiffToPermanentMatrix',
|
||||
diff: matrixSnapshot.diff
|
||||
};
|
||||
messaging.ask(request, updateMatrixSnapshot);
|
||||
messager.send(request, updateMatrixSnapshot);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -1081,7 +1081,7 @@ function revertMatrix() {
|
|||
what: 'applyDiffToTemporaryMatrix',
|
||||
diff: matrixSnapshot.diff
|
||||
};
|
||||
messaging.ask(request, updateMatrixSnapshot);
|
||||
messager.send(request, updateMatrixSnapshot);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -1100,13 +1100,13 @@ function revertAll() {
|
|||
var request = {
|
||||
what: 'revertTemporaryMatrix'
|
||||
};
|
||||
messaging.ask(request, updateMatrixSnapshot);
|
||||
messager.send(request, updateMatrixSnapshot);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function buttonReloadHandler() {
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'forceReloadTab',
|
||||
tabId: targetTabId
|
||||
});
|
||||
|
@ -1125,9 +1125,9 @@ function mouseleaveMatrixCellHandler() {
|
|||
/******************************************************************************/
|
||||
|
||||
function gotoExtensionURL() {
|
||||
var url = this.getAttribute('data-extension-url');
|
||||
var url = uDom(this).attr('data-extension-url');
|
||||
if ( url ) {
|
||||
messaging.tell({ what: 'gotoExtensionURL', url: url });
|
||||
messager.send({ what: 'gotoExtensionURL', url: url });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1136,7 +1136,7 @@ function gotoExtensionURL() {
|
|||
function gotoExternalURL() {
|
||||
var url = this.getAttribute('data-external-url');
|
||||
if ( url ) {
|
||||
messaging.tell({ what: 'gotoURL', url: url });
|
||||
messager.send({ what: 'gotoURL', url: url });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1152,8 +1152,6 @@ function dropDownMenuHide() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Because chrome.tabs.query() is async
|
||||
|
||||
var onMatrixSnapshotReady = function(response) {
|
||||
// Now that tabId and pageURL are set, we can build our menu
|
||||
initMenuEnvironment();
|
||||
|
@ -1165,7 +1163,7 @@ var onMatrixSnapshotReady = function(response) {
|
|||
uDom('#toolbarLeft').remove();
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/191
|
||||
uDom('#noNetTrafficPrompt').text(chrome.i18n.getMessage('matrixNoNetTrafficPrompt'));
|
||||
uDom('#noNetTrafficPrompt').text(vAPI.i18n('matrixNoNetTrafficPrompt'));
|
||||
uDom('#noNetTrafficPrompt').css('display', '');
|
||||
}
|
||||
};
|
||||
|
@ -1183,20 +1181,7 @@ var queryMatrixSnapshot = function(callback) {
|
|||
matrixSnapshot = response;
|
||||
callback();
|
||||
};
|
||||
var onTabsReceived = function(tabs) {
|
||||
if ( tabs.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
var tab = tabs[0];
|
||||
request.tabId = targetTabId = tab.id;
|
||||
request.tabURL = tab.url;
|
||||
messaging.ask(request, snapshotReceived);
|
||||
};
|
||||
if ( targetTabId === undefined ) {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, onTabsReceived);
|
||||
} else {
|
||||
messaging.ask(request, snapshotReceived);
|
||||
}
|
||||
messager.send(request, snapshotReceived);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -19,22 +19,24 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global messaging, uDom */
|
||||
/* global vAPI, uDom */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
messaging.start('privacy.js');
|
||||
var messager = vAPI.messaging.channel('privacy.js');
|
||||
|
||||
var cachedPrivacySettings = {};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function changeUserSettings(name, value) {
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'userSettings',
|
||||
name: name,
|
||||
value: value
|
||||
|
@ -44,7 +46,7 @@ function changeUserSettings(name, value) {
|
|||
/******************************************************************************/
|
||||
|
||||
function changeMatrixSwitch(name, state) {
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'setMatrixSwitch',
|
||||
switchName: name,
|
||||
state: state
|
||||
|
@ -141,7 +143,7 @@ uDom.onLoad(function() {
|
|||
|
||||
installEventHandlers();
|
||||
};
|
||||
messaging.ask({ what: 'getPrivacySettings' }, onSettingsReceived);
|
||||
messager.send({ what: 'getPrivacySettings' }, onSettingsReceived);
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -19,16 +19,18 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global messaging, uDom */
|
||||
/* global vAPI, uDom */
|
||||
/* jshint multistr: true */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
messaging.start('settings.js');
|
||||
var messager = vAPI.messaging.channel('settings.js');
|
||||
|
||||
var cachedUserSettings = {};
|
||||
|
||||
|
@ -68,7 +70,7 @@ var onSubframeColorChanged = function() {
|
|||
/******************************************************************************/
|
||||
|
||||
function changeUserSettings(name, value) {
|
||||
messaging.tell({
|
||||
messager.send({
|
||||
what: 'userSettings',
|
||||
name: name,
|
||||
value: value
|
||||
|
@ -126,7 +128,7 @@ uDom.onLoad(function() {
|
|||
|
||||
installEventHandlers();
|
||||
};
|
||||
messaging.ask({ what: 'getUserSettings' }, onUserSettingsReceived);
|
||||
messager.send({ what: 'getUserSettings' }, onUserSettingsReceived);
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -43,85 +43,6 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function onTabCreated(tab) {
|
||||
// Can this happen?
|
||||
if ( tab.id < 0 || !tab.url || tab.url === '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/303
|
||||
// This takes care of rebinding the tab to the proper page store
|
||||
// when the user navigate back in his history.
|
||||
µMatrix.bindTabToPageStats(tab.id, tab.url);
|
||||
}
|
||||
|
||||
chrome.tabs.onCreated.addListener(onTabCreated);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function onTabUpdated(tabId, changeInfo, tab) {
|
||||
// Can this happen?
|
||||
if ( !tab.url || tab.url === '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/303
|
||||
// This takes care of rebinding the tab to the proper page store
|
||||
// when the user navigate back in his history.
|
||||
if ( changeInfo.url ) {
|
||||
µMatrix.bindTabToPageStats(tabId, tab.url, 'pageUpdated');
|
||||
}
|
||||
|
||||
// rhill 2013-12-23: Compute state after whole page is loaded. This is
|
||||
// better than building a state snapshot dynamically when requests are
|
||||
// recorded, because here we are not afflicted by the browser cache
|
||||
// mechanism.
|
||||
|
||||
// rhill 2014-03-05: Use tab id instead of page URL: this allows a
|
||||
// blocked page using µMatrix internal data URI-based page to be properly
|
||||
// unblocked when user un-blacklist the hostname.
|
||||
// https://github.com/gorhill/httpswitchboard/issues/198
|
||||
if ( changeInfo.status === 'complete' ) {
|
||||
var pageStats = µMatrix.pageStatsFromTabId(tabId);
|
||||
if ( pageStats ) {
|
||||
pageStats.state = µMatrix.computeTabState(tabId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chrome.tabs.onUpdated.addListener(onTabUpdated);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function onTabRemoved(tabId) {
|
||||
// Can this happen?
|
||||
if ( tabId < 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
µMatrix.unbindTabFromPageStats(tabId);
|
||||
}
|
||||
|
||||
chrome.tabs.onRemoved.addListener(onTabRemoved);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Bind a top URL to a specific tab
|
||||
|
||||
function onBeforeNavigateCallback(details) {
|
||||
// Don't bind to a subframe
|
||||
if ( details.frameId > 0 ) {
|
||||
return;
|
||||
}
|
||||
// console.debug('onBeforeNavigateCallback() > "%s" = %o', details.url, details);
|
||||
|
||||
µMatrix.bindTabToPageStats(details.tabId, details.url);
|
||||
}
|
||||
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigateCallback);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Browser data jobs
|
||||
|
||||
(function() {
|
||||
|
@ -136,8 +57,8 @@ chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigateCallback);
|
|||
}
|
||||
µm.clearBrowserCacheCycle = µm.userSettings.clearBrowserCacheAfter;
|
||||
µm.browserCacheClearedCounter++;
|
||||
chrome.browsingData.removeCache({ since: 0 });
|
||||
// console.debug('clearBrowserCacheCallback()> chrome.browsingData.removeCache() called');
|
||||
vAPI.browserCache.clearByTime(0);
|
||||
// console.debug('clearBrowserCacheCallback()> vAPI.browserCache.clearByTime() called');
|
||||
};
|
||||
|
||||
µMatrix.asyncJobs.add('clearBrowserCache', null, jobCallback, 15 * 60 * 1000, true);
|
||||
|
@ -177,13 +98,14 @@ chrome.webNavigation.onBeforeNavigate.addListener(onBeforeNavigateCallback);
|
|||
var i = tabs.length;
|
||||
// console.debug('start.js > binding %d tabs', i);
|
||||
while ( i-- ) {
|
||||
µm.tabContextManager.commit(tabs[i].id, tabs[i].url);
|
||||
µm.bindTabToPageStats(tabs[i].id, tabs[i].url);
|
||||
}
|
||||
µm.webRequest.start();
|
||||
};
|
||||
|
||||
var queryTabs = function() {
|
||||
chrome.tabs.query({ url: '<all_urls>' }, bindTabs);
|
||||
vAPI.tabs.getAll(bindTabs);
|
||||
};
|
||||
|
||||
µm.load(queryTabs);
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
var getBytesInUseHandler = function(bytesInUse) {
|
||||
µm.storageUsed = bytesInUse;
|
||||
};
|
||||
chrome.storage.local.getBytesInUse(null, getBytesInUseHandler);
|
||||
vAPI.storage.getBytesInUse(null, getBytesInUseHandler);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -71,7 +71,7 @@
|
|||
callback(µm.userSettings);
|
||||
};
|
||||
|
||||
chrome.storage.local.get(this.userSettings, settingsLoaded);
|
||||
vAPI.storage.get(this.userSettings, settingsLoaded);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -157,7 +157,7 @@
|
|||
}
|
||||
|
||||
// Now get user's selection of lists
|
||||
chrome.storage.local.get(
|
||||
vAPI.storage.get(
|
||||
{ 'liveHostsFiles': availableHostsFiles },
|
||||
onSelectedHostsFilesLoaded
|
||||
);
|
||||
|
@ -208,8 +208,8 @@
|
|||
|
||||
var loadHostsFilesEnd = function() {
|
||||
µm.ubiquitousBlacklist.freeze();
|
||||
chrome.storage.local.set({ 'liveHostsFiles': µm.liveHostsFiles });
|
||||
µm.messaging.announce({ what: 'loadHostsFilesCompleted' });
|
||||
vAPI.storage.set({ 'liveHostsFiles': µm.liveHostsFiles });
|
||||
vAPI.messaging.broadcast({ what: 'loadHostsFilesCompleted' });
|
||||
callback();
|
||||
};
|
||||
|
||||
|
@ -343,7 +343,7 @@
|
|||
}
|
||||
|
||||
// Save switch states
|
||||
chrome.storage.local.set(
|
||||
vAPI.storage.set(
|
||||
{ 'liveHostsFiles': liveHostsFiles },
|
||||
this.loadUpdatableAssets.bind(this, update)
|
||||
);
|
||||
|
|
489
src/js/tab.js
489
src/js/tab.js
|
@ -21,11 +21,407 @@
|
|||
|
||||
/* global chrome, µMatrix */
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var µm = µMatrix;
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/303
|
||||
// Some kind of trick going on here:
|
||||
// Any scheme other than 'http' and 'https' is remapped into a fake
|
||||
// URL which trick the rest of µMatrix into being able to process an
|
||||
// otherwise unmanageable scheme. µMatrix needs web page to have a proper
|
||||
// hostname to work properly, so just like the 'chromium-behind-the-scene'
|
||||
// fake domain name, we map unknown schemes into a fake '{scheme}-scheme'
|
||||
// hostname. This way, for a specific scheme you can create scope with
|
||||
// rules which will apply only to that scheme.
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
µm.normalizePageURL = function(tabId, pageURL) {
|
||||
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
|
||||
return 'http://behind-the-scene/';
|
||||
}
|
||||
var uri = this.URI.set(pageURL);
|
||||
var scheme = uri.scheme;
|
||||
if ( scheme === 'https' || scheme === 'http' ) {
|
||||
return uri.normalizedURI();
|
||||
}
|
||||
|
||||
var url = 'http://' + scheme + '-scheme/';
|
||||
|
||||
if ( uri.hostname !== '' ) {
|
||||
url += uri.hostname + '/';
|
||||
}
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************
|
||||
|
||||
To keep track from which context *exactly* network requests are made. This is
|
||||
often tricky for various reasons, and the challenge is not specific to one
|
||||
browser.
|
||||
|
||||
The time at which a URL is assigned to a tab and the time when a network
|
||||
request for a root document is made must be assumed to be unrelated: it's all
|
||||
asynchronous. There is no guaranteed order in which the two events are fired.
|
||||
|
||||
Also, other "anomalies" can occur:
|
||||
|
||||
- a network request for a root document is fired without the corresponding
|
||||
tab being really assigned a new URL
|
||||
<https://github.com/chrisaljoudi/uBlock/issues/516>
|
||||
|
||||
- a network request for a secondary resource is labeled with a tab id for
|
||||
which no root document was pulled for that tab.
|
||||
<https://github.com/chrisaljoudi/uBlock/issues/1001>
|
||||
|
||||
- a network request for a secondary resource is made without the root
|
||||
document to which it belongs being formally bound yet to the proper tab id,
|
||||
causing a bad scope to be used for filtering purpose.
|
||||
<https://github.com/chrisaljoudi/uBlock/issues/1205>
|
||||
<https://github.com/chrisaljoudi/uBlock/issues/1140>
|
||||
|
||||
So the solution here is to keep a lightweight data structure which only
|
||||
purpose is to keep track as accurately as possible of which root document
|
||||
belongs to which tab. That's the only purpose, and because of this, there are
|
||||
no restrictions for when the URL of a root document can be associated to a tab.
|
||||
|
||||
Before, the PageStore object was trying to deal with this, but it had to
|
||||
enforce some restrictions so as to not descend into one of the above issues, or
|
||||
other issues. The PageStore object can only be associated with a tab for which
|
||||
a definitive navigation event occurred, because it collects information about
|
||||
what occurred in the tab (for example, the number of requests blocked for a
|
||||
page).
|
||||
|
||||
The TabContext objects do not suffer this restriction, and as a result they
|
||||
offer the most reliable picture of which root document URL is really associated
|
||||
to which tab. Moreover, the TabObject can undo an association from a root
|
||||
document, and automatically re-associate with the next most recent. This takes
|
||||
care of <https://github.com/chrisaljoudi/uBlock/issues/516>.
|
||||
|
||||
The PageStore object no longer cache the various information about which
|
||||
root document it is currently bound. When it needs to find out, it will always
|
||||
defer to the TabContext object, which will provide the real answer. This takes
|
||||
case of <https://github.com/chrisaljoudi/uBlock/issues/1205>. In effect, the
|
||||
master switch and dynamic filtering rules can be evaluated now properly even
|
||||
in the absence of a PageStore object, this was not the case before.
|
||||
|
||||
Also, the TabContext object will try its best to find a good candidate root
|
||||
document URL for when none exists. This takes care of
|
||||
<https://github.com/chrisaljoudi/uBlock/issues/1001>.
|
||||
|
||||
The TabContext manager is self-contained, and it takes care to properly
|
||||
housekeep itself.
|
||||
|
||||
*/
|
||||
|
||||
µm.tabContextManager = (function() {
|
||||
var tabContexts = Object.create(null);
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1001
|
||||
// This is to be used as last-resort fallback in case a tab is found to not
|
||||
// be bound while network requests are fired for the tab.
|
||||
var mostRecentRootDocURL = '';
|
||||
var mostRecentRootDocURLTimestamp = 0;
|
||||
|
||||
var gcPeriod = 10 * 60 * 1000;
|
||||
|
||||
var TabContext = function(tabId) {
|
||||
this.tabId = tabId;
|
||||
this.stack = [];
|
||||
this.rawURL =
|
||||
this.normalURL =
|
||||
this.rootHostname =
|
||||
this.rootDomain = '';
|
||||
this.timer = null;
|
||||
this.onTabCallback = null;
|
||||
this.onTimerCallback = null;
|
||||
|
||||
tabContexts[tabId] = this;
|
||||
};
|
||||
|
||||
TabContext.prototype.destroy = function() {
|
||||
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
|
||||
return;
|
||||
}
|
||||
if ( this.timer !== null ) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
delete tabContexts[this.tabId];
|
||||
};
|
||||
|
||||
TabContext.prototype.onTab = function(tab) {
|
||||
if ( tab ) {
|
||||
this.timer = setTimeout(this.onTimerCallback, gcPeriod);
|
||||
} else {
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
TabContext.prototype.onTimer = function() {
|
||||
this.timer = null;
|
||||
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
|
||||
return;
|
||||
}
|
||||
vAPI.tabs.get(this.tabId, this.onTabCallback);
|
||||
};
|
||||
|
||||
// This takes care of orphanized tab contexts. Can't be started for all
|
||||
// contexts, as the behind-the-scene context is permanent -- so we do not
|
||||
// want to slush it.
|
||||
TabContext.prototype.autodestroy = function() {
|
||||
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
|
||||
return;
|
||||
}
|
||||
this.onTabCallback = this.onTab.bind(this);
|
||||
this.onTimerCallback = this.onTimer.bind(this);
|
||||
this.timer = setTimeout(this.onTimerCallback, gcPeriod);
|
||||
};
|
||||
|
||||
// Update just force all properties to be updated to match the most current
|
||||
// root URL.
|
||||
TabContext.prototype.update = function() {
|
||||
if ( this.stack.length === 0 ) {
|
||||
this.rawURL = this.normalURL = this.rootHostname = this.rootDomain = '';
|
||||
} else {
|
||||
this.rawURL = this.stack[this.stack.length - 1];
|
||||
this.normalURL = µm.normalizePageURL(this.tabId, this.rawURL);
|
||||
this.rootHostname = µm.URI.hostnameFromURI(this.normalURL);
|
||||
this.rootDomain = µm.URI.domainFromHostname(this.rootHostname);
|
||||
}
|
||||
};
|
||||
|
||||
// Called whenever a candidate root URL is spotted for the tab.
|
||||
TabContext.prototype.push = function(url) {
|
||||
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
|
||||
return;
|
||||
}
|
||||
this.stack.push(url);
|
||||
this.update();
|
||||
};
|
||||
|
||||
// Called when a former push is a false positive:
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/516
|
||||
TabContext.prototype.unpush = function(url) {
|
||||
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
|
||||
return;
|
||||
}
|
||||
// We are not going to unpush if there is no other candidate, the
|
||||
// point of unpush is to make space for a better candidate.
|
||||
if ( this.stack.length === 1 ) {
|
||||
return;
|
||||
}
|
||||
var pos = this.stack.indexOf(url);
|
||||
if ( pos === -1 ) {
|
||||
return;
|
||||
}
|
||||
this.stack.splice(pos, 1);
|
||||
if ( this.stack.length === 0 ) {
|
||||
this.destroy();
|
||||
return;
|
||||
}
|
||||
if ( pos !== this.stack.length ) {
|
||||
return;
|
||||
}
|
||||
this.update();
|
||||
};
|
||||
|
||||
// This tells that the url is definitely the one to be associated with the
|
||||
// tab, there is no longer any ambiguity about which root URL is really
|
||||
// sitting in which tab.
|
||||
TabContext.prototype.commit = function(url) {
|
||||
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
|
||||
return;
|
||||
}
|
||||
this.stack = [url];
|
||||
this.update();
|
||||
};
|
||||
|
||||
// These are to be used for the API of the tab context manager.
|
||||
|
||||
var push = function(tabId, url) {
|
||||
var entry = tabContexts[tabId];
|
||||
if ( entry === undefined ) {
|
||||
entry = new TabContext(tabId);
|
||||
entry.autodestroy();
|
||||
}
|
||||
entry.push(url);
|
||||
mostRecentRootDocURL = url;
|
||||
mostRecentRootDocURLTimestamp = Date.now();
|
||||
return entry;
|
||||
};
|
||||
|
||||
// Find a tab context for a specific tab. If none is found, attempt to
|
||||
// fix this. When all fail, the behind-the-scene context is returned.
|
||||
var lookup = function(tabId, url) {
|
||||
var entry;
|
||||
if ( url !== undefined ) {
|
||||
entry = push(tabId, url);
|
||||
} else {
|
||||
entry = tabContexts[tabId];
|
||||
}
|
||||
if ( entry !== undefined ) {
|
||||
return entry;
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1025
|
||||
// Google Hangout popup opens without a root frame. So for now we will
|
||||
// just discard that best-guess root frame if it is too far in the
|
||||
// future, at which point it ceases to be a "best guess".
|
||||
if ( mostRecentRootDocURL !== '' && mostRecentRootDocURLTimestamp + 500 < Date.now() ) {
|
||||
mostRecentRootDocURL = '';
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1001
|
||||
// Not a behind-the-scene request, yet no page store found for the
|
||||
// tab id: we will thus bind the last-seen root document to the
|
||||
// unbound tab. It's a guess, but better than ending up filtering
|
||||
// nothing at all.
|
||||
if ( mostRecentRootDocURL !== '' ) {
|
||||
return push(tabId, mostRecentRootDocURL);
|
||||
}
|
||||
// If all else fail at finding a page store, re-categorize the
|
||||
// request as behind-the-scene. At least this ensures that ultimately
|
||||
// the user can still inspect/filter those net requests which were
|
||||
// about to fall through the cracks.
|
||||
// Example: Chromium + case #12 at
|
||||
// http://raymondhill.net/ublock/popup.html
|
||||
return tabContexts[vAPI.noTabId];
|
||||
};
|
||||
|
||||
var commit = function(tabId, url) {
|
||||
var entry = tabContexts[tabId];
|
||||
if ( entry === undefined ) {
|
||||
entry = push(tabId, url);
|
||||
} else {
|
||||
entry.commit(url);
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
|
||||
var unpush = function(tabId, url) {
|
||||
var entry = tabContexts[tabId];
|
||||
if ( entry !== undefined ) {
|
||||
entry.unpush(url);
|
||||
}
|
||||
};
|
||||
|
||||
var exists = function(tabId) {
|
||||
return tabContexts[tabId] !== undefined;
|
||||
};
|
||||
|
||||
// Behind-the-scene tab context
|
||||
(function() {
|
||||
var entry = new TabContext(vAPI.noTabId);
|
||||
entry.stack.push('');
|
||||
entry.rawURL = '';
|
||||
entry.normalURL = µm.normalizePageURL(entry.tabId);
|
||||
entry.rootHostname = µm.URI.hostnameFromURI(entry.normalURL);
|
||||
entry.rootDomain = µm.URI.domainFromHostname(entry.rootHostname);
|
||||
})();
|
||||
|
||||
// Context object, typically to be used to feed filtering engines.
|
||||
var Context = function(tabId) {
|
||||
var tabContext = lookup(tabId);
|
||||
this.rootHostname = tabContext.rootHostname;
|
||||
this.rootDomain = tabContext.rootDomain;
|
||||
this.pageHostname =
|
||||
this.pageDomain =
|
||||
this.requestURL =
|
||||
this.requestHostname =
|
||||
this.requestDomain = '';
|
||||
};
|
||||
|
||||
var createContext = function(tabId) {
|
||||
return new Context(tabId);
|
||||
};
|
||||
|
||||
return {
|
||||
push: push,
|
||||
unpush: unpush,
|
||||
commit: commit,
|
||||
lookup: lookup,
|
||||
exists: exists,
|
||||
createContext: createContext
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// When the DOM content of root frame is loaded, this means the tab
|
||||
// content has changed.
|
||||
|
||||
vAPI.tabs.onNavigation = function(details) {
|
||||
if ( details.frameId !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var tabContext = µm.tabContextManager.commit(details.tabId, details.url);
|
||||
var pageStore = µm.bindTabToPageStats(details.tabId, 'afterNavigate');
|
||||
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// It may happen the URL in the tab changes, while the page's document
|
||||
// stays the same (for instance, Google Maps). Without this listener,
|
||||
// the extension icon won't be properly refreshed.
|
||||
|
||||
vAPI.tabs.onUpdated = function(tabId, changeInfo, tab) {
|
||||
if ( !tab.url || tab.url === '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( changeInfo.url ) {
|
||||
µm.tabContextManager.commit(tabId, changeInfo.url);
|
||||
µm.bindTabToPageStats(tabId, 'tabUpdated');
|
||||
}
|
||||
|
||||
// rhill 2013-12-23: Compute state after whole page is loaded. This is
|
||||
// better than building a state snapshot dynamically when requests are
|
||||
// recorded, because here we are not afflicted by the browser cache
|
||||
// mechanism.
|
||||
|
||||
// rhill 2014-03-05: Use tab id instead of page URL: this allows a
|
||||
// blocked page using µMatrix internal data URI-based page to be properly
|
||||
// unblocked when user un-blacklist the hostname.
|
||||
// https://github.com/gorhill/httpswitchboard/issues/198
|
||||
if ( changeInfo.status === 'complete' ) {
|
||||
var pageStats = µm.pageStatsFromTabId(tabId);
|
||||
if ( pageStats ) {
|
||||
pageStats.state = µm.computeTabState(tabId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.tabs.onClosed = function(tabId) {
|
||||
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
|
||||
return;
|
||||
}
|
||||
µm.unbindTabFromPageStats(tabId);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.tabs.registerListeners();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// Create a new page url stats store (if not already present)
|
||||
|
||||
µMatrix.createPageStore = function(pageURL) {
|
||||
µm.createPageStore = function(pageURL) {
|
||||
// https://github.com/gorhill/httpswitchboard/issues/303
|
||||
// At this point, the URL has been page-URL-normalized
|
||||
|
||||
|
@ -57,46 +453,31 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/303
|
||||
// Some kind of trick going on here:
|
||||
// Any scheme other than 'http' and 'https' is remapped into a fake
|
||||
// URL which trick the rest of µMatrix into being able to process an
|
||||
// otherwise unmanageable scheme. µMatrix needs web pages to have a proper
|
||||
// hostname to work properly, so just like the 'chromium-behind-the-scene'
|
||||
// fake domain name, we map unknown schemes into a fake '{scheme}-scheme'
|
||||
// hostname. This way, for a specific scheme you can create scope with
|
||||
// rules which will apply only to that scheme.
|
||||
|
||||
µMatrix.normalizePageURL = function(pageURL) {
|
||||
var uri = this.URI.set(pageURL);
|
||||
if ( uri.scheme === 'https' || uri.scheme === 'http' ) {
|
||||
return uri.normalizedURI();
|
||||
}
|
||||
// If it is a scheme-based page URL, it is important it is crafted as a
|
||||
// normalized URL just like above.
|
||||
if ( uri.scheme !== '' ) {
|
||||
return 'http://' + uri.scheme + '-scheme/';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Create an entry for the tab if it doesn't exist
|
||||
|
||||
µMatrix.bindTabToPageStats = function(tabId, pageURL, context) {
|
||||
µm.bindTabToPageStats = function(tabId, context) {
|
||||
if ( vAPI.isBehindTheSceneTabId(tabId) === false ) {
|
||||
this.updateBadgeAsync(tabId);
|
||||
}
|
||||
|
||||
// Do not create a page store for URLs which are of no interests
|
||||
if ( µm.tabContextManager.exists(tabId) === false ) {
|
||||
this.unbindTabFromPageStats(tabId);
|
||||
return null;
|
||||
}
|
||||
|
||||
var tabContext = µm.tabContextManager.lookup(tabId);
|
||||
var rawURL = tabContext.rawURL;
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/303
|
||||
// Don't rebind pages blocked by µMatrix.
|
||||
var blockedRootFramePrefix = this.webRequest.blockedRootFramePrefix;
|
||||
if ( pageURL.slice(0, blockedRootFramePrefix.length) === blockedRootFramePrefix ) {
|
||||
if ( rawURL.lastIndexOf(blockedRootFramePrefix, 0) === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var pageStore;
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/303
|
||||
// Normalize to a page-URL.
|
||||
pageURL = this.normalizePageURL(pageURL);
|
||||
var pageURL = tabContext.normalURL;
|
||||
|
||||
// The previous page URL, if any, associated with the tab
|
||||
if ( this.tabIdToPageUrl.hasOwnProperty(tabId) ) {
|
||||
|
@ -159,7 +540,7 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µMatrix.unbindTabFromPageStats = function(tabId) {
|
||||
µm.unbindTabFromPageStats = function(tabId) {
|
||||
if ( this.tabIdToPageUrl.hasOwnProperty(tabId) === false ) {
|
||||
return;
|
||||
}
|
||||
|
@ -179,7 +560,7 @@
|
|||
|
||||
// Log a request
|
||||
|
||||
µMatrix.recordFromTabId = function(tabId, type, url, blocked) {
|
||||
µm.recordFromTabId = function(tabId, type, url, blocked) {
|
||||
var pageStats = this.pageStatsFromTabId(tabId);
|
||||
if ( pageStats ) {
|
||||
pageStats.recordRequest(type, url, blocked);
|
||||
|
@ -187,7 +568,7 @@
|
|||
}
|
||||
};
|
||||
|
||||
µMatrix.recordFromPageUrl = function(pageUrl, type, url, blocked, reason) {
|
||||
µm.recordFromPageUrl = function(pageUrl, type, url, blocked, reason) {
|
||||
var pageStats = this.pageStatsFromPageUrl(pageUrl);
|
||||
if ( pageStats ) {
|
||||
pageStats.recordRequest(type, url, blocked, reason);
|
||||
|
@ -196,7 +577,7 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µMatrix.onPageLoadCompleted = function(pageURL) {
|
||||
µm.onPageLoadCompleted = function(pageURL) {
|
||||
var pageStats = this.pageStatsFromPageUrl(pageURL);
|
||||
if ( !pageStats ) {
|
||||
return;
|
||||
|
@ -210,9 +591,9 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Reload content of a tabs.
|
||||
// Reload content of one or more tabs.
|
||||
|
||||
µMatrix.smartReloadTabs = function(which, tabId) {
|
||||
µm.smartReloadTabs = function(which, tabId) {
|
||||
if ( which === 'none' ) {
|
||||
return;
|
||||
}
|
||||
|
@ -224,7 +605,6 @@
|
|||
|
||||
// which === 'all'
|
||||
var reloadTabs = function(chromeTabs) {
|
||||
var µm = µMatrix;
|
||||
var tabId;
|
||||
var i = chromeTabs.length;
|
||||
while ( i-- ) {
|
||||
|
@ -236,7 +616,7 @@
|
|||
};
|
||||
|
||||
var getTabs = function() {
|
||||
chrome.tabs.query({ status: 'complete' }, reloadTabs);
|
||||
vAPI.tabs.getAll(reloadTabs);
|
||||
};
|
||||
|
||||
this.asyncJobs.add('smartReloadTabs', null, getTabs, 500);
|
||||
|
@ -246,7 +626,7 @@
|
|||
|
||||
// Reload content of a tab
|
||||
|
||||
µMatrix.smartReloadTab = function(tabId) {
|
||||
µm.smartReloadTab = function(tabId) {
|
||||
var pageStats = this.pageStatsFromTabId(tabId);
|
||||
if ( !pageStats ) {
|
||||
//console.error('HTTP Switchboard> µMatrix.smartReloadTab(): page stats for tab id %d not found', tabId);
|
||||
|
@ -304,7 +684,7 @@
|
|||
// console.log('old state: %o\nnew state: %o', oldState, newState);
|
||||
|
||||
if ( mustReload ) {
|
||||
chrome.tabs.reload(tabId);
|
||||
vAPI.tabs.reload(tabId);
|
||||
}
|
||||
// pageStats.state = newState;
|
||||
};
|
||||
|
@ -317,13 +697,13 @@
|
|||
// `chrome-devtools://devtools/devtools.html`
|
||||
// etc.
|
||||
|
||||
µMatrix.tabExists = function(tabId) {
|
||||
µm.tabExists = function(tabId) {
|
||||
return !!this.pageUrlFromTabId(tabId);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µMatrix.computeTabState = function(tabId) {
|
||||
µm.computeTabState = function(tabId) {
|
||||
var pageStats = this.pageStatsFromTabId(tabId);
|
||||
if ( !pageStats ) {
|
||||
//console.error('tab.js > µMatrix.computeTabState(): page stats for tab id %d not found', tabId);
|
||||
|
@ -358,18 +738,18 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µMatrix.pageUrlFromTabId = function(tabId) {
|
||||
µm.pageUrlFromTabId = function(tabId) {
|
||||
return this.tabIdToPageUrl[tabId];
|
||||
};
|
||||
|
||||
µMatrix.pageUrlFromPageStats = function(pageStats) {
|
||||
µm.pageUrlFromPageStats = function(pageStats) {
|
||||
if ( pageStats ) {
|
||||
return pageStats.pageUrl;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
µMatrix.pageStatsFromTabId = function(tabId) {
|
||||
µm.pageStatsFromTabId = function(tabId) {
|
||||
var pageUrl = this.tabIdToPageUrl[tabId];
|
||||
if ( pageUrl ) {
|
||||
return this.pageStats[pageUrl];
|
||||
|
@ -377,7 +757,7 @@
|
|||
return undefined;
|
||||
};
|
||||
|
||||
µMatrix.pageStatsFromPageUrl = function(pageURL) {
|
||||
µm.pageStatsFromPageUrl = function(pageURL) {
|
||||
if ( pageURL ) {
|
||||
return this.pageStats[this.normalizePageURL(pageURL)];
|
||||
}
|
||||
|
@ -386,7 +766,7 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µMatrix.resizeLogBuffers = function(size) {
|
||||
µm.resizeLogBuffers = function(size) {
|
||||
var pageStores = this.pageStats;
|
||||
for ( var pageURL in pageStores ) {
|
||||
if ( pageStores.hasOwnProperty(pageURL) ) {
|
||||
|
@ -397,15 +777,14 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µMatrix.forceReload = function(tabId) {
|
||||
chrome.tabs.reload(tabId, { bypassCache: true });
|
||||
µm.forceReload = function(tabId) {
|
||||
vAPI.tabs.reload(tabId, { bypassCache: true });
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Garbage collect stale url stats entries
|
||||
(function() {
|
||||
var µm = µMatrix;
|
||||
var gcPageStats = function() {
|
||||
var pageStore;
|
||||
var now = Date.now();
|
||||
|
@ -447,7 +826,7 @@
|
|||
|
||||
// Time somewhat arbitrary: If a web page has not been in a tab
|
||||
// for some time minutes, flush its stats.
|
||||
µMatrix.asyncJobs.add(
|
||||
µm.asyncJobs.add(
|
||||
'gcPageStats',
|
||||
null,
|
||||
gcPageStats,
|
||||
|
@ -455,3 +834,7 @@
|
|||
true
|
||||
);
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
|
|
@ -197,15 +197,15 @@ var onBeforeChromeExtensionRequestHandler = function(details) {
|
|||
|
||||
var onBeforeRootFrameRequestHandler = function(details) {
|
||||
var µm = µMatrix;
|
||||
|
||||
// Do not ignore traffic outside tabs
|
||||
var requestURL = details.url;
|
||||
var tabId = details.tabId;
|
||||
if ( tabId < 0 ) {
|
||||
|
||||
µm.tabContextManager.push(tabId, requestURL);
|
||||
|
||||
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
|
||||
tabId = µm.behindTheSceneTabId;
|
||||
}
|
||||
// It's a root frame, bind to a new page store
|
||||
else {
|
||||
µm.bindTabToPageStats(tabId, details.url);
|
||||
} else {
|
||||
µm.bindTabToPageStats(tabId);
|
||||
}
|
||||
|
||||
var uri = µm.URI.set(details.url);
|
||||
|
@ -213,7 +213,6 @@ var onBeforeRootFrameRequestHandler = function(details) {
|
|||
return;
|
||||
}
|
||||
|
||||
var requestURL = uri.normalizedURI();
|
||||
var requestHostname = uri.hostname;
|
||||
var pageStore = µm.pageStatsFromTabId(tabId);
|
||||
|
||||
|
@ -730,10 +729,6 @@ var onSubDocHeadersReceived = function(details) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// As per Chrome API doc, webRequest.onErrorOccurred event is the last
|
||||
// one called in the sequence of webRequest events.
|
||||
// http://developer.chrome.com/extensions/webRequest.html
|
||||
|
||||
var onErrorOccurredHandler = function(details) {
|
||||
// console.debug('onErrorOccurred()> "%s": %o', details.url, details);
|
||||
var requestType = requestTypeNormalizer[details.type];
|
||||
|
@ -798,68 +793,54 @@ var requestTypeNormalizer = {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.net.onBeforeRequest = {
|
||||
urls: [
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"chrome-extension://*/*"
|
||||
],
|
||||
extra: [ 'blocking' ],
|
||||
callback: onBeforeRequestHandler
|
||||
};
|
||||
|
||||
vAPI.net.onBeforeSendHeaders = {
|
||||
urls: [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
],
|
||||
types: [
|
||||
"main_frame",
|
||||
"sub_frame"
|
||||
],
|
||||
extra: [ 'blocking', 'requestHeaders' ],
|
||||
callback: onBeforeSendHeadersHandler
|
||||
};
|
||||
|
||||
vAPI.net.onHeadersReceived = {
|
||||
urls: [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
],
|
||||
types: [
|
||||
"main_frame",
|
||||
"sub_frame"
|
||||
],
|
||||
extra: [ 'blocking', 'responseHeaders' ],
|
||||
callback: onHeadersReceived
|
||||
};
|
||||
|
||||
vAPI.net.onErrorOccurred = {
|
||||
urls: [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
],
|
||||
callback: onErrorOccurredHandler
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var start = function() {
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
//function(details) {
|
||||
// quickProfiler.start('onBeforeRequest');
|
||||
// var r = onBeforeRequestHandler(details);
|
||||
// quickProfiler.stop();
|
||||
// return r;
|
||||
//},
|
||||
onBeforeRequestHandler,
|
||||
{
|
||||
"urls": [
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"chrome-extension://*/*"
|
||||
],
|
||||
"types": [
|
||||
"main_frame",
|
||||
"sub_frame",
|
||||
'stylesheet',
|
||||
"script",
|
||||
"image",
|
||||
"object",
|
||||
"xmlhttprequest",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
[ "blocking" ]
|
||||
);
|
||||
|
||||
//console.log('µMatrix > Beginning to intercept net requests at %s', (new Date()).toISOString());
|
||||
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||
onBeforeSendHeadersHandler,
|
||||
{
|
||||
'urls': [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
]
|
||||
},
|
||||
['blocking', 'requestHeaders']
|
||||
);
|
||||
|
||||
chrome.webRequest.onHeadersReceived.addListener(
|
||||
onHeadersReceived,
|
||||
{
|
||||
'urls': [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
]
|
||||
},
|
||||
['blocking', 'responseHeaders']
|
||||
);
|
||||
|
||||
chrome.webRequest.onErrorOccurred.addListener(
|
||||
onErrorOccurredHandler,
|
||||
{
|
||||
'urls': [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
]
|
||||
}
|
||||
);
|
||||
vAPI.net.registerListeners();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
µBlock - a Chromium browser extension to block requests.
|
||||
µBlock - a browser extension to block requests.
|
||||
Copyright (C) 2014 Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
@ -19,7 +19,9 @@
|
|||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
/* global DOMTokenList */
|
||||
/* exported uDom */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// It's just a silly, minimalist DOM framework: this allows me to not rely
|
||||
|
@ -30,6 +32,8 @@
|
|||
|
||||
var uDom = (function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var DOMList = function() {
|
||||
|
@ -136,7 +140,7 @@ var addHTMLToList = function(list, html) {
|
|||
var cTag = matches[1];
|
||||
var pTag = pTagOfChildTag[cTag] || 'div';
|
||||
var p = document.createElement(pTag);
|
||||
p.innerHTML = html;
|
||||
vAPI.insertHTML(p, html);
|
||||
// Find real parent
|
||||
var c = p.querySelector(cTag);
|
||||
p = c.parentNode;
|
||||
|
@ -222,6 +226,12 @@ DOMList.prototype.toArray = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
DOMList.prototype.pop = function() {
|
||||
return addNodeToList(new DOMList(), this.nodes.pop());
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
DOMList.prototype.forEach = function(fn) {
|
||||
var n = this.nodes.length;
|
||||
for ( var i = 0; i < n; i++ ) {
|
||||
|
@ -479,6 +489,28 @@ DOMList.prototype.clone = function(notDeep) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
DOMList.prototype.nthOfType = function() {
|
||||
if ( this.nodes.length === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
var node = this.nodes[0];
|
||||
var tagName = node.tagName;
|
||||
var i = 1;
|
||||
while ( node.previousElementSibling !== null ) {
|
||||
node = node.previousElementSibling;
|
||||
if ( typeof node.tagName !== 'string' ) {
|
||||
continue;
|
||||
}
|
||||
if ( node.tagName !== tagName ) {
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
DOMList.prototype.attr = function(attr, value) {
|
||||
var i = this.nodes.length;
|
||||
if ( value === undefined && typeof attr !== 'object' ) {
|
||||
|
@ -543,7 +575,7 @@ DOMList.prototype.html = function(html) {
|
|||
return i ? this.nodes[0].innerHTML : '';
|
||||
}
|
||||
while ( i-- ) {
|
||||
this.nodes[i].innerHTML = html;
|
||||
vAPI.insertHTML(this.nodes[i], html);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
@ -637,6 +669,24 @@ DOMList.prototype.toggleClasses = function(classNames, targetState) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var listenerEntries = [];
|
||||
|
||||
var ListenerEntry = function(target, type, capture, callback) {
|
||||
this.target = target;
|
||||
this.type = type;
|
||||
this.capture = capture;
|
||||
this.callback = callback;
|
||||
target.addEventListener(type, callback, capture);
|
||||
};
|
||||
|
||||
ListenerEntry.prototype.dispose = function() {
|
||||
this.target.removeEventListener(this.type, this.callback, this.capture);
|
||||
this.target = null;
|
||||
this.callback = null;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var makeEventHandler = function(selector, callback) {
|
||||
return function(event) {
|
||||
var dispatcher = event.currentTarget;
|
||||
|
@ -660,7 +710,7 @@ DOMList.prototype.on = function(etype, selector, callback) {
|
|||
|
||||
var i = this.nodes.length;
|
||||
while ( i-- ) {
|
||||
this.nodes[i].addEventListener(etype, callback, selector !== undefined);
|
||||
listenerEntries.push(new ListenerEntry(this.nodes[i], etype, selector !== undefined, callback));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
@ -691,6 +741,20 @@ DOMList.prototype.trigger = function(etype) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Cleanup
|
||||
|
||||
var onBeforeUnload = function() {
|
||||
var entry;
|
||||
while ( entry = listenerEntries.pop() ) {
|
||||
entry.dispose();
|
||||
}
|
||||
window.removeEventListener('beforeunload', onBeforeUnload);
|
||||
};
|
||||
|
||||
window.addEventListener('beforeunload', onBeforeUnload);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
return DOMListFactory;
|
||||
|
||||
})();
|
||||
|
|
|
@ -31,10 +31,10 @@ Naming convention from https://en.wikipedia.org/wiki/URI_scheme#Examples
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// This will inserted as a module in the µMatrix object.
|
||||
|
||||
µMatrix.URI = (function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Favorite regex tool: http://regex101.com/
|
||||
|
@ -49,6 +49,7 @@ var reRFC3986 = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#]*)(\?[^#]*)?(#.*)?/;
|
|||
// Derived
|
||||
var reSchemeFromURI = /^[^:\/?#]+:/;
|
||||
var reAuthorityFromURI = /^(?:[^:\/?#]+:)?(\/\/[^\/?#]+)/;
|
||||
var reCommonHostnameFromURL = /^https?:\/\/([0-9a-z_][0-9a-z._-]*[0-9a-z])\//;
|
||||
|
||||
// These are to parse authority field, not parsed by above official regex
|
||||
// IPv6 is seen as an exception: a non-compatible IPv6 is first tried, and
|
||||
|
@ -248,7 +249,11 @@ URI.authorityFromURI = function(uri) {
|
|||
// The most used function, so it better be fast.
|
||||
|
||||
URI.hostnameFromURI = function(uri) {
|
||||
var matches = reAuthorityFromURI.exec(uri);
|
||||
var matches = reCommonHostnameFromURL.exec(uri);
|
||||
if ( matches ) {
|
||||
return matches[1];
|
||||
}
|
||||
matches = reAuthorityFromURI.exec(uri);
|
||||
if ( !matches ) {
|
||||
return '';
|
||||
}
|
||||
|
@ -274,21 +279,98 @@ URI.hostnameFromURI = function(uri) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// It is expected that there is higher-scoped `publicSuffixList` lingering
|
||||
// somewhere. Cache it. See <https://github.com/gorhill/publicsuffixlist.js>.
|
||||
var psl = publicSuffixList;
|
||||
|
||||
URI.domainFromHostname = function(hostname) {
|
||||
if ( !reIPAddressNaive.test(hostname) ) {
|
||||
return psl.getDomain(hostname);
|
||||
// Try to skip looking up the PSL database
|
||||
if ( domainCache.hasOwnProperty(hostname) ) {
|
||||
var entry = domainCache[hostname];
|
||||
entry.tstamp = Date.now();
|
||||
return entry.domain;
|
||||
}
|
||||
return hostname;
|
||||
// Meh.. will have to search it
|
||||
if ( reIPAddressNaive.test(hostname) === false ) {
|
||||
return domainCacheAdd(hostname, psl.getDomain(hostname));
|
||||
}
|
||||
return domainCacheAdd(hostname, hostname);
|
||||
};
|
||||
|
||||
URI.domain = function() {
|
||||
return this.domainFromHostname(this.hostname);
|
||||
};
|
||||
|
||||
// It is expected that there is higher-scoped `publicSuffixList` lingering
|
||||
// somewhere. Cache it. See <https://github.com/gorhill/publicsuffixlist.js>.
|
||||
var psl = publicSuffixList;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Trying to alleviate the worries of looking up too often the domain name from
|
||||
// a hostname. With a cache, uBlock benefits given that it deals with a
|
||||
// specific set of hostnames within a narrow time span -- in other words, I
|
||||
// believe probability of cache hit are high in uBlock.
|
||||
|
||||
var DomainCacheEntry = function(domain) {
|
||||
this.init(domain);
|
||||
};
|
||||
|
||||
DomainCacheEntry.prototype.init = function(domain) {
|
||||
this.domain = domain;
|
||||
this.tstamp = Date.now();
|
||||
return this;
|
||||
};
|
||||
|
||||
DomainCacheEntry.prototype.dispose = function() {
|
||||
this.domain = '';
|
||||
if ( domainCacheEntryJunkyard.length < 25 ) {
|
||||
domainCacheEntryJunkyard.push(this);
|
||||
}
|
||||
};
|
||||
|
||||
var domainCacheEntryFactory = function(domain) {
|
||||
var entry = domainCacheEntryJunkyard.pop();
|
||||
if ( entry ) {
|
||||
return entry.init(domain);
|
||||
}
|
||||
return new DomainCacheEntry(domain);
|
||||
};
|
||||
|
||||
var domainCacheEntryJunkyard = [];
|
||||
|
||||
var domainCacheAdd = function(hostname, domain) {
|
||||
if ( domainCache.hasOwnProperty(hostname) ) {
|
||||
domainCache[hostname].tstamp = Date.now();
|
||||
} else {
|
||||
domainCache[hostname] = domainCacheEntryFactory(domain);
|
||||
domainCacheCount += 1;
|
||||
if ( domainCacheCount === domainCacheCountHighWaterMark ) {
|
||||
domainCachePrune();
|
||||
}
|
||||
}
|
||||
return domain;
|
||||
};
|
||||
|
||||
var domainCacheEntrySort = function(a, b) {
|
||||
return b.tstamp - a.tstamp;
|
||||
};
|
||||
|
||||
var domainCachePrune = function() {
|
||||
var hostnames = Object.keys(domainCache)
|
||||
.sort(domainCacheEntrySort)
|
||||
.slice(domainCacheCountLowWaterMark);
|
||||
var i = hostnames.length;
|
||||
domainCacheCount -= i;
|
||||
var hostname;
|
||||
while ( i-- ) {
|
||||
hostname = hostnames[i];
|
||||
domainCache[hostname].dispose();
|
||||
delete domainCache[hostname];
|
||||
}
|
||||
};
|
||||
|
||||
var domainCache = {};
|
||||
var domainCacheCount = 0;
|
||||
var domainCacheCountLowWaterMark = 75;
|
||||
var domainCacheCountHighWaterMark = 100;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
URI.domainFromURI = function(uri) {
|
||||
|
|
|
@ -19,15 +19,17 @@
|
|||
Home: https://github.com/gorhill/uMatrix
|
||||
*/
|
||||
|
||||
/* global chrome, messaging, uDom */
|
||||
/* global vAPI, uDom */
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
messaging.start('user-rules.js');
|
||||
var messager = vAPI.messaging.channel('user-rules.js');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -102,7 +104,7 @@ function handleImportFilePicker() {
|
|||
'what': 'setUserRules',
|
||||
'temporaryRules': rulesFromHTML('#diff .right li') + '\n' + this.result
|
||||
};
|
||||
messaging.ask(request, processUserRules);
|
||||
messager.send(request, processUserRules);
|
||||
};
|
||||
var file = this.files[0];
|
||||
if ( file === undefined || file.name === '' ) {
|
||||
|
@ -130,10 +132,9 @@ var startImportFilePicker = function() {
|
|||
/******************************************************************************/
|
||||
|
||||
function exportUserRulesToFile() {
|
||||
chrome.downloads.download({
|
||||
vAPI.download({
|
||||
'url': 'data:text/plain,' + encodeURIComponent(rulesFromHTML('#diff .left li')),
|
||||
'filename': uDom('[data-i18n="userRulesDefaultFileName"]').text(),
|
||||
'saveAs': true
|
||||
'filename': uDom('[data-i18n="userRulesDefaultFileName"]').text()
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -161,7 +162,7 @@ var revertHandler = function() {
|
|||
'what': 'setUserRules',
|
||||
'temporaryRules': rulesFromHTML('#diff .left li')
|
||||
};
|
||||
messaging.ask(request, processUserRules);
|
||||
messager.send(request, processUserRules);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -171,7 +172,7 @@ var commitHandler = function() {
|
|||
'what': 'setUserRules',
|
||||
'permanentRules': rulesFromHTML('#diff .right li')
|
||||
};
|
||||
messaging.ask(request, processUserRules);
|
||||
messager.send(request, processUserRules);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -191,7 +192,7 @@ var editStopHandler = function(ev) {
|
|||
'what': 'setUserRules',
|
||||
'temporaryRules': uDom('#diff .right textarea').val()
|
||||
};
|
||||
messaging.ask(request, processUserRules);
|
||||
messager.send(request, processUserRules);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -210,7 +211,7 @@ var temporaryRulesToggler = function(ev) {
|
|||
'what': 'setUserRules',
|
||||
'temporaryRules': rulesFromHTML('#diff .right li')
|
||||
};
|
||||
messaging.ask(request, processUserRules);
|
||||
messager.send(request, processUserRules);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -221,14 +222,14 @@ uDom.onLoad(function() {
|
|||
uDom('#importFilePicker').on('change', handleImportFilePicker);
|
||||
uDom('#exportButton').on('click', exportUserRulesToFile);
|
||||
|
||||
uDom('#revertButton').on('click', revertHandler)
|
||||
uDom('#commitButton').on('click', commitHandler)
|
||||
uDom('#editEnterButton').on('click', editStartHandler)
|
||||
uDom('#editStopButton').on('click', editStopHandler)
|
||||
uDom('#editCancelButton').on('click', editCancelHandler)
|
||||
uDom('#diff > .right > ul').on('click', 'li', temporaryRulesToggler)
|
||||
uDom('#revertButton').on('click', revertHandler);
|
||||
uDom('#commitButton').on('click', commitHandler);
|
||||
uDom('#editEnterButton').on('click', editStartHandler);
|
||||
uDom('#editStopButton').on('click', editStopHandler);
|
||||
uDom('#editCancelButton').on('click', editCancelHandler);
|
||||
uDom('#diff > .right > ul').on('click', 'li', temporaryRulesToggler);
|
||||
|
||||
messaging.ask({ what: 'getUserRules' }, processUserRules);
|
||||
messager.send({ what: 'getUserRules' }, processUserRules);
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -30,69 +30,17 @@
|
|||
/******************************************************************************/
|
||||
|
||||
var gotoURL = function(details) {
|
||||
if ( details.tabId ) {
|
||||
chrome.tabs.update(details.tabId, { url: details.url });
|
||||
} else {
|
||||
chrome.tabs.create({ url: details.url });
|
||||
}
|
||||
vAPI.tabs.open(details);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var gotoExtensionURL = function(url) {
|
||||
var hasFragment = function(url) {
|
||||
return url.indexOf('#') >= 0;
|
||||
};
|
||||
|
||||
var removeFragment = function(url) {
|
||||
var pos = url.indexOf('#');
|
||||
if ( pos < 0 ) {
|
||||
return url;
|
||||
}
|
||||
return url.slice(0, pos);
|
||||
};
|
||||
|
||||
var tabIndex = 9999;
|
||||
var targetUrl = chrome.extension.getURL(url);
|
||||
var urlToFind = removeFragment(targetUrl);
|
||||
|
||||
var currentWindow = function(tabs) {
|
||||
var updateProperties = { active: true };
|
||||
var i = tabs.length;
|
||||
while ( i-- ) {
|
||||
if ( removeFragment(tabs[i].url) !== urlToFind ) {
|
||||
continue;
|
||||
}
|
||||
// If current tab in dashboard is different, force the new one, if
|
||||
// there is one, to be activated.
|
||||
if ( tabs[i].url !== targetUrl ) {
|
||||
if ( hasFragment(targetUrl) ) {
|
||||
updateProperties.url = targetUrl;
|
||||
}
|
||||
}
|
||||
// Activate found matching tab
|
||||
// Commented out as per:
|
||||
// https://github.com/gorhill/httpswitchboard/issues/150#issuecomment-32683726
|
||||
// chrome.tabs.move(tabs[0].id, { index: index + 1 });
|
||||
chrome.tabs.update(tabs[i].id, updateProperties);
|
||||
return;
|
||||
}
|
||||
chrome.tabs.create({ 'url': targetUrl, index: tabIndex + 1 });
|
||||
};
|
||||
|
||||
var currentTab = function(tabs) {
|
||||
if ( tabs.length ) {
|
||||
tabIndex = tabs[0].index;
|
||||
}
|
||||
chrome.tabs.query({ currentWindow: true }, currentWindow);
|
||||
};
|
||||
|
||||
// https://github.com/gorhill/httpswitchboard/issues/150
|
||||
// Logic:
|
||||
// - If URL is already opened in a tab, just activate tab
|
||||
// - Otherwise find the current active tab and open in a tab immediately
|
||||
// to the right of the active tab
|
||||
chrome.tabs.query({ active: true }, currentTab);
|
||||
vAPI.tabs.open({
|
||||
url: url,
|
||||
index: -1,
|
||||
select: true
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -32,73 +32,34 @@ var noopFunc = function(){};
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Must read: https://code.google.com/p/chromium/issues/detail?id=410868#c8
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/19
|
||||
// https://github.com/gorhill/uBlock/issues/207
|
||||
// Since we may be called asynchronously, the tab id may not exist
|
||||
// anymore, so this ensures it does still exist.
|
||||
|
||||
exports.setIcon = function(id, imgDict, overlayStr) {
|
||||
var onIconReady = function() {
|
||||
if ( chrome.runtime.lastError ) {
|
||||
return;
|
||||
}
|
||||
chrome.browserAction.setBadgeText({ tabId: id, text: overlayStr });
|
||||
if ( overlayStr !== '' ) {
|
||||
chrome.browserAction.setBadgeBackgroundColor({ tabId: id, color: '#666' });
|
||||
}
|
||||
};
|
||||
chrome.browserAction.setIcon({ tabId: id, path: imgDict }, onIconReady);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
exports.injectScript = function(id, details) {
|
||||
chrome.tabs.executeScript(id, details);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
exports.keyvalSetOne = function(key, val, callback) {
|
||||
var bin = {};
|
||||
bin[key] = val;
|
||||
chrome.storage.local.set(bin, callback || noopFunc);
|
||||
vAPI.storage.set(bin, callback || noopFunc);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
exports.keyvalGetOne = function(key, callback) {
|
||||
chrome.storage.local.get(key, callback);
|
||||
vAPI.storage.get(key, callback);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
exports.keyvalSetMany = function(dict, callback) {
|
||||
chrome.storage.local.set(dict, callback || noopFunc);
|
||||
vAPI.storage.set(dict, callback || noopFunc);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
exports.keyvalRemoveOne = function(key, callback) {
|
||||
chrome.storage.local.remove(key, callback || noopFunc);
|
||||
vAPI.storage.remove(key, callback || noopFunc);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
exports.keyvalRemoveAll = function(callback) {
|
||||
chrome.storage.local.clear(callback || noopFunc);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
exports.restart = function() {
|
||||
// https://github.com/gorhill/uMatrix/issues/40
|
||||
// I don't know if that helps workaround whatever Chromium bug causes
|
||||
// the browser to crash.
|
||||
chrome.runtime.sendMessage({ what: 'restart' }, function() {
|
||||
chrome.runtime.reload();
|
||||
});
|
||||
vAPI.storage.clear(callback || noopFunc);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -91,9 +91,10 @@
|
|||
</div>
|
||||
|
||||
<script src="lib/punycode.min.js"></script>
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.js"></script>
|
||||
<script src="js/udom.js"></script>
|
||||
<script src="js/i18n.js"></script>
|
||||
<script src="js/messaging-client.js"></script>
|
||||
<script src="js/popup.js"></script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -104,10 +104,11 @@ html.rtl #spoof-user-agent-with {
|
|||
<p class="para" data-i18n="privacyProcessBehindTheSceneHelp"></p>
|
||||
</div>
|
||||
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.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/privacy.js"></script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -66,10 +66,11 @@ ul > li {
|
|||
</ul>
|
||||
|
||||
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.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/settings.js"></script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -37,10 +37,11 @@
|
|||
<input class="hidden" id="importFilePicker" type="file" accept="text/plain">
|
||||
<span class="hidden" data-i18n="userRulesDefaultFileName"></span>
|
||||
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-client.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/user-rules.js"></script>
|
||||
|
||||
</body>
|
||||
|
|
Loading…
Reference in a new issue