browser/components/preferences/cookies.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial