1 # -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 # ***** BEGIN LICENSE BLOCK *****
3 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 # The contents of this file are subject to the Mozilla Public License Version
6 # 1.1 (the "License"); you may not use this file except in compliance with
7 # the License. You may obtain a copy of the License at
8 # http://www.mozilla.org/MPL/
10 # Software distributed under the License is distributed on an "AS IS" basis,
11 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 # for the specific language governing rights and limitations under the
15 # The Original Code is the Firefox Preferences System.
17 # The Initial Developer of the Original Code is
19 # Portions created by the Initial Developer are Copyright (C) 2005
20 # the Initial Developer. All Rights Reserved.
23 # Ben Goodger <ben@mozilla.org>
24 # Ehsan Akhgari <ehsan.akhgari@gmail.com>
26 # Alternatively, the contents of this file may be used under the terms of
27 # either the GNU General Public License Version 2 or later (the "GPL"), or
28 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 # in which case the provisions of the GPL or the LGPL are applicable instead
30 # of those above. If you wish to allow use of your version of this file only
31 # under the terms of either the GPL or the LGPL, and not to allow others to
32 # use your version of this file under the terms of the MPL, indicate your
33 # decision by deleting the provisions above and replace them with the notice
34 # and other provisions required by the GPL or the LGPL. If you do not delete
35 # the provisions above, a recipient may use your version of this file under
36 # the terms of any one of the MPL, the GPL or the LGPL.
38 # ***** END LICENSE BLOCK *****
40 const nsICookie = Components.interfaces.nsICookie;
42 var gCookiesWindow = {
43 _cm : Components.classes["@mozilla.org/cookiemanager;1"]
44 .getService(Components.interfaces.nsICookieManager),
45 _ds : Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
46 .getService(Components.interfaces.nsIScriptableDateFormat),
53 var os = Components.classes["@mozilla.org/observer-service;1"]
54 .getService(Components.interfaces.nsIObserverService);
55 os.addObserver(this, "cookie-changed", false);
56 os.addObserver(this, "perm-changed", false);
58 this._bundle = document.getElementById("bundlePreferences");
59 this._tree = document.getElementById("cookiesList");
61 this._populateList(true);
63 document.getElementById("filter").focus();
67 var os = Components.classes["@mozilla.org/observer-service;1"]
68 .getService(Components.interfaces.nsIObserverService);
69 os.removeObserver(this, "cookie-changed");
70 os.removeObserver(this, "perm-changed");
73 _populateList: function (aInitialLoad) {
75 this._tree.treeBoxObject.view = this._view;
78 if (this._view.rowCount > 0)
79 this._tree.view.selection.select(0);
82 if ("arguments" in window &&
83 window.arguments[0] &&
84 window.arguments[0].filterString)
85 this.setFilter(window.arguments[0].filterString);
88 if (document.getElementById("filter").value != "")
95 _cookieEquals: function (aCookieA, aCookieB, aStrippedHost) {
96 return aCookieA.rawHost == aStrippedHost &&
97 aCookieA.name == aCookieB.name &&
98 aCookieA.path == aCookieB.path;
101 observe: function (aCookie, aTopic, aData) {
102 if (aTopic != "cookie-changed")
105 if (aCookie instanceof Components.interfaces.nsICookie) {
106 var strippedHost = this._makeStrippedHost(aCookie.host);
107 if (aData == "changed")
108 this._handleCookieChanged(aCookie, strippedHost);
109 else if (aData == "added")
110 this._handleCookieAdded(aCookie, strippedHost);
112 else if (aData == "cleared") {
114 this._hostOrder = [];
116 var oldRowCount = this._view._rowCount;
117 this._view._rowCount = 0;
118 this._tree.treeBoxObject.rowCountChanged(0, -oldRowCount);
119 this._view.selection.clearSelection();
121 else if (aData == "reload") {
122 // first, clear any existing entries
123 this.observe(aCookie, aTopic, "cleared");
125 // then, reload the list
126 this._populateList(false);
129 // We don't yet handle aData == "deleted" - it's a less common case
130 // and is rather complicated as selection tracking is difficult
133 _handleCookieChanged: function (changedCookie, strippedHost) {
135 var cookieItem = null;
136 if (!this._view._filtered) {
137 for (var i = 0; i < this._hostOrder.length; ++i) { // (var host in this._hosts) {
139 var hostItem = this._hosts[this._hostOrder[i]]; // var hostItem = this._hosts[host];
140 if (this._hostOrder[i] == strippedHost) { // host == strippedHost) {
141 // Host matches, look for the cookie within this Host collection
142 // and update its data
143 for (var j = 0; j < hostItem.cookies.length; ++j) {
145 var currCookie = hostItem.cookies[j];
146 if (this._cookieEquals(currCookie, changedCookie, strippedHost)) {
147 currCookie.value = changedCookie.value;
148 currCookie.isSecure = changedCookie.isSecure;
149 currCookie.isDomain = changedCookie.isDomain;
150 currCookie.expires = changedCookie.expires;
151 cookieItem = currCookie;
156 else if (hostItem.open)
157 rowIndex += hostItem.cookies.length;
161 // Just walk the filter list to find the item. It doesn't matter that
162 // we don't update the main Host collection when we do this, because
163 // when the filter is reset the Host collection is rebuilt anyway.
164 for (rowIndex = 0; rowIndex < this._view._filterSet.length; ++rowIndex) {
165 currCookie = this._view._filterSet[rowIndex];
166 if (this._cookieEquals(currCookie, changedCookie, strippedHost)) {
167 currCookie.value = changedCookie.value;
168 currCookie.isSecure = changedCookie.isSecure;
169 currCookie.isDomain = changedCookie.isDomain;
170 currCookie.expires = changedCookie.expires;
171 cookieItem = currCookie;
177 // Make sure the tree display is up to date...
178 this._tree.treeBoxObject.invalidateRow(rowIndex);
179 // ... and if the cookie is selected, update the displayed metadata too
180 if (cookieItem != null && this._view.selection.currentIndex == rowIndex)
181 this._updateCookieData(cookieItem);
184 _handleCookieAdded: function (changedCookie, strippedHost) {
185 var rowCountImpact = 0;
186 var addedHost = { value: 0 };
187 this._addCookie(strippedHost, changedCookie, addedHost);
188 if (!this._view._filtered) {
189 // The Host collection for this cookie already exists, and it's not open,
190 // so don't increment the rowCountImpact becaues the user is not going to
191 // see the additional rows as they're hidden.
192 if (addedHost.value || this._hosts[strippedHost].open)
196 // We're in search mode, and the cookie being added matches
197 // the search condition, so add it to the list.
198 var c = this._makeCookieObject(strippedHost, changedCookie);
199 if (this._cookieMatchesFilter(c)) {
200 this._view._filterSet.push(this._makeCookieObject(strippedHost, changedCookie));
204 // Now update the tree display at the end (we could/should re run the sort
205 // if any to get the position correct.)
206 var oldRowCount = this._rowCount;
207 this._view._rowCount += rowCountImpact;
208 this._tree.treeBoxObject.rowCountChanged(oldRowCount - 1, rowCountImpact);
210 document.getElementById("removeAllCookies").disabled = this._view._filtered;
221 return this._rowCount;
224 _getItemAtIndex: function (aIndex) {
226 return this._filterSet[aIndex];
229 var count = 0, hostIndex = 0;
231 var cacheIndex = Math.min(this._cacheValid, aIndex);
232 if (cacheIndex > 0) {
233 var cacheItem = this._cacheItems[cacheIndex];
234 start = cacheItem['start'];
235 count = hostIndex = cacheItem['count'];
238 for (var i = start; i < gCookiesWindow._hostOrder.length; ++i) { // var host in gCookiesWindow._hosts) {
239 var currHost = gCookiesWindow._hosts[gCookiesWindow._hostOrder[i]]; // gCookiesWindow._hosts[host];
240 if (!currHost) continue;
245 var cacheEntry = { 'start' : i, 'count' : count };
246 var cacheStart = count;
249 if (count < aIndex && aIndex <= (count + currHost.cookies.length)) {
250 // We are looking for an entry within this host's children,
251 // enumerate them looking for the index.
253 for (var i = 0; i < currHost.cookies.length; ++i) {
254 if (count == aIndex) {
255 var cookie = currHost.cookies[i];
256 cookie.parentIndex = hostIndex;
263 // A host entry was open, but we weren't looking for an index
264 // within that host entry's children, so skip forward over the
265 // entry's children. We need to add one to increment for the
267 count += currHost.cookies.length + 1;
273 for (var j = cacheStart; j < count; j++)
274 this._cacheItems[j] = cacheEntry;
275 this._cacheValid = count - 1;
280 _removeItemAtIndex: function (aIndex, aCount) {
281 var removeCount = aCount === undefined ? 1 : aCount;
282 if (this._filtered) {
283 // remove the cookies from the unfiltered set so that they
284 // don't reappear when the filter is changed. See bug 410863.
285 for (var i = aIndex; i < aIndex + removeCount; ++i) {
286 var item = this._filterSet[i];
287 var parent = gCookiesWindow._hosts[item.rawHost];
288 for (var j = 0; j < parent.cookies.length; ++j) {
289 if (item == parent.cookies[j]) {
290 parent.cookies.splice(j, 1);
295 this._filterSet.splice(aIndex, removeCount);
299 var item = this._getItemAtIndex(aIndex);
301 this._invalidateCache(aIndex - 1);
303 gCookiesWindow._hosts[item.rawHost] = null;
305 var parent = this._getItemAtIndex(item.parentIndex);
306 for (var i = 0; i < parent.cookies.length; ++i) {
307 var cookie = parent.cookies[i];
308 if (item.rawHost == cookie.rawHost &&
309 item.name == cookie.name && item.path == cookie.path)
310 parent.cookies.splice(i, removeCount);
315 _invalidateCache: function (aIndex) {
316 this._cacheValid = Math.min(this._cacheValid, aIndex);
319 getCellText: function (aIndex, aColumn) {
320 if (!this._filtered) {
321 var item = this._getItemAtIndex(aIndex);
324 if (aColumn.id == "domainCol")
326 else if (aColumn.id == "nameCol")
330 if (aColumn.id == "domainCol")
331 return this._filterSet[aIndex].rawHost;
332 else if (aColumn.id == "nameCol")
333 return this._filterSet[aIndex].name;
339 get selection () { return this._selection; },
340 set selection (val) { this._selection = val; return val; },
341 getRowProperties: function (aIndex, aProperties) {},
342 getCellProperties: function (aIndex, aColumn, aProperties) {},
343 getColumnProperties: function (aColumn, aProperties) {},
344 isContainer: function (aIndex) {
345 if (!this._filtered) {
346 var item = this._getItemAtIndex(aIndex);
347 if (!item) return false;
348 return item.container;
352 isContainerOpen: function (aIndex) {
353 if (!this._filtered) {
354 var item = this._getItemAtIndex(aIndex);
355 if (!item) return false;
360 isContainerEmpty: function (aIndex) {
361 if (!this._filtered) {
362 var item = this._getItemAtIndex(aIndex);
363 if (!item) return false;
364 return item.cookies.length == 0;
368 isSeparator: function (aIndex) { return false; },
369 isSorted: function (aIndex) { return false; },
370 canDrop: function (aIndex, aOrientation) { return false; },
371 drop: function (aIndex, aOrientation) {},
372 getParentIndex: function (aIndex) {
373 if (!this._filtered) {
374 var item = this._getItemAtIndex(aIndex);
375 // If an item has no parent index (i.e. it is at the top level) this
376 // function MUST return -1 otherwise we will go into an infinite loop.
377 // Containers are always top level items in the cookies tree, so make
378 // sure to return the appropriate value here.
379 if (!item || item.container) return -1;
380 return item.parentIndex;
384 hasNextSibling: function (aParentIndex, aIndex) {
385 if (!this._filtered) {
386 // |aParentIndex| appears to be bogus, but we can get the real
387 // parent index by getting the entry for |aIndex| and reading the
388 // parentIndex field.
389 // The index of the last item in this host collection is the
390 // index of the parent + the size of the host collection, and
391 // aIndex has a next sibling if it is less than this value.
392 var item = this._getItemAtIndex(aIndex);
394 if (item.container) {
395 for (var i = aIndex + 1; i < this.rowCount; ++i) {
396 var subsequent = this._getItemAtIndex(i);
397 if (subsequent.container)
403 var parent = this._getItemAtIndex(item.parentIndex);
404 if (parent && parent.container)
405 return aIndex < item.parentIndex + parent.cookies.length;
409 return aIndex < this.rowCount - 1;
411 hasPreviousSibling: function (aIndex) {
412 if (!this._filtered) {
413 var item = this._getItemAtIndex(aIndex);
414 if (!item) return false;
415 var parent = this._getItemAtIndex(item.parentIndex);
416 if (parent && parent.container)
417 return aIndex > item.parentIndex + 1;
421 getLevel: function (aIndex) {
422 if (!this._filtered) {
423 var item = this._getItemAtIndex(aIndex);
429 getImageSrc: function (aIndex, aColumn) {},
430 getProgressMode: function (aIndex, aColumn) {},
431 getCellValue: function (aIndex, aColumn) {},
432 setTree: function (aTree) {},
433 toggleOpenState: function (aIndex) {
434 if (!this._filtered) {
435 var item = this._getItemAtIndex(aIndex);
437 this._invalidateCache(aIndex);
438 var multiplier = item.open ? -1 : 1;
439 var delta = multiplier * item.cookies.length;
440 this._rowCount += delta;
441 item.open = !item.open;
442 gCookiesWindow._tree.treeBoxObject.rowCountChanged(aIndex + 1, delta);
443 gCookiesWindow._tree.treeBoxObject.invalidateRow(aIndex);
446 cycleHeader: function (aColumn) {},
447 selectionChanged: function () {},
448 cycleCell: function (aIndex, aColumn) {},
449 isEditable: function (aIndex, aColumn) {
452 isSelectable: function (aIndex, aColumn) {
455 setCellValue: function (aIndex, aColumn, aValue) {},
456 setCellText: function (aIndex, aColumn, aValue) {},
457 performAction: function (aAction) {},
458 performActionOnRow: function (aAction, aIndex) {},
459 performActionOnCell: function (aAction, aindex, aColumn) {}
462 _makeStrippedHost: function (aHost) {
463 var formattedHost = aHost.charAt(0) == "." ? aHost.substring(1, aHost.length) : aHost;
464 return formattedHost.substring(0, 4) == "www." ? formattedHost.substring(4, formattedHost.length) : formattedHost;
467 _addCookie: function (aStrippedHost, aCookie, aHostCount) {
468 if (!(aStrippedHost in this._hosts) || !this._hosts[aStrippedHost]) {
469 this._hosts[aStrippedHost] = { cookies : [],
470 rawHost : aStrippedHost,
474 this._hostOrder.push(aStrippedHost);
478 var c = this._makeCookieObject(aStrippedHost, aCookie);
479 this._hosts[aStrippedHost].cookies.push(c);
482 _makeCookieObject: function (aStrippedHost, aCookie) {
483 var host = aCookie.host;
484 var formattedHost = host.charAt(0) == "." ? host.substring(1, host.length) : host;
485 var c = { name : aCookie.name,
486 value : aCookie.value,
487 isDomain : aCookie.isDomain,
489 rawHost : aStrippedHost,
491 isSecure : aCookie.isSecure,
492 expires : aCookie.expires,
498 _loadCookies: function () {
499 var e = this._cm.enumerator;
500 var hostCount = { value: 0 };
502 this._hostOrder = [];
503 while (e.hasMoreElements()) {
504 var cookie = e.getNext();
505 if (cookie && cookie instanceof Components.interfaces.nsICookie) {
506 var strippedHost = this._makeStrippedHost(cookie.host);
507 this._addCookie(strippedHost, cookie, hostCount);
512 this._view._rowCount = hostCount.value;
515 formatExpiresString: function (aExpires) {
517 var date = new Date(1000 * aExpires);
518 return this._ds.FormatDateTime("", this._ds.dateFormatLong,
519 this._ds.timeFormatSeconds,
527 return this._bundle.getString("expireAtEndOfSession");
530 _updateCookieData: function (aItem) {
531 var seln = this._view.selection;
532 var ids = ["name", "value", "host", "path", "isSecure", "expires"];
535 if (aItem && !aItem.container && seln.count > 0) {
536 properties = { name: aItem.name, value: aItem.value, host: aItem.host,
537 path: aItem.path, expires: this.formatExpiresString(aItem.expires),
538 isDomain: aItem.isDomain ? this._bundle.getString("domainColon")
539 : this._bundle.getString("hostColon"),
540 isSecure: aItem.isSecure ? this._bundle.getString("forSecureOnly")
541 : this._bundle.getString("forAnyConnection") };
542 for (var i = 0; i < ids.length; ++i)
543 document.getElementById(ids[i]).disabled = false;
546 var noneSelected = this._bundle.getString("noCookieSelected");
547 properties = { name: noneSelected, value: noneSelected, host: noneSelected,
548 path: noneSelected, expires: noneSelected,
549 isSecure: noneSelected };
550 for (i = 0; i < ids.length; ++i)
551 document.getElementById(ids[i]).disabled = true;
553 for (var property in properties)
554 document.getElementById(property).value = properties[property];
557 onCookieSelected: function () {
558 var properties, item;
559 var seln = this._tree.view.selection;
560 if (!this._view._filtered)
561 item = this._view._getItemAtIndex(seln.currentIndex);
563 item = this._view._filterSet[seln.currentIndex];
565 this._updateCookieData(item);
567 var rangeCount = seln.getRangeCount();
568 var selectedCookieCount = 0;
569 for (var i = 0; i < rangeCount; ++i) {
570 var min = {}; var max = {};
571 seln.getRangeAt(i, min, max);
572 for (var j = min.value; j <= max.value; ++j) {
573 item = this._view._getItemAtIndex(j);
575 if (item.container && !item.open)
576 selectedCookieCount += item.cookies.length;
577 else if (!item.container)
578 ++selectedCookieCount;
581 var item = this._view._getItemAtIndex(seln.currentIndex);
582 if (item && seln.count == 1 && item.container && item.open)
583 selectedCookieCount += 2;
585 var removeCookie = document.getElementById("removeCookie");
586 var removeCookies = document.getElementById("removeCookies");
587 removeCookie.parentNode.selectedPanel =
588 selectedCookieCount == 1 ? removeCookie : removeCookies;
590 document.getElementById("removeAllCookies").disabled = this._view._filtered;
591 removeCookie.disabled = removeCookies.disabled = !(seln.count > 0);
594 deleteCookie: function () {
596 # // - Selection always moves to *NEXT* adjacent item unless item
597 # // is last child at a given level in which case it moves to *PREVIOUS*
600 # // Selection Cases (Somewhat Complicated)
602 # // 1) Single cookie selected, host has single child
604 # // //// cnn.com ///////////// goksdjf@ ////
607 # // Before SelectedIndex: 1 Before RowCount: 3
608 # // After SelectedIndex: 0 After RowCount: 1
610 # // 2) Host selected, host open
611 # // v goats.com ////////////////////////////
612 # // goats.com sldkkfjl
613 # // goat.scom flksj133
616 # // Before SelectedIndex: 0 Before RowCount: 4
617 # // After SelectedIndex: 0 After RowCount: 1
619 # // 3) Host selected, host closed
620 # // > goats.com ////////////////////////////
623 # // Before SelectedIndex: 0 Before RowCount: 2
624 # // After SelectedIndex: 0 After RowCount: 1
626 # // 4) Single cookie selected, host has many children
628 # // goats.com sldkkfjl
629 # // //// goats.com /////////// flksjl33 ////
632 # // Before SelectedIndex: 2 Before RowCount: 4
633 # // After SelectedIndex: 1 After RowCount: 3
635 # // 5) Single cookie selected, host has many children
637 # // //// goats.com /////////// flksjl33 ////
638 # // goats.com sldkkfjl
641 # // Before SelectedIndex: 1 Before RowCount: 4
642 # // After SelectedIndex: 1 After RowCount: 3
643 var seln = this._view.selection;
644 var tbo = this._tree.treeBoxObject;
646 if (seln.count < 1) return;
648 var nextSelected = 0;
649 var rowCountImpact = 0;
650 var deleteItems = [];
651 if (!this._view._filtered) {
652 var ci = seln.currentIndex;
654 var invalidateRow = -1;
655 var item = this._view._getItemAtIndex(ci);
656 if (item.container) {
657 rowCountImpact -= (item.open ? item.cookies.length : 0) + 1;
658 deleteItems = deleteItems.concat(item.cookies);
659 if (!this._view.hasNextSibling(-1, ci))
661 this._view._removeItemAtIndex(ci);
664 var parent = this._view._getItemAtIndex(item.parentIndex);
666 if (parent.cookies.length == 1) {
668 deleteItems.push(item);
669 if (!this._view.hasNextSibling(-1, ci))
671 if (!this._view.hasNextSibling(-1, item.parentIndex))
673 this._view._removeItemAtIndex(item.parentIndex);
674 invalidateRow = item.parentIndex;
677 deleteItems.push(item);
678 if (!this._view.hasNextSibling(-1, ci))
680 this._view._removeItemAtIndex(ci);
683 this._view._rowCount += rowCountImpact;
684 tbo.rowCountChanged(ci, rowCountImpact);
685 if (invalidateRow != -1)
686 tbo.invalidateRow(invalidateRow);
689 var rangeCount = seln.getRangeCount();
690 for (var i = 0; i < rangeCount; ++i) {
691 var min = {}; var max = {};
692 seln.getRangeAt(i, min, max);
693 nextSelected = min.value;
694 for (var j = min.value; j <= max.value; ++j) {
695 deleteItems.push(this._view._getItemAtIndex(j));
696 if (!this._view.hasNextSibling(-1, max.value))
699 var delta = max.value - min.value + 1;
700 this._view._removeItemAtIndex(min.value, delta);
701 rowCountImpact = -1 * delta;
702 this._view._rowCount += rowCountImpact;
703 tbo.rowCountChanged(min.value, rowCountImpact);
707 var psvc = Components.classes["@mozilla.org/preferences-service;1"]
708 .getService(Components.interfaces.nsIPrefBranch);
709 var blockFutureCookies = false;
710 if (psvc.prefHasUserValue("network.cookie.blockFutureCookies"))
711 blockFutureCookies = psvc.getBoolPref("network.cookie.blockFutureCookies");
712 for (i = 0; i < deleteItems.length; ++i) {
713 var item = deleteItems[i];
714 this._cm.remove(item.host, item.name, item.path, blockFutureCookies);
717 if (nextSelected < 0)
718 seln.clearSelection();
720 seln.select(nextSelected);
725 deleteAllCookies: function () {
726 this._cm.removeAll();
730 onCookieKeyPress: function (aEvent) {
731 if (aEvent.keyCode == 46)
735 _lastSortProperty : "",
736 _lastSortAscending: false,
737 sort: function (aProperty) {
738 var ascending = (aProperty == this._lastSortProperty) ? !this._lastSortAscending : true;
739 // Sort the Non-Filtered Host Collections
740 if (aProperty == "rawHost") {
741 function sortByHost(a, b) {
742 return a.toLowerCase().localeCompare(b.toLowerCase());
744 this._hostOrder.sort(sortByHost);
746 this._hostOrder.reverse();
749 function sortByProperty(a, b) {
750 return a[aProperty].toLowerCase().localeCompare(b[aProperty].toLowerCase());
752 for (var host in this._hosts) {
753 var cookies = this._hosts[host].cookies;
754 cookies.sort(sortByProperty);
758 // Sort the Filtered List, if in Filtered mode
759 if (this._view._filtered) {
760 this._view._filterSet.sort(sortByProperty);
762 this._view._filterSet.reverse();
765 // Adjust the Sort Indicator
766 var domainCol = document.getElementById("domainCol");
767 var nameCol = document.getElementById("nameCol");
768 var sortOrderString = ascending ? "ascending" : "descending";
769 if (aProperty == "rawHost") {
770 domainCol.setAttribute("sortDirection", sortOrderString);
771 nameCol.removeAttribute("sortDirection");
774 nameCol.setAttribute("sortDirection", sortOrderString);
775 domainCol.removeAttribute("sortDirection");
778 this._view._invalidateCache(0);
779 this._view.selection.clearSelection();
780 this._view.selection.select(0);
781 this._tree.treeBoxObject.invalidate();
782 this._tree.treeBoxObject.ensureRowIsVisible(0);
784 this._lastSortAscending = ascending;
785 this._lastSortProperty = aProperty;
788 clearFilter: function () {
789 // Revert to single-select in the tree
790 this._tree.setAttribute("seltype", "single");
792 // Clear the Tree Display
793 this._view._filtered = false;
794 this._view._rowCount = 0;
795 this._tree.treeBoxObject.rowCountChanged(0, -this._view._filterSet.length);
796 this._view._filterSet = [];
798 // Just reload the list to make sure deletions are respected
800 this._tree.treeBoxObject.view = this._view;
802 // Restore sort order
803 var sortby = this._lastSortProperty;
805 this._lastSortAscending = false;
806 this.sort("rawHost");
809 this._lastSortAscending = !this._lastSortAscending;
813 // Restore open state
814 for (var i = 0; i < this._openIndices.length; ++i)
815 this._view.toggleOpenState(this._openIndices[i]);
816 this._openIndices = [];
819 this._view.selection.clearSelection();
820 for (i = 0; i < this._lastSelectedRanges.length; ++i) {
821 var range = this._lastSelectedRanges[i];
822 this._view.selection.rangedSelect(range.min, range.max, true);
824 this._lastSelectedRanges = [];
826 document.getElementById("cookiesIntro").value = this._bundle.getString("cookiesAll");
829 _cookieMatchesFilter: function (aCookie) {
830 return aCookie.rawHost.indexOf(this._view._filterValue) != -1 ||
831 aCookie.name.indexOf(this._view._filterValue) != -1 ||
832 aCookie.value.indexOf(this._view._filterValue) != -1;
835 _filterCookies: function (aFilterValue) {
836 this._view._filterValue = aFilterValue;
838 for (var i = 0; i < gCookiesWindow._hostOrder.length; ++i) { //var host in gCookiesWindow._hosts) {
839 var currHost = gCookiesWindow._hosts[gCookiesWindow._hostOrder[i]]; // gCookiesWindow._hosts[host];
840 if (!currHost) continue;
841 for (var j = 0; j < currHost.cookies.length; ++j) {
842 var cookie = currHost.cookies[j];
843 if (this._cookieMatchesFilter(cookie))
844 cookies.push(cookie);
850 _lastSelectedRanges: [],
852 _saveState: function () {
854 var seln = this._view.selection;
855 this._lastSelectedRanges = [];
856 var rangeCount = seln.getRangeCount();
857 for (var i = 0; i < rangeCount; ++i) {
858 var min = {}; var max = {};
859 seln.getRangeAt(i, min, max);
860 this._lastSelectedRanges.push({ min: min.value, max: max.value });
864 this._openIndices = [];
865 for (i = 0; i < this._view.rowCount; ++i) {
866 var item = this._view._getItemAtIndex(i);
867 if (item && item.container && item.open)
868 this._openIndices.push(i);
872 filter: function () {
873 var filter = document.getElementById("filter").value;
875 gCookiesWindow.clearFilter();
878 var view = gCookiesWindow._view;
879 view._filterSet = gCookiesWindow._filterCookies(filter);
880 if (!view._filtered) {
881 // Save Display Info for the Non-Filtered mode when we first
882 // enter Filtered mode.
883 gCookiesWindow._saveState();
884 view._filtered = true;
886 // Move to multi-select in the tree
887 gCookiesWindow._tree.setAttribute("seltype", "multiple");
890 var oldCount = view._rowCount;
892 gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, -oldCount);
893 // Set up the filtered display
894 view._rowCount = view._filterSet.length;
895 gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, view.rowCount);
897 // if the view is not empty then select the first item
898 if (view.rowCount > 0)
899 view.selection.select(0);
901 document.getElementById("cookiesIntro").value = gCookiesWindow._bundle.getString("cookiesFiltered");
904 setFilter: function (aFilterString) {
905 document.getElementById("filter").value = aFilterString;
909 focusFilterBox: function () {
910 var filter = document.getElementById("filter");