diff options
Diffstat (limited to 'chrome')
18 files changed, 250 insertions, 67 deletions
diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc index 66bd9e3..d3ba09a 100644 --- a/chrome/browser/extensions/extension_page_actions_module.cc +++ b/chrome/browser/extensions/extension_page_actions_module.cc @@ -31,6 +31,18 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) { std::string url; EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kUrlKey, &url)); + std::string title; + int icon_id = 0; + if (enable) { + // Both of those are optional. + if (action->HasKey(keys::kTitleKey)) + EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kTitleKey, &title)); + if (action->HasKey(keys::kIconIdKey)) { + EXTENSION_FUNCTION_VALIDATE(action->GetInteger(keys::kIconIdKey, + &icon_id)); + } + } + // Find the TabContents that contains this tab id. TabContents* contents = NULL; ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL, &contents, NULL); @@ -66,7 +78,7 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) { } // Set visibility and broadcast notifications that the UI should be updated. - contents->SetPageActionEnabled(page_action, enable); + contents->SetPageActionEnabled(page_action, enable, title, icon_id); contents->NotifyNavigationStateChanged(TabContents::INVALIDATE_PAGE_ACTIONS); return true; diff --git a/chrome/browser/extensions/extension_page_actions_module_constants.cc b/chrome/browser/extensions/extension_page_actions_module_constants.cc index e58264b..2b54f1b 100755 --- a/chrome/browser/extensions/extension_page_actions_module_constants.cc +++ b/chrome/browser/extensions/extension_page_actions_module_constants.cc @@ -8,6 +8,8 @@ namespace extension_page_actions_module_constants { const wchar_t kTabIdKey[] = L"tabId"; const wchar_t kUrlKey[] = L"url"; +const wchar_t kTitleKey[] = L"title"; +const wchar_t kIconIdKey[] = L"iconId"; const char kNoExtensionError[] = "No extension with id: *."; const char kNoTabError[] = "No tab with id: *."; diff --git a/chrome/browser/extensions/extension_page_actions_module_constants.h b/chrome/browser/extensions/extension_page_actions_module_constants.h index bf28b9f..91db0d8 100755 --- a/chrome/browser/extensions/extension_page_actions_module_constants.h +++ b/chrome/browser/extensions/extension_page_actions_module_constants.h @@ -12,6 +12,8 @@ namespace extension_page_actions_module_constants { // Keys. extern const wchar_t kTabIdKey[]; extern const wchar_t kUrlKey[]; +extern const wchar_t kTitleKey[]; +extern const wchar_t kIconIdKey[]; // Error messages. extern const char kNoExtensionError[]; diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index df59e04..b44c630 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -753,12 +753,16 @@ Extension* ExtensionsServiceBackend::LoadExtension( for (PageActionMap::const_iterator i(page_actions.begin()); i != page_actions.end(); ++i) { PageAction* page_action = i->second; - FilePath path = page_action->icon_path(); - if (!file_util::PathExists(path)) { - ReportExtensionLoadError(extension_path, - StringPrintf("Could not load icon '%s' for page action.", - WideToUTF8(path.ToWStringHack()).c_str())); - return NULL; + const std::vector<FilePath>& icon_paths = page_action->icon_paths(); + for (std::vector<FilePath>::const_iterator iter = icon_paths.begin(); + iter != icon_paths.end(); ++iter) { + FilePath path = *iter; + if (!file_util::PathExists(path)) { + ReportExtensionLoadError(extension_path, + StringPrintf("Could not load icon '%s' for page action.", + WideToUTF8(path.ToWStringHack()).c_str())); + return NULL; + } } } diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index b195151..3b75dcc 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -40,7 +40,7 @@ const char* const good0 = "behllobkkfkfnphdnhnkndlbkcpglgmj"; const char* const good1 = "hpiknbiabeeppbpihjehijgoemciehgk"; const char* const good2 = "bjafgdebaacbbbecmhlhpofkepfkgcpa"; const char* const good_crx = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; -const char* const page_action = "kemkhnabegjkabakmlcaafgikalipenj"; +const char* const page_action = "obcimlgaoabeegjmmpldobjndiealpln"; const char* const theme_crx = "iamefpfkojoapidjnbafmgkgncegbkad"; const char* const theme2_crx = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf"; @@ -654,7 +654,9 @@ TEST_F(ExtensionsServiceTest, CleanupOnStartup) { ASSERT_FALSE(file_util::PathExists(vers)); } -// Test installing extensions. +// Test installing extensions. This test tries to install few extensions using +// crx files. If you need to change those crx files, feel free to repackage +// them, throw away the key used and change the id's above. TEST_F(ExtensionsServiceTest, InstallExtension) { InitializeEmptyExtensionsService(); @@ -690,6 +692,7 @@ TEST_F(ExtensionsServiceTest, InstallExtension) { // Bad signature. path = extensions_path.AppendASCII("bad_signature.crx"); InstallExtension(path, false); + ValidatePrefKeyCount(pref_count); // 0-length extension file. path = extensions_path.AppendASCII("not_an_extension.crx"); diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index c4906ce..0884317 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -565,23 +565,31 @@ void TabContents::SetIsCrashed(bool state) { } void TabContents::SetPageActionEnabled(const PageAction* page_action, - bool enable) { + bool enable, + const std::string& title, + int icon_id) { DCHECK(page_action); - if (enable == IsPageActionEnabled(page_action)) - return; // Don't need to do anything more. + if (!enable && + enabled_page_actions_.end() == enabled_page_actions_.find(page_action)) { + return; // Don't need to disable twice. + } - if (enable) - enabled_page_actions_.insert(page_action); - else + if (enable) { + enabled_page_actions_[page_action].reset( + new PageActionState(title, icon_id)); + } else { enabled_page_actions_.erase(page_action); + } } -bool TabContents::IsPageActionEnabled(const PageAction* page_action) { - DCHECK(page_action); - return enabled_page_actions_.end() != enabled_page_actions_.find(page_action); -} +const PageActionState* TabContents::GetPageActionState( + const PageAction* page_action) { + if (enabled_page_actions_.end() == enabled_page_actions_.find(page_action)) + return NULL; + return enabled_page_actions_[page_action].get(); +} void TabContents::NotifyNavigationStateChanged(unsigned changed_flags) { if (delegate_) diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 5b4fa7b..f81c725 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -32,6 +32,7 @@ #include "chrome/common/gears_api.h" #include "chrome/common/navigation_types.h" #include "chrome/common/notification_registrar.h" +#include "chrome/common/page_action.h" #include "chrome/common/property_bag.h" #include "chrome/common/renderer_preferences.h" #include "net/base/load_states.h" @@ -254,10 +255,17 @@ class TabContents : public PageNavigator, void SetIsCrashed(bool state); // Adds/removes a page action to the list of page actions that are active in + // this tab. The parameter |title| (if not empty) can be used to override the + // page action title for this tab and |icon_id| specifies an icon index + // (defined in the manifest) to use instead of the first icon (for this tab). + void SetPageActionEnabled(const PageAction* page_action, bool enable, + const std::string& title, int icon_id); + + // Returns the page action state for this tab. The pair returns contains + // the title (string) for the page action and the icon index to use (int). + // If this function returns NULL it means the page action is not enabled for // this tab. - void SetPageActionEnabled(const PageAction* page_action, bool enable); - // Checks to see if the PageAction should be visible in this tab. - bool IsPageActionEnabled(const PageAction* page_action); + const PageActionState* GetPageActionState(const PageAction* page_action); // Whether the tab is in the process of being destroyed. // Added as a tentative work-around for focus related bug #4633. This allows @@ -1036,10 +1044,12 @@ class TabContents : public PageNavigator, // Data for Page Actions ----------------------------------------------------- - // A set of page actions that are enabled in this tab. This list is cleared - // every time the mainframe navigates and populated by the PageAction - // extension API. - std::set<const PageAction*> enabled_page_actions_; + // A map of page actions that are enabled in this tab (and a state object + // that can be used to override the title and icon used for the page action). + // This map is cleared every time the mainframe navigates and populated by the + // PageAction extension API. + std::map< const PageAction*, linked_ptr<PageActionState> > + enabled_page_actions_; // Data for misc internal state ---------------------------------------------- diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index 7530dee..af8c57f 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -1140,7 +1140,8 @@ void LocationBarView::SecurityImageView::ShowInfoBubble() { class LocationBarView::PageActionImageView::ImageLoadingTracker : public base::RefCountedThreadSafe<ImageLoadingTracker> { public: - explicit ImageLoadingTracker(PageActionImageView* view) : view_(view) { + explicit ImageLoadingTracker(PageActionImageView* view, int image_count) + : view_(view), image_count_(image_count) { AddRef(); // We hold on to a reference to ourself to make sure we don't // get deleted until we get a response from image loading (see // ImageLoadingDone). @@ -1151,16 +1152,20 @@ class LocationBarView::PageActionImageView::ImageLoadingTracker view_ = NULL; } - void OnImageLoaded(SkBitmap* image) { - view_->OnImageLoaded(image); + void OnImageLoaded(SkBitmap* image, int index) { + view_->OnImageLoaded(image, index); delete image; - Release(); // We are no longer needed. + if (--image_count_ == 0) + Release(); // We are no longer needed. } private: // The view that is waiting for the image to load. PageActionImageView* view_; + + // The number of images this ImageTracker should keep track of. + int image_count_; }; // The LoadImageTask is for asynchronously loading the image on the file thread. @@ -1168,16 +1173,24 @@ class LocationBarView::PageActionImageView::ImageLoadingTracker // |callback_loop| to let the caller know the image is done loading. class LocationBarView::PageActionImageView::LoadImageTask : public Task { public: + // Constructor for the LoadImageTask class. |tracker| is the object that + // we use to communicate back to the entity that wants the image after we + // decode it. |path| is the path to load the image from. |index| is an + // identifier for the image that we pass back to the caller. LoadImageTask(ImageLoadingTracker* tracker, - const FilePath& path) + const FilePath& path, + int index) : callback_loop_(MessageLoop::current()), tracker_(tracker), - path_(path) {} + path_(path), + index_(index) {} void ReportBack(SkBitmap* image) { DCHECK(image); callback_loop_->PostTask(FROM_HERE, NewRunnableMethod(tracker_, - &PageActionImageView::ImageLoadingTracker::OnImageLoaded, image)); + &PageActionImageView::ImageLoadingTracker::OnImageLoaded, + image, + index_)); } virtual void Run() { @@ -1223,6 +1236,9 @@ class LocationBarView::PageActionImageView::LoadImageTask : public Task { // The path to the image to load asynchronously. FilePath path_; + + // The index of the icon being loaded. + int index_; }; LocationBarView::PageActionImageView::PageActionImageView( @@ -1233,15 +1249,22 @@ LocationBarView::PageActionImageView::PageActionImageView( owner_(owner), profile_(profile), page_action_(page_action), - tracker_(new ImageLoadingTracker(this)) { + current_tab_id_(-1), + tooltip_(page_action_->name()) { // Load the images this view needs asynchronously on the file thread. We'll // get a call back into OnImageLoaded if the image loads successfully. If not, // the ImageView will have no image and will not appear in the Omnibox. - DCHECK(!page_action->icon_path().empty()); - FilePath path = FilePath(page_action->icon_path()); + DCHECK(!page_action->icon_paths().empty()); + const std::vector<FilePath>& icon_paths = page_action->icon_paths(); + page_action_icons_.resize(icon_paths.size()); + int index = 0; MessageLoop* file_loop = g_browser_process->file_thread()->message_loop(); - file_loop->PostTask(FROM_HERE, - new LoadImageTask(tracker_, page_action->icon_path())); + tracker_ = new ImageLoadingTracker(this, icon_paths.size()); + for (std::vector<FilePath>::const_iterator iter = icon_paths.begin(); + iter != icon_paths.end(); ++iter) { + FilePath path = *iter; + file_loop->PostTask(FROM_HERE, new LoadImageTask(tracker_, path, index++)); + } } LocationBarView::PageActionImageView::~PageActionImageView() { @@ -1259,7 +1282,7 @@ bool LocationBarView::PageActionImageView::OnMousePressed( void LocationBarView::PageActionImageView::ShowInfoBubble() { SkColor text_color = SK_ColorBLACK; - ShowInfoBubbleImpl(ASCIIToWide(page_action_->name()), text_color); + ShowInfoBubbleImpl(ASCIIToWide(tooltip_), text_color); } void LocationBarView::PageActionImageView::UpdateVisibility( @@ -1269,12 +1292,30 @@ void LocationBarView::PageActionImageView::UpdateVisibility( current_tab_id_ = ExtensionTabUtil::GetTabId(contents); current_url_ = url; - SetVisible(contents->IsPageActionEnabled(page_action_)); + const PageActionState* state = contents->GetPageActionState(page_action_); + bool visible = state != NULL; + if (visible) { + // Set the tooltip. + if (state->title().empty()) + tooltip_ = page_action_->name(); + else + tooltip_ = state->title(); + // Set the image. + int index = state->icon_index(); + // The image index (if not within bounds) will be set to the first image. + if (index < 0 || index >= static_cast<int>(page_action_icons_.size())) + index = 0; + ImageView::SetImage(page_action_icons_[index]); + } + SetVisible(visible); } -void LocationBarView::PageActionImageView::OnImageLoaded(SkBitmap* image) { - tracker_ = NULL; // The tracker object will delete itself when we return. - ImageView::SetImage(image); +void LocationBarView::PageActionImageView::OnImageLoaded(SkBitmap* image, + size_t index) { + DCHECK(index < page_action_icons_.size()); + if (index == page_action_icons_.size() - 1) + tracker_ = NULL; // The tracker object will delete itself when we return. + page_action_icons_[index] = *image; owner_->UpdatePageActions(); } diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h index b90693f..97e7eb6 100644 --- a/chrome/browser/views/location_bar_view.h +++ b/chrome/browser/views/location_bar_view.h @@ -332,7 +332,7 @@ class LocationBarView : public LocationBar, void UpdateVisibility(TabContents* contents, GURL url); // A callback for when the image has loaded. - void OnImageLoaded(SkBitmap* image); + void OnImageLoaded(SkBitmap* image, size_t index); private: // We load the images for the PageActions on the file thread. These tasks @@ -350,6 +350,9 @@ class LocationBarView : public LocationBar, // us, it resides in the extension of this particular profile. const PageAction* page_action_; + // The icons representing different states for the page action. + std::vector<SkBitmap> page_action_icons_; + // The object that is waiting for the image loading to complete // asynchronously. ImageLoadingTracker* tracker_; @@ -360,6 +363,9 @@ class LocationBarView : public LocationBar, // The URL we are currently showing the icon for. GURL current_url_; + // The string to show for a tooltip; + std::string tooltip_; + DISALLOW_COPY_AND_ASSIGN(PageActionImageView); }; diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index 33baff8..6bce681 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -55,6 +55,7 @@ const wchar_t* Extension::kContentScriptsKey = L"content_scripts"; const wchar_t* Extension::kCssKey = L"css"; const wchar_t* Extension::kDescriptionKey = L"description"; const wchar_t* Extension::kIconPathKey = L"icon"; +const wchar_t* Extension::kIconPathsKey = L"icons"; const wchar_t* Extension::kJsKey = L"js"; const wchar_t* Extension::kMatchesKey = L"matches"; const wchar_t* Extension::kNameKey = L"name"; @@ -126,10 +127,12 @@ const char* Extension::kInvalidNameError = "Required value 'name' is missing or invalid."; const char* Extension::kInvalidPageActionError = "Invalid value for 'page_actions[*]'."; +const char* Extension::kInvalidPageActionIconPathError = + "Invalid value for 'page_actions[*].icons[*]'."; const char* Extension::kInvalidPageActionsListError = "Invalid value for 'page_actions'."; -const char* Extension::kInvalidPageActionIconPathError = - "Invalid value for 'page_actions[*].icon'."; +const char* Extension::kInvalidPageActionIconPathsError = + "Required value 'page_actions[*].icons' is missing or invalid."; const char* Extension::kInvalidPageActionIdError = "Required value 'id' is missing or invalid."; const char* Extension::kInvalidPageActionTypeValueError = @@ -398,15 +401,31 @@ PageAction* Extension::LoadPageActionHelper( scoped_ptr<PageAction> result(new PageAction()); result->set_extension_id(id()); - // Read the page action |icon|. - std::string icon; - if (!page_action->GetString(kIconPathKey, &icon)) { + ListValue* icons; + // Read the page action |icons|. + if (!page_action->HasKey(kIconPathsKey) || + !page_action->GetList(kIconPathsKey, &icons) || + icons->GetSize() == 0) { *error = ExtensionErrorUtils::FormatErrorMessage( - kInvalidPageActionIconPathError, IntToString(definition_index)); + kInvalidPageActionIconPathsError, IntToString(definition_index)); return NULL; } - FilePath icon_path = path_.AppendASCII(icon); - result->set_icon_path(icon_path); + + int icon_count = 0; + for (ListValue::const_iterator iter = icons->begin(); + iter != icons->end(); ++iter) { + FilePath::StringType path; + if (!(*iter)->GetAsString(&path) || path.empty()) { + *error = ExtensionErrorUtils::FormatErrorMessage( + kInvalidPageActionIconPathError, + IntToString(definition_index), IntToString(icon_count)); + return NULL; + } + + FilePath icon_path = path_.Append(path); + result->AddIconPath(icon_path); + ++icon_count; + } // Read the page action |id|. std::string id; @@ -504,7 +523,7 @@ FilePath Extension::GetResourcePath(const FilePath& extension_path, return ret_val; } -Extension::Extension(const FilePath& path) { +Extension::Extension(const FilePath& path) : is_theme_(false) { DCHECK(path.IsAbsolute()); location_ = INVALID; @@ -939,7 +958,11 @@ std::set<FilePath> Extension::GetBrowserImages() { for (PageActionMap::const_iterator it = page_actions().begin(); it != page_actions().end(); ++it) { - image_paths.insert(it->second->icon_path()); + const std::vector<FilePath>& icon_paths = it->second->icon_paths(); + for (std::vector<FilePath>::const_iterator iter = icon_paths.begin(); + iter != icon_paths.end(); ++iter) { + image_paths.insert(*iter); + } } return image_paths; diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index ec14b0b..1705e12 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -60,6 +60,7 @@ class Extension { static const wchar_t* kCssKey; static const wchar_t* kDescriptionKey; static const wchar_t* kIconPathKey; + static const wchar_t* kIconPathsKey; static const wchar_t* kJsKey; static const wchar_t* kMatchesKey; static const wchar_t* kNameKey; @@ -115,6 +116,7 @@ class Extension { static const char* kInvalidPageActionError; static const char* kInvalidPageActionsListError; static const char* kInvalidPageActionIconPathError; + static const char* kInvalidPageActionIconPathsError; static const char* kInvalidPageActionIdError; static const char* kInvalidPageActionTypeValueError; static const char* kInvalidPermissionsError; diff --git a/chrome/common/page_action.h b/chrome/common/page_action.h index d9ccfea..3331f8e 100644 --- a/chrome/common/page_action.h +++ b/chrome/common/page_action.h @@ -5,8 +5,9 @@ #ifndef CHROME_COMMON_PAGE_ACTION_H_ #define CHROME_COMMON_PAGE_ACTION_H_ -#include <string> #include <map> +#include <string> +#include <vector> #include "base/file_path.h" @@ -34,9 +35,9 @@ class PageAction { std::string name() const { return name_; } void set_name(const std::string& name) { name_ = name; } - FilePath icon_path() const { return icon_path_; } - void set_icon_path(const FilePath& icon_path) { - icon_path_ = icon_path; + const std::vector<FilePath>& icon_paths() const { return icon_paths_; } + void AddIconPath(const FilePath& icon_path) { + icon_paths_.push_back(icon_path); } private: @@ -53,10 +54,31 @@ class PageAction { // The name of the PageAction. std::string name_; - // The icon that represents the PageIcon. - FilePath icon_path_; + // The paths to the icons that this PageIcon can show. + std::vector<FilePath> icon_paths_; }; typedef std::map<std::string, PageAction*> PageActionMap; +// This class keeps track of what values each tab uses to override the default +// values of the PageAction. +class PageActionState { + public: + PageActionState(std::string title, int icon_index) + : title_(title), icon_index_(icon_index) { + } + + std::string title() const { return title_; } + int icon_index() const { return icon_index_; } + + private: + // The title to use. + std::string title_; + + // The icon to use. + int icon_index_; + + DISALLOW_COPY_AND_ASSIGN(PageActionState); +}; + #endif // CHROME_COMMON_PAGE_ACTION_H_ diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index c59e98c..cda253b 100644 --- a/chrome/renderer/renderer_resources.grd +++ b/chrome/renderer/renderer_resources.grd @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- This comment is only here because changes to resources are not picked up -without changes to the corresponding grd file. --> +without changes to the corresponding grd file. --> <grit latest_public_release="0" current_release="1"> <outputs> <output filename="grit/renderer_resources.h" type="rc_header"> diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index 8b4c4bb..2e76723 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -320,7 +320,9 @@ var chrome = chrome || {}; type: "object", properties: { tabId: chrome.types.pInt, - url: chrome.types.str + url: chrome.types.str, + title: chrome.types.optStr, + iconId: chrome.types.optPInt, }, optional: false } diff --git a/chrome/test/data/extensions/page_action.crx b/chrome/test/data/extensions/page_action.crx Binary files differindex 2a397c8..7420c32 100644 --- a/chrome/test/data/extensions/page_action.crx +++ b/chrome/test/data/extensions/page_action.crx diff --git a/chrome/test/data/extensions/samples/subscribe_page_action/background.html b/chrome/test/data/extensions/samples/subscribe_page_action/background.html index e85e5a6..0eeca7e 100644 --- a/chrome/test/data/extensions/samples/subscribe_page_action/background.html +++ b/chrome/test/data/extensions/samples/subscribe_page_action/background.html @@ -1,8 +1,13 @@ <html> +<head> <script> // The Page Action ID. var pageActionId = "RssPageAction"; + // The icons to use. These correspond to the icons listed in the manifest. + var subscribeId = 0; + var alreadySubscribedId = 1; + // The window this Page Action is associated with. var windowId = -1; @@ -15,6 +20,32 @@ // The feed URL found on the page. var feedUrl = ""; + // The URL to use to check if user is subscribed already. + var subscribedUrl = "http://www.google.com/reader/api/0/subscribed?s=feed%2F"; + + // The XMLHttpRequest object that checks if you are already subscribed. + var req; + + // The status of whether you have already subscribed to this feed or not. + var alreadySubscribed = false; + + function EnableIcon(subscribed) { + alreadySubscribed = subscribed; + if (!alreadySubscribed) { + chrome.pageActions.enableForTab( + pageActionId, {tabId: tabId, + url: pageUrl, + title: "Click to subscribe...", + iconId: subscribeId}); + } else { + chrome.pageActions.enableForTab( + pageActionId, {tabId: tabId, + url: pageUrl, + title: "You are already subscribed to this feed", + iconId: alreadySubscribedId}); + } + } + chrome.self.onConnect.addListener(function(port) { windowId = port.tab.windowId; tabId = port.tab.id; @@ -28,17 +59,29 @@ // Let Chrome know that the PageAction needs to be enabled for this tabId // and for the url of this page. if (feedUrl) { - chrome.pageActions.enableForTab(pageActionId, - {tabId: tabId, url: pageUrl}); + EnableIcon(false); // Not subscribed (as far as we know, might change). + + // But also check the server to see if we have already subscribed so + // that we can update the status. + feedUrl = encodeURIComponent(feedUrl); + req = new XMLHttpRequest(); + req.onload = handleResponse; + req.open("GET", subscribedUrl + feedUrl, false); + req.send(null); } }); }); + function handleResponse() { + if (req.responseText == "true") + EnableIcon(true); // true == Already suscribed. + } + // Chrome will call into us when the user clicks on the icon in the OmniBox. chrome.pageActions.onExecute.addListener(function(reply) { chrome.windows.getCurrent(function(window) { chrome.tabs.get(reply.data.tabId, function(tab) { - if (window.focused) { + if (!alreadySubscribed && window.focused) { // We need to know if we are the active window, because the tab may // have moved to another window and we don't want to execute this // action multiple times. @@ -46,7 +89,6 @@ reply.data.tabUrl == pageUrl) { // Create a new tab showing the subscription page with the right // feed URL. - var url = "http://www.google.com/reader/view/feed/" + feedUrl; chrome.tabs.create({url: "subscribe.html?" + feedUrl, windowId: windowId}); } @@ -55,4 +97,5 @@ }); }); </script> +</head> </html> diff --git a/chrome/test/data/extensions/samples/subscribe_page_action/feed-icon-16x16-subscribed.png b/chrome/test/data/extensions/samples/subscribe_page_action/feed-icon-16x16-subscribed.png Binary files differnew file mode 100644 index 0000000..0369a6b37 --- /dev/null +++ b/chrome/test/data/extensions/samples/subscribe_page_action/feed-icon-16x16-subscribed.png diff --git a/chrome/test/data/extensions/samples/subscribe_page_action/manifest.json b/chrome/test/data/extensions/samples/subscribe_page_action/manifest.json index 9c34a50..6a8f225 100644 --- a/chrome/test/data/extensions/samples/subscribe_page_action/manifest.json +++ b/chrome/test/data/extensions/samples/subscribe_page_action/manifest.json @@ -16,7 +16,10 @@ { "id": "RssPageAction", "name": "Subscribe to this feed", - "icon": "feed-icon-16x16.png" + "icons": [ + "feed-icon-16x16.png", + "feed-icon-16x16-subscribed.png" + ] } ] }
\ No newline at end of file |