mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 19:50:12 +01:00
2217 lines
86 KiB
XML
2217 lines
86 KiB
XML
|
<?xml version="1.0"?>
|
||
|
|
||
|
<bindings id="mailBindings"
|
||
|
xmlns="http://www.mozilla.org/xbl"
|
||
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||
|
xmlns:nc="http://home.netscape.com/NC-rdf#"
|
||
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
||
|
|
||
|
<!-- dummy widget to force this file to load -->
|
||
|
<binding id="dummy" extends="xul:box"/>
|
||
|
|
||
|
<!-- temporary holding place for horizontal list -->
|
||
|
|
||
|
<binding id="extdescription" extends="chrome://global/content/bindings/text.xml#text-base">
|
||
|
<implementation implements="nsIDOMXULMultiSelectControlElement, nsIDOMXULSelectControlElement">
|
||
|
<field name="_isUpSelection">0</field>
|
||
|
<field name="_isDownSelection">0</field>
|
||
|
<field name="_suppressOnSelect">false</field>
|
||
|
<field name="_selectionStart">null</field>
|
||
|
<field name="_currentItem">null</field>
|
||
|
<field name="_selectTimeout">null</field>
|
||
|
<field name="_lastKeyTime">0</field>
|
||
|
<field name="_incrementalString">""</field>
|
||
|
|
||
|
<constructor>
|
||
|
<![CDATA[
|
||
|
var els = this.getElementsByAttribute("selected", "true");
|
||
|
this.selectedItems = [];
|
||
|
for (var i = 0; i < els.length; ++i)
|
||
|
this.selectedItems.push(els[i]);
|
||
|
]]>
|
||
|
</constructor>
|
||
|
|
||
|
<!-- ///////////////// public members ///////////////// -->
|
||
|
<property name="_selectDelay"
|
||
|
onset="this.setAttribute('_selectDelay', val);"
|
||
|
onget="return this.getAttribute('_selectDelay') || 50;"/>
|
||
|
|
||
|
<method name="timedSelect">
|
||
|
<parameter name="item"/>
|
||
|
<parameter name="timeout"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var suppress = this._suppressOnSelect;
|
||
|
if (timeout != -1)
|
||
|
this._suppressOnSelect = true;
|
||
|
|
||
|
this.selectItem(item);
|
||
|
|
||
|
this._suppressOnSelect = suppress;
|
||
|
|
||
|
if (timeout != -1) {
|
||
|
if (this._selectTimeout)
|
||
|
window.clearTimeout(this._selectTimeout);
|
||
|
|
||
|
this._selectTimeout = window.setTimeout(this._selectTimeoutHandler, timeout, this);
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="appendItem">
|
||
|
<parameter name="label"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||
|
var item = document.createElementNS(XULNS, "descriptionitem");
|
||
|
item.setAttribute("label", label);
|
||
|
this.appendChild(item);
|
||
|
return item;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<!-- ///////////////// private members ///////////////// -->
|
||
|
|
||
|
<method name="_fireOnSelect">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (!this._suppressOnSelect && this.getAttribute("suppressonselect") != "true") {
|
||
|
var event = document.createEvent("Events");
|
||
|
event.initEvent("select", false, true);
|
||
|
this.dispatchEvent(event);
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="_selectTimeoutHandler">
|
||
|
<parameter name="me"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
me._fireOnSelect();
|
||
|
me._selectTimeout = null;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<!-- ///////////////// nsIDOMXULSelectControlElement ///////////////// -->
|
||
|
|
||
|
<property name="selType"
|
||
|
onget="return this.getAttribute('seltype')"
|
||
|
onset="this.setAttribute('seltype', val); return val;"/>
|
||
|
|
||
|
<property name="selectedIndex">
|
||
|
<getter><![CDATA[
|
||
|
return this.selectedItems.length > 0 ? this.getIndexOfItem(this.selectedItems[0]) : -1;
|
||
|
]]></getter>
|
||
|
<setter><![CDATA[
|
||
|
if (val >= 0)
|
||
|
this.selectItem(this.getItemAtIndex(val));
|
||
|
else
|
||
|
this.clearSelection();
|
||
|
]]></setter>
|
||
|
</property>
|
||
|
|
||
|
<property name="selectedItem">
|
||
|
<getter><![CDATA[
|
||
|
return this.selectedItems.length > 0 ? this.selectedItems[0] : null;
|
||
|
]]></getter>
|
||
|
<setter><![CDATA[
|
||
|
this.selectItem(val);
|
||
|
]]></setter>
|
||
|
</property>
|
||
|
|
||
|
<!-- ///////////////// nsIDOMXULSelectMultipleControlElement ///////////////// -->
|
||
|
|
||
|
<property name="currentItem" onget="return this._currentItem;">
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
if (this._currentItem)
|
||
|
this._currentItem.removeAttribute("current");
|
||
|
this._currentItem = val;
|
||
|
if (val)
|
||
|
val.setAttribute("current", "true");
|
||
|
return val;
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
|
||
|
<property name="selectedCount" onget="return this.selectedItems.length;"/>
|
||
|
|
||
|
<method name="getSelectedItem">
|
||
|
<parameter name="index"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
return index < this.selectedItems.length ? this.selectedItems[index] : null;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="addItemToSelection">
|
||
|
<parameter name="item"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (this.selType != "multiple" && this.selectedCount)
|
||
|
return;
|
||
|
if (item.hasAttribute("selected"))
|
||
|
return;
|
||
|
this.selectedItems.push(item);
|
||
|
item.setAttribute("selected", "true");
|
||
|
this._fireOnSelect();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="removeItemFromSelection">
|
||
|
<parameter name="item"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (!item.hasAttribute("selected"))
|
||
|
return;
|
||
|
|
||
|
for (var i = 0; i < this.selectedItems.length; ++i) {
|
||
|
if (this.selectedItems[i] == item) {
|
||
|
this.selectedItems.splice(i, 1);
|
||
|
item.removeAttribute("selected");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._fireOnSelect();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="toggleItemSelection">
|
||
|
<parameter name="item"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (item.hasAttribute("selected"))
|
||
|
this.removeItemFromSelection(item);
|
||
|
else
|
||
|
this.addItemToSelection(item);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="selectItem">
|
||
|
<parameter name="item"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (!item)
|
||
|
return;
|
||
|
|
||
|
if (this.selectedItems.length == 1 && this.selectedItems[0] == item)
|
||
|
return;
|
||
|
|
||
|
this._selectionStart = null;
|
||
|
|
||
|
var suppress = this._suppressOnSelect;
|
||
|
this._suppressOnSelect = true;
|
||
|
|
||
|
this.clearSelection();
|
||
|
this.addItemToSelection(item);
|
||
|
this.currentItem = item;
|
||
|
|
||
|
this._suppressOnSelect = suppress;
|
||
|
this._fireOnSelect();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="selectItemRange">
|
||
|
<parameter name="startItem"/>
|
||
|
<parameter name="endItem"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (this.selType != "multiple")
|
||
|
return;
|
||
|
|
||
|
if (!startItem)
|
||
|
startItem = this._selectionStart ? this._selectionStart : this.currentItem;
|
||
|
if (!startItem)
|
||
|
startItem = endItem;
|
||
|
|
||
|
var suppressSelect = this._suppressOnSelect;
|
||
|
this._suppressOnSelect = true;
|
||
|
this.clearSelection();
|
||
|
|
||
|
this._selectionStart = startItem;
|
||
|
|
||
|
var currentItem;
|
||
|
var startIndex = this.getIndexOfItem(startItem);
|
||
|
var endIndex = this.getIndexOfItem(endItem);
|
||
|
if (endIndex < startIndex) {
|
||
|
currentItem = endItem;
|
||
|
endItem = startItem;
|
||
|
startItem = currentItem;
|
||
|
} else {
|
||
|
currentItem = startItem;
|
||
|
}
|
||
|
|
||
|
while (currentItem) {
|
||
|
if (currentItem.localName == "descriptionitem")
|
||
|
this.addItemToSelection(currentItem);
|
||
|
if (currentItem == endItem)
|
||
|
break;
|
||
|
currentItem = this.getNextItem(currentItem, 1);
|
||
|
}
|
||
|
|
||
|
this._suppressOnSelect = suppressSelect;
|
||
|
|
||
|
this._fireOnSelect();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="selectAll">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var suppress = this._suppressOnSelect;
|
||
|
this._suppressOnSelect = true;
|
||
|
|
||
|
var item = this.getItemAtIndex(0);
|
||
|
while (item) {
|
||
|
this.addItemToSelection(item);
|
||
|
item = this.getNextItem(item, 1);
|
||
|
}
|
||
|
|
||
|
this._suppressOnSelect = suppress;
|
||
|
this._fireOnSelect();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="invertSelection">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var suppress = this._suppressOnSelect;
|
||
|
this._suppressOnSelect = true;
|
||
|
|
||
|
var item = this.getItemAtIndex(0);
|
||
|
while (item) {
|
||
|
if (item.hasAttribute("selected"))
|
||
|
this.removeItemFromSelection(item);
|
||
|
else
|
||
|
this.addItemToSelection(item);
|
||
|
item = this.getNextItem(item, 1);
|
||
|
}
|
||
|
|
||
|
this._suppressOnSelect = suppress;
|
||
|
this._fireOnSelect();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="clearSelection">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (this.selectedItems)
|
||
|
{
|
||
|
for (var i = this.selectedItems.length-1; i >= 0; --i)
|
||
|
this.selectedItems[i].removeAttribute("selected");
|
||
|
|
||
|
this.selectedItems.splice(0, this.selectedItems.length);
|
||
|
}
|
||
|
this._selectionStart = null;
|
||
|
this._fireOnSelect();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="getNextItem">
|
||
|
<parameter name="startItem"/>
|
||
|
<parameter name="delta"/>
|
||
|
<body><![CDATA[
|
||
|
while (startItem) {
|
||
|
startItem = startItem.nextSibling;
|
||
|
if (startItem && startItem.localName == "descriptionitem") {
|
||
|
--delta;
|
||
|
if (delta == 0)
|
||
|
return startItem;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
]]></body>
|
||
|
</method>
|
||
|
|
||
|
<method name="getPreviousItem">
|
||
|
<parameter name="startItem"/>
|
||
|
<parameter name="delta"/>
|
||
|
<body><![CDATA[
|
||
|
while (startItem) {
|
||
|
startItem = startItem.previousSibling;
|
||
|
if (startItem && startItem.localName == "descriptionitem") {
|
||
|
--delta;
|
||
|
if (delta == 0)
|
||
|
return startItem;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
]]></body>
|
||
|
</method>
|
||
|
|
||
|
<!-- selection navigation -->
|
||
|
<method name="navigateToPreviousItem">
|
||
|
<parameter name="event"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (event.target != this)
|
||
|
return;
|
||
|
this._isUpSelection=0;
|
||
|
this._isDownSelection=0;
|
||
|
var n = this.getPreviousItem(this.selectedItems[this.selectedItems.length-1], 1);
|
||
|
if (n)
|
||
|
this.timedSelect(n, this._selectDelay);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="navigateToNextItem">
|
||
|
<parameter name="event"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (event.target != this)
|
||
|
return;
|
||
|
var n;
|
||
|
if (this.selectedItems.length == 0) {
|
||
|
n = this.getItemAtIndex(0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this._isUpSelection=0;
|
||
|
this._isDownSelection=0;
|
||
|
n = this.getNextItem(this.selectedItems[this.selectedItems.length-1], 1);
|
||
|
}
|
||
|
|
||
|
if (n)
|
||
|
this.timedSelect(n, this._selectDelay);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="navigateAndSelectNextItem">
|
||
|
<parameter name="event"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var l=this.selectedItems.length;
|
||
|
if (event.target != this || l < 1 || this.selType != "multiple")
|
||
|
return;
|
||
|
var n = this.getNextItem(this.selectedItems[l-1], 1);
|
||
|
if (n)
|
||
|
{
|
||
|
if ( this._isUpSelection)
|
||
|
{
|
||
|
if ( l > 1 )
|
||
|
this.removeItemFromSelection(this.selectedItems[l-1]);
|
||
|
if ( l <= 2 )
|
||
|
this._isUpSelection=0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.addItemToSelection(n);
|
||
|
this._isDownSelection=1;
|
||
|
}
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<method name="navigateAndSelectPreviousItem">
|
||
|
<parameter name="event"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var l = this.selectedItems.length;
|
||
|
if (event.target != this || l < 1 || this.selType != "multiple")
|
||
|
return;
|
||
|
var n = this.getPreviousItem(this.selectedItems[l-1], 1);
|
||
|
if (n)
|
||
|
{
|
||
|
if ( this._isDownSelection)
|
||
|
{
|
||
|
if ( l > 1 )
|
||
|
this.removeItemFromSelection(this.selectedItems[l-1]);
|
||
|
if ( l <= 2 )
|
||
|
this._isDownSelection=0;
|
||
|
} else
|
||
|
{
|
||
|
this.addItemToSelection(n);
|
||
|
this._isUpSelection=1;
|
||
|
}
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
</implementation>
|
||
|
|
||
|
<handlers>
|
||
|
|
||
|
<handler event="keypress" modifiers="shift" keycode="vk_down">
|
||
|
<![CDATA[
|
||
|
this.navigateAndSelectNextItem(event);
|
||
|
]]>
|
||
|
</handler>
|
||
|
|
||
|
<handler event="keypress" modifiers="shift" keycode="vk_right">
|
||
|
<![CDATA[
|
||
|
this.navigateAndSelectNextItem(event);
|
||
|
]]>
|
||
|
</handler>
|
||
|
<handler event="keypress" modifiers="shift" keycode="vk_up">
|
||
|
<![CDATA[
|
||
|
this.navigateAndSelectPreviousItem(event);
|
||
|
]]>
|
||
|
</handler>
|
||
|
|
||
|
<handler event="keypress" modifiers="shift" keycode="vk_left">
|
||
|
<![CDATA[
|
||
|
this.navigateAndSelectPreviousItem(event);
|
||
|
]]>
|
||
|
</handler>
|
||
|
|
||
|
<handler event="keypress" keycode="vk_up">
|
||
|
<![CDATA[
|
||
|
this.navigateToPreviousItem(event);
|
||
|
]]>
|
||
|
</handler>
|
||
|
<handler event="keypress" keycode="vk_left">
|
||
|
<![CDATA[
|
||
|
if (event.target != this)
|
||
|
return;
|
||
|
this.navigateToPreviousItem(event);
|
||
|
]]>
|
||
|
</handler>
|
||
|
<handler event="keypress" keycode="vk_down">
|
||
|
<![CDATA[
|
||
|
this.navigateToNextItem(event);
|
||
|
]]>
|
||
|
</handler>
|
||
|
<handler event="keypress" keycode="vk_right">
|
||
|
<![CDATA[
|
||
|
this.navigateToNextItem(event);
|
||
|
]]>
|
||
|
</handler>
|
||
|
<handler event="mousedown">
|
||
|
<![CDATA[
|
||
|
var targetItem = event.target;
|
||
|
if (targetItem.localName == "descriptionitem" && !event.ctrlKey && !event.shiftKey && !event.metaKey)
|
||
|
{
|
||
|
if (!targetItem.hasAttribute('selected'))
|
||
|
this.selectItem(targetItem);
|
||
|
this.currentItem = targetItem;
|
||
|
}
|
||
|
if (document.commandDispatcher.focusedElement != this)
|
||
|
this.focus(); // make sure the description has focus...
|
||
|
]]>
|
||
|
</handler>
|
||
|
<handler event="click">
|
||
|
<![CDATA[
|
||
|
if (event.button != 0) return;
|
||
|
|
||
|
var targetItem = event.target;
|
||
|
if (targetItem.localName == "descriptionitem")
|
||
|
{
|
||
|
if (this.selType != "multiple")
|
||
|
this.selectItem(targetItem);
|
||
|
else if (event.ctrlKey || event.metaKey) {
|
||
|
this.toggleItemSelection(targetItem);
|
||
|
this.currentItem = targetItem;
|
||
|
}
|
||
|
else if (event.shiftKey) {
|
||
|
this.selectItemRange(null, targetItem);
|
||
|
this.currentItem = targetItem;
|
||
|
}
|
||
|
else {
|
||
|
/* We want to deselect all the selected items except what was
|
||
|
clicked, UNLESS it was a right-click. We have to do this
|
||
|
in click rather than mousedown so that you can drag a
|
||
|
selected group of items */
|
||
|
|
||
|
var selectedItems = this.selectedItems;
|
||
|
var didSuppressSelect = false;
|
||
|
var i = 0;
|
||
|
while (i < selectedItems.length)
|
||
|
{
|
||
|
if (selectedItems[i] != targetItem)
|
||
|
{
|
||
|
if (!didSuppressSelect)
|
||
|
{
|
||
|
this._suppressOnSelect = true;
|
||
|
didSuppressSelect = true;
|
||
|
}
|
||
|
this.removeItemFromSelection(selectedItems[i]);
|
||
|
}
|
||
|
else
|
||
|
i++;
|
||
|
}
|
||
|
if (didSuppressSelect)
|
||
|
this._suppressOnSelect = false;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (this.selType != "multiple" || (!event.ctrlKey && !event.shiftKey && !event.metaKey))
|
||
|
this.clearSelection();
|
||
|
}
|
||
|
]]>
|
||
|
</handler>
|
||
|
</handlers>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="descriptionitem">
|
||
|
<content>
|
||
|
<xul:hbox class="attachmentBox" xbl:inherits="orient" align="start">
|
||
|
<xul:label class="descriptioncell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled,context" flex="1" dir="ltr" crop="center"/>
|
||
|
</xul:hbox>
|
||
|
</content>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="descriptionitem-iconic">
|
||
|
<content>
|
||
|
<xul:hbox class="attachmentBox" xbl:inherits="orient" align="center">
|
||
|
<xul:image class="descriptioncell-icon" xbl:inherits="src=image"/>
|
||
|
<xul:label class="descriptioncell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled,context" flex="1" dir="ltr" crop="center"/>
|
||
|
</xul:hbox>
|
||
|
</content>
|
||
|
</binding>
|
||
|
|
||
|
<!-- Message Pane Widgets -->
|
||
|
|
||
|
<!-- mail-toggle-headerfield: non email addrss headers which have a toggle associated with them (i.e. the subject).
|
||
|
use label to set the header name.
|
||
|
use headerValue to set the header value. -->
|
||
|
<binding id="mail-toggle-headerfield">
|
||
|
<content>
|
||
|
<xul:hbox class="headerNameBox" align="start">
|
||
|
<xul:image class="expandHeaderViewButton" xbl:inherits="onclick=ontwistyclick"/>
|
||
|
<xul:spacer flex="1"/>
|
||
|
<xul:label class="headerName" xbl:inherits="value=label"/>
|
||
|
</xul:hbox>
|
||
|
<xul:textbox class="headerValue plain" anonid="headerValue" flex="1" readonly="true"/>
|
||
|
</content>
|
||
|
|
||
|
<implementation>
|
||
|
<property name="headerValue" onset="return document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue').value = val;"/>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<!-- mail-headerfield: presents standard text header name & value pairs. Don't use this for email addresses.
|
||
|
use label to set the header name.
|
||
|
use headerValue to set the header value. -->
|
||
|
<binding id="mail-headerfield">
|
||
|
<content>
|
||
|
<xul:hbox class="headerNameBox" align="start">
|
||
|
<xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
|
||
|
</xul:hbox>
|
||
|
<xul:textbox class="headerValue plain" anonid="headerValue" flex="1" readonly="true"/>
|
||
|
</content>
|
||
|
|
||
|
<implementation>
|
||
|
<property name="headerValue" onset="return document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue').value = val;"/>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="mail-urlfield" extends="chrome://messenger/content/mailWidgets.xml#mail-headerfield">
|
||
|
<content>
|
||
|
<xul:hbox class="headerNameBox" align="start">
|
||
|
<xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
|
||
|
</xul:hbox>
|
||
|
<xul:label onclick="if (!event.button) messenger.launchExternalURL(event.target.value);"
|
||
|
class="headerValue plain headerValueUrl"
|
||
|
anonid="headerValue" flex="1" readonly="true" context="copyUrlPopup"/>
|
||
|
</content>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="mail-emailheaderfield">
|
||
|
<content>
|
||
|
<xul:hbox class="headerNameBox" align="start">
|
||
|
<xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
|
||
|
</xul:hbox>
|
||
|
<xul:mail-emailaddress anonid="emailAddressNode"/>
|
||
|
</content>
|
||
|
|
||
|
<implementation>
|
||
|
<property name="emailAddressNode" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'emailAddressNode');"
|
||
|
readonly="true"/>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<!-- multi-emailHeaderField: presents multiple emailheaderfields with a toggle -->
|
||
|
<binding id="mail-multi-emailHeaderField">
|
||
|
<content>
|
||
|
<xul:hbox class="headerNameBox" align="start" pack="end">
|
||
|
<xul:image class="addresstwisty" anonid="toggleIcon"
|
||
|
collapsed="true" onclick="toggleWrap();"/>
|
||
|
<xul:label class="headerName" xbl:inherits="value=label"/>
|
||
|
</xul:hbox>
|
||
|
|
||
|
<xul:hbox class="headerValueBox" anonid="longEmailAddresses" flex="1"
|
||
|
onoverflow="this.parentNode.toggleIcon.collapsed = false;"
|
||
|
onunderflow="this.parentNode.toggleIcon.collapsed = true;">
|
||
|
<xul:label class="headerValue" anonid="emailAddresses" flex="1"/>
|
||
|
</xul:hbox>
|
||
|
</content>
|
||
|
|
||
|
<implementation>
|
||
|
<constructor>
|
||
|
<![CDATA[
|
||
|
this.mAddresses = new Array;
|
||
|
]]>
|
||
|
</constructor>
|
||
|
|
||
|
<field name="mAddresses"/>
|
||
|
<!-- as a perf optimization we are going to keep a cache of email address nodes which we've
|
||
|
created around for the lifetime of the widget. mSizeOfAddressCache controls how many of these
|
||
|
elements we keep around -->
|
||
|
<field name="mSizeOfAddressCache">3</field>
|
||
|
|
||
|
<!-- addAddressView: a public method used to add an address to this widget.
|
||
|
aAddresses is an object with 3 properties: displayName, emailAddress and fullAddress
|
||
|
-->
|
||
|
<method name="addAddressView">
|
||
|
<parameter name="aAddress"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
this.mAddresses.push(aAddress);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<!-- updateEmailAddressNode: private method used to set properties on an address node -->
|
||
|
<method name="updateEmailAddressNode">
|
||
|
<parameter name="aEmailNode"/>
|
||
|
<parameter name="aAddress"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (aEmailNode.parentNode.useShortView && aAddress.displayName)
|
||
|
{
|
||
|
aEmailNode.setAttribute("label", aAddress.displayName);
|
||
|
aEmailNode.setAttribute("tooltiptext", aAddress.fullAddress);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
aEmailNode.setAttribute("label", aAddress.fullAddress || aAddress.displayName);
|
||
|
aEmailNode.removeAttribute("tooltiptext");
|
||
|
}
|
||
|
aEmailNode.setAttribute("emailAddress", aAddress.emailAddress);
|
||
|
aEmailNode.setAttribute("fullAddress", aAddress.fullAddress);
|
||
|
aEmailNode.setAttribute("displayName", aAddress.displayName);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
if ("AddExtraAddressProcessing" in top)
|
||
|
AddExtraAddressProcessing(aAddress.emailAddress, aEmailNode);
|
||
|
}
|
||
|
catch(ex)
|
||
|
{
|
||
|
dump("AddExtraAddressProcessing failed: " + ex);
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<!-- fillCachedAddresses: private method used to fill up any cached pre-existing
|
||
|
emailAddress fields without creating new email address fields. Returns a remainder
|
||
|
for the # of addresses which require new addresses being created.
|
||
|
Invariants: 1) aNumAddressesToShow >= 0 && it is <= mAddresses.length -->
|
||
|
<method name="fillCachedAddresses">
|
||
|
<parameter name="aAddressesNode"/>
|
||
|
<parameter name="aNumAddressesToShow"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var numExistingCachedAddresses = aAddressesNode.childNodes.length;
|
||
|
if (!numExistingCachedAddresses)
|
||
|
return this.mAddresses.length; // we couldn't pre fill anything
|
||
|
else if (numExistingCachedAddresses > 1)
|
||
|
numExistingCachedAddresses = (numExistingCachedAddresses + 1)/ 2;
|
||
|
|
||
|
var index = 0;
|
||
|
var numAddressesAdded = 0;
|
||
|
var emailAddressNode;
|
||
|
var commaNode;
|
||
|
while (numAddressesAdded < numExistingCachedAddresses && numAddressesAdded < aNumAddressesToShow)
|
||
|
{
|
||
|
if (index && numExistingCachedAddresses > 1)
|
||
|
{
|
||
|
commaNode = aAddressesNode.childNodes[index++];
|
||
|
if (commaNode)
|
||
|
commaNode.hidden = false;
|
||
|
}
|
||
|
|
||
|
// get the node pointed to by index
|
||
|
emailAddressNode = aAddressesNode.childNodes[index++];
|
||
|
this.updateEmailAddressNode(emailAddressNode, this.mAddresses[numAddressesAdded]);
|
||
|
emailAddressNode.hidden = false;
|
||
|
numAddressesAdded++;
|
||
|
}
|
||
|
|
||
|
// if we have added all of our elements but we still have more cached items in this address node
|
||
|
// then make sure the extra cached copies are hidden...
|
||
|
numExistingCachedAddresses = aAddressesNode.childNodes.length; // reset
|
||
|
while (index < numExistingCachedAddresses)
|
||
|
{
|
||
|
aAddressesNode.childNodes[index++].hidden = true;
|
||
|
}
|
||
|
|
||
|
return this.mAddresses.length - numAddressesAdded;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<!-- fillAddressesNode: private method used to create email address nodes for either our short
|
||
|
or long view. aAddressesNode: the div we want to add addresses too.
|
||
|
aNumAddressesToShow: number of addresses to put into the list -->
|
||
|
<method name="fillAddressesNode">
|
||
|
<parameter name="aAddressesNode"/>
|
||
|
<parameter name="aNumAddressesToShow"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var numAddresses = this.mAddresses.length;
|
||
|
if (aNumAddressesToShow <= 0 || aNumAddressesToShow > numAddresses) // then show all
|
||
|
aNumAddressesToShow = numAddresses;
|
||
|
|
||
|
// before we try to create email address nodes, try to leverage any cached nodes...
|
||
|
var remainder = this.fillCachedAddresses(aAddressesNode, aNumAddressesToShow);
|
||
|
var index = numAddresses - remainder;
|
||
|
while (index < numAddresses && index < aNumAddressesToShow)
|
||
|
{
|
||
|
var newAddressNode = document.createElement("mail-emailaddress");
|
||
|
if (index)
|
||
|
{
|
||
|
var textNode = document.createElement("text");
|
||
|
textNode.setAttribute("value", ", ");
|
||
|
textNode.setAttribute("class", "emailSeparator");
|
||
|
aAddressesNode.appendChild(textNode);
|
||
|
}
|
||
|
|
||
|
var itemInDocument = aAddressesNode.appendChild(newAddressNode);
|
||
|
this.updateEmailAddressNode(itemInDocument, this.mAddresses[index]);
|
||
|
index++;
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<property name="emailAddresses" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'emailAddresses');"
|
||
|
readonly="true"/>
|
||
|
<property name="longEmailAddresses" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'longEmailAddresses');"
|
||
|
readonly="true"/>
|
||
|
<property name="toggleIcon" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'toggleIcon');"
|
||
|
readonly="true"/>
|
||
|
|
||
|
<!-- buildView: public method used by callers when they are done adding all the email addresses to the widget
|
||
|
aNumAddressesToShow: total # of addresses to show in the short view -->
|
||
|
<method name="buildViews">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
this.fillAddressesNode(this.emailAddresses, -1);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="toggleWrap">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
if (this.toggleIcon.hasAttribute("open")) {
|
||
|
this.toggleIcon.removeAttribute("open");
|
||
|
this.longEmailAddresses.setAttribute("singleline", "true");
|
||
|
} else {
|
||
|
this.toggleIcon.setAttribute("open", "true");
|
||
|
this.longEmailAddresses.removeAttribute("singleline");
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<!-- internal method used to clear both our divs -->
|
||
|
<method name="clearChildNodes">
|
||
|
<parameter name="aParentNode"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
// we want to keep around the first mSizeOfAddressCache email address nodes
|
||
|
// don't forget that we have comma text nodes in there too so really we want to keep
|
||
|
// around cache size * 2 - 1.
|
||
|
var numItemsToPreserve = this.mSizeOfAddressCache * 2 - 1;
|
||
|
var numItemsInNode = aParentNode.childNodes.length;
|
||
|
|
||
|
while (numItemsInNode && (numItemsInNode > numItemsToPreserve))
|
||
|
{
|
||
|
aParentNode.removeChild(aParentNode.childNodes[numItemsInNode-1]);
|
||
|
numItemsInNode = numItemsInNode - 1;
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="clearEmailAddresses">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
// clear out our local state
|
||
|
this.mAddresses = new Array;
|
||
|
this.toggleIcon.removeAttribute("open");
|
||
|
this.toggleIcon.collapsed = true;
|
||
|
this.longEmailAddresses.setAttribute("singleline", "true");
|
||
|
// remove anything inside of each of our labels....
|
||
|
this.clearChildNodes(this.emailAddresses);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="mail-emailaddress">
|
||
|
<content popup="emailAddressPopup" context="emailAddressPopup">
|
||
|
<xul:label anonid="emailValue" class="emailDisplayButton plain"
|
||
|
xbl:inherits="value=label,crop"/>
|
||
|
<xul:image class="emailDisplayImage" anonid="emailImage"
|
||
|
xbl:inherits="src=image"/>
|
||
|
</content>
|
||
|
|
||
|
<implementation>
|
||
|
<property name="label" onset="this.getPart('emailValue').setAttribute('label',val); return val;"
|
||
|
onget="return this.getPart('emailValue').getAttribute('label');"/>
|
||
|
<property name="crop" onset="this.getPart('emailValue').setAttribute('crop',val); return val;"
|
||
|
onget="return this.getPart('emailValue').getAttribute('crop');"/>
|
||
|
<property name="disabled" onset="this.getPart('emailValue').setAttribute('disabled',val); return val;"
|
||
|
onget="return this.getPart('emailValue').getAttribute('disabled');"/>
|
||
|
<property name="src" onset="this.getPart('emailImage').setAttribute('src',val); return val;"
|
||
|
onget="return this.getPart('emailImage').getAttribute('src');"/>
|
||
|
<property name="imgalign" onset="this.getPart('emailImage').setAttribute('imgalign',val); return val;"
|
||
|
onget="return this.getPart('emailImage').getAttribute('imgalign');"/>
|
||
|
|
||
|
<method name="getPart">
|
||
|
<parameter name="aPartId"/>
|
||
|
<body><![CDATA[
|
||
|
return document.getAnonymousElementByAttribute(this, "anonid", aPartId);
|
||
|
]]></body>
|
||
|
</method>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<!-- Header field for showing the tags associated with a message -->
|
||
|
<binding id="mail-headerfield-tags">
|
||
|
<content>
|
||
|
<xul:hbox class="headerNameBox" align="start">
|
||
|
<xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
|
||
|
</xul:hbox>
|
||
|
<xul:label class="headerValue plain" anonid="headerValue" flex="1"/>
|
||
|
</content>
|
||
|
|
||
|
<implementation>
|
||
|
<property name="headerValue" onset="return this.buildTags(val);"/>
|
||
|
<method name="buildTags">
|
||
|
<parameter name="aTags"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
// aTags contains a list of actual tag names (not the keys), delimited by spaces
|
||
|
// each tag name is encoded.
|
||
|
|
||
|
// remove any existing tag items we've appended to the list
|
||
|
var headerValueNode = document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue');
|
||
|
for (var i = headerValueNode.childNodes.length - 1; i >= 0; --i)
|
||
|
headerValueNode.removeChild(headerValueNode.childNodes[i]);
|
||
|
|
||
|
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
|
||
|
.getService(Components.interfaces.nsIMsgTagService);
|
||
|
|
||
|
// tokenize the keywords based on ' '
|
||
|
var tagsArray = aTags.split(' ');
|
||
|
for (var index = 0; index < tagsArray.length; index++)
|
||
|
{
|
||
|
// for each tag, create a label, give it the font color that corresponds to the
|
||
|
// color of the tag and append it.
|
||
|
var tagName;
|
||
|
try {
|
||
|
// if we got a bad tag name, getTagForKey will throw an exception, skip it
|
||
|
// and go to the next one.
|
||
|
tagName = tagService.getTagForKey(tagsArray[index]);
|
||
|
} catch (ex) { continue; }
|
||
|
|
||
|
var color = tagService.getColorForKey(tagsArray[index]);
|
||
|
|
||
|
// now create a label for the tag name, and set the color
|
||
|
var label = document.createElement("label");
|
||
|
label.setAttribute('value', tagName);
|
||
|
label.style.color = color;
|
||
|
label.className = "tagvalue";
|
||
|
headerValueNode.appendChild(label);
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="search-menulist-abstract" name="searchMenulistAbstract" extends="xul:box">
|
||
|
<content>
|
||
|
<xul:menulist class="search-menulist" xbl:inherits="flex" oncommand="this.parentNode.onSelect(event)">
|
||
|
<xul:menupopup class="search-menulist-popup"/>
|
||
|
</xul:menulist>
|
||
|
</content>
|
||
|
|
||
|
<implementation>
|
||
|
<field name="internalScope">null</field>
|
||
|
<field readonly="true" name="validityManager">
|
||
|
<![CDATA[
|
||
|
Components.classes['@mozilla.org/mail/search/validityManager;1'].getService(Components.interfaces.nsIMsgSearchValidityManager);
|
||
|
]]>
|
||
|
</field>
|
||
|
<property name="searchScope" onget="return this.internalScope;">
|
||
|
<!-- scope ID - retrieve the table -->
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
// if scope isn't changing this is a noop
|
||
|
if (this.internalScope == val) return val;
|
||
|
|
||
|
this.internalScope = val;
|
||
|
this.refreshList();
|
||
|
var targets = this.targets;
|
||
|
if (targets) {
|
||
|
for (var i=0; i< targets.length; i++) {
|
||
|
targets[i].searchScope = val;
|
||
|
}
|
||
|
}
|
||
|
return val;
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
|
||
|
<property name="validityTable" readonly="true" onget="return this.validityManager.getTable(this.searchScope)"/>
|
||
|
|
||
|
<property name="valueStrings" readonly="true">
|
||
|
<getter>
|
||
|
<![CDATA[
|
||
|
var strings = new Array;
|
||
|
var ids = this.valueIds;
|
||
|
var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||
|
var hdrsArray = null;
|
||
|
try
|
||
|
{
|
||
|
var hdrs = pref.getCharPref("mailnews.customHeaders");
|
||
|
hdrs = hdrs.replace(/\s+/g,''); //remove white spaces before splitting
|
||
|
hdrsArray = hdrs.match(/[^:]+/g);
|
||
|
}
|
||
|
catch(ex)
|
||
|
{
|
||
|
}
|
||
|
var bundle = this.stringBundle;
|
||
|
var j=0;
|
||
|
for (var i=0; i<ids.length; i++)
|
||
|
{
|
||
|
if(ids[i] > Components.interfaces.nsMsgSearchAttrib.OtherHeader && hdrsArray)
|
||
|
strings[i] = hdrsArray[j++];
|
||
|
else
|
||
|
strings[i] = this.stringBundle.GetStringFromID(ids[i]);
|
||
|
}
|
||
|
return strings;
|
||
|
]]>
|
||
|
</getter>
|
||
|
</property>
|
||
|
<property name="targets" readonly="true">
|
||
|
<getter>
|
||
|
<![CDATA[
|
||
|
var forAttrs = this.getAttribute("for");
|
||
|
if (!forAttrs) return null;
|
||
|
var targetIds = forAttrs.split(",");
|
||
|
if (targetIds.length == 0) return null;
|
||
|
|
||
|
var targets = new Array;
|
||
|
var j=0;
|
||
|
for (var i=0; i<targetIds.length;i++) {
|
||
|
var target = document.getElementById(targetIds[i]);
|
||
|
if (target) targets[j++] = target;
|
||
|
}
|
||
|
return targets;
|
||
|
]]>
|
||
|
</getter>
|
||
|
</property>
|
||
|
|
||
|
<property name="optargets" readonly="true">
|
||
|
<getter>
|
||
|
<![CDATA[
|
||
|
var forAttrs = this.getAttribute("opfor");
|
||
|
if (!forAttrs) return null;
|
||
|
var optargetIds = forAttrs.split(",");
|
||
|
if (optargetIds.length == 0) return null;
|
||
|
|
||
|
var optargets = new Array;
|
||
|
var j=0;
|
||
|
for (var i=0; i<optargetIds.length;i++) {
|
||
|
var optarget = document.getElementById(optargetIds[i]);
|
||
|
if (optarget) optargets[j++] = optarget;
|
||
|
}
|
||
|
return optargets;
|
||
|
]]>
|
||
|
</getter>
|
||
|
</property>
|
||
|
|
||
|
<!-- value forwards to the internal menulist's "value" attribute -->
|
||
|
<property name="value" onget="return document.getAnonymousNodes(this)[0].selectedItem.getAttribute('value');">
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
var menulist = document.getAnonymousNodes(this)[0];
|
||
|
var dataItems = menulist.getElementsByAttribute("value", val);
|
||
|
if (dataItems.item(0))
|
||
|
menulist.selectedItem = dataItems[0];
|
||
|
|
||
|
// now notify targets of new parent's value
|
||
|
var targets = this.targets;
|
||
|
if (targets) {
|
||
|
for (var i=0; i < targets.length; i++) {
|
||
|
targets[i].parentValue = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// now notify optargets of new op parent's value
|
||
|
var optargets = this.optargets;
|
||
|
if (optargets) {
|
||
|
for (i=0; i < optargets.length; i++) {
|
||
|
optargets[i].opParentValue = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return val;
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
<!-- label forwards to the internal menulist's "label" attribute -->
|
||
|
<property name="label" onget="return document.getAnonymousNodes(this)[0].selectedItem.getAttribute('label');">
|
||
|
</property>
|
||
|
<method name="refreshList">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var menuItemIds = this.valueIds;
|
||
|
var menuItemStrings = this.valueStrings;
|
||
|
|
||
|
var menulist = document.getAnonymousNodes(this)[0];
|
||
|
var popup = menulist.firstChild;
|
||
|
|
||
|
// save our old "value" so we can restore it later
|
||
|
var oldData = menulist.value;
|
||
|
|
||
|
// remove the old popup children
|
||
|
while (popup.hasChildNodes())
|
||
|
popup.removeChild(popup.lastChild);
|
||
|
|
||
|
var newSelection;
|
||
|
var customizePos=-1;
|
||
|
for (var i=0; i<menuItemIds.length; i++)
|
||
|
{
|
||
|
// create the menuitem
|
||
|
if (Components.interfaces.nsMsgSearchAttrib.OtherHeader == menuItemIds[i].toString())
|
||
|
customizePos = i;
|
||
|
else
|
||
|
{
|
||
|
var menuitem = document.createElement("menuitem");
|
||
|
menuitem.setAttribute("label", menuItemStrings[i]);
|
||
|
menuitem.setAttribute("value", menuItemIds[i]);
|
||
|
popup.appendChild(menuitem);
|
||
|
// try to restore the selection
|
||
|
if (!newSelection || oldData == menuItemIds[i].toString())
|
||
|
newSelection = menuitem;
|
||
|
}
|
||
|
}
|
||
|
if (customizePos != -1)
|
||
|
{
|
||
|
var separator = document.createElement("menuseparator");
|
||
|
popup.appendChild(separator);
|
||
|
menuitem = document.createElement("menuitem");
|
||
|
menuitem.setAttribute("label", menuItemStrings[customizePos]);
|
||
|
menuitem.setAttribute("value", menuItemIds[customizePos]);
|
||
|
popup.appendChild(menuitem);
|
||
|
}
|
||
|
// now restore the selection
|
||
|
menulist.selectedItem = newSelection;
|
||
|
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<method name="onSelect">
|
||
|
<parameter name="event"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var menulist = document.getAnonymousNodes(this)[0];
|
||
|
// notify targets
|
||
|
var targets = this.targets;
|
||
|
if (targets) {
|
||
|
for (var i=0; i < targets.length; i++) {
|
||
|
targets[i].parentValue = menulist.value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var optargets = this.optargets;
|
||
|
if (optargets) {
|
||
|
for (i=0; i < optargets.length; i++) {
|
||
|
optargets[i].opParentValue = menulist.value;
|
||
|
}
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<!-- searchattribute - Subject, Sender, To, CC, etc. -->
|
||
|
<binding id="searchattribute" name="searchAttribute"
|
||
|
extends="chrome://messenger/content/mailWidgets.xml#search-menulist-abstract">
|
||
|
<implementation>
|
||
|
<field name="stringBundle">
|
||
|
<![CDATA[
|
||
|
srGetStrBundle("chrome://messenger/locale/search-attributes.properties");
|
||
|
]]>
|
||
|
</field>
|
||
|
<property name="valueIds" readonly="true">
|
||
|
<getter>
|
||
|
<![CDATA[
|
||
|
var length = new Object;
|
||
|
return this.validityTable.getAvailableAttributes(length);
|
||
|
]]>
|
||
|
</getter>
|
||
|
</property>
|
||
|
<constructor>
|
||
|
<![CDATA[
|
||
|
initializeTermFromId(this.id);
|
||
|
]]>
|
||
|
</constructor>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<!-- searchoperator - Contains, Is Less than, etc -->
|
||
|
<binding id="searchoperator" name="searchOperator"
|
||
|
extends="chrome://messenger/content/mailWidgets.xml#search-menulist-abstract">
|
||
|
<implementation>
|
||
|
<field name="searchAttribute">Components.interfaces.nsMsgSearchAttrib.Default</field>
|
||
|
<field name="stringBundle">
|
||
|
<![CDATA[
|
||
|
srGetStrBundle("chrome://messenger/locale/search-operators.properties");
|
||
|
]]>
|
||
|
</field>
|
||
|
<property name="valueIds" readonly="true">
|
||
|
<getter>
|
||
|
<![CDATA[
|
||
|
var length = new Object;
|
||
|
return this.validityTable.getAvailableOperators(this.searchAttribute,length);
|
||
|
]]>
|
||
|
</getter>
|
||
|
</property>
|
||
|
<property name="parentValue">
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
if (this.searchAttribute == val && val != Components.interfaces.nsMsgSearchAttrib.OtherHeader) return val;
|
||
|
this.searchAttribute = val;
|
||
|
this.refreshList();
|
||
|
if (val == Components.interfaces.nsMsgSearchAttrib.OtherHeader)
|
||
|
{
|
||
|
window.openDialog('chrome://messenger/content/CustomHeaders.xul', "", 'modal,centerscreen,resizable,titlebar,chrome', null);
|
||
|
setTimeout(UpdateAfterCustomHeaderChange, 0); // XXX bug 212625
|
||
|
}
|
||
|
return val;
|
||
|
]]>
|
||
|
</setter>
|
||
|
<getter>
|
||
|
<![CDATA[
|
||
|
return this.searchAttribute;
|
||
|
]]>
|
||
|
</getter>
|
||
|
</property>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<!-- searchvalue - a widget which dynamically changes its user interface
|
||
|
depending on what type of data it's supposed to be showing
|
||
|
currently handles arbitrary text entry, and menulists for
|
||
|
priority, status, junk status, tags, hasAttachment status,
|
||
|
and addressbook
|
||
|
-->
|
||
|
<binding id="searchvalue" name="searchValue">
|
||
|
<content>
|
||
|
<xul:textbox flex="1" class="search-value-textbox"/>
|
||
|
<xul:menulist flex="1" class="search-value-menulist">
|
||
|
<xul:menupopup class="search-value-popup">
|
||
|
<xul:menuitem value="2" stringTag="priorityLowest" class="search-value-menuitem"/>
|
||
|
<xul:menuitem value="3" stringTag="priorityLow" class="search-value-menuitem"/>
|
||
|
<xul:menuitem value="4" stringTag="priorityNormal" class="search-value-menuitem"/>
|
||
|
<xul:menuitem value="5" stringTag="priorityHigh" class="search-value-menuitem"/>
|
||
|
<xul:menuitem value="6" stringTag="priorityHighest" class="search-value-menuitem"/>
|
||
|
</xul:menupopup>
|
||
|
</xul:menulist>
|
||
|
<xul:menulist flex="1" class="search-value-menulist">
|
||
|
<xul:menupopup class="search-value-popup">
|
||
|
<xul:menuitem value="2" stringTag="replied" class="search-value-menuitem"/>
|
||
|
<xul:menuitem value="1" stringTag="read" class="search-value-menuitem"/>
|
||
|
<xul:menuitem value="65536" stringTag="new" class="search-value-menuitem"/>
|
||
|
<xul:menuitem value="4096" stringTag="forwarded" class="search-value-menuitem"/>
|
||
|
<xul:menuitem value="4" stringTag="flagged" class="search-value-menuitem"/>
|
||
|
</xul:menupopup>
|
||
|
</xul:menulist>
|
||
|
<xul:textbox flex="1" class="search-value-textbox"/>
|
||
|
<xul:menulist flex="1" class="search-value-menulist">
|
||
|
<xul:menupopup class="search-value-popup" ref="moz-abdirectory://"
|
||
|
datasources="rdf:addressdirectory"
|
||
|
sortActive="true"
|
||
|
sortDirection="ascending"
|
||
|
sortResource="http://home.netscape.com/NC-rdf#DirTreeNameSort">
|
||
|
<xul:template>
|
||
|
<xul:rule nc:IsRemote="true"/>
|
||
|
<xul:rule nc:IsMailList="false">
|
||
|
<xul:menuitem uri="..."
|
||
|
label="rdf:http://home.netscape.com/NC-rdf#DirName"
|
||
|
value="rdf:http://home.netscape.com/NC-rdf#DirUri"/>
|
||
|
</xul:rule>
|
||
|
</xul:template>
|
||
|
</xul:menupopup>
|
||
|
</xul:menulist>
|
||
|
<xul:menulist flex="1" class="search-value-menulist">
|
||
|
<xul:menupopup class="search-value-popup">
|
||
|
</xul:menupopup>
|
||
|
</xul:menulist>
|
||
|
<xul:menulist flex="1" class="search-value-menulist">
|
||
|
<xul:menupopup class="search-value-popup">
|
||
|
<xul:menuitem value="2" stringTag="junk" class="search-value-menuitem"/>
|
||
|
</xul:menupopup>
|
||
|
</xul:menulist>
|
||
|
<xul:menulist flex="1" class="search-value-menulist">
|
||
|
<xul:menupopup class="search-value-popup">
|
||
|
<xul:menuitem value="0" stringTag="hasAttachments" class="search-value-menuitem"/>
|
||
|
</xul:menupopup>
|
||
|
</xul:menulist>
|
||
|
</content>
|
||
|
<implementation>
|
||
|
<field name="internalOperator">null</field>
|
||
|
<field name="internalAttribute">null</field>
|
||
|
<field name="internalValue">null</field>
|
||
|
|
||
|
<property name="opParentValue" onget="return this.internalOperator;">
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
// noop if we're not changing it
|
||
|
if (this.internalOperator == val) return val;
|
||
|
|
||
|
// if it's not sender, we don't care
|
||
|
if (this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.Sender) {
|
||
|
this.internalOperator = val;
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
var children = document.getAnonymousNodes(this);
|
||
|
if (val == Components.interfaces.nsMsgSearchOp.IsntInAB ||
|
||
|
val == Components.interfaces.nsMsgSearchOp.IsInAB) {
|
||
|
// if the old internalOperator was
|
||
|
// IsntInAB or IsInAB, and the new internalOperator is
|
||
|
// IsntInAB or IsInAB, noop because the search value
|
||
|
// was an ab type, and it still is.
|
||
|
// otherwise, switch to the ab picker and select the PAB
|
||
|
if (this.internalOperator != Components.interfaces.nsMsgSearchOp.IsntInAB &&
|
||
|
this.internalOperator != Components.interfaces.nsMsgSearchOp.IsInAB) {
|
||
|
var abs = children[4].getElementsByAttribute("value", "moz-abmdbdirectory://abook.mab");
|
||
|
if (abs.item(0))
|
||
|
children[4].selectedItem = abs[0];
|
||
|
this.setAttribute("selectedIndex", "4");
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// if the old internalOperator wasn't
|
||
|
// IsntInAB or IsInAB, and the new internalOperator isn't
|
||
|
// IsntInAB or IsInAB, noop because the search value
|
||
|
// wasn't an ab type, and it still isn't.
|
||
|
// otherwise, switch to the textbox and clear it
|
||
|
if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
|
||
|
this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB) {
|
||
|
children[0].value = "";
|
||
|
this.setAttribute("selectedIndex", "0");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.internalOperator = val;
|
||
|
return val;
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
<!-- parentValue forwards to the attribute -->
|
||
|
<property name="parentValue" onset="return this.searchAttribute=val;"
|
||
|
onget="return this.searchAttribute;"/>
|
||
|
<property name="searchAttribute" onget="return this.internalAttribute;">
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
// noop if we're not changing it
|
||
|
if (this.internalAttribute == val) return val;
|
||
|
this.internalAttribute = val;
|
||
|
|
||
|
// if the searchAttribute changing, null out the internalOperator
|
||
|
this.internalOperator = null;
|
||
|
|
||
|
// we inherit from a deck, so just use it's index attribute
|
||
|
// to hide/show widgets
|
||
|
if (val == Components.interfaces.nsMsgSearchAttrib.Priority)
|
||
|
this.setAttribute("selectedIndex", "1");
|
||
|
else if (val == Components.interfaces.nsMsgSearchAttrib.MsgStatus)
|
||
|
this.setAttribute("selectedIndex", "2");
|
||
|
else if (val == Components.interfaces.nsMsgSearchAttrib.Date)
|
||
|
this.setAttribute("selectedIndex", "3");
|
||
|
else if (val == Components.interfaces.nsMsgSearchAttrib.Sender) {
|
||
|
// since the internalOperator is null
|
||
|
// this is the same as the initial state
|
||
|
// the initial state for Sender isn't an ab type search
|
||
|
// it's a text search, so show the textbox
|
||
|
this.setAttribute("selectedIndex", "0");
|
||
|
}
|
||
|
else if (val == Components.interfaces.nsMsgSearchAttrib.Keywords) {
|
||
|
this.setAttribute("selectedIndex", "5");
|
||
|
}
|
||
|
else if (val == Components.interfaces.nsMsgSearchAttrib.JunkStatus) {
|
||
|
this.setAttribute("selectedIndex", "6");
|
||
|
}
|
||
|
else if (val == Components.interfaces.nsMsgSearchAttrib.HasAttachmentStatus) {
|
||
|
this.setAttribute("selectedIndex", "7");
|
||
|
}
|
||
|
else {
|
||
|
// a normal text field
|
||
|
this.setAttribute("selectedIndex", "0");
|
||
|
}
|
||
|
return val;
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
<property name="value" onget="return this.internalValue;">
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
// val is a nsIMsgSearchValue object
|
||
|
this.internalValue = val;
|
||
|
var attrib = val.attrib;
|
||
|
var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
|
||
|
var children = document.getAnonymousNodes(this);
|
||
|
this.searchAttribute = attrib;
|
||
|
if (attrib == nsMsgSearchAttrib.Priority) {
|
||
|
var matchingPriority =
|
||
|
children[1].getElementsByAttribute("value", val.priority);
|
||
|
if (matchingPriority.item(0))
|
||
|
children[1].selectedItem = matchingPriority[0];
|
||
|
}
|
||
|
else if (attrib == nsMsgSearchAttrib.MsgStatus) {
|
||
|
var matchingStatus =
|
||
|
children[2].getElementsByAttribute("value", val.status);
|
||
|
if (matchingStatus.item(0))
|
||
|
children[2].selectedItem = matchingStatus[0];
|
||
|
}
|
||
|
else if (attrib == nsMsgSearchAttrib.AgeInDays)
|
||
|
children[0].value = val.age;
|
||
|
else if (attrib == nsMsgSearchAttrib.Date)
|
||
|
children[3].value = convertPRTimeToString(val.date);
|
||
|
else if (attrib == nsMsgSearchAttrib.Sender)
|
||
|
{
|
||
|
if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
|
||
|
this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB) {
|
||
|
var abs = children[4].getElementsByAttribute("value", val.str);
|
||
|
if (abs.item(0))
|
||
|
children[4].selectedItem = abs[0];
|
||
|
}
|
||
|
else
|
||
|
children[0].value = val.str;
|
||
|
}
|
||
|
else if (attrib == nsMsgSearchAttrib.Keywords)
|
||
|
{
|
||
|
var keywordVal = children[5].getElementsByAttribute("value", val.str);
|
||
|
if (keywordVal.item(0))
|
||
|
{
|
||
|
children[5].value = val.str;
|
||
|
children[5].selectedItem = keywordVal[0];
|
||
|
}
|
||
|
}
|
||
|
else if (attrib == nsMsgSearchAttrib.JunkStatus) {
|
||
|
var junkStatus =
|
||
|
children[6].getElementsByAttribute("value", val.junkStatus);
|
||
|
if (junkStatus.item(0))
|
||
|
children[6].selectedItem = junkStatus[0];
|
||
|
}
|
||
|
else if (attrib == nsMsgSearchAttrib.HasAttachmentStatus) {
|
||
|
var hasAttachmentStatus =
|
||
|
children[7].getElementsByAttribute("value", val.hasAttachmentStatus);
|
||
|
if (hasAttachmentStatus.item(0))
|
||
|
children[7].selectedItem = hasAttachmentStatus[0];
|
||
|
}
|
||
|
else if (attrib == nsMsgSearchAttrib.Size) {
|
||
|
children[0].value = val.size;
|
||
|
}
|
||
|
else
|
||
|
children[0].value = val.str;
|
||
|
return val;
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
<method name="save">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var searchValue = this.value;
|
||
|
var searchAttribute = this.searchAttribute;
|
||
|
var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
|
||
|
var children = document.getAnonymousNodes(this);
|
||
|
|
||
|
searchValue.attrib = searchAttribute;
|
||
|
if (searchAttribute == nsMsgSearchAttrib.Priority) {
|
||
|
searchValue.priority = children[1].selectedItem.value;
|
||
|
}
|
||
|
else if (searchAttribute == nsMsgSearchAttrib.MsgStatus)
|
||
|
searchValue.status = children[2].value;
|
||
|
else if (searchAttribute == nsMsgSearchAttrib.AgeInDays)
|
||
|
searchValue.age = children[0].value;
|
||
|
else if (searchAttribute == nsMsgSearchAttrib.Date)
|
||
|
searchValue.date = convertStringToPRTime(children[3].value);
|
||
|
else if (searchAttribute == nsMsgSearchAttrib.Sender) {
|
||
|
if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
|
||
|
this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB)
|
||
|
searchValue.str = children[4].selectedItem.value;
|
||
|
else
|
||
|
searchValue.str = children[0].value;
|
||
|
}
|
||
|
else if (searchAttribute == nsMsgSearchAttrib.Keywords)
|
||
|
{
|
||
|
searchValue.str = children[5].value;
|
||
|
}
|
||
|
else if (searchAttribute == nsMsgSearchAttrib.JunkStatus)
|
||
|
searchValue.junkStatus = children[6].value;
|
||
|
else if (searchAttribute == nsMsgSearchAttrib.Size)
|
||
|
searchValue.size = children[0].value;
|
||
|
else if (searchAttribute == nsMsgSearchAttrib.HasAttachmentStatus)
|
||
|
searchValue.status = 0x10000000; // 0x10000000 is MSG_FLAG_ATTACHMENT;
|
||
|
else
|
||
|
searchValue.str = children[0].value;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<method name="saveTo">
|
||
|
<parameter name="searchValue"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
this.internalValue = searchValue;
|
||
|
this.save();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<method name="fillInTags">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var children = document.getAnonymousNodes(this);
|
||
|
var popupMenu = children[5].firstChild;
|
||
|
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
|
||
|
.getService(Components.interfaces.nsIMsgTagService);
|
||
|
var tagArray = tagService.getAllTags({});
|
||
|
for (var i = 0; i < tagArray.length; ++i)
|
||
|
{
|
||
|
var taginfo = tagArray[i];
|
||
|
var newMenuItem = document.createElement('menuitem');
|
||
|
newMenuItem.setAttribute('label', taginfo.tag);
|
||
|
newMenuItem.setAttribute('value', taginfo.key);
|
||
|
popupMenu.appendChild(newMenuItem);
|
||
|
if (!i)
|
||
|
children[5].selectedItem = newMenuItem;
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<method name="fillStringsForChildren">
|
||
|
<parameter name="parentNode"/>
|
||
|
<parameter name="bundle"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var children = parentNode.childNodes;
|
||
|
var len=children.length;
|
||
|
for (var i=0; i<len; i++) {
|
||
|
var node = children[i];
|
||
|
var stringTag = node.getAttribute("stringTag");
|
||
|
if (stringTag) {
|
||
|
var attr = (node.tagName == "label") ? "value" : "label";
|
||
|
node.setAttribute(attr, bundle.GetStringFromName(stringTag));
|
||
|
}
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<method name="initialize">
|
||
|
<parameter name="menulist"/>
|
||
|
<parameter name="bundle"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
this.fillStringsForChildren(menulist.firstChild, bundle);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<constructor>
|
||
|
<![CDATA[
|
||
|
// initialize strings
|
||
|
var bundle = srGetStrBundle("chrome://messenger/locale/messenger.properties");
|
||
|
|
||
|
// intialize the priority picker
|
||
|
this.initialize(document.getAnonymousNodes(this)[1], bundle);
|
||
|
|
||
|
// initialize the status picker
|
||
|
this.initialize(document.getAnonymousNodes(this)[2], bundle);
|
||
|
|
||
|
// initialize the date picker
|
||
|
var datePicker = document.getAnonymousNodes(this)[3];
|
||
|
var searchAttribute = this.searchAttribute;
|
||
|
var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
|
||
|
var time;
|
||
|
if (searchAttribute == nsMsgSearchAttrib.Date)
|
||
|
time = datePicker.value;
|
||
|
else
|
||
|
time = new Date();
|
||
|
// do .value instead of .setAttribute("value", xxx);
|
||
|
// to work around for bug #179412
|
||
|
// (caused by bug #157210)
|
||
|
//
|
||
|
// the searchvalue widget has two textboxes
|
||
|
// one for text, one as a placeholder for a date / calendar widget
|
||
|
datePicker.value = convertDateToString(time);
|
||
|
|
||
|
// initialize the address book picker
|
||
|
this.initialize(document.getAnonymousNodes(this)[4], bundle);
|
||
|
|
||
|
// initialize the junk status picker
|
||
|
this.initialize(document.getAnonymousNodes(this)[6], bundle);
|
||
|
|
||
|
// initialize the has attachment status picker
|
||
|
this.initialize(document.getAnonymousNodes(this)[7], bundle);
|
||
|
|
||
|
// initialize the tag list
|
||
|
fillInTags();
|
||
|
]]>
|
||
|
</constructor>
|
||
|
</implementation>
|
||
|
<handlers>
|
||
|
<handler event="keypress" keycode="VK_RETURN" action="onEnterInSearchTerm();"/>
|
||
|
</handlers>
|
||
|
</binding>
|
||
|
<binding id="searchterm" name="searchTerm" extends="xul:box">
|
||
|
<implementation>
|
||
|
<field name="internalSearchTerm">null</field>
|
||
|
<field name="internalBooleanAnd">null</field>
|
||
|
<!-- the actual nsIMsgSearchTerm object -->
|
||
|
<property name="searchTerm" onget="return this.internalSearchTerm">
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
this.internalSearchTerm = val;
|
||
|
|
||
|
var term = val;
|
||
|
// val is a nsIMsgSearchTerm
|
||
|
var searchAttribute=this.searchattribute;
|
||
|
var searchOperator=this.searchoperator;
|
||
|
var searchValue=this.searchvalue;
|
||
|
|
||
|
// now reflect all attributes of the searchterm into the widgets
|
||
|
if (searchAttribute) searchAttribute.value = term.attrib;
|
||
|
if (searchOperator) searchOperator.value = val.op;
|
||
|
if (searchValue) searchValue.value = term.value;
|
||
|
|
||
|
this.booleanAnd = val.booleanAnd;
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
|
||
|
<property name="searchScope">
|
||
|
<getter>
|
||
|
<![CDATA[
|
||
|
var searchAttribute = this.searchattribute;
|
||
|
if (searchAttribute)
|
||
|
return searchAttribute.searchScope;
|
||
|
return undefined;
|
||
|
]]>
|
||
|
</getter>
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
var searchAttribute = this.searchattribute;
|
||
|
if (searchAttribute) searchAttribute.searchScope=val;
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
<!-- the three tags that make up a term - to use, set the
|
||
|
attribute in the XUL to the ID of the term.
|
||
|
-->
|
||
|
<property name="searchattribute"
|
||
|
onget="return document.getElementById(this.getAttribute('searchattribute'));"
|
||
|
onset="this.setAttribute('searchattribute',val.id)"/>
|
||
|
|
||
|
<property name="searchoperator"
|
||
|
onget="return document.getElementById(this.getAttribute('searchoperator'));"
|
||
|
onset="this.setAttribute('searchoperator',val.id)"/>
|
||
|
|
||
|
<property name="searchvalue"
|
||
|
onget="return document.getElementById(this.getAttribute('searchvalue'));"
|
||
|
onset="this.setAttribute('searchvalue',val.id)"/>
|
||
|
<field name="booleanNodes">
|
||
|
<![CDATA[
|
||
|
null;
|
||
|
]]>
|
||
|
</field>
|
||
|
<field name="stringBundle">
|
||
|
<![CDATA[
|
||
|
srGetStrBundle("chrome://messenger/locale/search.properties");
|
||
|
]]>
|
||
|
</field>
|
||
|
<property name="booleanAnd" onget="return this.internalBooleanAnd">
|
||
|
<setter>
|
||
|
<![CDATA[
|
||
|
// whenever you set this, all nodes in booleanNodes
|
||
|
// are updated to reflect the string
|
||
|
|
||
|
if (this.internalBooleanAnd == val) return;
|
||
|
this.internalBooleanAnd = val;
|
||
|
|
||
|
var booleanNodes = this.booleanNodes;
|
||
|
if (!booleanNodes) return;
|
||
|
|
||
|
var stringBundle = this.stringBundle;
|
||
|
var andString = val ? "And" : "Or";
|
||
|
for (var i=0; i<booleanNodes.length; i++) {
|
||
|
try {
|
||
|
var staticString =
|
||
|
stringBundle.GetStringFromName("search" + andString + i);
|
||
|
if (staticString && staticString.length>0)
|
||
|
booleanNodes[i].setAttribute("value", staticString);
|
||
|
} catch (ex) { /* no error, means string not found */}
|
||
|
}
|
||
|
]]>
|
||
|
</setter>
|
||
|
</property>
|
||
|
<method name="save">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var searchTerm = this.searchTerm;
|
||
|
searchTerm.attrib = this.searchattribute.value;
|
||
|
if (this.searchAttribute > nsMsgSearchAttrib.OtherHeader && this.searchAttribute < nsMsgSearchAttrib.kNumMsgSearchAttributes)
|
||
|
searchTerm.arbitraryHeader = this.searchattribute.label;
|
||
|
searchTerm.op = this.searchoperator.value;
|
||
|
if (this.searchvalue.value)
|
||
|
this.searchvalue.save();
|
||
|
else
|
||
|
this.searchvalue.saveTo(searchTerm.value);
|
||
|
searchTerm.value = this.searchvalue.value;
|
||
|
searchTerm.booleanAnd = this.booleanAnd;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<!-- if you have a search term element with no search term -->
|
||
|
<method name="saveTo">
|
||
|
<parameter name="searchTerm"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
this.internalSearchTerm = searchTerm;
|
||
|
this.save();
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<!-- Folder picker helper widgets -->
|
||
|
<binding id="popup-base" extends="chrome://global/content/bindings/popup.xml#popup">
|
||
|
<implementation>
|
||
|
<field name="tree" readonly="true">
|
||
|
document.getAnonymousNodes(this)[0];
|
||
|
</field>
|
||
|
<method name="updateHover">
|
||
|
<parameter name="event"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var box = this.tree.boxObject;
|
||
|
if (event.originalTarget == box.treeBody) {
|
||
|
// XXXbz We really want client*, but event.client* is bogus inside a popup!
|
||
|
var eventX = event.screenX - document.documentElement.boxObject.screenX;
|
||
|
var eventY = event.screenY - document.documentElement.boxObject.screenY;
|
||
|
var index = box.getRowAt(eventX, eventY);
|
||
|
box.view.selection.select(index);
|
||
|
return index;
|
||
|
}
|
||
|
return -1;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<method name="fire">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
this.hidePopup();
|
||
|
if (this.tree.currentIndex >= 0) {
|
||
|
this.setAttribute("uri", this.tree.builderView.getResourceAtIndex(this.tree.currentIndex).Value);
|
||
|
this.doCommand();
|
||
|
}
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<method name="onBlurMenuList">
|
||
|
<parameter name="event"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
this.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject).openMenu(false);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<field name="onKeyPressMenuList" readonly="true">
|
||
|
<![CDATA[
|
||
|
({
|
||
|
self: this,
|
||
|
tree: this.tree,
|
||
|
parentNode: this.parentNode,
|
||
|
getLastVisibleRow: function getLastVisibleRow(box) {
|
||
|
var f = box.getFirstVisibleRow();
|
||
|
var p = box.getPageLength();
|
||
|
var l = box.view.rowCount;
|
||
|
return (l < f + p ? l : f + p) - 1;
|
||
|
},
|
||
|
handleEvent: function handleEvent(event) {
|
||
|
if (event.altKey)
|
||
|
return;
|
||
|
var index;
|
||
|
var box = this.tree.treeBoxObject;
|
||
|
if (this.parentNode.hasAttribute("open")) {
|
||
|
event.stopPropagation();
|
||
|
event.preventDefault();
|
||
|
switch (event.keyCode) {
|
||
|
case event.DOM_VK_ESCAPE:
|
||
|
this.self.hidePopup();
|
||
|
return;
|
||
|
case event.DOM_VK_ENTER:
|
||
|
case event.DOM_VK_RETURN:
|
||
|
this.self.fire();
|
||
|
return;
|
||
|
}
|
||
|
index = this.tree.currentIndex;
|
||
|
} else {
|
||
|
switch (event.keyCode) {
|
||
|
case event.DOM_VK_PAGE_UP:
|
||
|
case event.DOM_VK_PAGE_DOWN:
|
||
|
return;
|
||
|
}
|
||
|
index = this.self.setInitialSelection();
|
||
|
}
|
||
|
switch (event.keyCode) {
|
||
|
case event.DOM_VK_UP:
|
||
|
if (index <= 0)
|
||
|
return;
|
||
|
index--;
|
||
|
break;
|
||
|
case event.DOM_VK_DOWN:
|
||
|
index++;
|
||
|
if (index == box.view.rowCount)
|
||
|
return;
|
||
|
break;
|
||
|
case event.DOM_VK_PAGE_UP:
|
||
|
if (index == box.getFirstVisibleRow())
|
||
|
box.scrollByPages(-1);
|
||
|
index = box.getFirstVisibleRow();
|
||
|
break;
|
||
|
case event.DOM_VK_PAGE_DOWN:
|
||
|
if (index == this.getLastVisibleRow(box))
|
||
|
box.scrollByPages(1);
|
||
|
index = this.getLastVisibleRow(box);
|
||
|
break;
|
||
|
case event.DOM_VK_HOME:
|
||
|
index = 0;
|
||
|
break;
|
||
|
case event.DOM_VK_END:
|
||
|
index = box.view.rowCount - 1;
|
||
|
break;
|
||
|
default:
|
||
|
if (event.charCode > 0 && !event.ctrlKey && !event.metaKey) {
|
||
|
event.preventDefault();
|
||
|
index = tree.keyNavigate(event);
|
||
|
if (index >= 0)
|
||
|
break;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
box.view.selection.select(index);
|
||
|
if (this.parentNode.hasAttribute("open"))
|
||
|
box.ensureRowIsVisible(index);
|
||
|
else
|
||
|
this.self.fire();
|
||
|
}
|
||
|
})
|
||
|
]]>
|
||
|
</field>
|
||
|
<method name="setInitialSelection">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var view = this.tree.view;
|
||
|
view.selection.selectEventsSuppressed = true;
|
||
|
for (var i = 0; i < view.rowCount; i++) {
|
||
|
if (view.isContainer(i)) {
|
||
|
if (view.isContainerEmpty(i) == view.isContainerOpen(i))
|
||
|
view.toggleOpenState(i);
|
||
|
if (view.isContainerOpen(i)) {
|
||
|
if (i + 1 == view.rowCount ||
|
||
|
view.getLevel(i + 1) <= view.getLevel(i)) {
|
||
|
view.toggleOpenState(i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
var index = -1;
|
||
|
var uri = this.parentNode.getAttribute("uri");
|
||
|
if (uri) {
|
||
|
var RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
|
||
|
index = view.getIndexOfResource(RDF.GetResource(uri));
|
||
|
}
|
||
|
view.selection.select(index);
|
||
|
return index;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
<constructor>
|
||
|
<![CDATA[
|
||
|
this.parentNode.addEventListener("keypress", this.onKeyPressMenuList, true);
|
||
|
]]>
|
||
|
</constructor>
|
||
|
<destructor>
|
||
|
<![CDATA[
|
||
|
this.parentNode.removeEventListener("keypress", this.onKeyPressMenuList, true);
|
||
|
]]>
|
||
|
</destructor>
|
||
|
</implementation>
|
||
|
<handlers>
|
||
|
<handler event="mousemove" action="this.updateHover(event);"/>
|
||
|
<handler event="click" button="0" action="if (this.updateHover(event) >= 0) this.fire();"/>
|
||
|
<handler event="popupshowing">
|
||
|
<![CDATA[
|
||
|
this.parentNode.addEventListener("blur", this.onBlurMenuList, false);
|
||
|
var box = this.tree.treeBoxObject;
|
||
|
box.focused = true;
|
||
|
var index = this.setInitialSelection();
|
||
|
var height = box.view.rowCount * box.rowHeight;
|
||
|
height += this.boxObject.height - box.treeBody.boxObject.height;
|
||
|
this.height = height;
|
||
|
if (index >= 0)
|
||
|
setTimeout(function() { box.ensureRowIsVisible(index); }, 0);
|
||
|
]]>
|
||
|
</handler>
|
||
|
<handler event="popupshown">
|
||
|
<![CDATA[
|
||
|
this.enableKeyboardNavigator(false);
|
||
|
]]>
|
||
|
</handler>
|
||
|
<handler event="popuphiding">
|
||
|
<![CDATA[
|
||
|
this.parentNode.removeEventListener("blur", this.onBlurMenuList, false);
|
||
|
]]>
|
||
|
</handler>
|
||
|
</handlers>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="folderTargetPopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
|
||
|
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||
|
<tree class="foldersTree" flex="1" datasources="rdf:msgaccountmanager rdf:mailnewsfolders" ref="msgaccounts:/" flags="dont-build-content" selstyle="primary" hidecolumnpicker="true">
|
||
|
<treecols>
|
||
|
<treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
|
||
|
</treecols>
|
||
|
<treechildren class="foldersTreeChildren"/>
|
||
|
<template>
|
||
|
<rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="true" nc:CanSearchMessages="true">
|
||
|
<treechildren>
|
||
|
<treeitem uri="rdf:*">
|
||
|
<treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
|
||
|
<treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
|
||
|
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"/>
|
||
|
</treerow>
|
||
|
</treeitem>
|
||
|
</treechildren>
|
||
|
</rule>
|
||
|
<rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="false" nc:CanSearchMessages="true" nc:Virtual="false">
|
||
|
<treechildren>
|
||
|
<treeitem uri="rdf:*">
|
||
|
<treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
|
||
|
<treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
|
||
|
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"/>
|
||
|
</treerow>
|
||
|
</treeitem>
|
||
|
</treechildren>
|
||
|
</rule>
|
||
|
<rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="true" nc:Virtual="false">
|
||
|
<treechildren>
|
||
|
<treeitem uri="rdf:*">
|
||
|
<treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
|
||
|
<treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
|
||
|
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"/>
|
||
|
</treerow>
|
||
|
</treeitem>
|
||
|
</treechildren>
|
||
|
</rule>
|
||
|
</template>
|
||
|
</tree>
|
||
|
</xbl:content>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="locationpopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
|
||
|
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||
|
<tree class="foldersTree" flex="1" datasources="rdf:null" flags="dont-build-content" selstyle="primary" hidecolumnpicker="true">
|
||
|
<treecols>
|
||
|
<treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
|
||
|
</treecols>
|
||
|
<treechildren class="foldersTreeChildren"/>
|
||
|
<template>
|
||
|
<rule nc:IsDeferred="false">
|
||
|
<treechildren>
|
||
|
<treeitem uri="rdf:*">
|
||
|
<treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
|
||
|
<treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeName"
|
||
|
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"/>
|
||
|
</treerow>
|
||
|
</treeitem>
|
||
|
</treechildren>
|
||
|
</rule>
|
||
|
</template>
|
||
|
</tree>
|
||
|
</xbl:content>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="searchpopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
|
||
|
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||
|
<tree class="foldersTree" flex="1" datasources="rdf:msgaccountmanager rdf:mailnewsfolders" ref="msgaccounts:/" flags="dont-build-content" selstyle="primary" hidecolumnpicker="true">
|
||
|
<treecols>
|
||
|
<treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
|
||
|
</treecols>
|
||
|
<treechildren class="foldersTreeChildren"/>
|
||
|
<template>
|
||
|
<rule nc:CanSearchMessages="true" nc:Virtual="false">
|
||
|
<treechildren>
|
||
|
<treeitem uri="rdf:*">
|
||
|
<treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
|
||
|
<treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
|
||
|
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"/>
|
||
|
</treerow>
|
||
|
</treeitem>
|
||
|
</treechildren>
|
||
|
</rule>
|
||
|
</template>
|
||
|
</tree>
|
||
|
</xbl:content>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="folderSummary-popup" extends="chrome://global/content/bindings/popup.xml#tooltip">
|
||
|
<content>
|
||
|
<children>
|
||
|
<xul:folderSummary/>
|
||
|
</children>
|
||
|
</content>
|
||
|
<handlers>
|
||
|
<handler event="popupshowing">
|
||
|
<![CDATA[
|
||
|
var folderTree = GetFolderTree();
|
||
|
var row = folderTree.treeBoxObject.getRowAt(event.clientX, event.clientY);
|
||
|
if (row == -1)
|
||
|
return false;
|
||
|
|
||
|
var msgFolder = GetFolderResource(folderTree, row).QueryInterface(Components.interfaces.nsIMsgFolder);
|
||
|
if (!msgFolder || msgFolder.isServer)
|
||
|
return false;
|
||
|
var asyncResults = {};
|
||
|
return document.getAnonymousNodes(this)[0].parseFolder(msgFolder, null, asyncResults);
|
||
|
]]>
|
||
|
</handler>
|
||
|
|
||
|
<handler event="popuphiding">
|
||
|
document.getAnonymousNodes(this)[0].clear();
|
||
|
</handler>
|
||
|
</handlers>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="folderSummary">
|
||
|
<content>
|
||
|
<xul:vbox/>
|
||
|
</content>
|
||
|
|
||
|
<implementation>
|
||
|
<field name="mMaxMsgHdrsInPopup">8</field>
|
||
|
<property name="hasMessages" readonly="true" onget="return document.getAnonymousNodes(this)[0].hasChildNodes();"/>
|
||
|
<method name="parseFolder">
|
||
|
<parameter name="aFolder"/>
|
||
|
<parameter name="aUrlListener"/>
|
||
|
<parameter name="aOutAsync"/>
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
// from nsMsgFolderFlags.h
|
||
|
const kMsgPopupFolderFlagTrash = 0x0100;
|
||
|
const kMsgPopupFolderFlagJunk = 0x40000000;
|
||
|
// skip servers, Trash and Junk folders
|
||
|
if (!aFolder || aFolder.isServer || aFolder.getFlag(kMsgPopupFolderFlagJunk) || aFolder.getFlag(kMsgPopupFolderFlagTrash))
|
||
|
return false;
|
||
|
var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||
|
var showPreviewText = pref.getBoolPref("mail.biff.alert.show_preview");
|
||
|
var folderArray = new Array;
|
||
|
if (aFolder.flags & MSG_FOLDER_FLAG_VIRTUAL)
|
||
|
{
|
||
|
var msgDatabase = aFolder.getMsgDatabase(null);
|
||
|
var dbFolderInfo = msgDatabase.dBFolderInfo;
|
||
|
var srchFolderUri = dbFolderInfo.getCharPtrProperty("searchFolderUri");
|
||
|
var srchFolderUriArray = srchFolderUri.split('|');
|
||
|
var foldersAdded = 0;
|
||
|
var RDF = Components.classes['@mozilla.org/rdf/rdf-service;1'].getService().QueryInterface(Components.interfaces.nsIRDFService);
|
||
|
for (var i in srchFolderUriArray)
|
||
|
{
|
||
|
var realFolder = RDF.GetResource(srchFolderUriArray[i]).QueryInterface(Components.interfaces.nsIMsgFolder);
|
||
|
if (!realFolder.isServer)
|
||
|
folderArray[foldersAdded++] = realFolder;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
folderArray[0] = aFolder;
|
||
|
var foundNewMsg = false;
|
||
|
for (var folderIndex = 0; folderIndex < folderArray.length; folderIndex++)
|
||
|
{
|
||
|
aFolder = folderArray[folderIndex];
|
||
|
// now get the database
|
||
|
var msgDatabase = aFolder.getMsgDatabase(null);
|
||
|
aFolder.setMsgDatabase(null);
|
||
|
var msgKeys = {};
|
||
|
var numMsgKeys = {};
|
||
|
msgDatabase.getNewList(numMsgKeys, msgKeys);
|
||
|
|
||
|
if (!numMsgKeys.value)
|
||
|
continue;
|
||
|
|
||
|
|
||
|
if (showPreviewText)
|
||
|
{
|
||
|
// fetchMsgPreviewText forces the previewText property to get generated
|
||
|
// for each of the message keys.
|
||
|
try {
|
||
|
aFolder.fetchMsgPreviewText(msgKeys.value, numMsgKeys.value, false, aUrlListener, aOutAsync);
|
||
|
aFolder.setMsgDatabase(null);
|
||
|
}
|
||
|
catch (ex)
|
||
|
{
|
||
|
// fetchMsgPreviewText throws an error when we call it on a news folder, we should just not show
|
||
|
// the tooltip if this method returns an error.
|
||
|
aFolder.setMsgDatabase(null);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
// if fetching the preview text is going to be an asynch operation and the caller
|
||
|
// is set up to handle that fact, then don't bother filling in any of the fields since
|
||
|
// we'll have to do this all over again when the fetch for the preview text completes.
|
||
|
// We don't expect to get called with a urlListener if we're doing a virtual folder.
|
||
|
if (aOutAsync.value && aUrlListener)
|
||
|
return false;
|
||
|
var unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
|
||
|
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
|
||
|
unicodeConverter.charset = "UTF-8";
|
||
|
foundNewMsg = true;
|
||
|
|
||
|
var index = 0;
|
||
|
var hdrParser = Components.classes["@mozilla.org/messenger/headerparser;1"].getService(Components.interfaces.nsIMsgHeaderParser);
|
||
|
while (document.getAnonymousNodes(this)[0].childNodes.length < this.mMaxMsgHdrsInPopup && index < numMsgKeys.value)
|
||
|
{
|
||
|
var msgPopup = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "folderSummaryMessage");
|
||
|
var msgHdr = msgDatabase.GetMsgHdrForKey(msgKeys.value[index++]);
|
||
|
|
||
|
var msgSubject = msgHdr.mime2DecodedSubject;
|
||
|
const kMsgFlagHasRe = 0x0010; // MSG_FLAG_HAS_RE
|
||
|
if(msgHdr.flags & kMsgFlagHasRe)
|
||
|
msgSubject = "Re: " + msgSubject;
|
||
|
|
||
|
msgPopup.setAttribute('subject', msgSubject);
|
||
|
|
||
|
var previewText = msgHdr.getStringProperty('preview');
|
||
|
// convert the preview text from utf-8 to unicode
|
||
|
if (previewText)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
var text = unicodeConverter.ConvertToUnicode(previewText);
|
||
|
if (text)
|
||
|
msgPopup.setAttribute('previewText', text);
|
||
|
}
|
||
|
catch (ex) { }
|
||
|
}
|
||
|
|
||
|
var names = {};
|
||
|
var emails = {};
|
||
|
var numAddresses = hdrParser.parseHeadersWithArray(msgHdr.mime2DecodedAuthor, emails, names, {});
|
||
|
msgPopup.setAttribute('sender', names.value[0] ? names.value[0] : emails.value[0]);
|
||
|
msgPopup.messageUri = aFolder.getUriForMsg(msgHdr);
|
||
|
msgPopup.folderUri = aFolder.URI;
|
||
|
msgPopup.msgKey = msgHdr.messageKey;
|
||
|
document.getAnonymousNodes(this)[0].appendChild(msgPopup);
|
||
|
}
|
||
|
if (document.getAnonymousNodes(this)[0].childNodes.length >= this.mMaxMsgHdrsInPopup)
|
||
|
return true;
|
||
|
}
|
||
|
return foundNewMsg;
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
|
||
|
<method name="clear">
|
||
|
<body>
|
||
|
<![CDATA[
|
||
|
var containingBox = document.getAnonymousNodes(this)[0];
|
||
|
while (containingBox.hasChildNodes())
|
||
|
containingBox.removeChild(containingBox.lastChild);
|
||
|
]]>
|
||
|
</body>
|
||
|
</method>
|
||
|
</implementation>
|
||
|
</binding>
|
||
|
|
||
|
<binding id="folderSummary-message">
|
||
|
<content>
|
||
|
<xul:vbox class="folderSummaryMessage">
|
||
|
<xul:hbox class="folderSummary-message-row">
|
||
|
<xul:label anonid="subject" flex="1" class="folderSummary-subject" xbl:inherits="value=subject" crop="right"/>
|
||
|
<xul:label anonid="sender" class="folderSummary-sender" xbl:inherits="value=sender" crop="right"/>
|
||
|
<xul:spring anonid="spring" flex="100%"/>
|
||
|
</xul:hbox>
|
||
|
<xul:description anonid="preview" class="folderSummary-message-row folderSummary-previewText" xbl:inherits="value=previewText" crop="right"></xul:description>
|
||
|
</xul:vbox>
|
||
|
</content>
|
||
|
<implementation>
|
||
|
<constructor>
|
||
|
<![CDATA[
|
||
|
var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||
|
if (!pref.getBoolPref("mail.biff.alert.show_preview"))
|
||
|
document.getAnonymousElementByAttribute(this, "anonid", "preview").hidden = true;
|
||
|
var hideSubject = !pref.getBoolPref("mail.biff.alert.show_subject");
|
||
|
var hideSender = !pref.getBoolPref("mail.biff.alert.show_sender");
|
||
|
if (hideSubject)
|
||
|
document.getAnonymousElementByAttribute(this, "anonid", "subject").hidden = true;
|
||
|
if (hideSender)
|
||
|
document.getAnonymousElementByAttribute(this, "anonid", "sender").hidden = true;
|
||
|
if (hideSubject && hideSender)
|
||
|
document.getAnonymousElementByAttribute(this, "anonid", "spring").hidden = true;
|
||
|
]]>
|
||
|
</constructor>
|
||
|
</implementation>
|
||
|
<handlers>
|
||
|
<handler event="click" button="0">
|
||
|
<![CDATA[
|
||
|
var mailSession = Components.classes["@mozilla.org/messenger/services/session;1"].
|
||
|
getService(Components.interfaces.nsIMsgMailSession);
|
||
|
var topmostMsgWindow;
|
||
|
try {
|
||
|
topmostMsgWindow = mailSession.topmostMsgWindow;
|
||
|
} catch (ex) {}
|
||
|
|
||
|
if (topmostMsgWindow)
|
||
|
{
|
||
|
try {
|
||
|
// SelectFolder throws an exception if the folder is not in the current folder view
|
||
|
mailSession.topmostMsgWindow.SelectFolder(this.folderUri);
|
||
|
mailSession.topmostMsgWindow.SelectMessage(this.messageUri);
|
||
|
} catch (ex) {}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// open a new window
|
||
|
var mailWindowService = Components.classes["@mozilla.org/messenger/windowservice;1"].
|
||
|
getService(Components.interfaces.nsIMessengerWindowService);
|
||
|
mailWindowService.openMessengerWindowWithUri("mail:3pane", this.folderUri, this.msgKey);
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
if (gAlertListener)
|
||
|
gAlertListener.observe(null, "alertclickcallback", "");
|
||
|
} catch (ex) {}
|
||
|
]]>
|
||
|
</handler>
|
||
|
</handlers>
|
||
|
</binding>
|
||
|
</bindings>
|