home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 October / maximum-cd-2009-10.iso / DiscContents / Firefox Setup 3.5.exe / nonlocalized / chrome / browser.jar / content / browser / preferences / cookies.js < prev    next >
Encoding:
Text File  |  2009-06-24  |  28.7 KB  |  858 lines

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