summaryrefslogtreecommitdiffstats
path: root/comm/mail/extensions/mailviews/content/msgViewPickerOverlay.js
blob: 4412be2ffe5668b60065f7cb86f4497eb84bbe6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/* 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 OpenOrFocusWindow */ // From mailWindowOverlay.js
/* globals GetSelectedMsgFolders */ // From messenger.js

var { MailServices } = ChromeUtils.import(
  "resource:///modules/MailServices.jsm"
);
var { MailViewConstants } = ChromeUtils.import(
  "resource:///modules/MailViewManager.jsm"
);

// these constants are now authoritatively defined in MailViewManager.jsm (above)
// tag views have kViewTagMarker + their key as value
var kViewItemAll = MailViewConstants.kViewItemAll;
var kViewItemUnread = MailViewConstants.kViewItemUnread;
var kViewItemTags = MailViewConstants.kViewItemTags; // former labels used values 2-6
var kViewItemNotDeleted = MailViewConstants.kViewItemNotDeleted;
// not a real view! a sentinel value to pop up a dialog
var kViewItemVirtual = MailViewConstants.kViewItemVirtual;
// not a real view! a sentinel value to pop up a dialog
var kViewItemCustomize = MailViewConstants.kViewItemCustomize;
var kViewItemFirstCustom = MailViewConstants.kViewItemFirstCustom;

var kViewCurrent = MailViewConstants.kViewCurrent;
var kViewCurrentTag = MailViewConstants.kViewCurrentTag;
var kViewTagMarker = MailViewConstants.kViewTagMarker;

/**
 * A reference to the nsIMsgMailViewList service that tracks custom mail views.
 */
var gMailViewList = null;

// perform the view/action requested by the aValue string
// and set the view picker label to the aLabel string
function ViewChange(aValue) {
  let about3Pane = document.getElementById("tabmail").currentAbout3Pane;
  let viewWrapper = about3Pane.gViewWrapper;
  if (!viewWrapper) {
    return;
  }

  if (aValue == kViewItemCustomize || aValue == kViewItemVirtual) {
    // restore to the previous view value, in case they cancel
    if (aValue == kViewItemCustomize) {
      LaunchCustomizeDialog();
    } else {
      about3Pane.folderPane.newVirtualFolder(
        ViewPickerBinding.currentViewLabel,
        viewWrapper.search.viewTerms,
        about3Pane.gFolder
      );
    }
    return;
  }

  // tag menuitem values are of the form :<keyword>
  if (isNaN(aValue)) {
    // split off the tag key
    var tagkey = aValue.substr(kViewTagMarker.length);
    viewWrapper.setMailView(kViewItemTags, tagkey);
  } else {
    var numval = Number(aValue);
    viewWrapper.setMailView(numval, null);
  }
}

function ViewChangeByMenuitem(aMenuitem) {
  // Mac View menu menuitems don't have XBL bindings
  ViewChange(aMenuitem.getAttribute("value"));
}

/**
 * Mediates interaction with the #viewPickerPopup.  In theory this should be
 *  an XBL binding, but for the insanity where the view picker may not be
 *  visible at all times (or ever).  No view picker widget, no binding.
 */
var ViewPickerBinding = {
  /**
   * Return true if the view picker is visible.  This is used by the
   *  FolderDisplayWidget to know whether or not to actually use mailviews. (The
   *  idea is that if we are not visible, then it would be confusing to the user
   *  if we filtered their mail since they would have no feedback about this and
   *  no way to change it.)
   */
  get isVisible() {
    return !!document.querySelector("#unifiedToolbarContent .view-picker");
  },

  /**
   * Return the string value representing the current mail view value as
   * understood by the view picker widgets.  The value is the index for
   * everything but tags.  for tags it's the ":"-prefixed tagname.
   */
  get currentViewValue() {
    let about3Pane = document.getElementById("tabmail").currentAbout3Pane;
    let viewWrapper = about3Pane.gViewWrapper;
    if (!viewWrapper) {
      return "";
    }
    if (viewWrapper.mailViewIndex == kViewItemTags) {
      return kViewTagMarker + viewWrapper.mailViewData;
    }
    return viewWrapper.mailViewIndex + "";
  },

  /**
   * @returns The label for the current mail view value.
   */
  get currentViewLabel() {
    return document.querySelector(
      `#toolbarViewPickerPopup [value="${this.currentViewValue}"]`
    )?.label;
  },
};

function LaunchCustomizeDialog() {
  OpenOrFocusWindow(
    {},
    "mailnews:mailviewlist",
    "chrome://messenger/content/mailViewList.xhtml"
  );
}

/**
 * All of these Refresh*ViewPopup* methods have to deal with several menu
 * instances. For example, the "View... Messages" menu, the view picker menu
 * list in the toolbar, in appmenu/View/Messages, etc.
 *
 * @param {Element} viewPopup - A menu popup element.
 */
function RefreshAllViewPopups(viewPopup) {
  RefreshViewPopup(viewPopup);
  let menupopups = viewPopup.getElementsByTagName("menupopup");
  if (menupopups.length > 1) {
    // When we have menupopups, we assume both tags and custom views are there.
    RefreshTagsPopup(menupopups[0]);
    RefreshCustomViewsPopup(menupopups[1]);
  }
}

/**
 * Refresh the view messages popup menu/panel. For example set checked and
 * hidden state on menu items. Used for example for appmenu/View/Messages panel.
 *
 * @param {Element} viewPopup - A menu popup element.
 */
function RefreshViewPopup(viewPopup) {
  // Mark default views if selected.
  let currentViewValue = ViewPickerBinding.currentViewValue;

  let viewAll = viewPopup.querySelector('[value="' + kViewItemAll + '"]');
  viewAll.setAttribute("checked", currentViewValue == kViewItemAll);

  let viewUnread = viewPopup.querySelector('[value="' + kViewItemUnread + '"]');
  viewUnread.setAttribute("checked", currentViewValue == kViewItemUnread);

  let viewNotDeleted = viewPopup.querySelector(
    '[value="' + kViewItemNotDeleted + '"]'
  );

  let folderArray = GetSelectedMsgFolders();
  if (folderArray.length == 0) {
    return;
  }

  // Only show the "Not Deleted" item for IMAP servers that are using the IMAP
  // delete model.
  viewNotDeleted.setAttribute("hidden", true);
  var msgFolder = folderArray[0];
  var server = msgFolder.server;
  if (server.type == "imap") {
    let imapServer = server.QueryInterface(Ci.nsIImapIncomingServer);

    if (imapServer.deleteModel == Ci.nsMsgImapDeleteModels.IMAPDelete) {
      viewNotDeleted.setAttribute("hidden", false);
      viewNotDeleted.setAttribute(
        "checked",
        currentViewValue == kViewItemNotDeleted
      );
    }
  }
}

/**
 * Refresh the contents of the custom views popup menu/panel.
 * Used for example for appmenu/View/Messages/CustomViews panel.
 *
 * @param {Element} parent - Parent element that will receive the menu items.
 * @param {string} [elementName] - Type of menu items to create (e.g. "menuitem", "toolbarbutton").
 * @param {string} [classes] - Classes to set on the menu items.
 */
function RefreshCustomViewsPopup(parent, elementName = "menuitem", classes) {
  if (!gMailViewList) {
    gMailViewList = Cc["@mozilla.org/messenger/mailviewlist;1"].getService(
      Ci.nsIMsgMailViewList
    );
  }

  // Remove all menu items.
  while (parent.hasChildNodes()) {
    parent.lastChild.remove();
  }

  // Rebuild the list.
  const currentView = ViewPickerBinding.currentViewValue;
  const numItems = gMailViewList.mailViewCount;

  for (let i = 0; i < numItems; ++i) {
    const viewInfo = gMailViewList.getMailViewAt(i);
    const item = document.createXULElement(elementName);

    item.setAttribute("label", viewInfo.prettyName);
    item.setAttribute("value", kViewItemFirstCustom + i);
    item.setAttribute("type", "radio");

    if (classes) {
      item.setAttribute("class", classes);
    }
    if (kViewItemFirstCustom + i == currentView) {
      item.setAttribute("checked", true);
    }

    item.addEventListener("command", () =>
      ViewChange(kViewItemFirstCustom + i)
    );

    parent.appendChild(item);
  }
}

/**
 * Refresh the contents of the tags popup menu/panel. For example, used for
 * appmenu/View/Messages/Tags.
 *
 * @param {Element} parent - Parent element that will receive the menu items.
 * @param {string} [elementName] - Type of menu items to create (e.g. "menuitem", "toolbarbutton").
 * @param {string} [classes] - Classes to set on the menu items.
 */
function RefreshTagsPopup(parent, elementName = "menuitem", classes) {
  // Remove all pre-existing menu items.
  while (parent.hasChildNodes()) {
    parent.lastChild.remove();
  }

  // Create tag menu items.
  let about3Pane = document.getElementById("tabmail").currentAbout3Pane;
  let viewWrapper = about3Pane.gViewWrapper;
  if (!viewWrapper) {
    return;
  }
  const currentTagKey =
    viewWrapper.mailViewIndex == kViewItemTags ? viewWrapper.mailViewData : "";

  const tagArray = MailServices.tags.getAllTags();

  tagArray.forEach(tagInfo => {
    const item = document.createXULElement(elementName);

    item.setAttribute("label", tagInfo.tag);
    item.setAttribute("value", kViewTagMarker + tagInfo.key);
    item.setAttribute("type", "radio");

    if (tagInfo.key == currentTagKey) {
      item.setAttribute("checked", true);
    }
    if (tagInfo.color) {
      item.setAttribute("style", `color: ${tagInfo.color};`);
    }
    if (classes) {
      item.setAttribute("class", classes);
    }

    item.addEventListener("command", () =>
      ViewChange(kViewTagMarker + tagInfo.key)
    );

    parent.appendChild(item);
  });
}