!import
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1 <?xml version="1.0"?>
2 <!--
3 - ***** BEGIN LICENSE BLOCK *****
4 - Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 -
6 - The contents of this file are subject to the Mozilla Public License Version
7 - 1.1 (the "License"); you may not use this file except in compliance with
8 - the License. You may obtain a copy of the License at
9 - http://www.mozilla.org/MPL/
10 -
11 - Software distributed under the License is distributed on an "AS IS" basis,
12 - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 - for the specific language governing rights and limitations under the
14 - License.
15 -
16 - The Original Code is Mail folder code.
17 -
18 - The Initial Developer of the Original Code is
19 - Joey Minta <jminta@gmail.com>
20 - Portions created by the Initial Developer are Copyright (C) 2008
21 - the Initial Developer. All Rights Reserved.
22 -
23 - Contributor(s):
24 -
25 - Alternatively, the contents of this file may be used under the terms of
26 - either the GNU General Public License Version 2 or later (the "GPL"), or
27 - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 - in which case the provisions of the GPL or the LGPL are applicable instead
29 - of those above. If you wish to allow use of your version of this file only
30 - under the terms of either the GPL or the LGPL, and not to allow others to
31 - use your version of this file under the terms of the MPL, indicate your
32 - decision by deleting the provisions above and replace them with the notice
33 - and other provisions required by the GPL or the LGPL. If you do not delete
34 - the provisions above, a recipient may use your version of this file under
35 - the terms of any one of the MPL, the GPL or the LGPL.
36 -
37 - ***** END LICENSE BLOCK *****
38 -->
39
40 <bindings id="mailFolderBindings"
41 xmlns="http://www.mozilla.org/xbl"
42 xmlns:xbl="http://www.mozilla.org/xbl"
43 xmlns:html="http://www.w3.org/1999/xhtml"
44 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
45
46 <binding id="folder-menupopup"
47 extends="chrome://global/content/bindings/popup.xml#popup">
48 <implementation>
constructor
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
49 <constructor><![CDATA[
50 // If we are a child of a menulist, we need to build our content right
51 // away, otherwise the menulist won't have proper sizing
52 if (this.parentNode && this.parentNode.localName == "menulist")
53 this._ensureInitialized();
54 ]]></constructor>
55 <!--
56 - Make sure we remove our listener when the window is being destroyed
57 -->
destructor
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
58 <destructor><![CDATA[
59 if (!this._initialized)
60 return;
61
62 const Cc = Components.classes;
63 const Ci = Components.interfaces;
64 var session = Cc["@mozilla.org/messenger/services/session;1"].
65 getService(Ci.nsIMsgMailSession);
66 session.RemoveFolderListener(this._listener);
67 ]]></destructor>
68
69 <!--
70 - If non-null, the subFolders of this nsIMsgFolder will be used to
71 - populate this menu. If this is null, the menu will be populated
72 - using the root-folders for all accounts
73 -->
field__parentFolder
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
74 <field name="_parentFolder">null</field>
get_parentFolder
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
set_parentFolder
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
75 <property name="parentFolder"
76 onget="return this._parentFolder;"
77 onset="return this._parentFolder = val;"/>
78
79 <!--
80 - Various filtering modes can be used with this menu-binding. To use
81 - one of them, append the mode="foo" attribute to the element. When
82 - building the menu, we will then use this._filters[mode] as a filter
83 - function to eliminate folders that should not be shown.
84 -
85 - Note that extensions should feel free to plug in here!
86 -->
field__filters
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
87 <field name="_filters"><![CDATA[({
88 // Returns true if messages can be filed in the folder
filter_filing
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
89 filing: function filter_filing(aFolder) {
90 if (!aFolder.server.canFileMessagesOnServer)
91 return false;
92
93 return (aFolder.canFileMessages || aFolder.hasSubFolders);
94 },
95
96 // Returns true if we can get mail for this folder. (usually this just
97 // means the "root" fake folder)
filter_getMail
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
98 getMail: function filter_getMail(aFolder) {
99 if (aFolder.isServer && aFolder.server.type != "none")
100 return true;
101 if (aFolder.server.type == "nntp" || aFolder.server.type == "rss")
102 return true;
103 return false;
104 },
105
106 // Returns true if we can add filters to this folder/account
filter_filter
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
107 filters: function filter_filter(aFolder) {
108 // We can always filter news
109 if (aFolder.server.type == "nntp")
110 return true;
111
112 return aFolder.server.canHaveFilters;
113 },
114
filter_subscribe
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
115 subscribe: function filter_subscribe(aFolder) {
116 return aFolder.canSubscribe;
117 }
118 })]]></field>
119
120 <!--
121 - The maximum number of entries in the "Recent" menu
122 -->
field__MAXRECENT
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
123 <field name="_MAXRECENT">15</field>
124
125 <!--
126 - Our listener to let us know when folders change/appear/disappear so
127 - we can know to rebuild ourselves.
128 -->
field__listener
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
129 <field name="_listener"><![CDATA[({
130 _menu: this,
act_add
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
131 OnItemAdded: function act_add(aRDFParentItem, aItem) {
132 if (!(aItem instanceof Components.interfaces.nsIMsgFolder))
133 return;
134 if (this._filterFunction && !this._filterFunction(aItem)) {
135 return;
136 }
137 //xxx we can optimize this later
138 //xxx I'm not quite sure why this isn't always a function
139 if (this._menu._teardown)
140 this._menu._teardown();
141 },
142
act_remove
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
143 OnItemRemoved: function act_remove(aRDFParentItem, aItem) {
144 if (!(aItem instanceof Components.interfaces.nsIMsgFolder))
145 return;
146 if (this._filterFunction && !this._filterFunction(aItem)) {
147 return;
148 }
149 //xxx we can optimize this later
150 if (this._menu._teardown)
151 this._menu._teardown();
152 },
153
154 //xxx I stole this listener list from nsMsgFolderDatasource.cpp, but
155 // someone should really document what events are fired when, so that
156 // we make sure we're updating at the right times.
OnItemPropertyChanged
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
157 OnItemPropertyChanged: function(aItem, aProperty, aOld, aNew) {},
OnItemIntPropertyChanged
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
158 OnItemIntPropertyChanged: function(aItem, aProperty, aOld, aNew) {
159 var child = this._getChildForItem(aItem);
160 if (child) {
161 child._folder = aItem;
162 this._menu._setCssSelectors(child, child._folder);
163 }
164 },
OnItemBoolPropertyChanged
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
165 OnItemBoolPropertyChanged: function(aItem, aProperty, aOld, aNew) {
166 var child = this._getChildForItem(aItem);
167 if (child) {
168 child._folder = aItem;
169 this._menu._setCssSelectors(child, child._folder);
170 }
171 },
OnItemUnicharPropertyChanged
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
172 OnItemUnicharPropertyChanged: function(aItem, aProperty, aOld, aNew) {
173 var child = this._getChildForItem(aItem);
174 if (child) {
175 child._folder = aItem;
176 this._menu._setCssSelectors(child, child._folder);
177 }
178 },
OnItemPropertyFlagChanged
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
179 OnItemPropertyFlagChanged: function(aItem, aProperty, aOld, aNew) {},
OnItemEvent
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
180 OnItemEvent: function(aFolder, aEvent) {
181 var child = this._getChildForItem(aFolder);
182 if (child) {
183 // Special casing folder renames here, since they require more work
184 // since sort-order may have changed
185 if (aEvent.toString() == "RenameCompleted") {
186 this._menu._teardown();
187 this._menu._ensureInitialized();
188 return;
189 }
190 }
191 },
192
193 /**
194 * Helper function to check and see whether we have a menuitem for this
195 * particular nsIMsgFolder
196 *
197 * @param aItem the nsIMsgFolder to check
198 * @returns null if no child for that folder exists, otherwise the
199 * menuitem for that child
200 */
act__itemIsChild
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
201 _getChildForItem: function act__itemIsChild(aItem) {
202 if (!this._menu || !this._menu._initialized)
203 return null;
204
205 if (!(aItem instanceof Components.interfaces.nsIMsgFolder))
206 return null;
207 for (var i = 0; i < this._menu.childNodes; i++) {
208 var folder = this._menu.childNodes[i]._folder;
209 if (folder && folder.URI == aItem.URI)
210 return aItem;
211 }
212 return null;
213 }
214 })]]></field>
215
216 <!--
217 - True if we have already built our menu-items and are now just
218 - listening for changes
219 -->
field__initialized
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
220 <field name="_initialized">false</field>
221
222 <!--
223 - Call this if you are unsure whether the menu-items have been built,
224 - but know that they need to be built now if they haven't.
225 -->
226 <method name="_ensureInitialized">
_ensureInitialized
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
227 <body><![CDATA[
228 if (this._initialized)
229 return;
230
231 // I really wish they'd just make this global...
232 const Cc = Components.classes;
233 const Ci = Components.interfaces;
234
235 var folders = new Array();
236
237 // Figure out which folders to build. If we don't have a parent, then
238 // we assume we should build the top-level accounts. (Actually we
239 // build the fake root folders for those accounts.)
240 if (!this._parentFolder) {
241 var acctMgr = Cc["@mozilla.org/messenger/account-manager;1"].
242 getService(Ci.nsIMsgAccountManager);
243 var count = acctMgr.accounts.Count();
244
245 // Sadly, the accountMgr doesn't provide us we a sorted list of
246 // accounts. We have to get them in the right order on our own. To
247 // Do this, we'll stick them in an array, and then sort that array.
248 var accounts = new Array();
249 for (var i = 0; i < count; i++) {
250 var acct = acctMgr.accounts.GetElementAt(i).QueryInterface(Ci.nsIMsgAccount);
251
252 // This is a HACK to work around bug 41133. If we have one of the
253 // dummy "news" accounts there, that account won't have an
254 // incomingServer attached to it, and everything will blow up.
255 if (acct.incomingServer)
256 accounts.push(acct);
257 }
258
259 /**
260 * This is our actual function for sorting accounts. Accounts go
261 * in the following order: (1) default account (2) other mail
262 * accounts (3) Local Folders (4) news
263 */
accountCompare
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
264 function accountCompare(a, b) {
265 if (a.key == acctMgr.defaultAccount.key)
266 return -1;
267 if (b.key == acctMgr.defaultAccount.key)
268 return 1;
269 var aIsNews = a.incomingServer.type == "nntp";
270 var bIsNews = b.incomingServer.type == "nntp";
271 if (aIsNews && !bIsNews)
272 return 1;
273 if (bIsNews && !aIsNews)
274 return -1;
275
276 var aIsLocal = a.incomingServer.type == "none";
277 var bIsLocal = b.incomingServer.type == "none";
278 if (aIsLocal && !bIsLocal)
279 return 1;
280 if (bIsLocal && !aIsLocal)
281 return -1;
282 return 0;
283 }
284 accounts = accounts.sort(accountCompare);
285
286 // Now generate our folder-list. Note that we'll special case this
287 // situation below, to avoid destroying the sort order we just made
288 for each (var acct in accounts) {
289 folders.push(acct.incomingServer.rootFolder);
290 }
291 } else {
292 // If we do have a parent folder, then we just build based on those
293 // subFolders for that parent
294 var myenum = this._parentFolder.subFolders;
295 while (myenum.hasMoreElements()) {
296 folders.push(myenum.getNext().QueryInterface(Ci.nsIMsgFolder));
297 }
298 }
299
300 // Lastly, we add a listener to get notified of changes in the folder
301 // structure.
302 var session = Cc["@mozilla.org/messenger/services/session;1"].
303 getService(Ci.nsIMsgMailSession);
304 session.AddFolderListener(this._listener, Ci.nsIFolderListener.all);
305
306 this._build(folders);
307 this._initialized = true;
308 ]]></body>
309 </method>
310
311 <!--
312 - Actually constructs the menu-items based on the folders given
313 -
314 - @param aFolders an array of nsIMsgFolders to use for building
315 -->
316 <method name="_build">
317 <parameter name="aFolders"/>
_build
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
318 <body><![CDATA[
319 // I'm not entirely happy about having to hard-code this as an attr,
320 // but there doesn't seem to be a better way.
321 if (this.getAttribute("showFileHereLabel") == "true" &&
322 this._parentFolder &&
323 (this._parentFolder.noSelect || this._parentFolder.canFileMessages)) {
324 var menuitem = document.createElement("menuitem");
325 menuitem._folder = this._parentFolder;
326 menuitem.setAttribute("label", this.getAttribute("fileHereLabel"));
327 menuitem.setAttribute("accesskey", this.getAttribute("fileHereAccessKey"));
328 // Eww. have to support some legacy code here...
329 menuitem.setAttribute("id", this._parentFolder.URI);
330 this.appendChild(menuitem);
331
332 if (this._parentFolder.noSelect)
333 menuitem.setAttribute("disabled", "true");
334
335 this.appendChild(document.createElement("menuseparator"));
336 }
337
338 // Some menus want a "Recent" option, but that should only be on our
339 // top-level menu
340 if (!this._parentFolder && this.getAttribute("showRecent") == "true") {
341 this._buildRecentMenu();
342 }
343
344 var folders;
345 // Extensions and other consumers can add to these modes too, see the
346 // above note on the _filters field.
347 var mode = this.getAttribute("mode");
348 if (mode && mode != "") {
349 var filterFunction = this._filters[mode];
350 folders = aFolders.filter(filterFunction);
351 this._listener._filterFunction = filterFunction;
352 } else {
353 folders = aFolders;
354 }
355
356 /**
357 * Sorts the list of folders. We give first priority to the sortKey
358 * property, and then via a case-insensitive comparison of names
359 */
nameCompare
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
360 function nameCompare(a, b) {
361 var sortKey = a.compareSortKeys(b);
362 if (sortKey)
363 return sortKey;
364 return a.prettyName.toLowerCase() > b.prettyName.toLowerCase();
365 }
366
367 /**
368 * If we're the root of the folder hierarchy, then we actually don't
369 * want to sort the folders, but rather the accounts to which the
370 * folders belong. Since that sorting was already done, we don't need
371 * to do anything for that case here
372 */
373 if (this._parentFolder)
374 folders = folders.sort(nameCompare);
375
376 for each (var folder in folders) {
377 var node;
378 // If we're going to add subFolders, we need to make menus, not
379 // menuitems.
380 if (!folder.hasSubFolders || this.getAttribute("expandFolders") == "false") {
381 node = document.createElement("menuitem");
382 // Grumble, grumble, legacy code support
383 node.setAttribute("id", folder.URI);
384 node.setAttribute("class", "folderMenuItem menuitem-iconic");
385 this.appendChild(node);
386 } else {
387 //xxx this is slightly problematic in that we haven't confirmed
388 // whether any of the subfolders will pass the filter
389 node = document.createElement("menu");
390 node.setAttribute("class", "folderMenuItem menu-iconic");
391 this.appendChild(node);
392 var popup = this.cloneNode(true);
393 popup._teardown();
394 node.appendChild(popup);
395 popup.parentFolder = folder;
396 }
397 node._folder = folder;
398 node.setAttribute("label", folder.prettyName);
399
400 this._setCssSelectors(folder, node);
401
402 //xxx for later optimization
403 //builtFolders.push(folder);
404 }
405 ]]></body>
406 </method>
407
408 <!--
409 - Builds a submenu with all of the recently used folders in it, to
410 - allow for easy access.
411 -->
412 <method name="_buildRecentMenu">
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
413 <body><![CDATA[
414 const Cc = Components.classes;
415 const Ci = Components.interfaces;
416 // Iterate through all folders in all accounts, and check MRU_Time,
417 // then take the most current 15.
418
419 /**
420 * This function will iterate through any existing sub-folders and
421 * (1) check if they're recent and (2) recursively call this function
422 * to iterate through any sub-sub-folders.
423 *
424 * @param aFolder the folder to check
425 */
checkSubFolders
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
426 function checkSubFolders(aFolder) {
427 if (!aFolder.hasSubFolders)
428 return;
429
430 var myenum = aFolder.subFolders;
431 while (myenum.hasMoreElements()) {
432 var folder = myenum.getNext().QueryInterface(Ci.nsIMsgFolder);
433 addIfRecent(folder);
434 checkSubFolders(folder);
435 }
436 }
437
438 var recentFolders = [];
439 var oldestTime = 0;
440
441 /**
442 * This function will add a folder to the recentFolders array if it
443 * is among the 15 most recent. If we exceed 15 folders, it will pop
444 * the oldest folder, ensuring that we end up with the right number
445 *
446 * @param aFolder the folder to check
447 */
448 var menu = this;
addIfRecent
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
449 function addIfRecent(aFolder) {
450 if (!aFolder.canFileMessages)
451 return;
452
453 var time = aFolder.getStringProperty("MRUTime") || 0;
454 if (time <= oldestTime)
455 return;
456
457 if (recentFolders.length == menu._MAXRECENT) {
458 recentFolders.sort(sorter);
459 recentFolders.pop();
460 oldestTime = recentFolders[recentFolders.length-1].getStringProperty("MRUTime");
461 }
462 recentFolders.push(aFolder);
463 }
464
465 // Start iterating at the top of the hierarchy, that is, with the root
466 // folders for each account.
467 var acctMgr = Cc["@mozilla.org/messenger/account-manager;1"].
468 getService(Ci.nsIMsgAccountManager);
469 var count = acctMgr.accounts.Count();
470 for (var i = 0; i < count; i++) {
471 var acct = acctMgr.accounts.GetElementAt(i).QueryInterface(Ci.nsIMsgAccount);
472 addIfRecent(acct.incomingServer.rootFolder);
473 checkSubFolders(acct.incomingServer.rootFolder);
474 }
475
sorter
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
476 function sorter(a, b) {
477 return a.getStringProperty("MRUTime") < b.getStringProperty("MRUTime");
478 }
479 recentFolders.sort(sorter);
480
481 // Because we're scanning across multiple accounts, we can end up with
482 // two folders with the same name. In this case, we append the name
483 // of the account as well, to distingiush.
484 var dupeNames = [];
485 for (var i = 0; i < recentFolders.length; i++) {
486 for (var j = i + 1; j < recentFolders.length; j++) {
487 // We can end up with the same name in dupeNames more than once,
488 // but that's ok.
489 if (recentFolders[i].prettyName == recentFolders[j].prettyName)
490 dupeNames.push(recentFolders[i].prettyName);
491 }
492 }
493
494 // Now create the Recent folder and its children
495 var menu = document.createElement("menu");
496 menu.setAttribute("label", this.getAttribute("recentLabel"));
497 menu.setAttribute("accesskey", this.getAttribute("recentAccessKey"));
498 var popup = document.createElement("menupopup");
499 menu.appendChild(popup);
500
501 // Create entries for each of the recent folders.
502 for each (var folder in recentFolders) {
503 var node = document.createElement("menuitem");
504
505 var label = folder.prettyName;
506 if (dupeNames.indexOf(label) != -1)
507 label += " - " + folder.server.prettyName;
508 node.setAttribute("label", label);
509
510 node.setAttribute("class", "folderMenuItem menuitem-iconic");
511 this._setCssSelectors(folder, node);
512 popup.appendChild(node);
513 }
514 this.appendChild(menu);
515 var sep = document.createElement("menuseparator");
516 this.appendChild(sep);
517 ]]></body>
518 </method>
519
520 <!--
521 - This function adds attributes on menu/menuitems to make it easier for
522 - css to style them.
523 -
524 - @param aFolder the folder that corresponds to the menu/menuitem
525 - @param aMenuNode the actual DOM node to set attributes on
526 -->
527 <method name="_setCssSelectors">
528 <parameter name="aFolder"/>
529 <parameter name="aMenuNode"/>
_setCssSelectors
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
530 <body><![CDATA[
531 const Ci = Components.interfaces;
532 // First set the SpecialFolder attribute
533 // Sigh... why aren't these in an IDL somewhere public?
534 if (aFolder.flags & 0x1000) // MSG_FOLDER_FLAG_INBOX
535 aMenuNode.setAttribute("SpecialFolder", "Inbox");
536 else if (aFolder.flags & 0x0100) // MSG_FOLDER_FLAG_TRASH
537 aMenuNode.setAttribute("SpecialFolder", "Trash");
538 else if (aFolder.flags & 0x0800) // MSG_FOLDER_FLAG_QUEUE
539 aMenuNode.setAttribute("SpecialFolder", "Unsent Messages");
540 else if (aFolder.flags & 0x0200) // MSG_FOLDER_FLAG_SENTMAIL
541 aMenuNode.setAttribute("SpecialFolder", "Sent");
542 else if (aFolder.flags & 0x0400) // MSG_FOLDER_FLAG_DRAFTS
543 aMenuNode.setAttribute("SpecialFolder", "Drafts");
544 else if (aFolder.flags & 0x400000) // MSG_FOLDER_FLAG_TEMPLATES
545 aMenuNode.setAttribute("SpecialFolder", "Templates");
546 else if (aFolder.flags & 0x40000000) // MSG_FOLDER_FLAG_JUNK
547 aMenuNode.setAttribute("SpecialFolder", "Junk");
548 else if (aFolder.flags & 0x0020) // MSG_FOLDER_FLAG_VIRTUAL
549 aMenuNode.setAttribute("SpecialFolder", "Virtual");
550 else
551 aMenuNode.setAttribute("SpecialFolder", "none");
552
553 // Now set the biffState
554 var biffStates = ["NewMail", "NoMail", "UnknownMail"];
555 for each (var state in biffStates) {
556 if (aFolder.biffState == Ci.nsIMsgFolder["nsMsgBiffState_" + state]) {
557 aMenuNode.setAttribute("BiffState", state);
558 break;
559 }
560 }
561
562 // IsServer is simple
563 aMenuNode.setAttribute("IsServer", aFolder.isServer);
564
565 // We have to work a bit for IsSecure. This sucks
566 var server = aFolder.server;
567 if (server instanceof Ci.nsINntpIncomingServer) {
568 aMenuNode.setAttribute("IsSecure", server.isSecure);
569 } else {
570 // If it's not a news-server, apparently we look at the socket type
571 var sock = server.socketType;
572 var isSecure = (sock == Ci.nsIMsgIncomingServer.alwaysUseTLS ||
573 sock == Ci.nsIMsgIncomingServer.useSSL);
574 aMenuNode.setAttribute("IsSecure", isSecure);
575 }
576
577 // the ServerType attribute
578 aMenuNode.setAttribute("ServerType", aFolder.server.type);
579 ]]></body>
580 </method>
581
582 <!--
583 - Makes a given folder selected.
584 -
585 - @param aFolder the folder to select
586 - @note If aFolder is not in this popup, but is instead a descendant of
587 - a member of the popup, that ancestor will be selected.
588 -->
589 <method name="selectFolder">
590 <parameter name="aFolder"/>
selectFolder
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
591 <body><![CDATA[
592 for (var i in this.childNodes) {
593 var child = this.childNodes[i];
594 if (!child || !child._folder)
595 continue;
596 if (child._folder.URI == aFolder.URI || (this._parentFolder &&
597 this._parentFolder.isAncestorOf(aFolder))) {
598 // Making an assumption about our DOM positioning here.
599 this.parentNode.selectedIndex = i;
600 return;
601 }
602 }
603 Components.utils.reportError("unable to find folder to select!");
604 ]]></body>
605 </method>
606
607 <!--
608 - Removes all menu-items for this popup, resets all fields, and
609 - removes the listener.
610 -->
611 <method name="_teardown">
_teardown
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
612 <body><![CDATA[
613 while(this.hasChildNodes())
614 this.removeChild(this.lastChild);
615
616 const Cc = Components.classes;
617 const Ci = Components.interfaces;
618 var session = Cc["@mozilla.org/messenger/services/session;1"].
619 getService(Ci.nsIMsgMailSession);
620 session.RemoveFolderListener(this._listener);
621
622 this._folders = null;
623 this._initialized = false;
624 ]]></body>
625 </method>
626 </implementation>
627
628 <handlers>
629 <!--
630 - In order to improve performance, we're not going to build any of the
631 - menu until we're shown (unless we're the child of a menulist, see
632 - note in the constructor).
633 -
634 - @note _ensureInitialized can be called repeatedly without issue, so
635 - don't worry about it here.
636 -->
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
637 <handler event="popupshowing" phase="capturing">
638 this._ensureInitialized();
639 </handler>
640 </handlers>
641 </binding>
642 </bindings>