Bug 460086 - Library context menu for history items should include "Delete all data to <domain>"

This also adds this to the history sidebar because of the modularity of the code.  Yay!
r=mconnor
r=dietrich

Tests will be landing in a follow-up patch.
This commit is contained in:
Shawn Wilsher 2008-11-05 03:24:22 -05:00
Родитель 5a5b552b7a
Коммит 364492d251
5 изменённых файлов: 194 добавлений и 4 удалений

Просмотреть файл

@ -129,6 +129,8 @@ PlacesController.prototype = {
case "cmd_cut":
case "cmd_delete":
return this._hasRemovableSelection(false);
case "placesCmd_deleteDataHost":
return this._hasRemovableSelection(false);
case "placesCmd_moveBookmarks":
return this._hasRemovableSelection(true);
case "cmd_copy":
@ -231,6 +233,12 @@ PlacesController.prototype = {
case "cmd_delete":
this.remove("Remove Selection");
break;
case "placesCmd_deleteDataHost":
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
let uri = PlacesUtils._uri(this._view.selectedNode.uri);
pb.removeDataFromDomain(uri.host);
break;
case "cmd_selectAll":
this.selectAll();
break;

Просмотреть файл

@ -91,6 +91,8 @@
oncommand="goDoCommand('placesCmd_sortBy:name');"/>
<command id="placesCmd_moveBookmarks"
oncommand="goDoCommand('placesCmd_moveBookmarks');"/>
<command id="placesCmd_deleteDataHost"
oncommand="goDoCommand('placesCmd_deleteDataHost');"/>
</commandset>
<popup id="placesContext"
@ -179,8 +181,21 @@
label="&deleteCmd.label;"
accesskey="&deleteCmd.accesskey;"
closemenu="single"
selection="any"
forcehideselection="livemarkChild"/>
selection="bookmark|tagChild|folder|query|dynamiccontainer|separator|host"/>
<menuitem id="placesContext_delete_history"
command="cmd_delete"
label="&cmd.delete.label;"
accesskey="&cmd.delete.accesskey;"
closemenu="single"
selection="link"
forcehideselection="bookmark"/>
<menuitem id="placesContext_deleteHost"
command="placesCmd_deleteDataHost"
label="&cmd.deleteDomainData.label;"
accesskey="&cmd.deleteDomainData.accesskey;"
closemenu="single"
selection="link"
forcehideselection="bookmark"/>
<menuseparator id="placesContext_deleteSeparator"/>
<menuitem id="placesContext_reload"
command="placesCmd_reload"

Просмотреть файл

@ -35,12 +35,33 @@
#
# ***** END LICENSE BLOCK *****
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
////////////////////////////////////////////////////////////////////////////////
//// Utilities
String.prototype.endsWith = function endsWith(aString)
{
let index = this.indexOf(aString);
// If it is not found, we know it doesn't end with it.
if (index == -1)
return false;
// Otherwise, we end with the given string iff the index is aString.length
// subtracted from our length.
return index == (this.length - aString.length);
}
////////////////////////////////////////////////////////////////////////////////
//// Constants
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
////////////////////////////////////////////////////////////////////////////////
//// PrivateBrowsingService
function PrivateBrowsingService() {
this._obs.addObserver(this, "profile-after-change", true);
@ -283,6 +304,138 @@ PrivateBrowsingService.prototype = {
*/
get autoStarted PBS_get_autoStarted() {
return this._autoStarted;
},
removeDataFromDomain: function PBS_removeDataFromDomain(aDomain)
{
// History
let (bh = Cc["@mozilla.org/browser/global-history;2"].
getService(Ci.nsIBrowserHistory)) {
bh.removePagesFromHost(aDomain, true);
}
// Cache
let (cs = Cc["@mozilla.org/network/cache-service;1"].
getService(Ci.nsICacheService)) {
// NOTE: there is no way to clear just that domain, so we clear out
// everything)
cs.evictEntries(Ci.nsICache.STORE_ANYWHERE);
}
// Cookies
let (cm = Cc["@mozilla.org/cookiemanager;1"].
getService(Ci.nsICookieManager)) {
let enumerator = cm.enumerator;
while (enumerator.hasMoreElements()) {
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
if (cookie.host.endsWith(aDomain))
cm.remove(cookie.host, cookie.name, cookie.path, false);
}
}
// Downloads
let (dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager)) {
// Active downloads
let enumerator = dm.activeDownloads;
while (enumerator.hasMoreElements()) {
let dl = enumerator.getNext().QueryInterface(Ci.nsIDownload);
if (dl.source.host.endsWith(aDomain)) {
dm.cancelDownload(dl.id);
dm.removeDownload(dl.id);
}
}
// Completed downloads
let db = dm.DBConnection;
// NOTE: This is lossy, but we feel that it is OK to be lossy here and not
// invoke the cost of creating a URI for each download entry and
// ensure that the hostname matches.
let stmt = db.createStatement(
"DELETE FROM moz_downloads " +
"WHERE source LIKE ?1 ESCAPE '/' " +
"AND state NOT IN (?2, ?3, ?4)"
);
let pattern = stmt.escapeStringForLIKE(aDomain, "/");
stmt.bindStringParameter(0, "%" + pattern + "%");
stmt.bindInt32Parameter(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
stmt.bindInt32Parameter(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
stmt.bindInt32Parameter(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
try {
stmt.execute();
}
finally {
stmt.finalize();
}
// We want to rebuild the list if the UI is showing, so dispatch the
// observer topic
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.notifyObservers(null, "download-manager-remove-download", null);
}
// Passwords
let (lm = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager)) {
// Clear all passwords for domain
let logins = lm.getAllLogins({});
for (let i = 0; i < logins.length; i++)
if (logins[i].hostname.endsWith(aDomain))
lm.removeLogin(logins[i]);
// Clear any "do not save for this site" for this domain
let disabledHosts = lm.getAllDisabledHosts({});
for (let i = 0; i < disabledHosts.length; i++)
if (disabledHosts[i].endsWith(aDomain))
lm.setLoginSavingEnabled(disabledHosts, true);
}
// Permissions
let (pm = Cc["@mozilla.org/permissionmanager;1"].
getService(Ci.nsIPermissionManager)) {
// Enumerate all of the permissions, and if one matches, remove it
let enumerator = pm.enumerator;
while (enumerator.hasMoreElements()) {
let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
if (perm.host.endsWith(aDomain))
pm.remove(perm.host, perm.type);
}
}
// Content Preferences
let (cp = Cc["@mozilla.org/content-pref/service;1"].
getService(Ci.nsIContentPrefService)) {
let db = cp.DBConnection;
// First we need to get the list of "groups" which are really just domains
let names = [];
let stmt = db.createStatement(
"SELECT name " +
"FROM groups " +
"WHERE name LIKE ?1 ESCAPE '/'"
);
let pattern = stmt.escapeStringForLIKE(aDomain, "/");
stmt.bindStringParameter(0, "%" + pattern);
try {
while (stmt.executeStep())
names.push(stmt.getString(0));
}
finally {
stmt.finalize();
}
// Now, for each name we got back, remove all of its prefs.
for (let i = 0; i < names.length; i++) {
// The service only cares about the host of the URI, so we don't need a
// full nsIURI object here.
let uri = { host: names[i]};
let enumerator = cp.getPrefs(uri).enumerator;
while (enumerator.hasMoreElements()) {
let pref = enumerator.getNext().QueryInterface(Ci.nsIProperty);
cp.removePref(uri, pref.name);
}
}
}
}
};

Просмотреть файл

@ -71,6 +71,11 @@
<!ENTITY cmd.edit_redo.accesskey "R">
<!ENTITY cmd.edit_redo.key "y">
<!ENTITY cmd.delete.label "Delete This Page">
<!ENTITY cmd.delete.accesskey "D">
<!ENTITY cmd.deleteDomainData.label "Forget About This Site">
<!ENTITY cmd.deleteDomainData.accesskey "F">
<!ENTITY cmd.open.label "Open">
<!ENTITY cmd.open.accesskey "O">
<!ENTITY cmd.open_window.label "Open in a New Window">

Просмотреть файл

@ -37,7 +37,7 @@
#include "nsISupports.idl"
[scriptable, uuid(effb626c-676f-4c9d-b6ca-70696787901a)]
[scriptable, uuid(49d6f133-80c0-48c7-876d-0b70bbfd0289)]
interface nsIPrivateBrowsingService : nsISupports
{
// When read, determines whether the private browsing mode is currently
@ -51,6 +51,15 @@ interface nsIPrivateBrowsingService : nsISupports
// automatically at application startup.
// This value will never be true if privateBrowsingEnabled is false.
readonly attribute boolean autoStarted;
/**
* Removes all data stored for a given domain. This includes all data for
* subdomains of the given domain.
*
* @param aDomain
* The domain that will have its data removed.
*/
void removeDataFromDomain(in AUTF8String aDomain);
};
%{C++