!import
1 <?xml version="1.0"?>
2
3 <bindings id="mailBindings"
4 xmlns="http://www.mozilla.org/xbl"
5 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
6 xmlns:nc="http://home.netscape.com/NC-rdf#"
7 xmlns:xbl="http://www.mozilla.org/xbl">
8
9 <!-- dummy widget to force this file to load -->
10 <binding id="dummy" extends="xul:box"/>
11
12 <!-- temporary holding place for horizontal list -->
13
14 <binding id="extdescription" extends="chrome://global/content/bindings/listbox.xml#listbox-base">
15 <implementation>
constructor
16 <constructor><![CDATA[
anon:17:31
17 this.children.filter(function(aChild) aChild.getAttribute("selected") == "true")
18 .forEach(this.selectedItems.push, this.selectedItems);
19 ]]></constructor>
20
21 <!-- ///////////////// public members ///////////////// -->
22
get_itemCount
23 <property name="itemCount" readonly="true"
24 onget="return this.children.length;"/>
25
26 <method name="getIndexOfItem">
27 <parameter name="item"/>
getIndexOfItem
28 <body><![CDATA[
29 return this.children.indexOf(item);
30 ]]></body>
31 </method>
32 <method name="getItemAtIndex">
33 <parameter name="index"/>
getItemAtIndex
34 <body><![CDATA[
35 return this.children[index] || null;
36 ]]></body>
37 </method>
38 <method name="getRowCount">
getRowCount
39 <body><![CDATA[
40 return this.children.length;
41 ]]></body>
42 </method>
43 <method name="getNumberOfVisibleRows">
getNumberOfVisibleRows
44 <body><![CDATA[
45 var firstItem = this.children[0] || null;
46 if (!firstItem)
47 return 0; // nothing to be visible
48 var itemsPerRow = Math.floor(this.boxObject.width / firstItem.boxObject.width);
49 var itemsPerCol = Math.floor(this.boxObject.height / firstItem.boxObject.height);
50 return Math.max(itemsPerRow, 1) * Math.max(itemsPerCol, 1);
51 ]]></body>
52 </method>
53 <method name="getIndexOfFirstVisibleRow">
getIndexOfFirstVisibleRow
54 <body><![CDATA[
55 //XXXzeniko unimplementable without a way to scroll
56 ]]></body>
57 </method>
58
59 <method name="ensureIndexIsVisible">
60 <parameter name="index"/>
ensureIndexIsVisible
61 <body><![CDATA[
62 this.ensureElementIsVisible(this.getItemAtIndex(index));
63 ]]></body>
64 </method>
65 <method name="ensureElementIsVisible">
66 <parameter name="item"/>
ensureElementIsVisible
67 <body><![CDATA[
68 //XXXzeniko unimplementable without a way to scroll
69 ]]></body>
70 </method>
71 <method name="scrollToIndex">
72 <parameter name="index"/>
scrollToIndex
73 <body><![CDATA[
74 //XXXzeniko unimplementable without a way to scroll
75 ]]></body>
76 </method>
77
78 <method name="appendItem">
79 <parameter name="label"/>
80 <parameter name="value"/>
appendItem
81 <body><![CDATA[
82 // -1 appends due to the way getItemAtIndex is implemented
83 return this.insertItemAt(-1, label, value);
84 ]]></body>
85 </method>
86 <method name="insertItemAt">
87 <parameter name="index"/>
88 <parameter name="label"/>
89 <parameter name="value"/>
insertItemAt
90 <body><![CDATA[
91 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
92 var item = document.createElementNS(XULNS, "descriptionitem");
93 item.setAttribute("label", label);
94 this.insertBefore(item, this.getItemAtIndex(index));
95 return item;
96 ]]></body>
97 </method>
98
99 <method name="scrollOnePage">
100 <parameter name="direction"/>
scrollOnePage
101 <body><![CDATA[
102 return direction * this.getNumberOfVisibleRows();
103 ]]></body>
104 </method>
105
106 <!-- ///////////////// private members ///////////////// -->
107
get_children
108 <property name="children" readonly="true"
109 onget="return Array.slice(this.getElementsByTagName('descriptionitem'));"/>
110
111 <method name="_fireOnSelect">
_fireOnSelect
112 <body><![CDATA[
113 if (!this._suppressOnSelect && !this.suppressOnSelect) {
114 var event = document.createEvent("Events");
115 event.initEvent("select", false, true);
116 this.dispatchEvent(event);
117 }
118 ]]></body>
119 </method>
120 </implementation>
121
122 <handlers>
onkeypress
123 <handler event="keypress" keycode="VK_LEFT" modifiers="control shift any"
124 action="this.moveByOffset(-1, !event.ctrlKey, event.shiftKey);"
125 phase="target" preventdefault="true"/>
onkeypress
126 <handler event="keypress" keycode="VK_RIGHT" modifiers="control shift any"
127 action="this.moveByOffset(1, !event.ctrlKey, event.shiftKey);"
128 phase="target" preventdefault="true"/>
onclick
129 <handler event="click" button="0" phase="target"><![CDATA[
130 if (this.selType != "multiple" || (!event.ctrlKey && !event.shiftKey && !event.metaKey))
131 this.clearSelection();
132 ]]></handler>
133 <!-- make sure we keep the focus... -->
onmousedown
134 <handler event="mousedown" button="0"
135 action="if (document.commandDispatcher.focusedElement != this) this.focus();"/>
136 </handlers>
137 </binding>
138
139 <binding id="descriptionitem" extends="chrome://global/content/bindings/listbox.xml#listitem">
140 <content>
141 <xul:hbox class="attachmentBox" xbl:inherits="orient" align="start">
142 <xul:label class="descriptioncell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled,context" flex="1" dir="ltr" crop="center"/>
143 </xul:hbox>
144 </content>
145 </binding>
146
147 <binding id="descriptionitem-iconic" extends="chrome://global/content/bindings/listbox.xml#listitem">
148 <content>
149 <xul:hbox class="attachmentBox" xbl:inherits="orient" align="center">
150 <xul:image class="descriptioncell-icon" xbl:inherits="src=image"/>
151 <xul:label class="descriptioncell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled,context" flex="1" dir="ltr" crop="center"/>
152 </xul:hbox>
153 </content>
154 </binding>
155
156 <!-- Message Pane Widgets -->
157
158 <!-- mail-toggle-headerfield: non email addrss headers which have a toggle associated with them (i.e. the subject).
159 use label to set the header name.
160 use headerValue to set the header value. -->
161 <binding id="mail-toggle-headerfield">
162 <content>
163 <xul:hbox class="headerNameBox" align="start">
164 <xul:image class="expandHeaderViewButton" xbl:inherits="onclick=ontwistyclick"/>
165 <xul:spacer flex="1"/>
166 <xul:label class="headerName" xbl:inherits="value=label" control="headerValue"/>
167 </xul:hbox>
168 <xul:textbox class="headerValue plain" anonid="headerValue" flex="1" readonly="true"/>
169 </content>
170
171 <implementation>
172 <property name="headerValue" onset="return document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue').value = val;"/>
173 </implementation>
174 </binding>
175
176 <!-- mail-headerfield: presents standard text header name & value pairs. Don't use this for email addresses.
177 use label to set the header name.
178 use headerValue to set the header value. -->
179 <binding id="mail-headerfield">
180 <content>
181 <xul:hbox class="headerNameBox" align="start">
182 <xul:label class="headerName" xbl:inherits="value=label" control="headerValue" flex="1"/>
183 </xul:hbox>
184 <xul:textbox class="headerValue plain" anonid="headerValue" flex="1" readonly="true"/>
185 </content>
186
187 <implementation>
188 <property name="headerValue" onset="return document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue').value = val;"/>
189 </implementation>
190 </binding>
191
192 <binding id="mail-urlfield" extends="chrome://messenger/content/mailWidgets.xml#mail-headerfield">
193 <content>
194 <xul:hbox class="headerNameBox" align="start">
195 <xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
196 </xul:hbox>
197 <xul:label onclick="if (!event.button) messenger.launchExternalURL(event.target.value);"
198 class="headerValue plain headerValueUrl"
199 anonid="headerValue" flex="1" readonly="true" context="copyUrlPopup"/>
200 </content>
201 </binding>
202
203 <binding id="mail-emailheaderfield">
204 <content>
205 <xul:hbox class="headerNameBox" align="start">
206 <xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
207 </xul:hbox>
208 <xul:mail-emailaddress anonid="emailAddressNode"/>
209 </content>
210
211 <implementation>
get_emailAddressNode
212 <property name="emailAddressNode" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'emailAddressNode');"
213 readonly="true"/>
214 </implementation>
215 </binding>
216
217 <!-- multi-emailHeaderField: presents multiple emailheaderfields with a toggle -->
218 <binding id="mail-multi-emailHeaderField">
219 <content>
220 <xul:hbox class="headerNameBox" align="start" pack="end">
221 <xul:image class="addresstwisty" anonid="toggleIcon"
222 collapsed="true" onclick="toggleWrap();"/>
223 <xul:label class="headerName" xbl:inherits="value=label"/>
224 </xul:hbox>
225
226 <xul:hbox class="headerValueBox" anonid="longEmailAddresses" flex="1"
227 onoverflow="if (event.detail != 1) this.parentNode.toggleIcon.collapsed = false;"
228 onunderflow="if (event.detail != 1) this.parentNode.toggleIcon.collapsed = true;">
229 <xul:label class="headerValue" anonid="emailAddresses" flex="1"/>
230 </xul:hbox>
231 </content>
232
233 <implementation>
constructor
234 <constructor>
235 <![CDATA[
236 this.mAddresses = new Array;
237 ]]>
238 </constructor>
239
field_mAddresses
240 <field name="mAddresses"/>
241 <!-- as a perf optimization we are going to keep a cache of email address nodes which we've
242 created around for the lifetime of the widget. mSizeOfAddressCache controls how many of these
243 elements we keep around -->
field_mSizeOfAddressCache
244 <field name="mSizeOfAddressCache">3</field>
245
246 <!-- addAddressView: a public method used to add an address to this widget.
247 aAddresses is an object with 3 properties: displayName, emailAddress and fullAddress
248 -->
249 <method name="addAddressView">
250 <parameter name="aAddress"/>
addAddressView
251 <body>
252 <![CDATA[
253 this.mAddresses.push(aAddress);
254 ]]>
255 </body>
256 </method>
257
258 <!-- updateEmailAddressNode: private method used to set properties on an address node -->
259 <method name="updateEmailAddressNode">
260 <parameter name="aEmailNode"/>
261 <parameter name="aAddress"/>
updateEmailAddressNode
262 <body>
263 <![CDATA[
264 if (aEmailNode.parentNode.useShortView && aAddress.displayName)
265 {
266 aEmailNode.setAttribute("label", aAddress.displayName);
267 aEmailNode.setAttribute("tooltiptext", aAddress.fullAddress);
268 }
269 else
270 {
271 aEmailNode.setAttribute("label", aAddress.fullAddress || aAddress.displayName);
272 aEmailNode.removeAttribute("tooltiptext");
273 }
274 aEmailNode.setAttribute("emailAddress", aAddress.emailAddress);
275 aEmailNode.setAttribute("fullAddress", aAddress.fullAddress);
276 aEmailNode.setAttribute("displayName", aAddress.displayName);
277
278 try
279 {
280 if ("AddExtraAddressProcessing" in top)
281 AddExtraAddressProcessing(aAddress.emailAddress, aEmailNode);
282 }
283 catch(ex)
284 {
285 dump("AddExtraAddressProcessing failed: " + ex);
286 }
287 ]]>
288 </body>
289 </method>
290
291 <!-- fillCachedAddresses: private method used to fill up any cached pre-existing
292 emailAddress fields without creating new email address fields. Returns a remainder
293 for the # of addresses which require new addresses being created.
294 Invariants: 1) aNumAddressesToShow >= 0 && it is <= mAddresses.length -->
295 <method name="fillCachedAddresses">
296 <parameter name="aAddressesNode"/>
297 <parameter name="aNumAddressesToShow"/>
fillCachedAddresses
298 <body>
299 <![CDATA[
300 var numExistingCachedAddresses = aAddressesNode.childNodes.length;
301 if (!numExistingCachedAddresses)
302 return this.mAddresses.length; // we couldn't pre fill anything
303 else if (numExistingCachedAddresses > 1)
304 numExistingCachedAddresses = (numExistingCachedAddresses + 1)/ 2;
305
306 var index = 0;
307 var numAddressesAdded = 0;
308 var emailAddressNode;
309 var commaNode;
310 while (numAddressesAdded < numExistingCachedAddresses && numAddressesAdded < aNumAddressesToShow)
311 {
312 if (index && numExistingCachedAddresses > 1)
313 {
314 commaNode = aAddressesNode.childNodes[index++];
315 if (commaNode)
316 commaNode.hidden = false;
317 }
318
319 // get the node pointed to by index
320 emailAddressNode = aAddressesNode.childNodes[index++];
321 this.updateEmailAddressNode(emailAddressNode, this.mAddresses[numAddressesAdded]);
322 emailAddressNode.hidden = false;
323 numAddressesAdded++;
324 }
325
326 // if we have added all of our elements but we still have more cached items in this address node
327 // then make sure the extra cached copies are hidden...
328 numExistingCachedAddresses = aAddressesNode.childNodes.length; // reset
329 while (index < numExistingCachedAddresses)
330 {
331 aAddressesNode.childNodes[index++].hidden = true;
332 }
333
334 return this.mAddresses.length - numAddressesAdded;
335 ]]>
336 </body>
337 </method>
338
339 <!-- fillAddressesNode: private method used to create email address nodes for either our short
340 or long view. aAddressesNode: the div we want to add addresses too.
341 aNumAddressesToShow: number of addresses to put into the list -->
342 <method name="fillAddressesNode">
343 <parameter name="aAddressesNode"/>
344 <parameter name="aNumAddressesToShow"/>
fillAddressesNode
345 <body>
346 <![CDATA[
347 var numAddresses = this.mAddresses.length;
348 if (aNumAddressesToShow <= 0 || aNumAddressesToShow > numAddresses) // then show all
349 aNumAddressesToShow = numAddresses;
350
351 // before we try to create email address nodes, try to leverage any cached nodes...
352 var remainder = this.fillCachedAddresses(aAddressesNode, aNumAddressesToShow);
353 var index = numAddresses - remainder;
354 while (index < numAddresses && index < aNumAddressesToShow)
355 {
356 var newAddressNode = document.createElement("mail-emailaddress");
357 if (index)
358 {
359 var textNode = document.createElement("text");
360 textNode.setAttribute("value", ", ");
361 textNode.setAttribute("class", "emailSeparator");
362 aAddressesNode.appendChild(textNode);
363 }
364
365 var itemInDocument = aAddressesNode.appendChild(newAddressNode);
366 this.updateEmailAddressNode(itemInDocument, this.mAddresses[index]);
367 index++;
368 }
369 ]]>
370 </body>
371 </method>
372
get_emailAddresses
373 <property name="emailAddresses" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'emailAddresses');"
374 readonly="true"/>
get_longEmailAddresses
375 <property name="longEmailAddresses" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'longEmailAddresses');"
376 readonly="true"/>
get_toggleIcon
377 <property name="toggleIcon" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'toggleIcon');"
378 readonly="true"/>
379
380 <!-- buildView: public method used by callers when they are done adding all the email addresses to the widget
381 aNumAddressesToShow: total # of addresses to show in the short view -->
382 <method name="buildViews">
buildViews
383 <body>
384 <![CDATA[
385 this.fillAddressesNode(this.emailAddresses, -1);
386 ]]>
387 </body>
388 </method>
389
390 <method name="toggleWrap">
toggleWrap
391 <body>
392 <![CDATA[
393 if (this.toggleIcon.hasAttribute("open")) {
394 this.toggleIcon.removeAttribute("open");
395 this.longEmailAddresses.setAttribute("singleline", "true");
396 } else {
397 this.toggleIcon.setAttribute("open", "true");
398 this.longEmailAddresses.removeAttribute("singleline");
399 }
400 ]]>
401 </body>
402 </method>
403
404 <!-- internal method used to clear both our divs -->
405 <method name="clearChildNodes">
406 <parameter name="aParentNode"/>
clearChildNodes
407 <body>
408 <![CDATA[
409 // we want to keep around the first mSizeOfAddressCache email address nodes
410 // don't forget that we have comma text nodes in there too so really we want to keep
411 // around cache size * 2 - 1.
412 var numItemsToPreserve = this.mSizeOfAddressCache * 2 - 1;
413 var numItemsInNode = aParentNode.childNodes.length;
414
415 while (numItemsInNode && (numItemsInNode > numItemsToPreserve))
416 {
417 aParentNode.removeChild(aParentNode.childNodes[numItemsInNode-1]);
418 numItemsInNode = numItemsInNode - 1;
419 }
420 ]]>
421 </body>
422 </method>
423
424 <method name="clearHeaderValues">
425 <body>
426 <![CDATA[
427 // clear out our local state
428 this.mAddresses = new Array;
429 if (this.toggleIcon.hasAttribute("open"))
430 // no automatic overflow tracking in this case
431 this.toggleIcon.collapsed = true;
432 this.toggleIcon.removeAttribute("open");
433 this.longEmailAddresses.setAttribute("singleline", "true");
434 // remove anything inside of each of our labels....
435 this.clearChildNodes(this.emailAddresses);
436 ]]>
437 </body>
438 </method>
439 </implementation>
440 </binding>
441
442 <binding id="mail-emailaddress">
443 <content popup="emailAddressPopup" context="emailAddressPopup">
444 <xul:label anonid="emailValue" class="emailDisplayButton plain"
445 xbl:inherits="value=label,crop"/>
446 <xul:image class="emailDisplayImage" anonid="emailImage"
447 xbl:inherits="src=image"/>
448 </content>
449
450 <implementation>
get_label
set_label
451 <property name="label" onset="this.getPart('emailValue').setAttribute('label',val); return val;"
452 onget="return this.getPart('emailValue').getAttribute('label');"/>
get_crop
set_crop
453 <property name="crop" onset="this.getPart('emailValue').setAttribute('crop',val); return val;"
454 onget="return this.getPart('emailValue').getAttribute('crop');"/>
get_disabled
set_disabled
455 <property name="disabled" onset="this.getPart('emailValue').setAttribute('disabled',val); return val;"
456 onget="return this.getPart('emailValue').getAttribute('disabled');"/>
get_src
set_src
457 <property name="src" onset="this.getPart('emailImage').setAttribute('src',val); return val;"
458 onget="return this.getPart('emailImage').getAttribute('src');"/>
get_imgalign
set_imgalign
459 <property name="imgalign" onset="this.getPart('emailImage').setAttribute('imgalign',val); return val;"
460 onget="return this.getPart('emailImage').getAttribute('imgalign');"/>
461
462 <method name="getPart">
463 <parameter name="aPartId"/>
getPart
464 <body><![CDATA[
465 return document.getAnonymousElementByAttribute(this, "anonid", aPartId);
466 ]]></body>
467 </method>
468 </implementation>
469 </binding>
470
471 <binding id="mail-messageids-headerfield">
472 <content>
473 <xul:hbox class="headerNameBox" align="start" pack="end">
474 <xul:image class="addresstwisty" anonid="toggleIcon"
475 onclick="toggleWrap();"/>
476 <xul:label class="headerName" xbl:inherits="value=label"/>
477 </xul:hbox>
478 <xul:hbox class="headerValueBox" flex="1">
479 <xul:label class="headerValue" anonid="headerValue" flex="1"/>
480 </xul:hbox>
481 </content>
482
483 <implementation>
constructor
484 <constructor>
485 <![CDATA[
486 this.mMessageIds = [];
487 this.showFullMessageIds = false;
488 ]]>
489 </constructor>
490
491 <property name="headerValue" readonly="true"
492 onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue');"/>
get_toggleIcon
493 <property name="toggleIcon" readonly="true"
494 onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'toggleIcon');"/>
495
field_mMessageIds
496 <field name="mMessageIds"/>
497
498 <!-- addMessageIdView: a public method used to add a message-id to this widget. -->
499 <method name="addMessageIdView">
500 <parameter name="aMessageId"/>
addMessageIdView
501 <body>
502 <![CDATA[
503 this.mMessageIds.push(aMessageId);
504 ]]>
505 </body>
506 </method>
507
508 <!-- updateMessageIdNode: private method used to set properties on an MessageId node -->
509 <method name="updateMessageIdNode">
510 <parameter name="aMessageIdNode"/>
511 <parameter name="aIndex"/>
512 <parameter name="aMessageId"/>
updateMessageIdNode
513 <body>
514 <![CDATA[
515 var showFullMessageIds = this.showFullMessageIds;
516
517 if (showFullMessageIds)
518 {
519 aMessageIdNode.setAttribute("label", aMessageId);
520 aMessageIdNode.removeAttribute("tooltiptext");
521 }
522 else
523 {
524 aMessageIdNode.setAttribute("label", aIndex);
525 aMessageIdNode.setAttribute("tooltiptext", aMessageId);
526 }
527
528 aMessageIdNode.setAttribute("index", aIndex);
529 aMessageIdNode.setAttribute("messageid", aMessageId);
530 ]]>
531 </body>
532 </method>
533
534 <method name="fillMessageIdNodes">
fillMessageIdNodes
535 <body>
536 <![CDATA[
537 var headerValue = this.headerValue;
538 var messageIdNodes = headerValue.childNodes;
539 var numMessageIds = this.mMessageIds.length;
540 var index = 0;
541
542 while (messageIdNodes.length > numMessageIds * 2 - 1)
543 headerValue.removeChild(headerValue.lastChild);
544
545 for (var index = 0; index < numMessageIds; index++)
546 {
547 if (index * 2 <= messageIdNodes.length - 1)
548 {
549 this.updateMessageIdNode(messageIdNodes[index * 2], index + 1, this.mMessageIds[index]);
550 }
551 else
552 {
553 var newMessageIdNode = document.createElement("mail-messageid");
554
555 if (index)
556 {
557 var textNode = document.createElement("text");
558 textNode.setAttribute("value", ", ");
559 textNode.setAttribute("class", "messageIdSeparator");
560 headerValue.appendChild(textNode);
561 }
562 var itemInDocument = headerValue.appendChild(newMessageIdNode);
563 this.updateMessageIdNode(itemInDocument, index + 1, this.mMessageIds[index]);
564 }
565 }
566 ]]>
567 </body>
568 </method>
569
570 <method name="toggleWrap">
toggleWrap
571 <body>
572 <![CDATA[
573 var headerValue = this.headerValue;
574 var messageIdNodes = headerValue.childNodes;
575 var showFullMessageIds = !this.showFullMessageIds;
576 var messageIds = this.mMessageIds
577
578 for (var i = 0; i < messageIdNodes.length; i += 2)
579 {
580 if (showFullMessageIds)
581 {
582 this.toggleIcon.setAttribute("open", "true");
583 messageIdNodes[i].setAttribute("label", messageIds[i / 2]);
584 messageIdNodes[i].removeAttribute("tooltiptext");
585 headerValue.removeAttribute("singleline");
586 } else
587 {
588 this.toggleIcon.removeAttribute("open");
589 messageIdNodes[i].setAttribute("label", i / 2 + 1);
590 messageIdNodes[i].setAttribute("tooltiptext", messageIds[i / 2]);
591 }
592 }
593
594 this.showFullMessageIds = showFullMessageIds;
595 ]]>
596 </body>
597 </method>
598
599 <method name="clearHeaderValues">
600 <body>
601 <![CDATA[
602 // clear out our local state
603 this.mMessageIds = new Array;
604 if (this.showFullMessageIds)
605 {
606 this.showFullMessageIds = false;
607 this.toggleIcon.removeAttribute("open");
608 }
609 ]]>
610 </body>
611 </method>
612 </implementation>
613 </binding>
614
615 <binding id="mail-messageid">
616 <content context="messageIdContext" onclick="MessageIdClick(this, event);">
617 <xul:label anonid="messageIdValue" class="messageIdDisplayButton plain"
618 xbl:inherits="value=label"/>
619 <xul:image class="messageIdDisplayImage" anonid="messageIdImage"/>
620 </content>
621
622 <implementation>
get_label
set_label
623 <property name="label" onset="this.getPart().setAttribute('label',val); return val;"
624 onget="return this.getPart('messageIdValue').getAttribute('label');"/>
625
626 <method name="getPart">
627 <parameter name="aPartId"/>
getPart
628 <body><![CDATA[
629 return document.getAnonymousElementByAttribute(this, "anonid", 'messageIdValue');
630 ]]></body>
631 </method>
632 </implementation>
633 </binding>
634
635 <!-- Header field for showing the tags associated with a message -->
636 <binding id="mail-headerfield-tags">
637 <content>
638 <xul:hbox class="headerNameBox" align="start">
639 <xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
640 </xul:hbox>
641 <xul:label class="headerValue plain" anonid="headerValue" flex="1"/>
642 </content>
643
644 <implementation>
645 <property name="headerValue" onset="return this.buildTags(val);"/>
646 <method name="buildTags">
647 <parameter name="aTags"/>
buildTags
648 <body>
649 <![CDATA[
650 // aTags contains a list of actual tag names (not the keys), delimited by spaces
651 // each tag name is encoded.
652
653 // remove any existing tag items we've appended to the list
654 var headerValueNode = document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue');
655 for (var i = headerValueNode.childNodes.length - 1; i >= 0; --i)
656 headerValueNode.removeChild(headerValueNode.childNodes[i]);
657
658 var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
659 .getService(Components.interfaces.nsIMsgTagService);
660
661 // tokenize the keywords based on ' '
662 var tagsArray = aTags.split(' ');
663 for (var index = 0; index < tagsArray.length; index++)
664 {
665 // for each tag, create a label, give it the font color that corresponds to the
666 // color of the tag and append it.
667 var tagName;
668 try {
669 // if we got a bad tag name, getTagForKey will throw an exception, skip it
670 // and go to the next one.
671 tagName = tagService.getTagForKey(tagsArray[index]);
672 } catch (ex) { continue; }
673
674 var color = tagService.getColorForKey(tagsArray[index]);
675
676 // now create a label for the tag name, and set the color
677 var label = document.createElement("label");
678 label.setAttribute('value', tagName);
679 label.style.color = color;
680 label.className = "tagvalue";
681 headerValueNode.appendChild(label);
682 }
683 ]]>
684 </body>
685 </method>
686 </implementation>
687 </binding>
688
689 <binding id="search-menulist-abstract" name="searchMenulistAbstract" extends="xul:box">
690 <content>
691 <xul:menulist class="search-menulist" xbl:inherits="flex,disabled" oncommand="this.parentNode.onSelect(event)">
692 <xul:menupopup class="search-menulist-popup"/>
693 </xul:menulist>
694 </content>
695
696 <implementation>
field_internalScope
697 <field name="internalScope">null</field>
field_validityManager
698 <field readonly="true" name="validityManager">
699 <![CDATA[
700 Components.classes['@mozilla.org/mail/search/validityManager;1'].getService(Components.interfaces.nsIMsgSearchValidityManager);
701 ]]>
702 </field>
get_searchScope
703 <property name="searchScope" onget="return this.internalScope;">
704 <!-- scope ID - retrieve the table -->
set_searchScope
705 <setter>
706 <![CDATA[
707 // if scope isn't changing this is a noop
708 if (this.internalScope == val) return val;
709
710 this.internalScope = val;
711 this.refreshList();
712 var targets = this.targets;
713 if (targets) {
714 for (var i=0; i< targets.length; i++) {
715 targets[i].searchScope = val;
716 }
717 }
718 return val;
719 ]]>
720 </setter>
721 </property>
722
get_validityTable
723 <property name="validityTable" readonly="true" onget="return this.validityManager.getTable(this.searchScope)"/>
724
725 <property name="valueStrings" readonly="true">
get_valueStrings
726 <getter>
727 <![CDATA[
728 var strings = new Array;
729 var ids = this.valueIds;
730 var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
731 var hdrsArray = null;
732 try
733 {
734 var hdrs = pref.getCharPref("mailnews.customHeaders");
735 hdrs = hdrs.replace(/\s+/g, ""); //remove white spaces before splitting
736 hdrsArray = hdrs.match(/[^:]+/g);
737 }
738 catch(ex)
739 {
740 }
741 var bundle = this.stringBundle;
742 var j=0;
743 for (var i=0; i<ids.length; i++)
744 {
745 if(ids[i] > Components.interfaces.nsMsgSearchAttrib.OtherHeader && hdrsArray)
746 strings[i] = hdrsArray[j++];
747 else
748 strings[i] = this.stringBundle.GetStringFromID(ids[i]);
749 }
750 return strings;
751 ]]>
752 </getter>
753 </property>
754 <property name="targets" readonly="true">
get_targets
755 <getter>
756 <![CDATA[
757 var forAttrs = this.getAttribute("for");
758 if (!forAttrs) return null;
759 var targetIds = forAttrs.split(",");
760 if (targetIds.length == 0) return null;
761
762 var targets = new Array;
763 var j=0;
764 for (var i=0; i<targetIds.length;i++) {
765 var target = document.getElementById(targetIds[i]);
766 if (target) targets[j++] = target;
767 }
768 return targets;
769 ]]>
770 </getter>
771 </property>
772
773 <property name="optargets" readonly="true">
get_optargets
774 <getter>
775 <![CDATA[
776 var forAttrs = this.getAttribute("opfor");
777 if (!forAttrs) return null;
778 var optargetIds = forAttrs.split(",");
779 if (optargetIds.length == 0) return null;
780
781 var optargets = new Array;
782 var j=0;
783 for (var i=0; i<optargetIds.length;i++) {
784 var optarget = document.getElementById(optargetIds[i]);
785 if (optarget) optargets[j++] = optarget;
786 }
787 return optargets;
788 ]]>
789 </getter>
790 </property>
791
792 <!-- value forwards to the internal menulist's "value" attribute -->
get_value
793 <property name="value" onget="return document.getAnonymousNodes(this)[0].selectedItem.getAttribute('value');">
set_value
794 <setter>
795 <![CDATA[
796 var menulist = document.getAnonymousNodes(this)[0];
797 var dataItems = menulist.getElementsByAttribute("value", val);
798 if (dataItems.item(0))
799 menulist.selectedItem = dataItems[0];
800
801 // now notify targets of new parent's value
802 var targets = this.targets;
803 if (targets) {
804 for (var i=0; i < targets.length; i++) {
805 targets[i].parentValue = val;
806 }
807 }
808
809 // now notify optargets of new op parent's value
810 var optargets = this.optargets;
811 if (optargets) {
812 for (i=0; i < optargets.length; i++) {
813 optargets[i].opParentValue = val;
814 }
815 }
816
817 return val;
818 ]]>
819 </setter>
820 </property>
821 <!-- label forwards to the internal menulist's "label" attribute -->
get_label
822 <property name="label" onget="return document.getAnonymousNodes(this)[0].selectedItem.getAttribute('label');">
823 </property>
824 <method name="refreshList">
refreshList
825 <body>
826 <![CDATA[
827 var menuItemIds = this.valueIds;
828 var menuItemStrings = this.valueStrings;
829
830 var menulist = document.getAnonymousNodes(this)[0];
831 var popup = menulist.firstChild;
832
833 // save our old "value" so we can restore it later
834 var oldData = menulist.value;
835
836 // remove the old popup children
837 while (popup.hasChildNodes())
838 popup.removeChild(popup.lastChild);
839
840 var newSelection;
841 var customizePos=-1;
842 for (var i = 0; i < menuItemIds.length; ++i)
843 {
844 // create the menuitem
845 if (Components.interfaces.nsMsgSearchAttrib.OtherHeader == menuItemIds[i].toString())
846 customizePos = i;
847 else
848 {
849 var menuitem = document.createElement("menuitem");
850 menuitem.setAttribute("label", menuItemStrings[i]);
851 menuitem.setAttribute("value", menuItemIds[i]);
852 popup.appendChild(menuitem);
853 // try to restore the selection
854 if (!newSelection || oldData == menuItemIds[i].toString())
855 newSelection = menuitem;
856 }
857 }
858 if (customizePos != -1)
859 {
860 var separator = document.createElement("menuseparator");
861 popup.appendChild(separator);
862 menuitem = document.createElement("menuitem");
863 menuitem.setAttribute("label", menuItemStrings[customizePos]);
864 menuitem.setAttribute("value", menuItemIds[customizePos]);
865 popup.appendChild(menuitem);
866 }
867 // now restore the selection
868 menulist.selectedItem = newSelection;
869
870 ]]>
871 </body>
872 </method>
873 <method name="onSelect">
874 <parameter name="event"/>
onSelect
875 <body>
876 <![CDATA[
877 var menulist = document.getAnonymousNodes(this)[0];
878 // notify targets
879 var targets = this.targets;
880 if (targets) {
881 for (var i=0; i < targets.length; i++) {
882 targets[i].parentValue = menulist.value;
883 }
884 }
885
886 var optargets = this.optargets;
887 if (optargets) {
888 for (i = 0; i < optargets.length; ++i) {
889 optargets[i].opParentValue = menulist.value;
890 }
891 }
892 ]]>
893 </body>
894 </method>
895 </implementation>
896 </binding>
897
898 <!-- searchattribute - Subject, Sender, To, CC, etc. -->
899 <binding id="searchattribute" name="searchAttribute"
900 extends="chrome://messenger/content/mailWidgets.xml#search-menulist-abstract">
901 <implementation>
field_stringBundle
902 <field name="stringBundle">
903 <![CDATA[
904 Components.classes["@mozilla.org/intl/stringbundle;1"]
905 .getService(Components.interfaces.nsIStringBundleService)
906 .createBundle("chrome://messenger/locale/search-attributes.properties")
907 ]]>
908 </field>
909 <property name="valueIds" readonly="true">
get_valueIds
910 <getter>
911 <![CDATA[
912 var length = new Object;
913 return this.validityTable.getAvailableAttributes(length);
914 ]]>
915 </getter>
916 </property>
constructor
917 <constructor>
918 <![CDATA[
919 initializeTermFromId(this.id);
920 ]]>
921 </constructor>
922 </implementation>
923 </binding>
924
925 <!-- searchoperator - Contains, Is Less than, etc -->
926 <binding id="searchoperator" name="searchOperator"
927 extends="chrome://messenger/content/mailWidgets.xml#search-menulist-abstract">
928 <implementation>
field_searchAttribute
929 <field name="searchAttribute">Components.interfaces.nsMsgSearchAttrib.Default</field>
field_stringBundle
930 <field name="stringBundle">
931 <![CDATA[
932 Components.classes["@mozilla.org/intl/stringbundle;1"]
933 .getService(Components.interfaces.nsIStringBundleService)
934 .createBundle("chrome://messenger/locale/search-operators.properties")
935 ]]>
936 </field>
937 <property name="valueIds" readonly="true">
get_valueIds
938 <getter>
939 <![CDATA[
940 var length = new Object;
941 return this.validityTable.getAvailableOperators(this.searchAttribute,length);
942 ]]>
943 </getter>
944 </property>
945 <property name="parentValue">
set_parentValue
946 <setter>
947 <![CDATA[
948 if (this.searchAttribute == val && val != Components.interfaces.nsMsgSearchAttrib.OtherHeader) return val;
949 this.searchAttribute = val;
950 this.refreshList();
951 if (val == Components.interfaces.nsMsgSearchAttrib.OtherHeader)
952 {
953 window.openDialog('chrome://messenger/content/CustomHeaders.xul', "", 'modal,centerscreen,resizable,titlebar,chrome', null);
954 setTimeout(UpdateAfterCustomHeaderChange, 0); // XXX bug 212625
955 }
956 return val;
957 ]]>
958 </setter>
get_parentValue
959 <getter>
960 <![CDATA[
961 return this.searchAttribute;
962 ]]>
963 </getter>
964 </property>
965 </implementation>
966 </binding>
967
968 <!-- searchvalue - a widget which dynamically changes its user interface
969 depending on what type of data it's supposed to be showing
970 currently handles arbitrary text entry, and menulists for
971 priority, status, junk status, tags, hasAttachment status,
972 and addressbook
973 -->
974 <binding id="searchvalue" name="searchValue">
975 <content>
976 <xul:textbox flex="1" class="search-value-textbox" xbl:inherits="disabled"/>
977 <xul:menulist flex="1" class="search-value-menulist" xbl:inherits="disabled">
978 <xul:menupopup class="search-value-popup">
979 <xul:menuitem value="2" stringTag="priorityLowest" class="search-value-menuitem"/>
980 <xul:menuitem value="3" stringTag="priorityLow" class="search-value-menuitem"/>
981 <xul:menuitem value="4" stringTag="priorityNormal" class="search-value-menuitem"/>
982 <xul:menuitem value="5" stringTag="priorityHigh" class="search-value-menuitem"/>
983 <xul:menuitem value="6" stringTag="priorityHighest" class="search-value-menuitem"/>
984 </xul:menupopup>
985 </xul:menulist>
986 <xul:menulist flex="1" class="search-value-menulist" xbl:inherits="disabled">
987 <xul:menupopup class="search-value-popup">
988 <xul:menuitem value="2" stringTag="replied" class="search-value-menuitem"/>
989 <xul:menuitem value="1" stringTag="read" class="search-value-menuitem"/>
990 <xul:menuitem value="65536" stringTag="new" class="search-value-menuitem"/>
991 <xul:menuitem value="4096" stringTag="forwarded" class="search-value-menuitem"/>
992 <xul:menuitem value="4" stringTag="flagged" class="search-value-menuitem"/>
993 </xul:menupopup>
994 </xul:menulist>
995 <xul:textbox flex="1" class="search-value-textbox" xbl:inherits="disabled"/>
996 <xul:menulist flex="1" class="search-value-menulist" xbl:inherits="disabled">
997 <xul:menupopup class="search-value-popup" ref="moz-abdirectory://"
998 datasources="rdf:addressdirectory"
999 sortActive="true"
1000 sortDirection="ascending"
1001 sortResource="http://home.netscape.com/NC-rdf#DirTreeNameSort">
1002 <xul:template>
1003 <xul:rule nc:IsRemote="true"/>
1004 <xul:rule nc:IsMailList="false">
1005 <xul:menuitem uri="..."
1006 label="rdf:http://home.netscape.com/NC-rdf#DirName"
1007 value="rdf:http://home.netscape.com/NC-rdf#DirUri"/>
1008 </xul:rule>
1009 </xul:template>
1010 </xul:menupopup>
1011 </xul:menulist>
1012 <xul:menulist flex="1" class="search-value-menulist" xbl:inherits="disabled">
1013 <xul:menupopup class="search-value-popup">
1014 </xul:menupopup>
1015 </xul:menulist>
1016 <xul:menulist flex="1" class="search-value-menulist" xbl:inherits="disabled">
1017 <xul:menupopup class="search-value-popup">
1018 <xul:menuitem value="2" stringTag="junk" class="search-value-menuitem"/>
1019 </xul:menupopup>
1020 </xul:menulist>
1021 <xul:menulist flex="1" class="search-value-menulist" xbl:inherits="disabled">
1022 <xul:menupopup class="search-value-popup">
1023 <xul:menuitem value="0" stringTag="hasAttachments" class="search-value-menuitem"/>
1024 </xul:menupopup>
1025 </xul:menulist>
1026 </content>
1027 <implementation>
field_internalOperator
1028 <field name="internalOperator">null</field>
field_internalAttribute
1029 <field name="internalAttribute">null</field>
field_internalValue
1030 <field name="internalValue">null</field>
1031
get_opParentValue
1032 <property name="opParentValue" onget="return this.internalOperator;">
set_opParentValue
1033 <setter>
1034 <![CDATA[
1035 // noop if we're not changing it
1036 if (this.internalOperator == val) return val;
1037
1038 // if it's not sender, we don't care
1039 if (this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.Sender) {
1040 this.internalOperator = val;
1041 return val;
1042 }
1043
1044 var children = document.getAnonymousNodes(this);
1045 if (val == Components.interfaces.nsMsgSearchOp.IsntInAB ||
1046 val == Components.interfaces.nsMsgSearchOp.IsInAB) {
1047 // if the old internalOperator was
1048 // IsntInAB or IsInAB, and the new internalOperator is
1049 // IsntInAB or IsInAB, noop because the search value
1050 // was an ab type, and it still is.
1051 // otherwise, switch to the ab picker and select the PAB
1052 if (this.internalOperator != Components.interfaces.nsMsgSearchOp.IsntInAB &&
1053 this.internalOperator != Components.interfaces.nsMsgSearchOp.IsInAB) {
1054 var abs = children[4].getElementsByAttribute("value", "moz-abmdbdirectory://abook.mab");
1055 if (abs.item(0))
1056 children[4].selectedItem = abs[0];
1057 this.setAttribute("selectedIndex", "4");
1058 }
1059 }
1060 else {
1061 // if the old internalOperator wasn't
1062 // IsntInAB or IsInAB, and the new internalOperator isn't
1063 // IsntInAB or IsInAB, noop because the search value
1064 // wasn't an ab type, and it still isn't.
1065 // otherwise, switch to the textbox and clear it
1066 if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
1067 this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB) {
1068 children[0].value = "";
1069 this.setAttribute("selectedIndex", "0");
1070 }
1071 }
1072
1073 this.internalOperator = val;
1074 return val;
1075 ]]>
1076 </setter>
1077 </property>
1078 <!-- parentValue forwards to the attribute -->
get_parentValue
set_parentValue
1079 <property name="parentValue" onset="return this.searchAttribute=val;"
1080 onget="return this.searchAttribute;"/>
get_searchAttribute
1081 <property name="searchAttribute" onget="return this.internalAttribute;">
set_searchAttribute
1082 <setter>
1083 <![CDATA[
1084 // noop if we're not changing it
1085 if (this.internalAttribute == val) return val;
1086 this.internalAttribute = val;
1087
1088 // if the searchAttribute changing, null out the internalOperator
1089 this.internalOperator = null;
1090
1091 // we inherit from a deck, so just use it's index attribute
1092 // to hide/show widgets
1093 if (val == Components.interfaces.nsMsgSearchAttrib.Priority)
1094 this.setAttribute("selectedIndex", "1");
1095 else if (val == Components.interfaces.nsMsgSearchAttrib.MsgStatus)
1096 this.setAttribute("selectedIndex", "2");
1097 else if (val == Components.interfaces.nsMsgSearchAttrib.Date)
1098 this.setAttribute("selectedIndex", "3");
1099 else if (val == Components.interfaces.nsMsgSearchAttrib.Sender) {
1100 // since the internalOperator is null
1101 // this is the same as the initial state
1102 // the initial state for Sender isn't an ab type search
1103 // it's a text search, so show the textbox
1104 this.setAttribute("selectedIndex", "0");
1105 }
1106 else if (val == Components.interfaces.nsMsgSearchAttrib.Keywords) {
1107 this.setAttribute("selectedIndex", "5");
1108 }
1109 else if (val == Components.interfaces.nsMsgSearchAttrib.JunkStatus) {
1110 this.setAttribute("selectedIndex", "6");
1111 }
1112 else if (val == Components.interfaces.nsMsgSearchAttrib.HasAttachmentStatus) {
1113 this.setAttribute("selectedIndex", "7");
1114 }
1115 else {
1116 // a normal text field
1117 this.setAttribute("selectedIndex", "0");
1118 }
1119 return val;
1120 ]]>
1121 </setter>
1122 </property>
get_value
1123 <property name="value" onget="return this.internalValue;">
set_value
1124 <setter>
1125 <![CDATA[
1126 // val is a nsIMsgSearchValue object
1127 this.internalValue = val;
1128 var attrib = val.attrib;
1129 var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
1130 var children = document.getAnonymousNodes(this);
1131 this.searchAttribute = attrib;
1132 if (attrib == nsMsgSearchAttrib.Priority) {
1133 var matchingPriority =
1134 children[1].getElementsByAttribute("value", val.priority);
1135 if (matchingPriority.item(0))
1136 children[1].selectedItem = matchingPriority[0];
1137 }
1138 else if (attrib == nsMsgSearchAttrib.MsgStatus) {
1139 var matchingStatus =
1140 children[2].getElementsByAttribute("value", val.status);
1141 if (matchingStatus.item(0))
1142 children[2].selectedItem = matchingStatus[0];
1143 }
1144 else if (attrib == nsMsgSearchAttrib.AgeInDays)
1145 children[0].value = val.age;
1146 else if (attrib == nsMsgSearchAttrib.Date)
1147 children[3].value = convertPRTimeToString(val.date);
1148 else if (attrib == nsMsgSearchAttrib.Sender)
1149 {
1150 if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
1151 this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB) {
1152 var abs = children[4].getElementsByAttribute("value", val.str);
1153 if (abs.item(0))
1154 children[4].selectedItem = abs[0];
1155 }
1156 else
1157 children[0].value = val.str;
1158 }
1159 else if (attrib == nsMsgSearchAttrib.Keywords)
1160 {
1161 var keywordVal = children[5].getElementsByAttribute("value", val.str);
1162 if (keywordVal.item(0))
1163 {
1164 children[5].value = val.str;
1165 children[5].selectedItem = keywordVal[0];
1166 }
1167 }
1168 else if (attrib == nsMsgSearchAttrib.JunkStatus) {
1169 var junkStatus =
1170 children[6].getElementsByAttribute("value", val.junkStatus);
1171 if (junkStatus.item(0))
1172 children[6].selectedItem = junkStatus[0];
1173 }
1174 else if (attrib == nsMsgSearchAttrib.HasAttachmentStatus) {
1175 var hasAttachmentStatus =
1176 children[7].getElementsByAttribute("value", val.hasAttachmentStatus);
1177 if (hasAttachmentStatus.item(0))
1178 children[7].selectedItem = hasAttachmentStatus[0];
1179 }
1180 else if (attrib == nsMsgSearchAttrib.Size) {
1181 children[0].value = val.size;
1182 }
1183 else
1184 children[0].value = val.str;
1185 return val;
1186 ]]>
1187 </setter>
1188 </property>
1189 <method name="save">
save
1190 <body>
1191 <![CDATA[
1192 var searchValue = this.value;
1193 var searchAttribute = this.searchAttribute;
1194 var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
1195 var children = document.getAnonymousNodes(this);
1196
1197 searchValue.attrib = searchAttribute;
1198 if (searchAttribute == nsMsgSearchAttrib.Priority) {
1199 searchValue.priority = children[1].selectedItem.value;
1200 }
1201 else if (searchAttribute == nsMsgSearchAttrib.MsgStatus)
1202 searchValue.status = children[2].value;
1203 else if (searchAttribute == nsMsgSearchAttrib.AgeInDays)
1204 searchValue.age = children[0].value;
1205 else if (searchAttribute == nsMsgSearchAttrib.Date)
1206 searchValue.date = convertStringToPRTime(children[3].value);
1207 else if (searchAttribute == nsMsgSearchAttrib.Sender) {
1208 if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
1209 this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB)
1210 searchValue.str = children[4].selectedItem.value;
1211 else
1212 searchValue.str = children[0].value;
1213 }
1214 else if (searchAttribute == nsMsgSearchAttrib.Keywords)
1215 {
1216 searchValue.str = children[5].value;
1217 }
1218 else if (searchAttribute == nsMsgSearchAttrib.JunkStatus)
1219 searchValue.junkStatus = children[6].value;
1220 else if (searchAttribute == nsMsgSearchAttrib.Size)
1221 searchValue.size = children[0].value;
1222 else if (searchAttribute == nsMsgSearchAttrib.HasAttachmentStatus)
1223 searchValue.status = 0x10000000; // 0x10000000 is MSG_FLAG_ATTACHMENT;
1224 else
1225 searchValue.str = children[0].value;
1226 ]]>
1227 </body>
1228 </method>
1229 <method name="saveTo">
1230 <parameter name="searchValue"/>
saveTo
1231 <body>
1232 <![CDATA[
1233 this.internalValue = searchValue;
1234 this.save();
1235 ]]>
1236 </body>
1237 </method>
1238 <method name="fillInTags">
fillInTags
1239 <body>
1240 <![CDATA[
1241 var children = document.getAnonymousNodes(this);
1242 var popupMenu = children[5].firstChild;
1243 var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
1244 .getService(Components.interfaces.nsIMsgTagService);
1245 var tagArray = tagService.getAllTags({});
1246 for (var i = 0; i < tagArray.length; ++i)
1247 {
1248 var taginfo = tagArray[i];
1249 var newMenuItem = document.createElement('menuitem');
1250 newMenuItem.setAttribute('label', taginfo.tag);
1251 newMenuItem.setAttribute('value', taginfo.key);
1252 popupMenu.appendChild(newMenuItem);
1253 if (!i)
1254 children[5].selectedItem = newMenuItem;
1255 }
1256 ]]>
1257 </body>
1258 </method>
1259 <method name="fillStringsForChildren">
1260 <parameter name="parentNode"/>
1261 <parameter name="bundle"/>
fillStringsForChildren
1262 <body>
1263 <![CDATA[
1264 var children = parentNode.childNodes;
1265 var len=children.length;
1266 for (var i=0; i<len; i++) {
1267 var node = children[i];
1268 var stringTag = node.getAttribute("stringTag");
1269 if (stringTag) {
1270 var attr = (node.tagName == "label") ? "value" : "label";
1271 node.setAttribute(attr, bundle.GetStringFromName(stringTag));
1272 }
1273 }
1274 ]]>
1275 </body>
1276 </method>
1277 <method name="initialize">
1278 <parameter name="menulist"/>
1279 <parameter name="bundle"/>
initialize
1280 <body>
1281 <![CDATA[
1282 this.fillStringsForChildren(menulist.firstChild, bundle);
1283 ]]>
1284 </body>
1285 </method>
constructor
1286 <constructor>
1287 <![CDATA[
1288 // initialize strings
1289 var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
1290 .getService(Components.interfaces.nsIStringBundleService)
1291 .createBundle("chrome://messenger/locale/messenger.properties");
1292
1293 // intialize the priority picker
1294 this.initialize(document.getAnonymousNodes(this)[1], bundle);
1295
1296 // initialize the status picker
1297 this.initialize(document.getAnonymousNodes(this)[2], bundle);
1298
1299 // initialize the date picker
1300 var datePicker = document.getAnonymousNodes(this)[3];
1301 var searchAttribute = this.searchAttribute;
1302 var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
1303 var time;
1304 if (searchAttribute == nsMsgSearchAttrib.Date)
1305 time = datePicker.value;
1306 else
1307 time = new Date();
1308 // do .value instead of .setAttribute("value", xxx);
1309 // to work around for bug #179412
1310 // (caused by bug #157210)
1311 //
1312 // the searchvalue widget has two textboxes
1313 // one for text, one as a placeholder for a date / calendar widget
1314 datePicker.value = convertDateToString(time);
1315
1316 // initialize the address book picker
1317 this.initialize(document.getAnonymousNodes(this)[4], bundle);
1318
1319 // initialize the junk status picker
1320 this.initialize(document.getAnonymousNodes(this)[6], bundle);
1321
1322 // initialize the has attachment status picker
1323 this.initialize(document.getAnonymousNodes(this)[7], bundle);
1324
1325 // initialize the tag list
1326 fillInTags();
1327 ]]>
1328 </constructor>
1329 </implementation>
1330 <handlers>
onkeypress
1331 <handler event="keypress" keycode="VK_RETURN" action="onEnterInSearchTerm();"/>
1332 </handlers>
1333 </binding>
1334 <binding id="searchterm" name="searchTerm" extends="xul:box">
1335 <implementation>
field_internalSearchTerm
1336 <field name="internalSearchTerm">null</field>
field_internalBooleanAnd
1337 <field name="internalBooleanAnd">null</field>
1338 <!-- the actual nsIMsgSearchTerm object -->
get_searchTerm
1339 <property name="searchTerm" onget="return this.internalSearchTerm">
set_searchTerm
1340 <setter>
1341 <![CDATA[
1342 this.internalSearchTerm = val;
1343
1344 var term = val;
1345 // val is a nsIMsgSearchTerm
1346 var searchAttribute=this.searchattribute;
1347 var searchOperator=this.searchoperator;
1348 var searchValue=this.searchvalue;
1349
1350 // now reflect all attributes of the searchterm into the widgets
1351 if (searchAttribute) searchAttribute.value = term.attrib;
1352 if (searchOperator) searchOperator.value = val.op;
1353 if (searchValue) searchValue.value = term.value;
1354
1355 this.booleanAnd = val.booleanAnd;
1356 ]]>
1357 </setter>
1358 </property>
1359
1360 <property name="searchScope">
get_searchScope
1361 <getter>
1362 <![CDATA[
1363 var searchAttribute = this.searchattribute;
1364 if (searchAttribute)
1365 return searchAttribute.searchScope;
1366 return undefined;
1367 ]]>
1368 </getter>
set_searchScope
1369 <setter>
1370 <![CDATA[
1371 var searchAttribute = this.searchattribute;
1372 if (searchAttribute) searchAttribute.searchScope=val;
1373 ]]>
1374 </setter>
1375 </property>
1376 <!-- the three tags that make up a term - to use, set the
1377 attribute in the XUL to the ID of the term.
1378 -->
get_searchattribute
set_searchattribute
1379 <property name="searchattribute"
1380 onget="return document.getElementById(this.getAttribute('searchattribute'));"
1381 onset="this.setAttribute('searchattribute',val.id)"/>
1382
get_searchoperator
set_searchoperator
1383 <property name="searchoperator"
1384 onget="return document.getElementById(this.getAttribute('searchoperator'));"
1385 onset="this.setAttribute('searchoperator',val.id)"/>
1386
get_searchvalue
set_searchvalue
1387 <property name="searchvalue"
1388 onget="return document.getElementById(this.getAttribute('searchvalue'));"
1389 onset="this.setAttribute('searchvalue',val.id)"/>
field_booleanNodes
1390 <field name="booleanNodes">
1391 <![CDATA[
1392 null;
1393 ]]>
1394 </field>
field_stringBundle
1395 <field name="stringBundle">
1396 <![CDATA[
1397 Components.classes["@mozilla.org/intl/stringbundle;1"]
1398 .getService(Components.interfaces.nsIStringBundleService)
1399 .createBundle("chrome://messenger/locale/search.properties")
1400 ]]>
1401 </field>
get_booleanAnd
1402 <property name="booleanAnd" onget="return this.internalBooleanAnd">
set_booleanAnd
1403 <setter>
1404 <![CDATA[
1405 // whenever you set this, all nodes in booleanNodes
1406 // are updated to reflect the string
1407
1408 if (this.internalBooleanAnd == val) return;
1409 this.internalBooleanAnd = val;
1410
1411 var booleanNodes = this.booleanNodes;
1412 if (!booleanNodes) return;
1413
1414 var stringBundle = this.stringBundle;
1415 var andString = val ? "And" : "Or";
1416 for (var i=0; i<booleanNodes.length; i++) {
1417 try {
1418 var staticString =
1419 stringBundle.GetStringFromName("search" + andString + i);
1420 if (staticString && staticString.length>0)
1421 booleanNodes[i].setAttribute("value", staticString);
1422 } catch (ex) { /* no error, means string not found */}
1423 }
1424 ]]>
1425 </setter>
1426 </property>
1427 <method name="save">
save
1428 <body>
1429 <![CDATA[
1430 var searchTerm = this.searchTerm;
1431 searchTerm.attrib = this.searchattribute.value;
1432 if (this.searchAttribute > nsMsgSearchAttrib.OtherHeader && this.searchAttribute < nsMsgSearchAttrib.kNumMsgSearchAttributes)
1433 searchTerm.arbitraryHeader = this.searchattribute.label;
1434 searchTerm.op = this.searchoperator.value;
1435 if (this.searchvalue.value)
1436 this.searchvalue.save();
1437 else
1438 this.searchvalue.saveTo(searchTerm.value);
1439 searchTerm.value = this.searchvalue.value;
1440 searchTerm.booleanAnd = this.booleanAnd;
1441 ]]>
1442 </body>
1443 </method>
1444 <!-- if you have a search term element with no search term -->
1445 <method name="saveTo">
1446 <parameter name="searchTerm"/>
saveTo
1447 <body>
1448 <![CDATA[
1449 this.internalSearchTerm = searchTerm;
1450 this.save();
1451 ]]>
1452 </body>
1453 </method>
1454 </implementation>
1455 </binding>
1456
1457 <!-- Folder picker helper widgets -->
1458 <binding id="popup-base" extends="chrome://global/content/bindings/popup.xml#popup">
1459 <implementation>
field_tree
1460 <field name="tree" readonly="true">
1461 document.getAnonymousNodes(this)[0];
1462 </field>
1463 <method name="updateHover">
1464 <parameter name="event"/>
updateHover
1465 <body>
1466 <![CDATA[
1467 var box = this.tree.treeBoxObject;
1468 if (event.originalTarget == box.treeBody) {
1469 var index = box.getRowAt(event.clientX, event.clientY);
1470 box.view.selection.select(index);
1471 return index;
1472 }
1473 return -1;
1474 ]]>
1475 </body>
1476 </method>
1477 <method name="fire">
fire
1478 <body>
1479 <![CDATA[
1480 this.hidePopup();
1481 if (this.tree.currentIndex >= 0) {
1482 this.setAttribute("uri", this.tree.builderView.getResourceAtIndex(this.tree.currentIndex).Value);
1483 this.doCommand();
1484 }
1485 ]]>
1486 </body>
1487 </method>
1488 <method name="onBlurMenuList">
1489 <parameter name="event"/>
1490 <body>
1491 <![CDATA[
1492 this.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject).openMenu(false);
1493 ]]>
1494 </body>
1495 </method>
1496 <field name="onKeyPressMenuList" readonly="true">
1497 <![CDATA[
1498 ({
1499 self: this,
1500 tree: this.tree,
1501 parentNode: this.parentNode,
getLastVisibleRow
1502 getLastVisibleRow: function getLastVisibleRow(box) {
1503 var f = box.getFirstVisibleRow();
1504 var p = box.getPageLength();
1505 var l = box.view.rowCount;
1506 return (l < f + p ? l : f + p) - 1;
1507 },
handleEvent
1508 handleEvent: function handleEvent(event) {
1509 if (event.altKey)
1510 return;
1511 var index;
1512 var box = this.tree.treeBoxObject;
1513 if (this.parentNode.hasAttribute("open")) {
1514 event.stopPropagation();
1515 event.preventDefault();
1516 switch (event.keyCode) {
1517 case event.DOM_VK_ESCAPE:
1518 this.self.hidePopup();
1519 return;
1520 case event.DOM_VK_ENTER:
1521 case event.DOM_VK_RETURN:
1522 this.self.fire();
1523 return;
1524 }
1525 index = this.tree.currentIndex;
1526 } else {
1527 switch (event.keyCode) {
1528 case event.DOM_VK_PAGE_UP:
1529 case event.DOM_VK_PAGE_DOWN:
1530 return;
1531 }
1532 index = this.self.setInitialSelection();
1533 }
1534 switch (event.keyCode) {
1535 case event.DOM_VK_UP:
1536 if (index <= 0)
1537 return;
1538 index--;
1539 break;
1540 case event.DOM_VK_DOWN:
1541 index++;
1542 if (index == box.view.rowCount)
1543 return;
1544 break;
1545 case event.DOM_VK_PAGE_UP:
1546 if (index == box.getFirstVisibleRow())
1547 box.scrollByPages(-1);
1548 index = box.getFirstVisibleRow();
1549 break;
1550 case event.DOM_VK_PAGE_DOWN:
1551 if (index == this.getLastVisibleRow(box))
1552 box.scrollByPages(1);
1553 index = this.getLastVisibleRow(box);
1554 break;
1555 case event.DOM_VK_HOME:
1556 index = 0;
1557 break;
1558 case event.DOM_VK_END:
1559 index = box.view.rowCount - 1;
1560 break;
1561 default:
1562 if (event.charCode > 0 && !event.ctrlKey && !event.metaKey) {
1563 event.preventDefault();
1564 index = tree.keyNavigate(event);
1565 if (index >= 0)
1566 break;
1567 }
1568 return;
1569 }
1570 box.view.selection.select(index);
1571 if (this.parentNode.hasAttribute("open"))
1572 box.ensureRowIsVisible(index);
1573 else
1574 this.self.fire();
1575 }
1576 })
1577 ]]>
1578 </field>
1579 <method name="setInitialSelection">
setInitialSelection
1580 <body>
1581 <![CDATA[
1582 var view = this.tree.view;
1583
1584 if (!view.selection.currentColumn)
1585 view.selection.currentColumn = this.tree.columns.getFirstColumn();
1586
1587 view.selection.selectEventsSuppressed = true;
1588 for (var i = 0; i < view.rowCount; i++) {
1589 if (view.isContainer(i)) {
1590 if (view.isContainerEmpty(i) == view.isContainerOpen(i))
1591 view.toggleOpenState(i);
1592 if (view.isContainerOpen(i)) {
1593 if (i + 1 == view.rowCount ||
1594 view.getLevel(i + 1) <= view.getLevel(i)) {
1595 view.toggleOpenState(i);
1596 }
1597 }
1598 }
1599 }
1600 var index = -1;
1601 var uri = this.parentNode.getAttribute("uri");
1602 if (uri) {
1603 var RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
1604 index = view.getIndexOfResource(RDF.GetResource(uri));
1605 }
1606 view.selection.select(index);
1607 return index;
1608 ]]>
1609 </body>
1610 </method>
constructor
1611 <constructor>
1612 <![CDATA[
1613 this.setAttribute("ignorekeys", "true");
1614 this.parentNode.addEventListener("keypress", this.onKeyPressMenuList, true);
1615 ]]>
1616 </constructor>
destructor
1617 <destructor>
1618 <![CDATA[
1619 this.parentNode.removeEventListener("keypress", this.onKeyPressMenuList, true);
1620 ]]>
1621 </destructor>
1622 </implementation>
1623 <handlers>
onmousemove
1624 <handler event="mousemove" action="this.updateHover(event);"/>
onclick
1625 <handler event="click" button="0" action="if (this.updateHover(event) >= 0) this.fire();"/>
1626 <handler event="popupshowing">
1627 <![CDATA[
1628 this.parentNode.addEventListener("blur", this.onBlurMenuList, false);
1629 var box = this.tree.treeBoxObject;
1630 box.focused = true;
1631 var index = this.setInitialSelection();
1632 var height = box.view.rowCount * box.rowHeight;
1633 height += this.boxObject.height - box.treeBody.boxObject.height;
1634 this.height = height;
1635 if (index >= 0)
anon:1636:23
1636 setTimeout(function() { box.ensureRowIsVisible(index); }, 0);
1637 ]]>
1638 </handler>
1639 <handler event="popuphiding">
1640 <![CDATA[
1641 this.parentNode.removeEventListener("blur", this.onBlurMenuList, false);
1642 ]]>
1643 </handler>
1644 </handlers>
1645 </binding>
1646
1647 <binding id="folderTargetPopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
1648 <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
1649 <tree class="foldersTree" flex="1" datasources="rdf:msgaccountmanager rdf:mailnewsfolders" ref="msgaccounts:/" flags="dont-build-content" seltype="text" hidecolumnpicker="true">
1650 <treecols>
1651 <treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
1652 </treecols>
1653 <treechildren class="foldersTreeChildren"/>
1654 <template>
1655 <rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="true" nc:CanSearchMessages="true">
1656 <treechildren>
1657 <treeitem uri="rdf:*">
1658 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
1659 <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
1660 properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder isServer-rdf:http://home.netscape.com/NC-rdf#IsServer isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
1661 </treerow>
1662 </treeitem>
1663 </treechildren>
1664 </rule>
1665 <rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="false" nc:CanSearchMessages="true" nc:Virtual="false">
1666 <treechildren>
1667 <treeitem uri="rdf:*">
1668 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
1669 <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
1670 properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder isServer-rdf:http://home.netscape.com/NC-rdf#IsServer isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
1671 </treerow>
1672 </treeitem>
1673 </treechildren>
1674 </rule>
1675 <rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="true" nc:Virtual="false">
1676 <treechildren>
1677 <treeitem uri="rdf:*">
1678 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
1679 <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
1680 properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder isServer-rdf:http://home.netscape.com/NC-rdf#IsServer isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
1681 </treerow>
1682 </treeitem>
1683 </treechildren>
1684 </rule>
1685 </template>
1686 </tree>
1687 </xbl:content>
1688 </binding>
1689
1690 <binding id="locationpopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
1691 <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
1692 <tree class="foldersTree" flex="1" datasources="rdf:null" flags="dont-build-content" seltype="text" hidecolumnpicker="true">
1693 <treecols>
1694 <treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
1695 </treecols>
1696 <treechildren class="foldersTreeChildren"/>
1697 <template>
1698 <rule nc:IsDeferred="false">
1699 <treechildren>
1700 <treeitem uri="rdf:*">
1701 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
1702 <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeName"
1703 properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder biffState-rdf:http://home.netscape.com/NC-rdf#BiffState isServer-rdf:http://home.netscape.com/NC-rdf#IsServer newMessages-rdf:http://home.netscape.com/NC-rdf#NewMessages hasUnreadMessages-rdf:http://home.netscape.com/NC-rdf#HasUnreadMessages isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
1704 </treerow>
1705 </treeitem>
1706 </treechildren>
1707 </rule>
1708 </template>
1709 </tree>
1710 </xbl:content>
1711 </binding>
1712
1713 <binding id="searchpopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
1714 <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
1715 <tree class="foldersTree" flex="1" datasources="rdf:msgaccountmanager rdf:mailnewsfolders" ref="msgaccounts:/" flags="dont-build-content" seltype="text" hidecolumnpicker="true">
1716 <treecols>
1717 <treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
1718 </treecols>
1719 <treechildren class="foldersTreeChildren"/>
1720 <template>
1721 <rule nc:CanSearchMessages="true" nc:Virtual="false">
1722 <treechildren>
1723 <treeitem uri="rdf:*">
1724 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
1725 <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
1726 properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder isServer-rdf:http://home.netscape.com/NC-rdf#IsServer isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
1727 </treerow>
1728 </treeitem>
1729 </treechildren>
1730 </rule>
1731 </template>
1732 </tree>
1733 </xbl:content>
1734 </binding>
1735
1736 <binding id="folderSummary-popup" extends="chrome://global/content/bindings/popup.xml#tooltip">
1737 <content>
1738 <children>
1739 <xul:folderSummary/>
1740 </children>
1741 </content>
1742 <handlers>
1743 <handler event="popupshowing">
1744 <![CDATA[
1745 var folderTree = GetFolderTree();
1746 var row = folderTree.treeBoxObject.getRowAt(event.clientX, event.clientY);
1747 if (row == -1)
1748 return false;
1749
1750 var msgFolder = GetFolderResource(folderTree, row).QueryInterface(Components.interfaces.nsIMsgFolder);
1751 if (!msgFolder || msgFolder.isServer)
1752 return false;
1753 var asyncResults = {};
1754 return document.getAnonymousNodes(this)[0].parseFolder(msgFolder, null, asyncResults);
1755 ]]>
1756 </handler>
1757
1758 <handler event="popuphiding">
1759 document.getAnonymousNodes(this)[0].clear();
1760 </handler>
1761 </handlers>
1762 </binding>
1763
1764 <binding id="folderSummary">
1765 <content>
1766 <xul:vbox/>
1767 </content>
1768
1769 <implementation>
1770 <field name="mMaxMsgHdrsInPopup">8</field>
get_hasMessages
1771 <property name="hasMessages" readonly="true" onget="return document.getAnonymousNodes(this)[0].hasChildNodes();"/>
1772 <method name="parseFolder">
1773 <parameter name="aFolder"/>
1774 <parameter name="aUrlListener"/>
1775 <parameter name="aOutAsync"/>
parseFolder
1776 <body>
1777 <![CDATA[
1778 // from nsMsgFolderFlags.h
1779 const kMsgPopupFolderFlagTrash = 0x0100;
1780 const kMsgPopupFolderFlagJunk = 0x40000000;
1781 // skip servers, Trash and Junk folders
1782 if (!aFolder || aFolder.isServer || aFolder.getFlag(kMsgPopupFolderFlagJunk) || aFolder.getFlag(kMsgPopupFolderFlagTrash))
1783 return false;
1784 var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
1785 var showPreviewText = pref.getBoolPref("mail.biff.alert.show_preview");
1786 var folderArray = new Array;
1787 if (aFolder.flags & MSG_FOLDER_FLAG_VIRTUAL)
1788 {
1789 var msgDatabase = aFolder.getMsgDatabase(null);
1790 var dbFolderInfo = msgDatabase.dBFolderInfo;
1791 var srchFolderUri = dbFolderInfo.getCharProperty("searchFolderUri");
1792 var srchFolderUriArray = srchFolderUri.split('|');
1793 var foldersAdded = 0;
1794 var RDF = Components.classes['@mozilla.org/rdf/rdf-service;1'].getService().QueryInterface(Components.interfaces.nsIRDFService);
1795 for (var i in srchFolderUriArray)
1796 {
1797 var realFolder = RDF.GetResource(srchFolderUriArray[i]).QueryInterface(Components.interfaces.nsIMsgFolder);
1798 if (!realFolder.isServer)
1799 folderArray[foldersAdded++] = realFolder;
1800 }
1801 }
1802 else
1803 folderArray[0] = aFolder;
1804 var foundNewMsg = false;
1805 for (var folderIndex = 0; folderIndex < folderArray.length; folderIndex++)
1806 {
1807 aFolder = folderArray[folderIndex];
1808 // now get the database
1809 var msgDatabase = aFolder.getMsgDatabase(null);
1810 aFolder.setMsgDatabase(null);
1811 var msgKeys = {};
1812 var numMsgKeys = {};
1813 msgDatabase.getNewList(numMsgKeys, msgKeys);
1814
1815 if (!numMsgKeys.value)
1816 continue;
1817
1818 if (showPreviewText)
1819 {
1820 // fetchMsgPreviewText forces the previewText property to get generated
1821 // for each of the message keys.
1822 try {
1823 aOutAsync.value = aFolder.fetchMsgPreviewText(msgKeys.value, numMsgKeys.value, false, aUrlListener);
1824 aFolder.setMsgDatabase(null);
1825 }
1826 catch (ex)
1827 {
1828 // fetchMsgPreviewText throws an error when we call it on a news folder, we should just not show
1829 // the tooltip if this method returns an error.
1830 aFolder.setMsgDatabase(null);
1831 continue;
1832 }
1833 }
1834 // if fetching the preview text is going to be an asynch operation and the caller
1835 // is set up to handle that fact, then don't bother filling in any of the fields since
1836 // we'll have to do this all over again when the fetch for the preview text completes.
1837 // We don't expect to get called with a urlListener if we're doing a virtual folder.
1838 if (aOutAsync.value && aUrlListener)
1839 return false;
1840 var unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
1841 .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
1842 unicodeConverter.charset = "UTF-8";
1843 foundNewMsg = true;
1844
1845 var index = 0;
1846 var hdrParser = Components.classes["@mozilla.org/messenger/headerparser;1"].getService(Components.interfaces.nsIMsgHeaderParser);
1847 while (document.getAnonymousNodes(this)[0].childNodes.length < this.mMaxMsgHdrsInPopup && index < numMsgKeys.value)
1848 {
1849 var msgPopup = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "folderSummaryMessage");
1850 var msgHdr = msgDatabase.GetMsgHdrForKey(msgKeys.value[index++]);
1851
1852 var msgSubject = msgHdr.mime2DecodedSubject;
1853 const kMsgFlagHasRe = 0x0010; // MSG_FLAG_HAS_RE
1854 if(msgHdr.flags & kMsgFlagHasRe)
1855 msgSubject = (msgSubject) ? "Re: " + msgSubject : "Re: ";
1856
1857 msgPopup.setAttribute('subject', msgSubject);
1858
1859 var previewText = msgHdr.getStringProperty('preview');
1860 // convert the preview text from utf-8 to unicode
1861 if (previewText)
1862 {
1863 try
1864 {
1865 var text = unicodeConverter.ConvertToUnicode(previewText);
1866 if (text)
1867 msgPopup.setAttribute('previewText', text);
1868 }
1869 catch (ex) { }
1870 }
1871
1872 var names = {};
1873 var emails = {};
1874 var numAddresses = hdrParser.parseHeadersWithArray(msgHdr.mime2DecodedAuthor, emails, names, {});
1875 msgPopup.setAttribute('sender', names.value[0] ? names.value[0] : emails.value[0]);
1876 msgPopup.messageUri = aFolder.getUriForMsg(msgHdr);
1877 msgPopup.folderUri = aFolder.URI;
1878 msgPopup.msgKey = msgHdr.messageKey;
1879 document.getAnonymousNodes(this)[0].appendChild(msgPopup);
1880 }
1881 if (document.getAnonymousNodes(this)[0].childNodes.length >= this.mMaxMsgHdrsInPopup)
1882 return true;
1883 }
1884 return foundNewMsg;
1885 ]]>
1886 </body>
1887 </method>
1888
1889 <method name="clear">
clear
1890 <body>
1891 <![CDATA[
1892 var containingBox = document.getAnonymousNodes(this)[0];
1893 while (containingBox.hasChildNodes())
1894 containingBox.removeChild(containingBox.lastChild);
1895 ]]>
1896 </body>
1897 </method>
1898 </implementation>
1899 </binding>
1900
1901 <binding id="folderSummary-message">
1902 <content>
1903 <xul:vbox class="folderSummaryMessage">
1904 <xul:hbox class="folderSummary-message-row">
1905 <xul:label anonid="subject" flex="1" class="folderSummary-subject" xbl:inherits="value=subject" crop="right"/>
1906 <xul:label anonid="sender" class="folderSummary-sender" xbl:inherits="value=sender" crop="right"/>
1907 <xul:spring anonid="spring" flex="100%"/>
1908 </xul:hbox>
1909 <xul:description anonid="preview" class="folderSummary-message-row folderSummary-previewText" xbl:inherits="value=previewText" crop="right"></xul:description>
1910 </xul:vbox>
1911 </content>
1912 <implementation>
constructor
1913 <constructor>
1914 <![CDATA[
1915 var pref = Components.classes["@mozilla.org/preferences-service;1"]
1916 .getService(Components.interfaces.nsIPrefBranch);
1917 if (!pref.getBoolPref("mail.biff.alert.show_preview"))
1918 document.getAnonymousElementByAttribute(this, "anonid", "preview").hidden = true;
1919 var hideSubject = !pref.getBoolPref("mail.biff.alert.show_subject");
1920 var hideSender = !pref.getBoolPref("mail.biff.alert.show_sender");
1921 if (hideSubject)
1922 document.getAnonymousElementByAttribute(this, "anonid", "subject").hidden = true;
1923 if (hideSender)
1924 document.getAnonymousElementByAttribute(this, "anonid", "sender").hidden = true;
1925 if (hideSubject && hideSender)
1926 document.getAnonymousElementByAttribute(this, "anonid", "spring").hidden = true;
1927 ]]>
1928 </constructor>
1929 </implementation>
1930 <handlers>
onclick
1931 <handler event="click" button="0">
1932 <![CDATA[
1933 var mailSession = Components.classes["@mozilla.org/messenger/services/session;1"].
1934 getService(Components.interfaces.nsIMsgMailSession);
1935 var topmostMsgWindow;
1936 try {
1937 topmostMsgWindow = mailSession.topmostMsgWindow;
1938 } catch (ex) {}
1939
1940 if (topmostMsgWindow)
1941 {
1942 try {
1943 // SelectFolder throws an exception if the folder is not in the current folder view
1944 mailSession.topmostMsgWindow.windowCommands.selectFolder(this.folderUri);
1945 mailSession.topmostMsgWindow.windowCommands.selectMessage(this.messageUri);
1946 } catch (ex) {}
1947 }
1948 else
1949 {
1950 // open a new window
1951 var mailWindowService = Components.classes["@mozilla.org/messenger/windowservice;1"].
1952 getService(Components.interfaces.nsIMessengerWindowService);
1953 mailWindowService.openMessengerWindowWithUri("mail:3pane", this.folderUri, this.msgKey);
1954 }
1955
1956 if (gAlertListener)
1957 gAlertListener.observe(null, "alertclickcallback", "");
1958 ]]>
1959 </handler>
1960 </handlers>
1961 </binding>
1962 </bindings>