зеркало из https://github.com/mozilla/gecko-dev.git
fix for #64060 - bulk delete history entries by hostname & domainname
also add a new history controller for future history coolness a=ben, r=jag, and a bit of r=timeless
This commit is contained in:
Родитель
9adc8a60f5
Коммит
369607b9ae
|
@ -44,6 +44,11 @@ interface nsIGlobalHistory : nsISupports
|
|||
// Remove the specified page from the global history
|
||||
void RemovePage(in string aURL);
|
||||
|
||||
// Remove all pages from the given host.
|
||||
// If aEntireDomain is true, will assume aHost is a domain,
|
||||
// and remove all pages from the entire domain.
|
||||
void RemovePagesFromHost(in string aHost, in boolean aEntireDomain);
|
||||
|
||||
// Remove all pages from global history
|
||||
void RemoveAllPages();
|
||||
|
||||
|
|
|
@ -44,6 +44,11 @@ interface nsIGlobalHistory : nsISupports
|
|||
// Remove the specified page from the global history
|
||||
void RemovePage(in string aURL);
|
||||
|
||||
// Remove all pages from the given host.
|
||||
// If aEntireDomain is true, will assume aHost is a domain,
|
||||
// and remove all pages from the entire domain.
|
||||
void RemovePagesFromHost(in string aHost, in boolean aEntireDomain);
|
||||
|
||||
// Remove all pages from global history
|
||||
void RemoveAllPages();
|
||||
|
||||
|
|
|
@ -23,19 +23,150 @@
|
|||
|
||||
// The history window uses JavaScript in bookmarks.js too.
|
||||
|
||||
function debug(msg)
|
||||
{
|
||||
// Uncomment for noise
|
||||
//dump(msg+"\n");
|
||||
}
|
||||
|
||||
var gHistoryTree;
|
||||
var gLastHostname;
|
||||
var gLastDomain;
|
||||
var gGlobalHistory;
|
||||
|
||||
var gDeleteByHostname;
|
||||
var gDeleteByDomain;
|
||||
var gHistoryBundle;
|
||||
|
||||
function HistoryInit() {
|
||||
var tree = document.getElementById("historyTree");
|
||||
var historyController = new nsTreeController(tree);
|
||||
|
||||
gHistoryTree = document.getElementById("historyTree");
|
||||
gDeleteByHostname = document.getElementById("cmd_deleteByHostname");
|
||||
gDeleteByDomain = document.getElementById("cmd_deleteByDomain");
|
||||
gHistoryBundle = document.getElementById("historyBundle");
|
||||
|
||||
var treeController = new nsTreeController(gHistoryTree);
|
||||
var historyController = new nsHistoryController;
|
||||
gHistoryTree.controllers.appendController(historyController);
|
||||
|
||||
gGlobalHistory = Components.classes["@mozilla.org/browser/global-history;1"].getService(Components.interfaces.nsIGlobalHistory);
|
||||
|
||||
var children = document.getElementById('treechildren-bookmarks');
|
||||
if (children.firstChild)
|
||||
tree.selectItem(children.firstChild);
|
||||
tree.focus();
|
||||
gHistoryTree.selectItem(children.firstChild);
|
||||
gHistoryTree.focus();
|
||||
|
||||
dump("Updating sort..\n");
|
||||
// do a sort
|
||||
RefreshSort();
|
||||
}
|
||||
|
||||
function updateHistoryCommands()
|
||||
{
|
||||
dump("Updating history commands..\n");
|
||||
goUpdateCommand("cmd_deleteByHostname");
|
||||
goUpdateCommand("cmd_deleteByDomain");
|
||||
}
|
||||
|
||||
function historyOnSelect(event)
|
||||
{
|
||||
dump("History selection has changed..\n");
|
||||
// every time selection changes, save the last hostname
|
||||
gLastHostname = "";
|
||||
gLastDomain = "";
|
||||
var selection = gHistoryTree.selectedItems;
|
||||
if (selection && selection.length > 0) {
|
||||
var url = selection[0].id;
|
||||
// matches scheme://(hostname)...
|
||||
var match = url.match(/.*:\/\/([^\/:]*)/);
|
||||
|
||||
if (match && match.length>1)
|
||||
gLastHostname = match[1];
|
||||
}
|
||||
|
||||
if (gLastHostname) {
|
||||
// matches the last foo.bar in foo.bar or baz.foo.bar
|
||||
var match = gLastHostname.match(/([^.]+\.[^.]+$)/);
|
||||
if (match)
|
||||
gLastDomain = match[1];
|
||||
}
|
||||
|
||||
|
||||
document.commandDispatcher.updateCommands("select");
|
||||
}
|
||||
|
||||
function nsHistoryController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
nsHistoryController.prototype =
|
||||
{
|
||||
supportsCommand: function(command)
|
||||
{
|
||||
switch(command) {
|
||||
case "cmd_deleteByHostname":
|
||||
case "cmd_deleteByDomain":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
isCommandEnabled: function(command)
|
||||
{
|
||||
var enabled = false;
|
||||
var stringId;
|
||||
var text;
|
||||
switch(command) {
|
||||
case "cmd_deleteByHostname":
|
||||
dump("Updating cmd_deleteByHostname..\n");
|
||||
if (gLastHostname) {
|
||||
stringId = "deleteHost";
|
||||
enabled = true;
|
||||
} else {
|
||||
stringId = "deleteHostNoSelection";
|
||||
}
|
||||
text =
|
||||
gHistoryBundle.stringBundle.formatStringFromName(stringId,
|
||||
[ gLastHostname ], 1);
|
||||
dump("Setting value to " + text + "\n");
|
||||
gDeleteByHostname.setAttribute("value", text);
|
||||
|
||||
break;
|
||||
case "cmd_deleteByDomain":
|
||||
if (gLastDomain) {
|
||||
stringId = "deleteDomain";
|
||||
enabled = true;
|
||||
} else {
|
||||
stringId = "deleteDomainNoSelection";
|
||||
}
|
||||
text = gHistoryBundle.stringBundle.formatStringFromName(stringId,
|
||||
[ gLastDomain ], 1);
|
||||
gDeleteByDomain.setAttribute("value", text);
|
||||
}
|
||||
return enabled;
|
||||
},
|
||||
|
||||
doCommand: function(command)
|
||||
{
|
||||
switch(command) {
|
||||
case "cmd_deleteByHostname":
|
||||
gGlobalHistory.RemovePagesFromHost(gLastHostname, false)
|
||||
return true;
|
||||
|
||||
case "cmd_deleteByDomain":
|
||||
gGlobalHistory.RemovePagesFromHost(gLastDomain, true)
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var historyDNDObserver = {
|
||||
onDragStart: function (aEvent)
|
||||
{
|
||||
|
|
|
@ -46,9 +46,16 @@
|
|||
<script src="chrome://global/content/strres.js"/>
|
||||
<script src="chrome://global/content/globalOverlay.js"/>
|
||||
|
||||
<stringbundle id="historyBundle"
|
||||
src="chrome://communicator/locale/history/history.properties"/>
|
||||
|
||||
<commands id="commands">
|
||||
<commandset id="selectEditMenuItems"/>
|
||||
<commandset id="globalEditMenuItems"/>
|
||||
<commandset id="historyEditMenuItems"
|
||||
commandupdater="true"
|
||||
events="select"
|
||||
oncommandupdate="updateHistoryCommands()"/>
|
||||
</commands>
|
||||
|
||||
<broadcasterset id="broadcasterset">
|
||||
|
@ -64,6 +71,8 @@
|
|||
<broadcaster id="cmd_copy"/>
|
||||
<broadcaster id="cmd_delete"/>
|
||||
<broadcaster id="cmd_selectAll"/>
|
||||
<broadcaster id="cmd_deleteByHostname" oncommand="goDoCommand('cmd_deleteByHostname');"/>
|
||||
<broadcaster id="cmd_deleteByDomain" oncommand="goDoCommand('cmd_deleteByDomain');"/>
|
||||
</broadcasterset>
|
||||
<keyset id="keyset">
|
||||
<!-- File Menu -->
|
||||
|
@ -101,6 +110,8 @@
|
|||
<menuitem id="menu_cut"/>
|
||||
<menuitem id="menu_copy"/>
|
||||
<menuitem id="menu_delete"/>
|
||||
<menuitem id="menu_deleteByHostname" observes="cmd_deleteByHostname"/>
|
||||
<menuitem id="menu_deleteByDomain" observes="cmd_deleteByDomain"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="menu_selectAll"/>
|
||||
<menuseparator/>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
datasources="rdf:history rdf:localsearch"
|
||||
flex="1"
|
||||
multiple="true"
|
||||
onselect="historyOnSelect(event)"
|
||||
ondraggesture="nsDragAndDrop.startDrag(event, historyDNDObserver);">
|
||||
|
||||
<template>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
deleteHost=Delete all from %S
|
||||
deleteDomain=Delete entire domain %S
|
||||
deleteHostNoSelection=Delete host
|
||||
deleteDomainNoSelection=Delete domain
|
|
@ -53,6 +53,8 @@
|
|||
#include "prtime.h"
|
||||
#include "rdf.h"
|
||||
|
||||
#include "nsIURL.h"
|
||||
|
||||
#include "nsInt64.h"
|
||||
#include "nsMorkCID.h"
|
||||
#include "nsIMdbFactoryFactory.h"
|
||||
|
@ -75,9 +77,6 @@ nsIRDFResource* nsGlobalHistory::kNC_HistoryRoot;
|
|||
nsIRDFResource* nsGlobalHistory::kNC_HistoryBySite;
|
||||
nsIRDFResource* nsGlobalHistory::kNC_HistoryByDate;
|
||||
|
||||
#ifdef DEBUG_sspitzer
|
||||
#define DEBUG_LAST_PAGE_VISITED 1
|
||||
#endif /* DEBUG_sspitzer */
|
||||
|
||||
#define PREF_BROWSER_HISTORY_LAST_PAGE_VISITED "browser.history.last_page_visited"
|
||||
#define PREF_BROWSER_HISTORY_EXPIRE_DAYS "browser.history_expire_days"
|
||||
|
@ -87,6 +86,7 @@ nsIRDFResource* nsGlobalHistory::kNC_HistoryByDate;
|
|||
|
||||
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
||||
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
|
||||
static NS_DEFINE_CID(kStandardUrlCID, NS_STANDARDURL_CID);
|
||||
|
||||
struct matchExpiration_t {
|
||||
PRInt64 *expirationDate;
|
||||
|
@ -97,6 +97,13 @@ struct matchUrl_t {
|
|||
const char *url;
|
||||
};
|
||||
|
||||
struct matchHost_t {
|
||||
const char *host;
|
||||
PRBool entireDomain; // should we delete the entire domain?
|
||||
nsGlobalHistory *history;
|
||||
nsIURL* cachedUrl;
|
||||
};
|
||||
|
||||
static nsresult
|
||||
PRInt64ToChars(const PRInt64& aValue, char* aBuf, PRInt32 aSize)
|
||||
{
|
||||
|
@ -153,7 +160,7 @@ CharsToPRInt64(const char* aBuf, PRUint32 aCount, PRInt64* aResult)
|
|||
|
||||
|
||||
PRBool
|
||||
nsGlobalHistory::matchExpiration(nsIMdbRow *row, PRInt64* expirationDate)
|
||||
nsGlobalHistory::MatchExpiration(nsIMdbRow *row, PRInt64* expirationDate)
|
||||
{
|
||||
mdb_err err;
|
||||
nsresult rv;
|
||||
|
@ -174,7 +181,7 @@ static PRBool
|
|||
matchExpirationCallback(nsIMdbRow *row, void *aClosure)
|
||||
{
|
||||
matchExpiration_t *expires = (matchExpiration_t*)aClosure;
|
||||
return expires->history->matchExpiration(row, expires->expirationDate);
|
||||
return expires->history->MatchExpiration(row, expires->expirationDate);
|
||||
}
|
||||
|
||||
static PRBool
|
||||
|
@ -183,6 +190,12 @@ matchAllCallback(nsIMdbRow *row, void *aClosure)
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
matchHostCallback(nsIMdbRow *row, void *aClosure)
|
||||
{
|
||||
matchHost_t *hostInfo = (matchHost_t*)aClosure;
|
||||
return hostInfo->history->MatchHost(row, hostInfo);
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsMdbTableEnumerator::nsMdbTableEnumerator()
|
||||
|
@ -687,6 +700,7 @@ nsGlobalHistory::RemovePage(const char *aURL)
|
|||
mdb_err err;
|
||||
nsresult rv;
|
||||
|
||||
if (!mTable) return NS_ERROR_NOT_INITIALIZED;
|
||||
// find the old row, ignore it if we don't have it
|
||||
nsMdbPtr<nsIMdbRow> row(mEnv);
|
||||
rv = FindUrl(aURL, getter_Acquires(row));
|
||||
|
@ -709,6 +723,61 @@ nsGlobalHistory::RemovePage(const char *aURL)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalHistory::RemovePagesFromHost(const char *aHost, PRBool aEntireDomain)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURL> url =
|
||||
do_CreateInstance(kStandardUrlCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
matchHost_t hostInfo;
|
||||
hostInfo.history = this;
|
||||
hostInfo.entireDomain = aEntireDomain;
|
||||
hostInfo.host = aHost;
|
||||
|
||||
hostInfo.cachedUrl = url;
|
||||
return RemoveMatchingRows(matchHostCallback, (void *)&hostInfo, PR_TRUE);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsGlobalHistory::MatchHost(nsIMdbRow *aRow,
|
||||
matchHost_t *hostInfo)
|
||||
{
|
||||
mdb_err err;
|
||||
nsresult rv;
|
||||
|
||||
mdbYarn yarn;
|
||||
err = aRow->AliasCellYarn(mEnv, kToken_URLColumn, &yarn);
|
||||
if (err != 0) return PR_FALSE;
|
||||
|
||||
// do smart zero-termination
|
||||
nsLiteralCString url((const char *)yarn.mYarn_Buf, yarn.mYarn_Fill);
|
||||
rv = hostInfo->cachedUrl->SetSpec(nsPromiseFlatCString(url).get());
|
||||
if (NS_FAILED(rv)) return PR_FALSE;
|
||||
|
||||
nsXPIDLCString urlHost;
|
||||
rv = hostInfo->cachedUrl->GetHost(getter_Copies(urlHost));
|
||||
if (NS_FAILED(rv)) return PR_FALSE;
|
||||
|
||||
if (PL_strcmp(urlHost, hostInfo->host) == 0)
|
||||
return PR_TRUE;
|
||||
|
||||
// now try for a domain match, if necessary
|
||||
if (hostInfo->entireDomain) {
|
||||
// do a reverse-search to match the end of the string
|
||||
char *domain = PL_strrstr(urlHost, hostInfo->host);
|
||||
|
||||
// now verify that we're matching EXACTLY the domain, and
|
||||
// not some random string inside the hostname
|
||||
if (domain && (PL_strcmp(domain, hostInfo->host) == 0))
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalHistory::RemoveAllPages()
|
||||
{
|
||||
|
@ -733,6 +802,8 @@ nsGlobalHistory::RemoveMatchingRows(rowMatchCallback aMatchFunc,
|
|||
err = mTable->GetCount(mEnv, &count);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// XXX tell RDF observers that we're about to do a batch update
|
||||
|
||||
// Begin the batch.
|
||||
int marker;
|
||||
err = mTable->StartBatchChangeHint(mEnv, &marker);
|
||||
|
@ -793,6 +864,9 @@ nsGlobalHistory::RemoveMatchingRows(rowMatchCallback aMatchFunc,
|
|||
// Finish the batch.
|
||||
err = mTable->EndBatchChangeHint(mEnv, &marker);
|
||||
NS_ASSERTION(err == 0, "error ending batch");
|
||||
|
||||
// XXX tell RDF observers that we're done with the batch
|
||||
|
||||
return ( err == 0) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -845,10 +919,6 @@ nsGlobalHistory::SaveLastPageVisited(const char *aURL)
|
|||
|
||||
rv = prefs->SetCharPref(PREF_BROWSER_HISTORY_LAST_PAGE_VISITED, aURL);
|
||||
|
||||
#ifdef DEBUG_LAST_PAGE_VISITED
|
||||
printf("XXX saving last page visited as: %s\n", aURL);
|
||||
#endif /* DEBUG_LAST_PAGE_VISITED */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -868,9 +938,6 @@ nsGlobalHistory::GetLastPageVisited(char **_retval)
|
|||
|
||||
*_retval = nsCRT::strdup((const char *)lastPageVisited);
|
||||
|
||||
#ifdef DEBUG_LAST_PAGE_VISITED
|
||||
printf("XXX getting last page visited as: %s\n", (const char *)lastPageVisited);
|
||||
#endif /* DEBUG_LAST_PAGE_VISITED */
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@ protected:
|
|||
};
|
||||
|
||||
typedef PRBool (*rowMatchCallback)(nsIMdbRow *aRow, void *closure);
|
||||
|
||||
struct matchHost_t;
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsGlobalHistory
|
||||
|
@ -111,7 +113,8 @@ public:
|
|||
virtual ~nsGlobalHistory();
|
||||
|
||||
// these must be public so that the callbacks can call them
|
||||
PRBool matchExpiration(nsIMdbRow *row, PRInt64* expirationDate);
|
||||
PRBool MatchExpiration(nsIMdbRow *row, PRInt64* expirationDate);
|
||||
PRBool MatchHost(nsIMdbRow *row, matchHost_t *hostInfo);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -165,6 +168,7 @@ protected:
|
|||
nsresult SetRowValue(nsIMdbRow *aRow, mdb_column aCol, const PRUnichar *aValue);
|
||||
|
||||
nsresult GetRowValue(nsIMdbRow *aRow, mdb_column aCol, nsAWritableString& aResult);
|
||||
nsresult GetRowValue(nsIMdbRow *aRow, mdb_column aCol, nsAWritableCString& aResult);
|
||||
|
||||
nsresult FindUrl(const char *aURL, nsIMdbRow **aResult);
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ en-US.jar:
|
|||
locale/en-US/communicator/directory/directory.dtd (directory/locale/en-US/directory.dtd)
|
||||
locale/en-US/communicator/history/history.dtd (history/resources/locale/en-US/history.dtd)
|
||||
locale/en-US/communicator/history/historyTreeOverlay.dtd (history/resources/locale/en-US/historyTreeOverlay.dtd)
|
||||
locale/en-US/communicator/history/history.properties (history/resources/locale/en-US/history.properties)
|
||||
locale/en-US/communicator/pref/pref-advanced.dtd (prefwindow/resources/locale/en-US/pref-advanced.dtd)
|
||||
locale/en-US/communicator/pref/pref-appearance.dtd (prefwindow/resources/locale/en-US/pref-appearance.dtd)
|
||||
locale/en-US/communicator/pref/pref-applications.dtd (prefwindow/resources/locale/en-US/pref-applications.dtd)
|
||||
|
|
Загрузка…
Ссылка в новой задаче