Without more information from you as to exactly what you desire to do, it is difficult to determine the best way to do this. In particular, it is hard to know exactly what situations to which you desire to respond.
It looks like you could use a listener to the tabs.onUpdated
event. While this fires more often than you actually desire, it does fire on reloading of a page.
Below is code that calls a function completedLoadingURLInTab()
when a URL has been loaded, or reloaded on a page. I've left in a bunch of console.log()
calls as comments which I would normally remove. They can be uncommented to show in the console all the times the event fires. This can be useful to determine exactly the contents of the data received from the event and the sequence of events that fire during various page navigation.
Note 1: I found that the changeInfo
object can be invalid under some circumstances. It was necessary to see if a property existed using hasOwnProperty()
and then obtain the value from the tabs.Tab
object that is also passed to the event handler.
Note 2: The tabs
permission in manifest.json is required.
function completedLoadingURLInTab(tabId, newUrl,oldUrl) {
//We have completed, loading a URL.
if(newUrl === oldUrl) {
//We re-loaded the previous URL
console.log(">>>>>>> Re-load tab=" + tabId + " with URL=" + newUrl);
} else {
//This URL _may_ be just a new position in the same page. That
// is something that needs to be checked for here.
console.log(">>>>>>> New URL loaded in tab=" + tabId + ". URL=" + newUrl);
}
//Remember the newUrl so we can check against it the next time
// an event is fired.
tabsInfo[tabId].previousCompleteUrl = newUrl;
tabsInfo[tabId].loadingUrl = newUrl;
}
let tabsInfo = {};
function InfoForTab(_loadingUrl,_previousUrl,_status) {
this.loadingUrl = _loadingUrl;
this.previousCompleteUrl = (_previousUrl === undefined) ? "" : _previousUrl;
this.status = (_status === undefined) ? "" : _status;
}
function foundNewTab(tabId) {
//Create an object to hold the collected info for the tab.
tabsInfo[tabId] = new InfoForTab();
console.log("New tab. ID=" + tabId);
}
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(!tabsInfo.hasOwnProperty(tabId)) {
//This is the first time we have encountered this tab.
foundNewTab(tabId);
}
let output="";
//We use the properties of "tab" instead of "changeInfo" because in testing it was
// clear that changeInfo was not always properly populated. The key(s) may just
// exist, but not have any value associated with them.
/*
//Testing output showing when the event is fired.
// This is used to determine, by experimentation, what events to ignore and which
// combinations and sequence of events occur during page navigation.
output += (changeInfo.hasOwnProperty("status")) ? "\nstatus=" + tab.status : "";
output += (changeInfo.hasOwnProperty("url")) ? "\nurl=" + tab.url : "";
output += (changeInfo.hasOwnProperty("pinned")) ? "\npinned=" + tab.pinned : "";
output += (changeInfo.hasOwnProperty("audible")) ? "\naudible=" + tab.audible : "";
output += (changeInfo.hasOwnProperty("mutedInfo")) ? "\nmutedInfo="+tab.mutedInfo : "";
output +=(changeInfo.hasOwnProperty("favIconUrl"))?"\nfavIconUrl="+tab.favIconUrl : "";
console.log("tabs.updated event: tabId=" + tabId + ":: changeInfo="
+ Object.keys(changeInfo) + output
);
*/
if(changeInfo.hasOwnProperty("status") && changeInfo.hasOwnProperty("url")
&& (tab.status === "loading")) {
//A URL is being loaded into the tab. This can be for the first time,
// or transitioning to a new URL, or reloading the page.
let outputFirst = "";
let outputLoading = "Loading";
if(tabsInfo[tabId].previousCompleteUrl === tab.url) {
//We are re-loading the same URL
outputLoading = "Re-loading";
}
//console.log(outputLoading + " URL=" + tab.url);
//We save the URL which is being loaded, but we really don't do anything with it.
tabsInfo[tabId].loadingUrl = tab.url;
tabsInfo[tabId].status = "loading";
return;
} //else
if(changeInfo.hasOwnProperty("status") && (tab.status === "complete")) {
if( tabsInfo[tabId].status === "loading") {
tabsInfo[tabId].status = "complete";
//console.log("In tabId="+tabId+" completed loading URL="+tab.url);
completedLoadingURLInTab(tabId, tab.url, tabsInfo[tabId].previousCompleteUrl);
return;
} //else
if( tabsInfo[tabId].status === "complete") {
if(tabsInfo[tabId].previousCompleteUrl === tab.url) {
//console.log("In tabId=" + tabId + " got completed status change after"
// + "already complete with URL="
// + tabsInfo[tabId].previousCompleteUrl);
return;
}//else
//console.log("In tabId=" + tabId + " completed directly loading new URL="
// + tab.url);
completedLoadingURLInTab(tabId, tab.url, tabsInfo[tabId].previousCompleteUrl);
return;
}
}//else
if(changeInfo.hasOwnProperty("status") && (tab.status === "loading")
&& ( tabsInfo[tabId].status === "complete")) {
//console.log("In tabId=" + tabId + " leaving page");
return;
}//else
if(changeInfo.hasOwnProperty("status") ) {
if((tab.status === "complete") && (tab.url === "about:newtab")
&& tabsInfo[tabId].loadingUrl === undefined ) {
//We have completed loading about:newtab for the first time in this tab.
tabsInfo[tabId].status = "complete";
completedLoadingURLInTab(tabId, tab.url, tabsInfo[tabId].previousCompleteUrl);
return;
} //else
//console.log("In tabId=" + tabId + " got status change to " + tab.status
// + " prior to loading a URL with current URL=" + tab.url);
return;
}//else
});
Given loading the add-on, opening a new tab and doing a bit of navigation (including a few page re-loads), the output in the console could look like:
New tab. ID=6
>>>>>>> New URL loaded in tab=6. URL=about:newtab
>>>>>>> New URL loaded in tab=6. URL=https://www.google.com/?gws_rd=ssl
>>>>>>> Re-load tab=6 with URL=https://www.google.com/?gws_rd=ssl
>>>>>>> New URL loaded in tab=6. URL=https://www.google.com/?gws_rd=ssl#q=test
>>>>>>> Re-load tab=6 with URL=https://www.google.com/?gws_rd=ssl#q=test
>>>>>>> New URL loaded in tab=6. URL=https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onUpdated
>>>>>>> New URL loaded in tab=6. URL=https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onUpdated#changeInfo
>>>>>>> Re-load tab=6 with URL=https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onUpdated#changeInfo
Alternately, use the webNavigation
events
The webNavigation
events provide you information directly about web navigation. They will probably provide you with a better solution than tabs.onUpdated
.
If you use webNavigation
events, you will need to experiment to see which combination of events fire for the situations your are concerned about. Most likely this will be Completed
and/or ReferenceFragmentUpdated
.
So you can get a feel for what when these events fire, the following code will log to the console all webNavigation
events:
var webNavEvents = ['BeforeNavigate',
'Committed',
'Completed',
//'CreatedNavigationTarget', //Not supported by Firefox
'DOMContentLoaded',
'ErrorOccurred',
'HistoryStateUpdated',
'ReferenceFragmentUpdated'
//'TabReplaced' //Not supported by Firefox
];
webNavEvents.forEach(function(navType){
browser.webNavigation['on' + navType].addListener(function(type,details){
console.log('\twebNavigation->' + type
+ ': tadId=' + details.tabId
+ ':: url=' + details.url
+ ((typeof details.transitionType === 'string') ? ':: transitionType='
+ details.transitionType : '')
);
}.bind(undefined,navType));
});
load
,readystatechange
, etc.). Some things you may be doing can provide inherent notification of some events. – Aedestabs.onUpdated
might work, but the event doesn’t occur when the page is refreshed — only when the popup itself is updated, which is too late. I can’t see anything else in the documentation which remotely comes close. I am investigatingwebNavigation
, but I think that’s a dead end, and I haven’t yet worked it out. – Albinaalbinismtabs.onUpdated
certainly fires when the page is reloaded. I've been working on an answer for you usingtabs.onUpdated
. I'll post it shortly. – Aedes