[NAVIGATOR] Add Cookie Manager

custom-2020
Matt A. Tobin 4 years ago committed by Roy Tam
parent 94de06b6bb
commit 43ae81a6b6
  1. 2
      navigator/base/content/navigatorOverlay.xul
  2. 2
      navigator/base/content/pref/pref-cookies.xul
  3. 7
      navigator/base/content/tasksOverlay.js
  4. 37
      navigator/components/cookies/content/cookieManager.css
  5. 948
      navigator/components/cookies/content/cookieManager.js
  6. 105
      navigator/components/cookies/content/cookieManager.xul
  7. 15
      navigator/components/cookies/jar.mn
  8. 27
      navigator/components/cookies/locale/cookieManager.dtd
  9. 37
      navigator/components/cookies/locale/cookieManager.properties
  10. 6
      navigator/components/cookies/moz.build
  11. 1
      navigator/components/moz.build

@ -507,7 +507,7 @@
<menuitem id="menuitem_cookieDisplay"
label="&cookieDisplayCookiesCmd.label;"
accesskey="&cookieDisplayCookiesCmd.accesskey;"
oncommand="toDataManager(hostUrl() + '|cookies');
oncommand="toCookieManager();
event.stopPropagation();"/>
</menupopup>
</menu>

@ -82,7 +82,7 @@
label="&viewCookies.label;"
accesskey="&viewCookies.accesskey;"
preference="pref.advanced.cookies.disable_button.view_cookies"
oncommand="toDataManager('|cookies');"/>
oncommand="toCookieManager();"/>
</hbox>
</groupbox>
</prefpane>

@ -12,6 +12,13 @@ function toNavigator()
OpenBrowserWindow();
}
function toCookieManager()
{
toOpenWindowByType("Navigator:Cookies",
"chrome://navigator/content/cookies/cookieManager.xul",
"resizable");
}
function toPasswordManager()
{
toOpenWindowByType("Toolkit:PasswordManager",

@ -0,0 +1,37 @@
/*
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
.contentPane {
margin: 9px 8px 5px;
}
.actionButtons {
margin: 0 3px 6px !important;
}
#cookiesChildren::-moz-tree-image(domainCol) {
width: 16px;
height: 16px;
margin: 0 2px;
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png") !important;
}
#cookiesChildren::-moz-tree-image(domainCol, container) {
list-style-image: url("chrome://global/skin/icons/folder-item.png") !important;
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#cookiesChildren::-moz-tree-image(domainCol, container, open) {
-moz-image-region: rect(16px, 32px, 32px, 16px);
}
#cookieInfoBox {
border: 1px solid ThreeDShadow;
border-radius: 0;
margin: 4px;
padding: 0;
}

@ -0,0 +1,948 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const nsICookie = Components.interfaces.nsICookie;
Components.utils.import("resource://gre/modules/PluralForm.jsm");
var gCookiesWindow = {
_cm : Components.classes["@mozilla.org/cookiemanager;1"]
.getService(Components.interfaces.nsICookieManager),
_ds : Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
.getService(Components.interfaces.nsIScriptableDateFormat),
_hosts : {},
_hostOrder : [],
_tree : null,
_bundle : null,
init: function () {
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.addObserver(this, "cookie-changed", false);
os.addObserver(this, "perm-changed", false);
this._bundle = document.getElementById("bundleCookies");
this._tree = document.getElementById("cookiesList");
let removeAllCookies = document.getElementById("removeAllCookies");
removeAllCookies.setAttribute("accesskey", this._bundle.getString("removeAllCookies.accesskey"));
let removeSelectedCookies = document.getElementById("removeSelectedCookies");
removeSelectedCookies.setAttribute("accesskey", this._bundle.getString("removeSelectedCookies.accesskey"));
this._populateList(true);
document.getElementById("filter").focus();
},
uninit: function () {
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.removeObserver(this, "cookie-changed");
os.removeObserver(this, "perm-changed");
},
_populateList: function (aInitialLoad) {
this._loadCookies();
this._tree.view = this._view;
if (aInitialLoad)
this.sort("rawHost");
if (this._view.rowCount > 0)
this._tree.view.selection.select(0);
if (aInitialLoad) {
if ("arguments" in window &&
window.arguments[0] &&
window.arguments[0].filterString)
this.setFilter(window.arguments[0].filterString);
}
else {
if (document.getElementById("filter").value != "")
this.filter();
}
this._updateRemoveAllButton();
this._saveState();
},
_cookieEquals: function (aCookieA, aCookieB, aStrippedHost) {
return aCookieA.rawHost == aStrippedHost &&
aCookieA.name == aCookieB.name &&
aCookieA.path == aCookieB.path &&
ChromeUtils.isOriginAttributesEqual(aCookieA.originAttributes,
aCookieB.originAttributes);
},
observe: function (aCookie, aTopic, aData) {
if (aTopic != "cookie-changed")
return;
if (aCookie instanceof Components.interfaces.nsICookie) {
var strippedHost = this._makeStrippedHost(aCookie.host);
if (aData == "changed")
this._handleCookieChanged(aCookie, strippedHost);
else if (aData == "added")
this._handleCookieAdded(aCookie, strippedHost);
}
else if (aData == "cleared") {
this._hosts = {};
this._hostOrder = [];
var oldRowCount = this._view._rowCount;
this._view._rowCount = 0;
this._tree.treeBoxObject.rowCountChanged(0, -oldRowCount);
this._view.selection.clearSelection();
this._updateRemoveAllButton();
}
else if (aData == "reload") {
// first, clear any existing entries
this.observe(aCookie, aTopic, "cleared");
// then, reload the list
this._populateList(false);
}
// We don't yet handle aData == "deleted" - it's a less common case
// and is rather complicated as selection tracking is difficult
},
_handleCookieChanged: function (changedCookie, strippedHost) {
var rowIndex = 0;
var cookieItem = null;
if (!this._view._filtered) {
for (var i = 0; i < this._hostOrder.length; ++i) { // (var host in this._hosts) {
++rowIndex;
var hostItem = this._hosts[this._hostOrder[i]]; // var hostItem = this._hosts[host];
if (this._hostOrder[i] == strippedHost) { // host == strippedHost) {
// Host matches, look for the cookie within this Host collection
// and update its data
for (var j = 0; j < hostItem.cookies.length; ++j) {
++rowIndex;
var currCookie = hostItem.cookies[j];
if (this._cookieEquals(currCookie, changedCookie, strippedHost)) {
currCookie.value = changedCookie.value;
currCookie.isSecure = changedCookie.isSecure;
currCookie.isDomain = changedCookie.isDomain;
currCookie.expires = changedCookie.expires;
cookieItem = currCookie;
break;
}
}
}
else if (hostItem.open)
rowIndex += hostItem.cookies.length;
}
}
else {
// Just walk the filter list to find the item. It doesn't matter that
// we don't update the main Host collection when we do this, because
// when the filter is reset the Host collection is rebuilt anyway.
for (rowIndex = 0; rowIndex < this._view._filterSet.length; ++rowIndex) {
currCookie = this._view._filterSet[rowIndex];
if (this._cookieEquals(currCookie, changedCookie, strippedHost)) {
currCookie.value = changedCookie.value;
currCookie.isSecure = changedCookie.isSecure;
currCookie.isDomain = changedCookie.isDomain;
currCookie.expires = changedCookie.expires;
cookieItem = currCookie;
break;
}
}
}
// Make sure the tree display is up to date...
this._tree.treeBoxObject.invalidateRow(rowIndex);
// ... and if the cookie is selected, update the displayed metadata too
if (cookieItem != null && this._view.selection.currentIndex == rowIndex)
this._updateCookieData(cookieItem);
},
_handleCookieAdded: function (changedCookie, strippedHost) {
var rowCountImpact = 0;
var addedHost = { value: 0 };
this._addCookie(strippedHost, changedCookie, addedHost);
if (!this._view._filtered) {
// The Host collection for this cookie already exists, and it's not open,
// so don't increment the rowCountImpact becaues the user is not going to
// see the additional rows as they're hidden.
if (addedHost.value || this._hosts[strippedHost].open)
++rowCountImpact;
}
else {
// We're in search mode, and the cookie being added matches
// the search condition, so add it to the list.
var c = this._makeCookieObject(strippedHost, changedCookie);
if (this._cookieMatchesFilter(c)) {
this._view._filterSet.push(this._makeCookieObject(strippedHost, changedCookie));
++rowCountImpact;
}
}
// Now update the tree display at the end (we could/should re run the sort
// if any to get the position correct.)
var oldRowCount = this._rowCount;
this._view._rowCount += rowCountImpact;
this._tree.treeBoxObject.rowCountChanged(oldRowCount - 1, rowCountImpact);
this._updateRemoveAllButton();
},
_view: {
_filtered : false,
_filterSet : [],
_filterValue: "",
_rowCount : 0,
_cacheValid : 0,
_cacheItems : [],
get rowCount() {
return this._rowCount;
},
_getItemAtIndex: function (aIndex) {
if (this._filtered)
return this._filterSet[aIndex];
var start = 0;
var count = 0, hostIndex = 0;
var cacheIndex = Math.min(this._cacheValid, aIndex);
if (cacheIndex > 0) {
var cacheItem = this._cacheItems[cacheIndex];
start = cacheItem['start'];
count = hostIndex = cacheItem['count'];
}
for (var i = start; i < gCookiesWindow._hostOrder.length; ++i) { // var host in gCookiesWindow._hosts) {
var currHost = gCookiesWindow._hosts[gCookiesWindow._hostOrder[i]]; // gCookiesWindow._hosts[host];
if (!currHost) continue;
if (count == aIndex)
return currHost;
hostIndex = count;
var cacheEntry = { 'start' : i, 'count' : count };
var cacheStart = count;
if (currHost.open) {
if (count < aIndex && aIndex <= (count + currHost.cookies.length)) {
// We are looking for an entry within this host's children,
// enumerate them looking for the index.
++count;
for (var i = 0; i < currHost.cookies.length; ++i) {
if (count == aIndex) {
var cookie = currHost.cookies[i];
cookie.parentIndex = hostIndex;
return cookie;
}
++count;
}
}
else {
// A host entry was open, but we weren't looking for an index
// within that host entry's children, so skip forward over the
// entry's children. We need to add one to increment for the
// host value too.
count += currHost.cookies.length + 1;
}
}
else
++count;
for (var j = cacheStart; j < count; j++)
this._cacheItems[j] = cacheEntry;
this._cacheValid = count - 1;
}
return null;
},
_removeItemAtIndex: function (aIndex, aCount) {
var removeCount = aCount === undefined ? 1 : aCount;
if (this._filtered) {
// remove the cookies from the unfiltered set so that they
// don't reappear when the filter is changed. See bug 410863.
for (var i = aIndex; i < aIndex + removeCount; ++i) {
var item = this._filterSet[i];
var parent = gCookiesWindow._hosts[item.rawHost];
for (var j = 0; j < parent.cookies.length; ++j) {
if (item == parent.cookies[j]) {
parent.cookies.splice(j, 1);
break;
}
}
}
this._filterSet.splice(aIndex, removeCount);
return;
}
var item = this._getItemAtIndex(aIndex);
if (!item) return;
this._invalidateCache(aIndex - 1);
if (item.container) {
gCookiesWindow._hosts[item.rawHost] = null;
} else {
var parent = this._getItemAtIndex(item.parentIndex);
for (var i = 0; i < parent.cookies.length; ++i) {
var cookie = parent.cookies[i];
if (item.rawHost == cookie.rawHost &&
item.name == cookie.name &&
item.path == cookie.path &&
ChromeUtils.isOriginAttributesEqual(item.originAttributes,
cookie.originAttributes)) {
parent.cookies.splice(i, removeCount);
}
}
}
},
_invalidateCache: function (aIndex) {
this._cacheValid = Math.min(this._cacheValid, aIndex);
},
getCellText: function (aIndex, aColumn) {
if (!this._filtered) {
var item = this._getItemAtIndex(aIndex);
if (!item)
return "";
if (aColumn.id == "domainCol")
return item.rawHost;
else if (aColumn.id == "nameCol")
return item.name;
}
else {
if (aColumn.id == "domainCol")
return this._filterSet[aIndex].rawHost;
else if (aColumn.id == "nameCol")
return this._filterSet[aIndex].name;
}
return "";
},
_selection: null,
get selection () { return this._selection; },
set selection (val) { this._selection = val; return val; },
getRowProperties: function (aIndex) { return ""; },
getCellProperties: function (aIndex, aColumn) { return ""; },
getColumnProperties: function (aColumn) { return ""; },
isContainer: function (aIndex) {
if (!this._filtered) {
var item = this._getItemAtIndex(aIndex);
if (!item) return false;
return item.container;
}
return false;
},
isContainerOpen: function (aIndex) {
if (!this._filtered) {
var item = this._getItemAtIndex(aIndex);
if (!item) return false;
return item.open;
}
return false;
},
isContainerEmpty: function (aIndex) {
if (!this._filtered) {
var item = this._getItemAtIndex(aIndex);
if (!item) return false;
return item.cookies.length == 0;
}
return false;
},
isSeparator: function (aIndex) { return false; },
isSorted: function (aIndex) { return false; },
canDrop: function (aIndex, aOrientation) { return false; },
drop: function (aIndex, aOrientation) {},
getParentIndex: function (aIndex) {
if (!this._filtered) {
var item = this._getItemAtIndex(aIndex);
// If an item has no parent index (i.e. it is at the top level) this
// function MUST return -1 otherwise we will go into an infinite loop.
// Containers are always top level items in the cookies tree, so make
// sure to return the appropriate value here.
if (!item || item.container) return -1;
return item.parentIndex;
}
return -1;
},
hasNextSibling: function (aParentIndex, aIndex) {
if (!this._filtered) {
// |aParentIndex| appears to be bogus, but we can get the real
// parent index by getting the entry for |aIndex| and reading the
// parentIndex field.
// The index of the last item in this host collection is the
// index of the parent + the size of the host collection, and
// aIndex has a next sibling if it is less than this value.
var item = this._getItemAtIndex(aIndex);
if (item) {
if (item.container) {
for (var i = aIndex + 1; i < this.rowCount; ++i) {
var subsequent = this._getItemAtIndex(i);
if (subsequent.container)
return true;
}
return false;
}
else {
var parent = this._getItemAtIndex(item.parentIndex);
if (parent && parent.container)
return aIndex < item.parentIndex + parent.cookies.length;
}
}
}
return aIndex < this.rowCount - 1;
},
hasPreviousSibling: function (aIndex) {
if (!this._filtered) {
var item = this._getItemAtIndex(aIndex);
if (!item) return false;
var parent = this._getItemAtIndex(item.parentIndex);
if (parent && parent.container)
return aIndex > item.parentIndex + 1;
}
return aIndex > 0;
},
getLevel: function (aIndex) {
if (!this._filtered) {
var item = this._getItemAtIndex(aIndex);
if (!item) return 0;
return item.level;
}
return 0;
},
getImageSrc: function (aIndex, aColumn) {},
getProgressMode: function (aIndex, aColumn) {},
getCellValue: function (aIndex, aColumn) {},
setTree: function (aTree) {},
toggleOpenState: function (aIndex) {
if (!this._filtered) {
var item = this._getItemAtIndex(aIndex);
if (!item) return;
this._invalidateCache(aIndex);
var multiplier = item.open ? -1 : 1;
var delta = multiplier * item.cookies.length;
this._rowCount += delta;
item.open = !item.open;
gCookiesWindow._tree.treeBoxObject.rowCountChanged(aIndex + 1, delta);
gCookiesWindow._tree.treeBoxObject.invalidateRow(aIndex);
}
},
cycleHeader: function (aColumn) {},
selectionChanged: function () {},
cycleCell: function (aIndex, aColumn) {},
isEditable: function (aIndex, aColumn) {
return false;
},
isSelectable: function (aIndex, aColumn) {
return false;
},
setCellValue: function (aIndex, aColumn, aValue) {},
setCellText: function (aIndex, aColumn, aValue) {},
performAction: function (aAction) {},
performActionOnRow: function (aAction, aIndex) {},
performActionOnCell: function (aAction, aindex, aColumn) {}
},
_makeStrippedHost: function (aHost) {
var formattedHost = aHost.charAt(0) == "." ? aHost.substring(1, aHost.length) : aHost;
return formattedHost.substring(0, 4) == "www." ? formattedHost.substring(4, formattedHost.length) : formattedHost;
},
_addCookie: function (aStrippedHost, aCookie, aHostCount) {
if (!(aStrippedHost in this._hosts) || !this._hosts[aStrippedHost]) {
this._hosts[aStrippedHost] = { cookies : [],
rawHost : aStrippedHost,
level : 0,
open : false,
container : true };
this._hostOrder.push(aStrippedHost);
++aHostCount.value;
}
var c = this._makeCookieObject(aStrippedHost, aCookie);
this._hosts[aStrippedHost].cookies.push(c);
},
_makeCookieObject: function (aStrippedHost, aCookie) {
var host = aCookie.host;
var formattedHost = host.charAt(0) == "." ? host.substring(1, host.length) : host;
var c = { name : aCookie.name,
value : aCookie.value,
isDomain : aCookie.isDomain,
host : aCookie.host,
rawHost : aStrippedHost,
path : aCookie.path,
isSecure : aCookie.isSecure,
expires : aCookie.expires,
level : 1,
container : false,
originAttributes: aCookie.originAttributes };
return c;
},
_loadCookies: function () {
var e = this._cm.enumerator;
var hostCount = { value: 0 };
this._hosts = {};
this._hostOrder = [];
while (e.hasMoreElements()) {
var cookie = e.getNext();
if (cookie && cookie instanceof Components.interfaces.nsICookie) {
var strippedHost = this._makeStrippedHost(cookie.host);
this._addCookie(strippedHost, cookie, hostCount);
}
else
break;
}
this._view._rowCount = hostCount.value;
},
formatExpiresString: function (aExpires) {
if (aExpires) {
var date = new Date(1000 * aExpires);
return this._ds.FormatDateTime("", this._ds.dateFormatLong,
this._ds.timeFormatSeconds,
date.getFullYear(),
date.getMonth() + 1,
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds());
}
return this._bundle.getString("expireAtEndOfSession");
},
_updateCookieData: function (aItem) {
var seln = this._view.selection;
var ids = ["name", "value", "host", "path", "isSecure", "expires"];
var properties;
if (aItem && !aItem.container && seln.count > 0) {
properties = { name: aItem.name, value: aItem.value, host: aItem.host,
path: aItem.path, expires: this.formatExpiresString(aItem.expires),
isDomain: aItem.isDomain ? this._bundle.getString("domainColon")
: this._bundle.getString("hostColon"),
isSecure: aItem.isSecure ? this._bundle.getString("forSecureOnly")
: this._bundle.getString("forAnyConnection") };
for (var i = 0; i < ids.length; ++i)
document.getElementById(ids[i]).disabled = false;
}
else {
var noneSelected = this._bundle.getString("noCookieSelected");
properties = { name: noneSelected, value: noneSelected, host: noneSelected,
path: noneSelected, expires: noneSelected,
isSecure: noneSelected };
for (i = 0; i < ids.length; ++i)
document.getElementById(ids[i]).disabled = true;
}
for (var property in properties)
document.getElementById(property).value = properties[property];
},
onCookieSelected: function () {
var properties, item;
var seln = this._tree.view.selection;
var hasRows = this._tree.view.rowCount > 0;
var hasSelection = seln.count > 0;
if (!this._view._filtered)
item = this._view._getItemAtIndex(seln.currentIndex);
else
item = this._view._filterSet[seln.currentIndex];
this._updateCookieData(item);
var rangeCount = seln.getRangeCount();
var selectedCookieCount = 0;
for (var i = 0; i < rangeCount; ++i) {
var min = {}; var max = {};
seln.getRangeAt(i, min, max);
for (var j = min.value; j <= max.value; ++j) {
item = this._view._getItemAtIndex(j);
if (!item) continue;
if (item.container && !item.open)
selectedCookieCount += item.cookies.length;
else if (!item.container)
++selectedCookieCount;
}
}
var item = this._view._getItemAtIndex(seln.currentIndex);
if (item && seln.count == 1 && item.container && item.open)
selectedCookieCount += 2;
let buttonLabel = this._bundle.getString("removeSelectedCookies.label");
let removeSelectedCookies = document.getElementById("removeSelectedCookies");
removeSelectedCookies.label = PluralForm.get(selectedCookieCount, buttonLabel)
.replace("#1", selectedCookieCount);
removeSelectedCookies.disabled = !hasRows || !hasSelection;
},
performDeletion: function gCookiesWindow_performDeletion(deleteItems) {
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var blockFutureCookies = false;
if (psvc.prefHasUserValue("network.cookie.blockFutureCookies"))
blockFutureCookies = psvc.getBoolPref("network.cookie.blockFutureCookies");
for (var i = 0; i < deleteItems.length; ++i) {
var item = deleteItems[i];
this._cm.remove(item.host, item.name, item.path,
blockFutureCookies, item.originAttributes);
}
},
deleteCookie: function () {
// Selection Notes
// - Selection always moves to *NEXT* adjacent item unless item
// is last child at a given level in which case it moves to *PREVIOUS*
// item
//
// Selection Cases (Somewhat Complicated)
//
// 1) Single cookie selected, host has single child
// v cnn.com
// //// cnn.com ///////////// goksdjf@ ////
// > atwola.com
//
// Before SelectedIndex: 1 Before RowCount: 3
// After SelectedIndex: 0 After RowCount: 1
//
// 2) Host selected, host open
// v goats.com ////////////////////////////
// goats.com sldkkfjl
// goat.scom flksj133
// > atwola.com
//
// Before SelectedIndex: 0 Before RowCount: 4
// After SelectedIndex: 0 After RowCount: 1
//
// 3) Host selected, host closed
// > goats.com ////////////////////////////
// > atwola.com
//
// Before SelectedIndex: 0 Before RowCount: 2
// After SelectedIndex: 0 After RowCount: 1
//
// 4) Single cookie selected, host has many children
// v goats.com
// goats.com sldkkfjl
// //// goats.com /////////// flksjl33 ////
// > atwola.com
//
// Before SelectedIndex: 2 Before RowCount: 4
// After SelectedIndex: 1 After RowCount: 3
//
// 5) Single cookie selected, host has many children
// v goats.com
// //// goats.com /////////// flksjl33 ////
// goats.com sldkkfjl
// > atwola.com
//
// Before SelectedIndex: 1 Before RowCount: 4
// After SelectedIndex: 1 After RowCount: 3
var seln = this._view.selection;
var tbo = this._tree.treeBoxObject;
if (seln.count < 1) return;
var nextSelected = 0;
var rowCountImpact = 0;
var deleteItems = [];
if (!this._view._filtered) {
var ci = seln.currentIndex;
nextSelected = ci;
var invalidateRow = -1;
var item = this._view._getItemAtIndex(ci);
if (item.container) {
rowCountImpact -= (item.open ? item.cookies.length : 0) + 1;
deleteItems = deleteItems.concat(item.cookies);
if (!this._view.hasNextSibling(-1, ci))
--nextSelected;
this._view._removeItemAtIndex(ci);
}
else {
var parent = this._view._getItemAtIndex(item.parentIndex);
--rowCountImpact;
if (parent.cookies.length == 1) {
--rowCountImpact;
deleteItems.push(item);
if (!this._view.hasNextSibling(-1, ci))
--nextSelected;
if (!this._view.hasNextSibling(-1, item.parentIndex))
--nextSelected;
this._view._removeItemAtIndex(item.parentIndex);
invalidateRow = item.parentIndex;
}
else {
deleteItems.push(item);
if (!this._view.hasNextSibling(-1, ci))
--nextSelected;
this._view._removeItemAtIndex(ci);
}
}
this._view._rowCount += rowCountImpact;
tbo.rowCountChanged(ci, rowCountImpact);
if (invalidateRow != -1)
tbo.invalidateRow(invalidateRow);
}
else {
var rangeCount = seln.getRangeCount();
// Traverse backwards through selections to avoid messing
// up the indices when they are deleted.
// See bug 388079.
for (var i = rangeCount - 1; i >= 0; --i) {
var min = {}; var max = {};
seln.getRangeAt(i, min, max);
nextSelected = min.value;
for (var j = min.value; j <= max.value; ++j) {
deleteItems.push(this._view._getItemAtIndex(j));
if (!this._view.hasNextSibling(-1, max.value))
--nextSelected;
}
var delta = max.value - min.value + 1;
this._view._removeItemAtIndex(min.value, delta);
rowCountImpact = -1 * delta;
this._view._rowCount += rowCountImpact;
tbo.rowCountChanged(min.value, rowCountImpact);
}
}
this.performDeletion(deleteItems);
if (nextSelected < 0)
seln.clearSelection();
else {
seln.select(nextSelected);
this._tree.focus();
}
},
deleteAllCookies: function () {
if (this._view._filtered) {
var rowCount = this._view.rowCount;
var deleteItems = [];
for (var index = 0; index < rowCount; index++) {
deleteItems.push(this._view._getItemAtIndex(index));
}
this._view._removeItemAtIndex(0, rowCount);
this._view._rowCount = 0;
this._tree.treeBoxObject.rowCountChanged(0, -rowCount);
this.performDeletion(deleteItems);
}
else {
this._cm.removeAll();
}
this._updateRemoveAllButton();
this.focusFilterBox();
},
onCookieKeyPress: function (aEvent) {
if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE
#ifdef XP_MACOSX
|| aEvent.keyCode == KeyEvent.DOM_VK_BACK_SPACE
#endif
) {
this.deleteCookie();
}
},
_lastSortProperty : "",
_lastSortAscending: false,
sort: function (aProperty) {
var ascending = (aProperty == this._lastSortProperty) ? !this._lastSortAscending : true;
// Sort the Non-Filtered Host Collections
if (aProperty == "rawHost") {
function sortByHost(a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
}
this._hostOrder.sort(sortByHost);
if (!ascending)
this._hostOrder.reverse();
}
function sortByProperty(a, b) {
return a[aProperty].toLowerCase().localeCompare(b[aProperty].toLowerCase());
}
for (var host in this._hosts) {
var cookies = this._hosts[host].cookies;
cookies.sort(sortByProperty);
if (!ascending)
cookies.reverse();
}
// Sort the Filtered List, if in Filtered mode
if (this._view._filtered) {
this._view._filterSet.sort(sortByProperty);
if (!ascending)
this._view._filterSet.reverse();
}
// Adjust the Sort Indicator
var domainCol = document.getElementById("domainCol");
var nameCol = document.getElementById("nameCol");
var sortOrderString = ascending ? "ascending" : "descending";
if (aProperty == "rawHost") {
domainCol.setAttribute("sortDirection", sortOrderString);
nameCol.removeAttribute("sortDirection");
}
else {
nameCol.setAttribute("sortDirection", sortOrderString);
domainCol.removeAttribute("sortDirection");
}
this._view._invalidateCache(0);
this._view.selection.clearSelection();
if (this._view.rowCount > 0) {
this._view.selection.select(0);
}
this._tree.treeBoxObject.invalidate();
this._tree.treeBoxObject.ensureRowIsVisible(0);
this._lastSortAscending = ascending;
this._lastSortProperty = aProperty;
},
clearFilter: function () {
// Revert to single-select in the tree
this._tree.setAttribute("seltype", "single");
// Clear the Tree Display
this._view._filtered = false;
this._view._rowCount = 0;
this._tree.treeBoxObject.rowCountChanged(0, -this._view._filterSet.length);
this._view._filterSet = [];
// Just reload the list to make sure deletions are respected
this._loadCookies();
this._tree.view = this._view;
// Restore sort order
var sortby = this._lastSortProperty;
if (sortby == "") {
this._lastSortAscending = false;
this.sort("rawHost");
}
else {
this._lastSortAscending = !this._lastSortAscending;
this.sort(sortby);
}
// Restore open state
for (var i = 0; i < this._openIndices.length; ++i)
this._view.toggleOpenState(this._openIndices[i]);
this._openIndices = [];
// Restore selection
this._view.selection.clearSelection();
for (i = 0; i < this._lastSelectedRanges.length; ++i) {
var range = this._lastSelectedRanges[i];
this._view.selection.rangedSelect(range.min, range.max, true);
}
this._lastSelectedRanges = [];
document.getElementById("cookiesIntro").value = this._bundle.getString("cookiesAll");
this._updateRemoveAllButton();
},
_cookieMatchesFilter: function (aCookie) {
return aCookie.rawHost.indexOf(this._view._filterValue) != -1 ||
aCookie.name.indexOf(this._view._filterValue) != -1 ||
aCookie.value.indexOf(this._view._filterValue) != -1;
},
_filterCookies: function (aFilterValue) {
this._view._filterValue = aFilterValue;
var cookies = [];
for (var i = 0; i < gCookiesWindow._hostOrder.length; ++i) { //var host in gCookiesWindow._hosts) {
var currHost = gCookiesWindow._hosts[gCookiesWindow._hostOrder[i]]; // gCookiesWindow._hosts[host];
if (!currHost) continue;
for (var j = 0; j < currHost.cookies.length; ++j) {
var cookie = currHost.cookies[j];
if (this._cookieMatchesFilter(cookie))
cookies.push(cookie);
}
}
return cookies;
},
_lastSelectedRanges: [],
_openIndices: [],
_saveState: function () {
// Save selection
var seln = this._view.selection;
this._lastSelectedRanges = [];
var rangeCount = seln.getRangeCount();
for (var i = 0; i < rangeCount; ++i) {
var min = {}; var max = {};
seln.getRangeAt(i, min, max);
this._lastSelectedRanges.push({ min: min.value, max: max.value });
}
// Save open states
this._openIndices = [];
for (i = 0; i < this._view.rowCount; ++i) {
var item = this._view._getItemAtIndex(i);
if (item && item.container && item.open)
this._openIndices.push(i);
}
},
_updateRemoveAllButton: function gCookiesWindow__updateRemoveAllButton() {
let removeAllCookies = document.getElementById("removeAllCookies");
removeAllCookies.disabled = this._view._rowCount == 0;
let labelStringID = "removeAllCookies.label";
let accessKeyStringID = "removeAllCookies.accesskey";
if (this._view._filtered) {
labelStringID = "removeAllShownCookies.label";
accessKeyStringID = "removeAllShownCookies.accesskey";
}
removeAllCookies.setAttribute("label", this._bundle.getString(labelStringID));
removeAllCookies.setAttribute("accesskey", this._bundle.getString(accessKeyStringID));
},
filter: function () {
var filter = document.getElementById("filter").value;
if (filter == "") {
gCookiesWindow.clearFilter();
return;
}
var view = gCookiesWindow._view;
view._filterSet = gCookiesWindow._filterCookies(filter);
if (!view._filtered) {
// Save Display Info for the Non-Filtered mode when we first
// enter Filtered mode.
gCookiesWindow._saveState();
view._filtered = true;
}
// Move to multi-select in the tree
gCookiesWindow._tree.setAttribute("seltype", "multiple");
// Clear the display
var oldCount = view._rowCount;
view._rowCount = 0;
gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, -oldCount);
// Set up the filtered display
view._rowCount = view._filterSet.length;
gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, view.rowCount);
// if the view is not empty then select the first item
if (view.rowCount > 0)
view.selection.select(0);
document.getElementById("cookiesIntro").value = gCookiesWindow._bundle.getString("cookiesFiltered");
this._updateRemoveAllButton();
},
setFilter: function (aFilterString) {
document.getElementById("filter").value = aFilterString;
this.filter();
},
focusFilterBox: function () {
var filter = document.getElementById("filter");
filter.focus();
filter.select();
},
onWindowKeyPress: function (aEvent) {
if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE)
window.close();
}
};

@ -0,0 +1,105 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://navigator/content/cookies/cookieManager.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://navigator/locale/cookies/cookieManager.dtd" >
<window id="CookiesDialog" windowtype="Navigator:Cookies"
class="windowDialog" title="&window.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
style="width: &window.width;;"
onload="gCookiesWindow.init();"
onunload="gCookiesWindow.uninit();"
persist="screenX screenY width height"
onkeypress="gCookiesWindow.onWindowKeyPress(event);">
<script src="chrome://navigator/content/cookies/cookieManager.js"/>
<stringbundle id="bundleCookies"
src="chrome://navigator/locale/cookies/cookieManager.properties"/>
<keyset>
<key key="&windowClose.key;" modifiers="accel" oncommand="window.close();"/>
<key key="&focusSearch1.key;" modifiers="accel" oncommand="gCookiesWindow.focusFilterBox();"/>
<key key="&focusSearch2.key;" modifiers="accel" oncommand="gCookiesWindow.focusFilterBox();"/>
</keyset>
<vbox flex="1" class="contentPane">
<hbox align="center">
<label accesskey="&filter.accesskey;" control="filter">&filter.label;</label>
<textbox type="search" id="filter" flex="1"
aria-controls="cookiesList"
oncommand="gCookiesWindow.filter();"/>
</hbox>
<separator class="thin"/>
<label control="cookiesList" id="cookiesIntro" value="&cookiesonsystem.label;"/>
<separator class="thin"/>
<tree id="cookiesList" flex="1" style="height: 10em;"
onkeypress="gCookiesWindow.onCookieKeyPress(event)"
onselect="gCookiesWindow.onCookieSelected();"
hidecolumnpicker="true" seltype="single">
<treecols>
<treecol id="domainCol" label="&cookiedomain.label;" flex="2" primary="true"
persist="width" onclick="gCookiesWindow.sort('rawHost');"/>
<splitter class="tree-splitter"/>
<treecol id="nameCol" label="&cookiename.label;" flex="1"
persist="width"
onclick="gCookiesWindow.sort('name');"/>
</treecols>
<treechildren id="cookiesChildren"/>
</tree>
<hbox id="cookieInfoBox">
<grid flex="1" id="cookieInfoGrid">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<hbox pack="end"><label id="nameLabel" control="name" value="&props.name.label;"/></hbox>
<textbox id="name" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end"><label id="valueLabel" control="value" value="&props.value.label;"/></hbox>
<textbox id="value" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end"><label id="isDomain" control="host" value="&props.domain.label;"/></hbox>
<textbox id="host" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end"><label id="pathLabel" control="path" value="&props.path.label;"/></hbox>
<textbox id="path" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end"><label id="isSecureLabel" control="isSecure" value="&props.secure.label;"/></hbox>
<textbox id="isSecure" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end"><label id="expiresLabel" control="expires" value="&props.expires.label;"/></hbox>
<textbox id="expires" readonly="true" class="plain"/>
</row>
</rows>
</grid>
</hbox>
</vbox>
<hbox align="end">
<hbox class="actionButtons" flex="1">
<button id="removeSelectedCookies" disabled="true" icon="clear"
oncommand="gCookiesWindow.deleteCookie();"/>
<button id="removeAllCookies" disabled="true" icon="clear"
oncommand="gCookiesWindow.deleteAllCookies();"/>
<spacer flex="1"/>
#ifndef XP_MACOSX
<button oncommand="close();" icon="close"
label="&button.close.label;" accesskey="&button.close.accesskey;"/>
#endif
</hbox>
<resizer type="window" dir="bottomend"/>
</hbox>
</window>

@ -0,0 +1,15 @@
#filter substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
comm.jar:
% content navigator %content/navigator/
content/navigator/cookies/cookieManager.css (content/cookieManager.css)
* content/navigator/cookies/cookieManager.js (content/cookieManager.js)
* content/navigator/cookies/cookieManager.xul (content/cookieManager.xul)
@AB_CD@.jar:
% locale navigator @AB_CD@ %locale/@AB_CD@/navigator/
locale/@AB_CD@/navigator/cookies/cookieManager.dtd (locale/cookieManager.dtd)
locale/@AB_CD@/navigator/cookies/cookieManager.properties (locale/cookieManager.properties)

@ -0,0 +1,27 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY window.width "36em">
<!ENTITY cookiesonsystem.label "The following cookies are stored on your computer:">
<!ENTITY cookiename.label "Cookie Name">
<!ENTITY cookiedomain.label "Site">
<!ENTITY props.name.label "Name:">
<!ENTITY props.value.label "Content:">
<!ENTITY props.domain.label "Host:">
<!ENTITY props.path.label "Path:">
<!ENTITY props.secure.label "Send For:">
<!ENTITY props.expires.label "Expires:">
<!ENTITY window.title "Cookie Manager">
<!ENTITY windowClose.key "w">
<!ENTITY focusSearch1.key "f">
<!ENTITY focusSearch2.key "k">
<!ENTITY filter.label "Search:">
<!ENTITY filter.accesskey "S">
<!ENTITY button.close.label "Close">
<!ENTITY button.close.accesskey "C">

@ -0,0 +1,37 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
hostColon=Host:
domainColon=Domain:
forSecureOnly=Encrypted connections only
forAnyConnection=Any type of connection
expireAtEndOfSession=At end of session
can=Allow
canAccessFirstParty=Allow first party only
canSession=Allow for Session
cannot=Block
noCookieSelected=<no cookie selected>
cookiesAll=The following cookies are stored on your computer:
cookiesFiltered=The following cookies match your search:
# LOCALIZATION NOTE (removeAllCookies, removeAllShownCookies):
# removeAllCookies and removeAllShownCookies are both used on the same one button,
# never displayed together and can share the same accesskey.
# When only partial cookies are shown as a result of keyword search,
# removeAllShownCookies is displayed as button label.
# removeAllCookies is displayed when no keyword search and all cookies are shown.
removeAllCookies.label=Remove All
removeAllCookies.accesskey=A
removeAllShownCookies.label=Remove All Shown
removeAllShownCookies.accesskey=A
# LOCALIZATION NOTE (removeSelectedCookies):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
# If you need to display the number of selected elements in your language,
# you can use #1 in your localization as a placeholder for the number.
# For example this is the English string with numbers:
# removeSelectedCookied=Remove #1 Selected;Remove #1 Selected
removeSelectedCookies.label=Remove Selected;Remove Selected
removeSelectedCookies.accesskey=R

@ -0,0 +1,6 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
JAR_MANIFESTS += ['jar.mn']

@ -5,6 +5,7 @@
DIRS += [
'build',
'cookies',
'dirprovider',
'downloads',
'feeds',

Loading…
Cancel
Save