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:
Родитель
5a5b552b7a
Коммит
364492d251
|
@ -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++
|
||||
|
|
Загрузка…
Ссылка в новой задаче