var SysTrayX = { version: "0", }; var BrowserInfo = {}; SysTrayX.Accounts = { initialized: false, init: async function () { BrowserInfo = await browser.runtime.getBrowserInfo().then((info) => info); this.getAccounts().then(this.getAccountsCb); }, /* * Use the messages API to get the unread messages (Promise) * Be aware that the data is only avaiable inside the callback */ getAccounts: async function () { return await browser.accounts.list(); }, /* * Callback for getAccounts */ getAccountsCb: function (mailAccount) { function createFolderTreePre74(accountName, folders) { let result = []; let level = { result }; folders.forEach((folder) => { folder.path .slice(1) .split("/") .reduce((r, name, i, a) => { if (!r[name]) { r[name] = { result: [] }; r.result.push({ accountId: folder.accountId, name: folder.name, type: folder.type, subFolders: r[name].result, }); } return r[name]; }, level); }); function traverse(path, folders) { if (!folders) { return; } for (let f of folders) { f.accountName = accountName; f.path = path + "/" + f.name; traverse(path + "/" + f.name, f.subFolders); } } traverse("", result); return result; } function createFolderTree(accountName, folders) { function traverse(path, folders) { if (!folders) { return; } for (let f of folders) { f.accountName = accountName; f.path = path + "/" + f.name; traverse(path + "/" + f.name, f.subFolders); } } traverse("", folders); return folders; } let accounts = new Object(); for (let i = 0; i < mailAccount.length; i++) { if (false) { console.debug("SysTrayX accounts id: " + mailAccount[i].id); console.debug("SysTrayX accounts name: " + mailAccount[i].name); console.debug("SysTrayX accounts type: " + mailAccount[i].type); for (let j = 0; j < mailAccount[i].folders.length; j++) { console.debug( "SysTrayX accounts folder path: " + mailAccount[i].folders[j].path ); console.debug( "SysTrayX accounts folder name: " + mailAccount[i].folders[j].name ); console.debug( "SysTrayX accounts folder type: " + mailAccount[i].folders[j].type ); } } if (!accounts[mailAccount[i].type]) { accounts[mailAccount[i].type] = []; } accounts[mailAccount[i].type].push({ id: mailAccount[i].id, name: mailAccount[i].name, folders: mailAccount[i].folders, }); } /* * Build tree */ // Get base const treeBase = document.getElementById("accountsTree"); for (let prop in accounts) { const typeLi = document.createElement("li"); const typeSpan = document.createElement("span"); if (accounts[prop]) { typeSpan.setAttribute("class", "caret"); } const typeText = document.createTextNode(prop); typeSpan.appendChild(typeText); typeLi.appendChild(typeSpan); if (accounts[prop]) { const typeUl = document.createElement("ul"); typeUl.setAttribute("class", "nested active"); for (let i = 0; i < accounts[prop].length; ++i) { const typeLi = document.createElement("li"); const typeSubSpan = document.createElement("span"); typeSubSpan.setAttribute("class", "caret"); typeLi.appendChild(typeSubSpan); const typeInput = document.createElement("input"); typeInput.setAttribute("type", "checkbox"); typeInput.setAttribute("value", JSON.stringify(accounts[prop][i])); typeInput.setAttribute("name", accounts[prop][i].id); typeLi.appendChild(typeInput); const typeText = document.createTextNode( " " + accounts[prop][i].name ); typeLi.appendChild(typeText); // Create a usable folder tree let folders = []; if (BrowserInfo.version.split(".")[0] < 74) { // Pre TB74 accounts API folders = createFolderTreePre74( accounts[prop][i].name, accounts[prop][i].folders ); } else { // TB74+ accounts API, (this shit never ends...) folders = createFolderTree( accounts[prop][i].name, accounts[prop][i].folders ); } // Recursive list creator function createListLevel(level, parent) { const typeLevelUl = document.createElement("ul"); typeLevelUl.setAttribute("class", "nested"); if (parent) { parent.subFolders = []; parent.name = "^ Add base folder"; level.unshift(parent); } level.forEach((element) => { const typeEleLi = document.createElement("li"); const typeEleSpan = document.createElement("span"); if (element.subFolders.length > 0) { typeEleSpan.setAttribute("class", "caret"); } else { typeEleSpan.setAttribute("class", "caretfiller"); } typeEleLi.appendChild(typeEleSpan); const typeEleInput = document.createElement("input"); typeEleInput.setAttribute("type", "checkbox"); typeEleInput.setAttribute( "value", JSON.stringify({ accountName: element.accountName, accountId: element.accountId, type: element.type != undefined ? element.type : "", path: element.path, name: element.path.split("/").pop(), version: SysTrayX.version, }) ); if (element.subFolders.length > 0) { typeEleInput.setAttribute("name", "parent-" + element.name); } else { typeEleInput.setAttribute("name", "child-" + element.name); } typeEleLi.appendChild(typeEleInput); const typeEleText = document.createTextNode(" " + element.name); typeEleLi.appendChild(typeEleText); if (element.subFolders.length > 0) { typeEleLi.appendChild( createListLevel(element.subFolders, element) ); } typeLevelUl.appendChild(typeEleLi); }); return typeLevelUl; } // Create a folder list recursively typeLi.appendChild(createListLevel(folders)); typeUl.appendChild(typeLi); } typeLi.appendChild(typeUl); } treeBase.appendChild(typeLi); // Setup checkbox control let checkboxes = treeBase.querySelectorAll('input[type="checkbox"]'); for (let x = 0; x < checkboxes.length; x++) { checkboxes[x].addEventListener("change", function (e) { let parentNode = this.parentNode; const cbDescendants = parentNode.querySelectorAll( 'input[type="checkbox"]' ); for (let y = 0; y < cbDescendants.length; y++) { cbDescendants[y].checked = this.checked; cbDescendants[y].indeterminate = false; } while (["ul", "li"].indexOf(parentNode.nodeName.toLowerCase()) >= 0) { const mainCb = parentNode.querySelector( ':scope > input[type="checkbox"]' ); if (mainCb && mainCb != this) { mainCb.checked = this.checked; const mainCbChildren = mainCb.parentNode.querySelectorAll( 'input[type="checkbox"]' ); const numTotal = mainCbChildren.length; let numChecked = 0; for (let z = 0; z < mainCbChildren.length; z++) { numChecked += mainCbChildren[z].checked; } if (numTotal === numChecked) { mainCb.indeterminate = false; mainCb.checked = true; } else { if (numChecked === 0) { mainCb.indeterminate = false; mainCb.checked = false; } else { mainCb.indeterminate = true; mainCb.checked = false; } } } parentNode = parentNode.parentNode; } }); } } /* * Activate tree */ const toggler = document.getElementsByClassName("caret"); for (let i = 0; i < toggler.length; i++) { toggler[i].addEventListener("click", function () { this.parentElement.querySelector(".nested").classList.toggle("active"); this.classList.toggle("caret-down"); }); } }, }; SysTrayX.version = browser.runtime.getManifest().version; SysTrayX.Accounts.init();