chrome-browser-polyfill.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. /*
  2. * Copyright 2010-2019 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile.
  6. *
  7. * The code in this file is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU Affero General Public License
  9. * (GNU AGPL) as published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * The code in this file is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
  15. * General Public License for more details.
  16. *
  17. * As additional permission under GNU AGPL version 3 section 7, you may
  18. * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
  19. * AGPL normally required by section 4, provided you include this license
  20. * notice and a URL through which recipients can access the Corresponding
  21. * Source.
  22. */
  23. (() => {
  24. const FEATURE_TESTS = {};
  25. if (!this.browser && this.chrome) {
  26. const nativeAPI = this.chrome;
  27. this.__defineGetter__("browser", () => ({
  28. browserAction: {
  29. onClicked: {
  30. addListener: listener => nativeAPI.browserAction.onClicked.addListener(listener)
  31. },
  32. setBadgeText: options => new Promise((resolve, reject) => {
  33. if (!FEATURE_TESTS["browserAction.setBadgeText"] || !FEATURE_TESTS["browserAction.setBadgeText"].callbackNotSupported) {
  34. try {
  35. nativeAPI.browserAction.setBadgeText(options, () => {
  36. if (nativeAPI.runtime.lastError) {
  37. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  38. } else {
  39. resolve();
  40. }
  41. });
  42. } catch (error) {
  43. FEATURE_TESTS["browserAction.setBadgeText"] = { callbackNotSupported: true };
  44. }
  45. }
  46. if (FEATURE_TESTS["browserAction.setBadgeText"] && FEATURE_TESTS["browserAction.setBadgeText"].callbackNotSupported) {
  47. nativeAPI.browserAction.setBadgeText(options);
  48. if (nativeAPI.runtime.lastError) {
  49. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  50. } else {
  51. resolve();
  52. }
  53. }
  54. }),
  55. setBadgeBackgroundColor: options => new Promise((resolve, reject) => {
  56. if (!FEATURE_TESTS["browserAction.setBadgeBackgroundColor"] || !FEATURE_TESTS["browserAction.setBadgeBackgroundColor"].callbackNotSupported) {
  57. try {
  58. nativeAPI.browserAction.setBadgeBackgroundColor(options, () => {
  59. if (nativeAPI.runtime.lastError) {
  60. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  61. } else {
  62. resolve();
  63. }
  64. });
  65. } catch (error) {
  66. FEATURE_TESTS["browserAction.setBadgeBackgroundColor"] = { callbackNotSupported: true };
  67. }
  68. }
  69. if (FEATURE_TESTS["browserAction.setBadgeBackgroundColor"] && FEATURE_TESTS["browserAction.setBadgeBackgroundColor"].callbackNotSupported) {
  70. nativeAPI.browserAction.setBadgeBackgroundColor(options);
  71. if (nativeAPI.runtime.lastError) {
  72. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  73. } else {
  74. resolve();
  75. }
  76. }
  77. }),
  78. setTitle: options => new Promise((resolve, reject) => {
  79. if (!FEATURE_TESTS["browserAction.setTitle"] || !FEATURE_TESTS["browserAction.setTitle"].callbackNotSupported) {
  80. try {
  81. nativeAPI.browserAction.setTitle(options, () => {
  82. if (nativeAPI.runtime.lastError) {
  83. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  84. } else {
  85. resolve();
  86. }
  87. });
  88. } catch (error) {
  89. FEATURE_TESTS["browserAction.setTitle"] = { callbackNotSupported: true };
  90. }
  91. }
  92. if (FEATURE_TESTS["browserAction.setTitle"] && FEATURE_TESTS["browserAction.setTitle"].callbackNotSupported) {
  93. nativeAPI.browserAction.setTitle(options);
  94. if (nativeAPI.runtime.lastError) {
  95. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  96. } else {
  97. resolve();
  98. }
  99. }
  100. }),
  101. setIcon: options => new Promise((resolve, reject) => {
  102. if (!FEATURE_TESTS["browserAction.setIcon"] || !FEATURE_TESTS["browserAction.setIcon"].callbackNotSupported) {
  103. try {
  104. nativeAPI.browserAction.setIcon(options, () => {
  105. if (nativeAPI.runtime.lastError) {
  106. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  107. } else {
  108. resolve();
  109. }
  110. });
  111. } catch (error) {
  112. FEATURE_TESTS["browserAction.setIcon"] = { callbackNotSupported: true };
  113. }
  114. }
  115. if (FEATURE_TESTS["browserAction.setIcon"] && FEATURE_TESTS["browserAction.setIcon"].callbackNotSupported) {
  116. nativeAPI.browserAction.setIcon(options);
  117. if (nativeAPI.runtime.lastError) {
  118. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  119. } else {
  120. resolve();
  121. }
  122. }
  123. })
  124. },
  125. bookmarks: {
  126. onCreated: {
  127. addListener: listener => nativeAPI.bookmarks.onCreated.addListener(listener),
  128. removeListener: listener => nativeAPI.bookmarks.onCreated.removeListener(listener)
  129. }
  130. },
  131. commands: {
  132. onCommand: {
  133. addListener: listener => nativeAPI.commands.onCommand.addListener(listener)
  134. }
  135. },
  136. downloads: {
  137. download: options => new Promise((resolve, reject) => {
  138. nativeAPI.downloads.download(options, downloadId => {
  139. if (nativeAPI.runtime.lastError) {
  140. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  141. } else {
  142. resolve(downloadId);
  143. }
  144. });
  145. }),
  146. onChanged: {
  147. addListener: listener => nativeAPI.downloads.onChanged.addListener(listener),
  148. removeListener: listener => nativeAPI.downloads.onChanged.removeListener(listener)
  149. }
  150. },
  151. i18n: {
  152. getMessage: (messageName, substitutions) => nativeAPI.i18n.getMessage(messageName, substitutions)
  153. },
  154. identity: {
  155. get getAuthToken() {
  156. return nativeAPI.identity && nativeAPI.identity.getAuthToken && (details => new Promise((resolve, reject) =>
  157. nativeAPI.identity.getAuthToken(details, token => {
  158. if (nativeAPI.runtime.lastError) {
  159. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  160. } else {
  161. resolve(token);
  162. }
  163. })
  164. ));
  165. },
  166. get launchWebAuthFlow() {
  167. return nativeAPI.identity && nativeAPI.identity.launchWebAuthFlow && (options => new Promise((resolve, reject) => {
  168. nativeAPI.identity.launchWebAuthFlow(options, responseUrl => {
  169. if (nativeAPI.runtime.lastError) {
  170. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  171. } else {
  172. resolve(responseUrl);
  173. }
  174. });
  175. }));
  176. },
  177. get removeCachedAuthToken() {
  178. return nativeAPI.identity && nativeAPI.identity.removeCachedAuthToken && (details => new Promise((resolve, reject) =>
  179. nativeAPI.identity.removeCachedAuthToken(details, () => {
  180. if (nativeAPI.runtime.lastError) {
  181. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  182. } else {
  183. resolve();
  184. }
  185. })
  186. ));
  187. }
  188. },
  189. menus: {
  190. onClicked: {
  191. addListener: listener => nativeAPI.contextMenus.onClicked.addListener(listener)
  192. },
  193. create: options => nativeAPI.contextMenus.create(options),
  194. update: (menuItemId, options) => new Promise((resolve, reject) => {
  195. nativeAPI.contextMenus.update(menuItemId, options, () => {
  196. if (nativeAPI.runtime.lastError) {
  197. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  198. } else {
  199. resolve();
  200. }
  201. });
  202. }),
  203. removeAll: () => new Promise((resolve, reject) => {
  204. nativeAPI.contextMenus.removeAll(() => {
  205. if (nativeAPI.runtime.lastError) {
  206. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  207. } else {
  208. resolve();
  209. }
  210. });
  211. })
  212. },
  213. permissions: {
  214. request: permissions => new Promise((resolve, reject) => {
  215. nativeAPI.permissions.request(permissions, result => {
  216. if (nativeAPI.runtime.lastError) {
  217. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  218. } else {
  219. resolve(result);
  220. }
  221. });
  222. })
  223. },
  224. runtime: {
  225. getManifest: () => nativeAPI.runtime.getManifest(),
  226. onMessage: {
  227. addListener: listener => nativeAPI.runtime.onMessage.addListener((message, sender, sendResponse) => {
  228. const response = listener(message, sender);
  229. if (response && typeof response.then == "function") {
  230. response
  231. .then(response => {
  232. if (response !== undefined) {
  233. try {
  234. sendResponse(response);
  235. } catch (error) {
  236. // ignored
  237. }
  238. }
  239. });
  240. return true;
  241. }
  242. }),
  243. removeListener: listener => nativeAPI.runtime.onMessage.removeListener(listener)
  244. },
  245. onMessageExternal: {
  246. addListener: listener => nativeAPI.runtime.onMessageExternal.addListener((message, sender, sendResponse) => {
  247. const response = listener(message, sender);
  248. if (response && typeof response.then == "function") {
  249. response
  250. .then(response => {
  251. if (response !== undefined) {
  252. try {
  253. sendResponse(response);
  254. } catch (error) {
  255. // ignored
  256. }
  257. }
  258. });
  259. return true;
  260. }
  261. })
  262. },
  263. sendMessage: message => new Promise((resolve, reject) => {
  264. nativeAPI.runtime.sendMessage(message, response => {
  265. if (nativeAPI.runtime.lastError) {
  266. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  267. } else {
  268. resolve(response);
  269. }
  270. });
  271. if (nativeAPI.runtime.lastError) {
  272. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  273. }
  274. }),
  275. getURL: (path) => nativeAPI.runtime.getURL(path),
  276. get lastError() {
  277. return nativeAPI.runtime.lastError;
  278. }
  279. },
  280. storage: {
  281. local: {
  282. set: value => new Promise((resolve, reject) => {
  283. nativeAPI.storage.local.set(value, () => {
  284. if (nativeAPI.runtime.lastError) {
  285. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  286. } else {
  287. resolve();
  288. }
  289. });
  290. }),
  291. get: () => new Promise((resolve, reject) => {
  292. nativeAPI.storage.local.get(null, value => {
  293. if (nativeAPI.runtime.lastError) {
  294. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  295. } else {
  296. resolve(value);
  297. }
  298. });
  299. }),
  300. clear: () => new Promise((resolve, reject) => {
  301. nativeAPI.storage.local.clear(() => {
  302. if (nativeAPI.runtime.lastError) {
  303. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  304. } else {
  305. resolve();
  306. }
  307. });
  308. }),
  309. remove: keys => new Promise((resolve, reject) => {
  310. nativeAPI.storage.local.remove(keys, () => {
  311. if (nativeAPI.runtime.lastError) {
  312. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  313. } else {
  314. resolve();
  315. }
  316. });
  317. })
  318. },
  319. sync: {
  320. set: value => new Promise((resolve, reject) => {
  321. nativeAPI.storage.sync.set(value, () => {
  322. if (nativeAPI.runtime.lastError) {
  323. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  324. } else {
  325. resolve();
  326. }
  327. });
  328. }),
  329. get: () => new Promise((resolve, reject) => {
  330. nativeAPI.storage.sync.get(null, value => {
  331. if (nativeAPI.runtime.lastError) {
  332. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  333. } else {
  334. resolve(value);
  335. }
  336. });
  337. }),
  338. clear: () => new Promise((resolve, reject) => {
  339. nativeAPI.storage.sync.clear(() => {
  340. if (nativeAPI.runtime.lastError) {
  341. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  342. } else {
  343. resolve();
  344. }
  345. });
  346. }),
  347. remove: keys => new Promise((resolve, reject) => {
  348. nativeAPI.storage.sync.remove(keys, () => {
  349. if (nativeAPI.runtime.lastError) {
  350. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  351. } else {
  352. resolve();
  353. }
  354. });
  355. })
  356. }
  357. },
  358. tabs: {
  359. onCreated: {
  360. addListener: listener => nativeAPI.tabs.onCreated.addListener(listener)
  361. },
  362. onActivated: {
  363. addListener: listener => nativeAPI.tabs.onActivated.addListener(listener)
  364. },
  365. onUpdated: {
  366. addListener: listener => nativeAPI.tabs.onUpdated.addListener(listener),
  367. removeListener: listener => nativeAPI.tabs.onUpdated.removeListener(listener)
  368. },
  369. onRemoved: {
  370. addListener: listener => nativeAPI.tabs.onRemoved.addListener(listener),
  371. removeListener: listener => nativeAPI.tabs.onRemoved.removeListener(listener)
  372. },
  373. executeScript: (tabId, details) => new Promise((resolve, reject) => {
  374. nativeAPI.tabs.executeScript(tabId, details, () => {
  375. if (nativeAPI.runtime.lastError) {
  376. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  377. } else {
  378. resolve();
  379. }
  380. });
  381. }),
  382. sendMessage: (tabId, message, options = {}) => new Promise((resolve, reject) => {
  383. nativeAPI.tabs.sendMessage(tabId, message, options, response => {
  384. if (nativeAPI.runtime.lastError) {
  385. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  386. } else {
  387. resolve(response);
  388. }
  389. });
  390. if (nativeAPI.runtime.lastError) {
  391. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  392. }
  393. }),
  394. query: options => new Promise((resolve, reject) => {
  395. nativeAPI.tabs.query(options, tabs => {
  396. if (nativeAPI.runtime.lastError) {
  397. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  398. } else {
  399. resolve(tabs);
  400. }
  401. });
  402. }),
  403. create: createProperties => new Promise((resolve, reject) => {
  404. nativeAPI.tabs.create(createProperties, tab => {
  405. if (nativeAPI.runtime.lastError) {
  406. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  407. } else {
  408. resolve(tab);
  409. }
  410. });
  411. }),
  412. get: options => new Promise((resolve, reject) => {
  413. nativeAPI.tabs.get(options, tab => {
  414. if (nativeAPI.runtime.lastError) {
  415. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  416. } else {
  417. resolve(tab);
  418. }
  419. });
  420. }),
  421. remove: tabId => new Promise((resolve, reject) => {
  422. nativeAPI.tabs.remove(tabId, () => {
  423. if (nativeAPI.runtime.lastError) {
  424. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  425. } else {
  426. resolve();
  427. }
  428. });
  429. }),
  430. update: (tabId, updateProperties) => new Promise((resolve, reject) => {
  431. nativeAPI.tabs.update(tabId, updateProperties, tab => {
  432. if (nativeAPI.runtime.lastError) {
  433. reject(nativeAPI.runtime.lastError.message || nativeAPI.runtime.lastError);
  434. } else {
  435. resolve(tab);
  436. }
  437. });
  438. })
  439. },
  440. devtools: nativeAPI.devtools && {
  441. inspectedWindow: nativeAPI.devtools.inspectedWindow && {
  442. onResourceContentCommitted: nativeAPI.devtools.inspectedWindow.onResourceContentCommitted && {
  443. addListener: listener => nativeAPI.devtools.inspectedWindow.onResourceContentCommitted.addListener(listener)
  444. },
  445. get tabId() {
  446. return nativeAPI.devtools.inspectedWindow.tabId;
  447. }
  448. }
  449. }
  450. }));
  451. }
  452. })();