home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / mail.xpi / bin / chrome / messenger.jar / content / messenger / searchTermOverlay.js < prev    next >
Text File  |  2001-09-24  |  15KB  |  455 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  *
  13.  * The Original Code is Mozilla Communicator client code.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape Communications
  16.  * Corporation.  Portions created by Netscape are
  17.  * Copyright (C) 1998 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  * Original Author:
  21.  *   Alec Flett <alecf@netscape.com>
  22.  *
  23.  * Contributor(s):
  24.  *   Seth Spitzer <sspitzer@netscape.com>
  25.  */
  26.  
  27. var gTotalSearchTerms=0;
  28. var gSearchRowContainer;
  29. var gSearchTerms = new Array;
  30. var gSearchRemovedTerms = new Array;
  31. var gSearchScope;
  32. var gSearchLessButton;
  33. var gSearchBooleanRadiogroup;
  34. var gSearchTermTree;
  35.  
  36. //
  37. function searchTermContainer() {}
  38.  
  39. searchTermContainer.prototype = {
  40.     internalSearchTerm : '',
  41.     internalBooleanAnd : '',
  42.  
  43.     // this.searchTerm: the actual nsIMsgSearchTerm object
  44.     get searchTerm() { return this.internalSearchTerm; },
  45.     set searchTerm(val) {
  46.         this.internalSearchTerm = val;
  47.  
  48.         var term = val;
  49.         // val is a nsIMsgSearchTerm
  50.         var searchAttribute=this.searchattribute;
  51.         var searchOperator=this.searchoperator;
  52.         var searchValue=this.searchvalue;
  53.  
  54.         // now reflect all attributes of the searchterm into the widgets
  55.         if (searchAttribute) searchAttribute.value = term.attrib;
  56.         if (searchOperator) searchOperator.value = val.op;
  57.         if (searchValue) searchValue.value = term.value;
  58.  
  59.         this.booleanAnd = val.booleanAnd;
  60.         return val;
  61.     },
  62.  
  63.     // searchscope - just forward to the searchattribute
  64.     get searchScope() {
  65.         if (this.searchattribute)
  66.           return this.searchattribute.searchScope;
  67.         return undefined;
  68.     },
  69.     set searchScope(val) {
  70.         var searchAttribute = this.searchattribute;
  71.         if (searchAttribute) searchAttribute.searchScope=val;
  72.         return val;
  73.     },
  74.  
  75.     saveId: function (element, slot) {
  76.         this[slot] = element.id;
  77.     },
  78.  
  79.     getElement: function (slot) {
  80.         return document.getElementById(this[slot]);
  81.     },
  82.  
  83.     // three well-defined properties:
  84.     // searchattribute, searchoperator, searchvalue
  85.     // the trick going on here is that we're storing the Element's Id,
  86.     // not the element itself, because the XBL object may change out
  87.     // from underneath us
  88.     get searchattribute() { return this.getElement("internalSearchAttributeId"); },
  89.     set searchattribute(val) {
  90.         this.saveId(val, "internalSearchAttributeId");
  91.         return val;
  92.     },
  93.     get searchoperator() { return this.getElement("internalSearchOperatorId"); },
  94.     set searchoperator(val) {
  95.         this.saveId(val, "internalSearchOperatorId");
  96.         return val;
  97.     },
  98.     get searchvalue() { return this.getElement("internalSearchValueId"); },
  99.     set searchvalue(val) {
  100.         this.saveId(val, "internalSearchValueId");
  101.         return val;
  102.     },
  103.  
  104.     booleanNodes: null,
  105.     stringBundle: document.getElementById("bundle_search"),
  106.     get booleanAnd() { return this.internalBooleanAnd; },
  107.     set booleanAnd(val) {
  108.         // whenever you set this, all nodes in booleanNodes
  109.         // are updated to reflect the string
  110.  
  111.         if (this.internalBooleanAnd == val) return val;
  112.         this.internalBooleanAnd = val;
  113.  
  114.         var booleanNodes = this.booleanNodes;
  115.         if (!booleanNodes) return val;
  116.  
  117.         var stringBundle = this.stringBundle;
  118.         var andString = val ? "And" : "Or";
  119.         for (var i=0; i<booleanNodes.length; i++) {
  120.             try {
  121.                 var staticString =
  122.                     stringBundle.getString("search" + andString + i);
  123.                 if (staticString && staticString.length>0)
  124.                     booleanNodes[i].setAttribute("label", staticString);
  125.             } catch (ex) { /* no error, means string not found */}
  126.         }
  127.         return val;
  128.     },
  129.  
  130.     save: function () {
  131.         var searchTerm = this.searchTerm;
  132.         searchTerm.attrib = this.searchattribute.value;
  133.         searchTerm.op = this.searchoperator.value;
  134.         if (this.searchvalue.value)
  135.             this.searchvalue.save();
  136.         else
  137.             this.searchvalue.saveTo(searchTerm.value);
  138.         searchTerm.value = this.searchvalue.value;
  139.         searchTerm.booleanAnd = this.booleanAnd;
  140.     },
  141.     // if you have a search term element with no search term
  142.     saveTo: function(searchTerm) {
  143.         this.internalSearchTerm = searchTerm;
  144.         this.save();
  145.     }
  146. }
  147.  
  148. var nsIMsgSearchTerm = Components.interfaces.nsIMsgSearchTerm;
  149.  
  150. function initializeSearchWidgets() {
  151.     gSearchBooleanRadiogroup = document.getElementById("booleanAndGroup");
  152.     gSearchRowContainer = document.getElementById("searchTermList");
  153.     gSearchTermTree = document.getElementById("searchTermTree");
  154.     gSearchLessButton = document.getElementById("less");
  155.     if (!gSearchLessButton)
  156.         dump("I couldn't find less button!");
  157. }
  158.  
  159. function initializeBooleanWidgets() 
  160. {
  161.     var booleanAnd = true;
  162.     // get the boolean value from the first term
  163.     var firstTerm = gSearchTerms[0].searchTerm;
  164.     if (firstTerm)
  165.         booleanAnd = firstTerm.booleanAnd;
  166.  
  167.     // target radio items have value="and" or value="or"
  168.     var targetValue = "or";
  169.     if (booleanAnd) targetValue = "and";
  170.  
  171.     var targetElement = gSearchBooleanRadiogroup.getElementsByAttribute("value", targetValue)[0];
  172.  
  173.     gSearchBooleanRadiogroup.selectedItem = targetElement;
  174. }
  175.  
  176. function initializeSearchRows(scope, searchTerms)
  177. {
  178.     gTotalSearchTerms = searchTerms.Count();
  179.     for (var i=0; i<gTotalSearchTerms; i++) {
  180.         var searchTerm = searchTerms.QueryElementAt(i, nsIMsgSearchTerm);
  181.         createSearchRow(i, scope, searchTerm);
  182.     }
  183.     initializeBooleanWidgets();
  184. }
  185.  
  186. function scrollToLastSearchTerm(index)
  187. {
  188.     if (index > 0)
  189.       gSearchTermTree.ensureIndexIsVisible(index-1);
  190. }
  191.  
  192. function onMore(event)
  193. {
  194.     if(gTotalSearchTerms==1)
  195.       gSearchLessButton .removeAttribute("disabled", "false");
  196.     createSearchRow(gTotalSearchTerms++, gSearchScope, null);
  197.     // the user just added a term, so scroll to it
  198.     scrollToLastSearchTerm(gTotalSearchTerms);
  199. }
  200.  
  201. function onLess(event)
  202. {
  203.     if (gTotalSearchTerms>1)
  204.         removeSearchRow(--gTotalSearchTerms);
  205.     if (gTotalSearchTerms==1)
  206.         gSearchLessButton .setAttribute("disabled", "true");
  207.  
  208.     // the user removed a term, so scroll to the bottom so they are aware of it
  209.     scrollToLastSearchTerm(gTotalSearchTerms);
  210. }
  211.  
  212. // set scope on all visible searchattribute tags
  213. function setSearchScope(scope) {
  214.     gSearchScope = scope;
  215.     for (var i=0; i<gSearchTerms.length; i++) {
  216.         gSearchTerms[i].obj.searchattribute.searchScope = scope;
  217.         gSearchTerms[i].scope = scope;
  218.     }
  219. }
  220.  
  221. function booleanChanged(event) {
  222.     // when boolean changes, we have to update all the attributes on the
  223.     // search terms
  224.  
  225.     var newBoolValue =
  226.         (event.target.getAttribute("value") == "and") ? true : false;
  227.     for (var i=0; i<gSearchTerms.length; i++) {
  228.         var searchTerm = gSearchTerms[i].obj;
  229.         searchTerm.booleanAnd = newBoolValue;
  230.     }
  231. }
  232.  
  233.  
  234. function createSearchRow(index, scope, searchTerm)
  235. {
  236.     var searchAttr = document.createElement("searchattribute");
  237.     var searchOp = document.createElement("searchoperator");
  238.     var searchVal = document.createElement("searchvalue");
  239.  
  240.     // now set up ids:
  241.     searchAttr.id = "searchAttr" + index;
  242.     searchOp.id  = "searchOp" + index;
  243.     searchVal.id = "searchVal" + index;
  244.  
  245.     searchAttr.setAttribute("for", searchOp.id + "," + searchVal.id);
  246.  
  247.     var rowdata = new Array(null, searchAttr,
  248.                             null, searchOp,
  249.                             null, searchVal,
  250.                             null);
  251.     var searchrow = constructRow(rowdata);
  252.     searchrow.id = "searchRow" + index;
  253.  
  254.     var searchTermObj = new searchTermContainer;
  255.  
  256.     gSearchTerms[gSearchTerms.length] = {obj:searchTermObj, scope:scope, searchTerm:searchTerm, initialized:false};
  257.  
  258.     searchTermObj.searchattribute = searchAttr;
  259.     searchTermObj.searchoperator = searchOp;
  260.     searchTermObj.searchvalue = searchVal;
  261.  
  262.     // now invalidate the newly created items because they've been inserted
  263.     // into the document, and XBL bindings will be inserted in their place
  264.     //searchAttr = searchOp = searchVal = undefined;
  265.  
  266.     // and/or string handling:
  267.     // this is scary - basically we want to take every other
  268.     // treecell, (note the i+=2) which will be a text label,
  269.     // and set the searchTermObj's
  270.     // booleanNodes to that
  271.     var stringNodes = new Array;
  272.     var treecells = searchrow.firstChild.childNodes;
  273.     var j=0;
  274.     for (var i=0; i<treecells.length; i+=2) {
  275.         stringNodes[j++] = treecells[i];
  276.     }
  277.     searchTermObj.booleanNodes = stringNodes;
  278.  
  279.     gSearchRowContainer.appendChild(searchrow);
  280. }
  281.  
  282. function initializeTermFromId(id)
  283. {
  284.     // id is of the form searchAttr<n>
  285.     // strlen("searchAttr") == 10
  286.     // turn searchAttr<n> -> <n>
  287.     var index = parseInt(id.slice(10)); 
  288.     initializeTermFromIndex(index)
  289. }
  290.  
  291. function initializeTermFromIndex(index)
  292. {
  293.     var searchTermObj = gSearchTerms[index].obj;
  294.  
  295.     searchTermObj.searchScope = gSearchTerms[index].scope;
  296.     // the search term will initialize the searchTerm element, including
  297.     // .booleanAnd
  298.     if (gSearchTerms[index].searchTerm)
  299.         searchTermObj.searchTerm = gSearchTerms[index].searchTerm;
  300.     // here, we don't have a searchTerm, so it's probably a new element -
  301.     // we'll initialize the .booleanAnd from the existing setting in
  302.     // the UI
  303.     else
  304.         searchTermObj.booleanAnd = getBooleanAnd();
  305.  
  306.     gSearchTerms[index].initialized = true;
  307. }
  308.  
  309. // creates a <treerow> using the array treeCellChildren as
  310. // the children of each treecell
  311. function constructRow(treeCellChildren)
  312. {
  313.     var treeitem = document.createElement("treeitem");
  314.     var row = document.createElement("treerow");
  315.     for (var i = 0; i<treeCellChildren.length; i++) {
  316.       var treecell = document.createElement("treecell");
  317.  
  318.       // it's ok to have empty cells
  319.       if (treeCellChildren[i]) {
  320.           treecell.setAttribute("allowevents", "true");
  321.           treeCellChildren[i].setAttribute("flex", "1");
  322.           treecell.appendChild(treeCellChildren[i]);
  323.       }
  324.       row.appendChild(treecell);
  325.     }
  326.     treeitem.appendChild(row);
  327.     return treeitem;
  328. }
  329.  
  330. function removeSearchRow(index)
  331. {
  332.     var searchTermObj = gSearchTerms[index].obj;
  333.     if (!searchTermObj) {
  334.         return;
  335.     }
  336.  
  337.     // if it is an existing (but offscreen) term,
  338.     // make sure it is initialized before we remove it.
  339.     if (!gSearchTerms[index].searchTerm && !gSearchTerms[index].initialized)
  340.         initializeTermFromIndex(index);
  341.  
  342.     // need to remove row from tree, so walk upwards from the
  343.     // searchattribute to find the first <treeitem>
  344.     var treeItemRow = searchTermObj.searchattribute;
  345.     while (treeItemRow) {
  346.         if (treeItemRow.localName == "treeitem") break;
  347.         treeItemRow = treeItemRow.parentNode;
  348.     }
  349.  
  350.     if (!treeItemRow) {
  351.         dump("Error: couldn't find parent treeitem!\n");
  352.         return;
  353.     }
  354.  
  355.  
  356.     if (searchTermObj.searchTerm) {
  357.         gSearchRemovedTerms[gSearchRemovedTerms.length] = searchTermObj.searchTerm;
  358.     } else {
  359.         //dump("That wasn't real. ignoring \n");
  360.     }
  361.  
  362.     treeItemRow.parentNode.removeChild(treeItemRow);
  363.     // remove it from the list of terms - XXX this does it?
  364.     // remove the last element
  365.     gSearchTerms.length--;
  366. }
  367.  
  368. function getBooleanAnd()
  369. {
  370.     if (gSearchBooleanRadiogroup.selectedItem)
  371.         return (gSearchBooleanRadiogroup.selectedItem.getAttribute("value") == "and") ? true : false;
  372.  
  373.     // default to false
  374.     return false;
  375. }
  376.  
  377. // save the search terms from the UI back to the actual search terms
  378. // searchTerms: nsISupportsArray of terms
  379. // termOwner:   object which can contain and create the terms
  380. //              (will be unnecessary if we just make terms creatable
  381. //               via XPCOM)
  382. function saveSearchTerms(searchTerms, termOwner)
  383. {
  384.     var i;
  385.     for (i = 0; i<gSearchTerms.length; i++) {
  386.         try {
  387.             var searchTerm = gSearchTerms[i].obj.searchTerm;
  388.  
  389.             // the term might be an offscreen one we haven't initialized yet
  390.             // if so, don't bother saving it.
  391.             if (!searchTerm && !gSearchTerms[i].initialized) {
  392.                 // is an existing term, but not initialize, so skip saving
  393.                 continue;
  394.             }
  395.  
  396.             if (searchTerm)
  397.                 gSearchTerms[i].obj.save();
  398.             else {
  399.                 // need to create a new searchTerm, and somehow save it to that
  400.                 searchTerm = termOwner.createTerm();
  401.                 gSearchTerms[i].obj.saveTo(searchTerm);
  402.                 termOwner.appendTerm(searchTerm);
  403.             }
  404.         } catch (ex) {
  405.             dump("** Error saving element " + i + ": " + ex + "\n");
  406.         }
  407.     }
  408.  
  409.     // now remove the queued elements
  410.     for (i=0; i<gSearchRemovedTerms.length; i++) {
  411.         // this is so nasty, we have to iterate through
  412.         // because GetIndexOf is acting funny
  413.         var searchTermSupports =
  414.             gSearchRemovedTerms[i].QueryInterface(Components.interfaces.nsISupports);
  415.         searchTerms.RemoveElement(searchTermSupports);
  416.     }
  417.  
  418. }
  419.  
  420. function onReset(event)
  421. {
  422.     while (gTotalSearchTerms>0)
  423.         removeSearchRow(--gTotalSearchTerms);
  424.     onMore(event);
  425. }
  426.  
  427. function convertPRTimeToString(tm)
  428. {
  429.   var time = new Date();
  430.   // PRTime is in microseconds, Javascript time is in seconds
  431.   // so divide by 1000 when converting
  432.   time.setTime(tm / 1000);
  433.   
  434.   return convertDateToString(time);
  435. }
  436.  
  437. function convertDateToString(time)
  438. {
  439.   var dateStr = time.getMonth() + 1;
  440.   dateStr += "/";
  441.   dateStr += time.getDate();
  442.   dateStr += "/";
  443.   dateStr += 1900 + time.getYear();
  444.   return dateStr;
  445. }
  446.  
  447. function convertStringToPRTime(str)
  448. {
  449.   var time = new Date();
  450.   time.setTime(Date.parse(str));
  451.   // Javascript time is in seconds, PRTime is in microseconds
  452.   // so multiply by 1000 when converting
  453.   return (time.getTime() * 1000);
  454. }
  455.