preinit.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. /* global API */// msg.js
  2. /* global URLS waitForTabUrl */// toolbox.js
  3. 'use strict';
  4. const ABOUT_BLANK = 'about:blank';
  5. /* exported preinit */
  6. const preinit = (async () => {
  7. let [tab] = await browser.tabs.query({currentWindow: true, active: true});
  8. if (!chrome.app && tab.status === 'loading' && tab.url === ABOUT_BLANK) {
  9. tab = await waitForTabUrl(tab);
  10. }
  11. const frames = sortTabFrames(await browser.webNavigation.getAllFrames({tabId: tab.id}));
  12. let url = tab.pendingUrl || tab.url || ''; // new Chrome uses pendingUrl while connecting
  13. if (url === 'chrome://newtab/' && !URLS.chromeProtectsNTP) {
  14. url = frames[0].url || '';
  15. }
  16. if (!URLS.supported(url)) {
  17. url = '';
  18. frames.length = 1;
  19. }
  20. frames[0].url = url;
  21. const uniqFrames = frames.filter(f => f.url && !f.isDupe);
  22. const styles = await Promise.all(uniqFrames.map(async ({url}) => ({
  23. url,
  24. styles: await getStyleDataMerged(url),
  25. })));
  26. return {frames, styles, url};
  27. })();
  28. /* Merges the extra props from API into style data.
  29. * When `id` is specified returns a single object otherwise an array */
  30. async function getStyleDataMerged(url, id) {
  31. const styles = (await API.styles.getByUrl(url, id))
  32. .map(r => Object.assign(r.style, r));
  33. return id ? styles[0] : styles;
  34. }
  35. /** @param {browser.webNavigation._GetAllFramesReturnDetails[]} frames */
  36. function sortTabFrames(frames) {
  37. const unknown = new Map(frames.map(f => [f.frameId, f]));
  38. const known = new Map([[0, unknown.get(0) || {frameId: 0, url: ''}]]);
  39. unknown.delete(0);
  40. let lastSize = 0;
  41. while (unknown.size !== lastSize) {
  42. for (const [frameId, f] of unknown) {
  43. if (known.has(f.parentFrameId)) {
  44. unknown.delete(frameId);
  45. if (!f.errorOccurred) known.set(frameId, f);
  46. if (f.url === ABOUT_BLANK) f.url = known.get(f.parentFrameId).url;
  47. }
  48. }
  49. lastSize = unknown.size; // guard against an infinite loop due to a weird frame structure
  50. }
  51. const sortedFrames = [...known.values(), ...unknown.values()];
  52. const urls = new Set([ABOUT_BLANK]);
  53. for (const f of sortedFrames) {
  54. if (!f.url) f.url = '';
  55. f.isDupe = urls.has(f.url);
  56. urls.add(f.url);
  57. }
  58. return sortedFrames;
  59. }