browser.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /* global chrome */
  2. const global = window;
  3. function wrapAsync(func) {
  4. return (...args) => new Promise((resolve, reject) => {
  5. args.push(res => {
  6. const err = chrome.runtime.lastError;
  7. if (err) {
  8. console.error(args);
  9. reject(err);
  10. } else {
  11. resolve(res);
  12. }
  13. });
  14. func(...args);
  15. });
  16. }
  17. function wrapAPIs(source, meta) {
  18. const target = {};
  19. Object.keys(source).forEach(key => {
  20. const metaVal = meta && meta[key];
  21. if (metaVal) {
  22. const value = source[key];
  23. if (typeof metaVal === 'function') {
  24. target[key] = metaVal(value);
  25. } else if (typeof metaVal === 'object' && typeof value === 'object') {
  26. target[key] = wrapAPIs(value, metaVal);
  27. } else {
  28. target[key] = value;
  29. }
  30. }
  31. });
  32. return target;
  33. }
  34. const meta = {
  35. browserAction: true,
  36. i18n: true,
  37. notifications: {
  38. onClicked: true,
  39. onClosed: true,
  40. create: wrapAsync,
  41. },
  42. runtime: {
  43. getManifest: true,
  44. getURL: true,
  45. onMessage(onMessage) {
  46. function wrapListener(listener) {
  47. return function onChromeMessage(message, sender, sendResponse) {
  48. const result = listener(message, sender);
  49. if (result && typeof result.then === 'function') {
  50. result.then(data => {
  51. sendResponse({ data });
  52. }, error => {
  53. console.error(error);
  54. sendResponse({ error });
  55. });
  56. return true;
  57. } else if (typeof result !== 'undefined') {
  58. // In some browsers (e.g Chrome 56, Vivaldi), the listener in
  59. // popup pages are not properly cleared after closed.
  60. // They may send `undefined` before the real response is sent.
  61. sendResponse({ data: result });
  62. }
  63. };
  64. }
  65. return {
  66. addListener(listener) {
  67. return onMessage.addListener(wrapListener(listener));
  68. },
  69. };
  70. },
  71. sendMessage(sendMessage) {
  72. const promisifiedSendMessage = wrapAsync(sendMessage);
  73. return data => promisifiedSendMessage(data)
  74. .then(res => {
  75. if (res && res.error) throw res.error;
  76. return res && res.data;
  77. });
  78. },
  79. },
  80. tabs: {
  81. onUpdated: true,
  82. create: wrapAsync,
  83. get: wrapAsync,
  84. query: wrapAsync,
  85. reload: wrapAsync,
  86. remove: wrapAsync,
  87. sendMessage: wrapAsync,
  88. update: wrapAsync,
  89. },
  90. webRequest: true,
  91. };
  92. if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
  93. global.browser = wrapAPIs(chrome, meta);
  94. global.browser.__patched = true;
  95. }