summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/base/content/virtualFolderListEdit.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/base/content/virtualFolderListEdit.js')
-rw-r--r--comm/mailnews/base/content/virtualFolderListEdit.js206
1 files changed, 206 insertions, 0 deletions
diff --git a/comm/mailnews/base/content/virtualFolderListEdit.js b/comm/mailnews/base/content/virtualFolderListEdit.js
new file mode 100644
index 0000000000..775d3ba1c7
--- /dev/null
+++ b/comm/mailnews/base/content/virtualFolderListEdit.js
@@ -0,0 +1,206 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* globals PROTO_TREE_VIEW */
+
+var { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ FolderUtils: "resource:///modules/FolderUtils.jsm",
+ MailUtils: "resource:///modules/MailUtils.jsm",
+});
+
+window.addEventListener("DOMContentLoaded", () => {
+ gSelectVirtual.load();
+});
+
+var gFolderTreeView = new PROTO_TREE_VIEW();
+
+var gSelectVirtual = {
+ _treeElement: null,
+ _selectedList: new Set(),
+
+ load() {
+ if (window.arguments[0].searchFolderURIs) {
+ let srchFolderUriArray = window.arguments[0].searchFolderURIs.split("|");
+ for (let uri of srchFolderUriArray) {
+ this._selectedList.add(MailUtils.getOrCreateFolder(uri));
+ }
+ }
+
+ // Add the top level of the folder tree.
+ for (let account of FolderUtils.allAccountsSorted(true)) {
+ let server = account.incomingServer;
+ if (
+ server instanceof Ci.nsIPop3IncomingServer &&
+ server.deferredToAccount
+ ) {
+ continue;
+ }
+
+ gFolderTreeView._rowMap.push(new FolderRow(server.rootFolder));
+ }
+
+ // Recursively expand the tree to show all selected folders.
+ function expandToSelected(row, i) {
+ hiddenFolders.delete(row._folder);
+ for (let folder of hiddenFolders) {
+ if (row._folder.isAncestorOf(folder)) {
+ gFolderTreeView.toggleOpenState(i);
+ for (let j = row.children.length - 1; j >= 0; j--) {
+ expandToSelected(row.children[j], i + j + 1);
+ }
+ break;
+ }
+ }
+ }
+
+ let hiddenFolders = new Set(gSelectVirtual._selectedList);
+ for (let i = gFolderTreeView.rowCount - 1; i >= 0; i--) {
+ expandToSelected(gFolderTreeView._rowMap[i], i);
+ }
+
+ this._treeElement = document.getElementById("folderPickerTree");
+ this._treeElement.view = gFolderTreeView;
+ },
+
+ onKeyPress(aEvent) {
+ // For now, only do something on space key.
+ if (aEvent.charCode != aEvent.DOM_VK_SPACE) {
+ return;
+ }
+
+ let selection = this._treeElement.view.selection;
+ let start = {};
+ let end = {};
+ let numRanges = selection.getRangeCount();
+
+ for (let range = 0; range < numRanges; range++) {
+ selection.getRangeAt(range, start, end);
+ for (let i = start.value; i <= end.value; i++) {
+ this._toggle(i);
+ }
+ }
+ },
+
+ onClick(aEvent) {
+ // We only care about button 0 (left click) events.
+ if (aEvent.button != 0) {
+ return;
+ }
+
+ // We don't want to toggle when clicking on header or tree (scrollbar) or
+ // on treecol.
+ if (aEvent.target.nodeName != "treechildren") {
+ return;
+ }
+
+ let treeCellInfo = this._treeElement.getCellAt(
+ aEvent.clientX,
+ aEvent.clientY
+ );
+ if (treeCellInfo.row == -1 || treeCellInfo.col.id != "selectedCol") {
+ return;
+ }
+
+ this._toggle(treeCellInfo.row);
+ },
+
+ _toggle(aRow) {
+ let folder = gFolderTreeView._rowMap[aRow]._folder;
+ if (this._selectedList.has(folder)) {
+ this._selectedList.delete(folder);
+ } else {
+ this._selectedList.add(folder);
+ }
+
+ gFolderTreeView._tree.invalidateRow(aRow);
+ },
+
+ onAccept() {
+ // XXX We should just pass the folder objects around...
+ let uris = [...this._selectedList.values()]
+ .map(folder => folder.URI)
+ .join("|");
+
+ if (window.arguments[0].okCallback) {
+ window.arguments[0].okCallback(uris);
+ }
+ },
+};
+
+document.addEventListener("dialogaccept", () => gSelectVirtual.onAccept());
+
+/**
+ * A tree row representing a single folder.
+ */
+class FolderRow {
+ constructor(folder, parent = null) {
+ this._folder = folder;
+ this._open = false;
+ this._level = parent ? parent.level + 1 : 0;
+ this._parent = parent;
+ this._children = null;
+ }
+
+ get id() {
+ return this._folder.URI;
+ }
+
+ get text() {
+ return this.getText("folderNameCol");
+ }
+
+ getText(aColName) {
+ switch (aColName) {
+ case "folderNameCol":
+ return this._folder.abbreviatedName;
+ default:
+ return "";
+ }
+ }
+
+ get open() {
+ return this._open;
+ }
+
+ get level() {
+ return this._level;
+ }
+
+ getProperties(column) {
+ let properties = "";
+ switch (column?.id) {
+ case "folderNameCol":
+ // From folderUtils.jsm.
+ properties = FolderUtils.getFolderProperties(this._folder, this.open);
+ break;
+ case "selectedCol":
+ properties = "selectedColumn";
+ if (gSelectVirtual._selectedList.has(this._folder)) {
+ properties += " selected-true";
+ }
+ break;
+ }
+ return properties;
+ }
+
+ get children() {
+ if (this._children === null) {
+ this._children = [];
+ for (let subFolder of this._folder.subFolders) {
+ if (!subFolder.getFlag(Ci.nsMsgFolderFlags.Virtual)) {
+ this._children.push(new FolderRow(subFolder, this));
+ }
+ }
+ this._children.sort((a, b) => a._folder.compareSortKeys(b._folder));
+ }
+ return this._children;
+ }
+}