cookies.js
Go to the documentation of this file.
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
4 #
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/
9 #
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
13 # License.
14 #
15 # The Original Code is the Firefox Preferences System.
16 #
17 # The Initial Developer of the Original Code is
18 # Ben Goodger.
19 # Portions created by the Initial Developer are Copyright (C) 2005
20 # the Initial Developer. All Rights Reserved.
21 #
22 # Contributor(s):
23 # Ben Goodger <ben@mozilla.org>
24 # Ehsan Akhgari <ehsan.akhgari@gmail.com>
25 #
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.
37 #
38 # ***** END LICENSE BLOCK *****
39 
40 const nsICookie = Components.interfaces.nsICookie;
41 
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),
47  _hosts : {},
48  _hostOrder : [],
49  _tree : null,
50  _bundle : null,
51 
52  init: function () {
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);
57 
58  this._bundle = document.getElementById("bundlePreferences");
59  this._tree = document.getElementById("cookiesList");
60 
61  this._populateList(true);
62 
63  document.getElementById("filter").focus();
64  },
65 
66  uninit: function () {
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");
71  },
72 
73  _populateList: function (aInitialLoad) {
74  this._loadCookies();
75  this._tree.treeBoxObject.view = this._view;
76  if (aInitialLoad)
77  this.sort("rawHost");
78  if (this._view.rowCount > 0)
79  this._tree.view.selection.select(0);
80 
81  if (aInitialLoad) {
82  if ("arguments" in window &&
83  window.arguments[0] &&
84  window.arguments[0].filterString)
85  this.setFilter(window.arguments[0].filterString);
86  }
87  else {
88  if (document.getElementById("filter").value != "")
89  this.filter();
90  }
91 
92  this._saveState();
93  },
94 
95  _cookieEquals: function (aCookieA, aCookieB, aStrippedHost) {
96  return aCookieA.rawHost == aStrippedHost &&
97  aCookieA.name == aCookieB.name &&
98  aCookieA.path == aCookieB.path;
99  },
100 
101  observe: function (aCookie, aTopic, aData) {
102  if (aTopic != "cookie-changed")
103  return;
104 
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);
111  }
112  else if (aData == "cleared") {
113  this._hosts = {};
114  this._hostOrder = [];
115 
116  var oldRowCount = this._view._rowCount;
117  this._view._rowCount = 0;
118  this._tree.treeBoxObject.rowCountChanged(0, -oldRowCount);
119  this._view.selection.clearSelection();
120  }
121  else if (aData == "reload") {
122  // first, clear any existing entries
123  this.observe(aCookie, aTopic, "cleared");
124 
125  // then, reload the list
126  this._populateList(false);
127  }
128 
129  // We don't yet handle aData == "deleted" - it's a less common case
130  // and is rather complicated as selection tracking is difficult
131  },
132 
133  _handleCookieChanged: function (changedCookie, strippedHost) {
134  var rowIndex = 0;
135  var cookieItem = null;
136  if (!this._view._filtered) {
137  for (var i = 0; i < this._hostOrder.length; ++i) { // (var host in this._hosts) {
138  ++rowIndex;
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) {
144  ++rowIndex;
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;
152  break;
153  }
154  }
155  }
156  else if (hostItem.open)
157  rowIndex += hostItem.cookies.length;
158  }
159  }
160  else {
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;
172  break;
173  }
174  }
175  }
176 
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);
182  },
183 
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)
193  ++rowCountImpact;
194  }
195  else {
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));
201  ++rowCountImpact;
202  }
203  }
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);
209 
210  document.getElementById("removeAllCookies").disabled = this._view._filtered;
211  },
212 
213  _view: {
214  _filtered : false,
215  _filterSet : [],
216  _filterValue: "",
217  _rowCount : 0,
218  _cacheValid : 0,
219  _cacheItems : [],
220  get rowCount() {
221  return this._rowCount;
222  },
223 
224  _getItemAtIndex: function (aIndex) {
225  if (this._filtered)
226  return this._filterSet[aIndex];
227 
228  var start = 0;
229  var count = 0, hostIndex = 0;
230 
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'];
236  }
237 
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;
241  if (count == aIndex)
242  return currHost;
243  hostIndex = count;
244 
245  var cacheEntry = { 'start' : i, 'count' : count };
246  var cacheStart = count;
247 
248  if (currHost.open) {
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.
252  ++count;
253  for (var i = 0; i < currHost.cookies.length; ++i) {
254  if (count == aIndex) {
255  var cookie = currHost.cookies[i];
256  cookie.parentIndex = hostIndex;
257  return cookie;
258  }
259  ++count;
260  }
261  }
262  else {
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
266  // host value too.
267  count += currHost.cookies.length + 1;
268  }
269  }
270  else
271  ++count;
272 
273  for (var j = cacheStart; j < count; j++)
274  this._cacheItems[j] = cacheEntry;
275  this._cacheValid = count - 1;
276  }
277  return null;
278  },
279 
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);
291  break;
292  }
293  }
294  }
295  this._filterSet.splice(aIndex, removeCount);
296  return;
297  }
298 
299  var item = this._getItemAtIndex(aIndex);
300  if (!item) return;
301  this._invalidateCache(aIndex - 1);
302  if (item.container)
303  gCookiesWindow._hosts[item.rawHost] = null;
304  else {
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);
311  }
312  }
313  },
314 
315  _invalidateCache: function (aIndex) {
316  this._cacheValid = Math.min(this._cacheValid, aIndex);
317  },
318 
319  getCellText: function (aIndex, aColumn) {
320  if (!this._filtered) {
321  var item = this._getItemAtIndex(aIndex);
322  if (!item)
323  return "";
324  if (aColumn.id == "domainCol")
325  return item.rawHost;
326  else if (aColumn.id == "nameCol")
327  return item.name;
328  }
329  else {
330  if (aColumn.id == "domainCol")
331  return this._filterSet[aIndex].rawHost;
332  else if (aColumn.id == "nameCol")
333  return this._filterSet[aIndex].name;
334  }
335  return "";
336  },
337 
338  _selection: null,
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;
349  }
350  return false;
351  },
352  isContainerOpen: function (aIndex) {
353  if (!this._filtered) {
354  var item = this._getItemAtIndex(aIndex);
355  if (!item) return false;
356  return item.open;
357  }
358  return false;
359  },
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;
365  }
366  return false;
367  },
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;
381  }
382  return -1;
383  },
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);
393  if (item) {
394  if (item.container) {
395  for (var i = aIndex + 1; i < this.rowCount; ++i) {
396  var subsequent = this._getItemAtIndex(i);
397  if (subsequent.container)
398  return true;
399  }
400  return false;
401  }
402  else {
403  var parent = this._getItemAtIndex(item.parentIndex);
404  if (parent && parent.container)
405  return aIndex < item.parentIndex + parent.cookies.length;
406  }
407  }
408  }
409  return aIndex < this.rowCount - 1;
410  },
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;
418  }
419  return aIndex > 0;
420  },
421  getLevel: function (aIndex) {
422  if (!this._filtered) {
423  var item = this._getItemAtIndex(aIndex);
424  if (!item) return 0;
425  return item.level;
426  }
427  return 0;
428  },
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);
436  if (!item) return;
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);
444  }
445  },
446  cycleHeader: function (aColumn) {},
447  selectionChanged: function () {},
448  cycleCell: function (aIndex, aColumn) {},
449  isEditable: function (aIndex, aColumn) {
450  return false;
451  },
452  isSelectable: function (aIndex, aColumn) {
453  return false;
454  },
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) {}
460  },
461 
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;
465  },
466 
467  _addCookie: function (aStrippedHost, aCookie, aHostCount) {
468  if (!(aStrippedHost in this._hosts) || !this._hosts[aStrippedHost]) {
469  this._hosts[aStrippedHost] = { cookies : [],
470  rawHost : aStrippedHost,
471  level : 0,
472  open : false,
473  container : true };
474  this._hostOrder.push(aStrippedHost);
475  ++aHostCount.value;
476  }
477 
478  var c = this._makeCookieObject(aStrippedHost, aCookie);
479  this._hosts[aStrippedHost].cookies.push(c);
480  },
481 
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,
488  host : aCookie.host,
489  rawHost : aStrippedHost,
490  path : aCookie.path,
491  isSecure : aCookie.isSecure,
492  expires : aCookie.expires,
493  level : 1,
494  container : false };
495  return c;
496  },
497 
498  _loadCookies: function () {
499  var e = this._cm.enumerator;
500  var hostCount = { value: 0 };
501  this._hosts = {};
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);
508  }
509  else
510  break;
511  }
512  this._view._rowCount = hostCount.value;
513  },
514 
515  formatExpiresString: function (aExpires) {
516  if (aExpires) {
517  var date = new Date(1000 * aExpires);
518  return this._ds.FormatDateTime("", this._ds.dateFormatLong,
519  this._ds.timeFormatSeconds,
520  date.getFullYear(),
521  date.getMonth() + 1,
522  date.getDate(),
523  date.getHours(),
524  date.getMinutes(),
525  date.getSeconds());
526  }
527  return this._bundle.getString("expireAtEndOfSession");
528  },
529 
530  _updateCookieData: function (aItem) {
531  var seln = this._view.selection;
532  var ids = ["name", "value", "host", "path", "isSecure", "expires"];
533  var properties;
534 
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;
544  }
545  else {
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;
552  }
553  for (var property in properties)
554  document.getElementById(property).value = properties[property];
555  },
556 
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);
562  else
563  item = this._view._filterSet[seln.currentIndex];
564 
565  this._updateCookieData(item);
566 
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);
574  if (!item) continue;
575  if (item.container && !item.open)
576  selectedCookieCount += item.cookies.length;
577  else if (!item.container)
578  ++selectedCookieCount;
579  }
580  }
581  var item = this._view._getItemAtIndex(seln.currentIndex);
582  if (item && seln.count == 1 && item.container && item.open)
583  selectedCookieCount += 2;
584 
585  var stringKey = selectedCookieCount == 1 ? "removeCookie" : "removeCookies";
586  document.getElementById("removeCookie").label = this._bundle.getString(stringKey);
587 
588  document.getElementById("removeAllCookies").disabled = this._view._filtered;
589  document.getElementById("removeCookie").disabled = !(seln.count > 0);
590  },
591 
592  deleteCookie: function () {
593 # // Selection Notes
594 # // - Selection always moves to *NEXT* adjacent item unless item
595 # // is last child at a given level in which case it moves to *PREVIOUS*
596 # // item
597 # //
598 # // Selection Cases (Somewhat Complicated)
599 # //
600 # // 1) Single cookie selected, host has single child
601 # // v cnn.com
602 # //
603 # // > atwola.com
604 # //
605 # // Before SelectedIndex: 1 Before RowCount: 3
606 # // After SelectedIndex: 0 After RowCount: 1
607 # //
608 # // 2) Host selected, host open
609 # // v goats.com
610 # // goats.com sldkkfjl
611 # // goat.scom flksj133
612 # // > atwola.com
613 # //
614 # // Before SelectedIndex: 0 Before RowCount: 4
615 # // After SelectedIndex: 0 After RowCount: 1
616 # //
617 # // 3) Host selected, host closed
618 # // > goats.com
619 # // > atwola.com
620 # //
621 # // Before SelectedIndex: 0 Before RowCount: 2
622 # // After SelectedIndex: 0 After RowCount: 1
623 # //
624 # // 4) Single cookie selected, host has many children
625 # // v goats.com
626 # // goats.com sldkkfjl
627 # //
628 # // > atwola.com
629 # //
630 # // Before SelectedIndex: 2 Before RowCount: 4
631 # // After SelectedIndex: 1 After RowCount: 3
632 # //
633 # // 5) Single cookie selected, host has many children
634 # // v goats.com
635 # //
636 # // goats.com sldkkfjl
637 # // > atwola.com
638 # //
639 # // Before SelectedIndex: 1 Before RowCount: 4
640 # // After SelectedIndex: 1 After RowCount: 3
641  var seln = this._view.selection;
642  var tbo = this._tree.treeBoxObject;
643 
644  if (seln.count < 1) return;
645 
646  var nextSelected = 0;
647  var rowCountImpact = 0;
648  var deleteItems = [];
649  if (!this._view._filtered) {
650  var ci = seln.currentIndex;
651  nextSelected = ci;
652  var invalidateRow = -1;
653  var item = this._view._getItemAtIndex(ci);
654  if (item.container) {
655  rowCountImpact -= (item.open ? item.cookies.length : 0) + 1;
656  deleteItems = deleteItems.concat(item.cookies);
657  if (!this._view.hasNextSibling(-1, ci))
658  --nextSelected;
659  this._view._removeItemAtIndex(ci);
660  }
661  else {
662  var parent = this._view._getItemAtIndex(item.parentIndex);
663  --rowCountImpact;
664  if (parent.cookies.length == 1) {
665  --rowCountImpact;
666  deleteItems.push(item);
667  if (!this._view.hasNextSibling(-1, ci))
668  --nextSelected;
669  if (!this._view.hasNextSibling(-1, item.parentIndex))
670  --nextSelected;
671  this._view._removeItemAtIndex(item.parentIndex);
672  invalidateRow = item.parentIndex;
673  }
674  else {
675  deleteItems.push(item);
676  if (!this._view.hasNextSibling(-1, ci))
677  --nextSelected;
678  this._view._removeItemAtIndex(ci);
679  }
680  }
681  this._view._rowCount += rowCountImpact;
682  tbo.rowCountChanged(ci, rowCountImpact);
683  if (invalidateRow != -1)
684  tbo.invalidateRow(invalidateRow);
685  }
686  else {
687  var rangeCount = seln.getRangeCount();
688  for (var i = 0; i < rangeCount; ++i) {
689  var min = {}; var max = {};
690  seln.getRangeAt(i, min, max);
691  nextSelected = min.value;
692  for (var j = min.value; j <= max.value; ++j) {
693  deleteItems.push(this._view._getItemAtIndex(j));
694  if (!this._view.hasNextSibling(-1, max.value))
695  --nextSelected;
696  }
697  var delta = max.value - min.value + 1;
698  this._view._removeItemAtIndex(min.value, delta);
699  rowCountImpact = -1 * delta;
700  this._view._rowCount += rowCountImpact;
701  tbo.rowCountChanged(min.value, rowCountImpact);
702  }
703  }
704 
705  var psvc = Components.classes["@mozilla.org/preferences-service;1"]
706  .getService(Components.interfaces.nsIPrefBranch);
707  var blockFutureCookies = false;
708  if (psvc.prefHasUserValue("network.cookie.blockFutureCookies"))
709  blockFutureCookies = psvc.getBoolPref("network.cookie.blockFutureCookies");
710  for (i = 0; i < deleteItems.length; ++i) {
711  var item = deleteItems[i];
712  this._cm.remove(item.host, item.name, item.path, blockFutureCookies);
713  }
714 
715  if (nextSelected < 0)
716  seln.clearSelection();
717  else {
718  seln.select(nextSelected);
719  this._tree.focus();
720  }
721  },
722 
723  deleteAllCookies: function () {
724  this._cm.removeAll();
725  this._tree.focus();
726  },
727 
728  onCookieKeyPress: function (aEvent) {
729  if (aEvent.keyCode == 46)
730  this.deleteCookie();
731  },
732 
733  _lastSortProperty : "",
734  _lastSortAscending: false,
735  sort: function (aProperty) {
736  var ascending = (aProperty == this._lastSortProperty) ? !this._lastSortAscending : true;
737  // Sort the Non-Filtered Host Collections
738  if (aProperty == "rawHost") {
739  function sortByHost(a, b) {
740  return a.toLowerCase().localeCompare(b.toLowerCase());
741  }
742  this._hostOrder.sort(sortByHost);
743  if (!ascending)
744  this._hostOrder.reverse();
745  }
746 
747  function sortByProperty(a, b) {
748  return a[aProperty].toLowerCase().localeCompare(b[aProperty].toLowerCase());
749  }
750  for (var host in this._hosts) {
751  var cookies = this._hosts[host].cookies;
752  cookies.sort(sortByProperty);
753  if (!ascending)
754  cookies.reverse();
755  }
756  // Sort the Filtered List, if in Filtered mode
757  if (this._view._filtered) {
758  this._view._filterSet.sort(sortByProperty);
759  if (!ascending)
760  this._view._filterSet.reverse();
761  }
762 
763  this._view._invalidateCache(0);
764  this._view.selection.clearSelection();
765  this._view.selection.select(0);
766  this._tree.treeBoxObject.invalidate();
767  this._tree.treeBoxObject.ensureRowIsVisible(0);
768 
769  this._lastSortAscending = ascending;
770  this._lastSortProperty = aProperty;
771  },
772 
773  clearFilter: function () {
774  // Revert to single-select in the tree
775  this._tree.setAttribute("seltype", "single");
776 
777  // Clear the Tree Display
778  this._view._filtered = false;
779  this._view._rowCount = 0;
780  this._tree.treeBoxObject.rowCountChanged(0, -this._view._filterSet.length);
781  this._view._filterSet = [];
782 
783  // Just reload the list to make sure deletions are respected
784  this._loadCookies();
785  this._tree.treeBoxObject.view = this._view;
786 
787  // Restore sort order
788  var sortby = this._lastSortProperty;
789  if (sortby == "") {
790  this._lastSortAscending = false;
791  this.sort("rawHost");
792  }
793  else {
794  this._lastSortAscending = !this._lastSortAscending;
795  this.sort(sortby);
796  }
797 
798  // Restore open state
799  for (var i = 0; i < this._openIndices.length; ++i)
800  this._view.toggleOpenState(this._openIndices[i]);
801  this._openIndices = [];
802 
803  // Restore selection
804  this._view.selection.clearSelection();
805  for (i = 0; i < this._lastSelectedRanges.length; ++i) {
806  var range = this._lastSelectedRanges[i];
807  this._view.selection.rangedSelect(range.min, range.max, true);
808  }
809  this._lastSelectedRanges = [];
810 
811  document.getElementById("cookiesIntro").value = this._bundle.getString("cookiesAll");
812  },
813 
814  _cookieMatchesFilter: function (aCookie) {
815  return aCookie.rawHost.indexOf(this._view._filterValue) != -1 ||
816  aCookie.name.indexOf(this._view._filterValue) != -1 ||
817  aCookie.value.indexOf(this._view._filterValue) != -1;
818  },
819 
820  _filterCookies: function (aFilterValue) {
821  this._view._filterValue = aFilterValue;
822  var cookies = [];
823  for (var i = 0; i < gCookiesWindow._hostOrder.length; ++i) { //var host in gCookiesWindow._hosts) {
824  var currHost = gCookiesWindow._hosts[gCookiesWindow._hostOrder[i]]; // gCookiesWindow._hosts[host];
825  if (!currHost) continue;
826  for (var j = 0; j < currHost.cookies.length; ++j) {
827  var cookie = currHost.cookies[j];
828  if (this._cookieMatchesFilter(cookie))
829  cookies.push(cookie);
830  }
831  }
832  return cookies;
833  },
834 
835  _lastSelectedRanges: [],
836  _openIndices: [],
837  _saveState: function () {
838  // Save selection
839  var seln = this._view.selection;
840  this._lastSelectedRanges = [];
841  var rangeCount = seln.getRangeCount();
842  for (var i = 0; i < rangeCount; ++i) {
843  var min = {}; var max = {};
844  seln.getRangeAt(i, min, max);
845  this._lastSelectedRanges.push({ min: min.value, max: max.value });
846  }
847 
848  // Save open states
849  this._openIndices = [];
850  for (i = 0; i < this._view.rowCount; ++i) {
851  var item = this._view._getItemAtIndex(i);
852  if (item && item.container && item.open)
853  this._openIndices.push(i);
854  }
855  },
856 
857  filter: function () {
858  var filter = document.getElementById("filter").value;
859  if (filter == "") {
860  gCookiesWindow.clearFilter();
861  return;
862  }
863  var view = gCookiesWindow._view;
864  view._filterSet = gCookiesWindow._filterCookies(filter);
865  if (!view._filtered) {
866  // Save Display Info for the Non-Filtered mode when we first
867  // enter Filtered mode.
868  gCookiesWindow._saveState();
869  view._filtered = true;
870  }
871  // Move to multi-select in the tree
872  gCookiesWindow._tree.setAttribute("seltype", "multiple");
873 
874  // Clear the display
875  var oldCount = view._rowCount;
876  view._rowCount = 0;
877  gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, -oldCount);
878  // Set up the filtered display
879  view._rowCount = view._filterSet.length;
880  gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, view.rowCount);
881 
882  // if the view is not empty then select the first item
883  if (view.rowCount > 0)
884  view.selection.select(0);
885 
886  document.getElementById("cookiesIntro").value = gCookiesWindow._bundle.getString("cookiesFiltered");
887  },
888 
889  setFilter: function (aFilterString) {
890  document.getElementById("filter").value = aFilterString;
891  this.filter();
892  },
893 
894  focusFilterBox: function () {
895  var filter = document.getElementById("filter");
896  filter.focus();
897  filter.select();
898  }
899 };
function start(ch)
const nsICookie
Definition: cookies.js:40
_setDateDatepicker date
onPageChanged aValue
Definition: FeedWriter.js:1395
var gCookiesWindow
Definition: cookies.js:42
_updateCookies aHost
let window
gImageView getCellProperties
Definition: pageInfo.js:171
_window init
Definition: FeedWriter.js:1144
var count
Definition: test_bug7406.js:32
BogusChannel prototype open
this _dialogInput val(dateText)
_updateCookies aCookie
return null
Definition: FeedWriter.js:1143
var os
countRef value
Definition: FeedWriter.js:1423
restoreHistoryPrecursor aCount
#define min(a, b)
function uninit(aEvent)
Definition: aboutDialog.js:89
_getSelectedPageStyle s i
Array filter(tab.attributes, function(aAttr){return(_this.xulAttributes.indexOf(aAttr.name) >-1);}).forEach(tab.removeAttribute
_updateTextAndScrollDataForFrame aData
sbDeviceFirmwareAutoCheckForUpdate prototype observe
function range(x, y)
Definition: httpd.js:138