The following extension adds a listener to webNavigation.onCompleted
which is used to remember, indexed by tabId, both the most recent URL in frameId==0
for which the event is fired, and the prior URL.(以下扩展将一个侦听器添加到webNavigation.onCompleted
,该侦听器用于记住由tabId索引的,触发了事件的frameId==0
最新URL和先前的URL(由tabId索引)。)
A listener is added to webNavigation.onBeforeNavigate
which watches for matching URLs, in this case, stackexchange.com
.(侦听器被添加到webNavigation.onBeforeNavigate
该手表匹配的URL,在这种情况下, stackexchange.com
。) If the URL matches, the tab URL is updated, via tabs.update
, to navigate back to the last URL for which a webNavigation.onCompleted
event was fired.(如果URL匹配,则通过tabs.update
来更新选项卡URL,以导航回为其触发webNavigation.onCompleted
事件的最后一个URL。)
If the onBeforeNavigate
event is for a frameId
other than 0
, then the tab is navigated to the previous URL for which a onCompleted
event was fired for frameId==0
.(如果onBeforeNavigate
事件是针对非0
的frameId
,则该选项卡将导航到先前的URL,对于该URL,已针对frameId==0
触发了onCompleted
事件。) If the prior URL was not used, then we could get into a loop where the current URL is repeatedly re-loaded due to the URL in one of its frames matching the URL we are blocking.(如果未使用先前的URL,那么我们可能会陷入一个循环,其中由于其框架之一中的URL与我们阻止的URL相匹配,因此会重复重新加载当前URL。) A better way to handle this would be to inject a content script to change the src
attribute for the frame.(处理此问题的更好方法是注入内容脚本以更改框架的src
属性。) We would then need to handle frames within frames.(然后,我们需要处理框架内的框架。)
blockNavigation.js :(blockNavigation.js :)
//Remember tab URLs
var tabsInfo = {};
function completedLoadingUrlInTab(details) {
//console.log('details:',details);
//We have completed loading a URL.
createTabRecordIfNeeded(details.tabId);
if(details.frameId !== 0){
//Only record inforamtion for the main frame
return;
}
//Remember the newUrl so we can check against it the next time
// an event is fired.
tabsInfo[details.tabId].priorCompleteUrl = tabsInfo[details.tabId].completeUrl;
tabsInfo[details.tabId].completeUrl = details.url;
}
function InfoForTab(_url,_priorUrl) {
this.completeUrl = (typeof _url !== 'string') ? "" : _url;
this.priorCompleteUrl = (typeof _priorUrl !== 'string') ? "" : _priorUrl;
}
function createTabRecordIfNeeded(tabId) {
if(!tabsInfo.hasOwnProperty(tabId) || typeof tabsInfo[tabId] !== 'object') {
//This is the first time we have encountered this tab.
//Create an object to hold the collected info for the tab.
tabsInfo[tabId] = new InfoForTab();
}
}
//Block URLs
function blockUrlIfMatch(details){
createTabRecordIfNeeded(details.tabId);
if(/^[^:/]+://[^/]*stackexchange.[^/.]+//.test(details.url)){
//Block this URL by navigating to the already current URL
console.log('Blocking URL:',details.url);
console.log('Returning to URL:',tabsInfo[details.tabId].completeUrl);
if(details.frameId !==0){
//This navigation is in a subframe. We currently handle that by
// navigating to the page prior to the current one.
// Probably should handle this by changing the src of the frame.
// This would require injecting a content script to change the src.
// Would also need to handle frames within frames.
//Must navigate to priorCmpleteUrl as we can not load the current one.
tabsInfo[details.tabId].completeUrl = tabsInfo[details.tabId].priorCompleteUrl;
}
var urlToUse = tabsInfo[details.tabId].completeUrl;
urlToUse = (typeof urlToUse === 'string') ? urlToUse : '';
chrome.tabs.update(details.tabId,{url: urlToUse},function(tab){
if(chrome.runtime.lastError){
if(chrome.runtime.lastError.message.indexOf('No tab with id:') > -1){
//Chrome is probably loading a page in a tab which it is expecting to
// swap out with a current tab. Need to decide how to handle this
// case.
//For now just output the error message
console.log('Error:',chrome.runtime.lastError.message)
} else {
console.log('Error:',chrome.runtime.lastError.message)
}
}
});
//Notify the user URL was blocked.
notifyOfBlockedUrl(details.url);
}
}
function notifyOfBlockedUrl(url){
//This will fail if you have not provided an icon.
chrome.notifications.create({
type: 'basic',
iconUrl: 'blockedUrl.png',
title:'Blocked URL',
message:url
});
}
//Startup
chrome.webNavigation.onCompleted.addListener(completedLoadingUrlInTab);
chrome.webNavigation.onBeforeNavigate.addListener(blockUrlIfMatch);
//Get the URLs for all current tabs when add-on is loaded.
//Block any currently matching URLs. Does not check for URLs in frames.
chrome.tabs.query({},tabs => {
tabs.forEach(tab => {
createTabRecordIfNeeded(tab.id);
tabsInfo[tab.id].completeUrl = tab.url;
blockUrlIfMatch({
tabId : tab.id,
frameId : 1, //use 1. This will result in going to '' at this time.
url : tab.url
});
});
});
manifest.json :(manifest.json :)
{
"description": "Watch webNavigation events and block matching URLs",
"manifest_version": 2,
"name": "webNavigation based block navigation to matched URLs",
"version": "0.1",
"permissions": [
"notifications",
"webNavigation",
"tabs"
],
"background": {
"scripts": ["blockNavigation.js"]
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…