preinit.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /* global API */// msg.js
  2. /* global closeCurrentTab download */// toolbox.js
  3. 'use strict';
  4. /* exported preinit */
  5. const preinit = (() => {
  6. const params = new URLSearchParams(location.search);
  7. const tabId = params.has('tabId') ? Number(params.get('tabId')) : -1;
  8. const initialUrl = params.get('updateUrl');
  9. /** @type function(?options):Promise<?string> */
  10. let getData;
  11. /** @type {Promise<?string>} */
  12. let firstGet;
  13. if (tabId < 0) {
  14. getData = DirectDownloader();
  15. firstGet = API.usercss.getInstallCode(initialUrl)
  16. .then(code => code || getData())
  17. .catch(getData);
  18. } else {
  19. getData = PortDownloader();
  20. firstGet = getData({force: true});
  21. }
  22. function DirectDownloader() {
  23. let oldCode = null;
  24. return async () => {
  25. const code = await download(initialUrl, {
  26. // Disabling cache on http://localhost otherwise the recheck delay gets too big
  27. headers: {'Cache-Control': 'no-cache, no-store'},
  28. });
  29. if (oldCode !== code) {
  30. oldCode = code;
  31. return code;
  32. }
  33. };
  34. }
  35. function PortDownloader() {
  36. const resolvers = new Map();
  37. const port = chrome.tabs.connect(tabId, {name: 'downloadSelf'});
  38. port.onMessage.addListener(({id, code, error}) => {
  39. const r = resolvers.get(id);
  40. resolvers.delete(id);
  41. if (error) {
  42. r.reject(error);
  43. } else {
  44. r.resolve(code);
  45. }
  46. });
  47. port.onDisconnect.addListener(async () => {
  48. const tab = await browser.tabs.get(tabId).catch(() => ({}));
  49. if (tab.url === initialUrl) {
  50. location.reload();
  51. } else {
  52. closeCurrentTab();
  53. }
  54. });
  55. return (opts = {}) => new Promise((resolve, reject) => {
  56. const id = performance.now();
  57. resolvers.set(id, {resolve, reject});
  58. opts.id = id;
  59. port.postMessage(opts);
  60. });
  61. }
  62. return {
  63. getData,
  64. initialUrl,
  65. tabId,
  66. /** @type {Promise<{style, dup} | {error}>} */
  67. ready: (async () => {
  68. let sourceCode;
  69. try {
  70. sourceCode = await firstGet;
  71. } catch (error) {
  72. return {error};
  73. }
  74. try {
  75. const data = await API.usercss.build({sourceCode, checkDup: true, metaOnly: true});
  76. Object.defineProperty(data.style, 'sectionsPromise', {
  77. value: API.usercss.buildCode(data.style).then(style => style.sections),
  78. configurable: true,
  79. });
  80. return data;
  81. } catch (error) {
  82. return {error, sourceCode};
  83. }
  84. })(),
  85. };
  86. })();