Enhance: promisify chrome into browser, drop promisify (#866)
				
					
				
			* promisify `chrome` into `browser` * comment * comment * comment * Add: a naive browser polyfill * Fix: polyfill doesn't detect content script env correctly Co-authored-by: eight04 <eight04@gmail.com>
This commit is contained in:
		
							parent
							
								
									3d94c641b3
								
							
						
					
					
						commit
						54b1f218e0
					
				|  | @ -1,7 +1,7 @@ | ||||||
| /* global download prefs openURL FIREFOX CHROME | /* global download prefs openURL FIREFOX CHROME | ||||||
|   URLS ignoreChromeError usercssHelper |   URLS ignoreChromeError usercssHelper | ||||||
|   styleManager msg navigatorUtil workerUtil contentScripts sync |   styleManager msg navigatorUtil workerUtil contentScripts sync | ||||||
|   findExistingTab createTab activateTab isTabReplaceable getActiveTab |   findExistingTab activateTab isTabReplaceable getActiveTab | ||||||
|   tabManager */ |   tabManager */ | ||||||
| 
 | 
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
|  | @ -336,7 +336,7 @@ function openManage({options = false, search} = {}) { | ||||||
|         if (isTabReplaceable(tab, url)) { |         if (isTabReplaceable(tab, url)) { | ||||||
|           return activateTab(tab, {url}); |           return activateTab(tab, {url}); | ||||||
|         } |         } | ||||||
|         return createTab({url}); |         return browser.tabs.create({url}); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| /* global msg queryTabs ignoreChromeError URLS */ | /* global msg ignoreChromeError URLS */ | ||||||
| /* exported contentScripts */ | /* exported contentScripts */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
|  | @ -55,7 +55,7 @@ const contentScripts = (() => { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function injectToAllTabs() { |   function injectToAllTabs() { | ||||||
|     return queryTabs({}).then(tabs => { |     return browser.tabs.query({}).then(tabs => { | ||||||
|       for (const tab of tabs) { |       for (const tab of tabs) { | ||||||
|         // skip unloaded/discarded/chrome tabs
 |         // skip unloaded/discarded/chrome tabs
 | ||||||
|         if (!tab.width || tab.discarded || !URLS.supported(tab.url)) continue; |         if (!tab.width || tab.discarded || !URLS.supported(tab.url)) continue; | ||||||
|  |  | ||||||
|  | @ -1,46 +1,29 @@ | ||||||
| /* global promisify */ | /* global chromeLocal */ | ||||||
| /* exported createChromeStorageDB */ | /* exported createChromeStorageDB */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| function createChromeStorageDB() { | function createChromeStorageDB() { | ||||||
|   const get = promisify(chrome.storage.local.get.bind(chrome.storage.local)); |  | ||||||
|   const set = promisify(chrome.storage.local.set.bind(chrome.storage.local)); |  | ||||||
|   const remove = promisify(chrome.storage.local.remove.bind(chrome.storage.local)); |  | ||||||
| 
 |  | ||||||
|   let INC; |   let INC; | ||||||
| 
 | 
 | ||||||
|   const PREFIX = 'style-'; |   const PREFIX = 'style-'; | ||||||
|   const METHODS = { |   const METHODS = { | ||||||
|     // FIXME: we don't use this method at all. Should we remove this?
 |     // FIXME: we don't use this method at all. Should we remove this?
 | ||||||
|     get: id => get(PREFIX + id) |     get: id => chromeLocal.getValue(PREFIX + id), | ||||||
|       .then(result => result[PREFIX + id]), |     put: obj => | ||||||
|     put: obj => Promise.resolve() |       // FIXME: should we clone the object?
 | ||||||
|       .then(() => { |       Promise.resolve(!obj.id && prepareInc().then(() => Object.assign(obj, {id: INC++}))) | ||||||
|         if (!obj.id) { |         .then(() => chromeLocal.setValue(PREFIX + obj.id, obj)) | ||||||
|           return prepareInc() |         .then(() => obj.id), | ||||||
|             .then(() => { |  | ||||||
|               // FIXME: should we clone the object?
 |  | ||||||
|               obj.id = INC++; |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|       .then(() => set({[PREFIX + obj.id]: obj})) |  | ||||||
|       .then(() => obj.id), |  | ||||||
|     putMany: items => prepareInc() |     putMany: items => prepareInc() | ||||||
|       .then(() => { |       .then(() => | ||||||
|         for (const item of items) { |         chromeLocal.set(items.reduce((data, item) => { | ||||||
|           if (!item.id) { |           if (!item.id) item.id = INC++; | ||||||
|             item.id = INC++; |           data[PREFIX + item.id] = item; | ||||||
|           } |           return data; | ||||||
|         } |         }, {}))) | ||||||
|         return set(items.reduce((obj, curr) => { |  | ||||||
|           obj[PREFIX + curr.id] = curr; |  | ||||||
|           return obj; |  | ||||||
|         }, {})); |  | ||||||
|       }) |  | ||||||
|       .then(() => items.map(i => i.id)), |       .then(() => items.map(i => i.id)), | ||||||
|     delete: id => remove(PREFIX + id), |     delete: id => chromeLocal.remove(PREFIX + id), | ||||||
|     getAll: () => get(null) |     getAll: () => chromeLocal.get() | ||||||
|       .then(result => { |       .then(result => { | ||||||
|         const output = []; |         const output = []; | ||||||
|         for (const key in result) { |         for (const key in result) { | ||||||
|  | @ -69,7 +52,7 @@ function createChromeStorageDB() { | ||||||
| 
 | 
 | ||||||
|   function prepareInc() { |   function prepareInc() { | ||||||
|     if (INC) return Promise.resolve(); |     if (INC) return Promise.resolve(); | ||||||
|     return get(null).then(result => { |     return chromeLocal.get().then(result => { | ||||||
|       INC = 1; |       INC = 1; | ||||||
|       for (const key in result) { |       for (const key in result) { | ||||||
|         if (key.startsWith(PREFIX)) { |         if (key.startsWith(PREFIX)) { | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| /* global promisify CHROME URLS */ | /* global CHROME URLS */ | ||||||
| /* exported navigatorUtil */ | /* exported navigatorUtil */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
|  | @ -6,7 +6,6 @@ const navigatorUtil = (() => { | ||||||
|   const handler = { |   const handler = { | ||||||
|     urlChange: null |     urlChange: null | ||||||
|   }; |   }; | ||||||
|   const tabGet = promisify(chrome.tabs.get.bind(chrome.tabs)); |  | ||||||
|   return extendNative({onUrlChange}); |   return extendNative({onUrlChange}); | ||||||
| 
 | 
 | ||||||
|   function onUrlChange(fn) { |   function onUrlChange(fn) { | ||||||
|  | @ -48,7 +47,7 @@ const navigatorUtil = (() => { | ||||||
|     ) { |     ) { | ||||||
|       return Promise.resolve(); |       return Promise.resolve(); | ||||||
|     } |     } | ||||||
|     return tabGet(data.tabId) |     return browser.tabs.get(data.tabId) | ||||||
|       .then(tab => { |       .then(tab => { | ||||||
|         if (tab.url === 'chrome://newtab/') { |         if (tab.url === 'chrome://newtab/') { | ||||||
|           data.url = tab.url; |           data.url = tab.url; | ||||||
|  |  | ||||||
|  | @ -1,9 +1,11 @@ | ||||||
| /* global chromeLocal promisify FIREFOX */ | /* global chromeLocal promisifyChrome FIREFOX */ | ||||||
| /* exported tokenManager */ | /* exported tokenManager */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| const tokenManager = (() => { | const tokenManager = (() => { | ||||||
|   const launchWebAuthFlow = promisify(chrome.identity.launchWebAuthFlow.bind(chrome.identity)); |   promisifyChrome({ | ||||||
|  |     identity: ['launchWebAuthFlow'], | ||||||
|  |   }); | ||||||
|   const AUTH = { |   const AUTH = { | ||||||
|     dropbox: { |     dropbox: { | ||||||
|       flow: 'token', |       flow: 'token', | ||||||
|  | @ -158,7 +160,7 @@ const tokenManager = (() => { | ||||||
|       Object.assign(query, provider.authQuery); |       Object.assign(query, provider.authQuery); | ||||||
|     } |     } | ||||||
|     const url = `${provider.authURL}?${stringifyQuery(query)}`; |     const url = `${provider.authURL}?${stringifyQuery(query)}`; | ||||||
|     return launchWebAuthFlow({ |     return browser.identity.launchWebAuthFlow({ | ||||||
|       url, |       url, | ||||||
|       interactive |       interactive | ||||||
|     }) |     }) | ||||||
|  |  | ||||||
|  | @ -1,8 +1,7 @@ | ||||||
| /* global API_METHODS usercss styleManager deepCopy openURL download URLS getTab */ | /* global API_METHODS usercss styleManager deepCopy openURL download URLS */ | ||||||
| /* exports usercssHelper */ | /* exported usercssHelper */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| // eslint-disable-next-line no-unused-vars
 |  | ||||||
| const usercssHelper = (() => { | const usercssHelper = (() => { | ||||||
|   const installCodeCache = {}; |   const installCodeCache = {}; | ||||||
|   const clearInstallCode = url => delete installCodeCache[url]; |   const clearInstallCode = url => delete installCodeCache[url]; | ||||||
|  | @ -46,7 +45,7 @@ const usercssHelper = (() => { | ||||||
|     openInstallerPage(tabId, url, {code, inTab} = {}) { |     openInstallerPage(tabId, url, {code, inTab} = {}) { | ||||||
|       const newUrl = `${URLS.installUsercss}?updateUrl=${encodeURIComponent(url)}`; |       const newUrl = `${URLS.installUsercss}?updateUrl=${encodeURIComponent(url)}`; | ||||||
|       if (inTab) { |       if (inTab) { | ||||||
|         getTab(tabId).then(tab => |         browser.tabs.get(tabId).then(tab => | ||||||
|           openURL({ |           openURL({ | ||||||
|             url: `${newUrl}&tabId=${tabId}`, |             url: `${newUrl}&tabId=${tabId}`, | ||||||
|             active: tab.active, |             active: tab.active, | ||||||
|  |  | ||||||
|  | @ -64,7 +64,6 @@ | ||||||
|     <script src="vendor-overwrites/codemirror-addon/match-highlighter.js"></script> |     <script src="vendor-overwrites/codemirror-addon/match-highlighter.js"></script> | ||||||
| 
 | 
 | ||||||
|     <script src="js/polyfill.js"></script> |     <script src="js/polyfill.js"></script> | ||||||
|     <script src="js/promisify.js"></script> |  | ||||||
|     <script src="js/dom.js"></script> |     <script src="js/dom.js"></script> | ||||||
|     <script src="js/messaging.js"></script> |     <script src="js/messaging.js"></script> | ||||||
|     <script src="js/prefs.js"></script> |     <script src="js/prefs.js"></script> | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* global CodeMirror onDOMready prefs setupLivePrefs $ $$ $create t tHTML | /* global CodeMirror onDOMready prefs setupLivePrefs $ $$ $create t tHTML | ||||||
|   createSourceEditor queryTabs sessionStorageHash getOwnTab FIREFOX API tryCatch |   createSourceEditor sessionStorageHash getOwnTab FIREFOX API tryCatch | ||||||
|   closeCurrentTab messageBox debounce workerUtil |   closeCurrentTab messageBox debounce workerUtil | ||||||
|   initBeautifyButton ignoreChromeError |   initBeautifyButton ignoreChromeError | ||||||
|   moveFocus msg createSectionsEditor rerouteHotkeys CODEMIRROR_THEMES */ |   moveFocus msg createSectionsEditor rerouteHotkeys CODEMIRROR_THEMES */ | ||||||
|  | @ -226,7 +226,7 @@ function preinit() { | ||||||
|   }).observe(document, {subtree: true, childList: true}); |   }).observe(document, {subtree: true, childList: true}); | ||||||
| 
 | 
 | ||||||
|   if (chrome.windows) { |   if (chrome.windows) { | ||||||
|     queryTabs({currentWindow: true}).then(tabs => { |     browser.tabs.query({currentWindow: true}).then(tabs => { | ||||||
|       const windowId = tabs[0].windowId; |       const windowId = tabs[0].windowId; | ||||||
|       if (prefs.get('openEditInWindow')) { |       if (prefs.get('openEditInWindow')) { | ||||||
|         if ( |         if ( | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| /* global CodeMirror focusAccessibility colorMimicry editor | /* global CodeMirror focusAccessibility colorMimicry editor chromeLocal | ||||||
|   onDOMready $ $$ $create t debounce tryRegExp stringAsRegExp template */ |   onDOMready $ $$ $create t debounce tryRegExp stringAsRegExp template */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
|  | @ -915,7 +915,7 @@ onDOMready().then(() => { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|   function readStorage() { |   function readStorage() { | ||||||
|     chrome.storage.local.get('editor', ({editor = {}}) => { |     chromeLocal.getValue('editor').then((editor = {}) => { | ||||||
|       state.find = editor.find || ''; |       state.find = editor.find || ''; | ||||||
|       state.replace = editor.replace || ''; |       state.replace = editor.replace || ''; | ||||||
|       state.icase = editor.icase || state.icase; |       state.icase = editor.icase || state.icase; | ||||||
|  | @ -924,14 +924,12 @@ onDOMready().then(() => { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|   function writeStorage() { |   function writeStorage() { | ||||||
|     chrome.storage.local.get('editor', ({editor}) => |     chromeLocal.getValue('editor').then((editor = {}) => | ||||||
|       chrome.storage.local.set({ |       chromeLocal.setValue('editor', Object.assign(editor, { | ||||||
|         editor: Object.assign(editor || {}, { |         find: state.find, | ||||||
|           find: state.find, |         replace: state.replace, | ||||||
|           replace: state.replace, |         icase: state.icase, | ||||||
|           icase: state.icase, |       }))); | ||||||
|         }) |  | ||||||
|       })); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| /* global showHelp $ $create tryRegExp queryTabs URLS t template openURL */ | /* global showHelp $ $create tryRegExp URLS t template openURL */ | ||||||
| /* exported regExpTester */ | /* exported regExpTester */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
|  | @ -66,7 +66,7 @@ const regExpTester = (() => { | ||||||
|       return rxData; |       return rxData; | ||||||
|     }); |     }); | ||||||
|     const getMatchInfo = m => m && {text: m[0], pos: m.index}; |     const getMatchInfo = m => m && {text: m[0], pos: m.index}; | ||||||
|     queryTabs({}).then(tabs => { |     browser.tabs.query({}).then(tabs => { | ||||||
|       const supported = tabs.map(tab => tab.url) |       const supported = tabs.map(tab => tab.url) | ||||||
|         .filter(url => URLS.supported(url)); |         .filter(url => URLS.supported(url)); | ||||||
|       const unique = [...new Set(supported).values()]; |       const unique = [...new Set(supported).values()]; | ||||||
|  |  | ||||||
|  | @ -10,7 +10,6 @@ | ||||||
|   <link href="install-usercss/install-usercss.css" rel="stylesheet"> |   <link href="install-usercss/install-usercss.css" rel="stylesheet"> | ||||||
| 
 | 
 | ||||||
|   <script src="js/polyfill.js"></script> |   <script src="js/polyfill.js"></script> | ||||||
|   <script src="js/promisify.js"></script> |  | ||||||
|   <script src="js/msg.js"></script> |   <script src="js/msg.js"></script> | ||||||
|   <script src="js/messaging.js"></script> |   <script src="js/messaging.js"></script> | ||||||
|   <script src="js/prefs.js"></script> |   <script src="js/prefs.js"></script> | ||||||
|  |  | ||||||
|  | @ -394,13 +394,9 @@ | ||||||
|         } |         } | ||||||
|       }); |       }); | ||||||
|       port.onDisconnect.addListener(() => { |       port.onDisconnect.addListener(() => { | ||||||
|         chrome.tabs.get(tabId, tab => { |         browser.tabs.get(tabId) | ||||||
|           if (chrome.runtime.lastError) { |           .then(tab => tab.url === initialUrl && location.reload()) | ||||||
|             closeCurrentTab(); |           .catch(closeCurrentTab); | ||||||
|           } else if (tab.url === initialUrl) { |  | ||||||
|             location.reload(); |  | ||||||
|           } |  | ||||||
|         }); |  | ||||||
|       }); |       }); | ||||||
|       return ({timer = true} = {}) => new Promise((resolve, reject) => { |       return ({timer = true} = {}) => new Promise((resolve, reject) => { | ||||||
|         const id = performance.now(); |         const id = performance.now(); | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| /* exported getTab getActiveTab onTabReady stringAsRegExp openURL ignoreChromeError | /* exported getTab getActiveTab onTabReady stringAsRegExp openURL ignoreChromeError | ||||||
|   getStyleWithNoCode tryRegExp sessionStorageHash download deepEqual |   getStyleWithNoCode tryRegExp sessionStorageHash download deepEqual | ||||||
|   closeCurrentTab capitalize CHROME_HAS_BORDER_BUG */ |   closeCurrentTab capitalize CHROME_HAS_BORDER_BUG */ | ||||||
| /* global promisify */ | /* global promisifyChrome */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| const CHROME = Boolean(chrome.app) && parseInt(navigator.userAgent.match(/Chrom\w+\/(\d+)|$/)[1]); | const CHROME = Boolean(chrome.app) && parseInt(navigator.userAgent.match(/Chrom\w+\/(\d+)|$/)[1]); | ||||||
|  | @ -93,33 +93,20 @@ if (IS_BG) { | ||||||
| // Object.defineProperty(window, 'localStorage', {value: {}});
 | // Object.defineProperty(window, 'localStorage', {value: {}});
 | ||||||
| // Object.defineProperty(window, 'sessionStorage', {value: {}});
 | // Object.defineProperty(window, 'sessionStorage', {value: {}});
 | ||||||
| 
 | 
 | ||||||
| const createTab = promisify(chrome.tabs.create.bind(chrome.tabs)); | promisifyChrome({ | ||||||
| const queryTabs = promisify(chrome.tabs.query.bind(chrome.tabs)); |   tabs: ['create', 'get', 'getCurrent', 'move', 'query', 'update'], | ||||||
| const updateTab = promisify(chrome.tabs.update.bind(chrome.tabs)); |   windows: ['create', 'update'], // Android doesn't have chrome.windows
 | ||||||
| const moveTabs = promisify(chrome.tabs.move.bind(chrome.tabs)); | }); | ||||||
| 
 |  | ||||||
| // Android doesn't have chrome.windows
 |  | ||||||
| const updateWindow = chrome.windows && promisify(chrome.windows.update.bind(chrome.windows)); |  | ||||||
| const createWindow = chrome.windows && promisify(chrome.windows.create.bind(chrome.windows)); |  | ||||||
| // FF57+ supports openerTabId, but not in Android
 | // FF57+ supports openerTabId, but not in Android
 | ||||||
| // (detecting FF57 by the feature it added, not navigator.ua which may be spoofed in about:config)
 | // (detecting FF57 by the feature it added, not navigator.ua which may be spoofed in about:config)
 | ||||||
| const openerTabIdSupported = (!FIREFOX || window.AbortController) && chrome.windows != null; | const openerTabIdSupported = (!FIREFOX || window.AbortController) && chrome.windows != null; | ||||||
| 
 | 
 | ||||||
| function getTab(id) { |  | ||||||
|   return new Promise(resolve => |  | ||||||
|     chrome.tabs.get(id, tab => |  | ||||||
|       !chrome.runtime.lastError && resolve(tab))); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function getOwnTab() { | function getOwnTab() { | ||||||
|   return new Promise(resolve => |   return browser.tabs.getCurrent(); | ||||||
|     chrome.tabs.getCurrent(tab => resolve(tab))); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| function getActiveTab() { | function getActiveTab() { | ||||||
|   return queryTabs({currentWindow: true, active: true}) |   return browser.tabs.query({currentWindow: true, active: true}) | ||||||
|     .then(tabs => tabs[0]); |     .then(tabs => tabs[0]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -140,7 +127,7 @@ function urlToMatchPattern(url, ignoreSearch) { | ||||||
| 
 | 
 | ||||||
| function findExistingTab({url, currentWindow, ignoreHash = true, ignoreSearch = false}) { | function findExistingTab({url, currentWindow, ignoreHash = true, ignoreSearch = false}) { | ||||||
|   url = new URL(url); |   url = new URL(url); | ||||||
|   return queryTabs({url: urlToMatchPattern(url, ignoreSearch), currentWindow}) |   return browser.tabs.query({url: urlToMatchPattern(url, ignoreSearch), currentWindow}) | ||||||
|     // FIXME: is tab.url always normalized?
 |     // FIXME: is tab.url always normalized?
 | ||||||
|     .then(tabs => tabs.find(matchTab)); |     .then(tabs => tabs.find(matchTab)); | ||||||
| 
 | 
 | ||||||
|  | @ -191,8 +178,8 @@ function openURL({ | ||||||
|         url: url !== tab.url && url.includes('#') ? url : undefined, |         url: url !== tab.url && url.includes('#') ? url : undefined, | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|     if (newWindow && createWindow) { |     if (newWindow && browser.windows) { | ||||||
|       return createWindow(Object.assign({url}, windowPosition)) |       return browser.windows.create(Object.assign({url}, windowPosition)) | ||||||
|         .then(wnd => wnd.tabs[0]); |         .then(wnd => wnd.tabs[0]); | ||||||
|     } |     } | ||||||
|     return getActiveTab().then((activeTab = {url: ''}) => |     return getActiveTab().then((activeTab = {url: ''}) => | ||||||
|  | @ -205,7 +192,7 @@ function openURL({ | ||||||
|     if (id != null && !openerTab.incognito && openerTabIdSupported) { |     if (id != null && !openerTab.incognito && openerTabIdSupported) { | ||||||
|       options.openerTabId = id; |       options.openerTabId = id; | ||||||
|     } |     } | ||||||
|     return createTab(options); |     return browser.tabs.create(options); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -232,9 +219,9 @@ function activateTab(tab, {url, index, openerTabId} = {}) { | ||||||
|     options.openerTabId = openerTabId; |     options.openerTabId = openerTabId; | ||||||
|   } |   } | ||||||
|   return Promise.all([ |   return Promise.all([ | ||||||
|     updateTab(tab.id, options), |     browser.tabs.update(tab.id, options), | ||||||
|     updateWindow && updateWindow(tab.windowId, {focused: true}), |     browser.windows && browser.windows.update(tab.windowId, {focused: true}), | ||||||
|     index != null && moveTabs(tab.id, {index}) |     index != null && browser.tabs.move(tab.id, {index}) | ||||||
|   ]) |   ]) | ||||||
|     .then(() => tab); |     .then(() => tab); | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										24
									
								
								js/msg.js
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								js/msg.js
									
									
									
									
									
								
							|  | @ -1,12 +1,12 @@ | ||||||
| /* global promisify deepCopy */ | /* global promisifyChrome deepCopy */ | ||||||
| // deepCopy is only used if the script is executed in extension pages.
 | // deepCopy is only used if the script is executed in extension pages.
 | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| self.msg = self.INJECTED === 1 ? self.msg : (() => { | self.msg = self.INJECTED === 1 ? self.msg : (() => { | ||||||
|   const runtimeSend = promisify(chrome.runtime.sendMessage.bind(chrome.runtime)); |   promisifyChrome({ | ||||||
|   const tabSend = chrome.tabs && promisify(chrome.tabs.sendMessage.bind(chrome.tabs)); |     runtime: ['sendMessage'], | ||||||
|   const tabQuery = chrome.tabs && promisify(chrome.tabs.query.bind(chrome.tabs)); |     tabs: ['sendMessage', 'query'], | ||||||
| 
 |   }); | ||||||
|   const isBg = chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window; |   const isBg = chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window; | ||||||
|   if (isBg) { |   if (isBg) { | ||||||
|     window._msg = { |     window._msg = { | ||||||
|  | @ -49,19 +49,21 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => { | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     if (chrome.runtime.getBackgroundPage) { |     if (chrome.runtime.getBackgroundPage) { | ||||||
|       return promisify(chrome.runtime.getBackgroundPage.bind(chrome.runtime))() |       promisifyChrome({ | ||||||
|         .catch(() => null); |         runtime: ['getBackgroundPage'], | ||||||
|  |       }); | ||||||
|  |       return browser.runtime.getBackgroundPage().catch(() => null); | ||||||
|     } |     } | ||||||
|     return Promise.resolve(null); |     return Promise.resolve(null); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function send(data, target = 'extension') { |   function send(data, target = 'extension') { | ||||||
|     const message = {data, target}; |     const message = {data, target}; | ||||||
|     return runtimeSend(message).then(unwrapData); |     return browser.runtime.sendMessage(message).then(unwrapData); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function sendTab(tabId, data, options, target = 'tab') { |   function sendTab(tabId, data, options, target = 'tab') { | ||||||
|     return tabSend(tabId, {data, target}, options) |     return browser.tabs.sendMessage(tabId, {data, target}, options) | ||||||
|       .then(unwrapData); |       .then(unwrapData); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -99,7 +101,7 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function broadcastTab(data, filter, options, ignoreExtension = false, target = 'tab') { |   function broadcastTab(data, filter, options, ignoreExtension = false, target = 'tab') { | ||||||
|     return tabQuery({}) |     return browser.tabs.query({}) | ||||||
|       // TODO: send to activated tabs first?
 |       // TODO: send to activated tabs first?
 | ||||||
|       .then(tabs => { |       .then(tabs => { | ||||||
|         const requests = []; |         const requests = []; | ||||||
|  | @ -123,7 +125,7 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => { | ||||||
|           const message = {data: dataObj, target}; |           const message = {data: dataObj, target}; | ||||||
|           if (tab && tab.id) { |           if (tab && tab.id) { | ||||||
|             requests.push( |             requests.push( | ||||||
|               tabSend(tab.id, message, options) |               browser.tabs.sendMessage(tab.id, message, options) | ||||||
|                 .then(unwrapData) |                 .then(unwrapData) | ||||||
|                 .catch(ignoreError) |                 .catch(ignoreError) | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|  | @ -3,6 +3,8 @@ | ||||||
| // eslint-disable-next-line no-unused-expressions
 | // eslint-disable-next-line no-unused-expressions
 | ||||||
| self.INJECTED !== 1 && (() => { | self.INJECTED !== 1 && (() => { | ||||||
| 
 | 
 | ||||||
|  |   // this part runs in workers, content scripts, our extension pages
 | ||||||
|  | 
 | ||||||
|   if (!Object.entries) { |   if (!Object.entries) { | ||||||
|     Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]]); |     Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]]); | ||||||
|   } |   } | ||||||
|  | @ -10,9 +12,38 @@ self.INJECTED !== 1 && (() => { | ||||||
|     Object.values = obj => Object.keys(obj).map(k => obj[k]); |     Object.values = obj => Object.keys(obj).map(k => obj[k]); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // the above was shared by content scripts and workers,
 |   // don't use self.chrome. It is undefined in Firefox
 | ||||||
|   // the rest is only needed for our extension pages
 |   if (typeof chrome !== 'object') return; | ||||||
|   if (!self.chrome || !self.chrome.tabs) return; |   // the rest is for content scripts and our extension pages
 | ||||||
|  | 
 | ||||||
|  |   self.browser = polyfillBrowser(); | ||||||
|  | 
 | ||||||
|  |   /* Promisifies the specified `chrome` methods into `browser`. | ||||||
|  |     The definitions is an object like this: { | ||||||
|  |       'storage.sync': ['get', 'set'], // if deeper than one level, combine the path via `.`
 | ||||||
|  |       windows: ['create', 'update'], // items and sub-objects will only be created if present in `chrome`
 | ||||||
|  |     } */ | ||||||
|  |   self.promisifyChrome = definitions => { | ||||||
|  |     for (const [scopeName, methods] of Object.entries(definitions)) { | ||||||
|  |       const path = scopeName.split('.'); | ||||||
|  |       const src = path.reduce((obj, p) => obj && obj[p], chrome); | ||||||
|  |       if (!src) continue; | ||||||
|  |       const dst = path.reduce((obj, p) => obj[p] || (obj[p] = {}), browser); | ||||||
|  |       for (const name of methods) { | ||||||
|  |         const fn = src[name]; | ||||||
|  |         if (!fn || dst[name] && !dst[name].isTrap) continue; | ||||||
|  |         dst[name] = (...args) => new Promise((resolve, reject) => | ||||||
|  |           fn.call(src, ...args, (...results) => | ||||||
|  |             chrome.runtime.lastError ? | ||||||
|  |               reject(chrome.runtime.lastError) : | ||||||
|  |               resolve(results.length <= 1 ? results[0] : results))); | ||||||
|  |               // a couple of callbacks have 2 parameters (we don't use those methods, but just in case)
 | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   if (!chrome.tabs) return; | ||||||
|  |   // the rest is for our extension pages
 | ||||||
| 
 | 
 | ||||||
|   if (typeof document === 'object') { |   if (typeof document === 'object') { | ||||||
|     const ELEMENT_METH = { |     const ELEMENT_METH = { | ||||||
|  | @ -75,4 +106,27 @@ self.INJECTED !== 1 && (() => { | ||||||
|   } catch (err) { |   } catch (err) { | ||||||
|     Object.defineProperty(self, 'sessionStorage', {value: {}}); |     Object.defineProperty(self, 'sessionStorage', {value: {}}); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   function polyfillBrowser() { | ||||||
|  |     if (typeof browser === 'object' && browser.runtime) { | ||||||
|  |       return browser; | ||||||
|  |     } | ||||||
|  |     return createTrap(chrome, null); | ||||||
|  | 
 | ||||||
|  |     function createTrap(base, parent) { | ||||||
|  |       const target = typeof base === 'function' ? () => {} : {}; | ||||||
|  |       target.isTrap = true; | ||||||
|  |       return new Proxy(target, { | ||||||
|  |         get: (target, prop) => { | ||||||
|  |           if (target[prop]) return target[prop]; | ||||||
|  |           if (base[prop] && (typeof base[prop] === 'object' || typeof base[prop] === 'function')) { | ||||||
|  |             target[prop] = createTrap(base[prop], base); | ||||||
|  |             return target[prop]; | ||||||
|  |           } | ||||||
|  |           return base[prop]; | ||||||
|  |         }, | ||||||
|  |         apply: (target, thisArg, args) => base.apply(parent, args) | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| })(); | })(); | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								js/prefs.js
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								js/prefs.js
									
									
									
									
									
								
							|  | @ -1,4 +1,4 @@ | ||||||
| /* global promisify */ | /* global promisifyChrome */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| self.prefs = self.INJECTED === 1 ? self.prefs : (() => { | self.prefs = self.INJECTED === 1 ? self.prefs : (() => { | ||||||
|  | @ -107,10 +107,11 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => { | ||||||
|     specific: new Map(), |     specific: new Map(), | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const syncSet = promisify(chrome.storage.sync.set.bind(chrome.storage.sync)); |   promisifyChrome({ | ||||||
|   const syncGet = promisify(chrome.storage.sync.get.bind(chrome.storage.sync)); |     'storage.sync': ['get', 'set'], | ||||||
|  |   }); | ||||||
| 
 | 
 | ||||||
|   const initializing = syncGet('settings') |   const initializing = browser.storage.sync.get('settings') | ||||||
|     .then(result => { |     .then(result => { | ||||||
|       if (result.settings) { |       if (result.settings) { | ||||||
|         setAll(result.settings, true); |         setAll(result.settings, true); | ||||||
|  | @ -237,7 +238,7 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => { | ||||||
|     return new Promise((resolve, reject) => { |     return new Promise((resolve, reject) => { | ||||||
|       setTimeout(() => { |       setTimeout(() => { | ||||||
|         timer = null; |         timer = null; | ||||||
|         syncSet({settings: values}) |         browser.storage.sync.set({settings: values}) | ||||||
|           .then(resolve, reject); |           .then(resolve, reject); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  | @ -1,22 +0,0 @@ | ||||||
| 'use strict'; |  | ||||||
| /* |  | ||||||
| Convert chrome APIs into promises. Example: |  | ||||||
| 
 |  | ||||||
|   const storageSyncGet = promisify(chrome.storage.sync.get.bind(chrome.storage.sync)); |  | ||||||
|   storageSyncGet(['key']).then(result => {...}); |  | ||||||
| 
 |  | ||||||
| */ |  | ||||||
| self.promisify = self.INJECTED === 1 ? self.promisify : fn => |  | ||||||
|   (...args) => |  | ||||||
|     new Promise((resolve, reject) => { |  | ||||||
|       fn(...args, (...result) => { |  | ||||||
|         if (chrome.runtime.lastError) { |  | ||||||
|           reject(chrome.runtime.lastError); |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|         resolve( |  | ||||||
|           result.length === 0 ? undefined : |  | ||||||
|           result.length === 1 ? result[0] : result |  | ||||||
|         ); |  | ||||||
|       }); |  | ||||||
|     }); |  | ||||||
|  | @ -1,7 +1,12 @@ | ||||||
| /* global loadScript tryJSONparse */ | /* global loadScript tryJSONparse promisifyChrome */ | ||||||
| /* exported chromeLocal chromeSync */ | /* exported chromeLocal chromeSync */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
|  | promisifyChrome({ | ||||||
|  |   'storage.local': ['get', 'remove', 'set'], | ||||||
|  |   'storage.sync': ['get', 'remove', 'set'], | ||||||
|  | }); | ||||||
|  | 
 | ||||||
| const [chromeLocal, chromeSync] = (() => { | const [chromeLocal, chromeSync] = (() => { | ||||||
|   return [ |   return [ | ||||||
|     createWrapper('local'), |     createWrapper('local'), | ||||||
|  | @ -9,11 +14,11 @@ const [chromeLocal, chromeSync] = (() => { | ||||||
|   ]; |   ]; | ||||||
| 
 | 
 | ||||||
|   function createWrapper(name) { |   function createWrapper(name) { | ||||||
|     const storage = chrome.storage[name]; |     const storage = browser.storage[name]; | ||||||
|     const wrapper = { |     const wrapper = { | ||||||
|       get: data => new Promise(resolve => storage.get(data, resolve)), |       get: storage.get.bind(storage), | ||||||
|       set: data => new Promise(resolve => storage.set(data, () => resolve(data))), |       set: data => storage.set(data).then(() => data), | ||||||
|       remove: data => new Promise(resolve => storage.remove(data, resolve)), |       remove: storage.remove.bind(storage), | ||||||
| 
 | 
 | ||||||
|       /** |       /** | ||||||
|        * @param {String} key |        * @param {String} key | ||||||
|  |  | ||||||
|  | @ -147,7 +147,6 @@ | ||||||
|   </template> |   </template> | ||||||
| 
 | 
 | ||||||
|   <script src="js/polyfill.js"></script> |   <script src="js/polyfill.js"></script> | ||||||
|   <script src="js/promisify.js"></script> |  | ||||||
|   <script src="js/dom.js"></script> |   <script src="js/dom.js"></script> | ||||||
|   <script src="js/messaging.js"></script> |   <script src="js/messaging.js"></script> | ||||||
|   <script src="js/prefs.js"></script> |   <script src="js/prefs.js"></script> | ||||||
|  |  | ||||||
|  | @ -26,7 +26,6 @@ | ||||||
|   "background": { |   "background": { | ||||||
|     "scripts": [ |     "scripts": [ | ||||||
|       "js/polyfill.js", |       "js/polyfill.js", | ||||||
|       "js/promisify.js", |  | ||||||
|       "js/messaging.js", |       "js/messaging.js", | ||||||
|       "js/msg.js", |       "js/msg.js", | ||||||
|       "js/storage-util.js", |       "js/storage-util.js", | ||||||
|  | @ -77,7 +76,6 @@ | ||||||
|       "match_about_blank": true, |       "match_about_blank": true, | ||||||
|       "js": [ |       "js": [ | ||||||
|         "js/polyfill.js", |         "js/polyfill.js", | ||||||
|         "js/promisify.js", |  | ||||||
|         "js/msg.js", |         "js/msg.js", | ||||||
|         "js/prefs.js", |         "js/prefs.js", | ||||||
|         "content/style-injector.js", |         "content/style-injector.js", | ||||||
|  |  | ||||||
|  | @ -21,7 +21,6 @@ | ||||||
| 
 | 
 | ||||||
|   <script src="js/polyfill.js"></script> |   <script src="js/polyfill.js"></script> | ||||||
|   <script src="js/dom.js"></script> |   <script src="js/dom.js"></script> | ||||||
|   <script src="js/promisify.js"></script> |  | ||||||
|   <script src="js/messaging.js"></script> |   <script src="js/messaging.js"></script> | ||||||
|   <script src="js/msg.js"></script> |   <script src="js/msg.js"></script> | ||||||
|   <script src="js/localization.js"></script> |   <script src="js/localization.js"></script> | ||||||
|  |  | ||||||
|  | @ -179,7 +179,6 @@ | ||||||
|   <script src="manage/config-dialog.js"></script> |   <script src="manage/config-dialog.js"></script> | ||||||
| 
 | 
 | ||||||
|   <script src="js/polyfill.js"></script> |   <script src="js/polyfill.js"></script> | ||||||
|   <script src="js/promisify.js"></script> |  | ||||||
|   <script src="js/dom.js"></script> |   <script src="js/dom.js"></script> | ||||||
|   <script src="js/messaging.js"></script> |   <script src="js/messaging.js"></script> | ||||||
|   <script src="js/localization.js"></script> |   <script src="js/localization.js"></script> | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| /* global tabURL handleEvent $ $$ prefs template FIREFOX chromeLocal debounce | /* global tabURL handleEvent $ $$ prefs template FIREFOX chromeLocal debounce | ||||||
|   $create t API tWordBreak formatDate tryCatch tryJSONparse LZString |   $create t API tWordBreak formatDate tryCatch tryJSONparse LZString | ||||||
|   ignoreChromeError download */ |   promisifyChrome download */ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| window.addEventListener('showStyles:done', function _() { | window.addEventListener('showStyles:done', function _() { | ||||||
|  | @ -88,6 +88,9 @@ window.addEventListener('showStyles:done', function _() { | ||||||
|   return; |   return; | ||||||
| 
 | 
 | ||||||
|   function init() { |   function init() { | ||||||
|  |     promisifyChrome({ | ||||||
|  |       'storage.local': ['getBytesInUse'], // FF doesn't implement it
 | ||||||
|  |     }); | ||||||
|     setTimeout(() => document.body.classList.add(BODY_CLASS)); |     setTimeout(() => document.body.classList.add(BODY_CLASS)); | ||||||
| 
 | 
 | ||||||
|     $('#find-styles-inline-group').classList.add('hidden'); |     $('#find-styles-inline-group').classList.add('hidden'); | ||||||
|  | @ -711,7 +714,7 @@ window.addEventListener('showStyles:done', function _() { | ||||||
|         return chromeLocal.loadLZStringScript().then(() => |         return chromeLocal.loadLZStringScript().then(() => | ||||||
|           tryJSONparse(LZString.decompressFromUTF16(item.payload))); |           tryJSONparse(LZString.decompressFromUTF16(item.payload))); | ||||||
|       } else if (item) { |       } else if (item) { | ||||||
|         chrome.storage.local.remove(key); |         chromeLocal.remove(key); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  | @ -742,16 +745,8 @@ window.addEventListener('showStyles:done', function _() { | ||||||
| 
 | 
 | ||||||
|   function cleanupCache() { |   function cleanupCache() { | ||||||
|     chromeLocal.remove(CACHE_CLEANUP_NEEDED); |     chromeLocal.remove(CACHE_CLEANUP_NEEDED); | ||||||
|     if (chrome.storage.local.getBytesInUse) { |     Promise.resolve(!browser.storage.local.getBytesInUse ? 1e99 : browser.storage.local.getBytesInUse()) | ||||||
|       chrome.storage.local.getBytesInUse(null, size => { |       .then(size => size > CACHE_SIZE && chromeLocal.get().then(cleanupCacheInternal)); | ||||||
|         if (size > CACHE_SIZE) { |  | ||||||
|           chrome.storage.local.get(null, cleanupCacheInternal); |  | ||||||
|         } |  | ||||||
|         ignoreChromeError(); |  | ||||||
|       }); |  | ||||||
|     } else { |  | ||||||
|       chrome.storage.local.get(null, cleanupCacheInternal); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function cleanupCacheInternal(storage) { |   function cleanupCacheInternal(storage) { | ||||||
|  | @ -764,9 +759,8 @@ window.addEventListener('showStyles:done', function _() { | ||||||
|       sortedByTime.slice(0, sortedByTime.length / 2); |       sortedByTime.slice(0, sortedByTime.length / 2); | ||||||
|     const toRemove = expired.length ? expired : sortedByTime; |     const toRemove = expired.length ? expired : sortedByTime; | ||||||
|     if (toRemove.length) { |     if (toRemove.length) { | ||||||
|       chrome.storage.local.remove(toRemove.map(item => item.key), ignoreChromeError); |       chromeLocal.remove(toRemove.map(item => item.key)); | ||||||
|     } |     } | ||||||
|     ignoreChromeError(); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   //endregion
 |   //endregion
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user