home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / firefox-3.0.14 / chrome / browser.jar / content / browser / preferences / cookies.js < prev    next >
Encoding:
Text File  |  2008-01-25  |  29.1 KB  |  859 lines

  1. //@line 39 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/components/preferences/cookies.js"
  2.  
  3. const nsICookie = Components.interfaces.nsICookie;
  4.  
  5. var gCookiesWindow = {
  6.   _cm               : Components.classes["@mozilla.org/cookiemanager;1"]
  7.                                 .getService(Components.interfaces.nsICookieManager),
  8.   _ds               : Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
  9.                                 .getService(Components.interfaces.nsIScriptableDateFormat),
  10.   _hosts            : {},
  11.   _hostOrder        : [],
  12.   _tree             : null,
  13.   _bundle           : null,
  14.  
  15.   init: function ()
  16.   {
  17.     var os = Components.classes["@mozilla.org/observer-service;1"]
  18.                        .getService(Components.interfaces.nsIObserverService);
  19.     os.addObserver(this, "cookie-changed", false);
  20.     os.addObserver(this, "perm-changed", false);
  21.     
  22.     this._bundle = document.getElementById("bundlePreferences");
  23.     this._tree = document.getElementById("cookiesList");
  24.     
  25.     this._loadCookies();
  26.     this._tree.treeBoxObject.view = this._view;
  27.     this.sort("rawHost");
  28.     if (this._view.rowCount > 0) 
  29.       this._tree.view.selection.select(0);
  30.  
  31.     if ("arguments" in window && window.arguments[0] &&
  32.         window.arguments[0].filterString)
  33.       this.setFilter(window.arguments[0].filterString);
  34.     
  35.     this._saveState();
  36.       
  37.     document.getElementById("filter").focus();
  38.   },
  39.   
  40.   uninit: function ()
  41.   {
  42.     var os = Components.classes["@mozilla.org/observer-service;1"]
  43.                        .getService(Components.interfaces.nsIObserverService);
  44.     os.removeObserver(this, "cookie-changed");
  45.     os.removeObserver(this, "perm-changed");
  46.   },
  47.   
  48.   _cookieEquals: function (aCookieA, aCookieB, aStrippedHost)
  49.   {
  50.     return aCookieA.rawHost == aStrippedHost &&
  51.            aCookieA.name == aCookieB.name &&
  52.            aCookieA.path == aCookieB.path;
  53.   },
  54.   
  55.   observe: function (aCookie, aTopic, aData) 
  56.   {
  57.     if (aTopic != "cookie-changed")
  58.       return;
  59.     
  60.     if (aCookie instanceof Components.interfaces.nsICookie) {
  61.       var strippedHost = this._makeStrippedHost(aCookie.host);
  62.       if (aData == "changed")
  63.         this._handleCookieChanged(aCookie, strippedHost);
  64.       else if (aData == "added")
  65.         this._handleCookieAdded(aCookie, strippedHost);
  66.     }
  67.     else if (aData == "cleared") {
  68.       this._hosts = {};
  69.       this._hostOrder = [];
  70.     
  71.       var oldRowCount = this._view._rowCount;
  72.       this._view._rowCount = 0;
  73.       this._tree.treeBoxObject.rowCountChanged(0, -oldRowCount);
  74.       this._view.selection.clearSelection();
  75.     }
  76.     
  77.     // We don't yet handle aData == "deleted" - it's a less common case
  78.     // and is rather complicated as selection tracking is difficult
  79.   },
  80.   
  81.   _handleCookieChanged: function (changedCookie, strippedHost) 
  82.   {
  83.     var rowIndex = 0;
  84.     var cookieItem = null;
  85.     if (!this._view._filtered) {
  86.       for (var i = 0; i < this._hostOrder.length; ++i) { // (var host in this._hosts) {
  87.         ++rowIndex;
  88.         var hostItem = this._hosts[this._hostOrder[i]]; // var hostItem = this._hosts[host];
  89.         if (this._hostOrder[i] == strippedHost) { // host == strippedHost) {
  90.           // Host matches, look for the cookie within this Host collection
  91.           // and update its data
  92.           for (var j = 0; j < hostItem.cookies.length; ++j) {
  93.             ++rowIndex;
  94.             var currCookie = hostItem.cookies[j];
  95.             if (this._cookieEquals(currCookie, changedCookie, strippedHost)) {
  96.               currCookie.value    = changedCookie.value;
  97.               currCookie.isSecure = changedCookie.isSecure;
  98.               currCookie.isDomain = changedCookie.isDomain;
  99.               currCookie.expires  = changedCookie.expires;
  100.               cookieItem = currCookie;
  101.               break;
  102.             }
  103.           }
  104.         }
  105.         else if (hostItem.open)
  106.           rowIndex += hostItem.cookies.length;
  107.       }
  108.     }
  109.     else {
  110.       // Just walk the filter list to find the item. It doesn't matter that
  111.       // we don't update the main Host collection when we do this, because
  112.       // when the filter is reset the Host collection is rebuilt anyway.
  113.       for (rowIndex = 0; rowIndex < this._view._filterSet.length; ++rowIndex) {
  114.         currCookie = this._view._filterSet[rowIndex];
  115.         if (this._cookieEquals(currCookie, changedCookie, strippedHost)) {
  116.           currCookie.value    = changedCookie.value;
  117.           currCookie.isSecure = changedCookie.isSecure;
  118.           currCookie.isDomain = changedCookie.isDomain;
  119.           currCookie.expires  = changedCookie.expires;
  120.           cookieItem = currCookie;
  121.           break;
  122.         }
  123.       }
  124.     }
  125.     
  126.     // Make sure the tree display is up to date...
  127.     this._tree.treeBoxObject.invalidateRow(rowIndex);
  128.     // ... and if the cookie is selected, update the displayed metadata too
  129.     if (cookieItem != null && this._view.selection.currentIndex == rowIndex)
  130.       this._updateCookieData(cookieItem);  
  131.   },
  132.   
  133.   _handleCookieAdded: function (changedCookie, strippedHost)
  134.   {
  135.     var rowCountImpact = 0;
  136.     var addedHost = { value: 0 };
  137.     this._addCookie(strippedHost, changedCookie, addedHost);
  138.     if (!this._view._filtered) {
  139.       // The Host collection for this cookie already exists, and it's not open, 
  140.       // so don't increment the rowCountImpact becaues the user is not going to
  141.       // see the additional rows as they're hidden. 
  142.       if (addedHost.value || this._hosts[strippedHost].open)
  143.         ++rowCountImpact;
  144.     }
  145.     else {
  146.       // We're in search mode, and the cookie being added matches
  147.       // the search condition, so add it to the list. 
  148.       var c = this._makeCookieObject(strippedHost, changedCookie);
  149.       if (this._cookieMatchesFilter(c)) {
  150.         this._view._filterSet.push(this._makeCookieObject(strippedHost, changedCookie));
  151.         ++rowCountImpact;
  152.       }
  153.     }
  154.     // Now update the tree display at the end (we could/should re run the sort
  155.     // if any to get the position correct.)
  156.     var oldRowCount = this._rowCount;
  157.     this._view._rowCount += rowCountImpact;
  158.     this._tree.treeBoxObject.rowCountChanged(oldRowCount - 1, rowCountImpact);
  159.  
  160.     document.getElementById("removeAllCookies").disabled = this._view._filtered;
  161.   },
  162.   
  163.   _view: {
  164.     _filtered   : false,
  165.     _filterSet  : [],
  166.     _filterValue: "",
  167.     _rowCount   : 0,
  168.     _cacheValid : 0,
  169.     _cacheItems : [],
  170.     get rowCount() 
  171.     { 
  172.       return this._rowCount; 
  173.     },
  174.     
  175.     _getItemAtIndex: function (aIndex)
  176.     {
  177.       if (this._filtered)
  178.         return this._filterSet[aIndex];
  179.  
  180.       var start = 0;
  181.       var count = 0, hostIndex = 0;
  182.  
  183.       var cacheIndex = Math.min(this._cacheValid, aIndex);
  184.       if (cacheIndex > 0) {
  185.         var cacheItem = this._cacheItems[cacheIndex];
  186.         start = cacheItem['start'];
  187.         count = hostIndex = cacheItem['count'];
  188.       }
  189.  
  190.       for (var i = start; i < gCookiesWindow._hostOrder.length; ++i) { // var host in gCookiesWindow._hosts) {
  191.         var currHost = gCookiesWindow._hosts[gCookiesWindow._hostOrder[i]]; // gCookiesWindow._hosts[host];
  192.         if (!currHost) continue;
  193.         if (count == aIndex)
  194.           return currHost;
  195.         hostIndex = count;
  196.  
  197.         var cacheEntry = { 'start' : i, 'count' : count };
  198.         var cacheStart = count;
  199.  
  200.         if (currHost.open) {
  201.           if (count < aIndex && aIndex <= (count + currHost.cookies.length)) {
  202.             // We are looking for an entry within this host's children, 
  203.             // enumerate them looking for the index. 
  204.             ++count;
  205.             for (var i = 0; i < currHost.cookies.length; ++i) {
  206.               if (count == aIndex) {
  207.                 var cookie = currHost.cookies[i];
  208.                 cookie.parentIndex = hostIndex;
  209.                 return cookie;
  210.               }
  211.               ++count;
  212.             }
  213.           }
  214.           else {
  215.             // A host entry was open, but we weren't looking for an index
  216.             // within that host entry's children, so skip forward over the
  217.             // entry's children. We need to add one to increment for the
  218.             // host value too. 
  219.             count += currHost.cookies.length + 1;
  220.           }
  221.         }
  222.         else
  223.           ++count;
  224.  
  225.         for (var j = cacheStart; j < count; j++)
  226.           this._cacheItems[j] = cacheEntry;
  227.         this._cacheValid = count - 1;
  228.       }
  229.       return null;
  230.     },
  231.  
  232.     _removeItemAtIndex: function (aIndex, aCount)
  233.     {
  234.       var removeCount = aCount === undefined ? 1 : aCount;
  235.       if (this._filtered) {
  236.         // remove the cookies from the unfiltered set so that they
  237.         // don't reappear when the filter is changed. See bug 410863.
  238.         for (var i = aIndex; i < aIndex + removeCount; ++i) {
  239.           var item = this._filterSet[i];
  240.           var parent = gCookiesWindow._hosts[item.rawHost];
  241.           for (var j = 0; j < parent.cookies.length; ++j) {
  242.             if (item == parent.cookies[j]) {
  243.               parent.cookies.splice(j, 1);
  244.               break;
  245.             }
  246.           }
  247.         }
  248.         this._filterSet.splice(aIndex, removeCount);
  249.         return;
  250.       }
  251.       
  252.       var item = this._getItemAtIndex(aIndex);
  253.       if (!item) return;
  254.       this._invalidateCache(aIndex - 1);
  255.       if (item.container)
  256.         gCookiesWindow._hosts[item.rawHost] = null;
  257.       else {
  258.         var parent = this._getItemAtIndex(item.parentIndex);
  259.         for (var i = 0; i < parent.cookies.length; ++i) {
  260.           var cookie = parent.cookies[i];
  261.           if (item.rawHost == cookie.rawHost &&
  262.               item.name == cookie.name && item.path == cookie.path)
  263.             parent.cookies.splice(i, removeCount);
  264.         }
  265.       }
  266.     },
  267.  
  268.     _invalidateCache: function (aIndex)
  269.     {
  270.       this._cacheValid = Math.min(this._cacheValid, aIndex);
  271.     },
  272.     
  273.     getCellText: function (aIndex, aColumn)
  274.     {
  275.       if (!this._filtered) {
  276.         var item = this._getItemAtIndex(aIndex);
  277.         if (!item) 
  278.           return "";
  279.         if (aColumn.id == "domainCol")
  280.           return item.rawHost;
  281.         else if (aColumn.id == "nameCol")
  282.           return item.name;
  283.       }
  284.       else {
  285.         if (aColumn.id == "domainCol")
  286.           return this._filterSet[aIndex].rawHost;
  287.         else if (aColumn.id == "nameCol")
  288.           return this._filterSet[aIndex].name;
  289.       }
  290.       return "";
  291.     },
  292.  
  293.     _selection: null, 
  294.     get selection () { return this._selection; },
  295.     set selection (val) { this._selection = val; return val; },
  296.     getRowProperties: function (aIndex, aProperties) {},
  297.     getCellProperties: function (aIndex, aColumn, aProperties) {},
  298.     getColumnProperties: function (aColumn, aProperties) {},
  299.     isContainer: function (aIndex)
  300.     {
  301.       if (!this._filtered) {
  302.         var item = this._getItemAtIndex(aIndex);
  303.         if (!item) return false;
  304.         return item.container;
  305.       }
  306.       return false;
  307.     },
  308.     isContainerOpen: function (aIndex) 
  309.     { 
  310.       if (!this._filtered) {
  311.         var item = this._getItemAtIndex(aIndex);
  312.         if (!item) return false;
  313.         return item.open;
  314.       }
  315.       return false;
  316.     },
  317.     isContainerEmpty: function (aIndex) 
  318.     { 
  319.       if (!this._filtered) {
  320.         var item = this._getItemAtIndex(aIndex);
  321.         if (!item) return false;
  322.         return item.cookies.length == 0;
  323.       }
  324.       return false;
  325.     },
  326.     isSeparator: function (aIndex) { return false; },    
  327.     isSorted: function (aIndex) { return false; },    
  328.     canDrop: function (aIndex, aOrientation) { return false; },    
  329.     drop: function (aIndex, aOrientation) {},    
  330.     getParentIndex: function (aIndex) 
  331.     {
  332.       if (!this._filtered) {
  333.         var item = this._getItemAtIndex(aIndex);
  334.         // If an item has no parent index (i.e. it is at the top level) this 
  335.         // function MUST return -1 otherwise we will go into an infinite loop. 
  336.         // Containers are always top level items in the cookies tree, so make 
  337.         // sure to return the appropriate value here.        
  338.         if (!item || item.container) return -1;
  339.         return item.parentIndex;
  340.       }
  341.       return -1;
  342.     },    
  343.     hasNextSibling: function (aParentIndex, aIndex) 
  344.     { 
  345.       if (!this._filtered) {
  346.         // |aParentIndex| appears to be bogus, but we can get the real
  347.         // parent index by getting the entry for |aIndex| and reading the
  348.         // parentIndex field. 
  349.         // The index of the last item in this host collection is the 
  350.         // index of the parent + the size of the host collection, and
  351.         // aIndex has a next sibling if it is less than this value.
  352.         var item = this._getItemAtIndex(aIndex);
  353.         if (item) {
  354.           if (item.container) {
  355.             for (var i = aIndex + 1; i < this.rowCount; ++i) {
  356.               var subsequent = this._getItemAtIndex(i);
  357.               if (subsequent.container) 
  358.                 return true;
  359.             }
  360.             return false;
  361.           }
  362.           else {
  363.             var parent = this._getItemAtIndex(item.parentIndex);
  364.             if (parent && parent.container)
  365.               return aIndex < item.parentIndex + parent.cookies.length;
  366.           }
  367.         }
  368.       }
  369.       return aIndex < this.rowCount - 1;
  370.     },
  371.     hasPreviousSibling: function (aIndex)
  372.     {
  373.       if (!this._filtered) {
  374.         var item = this._getItemAtIndex(aIndex);
  375.         if (!item) return false;
  376.         var parent = this._getItemAtIndex(item.parentIndex);
  377.         if (parent && parent.container)
  378.           return aIndex > item.parentIndex + 1;
  379.       }
  380.       return aIndex > 0;
  381.     },
  382.     getLevel: function (aIndex) 
  383.     {
  384.       if (!this._filtered) {
  385.         var item = this._getItemAtIndex(aIndex);
  386.         if (!item) return 0;
  387.         return item.level;
  388.       }
  389.       return 0;
  390.     },
  391.     getImageSrc: function (aIndex, aColumn) {},    
  392.     getProgressMode: function (aIndex, aColumn) {},    
  393.     getCellValue: function (aIndex, aColumn) {},
  394.     setTree: function (aTree) {},    
  395.     toggleOpenState: function (aIndex) 
  396.     {
  397.       if (!this._filtered) {
  398.         var item = this._getItemAtIndex(aIndex);
  399.         if (!item) return;
  400.         this._invalidateCache(aIndex);
  401.         var multiplier = item.open ? -1 : 1;
  402.         var delta = multiplier * item.cookies.length;
  403.         this._rowCount += delta;
  404.         item.open = !item.open;
  405.         gCookiesWindow._tree.treeBoxObject.rowCountChanged(aIndex + 1, delta);
  406.         gCookiesWindow._tree.treeBoxObject.invalidateRow(aIndex);
  407.       }
  408.     },    
  409.     cycleHeader: function (aColumn) {},    
  410.     selectionChanged: function () {},    
  411.     cycleCell: function (aIndex, aColumn) {},    
  412.     isEditable: function (aIndex, aColumn) 
  413.     { 
  414.       return false; 
  415.     },
  416.     isSelectable: function (aIndex, aColumn) 
  417.     { 
  418.       return false; 
  419.     },
  420.     setCellValue: function (aIndex, aColumn, aValue) {},    
  421.     setCellText: function (aIndex, aColumn, aValue) {},    
  422.     performAction: function (aAction) {},  
  423.     performActionOnRow: function (aAction, aIndex) {},    
  424.     performActionOnCell: function (aAction, aindex, aColumn) {}
  425.   },
  426.   
  427.   _makeStrippedHost: function (aHost)
  428.   {
  429.     var formattedHost = aHost.charAt(0) == "." ? aHost.substring(1, aHost.length) : aHost;
  430.     return formattedHost.substring(0, 4) == "www." ? formattedHost.substring(4, formattedHost.length) : formattedHost;
  431.   },
  432.   
  433.   _addCookie: function (aStrippedHost, aCookie, aHostCount)
  434.   {
  435.     if (!(aStrippedHost in this._hosts) || !this._hosts[aStrippedHost]) {
  436.       this._hosts[aStrippedHost] = { cookies   : [], 
  437.                                      rawHost   : aStrippedHost,
  438.                                      level     : 0,
  439.                                      open      : false,
  440.                                      container : true };
  441.       this._hostOrder.push(aStrippedHost);
  442.       ++aHostCount.value;
  443.     }
  444.     
  445.     var c = this._makeCookieObject(aStrippedHost, aCookie);    
  446.     this._hosts[aStrippedHost].cookies.push(c);
  447.   },
  448.   
  449.   _makeCookieObject: function (aStrippedHost, aCookie)
  450.   {
  451.     var host = aCookie.host;
  452.     var formattedHost = host.charAt(0) == "." ? host.substring(1, host.length) : host;
  453.     var c = { name        : aCookie.name,
  454.               value       : aCookie.value,
  455.               isDomain    : aCookie.isDomain,
  456.               host        : aCookie.host,
  457.               rawHost     : aStrippedHost,
  458.               path        : aCookie.path,
  459.               isSecure    : aCookie.isSecure,
  460.               expires     : aCookie.expires,
  461.               level       : 1,
  462.               container   : false };
  463.     return c;
  464.   },
  465.   
  466.   _loadCookies: function () 
  467.   {
  468.     var e = this._cm.enumerator;
  469.     var hostCount = { value: 0 };
  470.     this._hosts = {};
  471.     this._hostOrder = [];
  472.     while (e.hasMoreElements()) {
  473.       var cookie = e.getNext();
  474.       if (cookie && cookie instanceof Components.interfaces.nsICookie) {
  475.         var strippedHost = this._makeStrippedHost(cookie.host);
  476.         this._addCookie(strippedHost, cookie, hostCount);
  477.       }
  478.       else
  479.         break;
  480.     }
  481.     this._view._rowCount = hostCount.value;
  482.   },
  483.   
  484.   formatExpiresString: function (aExpires) 
  485.   {
  486.     if (aExpires) {
  487.       var date = new Date(1000 * aExpires);
  488.       return this._ds.FormatDateTime("", this._ds.dateFormatLong,
  489.                                      this._ds.timeFormatSeconds,
  490.                                      date.getFullYear(),
  491.                                      date.getMonth() + 1,
  492.                                      date.getDate(),
  493.                                      date.getHours(),
  494.                                      date.getMinutes(),
  495.                                      date.getSeconds());
  496.     }
  497.     return this._bundle.getString("AtEndOfSession");
  498.   },
  499.   
  500.   _updateCookieData: function (aItem)
  501.   {
  502.     var seln = this._view.selection;
  503.     var ids = ["name", "value", "host", "path", "isSecure", "expires"];
  504.     var properties;
  505.     
  506.     if (aItem && !aItem.container && seln.count > 0) {
  507.       properties = { name: aItem.name, value: aItem.value, host: aItem.host,
  508.                      path: aItem.path, expires: this.formatExpiresString(aItem.expires),
  509.                      isDomain: aItem.isDomain ? this._bundle.getString("domainColon")
  510.                                               : this._bundle.getString("hostColon"),
  511.                      isSecure: aItem.isSecure ? this._bundle.getString("forSecureOnly")
  512.                                               : this._bundle.getString("forAnyConnection") };
  513.       for (var i = 0; i < ids.length; ++i)
  514.         document.getElementById(ids[i]).disabled = false;
  515.     }
  516.     else {
  517.       var noneSelected = this._bundle.getString("noCookieSelected");
  518.       properties = { name: noneSelected, value: noneSelected, host: noneSelected,
  519.                      path: noneSelected, expires: noneSelected, 
  520.                      isSecure: noneSelected };
  521.       for (i = 0; i < ids.length; ++i)
  522.         document.getElementById(ids[i]).disabled = true;
  523.     }
  524.     for (var property in properties)
  525.       document.getElementById(property).value = properties[property];
  526.   },
  527.   
  528.   onCookieSelected: function () 
  529.   {
  530.     var properties, item;
  531.     var seln = this._tree.view.selection;
  532.     if (!this._view._filtered) 
  533.       item = this._view._getItemAtIndex(seln.currentIndex);
  534.     else
  535.       item = this._view._filterSet[seln.currentIndex];
  536.       
  537.     this._updateCookieData(item);
  538.     
  539.     var rangeCount = seln.getRangeCount();
  540.     var selectedCookieCount = 0;
  541.     for (var i = 0; i < rangeCount; ++i) {
  542.       var min = {}; var max = {};
  543.       seln.getRangeAt(i, min, max);
  544.       for (var j = min.value; j <= max.value; ++j) {
  545.         item = this._view._getItemAtIndex(j);
  546.         if (!item) continue;
  547.         if (item.container && !item.open)
  548.           selectedCookieCount += item.cookies.length;
  549.         else if (!item.container)
  550.           ++selectedCookieCount;
  551.       }
  552.     }
  553.     var item = this._view._getItemAtIndex(seln.currentIndex);
  554.     if (item && seln.count == 1 && item.container && item.open)
  555.       selectedCookieCount += 2;
  556.       
  557.     var stringKey = selectedCookieCount == 1 ? "removeCookie" : "removeCookies";
  558.     document.getElementById("removeCookie").label = this._bundle.getString(stringKey);
  559.     
  560.     document.getElementById("removeAllCookies").disabled = this._view._filtered;
  561.     document.getElementById("removeCookie").disabled = !(seln.count > 0);
  562.   },
  563.   
  564.   deleteCookie: function () 
  565.   { 
  566. //@line 651 "/build/buildd/firefox-3.0-3.0.14+build2+nobinonly/build-tree/mozilla/browser/components/preferences/cookies.js"
  567.     var seln = this._view.selection;
  568.     var tbo = this._tree.treeBoxObject;
  569.     
  570.     if (seln.count < 1) return;
  571.     
  572.     var nextSelected = 0;
  573.     var rowCountImpact = 0;
  574.     var deleteItems = [];
  575.     if (!this._view._filtered) {
  576.       var ci = seln.currentIndex;
  577.       nextSelected = ci;
  578.       var invalidateRow = -1;
  579.       var item = this._view._getItemAtIndex(ci);
  580.       if (item.container) {
  581.         rowCountImpact -= (item.open ? item.cookies.length : 0) + 1;
  582.         deleteItems = deleteItems.concat(item.cookies);
  583.         if (!this._view.hasNextSibling(-1, ci)) 
  584.           --nextSelected;
  585.         this._view._removeItemAtIndex(ci);
  586.       }
  587.       else {
  588.         var parent = this._view._getItemAtIndex(item.parentIndex);
  589.         --rowCountImpact;
  590.         if (parent.cookies.length == 1) {
  591.           --rowCountImpact;
  592.           deleteItems.push(item);
  593.           if (!this._view.hasNextSibling(-1, ci))
  594.             --nextSelected;
  595.           if (!this._view.hasNextSibling(-1, item.parentIndex)) 
  596.             --nextSelected;
  597.           this._view._removeItemAtIndex(item.parentIndex);
  598.           invalidateRow = item.parentIndex;
  599.         }
  600.         else {
  601.           deleteItems.push(item);
  602.           if (!this._view.hasNextSibling(-1, ci)) 
  603.             --nextSelected;
  604.           this._view._removeItemAtIndex(ci);
  605.         }
  606.       }
  607.       this._view._rowCount += rowCountImpact;
  608.       tbo.rowCountChanged(ci, rowCountImpact);
  609.       if (invalidateRow != -1)
  610.         tbo.invalidateRow(invalidateRow);
  611.     }
  612.     else {
  613.       var rangeCount = seln.getRangeCount();
  614.       for (var i = 0; i < rangeCount; ++i) {
  615.         var min = {}; var max = {};
  616.         seln.getRangeAt(i, min, max);
  617.         nextSelected = min.value;        
  618.         for (var j = min.value; j <= max.value; ++j) {
  619.           deleteItems.push(this._view._getItemAtIndex(j));
  620.           if (!this._view.hasNextSibling(-1, max.value))
  621.             --nextSelected;
  622.         }
  623.         var delta = max.value - min.value + 1;
  624.         this._view._removeItemAtIndex(min.value, delta);
  625.         rowCountImpact = -1 * delta;
  626.         this._view._rowCount += rowCountImpact;
  627.         tbo.rowCountChanged(min.value, rowCountImpact);
  628.       }
  629.     }
  630.     
  631.     var psvc = Components.classes["@mozilla.org/preferences-service;1"]
  632.                          .getService(Components.interfaces.nsIPrefBranch);
  633.     var blockFutureCookies = false;
  634.     if (psvc.prefHasUserValue("network.cookie.blockFutureCookies"))
  635.       blockFutureCookies = psvc.getBoolPref("network.cookie.blockFutureCookies");
  636.     for (i = 0; i < deleteItems.length; ++i) {
  637.       var item = deleteItems[i];
  638.       this._cm.remove(item.host, item.name, item.path, blockFutureCookies);
  639.     }
  640.     
  641.     if (nextSelected < 0)
  642.       seln.clearSelection();
  643.     else {
  644.       seln.select(nextSelected);
  645.       this._tree.focus();
  646.     }
  647.   },
  648.   
  649.   deleteAllCookies: function ()
  650.   {
  651.     this._cm.removeAll();
  652.     this._tree.focus();
  653.   },
  654.   
  655.   onCookieKeyPress: function (aEvent)
  656.   {
  657.     if (aEvent.keyCode == 46)
  658.       this.deleteCookie();
  659.   },
  660.   
  661.   _lastSortProperty : "",
  662.   _lastSortAscending: false,
  663.   sort: function (aProperty) 
  664.   {
  665.     var ascending = (aProperty == this._lastSortProperty) ? !this._lastSortAscending : true;
  666.     // Sort the Non-Filtered Host Collections
  667.     if (aProperty == "rawHost") {
  668.       function sortByHost(a, b)
  669.       {
  670.         return a.toLowerCase().localeCompare(b.toLowerCase());
  671.       }
  672.       this._hostOrder.sort(sortByHost);
  673.       if (!ascending)
  674.         this._hostOrder.reverse();
  675.     }
  676.         
  677.     function sortByProperty(a, b) 
  678.     {
  679.       return a[aProperty].toLowerCase().localeCompare(b[aProperty].toLowerCase());
  680.     }
  681.     for (var host in this._hosts) {
  682.       var cookies = this._hosts[host].cookies;
  683.       cookies.sort(sortByProperty);
  684.       if (!ascending)
  685.         cookies.reverse();
  686.     }
  687.     // Sort the Filtered List, if in Filtered mode
  688.     if (this._view._filtered) { 
  689.       this._view._filterSet.sort(sortByProperty);
  690.       if (!ascending)
  691.         this._view._filterSet.reverse();
  692.     }
  693.  
  694.     this._view._invalidateCache(0);
  695.     this._view.selection.clearSelection();
  696.     this._view.selection.select(0);
  697.     this._tree.treeBoxObject.invalidate();
  698.     this._tree.treeBoxObject.ensureRowIsVisible(0);
  699.  
  700.     this._lastSortAscending = ascending;
  701.     this._lastSortProperty = aProperty;
  702.   },
  703.   
  704.   clearFilter: function ()
  705.   {
  706.     // Revert to single-select in the tree
  707.     this._tree.setAttribute("seltype", "single");
  708.     
  709.     // Clear the Filter and the Tree Display
  710.     document.getElementById("filter").value = "";
  711.     this._view._filtered = false;
  712.     this._view._rowCount = 0;
  713.     this._tree.treeBoxObject.rowCountChanged(0, -this._view._filterSet.length);
  714.     this._view._filterSet = [];
  715.  
  716.     // Just reload the list to make sure deletions are respected
  717.     this._loadCookies();
  718.     this._tree.treeBoxObject.view = this._view;
  719.     
  720.     // Restore sort order
  721.     var sortby = this._lastSortProperty;
  722.     if (sortby == "") {
  723.       this._lastSortAscending = false;
  724.       this.sort("rawHost");
  725.     }
  726.     else {
  727.       this._lastSortAscending = !this._lastSortAscending;
  728.       this.sort(sortby);
  729.     }
  730.  
  731.     // Restore open state
  732.     for (var i = 0; i < this._openIndices.length; ++i)
  733.       this._view.toggleOpenState(this._openIndices[i]);
  734.     this._openIndices = [];
  735.     
  736.     // Restore selection
  737.     this._view.selection.clearSelection();
  738.     for (i = 0; i < this._lastSelectedRanges.length; ++i) {
  739.       var range = this._lastSelectedRanges[i];
  740.       this._view.selection.rangedSelect(range.min, range.max, true);
  741.     }
  742.     this._lastSelectedRanges = [];
  743.  
  744.     document.getElementById("cookiesIntro").value = this._bundle.getString("cookiesAll");
  745.     document.getElementById("clearFilter").disabled = true;
  746.     document.getElementById("filter").focus();
  747.   },
  748.   
  749.   _cookieMatchesFilter: function (aCookie)
  750.   {
  751.     return aCookie.rawHost.indexOf(this._view._filterValue) != -1 ||
  752.            aCookie.name.indexOf(this._view._filterValue) != -1 || 
  753.            aCookie.value.indexOf(this._view._filterValue) != -1;
  754.   },
  755.   
  756.   _filterCookies: function (aFilterValue)
  757.   {
  758.     this._view._filterValue = aFilterValue;
  759.     var cookies = [];
  760.     for (var i = 0; i < gCookiesWindow._hostOrder.length; ++i) { //var host in gCookiesWindow._hosts) {
  761.       var currHost = gCookiesWindow._hosts[gCookiesWindow._hostOrder[i]]; // gCookiesWindow._hosts[host];
  762.       if (!currHost) continue;
  763.       for (var j = 0; j < currHost.cookies.length; ++j) {
  764.         var cookie = currHost.cookies[j];
  765.         if (this._cookieMatchesFilter(cookie))
  766.           cookies.push(cookie);
  767.       }
  768.     }
  769.     return cookies;
  770.   },
  771.   
  772.   _lastSelectedRanges: [],
  773.   _openIndices: [],
  774.   _saveState: function ()
  775.   {
  776.     // Save selection
  777.     var seln = this._view.selection;
  778.     this._lastSelectedRanges = [];
  779.     var rangeCount = seln.getRangeCount();
  780.     for (var i = 0; i < rangeCount; ++i) {
  781.       var min = {}; var max = {};
  782.       seln.getRangeAt(i, min, max);
  783.       this._lastSelectedRanges.push({ min: min.value, max: max.value });
  784.     }
  785.   
  786.     // Save open states
  787.     this._openIndices = [];
  788.     for (i = 0; i < this._view.rowCount; ++i) {
  789.       var item = this._view._getItemAtIndex(i);
  790.       if (item && item.container && item.open)
  791.         this._openIndices.push(i);
  792.     }
  793.   },
  794.   
  795.   _filterTimeout: -1,
  796.   onFilterInput: function ()
  797.   {
  798.     if (this._filterTimeout != -1)
  799.       clearTimeout(this._filterTimeout);
  800.    
  801.     function filterCookies()
  802.     {
  803.       var filter = document.getElementById("filter").value;
  804.       if (filter == "") {
  805.         gCookiesWindow.clearFilter();
  806.         return;
  807.       }        
  808.       var view = gCookiesWindow._view;
  809.       view._filterSet = gCookiesWindow._filterCookies(filter);
  810.       if (!view._filtered) {
  811.         // Save Display Info for the Non-Filtered mode when we first
  812.         // enter Filtered mode. 
  813.         gCookiesWindow._saveState();
  814.         view._filtered = true;
  815.       }
  816.       // Move to multi-select in the tree
  817.       gCookiesWindow._tree.setAttribute("seltype", "multiple");
  818.       
  819.       // Clear the display
  820.       var oldCount = view._rowCount;
  821.       view._rowCount = 0;
  822.       gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, -oldCount);
  823.       // Set up the filtered display
  824.       view._rowCount = view._filterSet.length;
  825.       gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, view.rowCount);
  826.       
  827.       // if the view is not empty then select the first item
  828.       if (view.rowCount > 0)
  829.         view.selection.select(0);
  830.  
  831.       document.getElementById("cookiesIntro").value = gCookiesWindow._bundle.getString("cookiesFiltered");
  832.       document.getElementById("clearFilter").disabled = false;
  833.     }
  834.     window.filterCookies = filterCookies;
  835.     this._filterTimeout = setTimeout("filterCookies();", 500);
  836.   },
  837.   
  838.   onFilterKeyPress: function (aEvent)
  839.   {
  840.     var filter = document.getElementById("filter").value;
  841.     if (aEvent.keyCode == 27 && filter != "") // ESC key
  842.       this.clearFilter();
  843.   },
  844.   
  845.   focusFilterBox: function ()
  846.   { 
  847.     var filter = document.getElementById("filter");
  848.     filter.focus();
  849.     filter.select();
  850.   },
  851.  
  852.   setFilter: function (aFilterString)
  853.   {
  854.     document.getElementById("filter").value = aFilterString;
  855.     this.onFilterInput();
  856.   }
  857. };
  858.  
  859.