chrome-browser-polyfill.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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. alarms: nativeAPI.alarms && {
  29. create: (name, alarmInfo) => nativeAPI.alarms.create(name, alarmInfo),
  30. onAlarm: {
  31. addListener: listener => nativeAPI.alarms.onAlarm.addListener(listener)
  32. }
  33. },
  34. browserAction: {
  35. onClicked: {
  36. addListener: listener => nativeAPI.browserAction.onClicked.addListener(listener)
  37. },
  38. setBadgeText: options => new Promise((resolve, reject) => {
  39. if (!FEATURE_TESTS["browserAction.setBadgeText"] || !FEATURE_TESTS["browserAction.setBadgeText"].callbackNotSupported) {
  40. try {
  41. nativeAPI.browserAction.setBadgeText(options, () => {
  42. if (nativeAPI.runtime.lastError) {
  43. reject(nativeAPI.runtime.lastError);
  44. } else {
  45. resolve();
  46. }
  47. });
  48. } catch (error) {
  49. FEATURE_TESTS["browserAction.setBadgeText"] = { callbackNotSupported: true };
  50. }
  51. }
  52. if (FEATURE_TESTS["browserAction.setBadgeText"] && FEATURE_TESTS["browserAction.setBadgeText"].callbackNotSupported) {
  53. nativeAPI.browserAction.setBadgeText(options);
  54. if (nativeAPI.runtime.lastError) {
  55. reject(nativeAPI.runtime.lastError);
  56. } else {
  57. resolve();
  58. }
  59. }
  60. }),
  61. setBadgeBackgroundColor: options => new Promise((resolve, reject) => {
  62. if (!FEATURE_TESTS["browserAction.setBadgeBackgroundColor"] || !FEATURE_TESTS["browserAction.setBadgeBackgroundColor"].callbackNotSupported) {
  63. try {
  64. nativeAPI.browserAction.setBadgeBackgroundColor(options, () => {
  65. if (nativeAPI.runtime.lastError) {
  66. reject(nativeAPI.runtime.lastError);
  67. } else {
  68. resolve();
  69. }
  70. });
  71. } catch (error) {
  72. FEATURE_TESTS["browserAction.setBadgeBackgroundColor"] = { callbackNotSupported: true };
  73. }
  74. }
  75. if (FEATURE_TESTS["browserAction.setBadgeBackgroundColor"] && FEATURE_TESTS["browserAction.setBadgeBackgroundColor"].callbackNotSupported) {
  76. nativeAPI.browserAction.setBadgeBackgroundColor(options);
  77. if (nativeAPI.runtime.lastError) {
  78. reject(nativeAPI.runtime.lastError);
  79. } else {
  80. resolve();
  81. }
  82. }
  83. }),
  84. setTitle: options => new Promise((resolve, reject) => {
  85. if (!FEATURE_TESTS["browserAction.setTitle"] || !FEATURE_TESTS["browserAction.setTitle"].callbackNotSupported) {
  86. try {
  87. nativeAPI.browserAction.setTitle(options, () => {
  88. if (nativeAPI.runtime.lastError) {
  89. reject(nativeAPI.runtime.lastError);
  90. } else {
  91. resolve();
  92. }
  93. });
  94. } catch (error) {
  95. FEATURE_TESTS["browserAction.setTitle"] = { callbackNotSupported: true };
  96. }
  97. }
  98. if (FEATURE_TESTS["browserAction.setTitle"] && FEATURE_TESTS["browserAction.setTitle"].callbackNotSupported) {
  99. nativeAPI.browserAction.setTitle(options);
  100. if (nativeAPI.runtime.lastError) {
  101. reject(nativeAPI.runtime.lastError);
  102. } else {
  103. resolve();
  104. }
  105. }
  106. }),
  107. setIcon: options => new Promise((resolve, reject) => {
  108. if (!FEATURE_TESTS["browserAction.setIcon"] || !FEATURE_TESTS["browserAction.setIcon"].callbackNotSupported) {
  109. try {
  110. nativeAPI.browserAction.setIcon(options, () => {
  111. if (nativeAPI.runtime.lastError) {
  112. reject(nativeAPI.runtime.lastError);
  113. } else {
  114. resolve();
  115. }
  116. });
  117. } catch (error) {
  118. FEATURE_TESTS["browserAction.setIcon"] = { callbackNotSupported: true };
  119. }
  120. }
  121. if (FEATURE_TESTS["browserAction.setIcon"] && FEATURE_TESTS["browserAction.setIcon"].callbackNotSupported) {
  122. nativeAPI.browserAction.setIcon(options);
  123. if (nativeAPI.runtime.lastError) {
  124. reject(nativeAPI.runtime.lastError);
  125. } else {
  126. resolve();
  127. }
  128. }
  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);
  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);
  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);
  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);
  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);
  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);
  207. } else {
  208. resolve();
  209. }
  210. });
  211. })
  212. },
  213. permissions: {
  214. request: permissions => new Promise((resolve, reject) => {
  215. nativeAPI.permissions.request(permissions, () => {
  216. if (nativeAPI.runtime.lastError) {
  217. reject(nativeAPI.runtime.lastError);
  218. } else {
  219. resolve();
  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);
  267. } else {
  268. resolve(response);
  269. }
  270. });
  271. if (nativeAPI.runtime.lastError) {
  272. reject(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);
  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);
  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);
  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);
  313. } else {
  314. resolve();
  315. }
  316. });
  317. })
  318. }
  319. },
  320. tabs: {
  321. onCreated: {
  322. addListener: listener => nativeAPI.tabs.onCreated.addListener(listener)
  323. },
  324. onActivated: {
  325. addListener: listener => nativeAPI.tabs.onActivated.addListener(listener)
  326. },
  327. onUpdated: {
  328. addListener: listener => nativeAPI.tabs.onUpdated.addListener(listener),
  329. removeListener: listener => nativeAPI.tabs.onUpdated.removeListener(listener)
  330. },
  331. onRemoved: {
  332. addListener: listener => nativeAPI.tabs.onRemoved.addListener(listener),
  333. removeListener: listener => nativeAPI.tabs.onRemoved.removeListener(listener)
  334. },
  335. executeScript: (tabId, details) => new Promise((resolve, reject) => {
  336. nativeAPI.tabs.executeScript(tabId, details, () => {
  337. if (nativeAPI.runtime.lastError) {
  338. reject(nativeAPI.runtime.lastError);
  339. } else {
  340. resolve();
  341. }
  342. });
  343. }),
  344. sendMessage: (tabId, message, options = {}) => new Promise((resolve, reject) => {
  345. nativeAPI.tabs.sendMessage(tabId, message, options, response => {
  346. if (nativeAPI.runtime.lastError) {
  347. reject(nativeAPI.runtime.lastError);
  348. } else {
  349. resolve(response);
  350. }
  351. });
  352. if (nativeAPI.runtime.lastError) {
  353. reject(nativeAPI.runtime.lastError);
  354. }
  355. }),
  356. query: options => new Promise((resolve, reject) => {
  357. nativeAPI.tabs.query(options, tabs => {
  358. if (nativeAPI.runtime.lastError) {
  359. reject(nativeAPI.runtime.lastError);
  360. } else {
  361. resolve(tabs);
  362. }
  363. });
  364. }),
  365. create: createProperties => new Promise((resolve, reject) => {
  366. nativeAPI.tabs.create(createProperties, tab => {
  367. if (nativeAPI.runtime.lastError) {
  368. reject(nativeAPI.runtime.lastError);
  369. } else {
  370. resolve(tab);
  371. }
  372. });
  373. }),
  374. get: options => new Promise((resolve, reject) => {
  375. nativeAPI.tabs.get(options, tab => {
  376. if (nativeAPI.runtime.lastError) {
  377. reject(nativeAPI.runtime.lastError);
  378. } else {
  379. resolve(tab);
  380. }
  381. });
  382. }),
  383. remove: tabId => new Promise((resolve, reject) => {
  384. nativeAPI.tabs.remove(tabId, () => {
  385. if (nativeAPI.runtime.lastError) {
  386. reject(nativeAPI.runtime.lastError);
  387. } else {
  388. resolve();
  389. }
  390. });
  391. })
  392. },
  393. devtools: nativeAPI.devtools && {
  394. inspectedWindow: nativeAPI.devtools.inspectedWindow && {
  395. onResourceContentCommitted: nativeAPI.devtools.inspectedWindow.onResourceContentCommitted && {
  396. addListener: listener => nativeAPI.devtools.inspectedWindow.onResourceContentCommitted.addListener(listener)
  397. },
  398. get tabId() {
  399. return nativeAPI.devtools.inspectedWindow.tabId;
  400. }
  401. }
  402. }
  403. }));
  404. }
  405. })();