From f57012ae92da0168a80d3efc8b8ddc56e17301ec Mon Sep 17 00:00:00 2001 From: Mitch Claborn Date: Mon, 16 Oct 2023 14:10:31 -0500 Subject: [PATCH 1/2] bug 106: add a reverse hierarchical display, sorted, without the account name headers --- src/_locales/de/messages.json | 6 +++++ src/_locales/en/messages.json | 6 +++++ src/_locales/fr/messages.json | 6 +++++ src/common/foldernode.js | 44 ++++++++++++++++++++++++++++++++--- src/common/util.js | 3 ++- src/options/options.html | 4 ++++ src/popup/baseItemList.js | 26 +++++++++++++++------ src/popup/folderList.js | 30 ++++++++++++++++++++---- src/popup/popup.js | 6 ++--- 9 files changed, 113 insertions(+), 18 deletions(-) diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json index ec4db8f..03eba4c 100644 --- a/src/_locales/de/messages.json +++ b/src/_locales/de/messages.json @@ -91,5 +91,11 @@ }, "useLegacyShortcutsDone": { "message": "Sie können nun ⇧M ⇧Y und ⇧G verwenden. Ändere die Tastenkürzel in der Erweiterungsverwaltung für Tastenkürzel." + }, + "reverseHierarchyCompact": { + "message": "Reverse hierarchy display (compact only)" + }, + "reverseHierarchyCompact.title": { + "message": "Compact mode only. Show the folder name first, in a reverse hierarchy, with the account name at the end. Don't show a separate line for the account. The list is sorted by the folder name (leaf node)." } } diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 19cf1ca..9e71f0f 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -91,5 +91,11 @@ }, "useLegacyShortcutsDone": { "message": "You can now use ⇧M ⇧Y and ⇧G. Change the keys in the extension shortcuts." + }, + "reverseHierarchyCompact": { + "message": "Reverse hierarchy display (compact only)" + }, + "reverseHierarchyCompact.title": { + "message": "Compact mode only. Show the folder name first, in a reverse hierarchy, with the account name at the end. Don't show a separate line for the account. The list is sorted by the folder name (leaf node)." } } diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json index 5a6d4ed..52f8add 100644 --- a/src/_locales/fr/messages.json +++ b/src/_locales/fr/messages.json @@ -88,5 +88,11 @@ }, "useLegacyShortcutsDone": { "message": "Vous pouvez à présent utiliser ⇧M ⇧Y et ⇧G. Utilisez l'extention shortcut pour les modifier." + }, + "reverseHierarchyCompact": { + "message": "Reverse hierarchy display (compact only)" + }, + "reverseHierarchyCompact.title": { + "message": "Compact mode only. Show the folder name first, in a reverse hierarchy, with the account name at the end. Don't show a separate line for the account. The list is sorted by the folder name (leaf node)." } } diff --git a/src/common/foldernode.js b/src/common/foldernode.js index 3473859..4ab132e 100644 --- a/src/common/foldernode.js +++ b/src/common/foldernode.js @@ -141,16 +141,54 @@ export class FolderNode extends BaseNode { return node; } - get fullNameParts() { + getFullNameParts(includeAccountNode) { let parts = []; let node = this; // eslint-disable-line consistent-this - while (node && !(node instanceof AccountNode)) { - parts.unshift(node.item.name); + while (node) { + let isAcctNode = node instanceof AccountNode; + if (includeAccountNode || !isAcctNode) { + parts.unshift(node.item.name); + } + if (isAcctNode) { + break; + } node = node.parent; } return parts; } + + get fullPathReversed() { + let fullFolderPathComponents = this.getFullNameParts(true).filter((val) => { + // Filter out [Gmail] and empty path components. + return val !== "" && !val.includes("["); + }); + + if (fullFolderPathComponents.length === 0) { + return ''; + } + + let display = ''; + for (var i = fullFolderPathComponents.length - 1; i >= 1; i--) { + if (display !== '') { + display += ' ← '; + } + display += fullFolderPathComponents[i]; + } + + if (display !== '') { + display += ' ← '; + } + + display += '' + fullFolderPathComponents[0] + ''; + + return display; + } + + get fullNameParts() { + return this.getFullNameParts(false); + } + } export class AccountNode extends FolderNode { diff --git a/src/common/util.js b/src/common/util.js index 277c075..999f97f 100644 --- a/src/common/util.js +++ b/src/common/util.js @@ -5,7 +5,8 @@ export const DEFAULT_PREFERENCES = { showFolderPath: false, useLegacyShortcuts: false, skipArchive: true, - defaultFolderSetting: "recent" + defaultFolderSetting: "recent", + reverseHierarchyCompact: false }; export async function getValidatedDefaultFolders(accountNodes) { diff --git a/src/options/options.html b/src/options/options.html index 765a539..92764a1 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -36,6 +36,10 @@ +
+ + +
diff --git a/src/popup/baseItemList.js b/src/popup/baseItemList.js index deb5ac3..21d8274 100644 --- a/src/popup/baseItemList.js +++ b/src/popup/baseItemList.js @@ -479,9 +479,13 @@ export default class BaseItemList extends HTMLElement { repopulate() { let lowerSearchTerm = this.searchValue.toLowerCase(); this.#clearItems(); + let addMode; + let itemsToAdd; if (lowerSearchTerm) { let searchWords = lowerSearchTerm.split(/\s+/); + addMode = BaseItemList.MODE_SEARCH; + itemsToAdd = []; for (let item of this.allItems) { let itemText = this.getItemText(item).toLowerCase(); @@ -494,18 +498,26 @@ export default class BaseItemList extends HTMLElement { } if (!mismatch) { - this._addItem(item, BaseItemList.MODE_SEARCH); + itemsToAdd.push(item); } } } else if (this.defaultItems) { - for (let item of this.defaultItems) { - this._addItem(item, BaseItemList.MODE_DEFAULT); - } + addMode = BaseItemList.MODE_DEFAULT; + itemsToAdd = this.defaultItems; } else { - for (let item of this.allItems) { - this._addItem(item, BaseItemList.MODE_ALL); - } + addMode = BaseItemList.MODE_ALL; + itemsToAdd = this.allItems; } + + itemsToAdd = this.sortItems(itemsToAdd); + + for (let item of itemsToAdd) { + this._addItem(item, addMode); + } + } + + sortItems(items) { + return items; } } diff --git a/src/popup/folderList.js b/src/popup/folderList.js index 0c15673..a478489 100644 --- a/src/popup/folderList.js +++ b/src/popup/folderList.js @@ -2,6 +2,7 @@ import BaseItemList from "./baseItemList.js"; class TBFolderList extends BaseItemList { #showFolderPath = false; + #reverseHierarchyCompact = false; #accounts = {}; static get style() { @@ -70,6 +71,22 @@ class TBFolderList extends BaseItemList { return folderNode.item.name; } + sortItems(items) { + if (this.#reverseHierarchyCompact) { + // sort in a new array + let sorted = []; + for (let item of items) { + sorted.push(item); + } + + sorted.sort(function(a,b){ + return a.fullPathReversed.toLowerCase().localeCompare(b.fullPathReversed.toLowerCase()); + }); + items = sorted; + } + return items; + } + _addItem(folderNode, mode) { // let depth = mode == BaseItemList.MODE_ALL ? (folderNode.path.match(/\//g) || []).length - 1 : 0; let depth = 0; @@ -84,11 +101,15 @@ class TBFolderList extends BaseItemList { // Filter out [Gmail] and empty path components. return val !== "" && !val.includes("["); }); - + let compact = this.hasAttribute("compact"); + let addAccountNode = true; if (compact) { - if (this.#showFolderPath) { + if (this.#reverseHierarchyCompact) { + addAccountNode = false; + item.querySelector(".text").innerHTML = folderNode.fullPathReversed; + } else if (this.#showFolderPath) { item.querySelector(".text").textContent = prettyFolderPathComponents.join("→"); } else { item.querySelector(".text").textContent = folderNode.name; @@ -104,7 +125,7 @@ class TBFolderList extends BaseItemList { item.querySelector(".item").item = folderNode.item; - if (!body.lastElementChild || body.lastElementChild.item.accountId != folderNode.accountId) { + if (addAccountNode && (!body.lastElementChild || body.lastElementChild.item.accountId != folderNode.accountId)) { let accountTemplate = this.shadowRoot.querySelector(".header-item-template"); let accountItem = this.shadowRoot.ownerDocument.importNode(accountTemplate.content, true); let account = this.#accounts[folderNode.accountId]; @@ -129,10 +150,11 @@ class TBFolderList extends BaseItemList { this.#accounts = Object.fromEntries(val.map(account => [account.id, account])); } - initItems(allItems, defaultItems, showFolderPath) { + initItems(allItems, defaultItems, showFolderPath, reverseHierarchyCompact) { this._allItems = allItems; this._defaultItems = defaultItems; this.#showFolderPath = showFolderPath; + this.#reverseHierarchyCompact = reverseHierarchyCompact; this.repopulate(); } diff --git a/src/popup/popup.js b/src/popup/popup.js index fb23e48..b1fcf62 100644 --- a/src/popup/popup.js +++ b/src/popup/popup.js @@ -31,8 +31,8 @@ function switchList(action) { } async function load() { - let { maxRecentFolders, showFolderPath, skipArchive, layout, defaultFolderSetting } = await browser.storage.local.get({ maxRecentFolders: 15, showFolderPath: true, layout: "auto", skipArchive: true, defaultFolderSetting: "recent" }); - + let { maxRecentFolders, showFolderPath, skipArchive, layout, defaultFolderSetting, reverseHierarchyCompact } = await browser.storage.local.get({ maxRecentFolders: 15, showFolderPath: true, layout: "auto", skipArchive: true, defaultFolderSetting: "recent", reverseHierarchyCompact: false }); + if (layout == "wide" || (layout == "auto" && window.outerWidth > 1400)) { document.documentElement.removeAttribute("compact"); document.getElementById("folder-list").removeAttribute("compact"); @@ -97,7 +97,7 @@ async function load() { let folderList = document.getElementById("folder-list"); folderList.accounts = accounts; - folderList.initItems(folders, defaultFolders, showFolderPath); + folderList.initItems(folders, defaultFolders, showFolderPath, reverseHierarchyCompact); folderList.ignoreFocus = true; folderList.addEventListener("item-selected", async (event) => { let operation = document.querySelector("input[name='action']:checked").value; From 4293037bc4cf3e9d1ea503ec330a6141f6adcaf7 Mon Sep 17 00:00:00 2001 From: Mitch Claborn Date: Mon, 16 Oct 2023 14:15:47 -0500 Subject: [PATCH 2/2] Add German and French translations for reverseHierarchyCompact --- src/_locales/de/messages.json | 4 ++-- src/_locales/fr/messages.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json index 03eba4c..c9d2f7d 100644 --- a/src/_locales/de/messages.json +++ b/src/_locales/de/messages.json @@ -93,9 +93,9 @@ "message": "Sie können nun ⇧M ⇧Y und ⇧G verwenden. Ändere die Tastenkürzel in der Erweiterungsverwaltung für Tastenkürzel." }, "reverseHierarchyCompact": { - "message": "Reverse hierarchy display (compact only)" + "message": "Hierarchieanzeige umkehren (nur kompakt)" }, "reverseHierarchyCompact.title": { - "message": "Compact mode only. Show the folder name first, in a reverse hierarchy, with the account name at the end. Don't show a separate line for the account. The list is sorted by the folder name (leaf node)." + "message": "Nur Kompaktmodus. Zeigen Sie zuerst den Ordnernamen in umgekehrter Hierarchie und am Ende den Kontonamen an. Für das Konto keine separate Zeile anzeigen. Die Liste ist nach dem Ordnernamen (Blattknoten) sortiert." } } diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json index 52f8add..ad1c06b 100644 --- a/src/_locales/fr/messages.json +++ b/src/_locales/fr/messages.json @@ -90,9 +90,9 @@ "message": "Vous pouvez à présent utiliser ⇧M ⇧Y et ⇧G. Utilisez l'extention shortcut pour les modifier." }, "reverseHierarchyCompact": { - "message": "Reverse hierarchy display (compact only)" + "message": "Affichage de la hiérarchie inversée (compact uniquement)" }, "reverseHierarchyCompact.title": { - "message": "Compact mode only. Show the folder name first, in a reverse hierarchy, with the account name at the end. Don't show a separate line for the account. The list is sorted by the folder name (leaf node)." + "message": "Mode compact uniquement. Affichez d'abord le nom du dossier, dans une hiérarchie inversée, avec le nom du compte à la fin. N'affichez pas de ligne distincte pour le compte. La liste est triée par nom de dossier (nœud feuille)." } }