diff options
-rw-r--r-- | chrome/browser/browsing_data_remover.cc | 4 | ||||
-rw-r--r-- | chrome/browser/browsing_data_remover.h | 4 | ||||
-rw-r--r-- | chrome/browser/dom_ui/history_ui.cc | 28 | ||||
-rw-r--r-- | chrome/browser/dom_ui/history_ui.h | 3 | ||||
-rw-r--r-- | chrome/browser/resources/history.html | 202 |
5 files changed, 163 insertions, 78 deletions
diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc index 507112f..33a0c6d 100644 --- a/chrome/browser/browsing_data_remover.cc +++ b/chrome/browser/browsing_data_remover.cc @@ -34,12 +34,13 @@ void RunnableMethodTraits<BrowsingDataRemover>::ReleaseCallee( BrowsingDataRemover* remover) { } +bool BrowsingDataRemover::removing_ = false; + BrowsingDataRemover::BrowsingDataRemover(Profile* profile, Time delete_begin, Time delete_end) : profile_(profile), delete_begin_(delete_begin), delete_end_(delete_end), - removing_(false), waiting_for_keywords_(false), waiting_for_clear_history_(false), waiting_for_clear_cache_(false) { @@ -180,6 +181,7 @@ void BrowsingDataRemover::NotifyAndDeleteIfDone() { if (!all_done()) return; + removing_ = false; FOR_EACH_OBSERVER(Observer, observer_list_, OnBrowsingDataRemoverDone()); // History requests aren't happy if you delete yourself from the callback. diff --git a/chrome/browser/browsing_data_remover.h b/chrome/browser/browsing_data_remover.h index 4affab2..96c8305 100644 --- a/chrome/browser/browsing_data_remover.h +++ b/chrome/browser/browsing_data_remover.h @@ -50,6 +50,8 @@ class BrowsingDataRemover : public NotificationObserver { // Called when history deletion is done. void OnHistoryDeletionDone(); + static bool is_removing() { return removing_; } + private: // NotificationObserver method. Callback when TemplateURLModel has finished // loading. Deletes the entries from the model, and if we're not waiting on @@ -86,7 +88,7 @@ class BrowsingDataRemover : public NotificationObserver { const base::Time delete_end_; // True if Remove has been invoked. - bool removing_; + static bool removing_; // True if we're waiting for the TemplateURLModel to finish loading. bool waiting_for_keywords_; diff --git a/chrome/browser/dom_ui/history_ui.cc b/chrome/browser/dom_ui/history_ui.cc index 0f735d4..9bc5d61 100644 --- a/chrome/browser/dom_ui/history_ui.cc +++ b/chrome/browser/dom_ui/history_ui.cc @@ -10,6 +10,7 @@ #include "base/thread.h" #include "base/time.h" #include "base/time_format.h" +#include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/history/history_types.h" @@ -117,11 +118,13 @@ BrowsingHistoryHandler::BrowsingHistoryHandler(DOMUI* dom_ui) } BrowsingHistoryHandler::~BrowsingHistoryHandler() { + cancelable_consumer_.CancelAllRequests(); + NotificationService* service = NotificationService::current(); service->RemoveObserver(this, NotificationType::HISTORY_URLS_DELETED, Source<Profile>(dom_ui_->get_profile())); - if (remover_) + if (remover_.get()) remover_->RemoveObserver(this); } @@ -179,6 +182,11 @@ void BrowsingHistoryHandler::HandleSearchHistory(const Value* value) { } void BrowsingHistoryHandler::HandleDeleteDay(const Value* value) { + if (BrowsingDataRemover::is_removing()) { + dom_ui_->CallJavascriptFunction(L"deleteFailed"); + return; + } + // Anything in-flight is invalid. cancelable_consumer_.CancelAllRequests(); @@ -190,13 +198,10 @@ void BrowsingHistoryHandler::HandleDeleteDay(const Value* value) { Time begin_time = time.LocalMidnight(); Time end_time = begin_time + TimeDelta::FromDays(1); - if (!remover_) { - remover_ = new BrowsingDataRemover(dom_ui_->get_profile(), - begin_time, - end_time); - remover_->AddObserver(this); - } - + remover_.reset(new BrowsingDataRemover(dom_ui_->get_profile(), + begin_time, + end_time)); + remover_->AddObserver(this); remover_->Remove(BrowsingDataRemover::REMOVE_HISTORY | BrowsingDataRemover::REMOVE_COOKIES | BrowsingDataRemover::REMOVE_CACHE); @@ -204,6 +209,8 @@ void BrowsingHistoryHandler::HandleDeleteDay(const Value* value) { void BrowsingHistoryHandler::OnBrowsingDataRemoverDone() { dom_ui_->CallJavascriptFunction(L"deleteComplete"); + remover_->RemoveObserver(this); + remover_.release(); } void BrowsingHistoryHandler::QueryComplete( @@ -247,7 +254,8 @@ void BrowsingHistoryHandler::QueryComplete( base::TimeFormatShortDate(page.visit_time())); page_value->SetString(L"snippet", page.snippet().text()); } - + page_value->SetBoolean(L"starred", + dom_ui_->get_profile()->GetBookmarkModel()->IsBookmarked(page.url())); results_value.Append(page_value); } @@ -370,6 +378,6 @@ GURL HistoryUI::GetBaseURL() { // static const GURL HistoryUI::GetHistoryURLWithSearchText( const std::wstring& text) { - return GURL(GetBaseURL().spec() + "/?q=" + + return GURL(GetBaseURL().spec() + "#q=" + EscapeQueryParamValue(WideToUTF8(text))); } diff --git a/chrome/browser/dom_ui/history_ui.h b/chrome/browser/dom_ui/history_ui.h index d6bed47..cc643b1 100644 --- a/chrome/browser/dom_ui/history_ui.h +++ b/chrome/browser/dom_ui/history_ui.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_DOM_UI_HISTORY_UI_H__ #define CHROME_BROWSER_DOM_UI_HISTORY_UI_H__ +#include "base/scoped_ptr.h" #include "chrome/browser/browsing_data_remover.h" #include "chrome/browser/dom_ui/chrome_url_data_manager.h" #include "chrome/browser/dom_ui/dom_ui.h" @@ -70,7 +71,7 @@ class BrowsingHistoryHandler : public DOMMessageHandler, std::wstring search_text_; // Browsing history remover - BrowsingDataRemover* remover_; + scoped_ptr<BrowsingDataRemover> remover_; // Our consumer for the history service. CancelableRequestConsumerTSimple<PageUsageData*> cancelable_consumer_; diff --git a/chrome/browser/resources/history.html b/chrome/browser/resources/history.html index 4324d2c..0b1e9b6 100644 --- a/chrome/browser/resources/history.html +++ b/chrome/browser/resources/history.html @@ -15,12 +15,20 @@ var BROWSING_GAP_TIME = 15 * 60 * 1000; function $(o) {return document.getElementById(o);} +function createElementWithClassName(type, className) { + var elm = document.createElement(type); + elm.className = className; + return elm; +} + // TODO(glen): Get rid of these global references, replace with a controller // or just make the classes own more of the page. var historyModel; var historyView; var localStrings; var pageState; +var deleteQueue = []; +var deleteInFlight = false; /////////////////////////////////////////////////////////////////////////////// // localStrings: @@ -74,6 +82,7 @@ function Page(result, continued, model) { this.model_ = model; this.title_ = result.title; this.url_ = result.url; + this.starred_ = result.starred; this.snippet_ = result.snippet || ""; this.changed = false; @@ -96,65 +105,69 @@ function Page(result, continued, model) { // Page, Public: -------------------------------------------------------------- /** - * @return {string} Gets the HTML representation of the page + * @return {DOMObject} Gets the DOM representation of the page * for use in browse results. */ -Page.prototype.getBrowseResultHTML = function() { - return '<div class="entry">' + - '<div class="time">' + - this.dateTimeOfDay + - '</div>' + - this.getTitleHTML_() + - '</div>'; +Page.prototype.getBrowseResultDOM = function() { + var node = createElementWithClassName('div', 'entry'); + var time = createElementWithClassName('div', 'time'); + time.appendChild(document.createTextNode(this.dateTimeOfDay)); + node.appendChild(time); + node.appendChild(this.getTitleDOM_()); + return node; } /** - * @return {string} Gets the HTML representation of the page for + * @return {DOMObject} Gets the DOM representation of the page for * use in search results. */ -Page.prototype.getSearchResultHTML = function() { - return '<tr class="entry"><td valign="top">' + - '<div class="time">' + - this.dateShort + - '</div>' + - '</td><td valign="top">' + - this.getTitleHTML_() + - '<div class="snippet">' + - this.getHighlightedSnippet_() + - '</div>' + - '</td></tr>'; +Page.prototype.getSearchResultDOM = function() { + var row = createElementWithClassName('tr', 'entry'); + var datecell = createElementWithClassName('td', 'time'); + datecell.appendChild(document.createTextNode(this.dateShort)); + row.appendChild(datecell); + + var titleCell = document.createElement('td'); + titleCell.valign = 'top'; + titleCell.appendChild(this.getTitleDOM_()); + var snippet = createElementWithClassName('div', 'snippet'); + snippet.appendChild(document.createTextNode(this.snippet_)); + this.highlightNodeContent_(snippet); + titleCell.appendChild(snippet); + row.appendChild(titleCell); + + return row; } // Page, private: ------------------------------------------------------------- /** - * @return {string} The page's snippet highlighted with the model's - * current search term. + * Highlights the content of a node with the current search text. + * @param {DOMObject} node to highlight */ -Page.prototype.getHighlightedSnippet_ = function() { - return Page.getHighlightedText_(this.snippet_, this.model_.getSearchText()); +Page.prototype.highlightNodeContent_ = function(node) { + node.innerHTML = Page.getHighlightedText_(node.innerHTML, + this.model_.getSearchText()); } /** - * @return {string} Gets the page's title highlighted with the - * model's current search term. + * @return {DOMObject} DOM representation for the title block. */ -Page.prototype.getHighlightedTitle_ = function() { - return Page.getHighlightedText_(this.title_, this.model_.getSearchText()); -} +Page.prototype.getTitleDOM_ = function() { + var node = document.createElement('div'); + node.className = 'title'; + var link = document.createElement('a'); + link.href = this.url_; + link.style.backgroundImage = 'url(chrome-ui://favicon/' + this.url_ + ')'; + link.appendChild(document.createTextNode(this.title_)); + this.highlightNodeContent_(link); -/** - * @return {string} HTML for the title block. - */ -Page.prototype.getTitleHTML_ = function() { - return '<div class="title">' + - '<a ' + - 'href="' + this.url_ + '" ' + - 'style="background-image:url(chrome-ui://favicon/' + - this.url_ + ')" ' + - '>' + - this.getHighlightedTitle_() + - '</a>' + - '</div>'; + node.appendChild(link); + + if (this.starred_) { + node.appendChild(createElementWithClassName('div', 'starred')); + } + + return node; } // Page, private, static: ----------------------------------------------------- @@ -245,6 +258,7 @@ HistoryModel.prototype.getSearchText = function() { */ HistoryModel.prototype.requestPage = function(page) { this.requestedPage_ = page; + this.changed = true; this.updateSearch_(); } @@ -476,18 +490,22 @@ HistoryView.prototype.onModelReady = function() { * Update the page with results. */ HistoryView.prototype.displayResults_ = function() { - var output = []; + this.resultDiv_.innerHTML = ''; + var results = this.model_.getNumberedRange( this.pageIndex_ * RESULTS_PER_PAGE, this.pageIndex_ * RESULTS_PER_PAGE + RESULTS_PER_PAGE); if (this.model_.getSearchText()) { - output.push('<table class="results" cellspacing="0" ', - 'cellpadding="0" border="0">'); + var resultTable = createElementWithClassName('table', 'results'); + resultTable.cellSpacing = 0; + resultTable.cellPadding = 0; + resultTable.border = 0; + for (var i = 0, page; page = results[i]; i++) { - output.push(page.getSearchResultHTML()); + resultTable.appendChild(page.getSearchResultDOM()); } - output.push('</table>'); + this.resultDiv_.appendChild(resultTable); } else { var lastTime = Math.infinity; for (var i = 0, page; page = results[i]; i++) { @@ -495,26 +513,33 @@ HistoryView.prototype.displayResults_ = function() { var thisTime = page.time.getTime(); if ((i == 0 && page.continued) || !page.continued) { - output.push('<div class="day">' + page.dateRelativeDay); - - if (i == 0 && page.continued) - output.push(' ' + localStrings.getString('cont')); - - output.push('<a href="#" class="delete-day" ' + - 'onclick="return deleteDay(\'' + - page.time.toString() + '\');">' + - localStrings.getString("deleteday") + '</a>'); - output.push('</div>'); + var day = createElementWithClassName('div', 'day'); + day.appendChild(document.createTextNode(page.dateRelativeDay)); + + if (i == 0 && page.continued) { + day.appendChild(document.createTextNode(' ' + + localStrings.getString('cont'))); + } + + var link = createElementWithClassName('a', 'delete-day'); + link.href = '#'; + link.time = page.time.toString(); + link.onclick = deleteDay; + link.appendChild( + document.createTextNode(localStrings.getString("deleteday"))); + + day.appendChild(link); + this.resultDiv_.appendChild(day); } else if (lastTime - thisTime > BROWSING_GAP_TIME) { - output.push('<div class="gap"></div>'); + this.resultDiv_.appendChild(createElementWithClassName('div', 'gap')); } lastTime = thisTime; - // Draw entry. - output.push(page.getBrowseResultHTML()); + // Add entry. + this.resultDiv_.appendChild(page.getBrowseResultDOM()); } } - this.resultDiv_.innerHTML = output.join(""); + this.displaySummaryBar_(); this.displayNavBar_(); } @@ -664,7 +689,9 @@ PageState.getHashString = function(term, page) { /** * Window onload handler, sets up the page. */ - function load() { +function load() { + $('term').focus(); + localStrings = new LocalStrings($('l10n')); historyModel = new HistoryModel(); historyView = new HistoryView(historyModel); @@ -699,14 +726,36 @@ function setPage(page) { /** * Delete a day from history. + * TODO: Add UI to indicate that something is happening. * @param {number} time A time from the day we wish to delete. */ -function deleteDay(time) { - if (confirm(localStrings.getString("deletedaywarning"))) - chrome.send("deleteDay", [time.toString()]); +function deleteDay() { + var time = this.time; + + // Check to see if item is already being deleted. + for (var i = 0, deleting; deleting = deleteQueue[i]; i++) { + if (deleting == time) + return false; + } + + if (confirm(localStrings.getString("deletedaywarning"))) { + deleteQueue.push(time); + deleteNextInQueue(); + } + return false; } +/** + * Delete the next item in our deletion queue. + */ +function deleteNextInQueue() { + if (!deleteInFlight && deleteQueue.length) { + deleteInFlight = true; + chrome.send("deleteDay", [deleteQueue[0]]); + } +} + /////////////////////////////////////////////////////////////////////////////// // Chrome callbacks: /** @@ -721,6 +770,21 @@ function historyResult(term, results) { */ function deleteComplete() { historyView.reload(); + deleteInFlight = false; + if (deleteQueue.length > 1) { + deleteQueue = deleteQueue.slice(1, deleteQueue.length); + deleteNextInQueue(); + } +} + +/** + * Our history system calls this function if a delete is not ready (e.g. + * another delete is in-progress). + */ +function deleteFailed() { + // The deletion failed - try again later. + deleteInFlight = false; + setTimeout(deleteNextInQueue, 500); } </script> <style type="text/css"> @@ -793,6 +857,14 @@ table.results { .results .time, .results .title { margin-top:18px; } +.starred { + background:url('../../app/theme/star_small.png'); + background-repeat:no-repeat; + display:inline-block; + margin-left:12px; + width:11px; + height:11px; +} .entry .title a { background-repeat:no-repeat; background-size:16px; |