зеркало из https://github.com/mozilla/pjs.git
search & filter revamp
- fixes #41711, #48698, #48238 among other things - moves some XBL into straight JS where it belongs - fixes bad XBL setters to return the value that comes in - fire more notification when filter attributes/operators change
This commit is contained in:
Родитель
5a92dc2eac
Коммит
a1506acc69
|
@ -3,7 +3,9 @@
|
|||
<bindings id="mailBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
|
||||
<!-- dummy widget to force this file to load -->
|
||||
<binding id="dummy" extends="xul:box"/>
|
||||
<!-- Message Pane Widgets -->
|
||||
<binding id="mail-emailaddress" extends="xul:box">
|
||||
<content>
|
||||
|
@ -66,9 +68,10 @@
|
|||
<setter>
|
||||
<![CDATA[
|
||||
// if scope isn't changing this is a noop
|
||||
if (this.internalScope == val) return;
|
||||
if (this.internalScope == val) return val;
|
||||
|
||||
this.internalScope = val;
|
||||
//dump("\trefreshList via .searchScope setter\n");
|
||||
this.refreshList();
|
||||
var targets = this.targets;
|
||||
if (targets) {
|
||||
|
@ -76,6 +79,7 @@
|
|||
targets[i].searchScope = val;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
@ -117,10 +121,23 @@
|
|||
<property name="value" onget="return document.getAnonymousNodes(this)[0].selectedItem.getAttribute('data');">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
dump("\tsetting value on id=" + this.id + "\n");
|
||||
var menulist = document.getAnonymousNodes(this)[0];
|
||||
var dataItems = menulist.getElementsByAttribute("data", val);
|
||||
if (dataItems.length > 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++) {
|
||||
//dump("setting parentValue via abstract .value on <" + this.localName +">\n");
|
||||
targets[i].parentValue = val;
|
||||
}
|
||||
} else {
|
||||
//dump("Doh! No targets!\n");
|
||||
}
|
||||
return val;
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
@ -218,9 +235,11 @@
|
|||
<property name="parentValue">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
if (this.searchAttribute == val) return;
|
||||
if (this.searchAttribute == val) return val;
|
||||
this.searchAttribute = val;
|
||||
//dump("\trefreshList via .parentValue on " + this.localName + "\n");
|
||||
this.refreshList();
|
||||
return val;
|
||||
]]>
|
||||
</setter>
|
||||
<getter>
|
||||
|
@ -243,11 +262,11 @@
|
|||
<xul:textfield flex="1" class="search-value-textfield"/>
|
||||
<xul:menulist flex="1" class="search-value-menulist">
|
||||
<xul:menupopup class="search-value-popup">
|
||||
<xul:menuitem value="Lowest" class="search-value-menuitem"/>
|
||||
<xul:menuitem value="Low" class="search-value-menuitem"/>
|
||||
<xul:menuitem value="Normal" class="search-value-menuitem"/>
|
||||
<xul:menuitem value="High" class="search-value-menuitem"/>
|
||||
<xul:menuitem value="Highest" class="search-value-menuitem"/>
|
||||
<xul:menuitem data="2" value="Lowest" class="search-value-menuitem"/>
|
||||
<xul:menuitem data="3" value="Low" class="search-value-menuitem"/>
|
||||
<xul:menuitem data="4" value="Normal" class="search-value-menuitem"/>
|
||||
<xul:menuitem data="5" value="High" class="search-value-menuitem"/>
|
||||
<xul:menuitem data="6" value="Highest" class="search-value-menuitem"/>
|
||||
</xul:menupopup>
|
||||
</xul:menulist>
|
||||
<xul:menulist flex="1" class="search-value-menulist">
|
||||
|
@ -259,13 +278,13 @@
|
|||
</content>
|
||||
<interface>
|
||||
<!-- parentValue forwards to the attribute -->
|
||||
<property name="parentValue" onset="this.searchAttribute=val;"
|
||||
<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;
|
||||
if (this.internalAttribute == val) return val;
|
||||
this.internalAttribute = val;
|
||||
// we inherit from a deck, so just use it's index attribute
|
||||
// to hide/show widgets
|
||||
|
@ -275,22 +294,39 @@
|
|||
this.setAttribute("index", "2");
|
||||
else
|
||||
this.setAttribute("index", "0");
|
||||
return val;
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
<property name="value" onget="return this.internalValue;">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
dump("\tsetting value on id=" + this.id + "\n");
|
||||
// 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 == Components.interfaces.nsMsgSearchAttrib.Priority)
|
||||
document.getAnonymousNodes(this)[1].data=val.priority;
|
||||
else if (attrib == Components.interfaces.nsMsgSearchAttrib.MsgStatus)
|
||||
document.getAnonymousNodes(this)[2].data=val.status;
|
||||
if (attrib == nsMsgSearchAttrib.Priority) {
|
||||
dump("Setting priority to " + val.priority + "..\n");
|
||||
var matchingPriority =
|
||||
children[1].getElementsByAttribute("data", val.priority);
|
||||
dump("found " + matchingPriority.length + " matching priority nodes\n");
|
||||
if (matchingPriority.length > 0)
|
||||
children[1].selectedItem = matchingPriority[0];
|
||||
}
|
||||
else if (attrib == nsMsgSearchAttrib.MsgStatus) {
|
||||
var matchingStatus =
|
||||
children[2].getElementsByAttribute("data", val.status);
|
||||
if (matchingStatus.length > 0)
|
||||
children[2].selectedItem = matchingStatus[0];
|
||||
}
|
||||
else if (attrib == nsMsgSearchAttrib.AgeInDays)
|
||||
children[0].value = val.age;
|
||||
else
|
||||
document.getAnonymousNodes(this)[0].value = val.str;
|
||||
children[0].value = val.str;
|
||||
return val;
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
@ -300,14 +336,19 @@
|
|||
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 = document.getAnonymousNodes(this)[1].selectedItem.data;
|
||||
if (searchAttribute == nsMsgSearchAttrib.Priority) {
|
||||
dump("\tSaving priority " + children[1].selectedItem.data + "\n");
|
||||
searchValue.priority = children[1].selectedItem.data;
|
||||
}
|
||||
else if (searchAttribute == nsMsgSearchAttrib.MsgStatus)
|
||||
searchValue.status = document.getAnonymousNodes(this)[2].selectedItem.data;
|
||||
searchValue.status = children[2].selectedItem.data;
|
||||
else if (searchAttribute == nsMsgSearchAttrib.AgeInDays)
|
||||
searchValue.age = children[0].value;
|
||||
else
|
||||
searchValue.str = document.getAnonymousNodes(this)[0].value;
|
||||
searchValue.str = children[0].value;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -322,120 +363,4 @@
|
|||
</method>
|
||||
</interface>
|
||||
</binding>
|
||||
<binding id="searchterm" name="searchTerm" extends="xul:box">
|
||||
<interface>
|
||||
<!-- 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)"/>
|
||||
<property name="booleanNodes">
|
||||
<![CDATA[
|
||||
null;
|
||||
]]>
|
||||
</property>
|
||||
<property name="stringBundle">
|
||||
<![CDATA[
|
||||
srGetStrBundle("chrome://messenger/locale/search.properties");
|
||||
]]>
|
||||
</property>
|
||||
<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;
|
||||
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">
|
||||
<argument name="searchTerm"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this.internalSearchTerm = searchTerm;
|
||||
this.save();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</interface>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
|
|
@ -102,6 +102,7 @@ function initializeDialog(filter)
|
|||
showActionElementFor(gActionElement.selectedItem);
|
||||
|
||||
if (filter.action == nsMsgFilterAction.MoveToFolder) {
|
||||
dump("pre-selecting target folder: " + filter.actionTargetFolderUri + "\n");
|
||||
// there are multiple sub-items that have given attribute
|
||||
var targets = gActionTargetElement.getElementsByAttribute("data", filter.actionTargetFolderUri);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ Rights Reserved.
|
|||
persist="width height screenX screenY"
|
||||
onload="filterEditorOnLoad('msgFccFolderPicker');">
|
||||
|
||||
<dummy class="usesMailWidgets"/>
|
||||
<script language="JavaScript" src="chrome://global/content/strres.js"/>
|
||||
<script language="JavaScript" src="chrome://messenger/content/FilterEditor.js"/>
|
||||
|
||||
|
@ -45,12 +46,15 @@ Rights Reserved.
|
|||
<textfield flex="1" id="filterName"/>
|
||||
</box>
|
||||
|
||||
<titledbox id="searchTermListBox" flex="1"/>
|
||||
<titledbox value="&conditions.label;" orient="vertical">
|
||||
<text value="&conditionDesc.label;"/>
|
||||
<box id="searchTermListBox" flex="1"/>
|
||||
</titledbox>
|
||||
|
||||
<titledbox autostretch="never">
|
||||
<titledbox autostretch="never" orient="horizontal">
|
||||
<title value="&filterAction.label;"/>
|
||||
|
||||
<menulist id="actionMenu" flex="1" oncommand="onActionChanged(event)">
|
||||
<box orient="horizontal" flex="1">
|
||||
<menulist id="actionMenu" oncommand="onActionChanged(event)">
|
||||
<menupopup>
|
||||
<menuitem data="1" actionvalueindex="0" value="&moveToFolder.label;"/>
|
||||
<menuitem data="2" actionvalueindex="1" value="&changePriority.label;"/>
|
||||
|
@ -63,7 +67,7 @@ Rights Reserved.
|
|||
<deck id="actionValueDeck" flex="1">
|
||||
<menulist id="actionTargetFolder" flex="1"
|
||||
oncommand="onTargetFolderSelected(event);"/>
|
||||
<menulist id="actionValuePriority">
|
||||
<menulist id="actionValuePriority" flex="1">
|
||||
<menupopup>
|
||||
<!-- see MailNewsTypes2.idl -->
|
||||
<menuitem data="6" value="&highestPriorityCmd.label;"/>
|
||||
|
@ -73,8 +77,9 @@ Rights Reserved.
|
|||
<menuitem data="2" value="&lowestPriorityCmd.label;"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<text id="actionValueNone"/>
|
||||
<text id="actionValueNone" flex="1"/>
|
||||
</deck>
|
||||
</box>
|
||||
</titledbox>
|
||||
|
||||
<separator/>
|
||||
|
|
|
@ -47,8 +47,8 @@ Rights Reserved.
|
|||
<rows>
|
||||
<row>
|
||||
<text class="label" value="&filtersForPrefix.label;"/>
|
||||
<spring/>
|
||||
<spring/>
|
||||
<box/>
|
||||
<box/>
|
||||
</row>
|
||||
<row>
|
||||
<menulist oncommand="onServerClick(event);" id="serverMenu">
|
||||
|
@ -60,13 +60,13 @@ Rights Reserved.
|
|||
</template>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<spring/>
|
||||
<spring/>
|
||||
<box/>
|
||||
<box/>
|
||||
</row>
|
||||
<row>
|
||||
<separator class="thin"/>
|
||||
<spring/>
|
||||
<spring/>
|
||||
<separator/>
|
||||
<box/>
|
||||
<box/>
|
||||
</row>
|
||||
<row>
|
||||
<box orient="vertical">
|
||||
|
@ -103,8 +103,8 @@ Rights Reserved.
|
|||
</template>
|
||||
|
||||
<treecolgroup>
|
||||
<treecol style="width: 0px" flex="75" rdf:resource="http://home.netscape.com/NC-rdf#Name" id="nameColumn"/>
|
||||
<treecol style="width: 0px" flex="25" id="activeColumn"/>
|
||||
<treecol style="width: 0px" flex="1" rdf:resource="http://home.netscape.com/NC-rdf#Name" id="nameColumn"/>
|
||||
<treecol id="activeColumn"/>
|
||||
</treecolgroup>
|
||||
|
||||
<treechildren flex="1"/>
|
||||
|
@ -113,8 +113,8 @@ Rights Reserved.
|
|||
</box>
|
||||
<box orient="vertical">
|
||||
<spring flex="1"/>
|
||||
<button class="reorder-up top" oncommand="onUp(event);"/>
|
||||
<button class="reorder-down top" oncommand="onDown(event);"/>
|
||||
<button class="reorder-up" oncommand="onUp(event);"/>
|
||||
<button class="reorder-down" oncommand="onDown(event);"/>
|
||||
<spring flex="1"/>
|
||||
</box>
|
||||
<box orient="vertical">
|
||||
|
|
|
@ -49,6 +49,12 @@ function searchOnLoad()
|
|||
|
||||
}
|
||||
|
||||
function searchOnUnload()
|
||||
{
|
||||
// release this early because msgWindow holds a weak reference
|
||||
msgWindow.rootDocShell = null;
|
||||
}
|
||||
|
||||
function initializeSearchWindowWidgets()
|
||||
{
|
||||
gFolderPicker = document.getElementById("searchableFolders");
|
||||
|
@ -104,7 +110,6 @@ function selectFolder(folder) {
|
|||
if (elements && elements.length)
|
||||
gFolderPicker.selectedItem = elements[0];
|
||||
}
|
||||
dump("Selected <" + gFolderPicker.selectedItem.localName + ">\n");
|
||||
updateSearchFolderPicker()
|
||||
}
|
||||
|
||||
|
@ -130,6 +135,7 @@ function onChooseFolder(event) {
|
|||
|
||||
function onSearch(event)
|
||||
{
|
||||
dump("setting up search..\n");
|
||||
gSearchSession.clearScopes();
|
||||
// tell the search session what the new scope is
|
||||
gSearchSession.addScopeTerm(GetScopeForFolder(gCurrentFolder),
|
||||
|
@ -142,6 +148,7 @@ function onSearch(event)
|
|||
// refresh the tree after the search starts, because initiating the
|
||||
// search will cause the datasource to clear itself
|
||||
gThreadTree.setAttribute("ref", gThreadTree.getAttribute("ref"));
|
||||
dump("Kicking it off with " + gThreadTree.getAttribute("ref") + "\n");
|
||||
}
|
||||
|
||||
|
||||
|
@ -223,6 +230,7 @@ function IsThreadAndMessagePaneSplitterCollapsed()
|
|||
|
||||
function setMsgDatasourceWindow(ds, msgwindow)
|
||||
{
|
||||
dump("setMsgDatasourceWindow(" + ds + ")\n");
|
||||
try {
|
||||
var msgDatasource = ds.QueryInterface(nsIMsgRDFDataSource);
|
||||
msgDatasource.window = msgwindow;
|
||||
|
|
|
@ -33,9 +33,11 @@ Rights Reserved.
|
|||
<window xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="searchOnLoad();"
|
||||
onunload="searchOnUnload();"
|
||||
title="&searchDialogTitle.label;"
|
||||
width="620" height="470"
|
||||
persist="screenX screenY width height"
|
||||
class="color-dialog"
|
||||
orient="vertical">
|
||||
|
||||
<keyset id="keyset"/>
|
||||
|
@ -43,8 +45,10 @@ Rights Reserved.
|
|||
<script src="chrome://global/content/strres.js"/>
|
||||
<script src="chrome://messenger/content/mailWindow.js"/>
|
||||
<script src="chrome://messenger/content/SearchDialog.js"/>
|
||||
|
||||
<box orient="vertical" class="dialog box-padded">
|
||||
|
||||
<dummy class="usesMailWidgets"/>
|
||||
<titledbox value="&conditions.label;" orient="vertical" class="dialog box-padded">
|
||||
|
||||
<box autostretch="never">
|
||||
<text class="label" value="&searchHeading.label;"/>
|
||||
<menulist id="searchableFolders" flex="2"
|
||||
|
@ -54,18 +58,20 @@ Rights Reserved.
|
|||
<checkbox value="&searchSubfolders.label;"/>
|
||||
-->
|
||||
</box>
|
||||
<separator/>
|
||||
<text class="label" value="&conditionDesc.label;"/>
|
||||
|
||||
<box flex="1">
|
||||
<titledbox id="searchTermListBox" flex="1"/>
|
||||
<box id="searchTermListBox" flex="1"/>
|
||||
<box orient="vertical">
|
||||
<button value="&searchButton.label;" oncommand="onSearch(event)"/>
|
||||
<button value="&resetButton.label;" oncommand="onReset(event)"/>
|
||||
<spring flex="1"/>
|
||||
<button value="&closeButton.label;" onclick="window.close()"/>
|
||||
<button value="&closeButton.label;" onclick="window.close();"/>
|
||||
<separator class="thin"/>
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
</titledbox>
|
||||
|
||||
<splitter id="searchfields-splitter" collapse="before" persist="state hidden"
|
||||
autostretch="never" orient="vertical">
|
||||
|
|
|
@ -23,17 +23,126 @@
|
|||
|
||||
var gTotalSearchTerms=0;
|
||||
var gSearchRowContainer;
|
||||
var gSearchTermContainer;
|
||||
var gSearchTerms = new Array;
|
||||
var gSearchRemovedTerms = new Array;
|
||||
var gSearchScope;
|
||||
var gSearchLessButton;
|
||||
|
||||
//
|
||||
function searchTermContainer() {}
|
||||
|
||||
searchTermContainer.prototype = {
|
||||
|
||||
// this.searchTerm: the actual nsIMsgSearchTerm object
|
||||
get searchTerm() { return this.internalSearchTerm; },
|
||||
set searchTerm(val) {
|
||||
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;
|
||||
return val;
|
||||
},
|
||||
|
||||
// searchscope - just forward to the searchattribute
|
||||
get searchScope() {
|
||||
if (this.searchattribute)
|
||||
return this.searchattribute.searchScope;
|
||||
return undefined;
|
||||
},
|
||||
set searchScope(val) {
|
||||
var searchAttribute = this.searchattribute;
|
||||
if (searchAttribute) searchAttribute.searchScope=val;
|
||||
return val;
|
||||
},
|
||||
|
||||
saveId: function (element, slot) {
|
||||
this[slot] = element.id;
|
||||
},
|
||||
|
||||
getElement: function (slot) {
|
||||
return document.getElementById(this[slot]);
|
||||
},
|
||||
|
||||
// three well-defined properties:
|
||||
// searchattribute, searchoperator, searchvalue
|
||||
// the trick going on here is that we're storing the Element's Id,
|
||||
// not the element itself, because the XBL object may change out
|
||||
// from underneath us
|
||||
get searchattribute() { return this.getElement("internalSearchAttributeId"); },
|
||||
set searchattribute(val) {
|
||||
this.saveId(val, "internalSearchAttributeId");
|
||||
return val;
|
||||
},
|
||||
get searchoperator() { return this.getElement("internalSearchOperatorId"); },
|
||||
set searchoperator(val) {
|
||||
this.saveId(val, "internalSearchOperatorId");
|
||||
return val;
|
||||
},
|
||||
get searchvalue() { return this.getElement("internalSearchValueId"); },
|
||||
set searchvalue(val) {
|
||||
this.saveId(val, "internalSearchValueId");
|
||||
return val;
|
||||
},
|
||||
|
||||
booleanNodes: null,
|
||||
stringBundle: srGetStrBundle("chrome://messenger/locale/search.properties"),
|
||||
get booleanAnd() { return this.internalBooleanAnd; },
|
||||
set booleanAnd(val) {
|
||||
// whenever you set this, all nodes in booleanNodes
|
||||
// are updated to reflect the string
|
||||
|
||||
if (this.internalBooleanAnd == val) return val;
|
||||
this.internalBooleanAnd = val;
|
||||
|
||||
var booleanNodes = this.booleanNodes;
|
||||
if (!booleanNodes) return val;
|
||||
|
||||
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 */}
|
||||
}
|
||||
return val;
|
||||
},
|
||||
|
||||
save: function () {
|
||||
var searchTerm = this.searchTerm;
|
||||
searchTerm.attrib = this.searchattribute.value;
|
||||
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;
|
||||
},
|
||||
// if you have a search term element with no search term
|
||||
saveTo: function(searchTerm) {
|
||||
this.internalSearchTerm = searchTerm;
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
var nsIMsgSearchTerm = Components.interfaces.nsIMsgSearchTerm;
|
||||
|
||||
function initializeSearchWidgets() {
|
||||
gSearchBooleanRadiogroup = document.getElementById("booleanAndGroup");
|
||||
gSearchRowContainer = document.getElementById("searchTermList");
|
||||
gSearchTermContainer = document.getElementById("searchterms");
|
||||
gSearchLessButton = document.getElementById("less");
|
||||
if (!gSearchLessButton)
|
||||
dump("I couldn't find less button!");
|
||||
|
@ -43,7 +152,7 @@ function initializeBooleanWidgets() {
|
|||
|
||||
var booleanAnd = true;
|
||||
// get the boolean value from the first term
|
||||
var firstTerm = gSearchTermContainer.firstChild;
|
||||
var firstTerm = gSearchTerms[0];
|
||||
if (firstTerm)
|
||||
booleanAnd = firstTerm.booleanAnd;
|
||||
|
||||
|
@ -85,11 +194,9 @@ function onLess(event)
|
|||
function setSearchScope(scope) {
|
||||
dump("Setting search scope to " + scope + "\n");
|
||||
gSearchScope = scope;
|
||||
var searchTermElements = gSearchTermContainer.childNodes;
|
||||
if (!searchTermElements) return;
|
||||
dump("..on " + searchTermElements.length + " elements.\n");
|
||||
for (var i=0; i<searchTermElements.length; i++) {
|
||||
searchTermElements[i].searchattribute.searchScope = scope;
|
||||
dump("..on " + gSearchTerms.length + " elements.\n");
|
||||
for (var i=0; i<gSearchTerms.length; i++) {
|
||||
gSearchTerms[i].searchattribute.searchScope = scope;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,11 +206,9 @@ function booleanChanged(event) {
|
|||
|
||||
var newBoolValue =
|
||||
(event.target.getAttribute("data") == "and") ? true : false;
|
||||
searchTermElements = gSearchTermContainer.childNodes;
|
||||
if (!searchTermElements) return;
|
||||
for (var i=0; i<searchTermElements.length; i++) {
|
||||
var searchTerm = searchTermElements[i];
|
||||
searchTerm.booleanAnd = newBoolValue;
|
||||
for (var i=0; i<gSearchTerms.length; i++) {
|
||||
var searchTerm = gSearchTerms[i];
|
||||
gSearchTerms.booleanAnd = newBoolValue;
|
||||
}
|
||||
dump("Boolean is now " + event.target.data + "\n");
|
||||
}
|
||||
|
@ -130,25 +235,23 @@ function createSearchRow(index, scope, searchTerm)
|
|||
|
||||
searchrow.id = "searchRow" + index;
|
||||
|
||||
// should this be done with XBL or just straight JS?
|
||||
// probably straight JS but I don't know how that's done.
|
||||
var searchTermElement = document.createElement("searchterm");
|
||||
searchTermElement.id = "searchTerm" + index;
|
||||
gSearchTermContainer.appendChild(searchTermElement);
|
||||
searchTermElement = document.getElementById(searchTermElement.id);
|
||||
var searchTermObj = new searchTermContainer;
|
||||
// is this necessary?
|
||||
//searchTermElement.id = "searchTerm" + index;
|
||||
gSearchTerms[gSearchTerms.length] = searchTermObj;
|
||||
|
||||
searchTermElement.searchattribute = searchAttr;
|
||||
searchTermElement.searchoperator = searchOp;
|
||||
searchTermElement.searchvalue = searchVal;
|
||||
searchTermObj.searchattribute = searchAttr;
|
||||
searchTermObj.searchoperator = searchOp;
|
||||
searchTermObj.searchvalue = searchVal;
|
||||
|
||||
// now invalidate the newly created items because they've been inserted
|
||||
// into the document, and XBL bindings will be inserted in their place
|
||||
searchAttr = searchOp = searchVal = undefined;
|
||||
//searchAttr = searchOp = searchVal = undefined;
|
||||
|
||||
// and/or string handling:
|
||||
// this is scary - basically we want to take every other
|
||||
// treecell, (note the i+=2) which will be a text label,
|
||||
// and set the searchTermElement's
|
||||
// and set the searchTermObj's
|
||||
// booleanNodes to that
|
||||
var stringNodes = new Array;
|
||||
var treecells = searchrow.firstChild.childNodes;
|
||||
|
@ -156,21 +259,27 @@ function createSearchRow(index, scope, searchTerm)
|
|||
for (var i=0; i<treecells.length; i+=2) {
|
||||
stringNodes[j++] = treecells[i];
|
||||
}
|
||||
searchTermElement.booleanNodes = stringNodes;
|
||||
searchTermObj.booleanNodes = stringNodes;
|
||||
|
||||
gSearchRowContainer.appendChild(searchrow);
|
||||
|
||||
searchTermElement.searchScope = scope;
|
||||
dump("createSearchRow: Setting searchScope = " + scope + "\n");
|
||||
searchTermObj.searchScope = scope;
|
||||
// the search term will initialize the searchTerm element, including
|
||||
// .booleanAnd
|
||||
if (searchTerm)
|
||||
searchTermElement.searchTerm = searchTerm;
|
||||
if (searchTerm) {
|
||||
dump("\nHave a searchterm (" +
|
||||
searchTerm.attrib + "/" +
|
||||
searchTerm.op + "/" +
|
||||
searchTerm.value + ")\n");
|
||||
searchTermObj.searchTerm = searchTerm;
|
||||
}
|
||||
|
||||
// here, we don't have a searchTerm, so it's probably a new element -
|
||||
// we'll initialize the .booleanAnd from the existing setting in
|
||||
// the UI
|
||||
else
|
||||
searchTermElement.booleanAnd = getBooleanAnd();
|
||||
searchTermObj.booleanAnd = getBooleanAnd();
|
||||
|
||||
}
|
||||
|
||||
|
@ -188,6 +297,9 @@ function constructRow(treeCellChildren)
|
|||
treecell.setAttribute("allowevents", "true");
|
||||
treeCellChildren[i].setAttribute("flex", "1");
|
||||
treecell.appendChild(treeCellChildren[i]);
|
||||
var child = treeCellChildren[i];
|
||||
dump("Appended a " + child.localName + "\n");
|
||||
|
||||
}
|
||||
row.appendChild(treecell);
|
||||
}
|
||||
|
@ -198,15 +310,16 @@ function constructRow(treeCellChildren)
|
|||
function removeSearchRow(index)
|
||||
{
|
||||
dump("removing search term " + index + "\n");
|
||||
var searchTermElement = document.getElementById("searchTerm" + index);
|
||||
if (!searchTermElement) {
|
||||
var searchTermObj = gSearchTerms[index];
|
||||
if (!searchTermObj) {
|
||||
dump("removeSearchRow: couldn't find search term " + index + "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// need to remove row from tree, so walk upwards from the
|
||||
// searchattribute to find the first <treeitem>
|
||||
var treeItemRow = searchTermElement.searchattribute;
|
||||
var treeItemRow = searchTermObj.searchattribute;
|
||||
dump("removeSearchRow: " + treeItemRow + "\n");
|
||||
while (treeItemRow) {
|
||||
if (treeItemRow.localName == "treeitem") break;
|
||||
treeItemRow = treeItemRow.parentNode;
|
||||
|
@ -218,15 +331,19 @@ function removeSearchRow(index)
|
|||
}
|
||||
|
||||
|
||||
if (searchTermElement.searchTerm) {
|
||||
dump("That was a real row! queuing " + searchTermElement.searchTerm + " for disposal\n");
|
||||
gSearchRemovedTerms[gSearchRemovedTerms.length] = searchTermElement.searchTerm;
|
||||
if (searchTermObj.searchTerm) {
|
||||
dump("That was a real row! queuing " + searchTermObj.searchTerm + " for disposal\n");
|
||||
gSearchRemovedTerms[gSearchRemovedTerms.length] = searchTermObj.searchTerm;
|
||||
} else {
|
||||
dump("That wasn't real. ignoring \n");
|
||||
}
|
||||
|
||||
treeItemRow.parentNode.removeChild(treeItemRow);
|
||||
searchTermElement.parentNode.removeChild(searchTermElement);
|
||||
// remove it from the list of terms - XXX this does it?
|
||||
dump("Removing row " + index + " from " + gSearchTerms.length + " items\n");
|
||||
// remove the last element
|
||||
gSearchTerms.length--;
|
||||
dump("Now there are " + gSearchTerms.length + " items\n");
|
||||
}
|
||||
|
||||
function getBooleanAnd()
|
||||
|
@ -245,25 +362,23 @@ function getBooleanAnd()
|
|||
// via XPCOM)
|
||||
function saveSearchTerms(searchTerms, termOwner)
|
||||
{
|
||||
var searchTermElements =
|
||||
gSearchTermContainer.childNodes;
|
||||
|
||||
for (var i = 0; i<searchTermElements.length; i++) {
|
||||
for (var i = 0; i<gSearchTerms.length; i++) {
|
||||
try {
|
||||
dump("Saving search element " + i + "\n");
|
||||
var searchTerm = searchTermElements[i].searchTerm;
|
||||
var searchTerm = gSearchTerms[i].searchTerm;
|
||||
if (searchTerm)
|
||||
searchTermElements[i].save();
|
||||
gSearchTerms[i].save();
|
||||
else {
|
||||
// need to create a new searchTerm, and somehow save it to that
|
||||
dump("Need to create searchterm " + i + "\n");
|
||||
searchTerm = termOwner.createTerm();
|
||||
searchTermElements[i].saveTo(searchTerm);
|
||||
gSearchTerms[i].saveTo(searchTerm);
|
||||
termOwner.appendTerm(searchTerm);
|
||||
}
|
||||
} catch (ex) {
|
||||
|
||||
dump("** Error: " + ex + "\n");
|
||||
dump("** Error saving element " + i + ": " + ex + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,9 +28,8 @@
|
|||
|
||||
<script src="chrome://messenger/content/searchTermOverlay.js"/>
|
||||
|
||||
<titledbox orient="vertical" id="searchTermListBox" value="&conditions.label;" flex="1">
|
||||
<box orient="vertical" id="searchTermListBox">
|
||||
|
||||
<text class="label" value="&conditionDesc.label;"/>
|
||||
|
||||
<radiogroup class="indent" id="booleanAndGroup" autostretch="never"
|
||||
selectedItem="or" oncommand="booleanChanged(event);">
|
||||
|
@ -89,6 +88,6 @@
|
|||
<button id="more" value="&more.label;" onclick="onMore(event);"/>
|
||||
<button id="less" value="&less.label;" disabled="true" onclick="onLess(event);"/>
|
||||
</box>
|
||||
</titledbox>
|
||||
</box>
|
||||
|
||||
</overlay>
|
||||
|
|
|
@ -29,3 +29,6 @@
|
|||
<!ENTITY normalPriorityCmd.label "Normal">
|
||||
<!ENTITY highPriorityCmd.label "High">
|
||||
<!ENTITY highestPriorityCmd.label "Highest">
|
||||
|
||||
<!ENTITY conditionDesc.label "When new messages arrive in my Inbox, watch for messages that:">
|
||||
<!ENTITY conditions.label "Conditions">
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<!ENTITY logFilterUseCheckbox.label "Log Filter Use">
|
||||
<!ENTITY viewLogButton.label "View Log">
|
||||
<!ENTITY description.label "Description">
|
||||
<!ENTITY filterHeader.label "Filters which are Enabled will be run in the order shown below:">
|
||||
<!ENTITY filterHeader.label "Filters which are enabled will be run in the order shown below.">
|
||||
<!ENTITY runFiltersNow.label "Run Filter(s) Now">
|
||||
<!ENTITY filtersForPrefix.label "Filters for:">
|
||||
<!ENTITY filtersForPostfix.label "">
|
||||
|
|
|
@ -7,3 +7,5 @@
|
|||
<!ENTITY optionsButton.label "Options">
|
||||
<!ENTITY closeButton.label "Close">
|
||||
<!ENTITY searchDialogTitle.label "Search Messages">
|
||||
<!ENTITY conditionDesc.label "Search for messages which:">
|
||||
<!ENTITY conditions.label "Criteria">
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
<!ENTITY more.label "More">
|
||||
<!ENTITY less.label "Fewer">
|
||||
<!ENTITY conditions.label "Conditions">
|
||||
<!ENTITY conditionDesc.label "When new messages arrive in my Inbox, watch for messages that:">
|
||||
<!ENTITY matchAll.label "Match ALL of the following conditions">
|
||||
<!ENTITY matchAny.label "Match at least ONE of the following conditions">
|
||||
<!ENTITY matchAll.label "match ALL of the following conditions">
|
||||
<!ENTITY matchAny.label "match at least ONE of the following conditions">
|
||||
|
|
|
@ -74,7 +74,7 @@ NS_IMETHODIMP
|
|||
nsMsgSearchValueImpl::SetPriority(nsMsgPriorityValue aValue)
|
||||
{
|
||||
NS_ENSURE_TRUE(mValue.attribute == nsMsgSearchAttrib::Priority, NS_ERROR_ILLEGAL_VALUE);
|
||||
aValue = mValue.u.priority;
|
||||
mValue.u.priority = aValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче