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

Unified Diff: chrome/renderer/extensions/chrome_webstore_bindings.cc

Issue 7795032: Add link URL and success/failure callback parameters to chrome.webstore.install() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review feedback Created 9 years, 3 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/renderer/extensions/chrome_webstore_bindings.cc
diff --git a/chrome/renderer/extensions/chrome_webstore_bindings.cc b/chrome/renderer/extensions/chrome_webstore_bindings.cc
index feba7c4c2fea107a72079e2c403cccb40f819e78..ecc4d57906335fea855ee3b582004a636cd07d62 100644
--- a/chrome/renderer/extensions/chrome_webstore_bindings.cc
+++ b/chrome/renderer/extensions/chrome_webstore_bindings.cc
@@ -4,6 +4,7 @@
#include "chrome/renderer/extensions/chrome_webstore_bindings.h"
+#include "base/lazy_instance.h"
#include "base/string_util.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/renderer/extensions/extension_render_view_helper.h"
@@ -22,8 +23,18 @@ using WebKit::WebFrame;
using WebKit::WebNode;
using WebKit::WebNodeList;
+namespace {
+
+const char kWebstoreV8ExtensionName[] = "v8/ChromeWebstore";
+
const char kWebstoreLinkRelation[] = "chrome-webstore-item";
+const char kPreferredStoreLinkUrlNotAString[] =
+ "The Chrome Web Store item link URL parameter must be a string.";
+const char kSuccessCallbackNotAFunctionError[] =
+ "The success callback parameter must be a function.";
+const char kFailureCallbackNotAFunctionError[] =
+ "The failure callback parameter must be a function.";
const char kNotInTopFrameError[] =
"Chrome Web Store installations can only be started by the top frame.";
const char kNotUserGestureError[] =
@@ -33,21 +44,65 @@ const char kNoWebstoreItemLinkFoundError[] =
const char kInvalidWebstoreItemUrlError[] =
"Invalid Chrome Web Store item URL.";
-namespace extensions_v8 {
+// chrome.webstore.install() calls generate an install ID so that the install's
+// callbacks may be fired when the browser notifies us of install completion
+// (successful or not) via HandleInstallResponse.
+int g_next_install_id = 0;
+
+// Callbacks are kept track of in maps keyed by install ID. Values are weak
+// references to functions. Entries are automatically removed when functions
+// get garbage collected.
+typedef std::map<int, v8::Persistent<v8::Function> > CallbackMap;
+
+base::LazyInstance<CallbackMap> g_success_callbacks(base::LINKER_INITIALIZED);
+base::LazyInstance<CallbackMap> g_failure_callbacks(base::LINKER_INITIALIZED);
+
+// Extra data to be passed to MakeWeak/RemoveFromCallbackMap to know which entry
+// to remove from which map.
+struct CallbackMapData {
+ CallbackMap* callback_map;
+ int install_id;
+};
+
+// Disposes of a callback function and its corresponding entry in the callback
+// map.
+static void RemoveFromCallbackMap(v8::Persistent<v8::Value> context,
+ void* data) {
+ CallbackMapData* callback_map_data = static_cast<CallbackMapData*>(data);
+ callback_map_data->callback_map->erase(callback_map_data->install_id);
+ delete callback_map_data;
+ context.Dispose();
+}
-static const char* const kWebstoreExtensionName = "v8/ChromeWebstore";
+// Adds |callback_param| (assumed to be a function) to |callback_map| under the
+// |install_id| key. Will be removed from the map when the value is about to be
+// GCed.
+static void AddToCallbackMap(int install_id,
+ v8::Local<v8::Value> callback_param,
+ CallbackMap* callback_map) {
+ CHECK(callback_param->IsFunction());
+ CallbackMapData* callback_map_data = new CallbackMapData();
+ callback_map_data->install_id = install_id;
+ callback_map_data->callback_map = callback_map;
-class ChromeWebstoreExtensionWrapper : public v8::Extension {
+ v8::Local<v8::Function> function = v8::Function::Cast(*callback_param);
+ v8::Persistent<v8::Function> wrapper =
+ v8::Persistent<v8::Function>::New(function);
+ (*callback_map)[install_id] = wrapper;
+ wrapper.MakeWeak(callback_map_data, RemoveFromCallbackMap);
+}
+
+} // anonymous namespace
+
+class ExtensionImpl : public v8::Extension {
public:
- ChromeWebstoreExtensionWrapper() :
+ ExtensionImpl() :
v8::Extension(
- kWebstoreExtensionName,
- "var chrome;"
- "if (!chrome)"
- " chrome = {};"
+ kWebstoreV8ExtensionName,
+ "var chrome = chrome || {};"
"if (!chrome.webstore) {"
" chrome.webstore = new function() {"
- " native function Install();"
+ " native function Install(preferredStoreUrl, onSuccess, onFailure);"
" this.install = Install;"
" };"
"}") {
@@ -71,16 +126,46 @@ class ChromeWebstoreExtensionWrapper : public v8::Extension {
if (!render_view)
return v8::Undefined();
+ std::string preferred_store_link_url;
+ if (args.Length() >= 1 && !args[0]->IsUndefined()) {
+ if (args[0]->IsString()) {
+ preferred_store_link_url = std::string(*v8::String::Utf8Value(args[0]));
+ } else {
+ v8::ThrowException(v8::String::New(kPreferredStoreLinkUrlNotAString));
+ return v8::Undefined();
+ }
+ }
+
std::string webstore_item_id;
std::string error;
- if (GetWebstoreItemIdFromFrame(frame, &webstore_item_id, &error)) {
- ExtensionRenderViewHelper* helper =
- ExtensionRenderViewHelper::Get(render_view);
- helper->InlineWebstoreInstall(webstore_item_id);
- } else {
+ if (!GetWebstoreItemIdFromFrame(
+ frame, preferred_store_link_url, &webstore_item_id, &error)) {
v8::ThrowException(v8::String::New(error.c_str()));
+ return v8::Undefined();
}
+ int install_id = g_next_install_id++;
+ if (args.Length() >= 2 && !args[1]->IsUndefined()) {
+ if (args[1]->IsFunction()) {
+ AddToCallbackMap(install_id, args[1], g_success_callbacks.Pointer());
+ } else {
+ v8::ThrowException(v8::String::New(kSuccessCallbackNotAFunctionError));
+ return v8::Undefined();
+ }
+ }
+ if (args.Length() >= 3 && !args[2]->IsUndefined()) {
+ if (args[2]->IsFunction()) {
+ AddToCallbackMap(install_id, args[2], g_failure_callbacks.Pointer());
+ } else {
+ v8::ThrowException(v8::String::New(kFailureCallbackNotAFunctionError));
+ return v8::Undefined();
+ }
+ }
+
+ ExtensionRenderViewHelper* helper =
+ ExtensionRenderViewHelper::Get(render_view);
+ helper->InlineWebstoreInstall(
+ install_id, webstore_item_id, frame->document().url());
return v8::Undefined();
}
@@ -91,7 +176,8 @@ class ChromeWebstoreExtensionWrapper : public v8::Extension {
// parameter will be populated with the ID. On failure, false will be returned
// and |error| will be populated with the error.
static bool GetWebstoreItemIdFromFrame(
- WebFrame* frame, std::string* webstore_item_id, std::string* error) {
+ WebFrame* frame, const std::string& preferred_store_link_url,
+ std::string* webstore_item_id, std::string* error) {
if (frame != frame->top()) {
*error = kNotInTopFrameError;
return false;
@@ -132,6 +218,12 @@ class ChromeWebstoreExtensionWrapper : public v8::Extension {
continue;
std::string webstore_url_string(elem.getAttribute("href").utf8());
+
+ if (!preferred_store_link_url.empty() &&
+ preferred_store_link_url != webstore_url_string) {
+ continue;
+ }
+
GURL webstore_url = GURL(webstore_url_string);
if (!webstore_url.is_valid()) {
*error = kInvalidWebstoreItemUrlError;
@@ -170,8 +262,27 @@ class ChromeWebstoreExtensionWrapper : public v8::Extension {
}
};
+// static
v8::Extension* ChromeWebstoreExtension::Get() {
- return new ChromeWebstoreExtensionWrapper();
+ return new ExtensionImpl();
}
-} // namespace extensions_v8
+// static
+void ChromeWebstoreExtension::HandleInstallResponse(int install_id,
+ bool success,
+ const std::string& error) {
+ CallbackMap* callback_map =
+ success ? g_success_callbacks.Pointer() : g_failure_callbacks.Pointer();
+ CallbackMap::iterator iter = callback_map->find(install_id);
+
+ if (iter == callback_map->end() || iter->second.IsEmpty()) return;
+ const v8::Persistent<v8::Function>& function = (*iter).second;
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(function->CreationContext());
+ v8::Handle<v8::Value> argv[1];
+ argv[0] = v8::String::New(error.c_str());
+ function->Call(v8::Object::New(), arraysize(argv), argv);
+
+ callback_map->erase(iter);
+}
« no previous file with comments | « chrome/renderer/extensions/chrome_webstore_bindings.h ('k') | chrome/renderer/extensions/extension_render_view_helper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698