aboutUnloads.js (3673B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 "use strict"; 5 6 const { TabUnloader } = ChromeUtils.importESModule( 7 "moz-src:///browser/components/tabbrowser/TabUnloader.sys.mjs" 8 ); 9 10 async function refreshData() { 11 const sortedTabs = await TabUnloader.getSortedTabs(null); 12 const tabTable = document.querySelector(".tab-table > tbody"); 13 const getHost = uri => { 14 try { 15 return uri?.host; 16 } catch (e) { 17 return uri?.spec; 18 } 19 }; 20 const updateTimestamp = () => { 21 document.l10n.setAttributes( 22 document.getElementById("label-last-updated"), 23 "about-unloads-last-updated", 24 { date: Date.now() } 25 ); 26 }; 27 28 // Reset the table 29 // Don't delete the first row showing the "no unloadable tab" message 30 while (tabTable.rows.length > 1) { 31 tabTable.deleteRow(1); 32 } 33 if (!sortedTabs.length) { 34 document.getElementById("button-unload").disabled = true; 35 document.getElementById("no-unloadable-tab-message").hidden = false; 36 updateTimestamp(); 37 return; 38 } 39 document.getElementById("button-unload").disabled = 40 !TabUnloader.isDiscardable(sortedTabs[0]); 41 document.getElementById("no-unloadable-tab-message").hidden = true; 42 43 const fragmentRows = new DocumentFragment(); 44 const templateRow = document.querySelector("template[name=tab-table-row]"); 45 46 let ordinal = 0; 47 for (const tabInfo of sortedTabs) { 48 if (!("tab" in tabInfo)) { 49 continue; 50 } 51 52 const fragment = templateRow.content.cloneNode(true); 53 const row = fragment.querySelector("tr"); 54 55 row.children[0].textContent = TabUnloader.isDiscardable(tabInfo) 56 ? ++ordinal 57 : "-"; 58 row.children[1].textContent = getHost( 59 tabInfo.tab?.linkedBrowser?.currentURI 60 ); 61 if ("lastAccessed" in tabInfo.tab) { 62 document.l10n.setAttributes( 63 row.children[2], 64 "about-unloads-last-accessed", 65 { date: tabInfo.tab.lastAccessed } 66 ); 67 } 68 row.children[3].textContent = tabInfo.weight; 69 row.children[4].textContent = tabInfo.sortWeight; 70 if ("memory" in tabInfo) { 71 document.l10n.setAttributes( 72 row.children[5], 73 "about-unloads-memory-in-mb", 74 { mem: tabInfo.memory / 1024 / 1024 } 75 ); 76 } 77 78 if (tabInfo.processes) { 79 for (const [pid, procEntry] of tabInfo.processes) { 80 if (pid < 0) { 81 // Tab is hosted by the main process 82 continue; 83 } 84 85 const procLabel = document.createElement("span"); 86 const procInfo = procEntry.entryToProcessMap; 87 88 if (procEntry.isTopLevel) { 89 procLabel.classList.add("top-level-process"); 90 } 91 if (procInfo.tabSet.size > 1) { 92 procLabel.classList.add("shared-process"); 93 } 94 procLabel.textContent = pid; 95 document.l10n.setAttributes( 96 procLabel, 97 "about-unloads-memory-in-mb-tooltip", 98 { mem: procInfo.memory / 1024 / 1024 } 99 ); 100 row.children[6].appendChild(procLabel); 101 row.children[6].appendChild(document.createTextNode(" ")); 102 } 103 } 104 105 fragmentRows.appendChild(fragment); 106 } 107 108 tabTable.appendChild(fragmentRows); 109 updateTimestamp(); 110 } 111 112 async function onLoad() { 113 document 114 .getElementById("button-unload") 115 .addEventListener("click", async () => { 116 await TabUnloader.unloadLeastRecentlyUsedTab(null); 117 await refreshData(); 118 }); 119 await refreshData(); 120 } 121 122 try { 123 document.addEventListener("DOMContentLoaded", onLoad, { once: true }); 124 } catch (ex) { 125 console.error(ex); 126 }