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

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: 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..31d387d6507344f1b5cfdff1247387dec8d6f5a3 100644
--- a/chrome/renderer/extensions/chrome_webstore_bindings.cc
+++ b/chrome/renderer/extensions/chrome_webstore_bindings.cc
@@ -22,8 +22,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 +43,66 @@ 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 next_install_id;
+
+// 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;
+
+CallbackMap success_callbacks;
Aaron Boodman 2011/09/06 23:24:32 Consider making a PendingWebstoreInstall class tha
Mihai Parparita -not on Chrome 2011/09/07 00:05:03 As discussed, this isn't that straightforward sinc
+CallbackMap failure_callbacks;
Aaron Boodman 2011/09/06 23:24:32 Static non-pod variables are not allowed in Chromi
Mihai Parparita -not on Chrome 2011/09/07 00:05:03 Done.
-static const char* const kWebstoreExtensionName = "v8/ChromeWebstore";
+// Extra data to be passed to MakeWeak/CallbackMapWeakReferenceCallback 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 CallbackMapWeakReferenceCallback(
+ 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();
+}
-class ChromeWebstoreExtensionWrapper : public v8::Extension {
+// 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;
+
+ 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, CallbackMapWeakReferenceCallback);
+}
+
+} // 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 = next_install_id++;
+ if (args.Length() >= 2 && !args[1]->IsUndefined()) {
+ if (args[1]->IsFunction()) {
+ AddToCallbackMap(install_id, args[1], &success_callbacks);
+ } 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], &failure_callbacks);
+ } 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,25 @@ 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) {
+ const CallbackMap& callback_map =
+ success ? success_callbacks : failure_callbacks;
+ CallbackMap::const_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);
Aaron Boodman 2011/09/06 23:24:32 You can remove the function from the map after thi
Mihai Parparita -not on Chrome 2011/09/07 00:05:03 Done.
+}
« 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