2017-03-14 23:27:52 +00:00
|
|
|
// keep message channel open for sendResponse in chrome.runtime.onMessage listener
|
|
|
|
const KEEP_CHANNEL_OPEN = true;
|
2017-03-15 11:55:20 +00:00
|
|
|
const OWN_ORIGIN = chrome.runtime.getURL('');
|
2017-03-14 23:27:52 +00:00
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
2012-04-16 01:56:12 +00:00
|
|
|
function notifyAllTabs(request) {
|
2017-03-15 17:15:32 +00:00
|
|
|
// list all tabs including chrome-extension:// which can be ours
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
if (request.codeIsUpdated === false && request.style) {
|
|
|
|
request = Object.assign({}, request, {
|
|
|
|
style: getStyleWithNoCode(request.style)
|
|
|
|
});
|
|
|
|
}
|
2017-03-15 17:15:32 +00:00
|
|
|
chrome.tabs.query({}, tabs => {
|
|
|
|
for (let tab of tabs) {
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
chrome.tabs.sendMessage(tab.id, request);
|
|
|
|
updateIcon(tab);
|
2017-03-15 17:15:32 +00:00
|
|
|
}
|
2012-04-16 01:56:12 +00:00
|
|
|
});
|
2015-04-07 17:07:45 +00:00
|
|
|
// notify all open popups
|
2017-03-15 11:58:59 +00:00
|
|
|
const reqPopup = Object.assign({}, request, {method: 'updatePopup', reason: request.method});
|
2016-01-30 23:08:10 +00:00
|
|
|
chrome.runtime.sendMessage(reqPopup);
|
2017-03-14 12:18:58 +00:00
|
|
|
// notify self: the message no longer is sent to the origin in new Chrome
|
|
|
|
if (typeof applyOnMessage !== 'undefined') {
|
|
|
|
applyOnMessage(reqPopup);
|
|
|
|
}
|
2017-03-18 22:35:27 +00:00
|
|
|
// notify self: pref changed by background page
|
|
|
|
if (request.method == 'prefChanged' && typeof onBackgroundMessage !== 'undefined') {
|
|
|
|
onBackgroundMessage(request);
|
|
|
|
}
|
2012-04-16 01:56:12 +00:00
|
|
|
}
|
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
2017-03-14 23:27:52 +00:00
|
|
|
function refreshAllTabs() {
|
|
|
|
return new Promise(resolve => {
|
2017-03-15 17:15:32 +00:00
|
|
|
// list all tabs including chrome-extension:// which can be ours
|
|
|
|
chrome.tabs.query({}, tabs => {
|
|
|
|
const lastTab = tabs[tabs.length - 1];
|
|
|
|
for (let tab of tabs) {
|
|
|
|
getStyles({matchUrl: tab.url, enabled: true, asHash: true}, styles => {
|
|
|
|
const message = {method: 'styleReplaceAll', styles};
|
|
|
|
if (tab.url == location.href && typeof applyOnMessage !== 'undefined') {
|
|
|
|
applyOnMessage(message);
|
|
|
|
} else {
|
|
|
|
chrome.tabs.sendMessage(tab.id, message);
|
|
|
|
}
|
|
|
|
updateIcon(tab, styles);
|
|
|
|
if (tab == lastTab) {
|
|
|
|
resolve();
|
|
|
|
}
|
2017-03-14 23:27:52 +00:00
|
|
|
});
|
2017-03-15 17:15:32 +00:00
|
|
|
}
|
2017-03-14 23:27:52 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
2015-05-14 21:24:10 +00:00
|
|
|
function updateIcon(tab, styles) {
|
2015-05-21 09:34:44 +00:00
|
|
|
// while NTP is still loading only process the request for its main frame with a real url
|
|
|
|
// (but when it's loaded we should process style toggle requests from popups, for example)
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
if (tab.url == 'chrome://newtab/' && tab.status != 'complete') {
|
2015-05-21 09:34:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-05-14 21:24:10 +00:00
|
|
|
if (styles) {
|
|
|
|
// check for not-yet-existing tabs e.g. omnibox instant search
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
chrome.tabs.get(tab.id, () => {
|
2015-05-14 21:24:10 +00:00
|
|
|
if (!chrome.runtime.lastError) {
|
|
|
|
stylesReceived(styles);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2017-03-21 01:32:38 +00:00
|
|
|
getTabRealURL(tab).then(url => {
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
// if we have access to this, call directly
|
|
|
|
// (Chrome no longer sends messages to the page itself)
|
|
|
|
const options = {method: 'getStyles', matchUrl: url, enabled: true, asHash: true};
|
|
|
|
if (typeof getStyles != 'undefined') {
|
|
|
|
getStyles(options, stylesReceived);
|
2015-05-21 09:34:44 +00:00
|
|
|
} else {
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
chrome.runtime.sendMessage(options, stylesReceived);
|
2015-05-21 09:34:44 +00:00
|
|
|
}
|
|
|
|
});
|
2012-04-16 01:56:12 +00:00
|
|
|
|
2015-05-14 21:24:10 +00:00
|
|
|
function stylesReceived(styles) {
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
let numStyles = styles.length;
|
|
|
|
if (numStyles === undefined) {
|
|
|
|
// for 'styles' asHash:true fake the length by counting numeric ids manually
|
|
|
|
numStyles = 0;
|
|
|
|
for (let id of Object.keys(styles)) {
|
|
|
|
numStyles += id.match(/^\d+$/) ? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const disableAll = 'disableAll' in styles ? styles.disableAll : prefs.get('disableAll');
|
|
|
|
const postfix = disableAll ? 'x' : numStyles == 0 ? 'w' : '';
|
2015-05-14 21:24:10 +00:00
|
|
|
chrome.browserAction.setIcon({
|
2016-08-22 11:01:27 +00:00
|
|
|
path: {
|
|
|
|
// Material Design 2016 new size is 16px
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
16: '16' + postfix + '.png', 32: '32' + postfix + '.png',
|
2016-08-22 11:01:27 +00:00
|
|
|
// Chromium forks or non-chromium browsers may still use the traditional 19px
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
19: '19' + postfix + '.png', 38: '38' + postfix + '.png',
|
2016-08-22 11:01:27 +00:00
|
|
|
},
|
2015-05-14 21:24:10 +00:00
|
|
|
tabId: tab.id
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
}, () => {
|
2015-10-11 14:09:49 +00:00
|
|
|
// if the tab was just closed an error may occur,
|
|
|
|
// e.g. 'windowPosition' pref updated in edit.js::window.onbeforeunload
|
|
|
|
if (!chrome.runtime.lastError) {
|
Improve style caching, cache requests too, add code:false mode
Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
2017-03-17 22:50:35 +00:00
|
|
|
const text = prefs.get('show-badge') && numStyles ? String(numStyles) : '';
|
|
|
|
chrome.browserAction.setBadgeText({text, tabId: tab.id});
|
2017-02-14 15:35:53 +00:00
|
|
|
chrome.browserAction.setBadgeBackgroundColor({
|
|
|
|
color: prefs.get(disableAll ? 'badgeDisabled' : 'badgeNormal')
|
|
|
|
});
|
2015-10-11 14:09:49 +00:00
|
|
|
}
|
2015-05-14 21:24:10 +00:00
|
|
|
});
|
|
|
|
}
|
2012-04-16 01:56:12 +00:00
|
|
|
}
|
2015-05-21 09:34:44 +00:00
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
|
|
|
function getActiveTab() {
|
|
|
|
return new Promise(resolve =>
|
|
|
|
chrome.tabs.query({currentWindow: true, active: true}, tabs =>
|
|
|
|
resolve(tabs[0])));
|
2015-05-21 09:34:44 +00:00
|
|
|
}
|
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
|
|
|
function getActiveTabRealURL() {
|
|
|
|
return getActiveTab()
|
|
|
|
.then(getTabRealURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getTabRealURL(tab) {
|
|
|
|
return new Promise(resolve => {
|
|
|
|
if (tab.url != 'chrome://newtab/') {
|
|
|
|
resolve(tab.url);
|
|
|
|
} else {
|
|
|
|
chrome.webNavigation.getFrame({tabId: tab.id, frameId: 0, processId: -1}, frame => {
|
|
|
|
frame && resolve(frame.url);
|
|
|
|
});
|
|
|
|
}
|
2015-05-21 09:34:44 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
|
|
|
function openURL({url}) {
|
|
|
|
url = !url.includes('://') ? chrome.runtime.getURL(url) : url;
|
|
|
|
return new Promise(resolve => {
|
|
|
|
chrome.tabs.query({currentWindow: true, url}, tabs => {
|
|
|
|
// switch to an existing tab with the requested url
|
|
|
|
if (tabs.length) {
|
|
|
|
chrome.tabs.highlight({
|
|
|
|
windowId: tabs[0].windowId,
|
|
|
|
tabs: tabs[0].index,
|
|
|
|
}, resolve);
|
|
|
|
} else {
|
|
|
|
// re-use an active new tab page
|
|
|
|
getActiveTab().then(tab =>
|
|
|
|
tab && tab.url == 'chrome://newtab/'
|
|
|
|
? chrome.tabs.update({url}, resolve)
|
|
|
|
: chrome.tabs.create({url}, resolve)
|
|
|
|
);
|
|
|
|
}
|
2015-05-21 09:34:44 +00:00
|
|
|
});
|
2017-03-21 01:32:38 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onDOMready() {
|
|
|
|
if (document.readyState != 'loading') {
|
|
|
|
return Promise.resolve();
|
2015-07-24 11:36:43 +00:00
|
|
|
}
|
2017-03-21 01:32:38 +00:00
|
|
|
return new Promise(resolve => {
|
|
|
|
document.addEventListener('DOMContentLoaded', function _() {
|
|
|
|
document.removeEventListener('DOMContentLoaded', _);
|
|
|
|
resolve();
|
|
|
|
});
|
|
|
|
});
|
2015-05-21 09:34:44 +00:00
|
|
|
}
|
2017-03-15 12:41:39 +00:00
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
2017-03-15 12:41:39 +00:00
|
|
|
function stringAsRegExp(s, flags) {
|
2017-03-21 01:32:38 +00:00
|
|
|
return new RegExp(s.replace(/[{}()\[\]\/\\.+?^$:=*!|]/g, '\\$&'), flags);
|
2017-03-15 12:41:39 +00:00
|
|
|
}
|
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
2017-03-15 12:41:39 +00:00
|
|
|
// expands * as .*?
|
|
|
|
function wildcardAsRegExp(s, flags) {
|
2017-03-21 01:32:38 +00:00
|
|
|
return new RegExp(s.replace(/[{}()\[\]\/\\.+?^$:=!|]/g, '\\$&').replace(/\*/g, '.*?'), flags);
|
2017-03-15 12:41:39 +00:00
|
|
|
}
|
2017-03-16 13:36:33 +00:00
|
|
|
|
2017-03-21 01:32:38 +00:00
|
|
|
|
2017-03-22 07:07:34 +00:00
|
|
|
// isolate deoptimization trigger:
|
|
|
|
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
|
|
|
|
// * Functions that contain object literals that contain __proto__, or get or set declarations.
|
|
|
|
const configureCommands = (() => ({
|
2017-03-16 13:36:33 +00:00
|
|
|
get url () {
|
|
|
|
return navigator.userAgent.indexOf('OPR') > -1 ?
|
|
|
|
'opera://settings/configureCommands' :
|
|
|
|
'chrome://extensions/configureCommands'
|
|
|
|
},
|
|
|
|
open: () => {
|
|
|
|
chrome.tabs.create({
|
|
|
|
'url': configureCommands.url
|
|
|
|
});
|
|
|
|
}
|
2017-03-22 07:07:34 +00:00
|
|
|
}))();
|