Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7077)

Unified Diff: chrome/browser/extensions/extension_history_api.cc

Issue 313001: Implement the Extension History API, v 0.1.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/extension_history_api.cc
===================================================================
--- chrome/browser/extensions/extension_history_api.cc (revision 0)
+++ chrome/browser/extensions/extension_history_api.cc (revision 0)
@@ -0,0 +1,366 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_history_api.h"
+
+#include "base/json/json_writer.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "base/task.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/extension_history_api_constants.h"
+#include "chrome/browser/extensions/extension_message_service.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/notification_service.h"
+
+namespace keys = extension_history_api_constants;
+
+namespace {
+
+double MilliSecondsFromTime(const base::Time& time) {
+ return 1000 * time.ToDoubleT();
+}
+
+void GetHistoryItemDictionary(const history::URLRow& row,
+ DictionaryValue* value) {
+ value->SetString(keys::kIdKey, Int64ToString(row.id()));
+ value->SetString(keys::kUrlKey, row.url().spec());
+ value->SetString(keys::kTitleKey, row.title());
+ value->SetReal(keys::kLastVisitdKey, MilliSecondsFromTime(row.last_visit()));
+ value->SetInteger(keys::kTypedCountKey, row.typed_count());
+ value->SetInteger(keys::kVisitCountKey, row.visit_count());
+}
+
+void AddHistoryNode(const history::URLRow& row, ListValue* list) {
+ DictionaryValue* dict = new DictionaryValue();
+ GetHistoryItemDictionary(row, dict);
+ list->Append(dict);
+}
+
+void GetVisitInfoDictionary(const history::VisitRow& row,
+ DictionaryValue* value) {
+ value->SetString(keys::kIdKey, Int64ToString(row.url_id));
+ value->SetString(keys::kVisitId, Int64ToString(row.visit_id));
+ value->SetReal(keys::kVisitTime, MilliSecondsFromTime(row.visit_time));
+ value->SetString(keys::kReferringVisitId,
+ Int64ToString(row.referring_visit));
+ value->SetInteger(keys::kTransition,
+ row.transition && PageTransition::CORE_MASK);
+}
+
+void AddVisitNode(const history::VisitRow& row, ListValue* list) {
+ DictionaryValue* dict = new DictionaryValue();
+ GetVisitInfoDictionary(row, dict);
+ list->Append(dict);
+}
+
+} // namespace
+
+ExtensionHistoryEventRouter* ExtensionHistoryEventRouter::GetInstance() {
+ return Singleton<ExtensionHistoryEventRouter>::get();
+}
+
+void ExtensionHistoryEventRouter::ObserveProfile(Profile* profile) {
+ NotificationSource source = Source<Profile>(profile);
+ if (profiles_.find(source.map_key()) == profiles_.end())
+ profiles_[source.map_key()] = profile;
+
+ if (registrar_.IsEmpty()) {
+ registrar_.Add(this,
+ NotificationType::HISTORY_URL_VISITED,
+ NotificationService::AllSources());
+ registrar_.Add(this,
+ NotificationType::HISTORY_URLS_DELETED,
+ NotificationService::AllSources());
+ }
+}
+
+void ExtensionHistoryEventRouter::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ ProfileMap::iterator it = profiles_.find(source.map_key());
+ if (it != profiles_.end()) {
+ Profile* profile = it->second;
+ switch (type.value) {
+ case NotificationType::HISTORY_URL_VISITED:
+ HistoryUrlVisited(
+ profile,
+ Details<const history::URLVisitedDetails>(details).ptr());
+ break;
+ case NotificationType::HISTORY_URLS_DELETED:
+ HistoryUrlsRemoved(
+ profile,
+ Details<const history::URLsDeletedDetails>(details).ptr());
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+}
+
+void ExtensionHistoryEventRouter::HistoryUrlVisited(
+ Profile* profile,
+ const history::URLVisitedDetails* details) {
+ ListValue args;
+ DictionaryValue* dict = new DictionaryValue();
+ GetHistoryItemDictionary(details->row, dict);
+ args.Append(dict);
+
+ std::string json_args;
+ base::JSONWriter::Write(&args, false, &json_args);
+ DispatchEvent(profile, keys::kOnVisited, json_args);
+}
+
+void ExtensionHistoryEventRouter::HistoryUrlsRemoved(
+ Profile* profile,
+ const history::URLsDeletedDetails* details) {
+ ListValue args;
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetBoolean(keys::kAllHistoryKey, details->all_history);
+ ListValue* urls = new ListValue();
+ for (std::set<GURL>::const_iterator iterator = details->urls.begin();
+ iterator != details->urls.end();
+ ++iterator) {
+ urls->Append(new StringValue(iterator->spec()));
+ }
+ dict->Set(keys::kUrlsKey, urls);
+ args.Append(dict);
+
+ std::string json_args;
+ base::JSONWriter::Write(&args, false, &json_args);
+ DispatchEvent(profile, keys::kOnVisitRemoved, json_args);
+}
+
+void ExtensionHistoryEventRouter::DispatchEvent(Profile* profile,
+ const char* event_name,
+ const std::string& json_args) {
+ if (profile && profile->GetExtensionMessageService()) {
+ profile->GetExtensionMessageService()->
+ DispatchEventToRenderers(event_name, json_args);
+ }
+}
+
+void HistoryFunction::Run() {
+ if (!RunImpl()) {
+ SendResponse(false);
+ }
+}
+
+bool HistoryFunction::GetUrlFromValue(Value* value, GURL* url) {
+ std::string url_string;
+ if (!value->GetAsString(&url_string)) {
+ bad_message_ = true;
+ return false;
+ }
+
+ GURL temp_url(url_string);
+ if (!temp_url.is_valid()) {
+ error_ = keys::kInvalidUrlError;
+ return false;
+ }
+ url->Swap(&temp_url);
+ return true;
+}
+
+bool HistoryFunction::GetTimeFromValue(Value* value, base::Time* time) {
+ double ms_from_epoch = 0;
+ if (!value->GetAsReal(&ms_from_epoch)) {
+ return false;
+ }
+ // The history service has seconds resolution, while javascript Date() has
+ // milliseconds resolution.
+ double seconds_from_epoch = ms_from_epoch / 1000;
+ *time = base::Time::FromDoubleT(seconds_from_epoch);
+ return true;
+}
+
+bool HistoryFunctionWithCallback::RunImpl() {
+ AddRef(); // Balanced in SendAysncRepose() and below.
+ bool retval = RunAsyncImpl();
+ if (false == retval)
+ Release();
+ return retval;
+}
+
+void HistoryFunctionWithCallback::SendAsyncResponse() {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &HistoryFunctionWithCallback::SendResponseToCallback));
+}
+
+void HistoryFunctionWithCallback::SendResponseToCallback() {
+ SendResponse(true);
+ Release(); // Balanced in RunImpl().
+}
+
+bool GetVisitsHistoryFunction::RunAsyncImpl() {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* json = static_cast<DictionaryValue*>(args_);
+
+ Value* value;
+ EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
+
+ GURL url;
+ if (!GetUrlFromValue(value, &url))
+ return false;
+
+ HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->QueryURL(url,
+ true, // Retrieve full history of a URL.
+ &cancelable_consumer_,
+ NewCallback(this, &GetVisitsHistoryFunction::QueryComplete));
+
+ return true;
+}
+
+void GetVisitsHistoryFunction::QueryComplete(
+ HistoryService::Handle request_service,
+ bool success,
+ const history::URLRow* url_row,
+ history::VisitVector* visits) {
+ ListValue* list = new ListValue();
+ if (visits && !visits->empty()) {
+ for (history::VisitVector::iterator iterator = visits->begin();
+ iterator != visits->end();
+ ++iterator) {
+ AddVisitNode(*iterator, list);
+ }
+ }
+ result_.reset(list);
+ SendAsyncResponse();
+}
+
+bool SearchHistoryFunction::RunAsyncImpl() {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* json = static_cast<DictionaryValue*>(args_);
+
+ // Initialize the HistoryQuery
+ std::wstring search_text;
+ EXTENSION_FUNCTION_VALIDATE(json->GetString(keys::kSearchKey, &search_text));
+
+ history::QueryOptions options;
+ options.most_recent_visit_only = true;
+ options.SetRecentDayRange(1);
+ options.max_count = 100;
+
+ if (json->HasKey(keys::kStartTimeKey)) { // Optional.
+ Value* value;
+ EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kStartTimeKey, &value));
+ EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &options.begin_time));
+ }
+ if (json->HasKey(keys::kEndTimeKey)) { // Optional.
+ Value* value;
+ EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kEndTimeKey, &value));
+ EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &options.end_time));
+ }
+ if (json->HasKey(keys::kMaxResultsKey)) { // Optional.
+ EXTENSION_FUNCTION_VALIDATE(json->GetInteger(keys::kMaxResultsKey,
+ &options.max_count));
+ }
+
+ HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->QueryHistory(search_text, options, &cancelable_consumer_,
+ NewCallback(this, &SearchHistoryFunction::SearchComplete));
+
+ return true;
+}
+
+void SearchHistoryFunction::SearchComplete(
+ HistoryService::Handle request_handle,
+ history::QueryResults* results) {
+ ListValue* list = new ListValue();
+ if (results && !results->empty()) {
+ for (history::QueryResults::URLResultVector::const_iterator iterator =
+ results->begin();
+ iterator != results->end();
+ ++iterator) {
+ AddHistoryNode(**iterator, list);
+ }
+ }
+ result_.reset(list);
+ SendAsyncResponse();
+}
+
+bool AddUrlHistoryFunction::RunImpl() {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* json = static_cast<DictionaryValue*>(args_);
+
+ Value* value;
+ EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
+
+ GURL url;
+ if (!GetUrlFromValue(value, &url))
+ return false;
+
+ HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->AddPage(url);
+
+ SendResponse(true);
+ return true;
+}
+
+bool DeleteUrlHistoryFunction::RunImpl() {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* json = static_cast<DictionaryValue*>(args_);
+
+ Value* value;
+ EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
+
+ GURL url;
+ if (!GetUrlFromValue(value, &url))
+ return false;
+
+ HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->DeleteURL(url);
+
+ SendResponse(true);
+ return true;
+}
+
+bool DeleteRangeHistoryFunction::RunAsyncImpl() {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* json = static_cast<DictionaryValue*>(args_);
+
+ Value* value = NULL;
+ EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kStartTimeKey, &value));
+ base::Time begin_time;
+ EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &begin_time));
+
+ EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kEndTimeKey, &value));
+ base::Time end_time;
+ EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &end_time));
+
+ HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->ExpireHistoryBetween(
+ begin_time,
+ end_time,
+ &cancelable_consumer_,
+ NewCallback(this, &DeleteRangeHistoryFunction::DeleteComplete));
+
+ return true;
+}
+
+void DeleteRangeHistoryFunction::DeleteComplete() {
+ SendAsyncResponse();
+}
+
+bool DeleteAllHistoryFunction::RunAsyncImpl() {
+ HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->ExpireHistoryBetween(
+ base::Time::FromDoubleT(0), // From the beginning of the epoch.
+ base::Time::Now(), // To the current time.
+ &cancelable_consumer_,
+ NewCallback(this, &DeleteAllHistoryFunction::DeleteComplete));
+
+ return true;
+}
+
+void DeleteAllHistoryFunction::DeleteComplete() {
+ SendAsyncResponse();
+}
Property changes on: chrome\browser\extensions\extension_history_api.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « chrome/browser/extensions/extension_history_api.h ('k') | chrome/browser/extensions/extension_history_api_constants.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698