aboutsummaryrefslogtreecommitdiffstats
path: root/js/tab.js
diff options
context:
space:
mode:
authorJesús <heckyel@hyperbola.info>2019-12-30 15:55:13 -0500
committerJesús <heckyel@hyperbola.info>2019-12-30 15:55:13 -0500
commit288df6a7bf8b933e2dc499e38f4915fcf974c14b (patch)
tree77bba994f260c064d3ee7f76c427ddfaa4f91710 /js/tab.js
parenta2c9deaa145b780722e93b3899600f287c8094a4 (diff)
downloadematrix-288df6a7bf8b933e2dc499e38f4915fcf974c14b.tar.lz
ematrix-288df6a7bf8b933e2dc499e38f4915fcf974c14b.tar.xz
ematrix-288df6a7bf8b933e2dc499e38f4915fcf974c14b.zip
backport
- Flush caches on upgrade - Properly handle FrameModule's unloading - Use the new module and remove the old implementation
Diffstat (limited to 'js/tab.js')
-rw-r--r--js/tab.js658
1 files changed, 346 insertions, 312 deletions
diff --git a/js/tab.js b/js/tab.js
index abaaf07..b34d923 100644
--- a/js/tab.js
+++ b/js/tab.js
@@ -21,32 +21,26 @@
uMatrix Home: https://github.com/gorhill/uMatrix
*/
-/******************************************************************************/
-/******************************************************************************/
-
-(function() {
-
+(function () {
'use strict';
- /******************************************************************************/
+ Cu.import('chrome://ematrix/content/lib/UriTools.jsm');
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 '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) ) {
+ // 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 '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://' + this.behindTheSceneScope + '/';
}
@@ -59,117 +53,122 @@
}
}
- // If the URL is that of our "blocked page" document, return the URL of
- // the blocked page.
- if ( pageURL.lastIndexOf(vAPI.getURL('main-blocked.html'), 0) === 0 ) {
- var matches = /main-blocked\.html\?details=([^&]+)/.exec(pageURL);
- if ( matches && matches.length === 2 ) {
+ // If the URL is that of our "blocked page" document, return
+ // the URL of the blocked page.
+ if (pageURL.lastIndexOf(vAPI.getURL('main-blocked.html'), 0) === 0) {
+ let matches = /main-blocked\.html\?details=([^&]+)/.exec(pageURL);
+ if (matches && matches.length === 2) {
try {
- var details = JSON.parse(atob(matches[1]));
+ let details = JSON.parse(atob(matches[1]));
pageURL = details.url;
} catch (e) {
}
}
}
- var uri = this.URI.set(pageURL);
- var scheme = uri.scheme;
- if ( scheme === 'https' || scheme === 'http' ) {
- return uri.normalizedURI();
+ let uri = UriTools.set(pageURL);
+ let scheme = uri.scheme;
+ if (scheme === 'https' || scheme === 'http') {
+ return UriTools.normalizedURI();
}
- var fakeHostname = scheme + '-scheme';
+ let fakeHostname = scheme + '-scheme';
- if ( uri.hostname !== '' ) {
+ if (uri.hostname !== '') {
fakeHostname = uri.hostname + '.' + fakeHostname;
- } else if ( scheme === 'about' ) {
+ } else if (scheme === 'about') {
fakeHostname = uri.path + '.' + fakeHostname;
}
return 'http://' + fakeHostname + '/';
};
- /******************************************************************************/
- /******************************************************************************
-
-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.
-
+ /*
+ 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);
+ ηm.tabContextManager = (function () {
+ let 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;
+ // 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.
+ let mostRecentRootDocURL = '';
+ let mostRecentRootDocURLTimestamp = 0;
- var gcPeriod = 31 * 60 * 1000; // every 31 minutes
+ let gcPeriod = 31 * 60 * 1000; // every 31 minutes
- // A pushed entry is removed from the stack unless it is committed with
- // a set time.
- var StackEntry = function(url, commit) {
+ // A pushed entry is removed from the stack unless it is
+ // committed with a set time.
+ let StackEntry = function (url, commit) {
this.url = url;
this.committed = commit;
this.tstamp = Date.now();
};
- var TabContext = function(tabId) {
+ let TabContext = function (tabId) {
this.tabId = tabId;
this.stack = [];
this.rawURL =
@@ -184,120 +183,134 @@ housekeep itself.
tabContexts[tabId] = this;
};
- TabContext.prototype.destroy = function() {
- if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
+ TabContext.prototype.destroy = function () {
+ if (vAPI.isBehindTheSceneTabId(this.tabId)) {
return;
}
- if ( this.gcTimer !== null ) {
+ if (this.gcTimer !== null) {
clearTimeout(this.gcTimer);
this.gcTimer = null;
}
delete tabContexts[this.tabId];
};
- TabContext.prototype.onTab = function(tab) {
- if ( tab ) {
+ TabContext.prototype.onTab = function (tab) {
+ if (tab) {
this.gcTimer = vAPI.setTimeout(this.onGC.bind(this), gcPeriod);
} else {
this.destroy();
}
};
- TabContext.prototype.onGC = function() {
+ TabContext.prototype.onGC = function () {
this.gcTimer = null;
- if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
+ if (vAPI.isBehindTheSceneTabId(this.tabId)) {
return;
}
vAPI.tabs.get(this.tabId, this.onTab.bind(this));
};
// https://github.com/gorhill/uBlock/issues/248
- // Stack entries have to be committed to stick. Non-committed stack
- // entries are removed after a set delay.
- TabContext.prototype.onCommit = function() {
- if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
+ // Stack entries have to be committed to stick. Non-committed
+ // stack entries are removed after a set delay.
+ TabContext.prototype.onCommit = function () {
+ if (vAPI.isBehindTheSceneTabId(this.tabId)) {
return;
}
this.commitTimer = null;
// Remove uncommitted entries at the top of the stack.
- var i = this.stack.length;
- while ( i-- ) {
- if ( this.stack[i].committed ) {
+ let i = this.stack.length;
+ while (i--) {
+ if (this.stack[i].committed) {
break;
}
}
// https://github.com/gorhill/uBlock/issues/300
// If no committed entry was found, fall back on the bottom-most one
// as being the committed one by default.
- if ( i === -1 && this.stack.length !== 0 ) {
+ if (i === -1 && this.stack.length !== 0) {
this.stack[0].committed = true;
i = 0;
}
- i += 1;
- if ( i < this.stack.length ) {
+
+ ++i;
+ if (i < this.stack.length) {
this.stack.length = i;
this.update();
ηm.bindTabToPageStats(this.tabId, 'newURL');
}
};
- // 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 flush it.
- TabContext.prototype.autodestroy = function() {
- if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
+ // 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 flush it.
+ TabContext.prototype.autodestroy = function () {
+ if (vAPI.isBehindTheSceneTabId(this.tabId)) {
return;
}
this.gcTimer = vAPI.setTimeout(this.onGC.bind(this), gcPeriod);
};
- // Update just force all properties to be updated to match the most recent
- // root URL.
- TabContext.prototype.update = function() {
- if ( this.stack.length === 0 ) {
- this.rawURL = this.normalURL = this.scheme =
- this.rootHostname = this.rootDomain = '';
+ // Update just force all properties to be updated to match the
+ // most recent root URL.
+ TabContext.prototype.update = function () {
+ if (this.stack.length === 0) {
+ this.rawURL =
+ this.normalURL =
+ this.scheme =
+ this.rootHostname =
+ this.rootDomain = '';
this.secure = false;
return;
}
+
this.rawURL = this.stack[this.stack.length - 1].url;
this.normalURL = ηm.normalizePageURL(this.tabId, this.rawURL);
- this.scheme = ηm.URI.schemeFromURI(this.rawURL);
- this.rootHostname = ηm.URI.hostnameFromURI(this.normalURL);
- this.rootDomain = ηm.URI.domainFromHostname(this.rootHostname) || this.rootHostname;
- this.secure = ηm.URI.isSecureScheme(this.scheme);
+ this.scheme = UriTools.schemeFromURI(this.rawURL);
+ this.rootHostname = UriTools.hostnameFromURI(this.normalURL);
+ this.rootDomain = UriTools.domainFromHostname(this.rootHostname)
+ || this.rootHostname;
+ this.secure = UriTools.isSecureScheme(this.scheme);
};
// Called whenever a candidate root URL is spotted for the tab.
- TabContext.prototype.push = function(url, context) {
- if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
- var committed = context !== undefined;
- var count = this.stack.length;
- var topEntry = this.stack[count - 1];
- if ( topEntry && topEntry.url === url ) {
- if ( committed ) {
+ TabContext.prototype.push = function (url, context) {
+ if (vAPI.isBehindTheSceneTabId(this.tabId)) {
+ return;
+ }
+
+ let committed = context !== undefined;
+ let count = this.stack.length;
+ let topEntry = this.stack[count - 1];
+
+ if (topEntry && topEntry.url === url) {
+ if (committed) {
topEntry.committed = true;
}
return;
}
- if ( this.commitTimer !== null ) {
+
+ if (this.commitTimer !== null) {
clearTimeout(this.commitTimer);
}
- if ( committed ) {
+
+ if (committed) {
this.stack = [new StackEntry(url, true)];
} else {
this.stack.push(new StackEntry(url));
- this.commitTimer = vAPI.setTimeout(this.onCommit.bind(this), 1000);
+ this.commitTimer =
+ vAPI.setTimeout(this.onCommit.bind(this), 1000);
}
+
this.update();
ηm.bindTabToPageStats(this.tabId, context);
};
// These are to be used for the API of the tab context manager.
- var push = function(tabId, url, context) {
- var entry = tabContexts[tabId];
- if ( entry === undefined ) {
+ let push = function (tabId, url, context) {
+ let entry = tabContexts[tabId];
+ if (entry === undefined) {
entry = new TabContext(tabId);
entry.autodestroy();
}
@@ -307,64 +320,77 @@ housekeep itself.
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 mustLookup = function(tabId, url) {
- var entry;
- if ( url !== undefined ) {
+ // 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.
+ let mustLookup = function (tabId, url) {
+ let entry;
+
+ if (url !== undefined) {
entry = push(tabId, url);
} else {
entry = tabContexts[tabId];
}
- if ( entry !== undefined ) {
+
+ 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() ) {
+ // 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 !== '' ) {
+ // 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.
+
+ // 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 lookup = function(tabId) {
+ let lookup = function (tabId) {
return tabContexts[tabId] || null;
};
// Behind-the-scene tab context
- (function() {
- var entry = new TabContext(vAPI.noTabId);
+ (function () {
+ let entry = new TabContext(vAPI.noTabId);
entry.stack.push(new StackEntry('', true));
entry.rawURL = '';
entry.normalURL = ηm.normalizePageURL(entry.tabId);
- entry.rootHostname = ηm.URI.hostnameFromURI(entry.normalURL);
- entry.rootDomain = ηm.URI.domainFromHostname(entry.rootHostname) || entry.rootHostname;
+ entry.rootHostname = UriTools.hostnameFromURI(entry.normalURL);
+ entry.rootDomain = UriTools.domainFromHostname(entry.rootHostname)
+ || entry.rootHostname;
})();
// https://github.com/gorhill/uMatrix/issues/513
- // Force a badge update here, it could happen that all the subsequent
- // network requests are already in the page store, which would cause
- // the badge to no be updated for these network requests.
-
- vAPI.tabs.onNavigation = function(details) {
- var tabId = details.tabId;
- if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
+ // Force a badge update here, it could happen that all the
+ // subsequent network requests are already in the page
+ // store, which would cause the badge to no be updated for
+ // these network requests.
+
+ vAPI.tabs.onNavigation = function (details) {
+ let tabId = details.tabId;
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
+ return;
+ }
push(tabId, details.url, 'newURL');
ηm.updateBadgeAsync(tabId);
};
@@ -372,19 +398,25 @@ housekeep itself.
// https://github.com/gorhill/uMatrix/issues/872
// `changeInfo.url` may not always be available (Firefox).
- vAPI.tabs.onUpdated = function(tabId, changeInfo, tab) {
- if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
- if ( typeof tab.url !== 'string' || tab.url === '' ) { return; }
- var url = changeInfo.url || tab.url;
- if ( url ) {
+ vAPI.tabs.onUpdated = function (tabId, changeInfo, tab) {
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
+ return;
+ }
+
+ if (typeof tab.url !== 'string' || tab.url === '') {
+ return;
+ }
+
+ let url = changeInfo.url || tab.url;
+ if (url) {
push(tabId, url, 'updateURL');
}
};
- vAPI.tabs.onClosed = function(tabId) {
+ vAPI.tabs.onClosed = function (tabId) {
ηm.unbindTabFromPageStats(tabId);
- var entry = tabContexts[tabId];
- if ( entry instanceof TabContext ) {
+ let entry = tabContexts[tabId];
+ if (entry instanceof TabContext) {
entry.destroy();
}
};
@@ -398,45 +430,43 @@ housekeep itself.
vAPI.tabs.registerListeners();
- /******************************************************************************/
- /******************************************************************************/
-
// Create an entry for the tab if it doesn't exist
- ηm.bindTabToPageStats = function(tabId, context) {
+ ηm.bindTabToPageStats = function (tabId, context) {
this.updateBadgeAsync(tabId);
- // Do not create a page store for URLs which are of no interests
- // Example: dev console
- var tabContext = this.tabContextManager.lookup(tabId);
- if ( tabContext === null ) {
+ // Do not create a page store for URLs which are of no
+ // interests Example: dev console
+ let tabContext = this.tabContextManager.lookup(tabId);
+ if (tabContext === null) {
throw new Error('Unmanaged tab id: ' + tabId);
}
// rhill 2013-11-24: Never ever rebind behind-the-scene
// virtual tab.
// https://github.com/gorhill/httpswitchboard/issues/67
- if ( vAPI.isBehindTheSceneTabId(tabId) ) {
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
return this.pageStores[tabId];
}
- var normalURL = tabContext.normalURL;
- var pageStore = this.pageStores[tabId] || null;
+ let normalURL = tabContext.normalURL;
+ let pageStore = this.pageStores[tabId] || null;
// The previous page URL, if any, associated with the tab
- if ( pageStore !== null ) {
+ if (pageStore !== null) {
// No change, do not rebind
- if ( pageStore.pageUrl === normalURL ) {
+ if (pageStore.pageUrl === normalURL) {
return pageStore;
}
// https://github.com/gorhill/uMatrix/issues/37
- // Just rebind whenever possible: the URL changed, but the document
- // maybe is the same.
+ // Just rebind whenever possible: the URL changed, but the
+ // document maybe is the same.
// Example: Google Maps, Github
// https://github.com/gorhill/uMatrix/issues/72
// Need to double-check that the new scope is same as old scope
- if ( context === 'updateURL' && pageStore.pageHostname === tabContext.rootHostname ) {
+ if (context === 'updateURL'
+ && pageStore.pageHostname === tabContext.rootHostname) {
pageStore.rawURL = tabContext.rawURL;
pageStore.normalURL = normalURL;
this.updateTitle(tabId);
@@ -450,259 +480,266 @@ housekeep itself.
// Try to resurrect first.
pageStore = this.resurrectPageStore(tabId, normalURL);
- if ( pageStore === null ) {
+ if (pageStore === null) {
pageStore = this.pageStoreFactory(tabContext);
}
this.pageStores[tabId] = pageStore;
this.updateTitle(tabId);
this.pageStoresToken = Date.now();
- // console.debug('tab.js > bindTabToPageStats(): dispatching traffic in tab id %d to page store "%s"', tabId, pageUrl);
-
return pageStore;
};
- /******************************************************************************/
-
- ηm.unbindTabFromPageStats = function(tabId) {
- // Never unbind behind-the-scene page store.
- if ( vAPI.isBehindTheSceneTabId(tabId) ) {
+ ηm.unbindTabFromPageStats = function (tabId) {
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
return;
}
- var pageStore = this.pageStores[tabId] || null;
- if ( pageStore === null ) {
+ let pageStore = this.pageStores[tabId] || null;
+ if (pageStore === null) {
return;
}
delete this.pageStores[tabId];
this.pageStoresToken = Date.now();
- if ( pageStore.incinerationTimer ) {
+ if (pageStore.incinerationTimer) {
clearTimeout(pageStore.incinerationTimer);
pageStore.incinerationTimer = null;
}
- if ( this.pageStoreCemetery.hasOwnProperty(tabId) === false ) {
+ if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
this.pageStoreCemetery[tabId] = {};
}
- var pageStoreCrypt = this.pageStoreCemetery[tabId];
+ let pageStoreCrypt = this.pageStoreCemetery[tabId];
- var pageURL = pageStore.pageUrl;
+ let pageURL = pageStore.pageUrl;
pageStoreCrypt[pageURL] = pageStore;
- pageStore.incinerationTimer = vAPI.setTimeout(
- this.incineratePageStore.bind(this, tabId, pageURL),
- 4 * 60 * 1000
- );
+ pageStore.incinerationTimer =
+ vAPI.setTimeout(this.incineratePageStore.bind(this, tabId, pageURL),
+ 4 * 60 * 1000);
};
- /******************************************************************************/
-
- ηm.resurrectPageStore = function(tabId, pageURL) {
- if ( this.pageStoreCemetery.hasOwnProperty(tabId) === false ) {
+ ηm.resurrectPageStore = function (tabId, pageURL) {
+ if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
return null;
}
- var pageStoreCrypt = this.pageStoreCemetery[tabId];
- if ( pageStoreCrypt.hasOwnProperty(pageURL) === false ) {
+ let pageStoreCrypt = this.pageStoreCemetery[tabId];
+
+ if (pageStoreCrypt.hasOwnProperty(pageURL) === false) {
return null;
}
- var pageStore = pageStoreCrypt[pageURL];
+ let pageStore = pageStoreCrypt[pageURL];
- if ( pageStore.incinerationTimer !== null ) {
+ if (pageStore.incinerationTimer !== null) {
clearTimeout(pageStore.incinerationTimer);
pageStore.incinerationTimer = null;
}
delete pageStoreCrypt[pageURL];
- if ( Object.keys(pageStoreCrypt).length === 0 ) {
+ if (Object.keys(pageStoreCrypt).length === 0) {
delete this.pageStoreCemetery[tabId];
}
return pageStore;
};
- /******************************************************************************/
-
- ηm.incineratePageStore = function(tabId, pageURL) {
- if ( this.pageStoreCemetery.hasOwnProperty(tabId) === false ) {
+ ηm.incineratePageStore = function (tabId, pageURL) {
+ if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
return;
}
- var pageStoreCrypt = this.pageStoreCemetery[tabId];
- if ( pageStoreCrypt.hasOwnProperty(pageURL) === false ) {
+ let pageStoreCrypt = this.pageStoreCemetery[tabId];
+
+ if (pageStoreCrypt.hasOwnProperty(pageURL) === false) {
return;
}
- var pageStore = pageStoreCrypt[pageURL];
- if ( pageStore.incinerationTimer !== null ) {
+ let pageStore = pageStoreCrypt[pageURL];
+ if (pageStore.incinerationTimer !== null) {
clearTimeout(pageStore.incinerationTimer);
pageStore.incinerationTimer = null;
}
delete pageStoreCrypt[pageURL];
- if ( Object.keys(pageStoreCrypt).length === 0 ) {
+
+ if (Object.keys(pageStoreCrypt).length === 0) {
delete this.pageStoreCemetery[tabId];
}
pageStore.dispose();
};
- /******************************************************************************/
-
- ηm.pageStoreFromTabId = function(tabId) {
+ ηm.pageStoreFromTabId = function (tabId) {
return this.pageStores[tabId] || null;
};
// Never return null
- ηm.mustPageStoreFromTabId = function(tabId) {
+ ηm.mustPageStoreFromTabId = function (tabId) {
return this.pageStores[tabId] || this.pageStores[vAPI.noTabId];
};
- /******************************************************************************/
-
- ηm.forceReload = function(tabId, bypassCache) {
+ ηm.forceReload = function (tabId, bypassCache) {
vAPI.tabs.reload(tabId, bypassCache);
};
- /******************************************************************************/
-
// Update badge
// rhill 2013-11-09: well this sucks, I can't update icon/badge
- // incrementally, as chromium overwrite the icon at some point without
- // notifying me, and this causes internal cached state to be out of sync.
+ // incrementally, as chromium overwrite the icon at some point
+ // without notifying me, and this causes internal cached state to
+ // be out of sync.
+ // ηMatrix: does it matter to us?
- ηm.updateBadgeAsync = (function() {
- var tabIdToTimer = Object.create(null);
+ ηm.updateBadgeAsync = (function () {
+ let tabIdToTimer = Object.create(null);
- var updateBadge = function(tabId) {
+ let updateBadge = function (tabId) {
delete tabIdToTimer[tabId];
- var iconId = null;
- var badgeStr = '';
+ let iconId = null;
+ let badgeStr = '';
- var pageStore = this.pageStoreFromTabId(tabId);
- if ( pageStore !== null ) {
- var total = pageStore.perLoadAllowedRequestCount +
+ let pageStore = this.pageStoreFromTabId(tabId);
+ if (pageStore !== null) {
+ let total = pageStore.perLoadAllowedRequestCount +
pageStore.perLoadBlockedRequestCount;
- if ( total ) {
- var squareSize = 19;
- var greenSize = squareSize * Math.sqrt(pageStore.perLoadAllowedRequestCount / total);
- iconId = greenSize < squareSize/2 ? Math.ceil(greenSize) : Math.floor(greenSize);
+
+ if (total) {
+ let squareSize = 19;
+ let greenSize = squareSize *
+ Math.sqrt(pageStore.perLoadAllowedRequestCount / total);
+
+ iconId = greenSize < squareSize/2 ?
+ Math.ceil(greenSize) :
+ Math.floor(greenSize);
}
- if ( this.userSettings.iconBadgeEnabled && pageStore.perLoadBlockedRequestCount !== 0) {
- badgeStr = this.formatCount(pageStore.perLoadBlockedRequestCount);
+
+ if (this.userSettings.iconBadgeEnabled
+ && pageStore.perLoadBlockedRequestCount !== 0) {
+ badgeStr =
+ this.formatCount(pageStore.perLoadBlockedRequestCount);
}
}
vAPI.setIcon(tabId, iconId, badgeStr);
};
- return function(tabId) {
- if ( tabIdToTimer[tabId] ) {
+ return function (tabId) {
+ if (tabIdToTimer[tabId]) {
return;
}
- if ( vAPI.isBehindTheSceneTabId(tabId) ) {
+
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
return;
}
- tabIdToTimer[tabId] = vAPI.setTimeout(updateBadge.bind(this, tabId), 750);
+
+ tabIdToTimer[tabId] =
+ vAPI.setTimeout(updateBadge.bind(this, tabId), 750);
};
})();
- /******************************************************************************/
+ ηm.updateTitle = (function () {
+ let tabIdToTimer = Object.create(null);
+ let tabIdToTryCount = Object.create(null);
+ let delay = 499;
- ηm.updateTitle = (function() {
- var tabIdToTimer = Object.create(null);
- var tabIdToTryCount = Object.create(null);
- var delay = 499;
-
- var tryNoMore = function(tabId) {
+ let tryNoMore = function (tabId) {
delete tabIdToTryCount[tabId];
};
- var tryAgain = function(tabId) {
- var count = tabIdToTryCount[tabId];
- if ( count === undefined ) {
+ let tryAgain = function (tabId) {
+ let count = tabIdToTryCount[tabId];
+ if (count === undefined) {
return false;
}
- if ( count === 1 ) {
+
+ if (count === 1) {
delete tabIdToTryCount[tabId];
return false;
}
+
tabIdToTryCount[tabId] = count - 1;
- tabIdToTimer[tabId] = vAPI.setTimeout(updateTitle.bind(ηm, tabId), delay);
+ tabIdToTimer[tabId] =
+ vAPI.setTimeout(updateTitle.bind(ηm, tabId), delay);
return true;
};
- var onTabReady = function(tabId, tab) {
- if ( !tab ) {
+ let onTabReady = function (tabId, tab) {
+ if (!tab) {
return tryNoMore(tabId);
}
- var pageStore = this.pageStoreFromTabId(tabId);
- if ( pageStore === null ) {
+
+ let pageStore = this.pageStoreFromTabId(tabId);
+ if (pageStore === null) {
return tryNoMore(tabId);
}
- if ( !tab.title && tryAgain(tabId) ) {
+
+ if (!tab.title && tryAgain(tabId)) {
return;
}
+
// https://github.com/gorhill/uMatrix/issues/225
// Sometimes title changes while page is loading.
- var settled = tab.title && tab.title === pageStore.title;
+ let settled = tab.title && tab.title === pageStore.title;
pageStore.title = tab.title || tab.url || '';
this.pageStoresToken = Date.now();
- if ( settled || !tryAgain(tabId) ) {
+ if (settled || !tryAgain(tabId)) {
tryNoMore(tabId);
}
};
- var updateTitle = function(tabId) {
+ let updateTitle = function (tabId) {
delete tabIdToTimer[tabId];
vAPI.tabs.get(tabId, onTabReady.bind(this, tabId));
};
- return function(tabId) {
- if ( vAPI.isBehindTheSceneTabId(tabId) ) {
+ return function (tabId) {
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
return;
}
- if ( tabIdToTimer[tabId] ) {
+
+ if (tabIdToTimer[tabId]) {
clearTimeout(tabIdToTimer[tabId]);
}
- tabIdToTimer[tabId] = vAPI.setTimeout(updateTitle.bind(this, tabId), delay);
+
+ tabIdToTimer[tabId] =
+ vAPI.setTimeout(updateTitle.bind(this, tabId), delay);
tabIdToTryCount[tabId] = 5;
};
})();
- /******************************************************************************/
-
// Stale page store entries janitor
// https://github.com/chrisaljoudi/uBlock/issues/455
- (function() {
- var cleanupPeriod = 7 * 60 * 1000;
- var cleanupSampleAt = 0;
- var cleanupSampleSize = 11;
-
- var cleanup = function() {
- var vapiTabs = vAPI.tabs;
- var tabIds = Object.keys(ηm.pageStores).sort();
- var checkTab = function(tabId) {
- vapiTabs.get(tabId, function(tab) {
- if ( !tab ) {
+ (function () {
+ let cleanupPeriod = 7 * 60 * 1000;
+ let cleanupSampleAt = 0;
+ let cleanupSampleSize = 11;
+
+ let cleanup = function () {
+ let tabIds = Object.keys(ηm.pageStores).sort();
+ let checkTab = function(tabId) {
+ vAPI.tabs.get(tabId, function (tab) {
+ if (!tab) {
ηm.unbindTabFromPageStats(tabId);
}
});
};
- if ( cleanupSampleAt >= tabIds.length ) {
+ if (cleanupSampleAt >= tabIds.length) {
cleanupSampleAt = 0;
}
- var tabId;
- var n = Math.min(cleanupSampleAt + cleanupSampleSize, tabIds.length);
- for ( var i = cleanupSampleAt; i < n; i++ ) {
+
+ let tabId;
+ let n =
+ Math.min(cleanupSampleAt + cleanupSampleSize, tabIds.length);
+
+ for (let i=cleanupSampleAt; i<n; i++) {
tabId = tabIds[i];
- if ( vAPI.isBehindTheSceneTabId(tabId) ) {
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
continue;
}
checkTab(tabId);
@@ -714,7 +751,4 @@ housekeep itself.
vAPI.setTimeout(cleanup, cleanupPeriod);
})();
-
- /******************************************************************************/
-
})();