Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / script_badge_controller.cc
blob5b6411ca3b856b909f44cf166ec5de8e726abbff
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/script_badge_controller.h"
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
12 #include "chrome/browser/extensions/extension_action.h"
13 #include "chrome/browser/extensions/extension_action_manager.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/extension_system.h"
16 #include "chrome/browser/extensions/tab_helper.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/sessions/session_id.h"
19 #include "chrome/common/extensions/extension_messages.h"
20 #include "content/public/browser/navigation_controller.h"
21 #include "content/public/browser/navigation_details.h"
22 #include "content/public/browser/navigation_entry.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/web_contents.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/extension_set.h"
27 #include "ipc/ipc_message.h"
28 #include "ipc/ipc_message_macros.h"
29 #include "url/gurl.h"
31 namespace extensions {
33 ScriptBadgeController::ScriptBadgeController(content::WebContents* web_contents,
34 TabHelper* tab_helper)
35 : TabHelper::ScriptExecutionObserver(tab_helper),
36 content::WebContentsObserver(web_contents) {
37 registrar_.Add(this,
38 chrome::NOTIFICATION_EXTENSION_UNLOADED,
39 content::Source<Profile>(profile()));
42 ScriptBadgeController::~ScriptBadgeController() {}
44 std::vector<ExtensionAction*> ScriptBadgeController::GetCurrentActions() const {
45 std::vector<ExtensionAction*> result;
46 ExtensionService* service = GetExtensionService();
47 if (!service)
48 return result;
50 ExtensionActionManager* extension_action_manager =
51 ExtensionActionManager::Get(profile());
52 const ExtensionSet* extensions = service->extensions();
53 for (std::set<std::string>::const_iterator
54 it = extensions_in_current_actions_.begin();
55 it != extensions_in_current_actions_.end(); ++it) {
56 const Extension* extension = extensions->GetByID(*it);
57 if (!extension)
58 continue;
59 ExtensionAction* script_badge =
60 extension_action_manager->GetScriptBadge(*extension);
61 if (script_badge)
62 result.push_back(script_badge);
64 return result;
67 void ScriptBadgeController::GetAttentionFor(
68 const std::string& extension_id) {
69 ExtensionAction* script_badge = AddExtensionToCurrentActions(extension_id);
70 if (!script_badge)
71 return;
73 // TODO(jyasskin): Modify the icon's appearance to indicate that the
74 // extension is merely asking for permission to run:
75 // http://crbug.com/133142
76 script_badge->SetAppearance(SessionID::IdForTab(web_contents()),
77 ExtensionAction::WANTS_ATTENTION);
79 NotifyChange();
82 LocationBarController::Action ScriptBadgeController::OnClicked(
83 const std::string& extension_id, int mouse_button) {
84 ExtensionService* service = GetExtensionService();
85 if (!service)
86 return ACTION_NONE;
88 const Extension* extension = service->extensions()->GetByID(extension_id);
89 CHECK(extension);
90 ExtensionAction* script_badge =
91 ExtensionActionManager::Get(profile())->GetScriptBadge(*extension);
92 CHECK(script_badge);
94 switch (mouse_button) {
95 case 1: // left
96 case 2: { // middle
97 extensions::TabHelper::FromWebContents(web_contents())->
98 active_tab_permission_granter()->GrantIfRequested(extension);
100 // Even if clicking the badge doesn't immediately cause the extension to
101 // run script on the page, we want to help users associate clicking with
102 // the extension having permission to modify the page, so we make the icon
103 // full-colored immediately.
104 if (script_badge->SetAppearance(SessionID::IdForTab(web_contents()),
105 ExtensionAction::ACTIVE))
106 NotifyChange();
108 // Fire the scriptBadge.onClicked event.
109 ExtensionActionAPI::ScriptBadgeExecuted(
110 profile(), *script_badge, SessionID::IdForTab(web_contents()));
112 // TODO(jyasskin): The fallback order should be user-defined popup ->
113 // onClicked handler -> default popup.
114 return ACTION_SHOW_SCRIPT_POPUP;
116 case 3: // right
117 // Don't grant access on right clicks, so users can investigate
118 // the extension without danger.
120 return extension->ShowConfigureContextMenus() ?
121 ACTION_SHOW_CONTEXT_MENU : ACTION_NONE;
124 return ACTION_NONE;
127 namespace {
128 std::string JoinExtensionIDs(const ExecutingScriptsMap& ids) {
129 std::vector<std::string> as_vector;
130 for (ExecutingScriptsMap::const_iterator iter = ids.begin();
131 iter != ids.end(); ++iter) {
132 as_vector.push_back(iter->first);
134 return "[" + JoinString(as_vector, ',') + "]";
136 } // namespace
138 void ScriptBadgeController::OnScriptsExecuted(
139 const content::WebContents* web_contents,
140 const ExecutingScriptsMap& extension_ids,
141 int32 on_page_id,
142 const GURL& on_url) {
143 int32 current_page_id = GetPageID();
144 if (on_page_id != current_page_id)
145 return;
147 if (current_page_id < 0) {
148 // Tracking down http://crbug.com/138323.
149 std::string message = base::StringPrintf(
150 "Expected a page ID of %d but there was no navigation entry. "
151 "Extension IDs are %s.",
152 on_page_id,
153 JoinExtensionIDs(extension_ids).c_str());
154 char buf[1024];
155 base::snprintf(buf, arraysize(buf), "%s", message.c_str());
156 LOG(ERROR) << message;
157 return;
160 bool changed = false;
161 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin();
162 it != extension_ids.end(); ++it) {
163 changed |= MarkExtensionExecuting(it->first);
165 if (changed)
166 NotifyChange();
169 Profile* ScriptBadgeController::profile() const {
170 content::WebContents* web_contents = this->web_contents();
171 if (web_contents)
172 return Profile::FromBrowserContext(web_contents->GetBrowserContext());
174 return NULL;
177 ExtensionService* ScriptBadgeController::GetExtensionService() const {
178 Profile* profile = this->profile();
179 if (profile)
180 return ExtensionSystem::Get(profile)->extension_service();
182 return NULL;
185 int32 ScriptBadgeController::GetPageID() {
186 content::NavigationEntry* nav_entry =
187 web_contents()->GetController().GetVisibleEntry();
188 return nav_entry ? nav_entry->GetPageID() : -1;
191 void ScriptBadgeController::NotifyChange() {
192 content::NotificationService::current()->Notify(
193 chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
194 content::Source<Profile>(profile()),
195 content::Details<content::WebContents>(web_contents()));
198 void ScriptBadgeController::DidNavigateMainFrame(
199 const content::LoadCommittedDetails& details,
200 const content::FrameNavigateParams& params) {
201 if (details.is_in_page)
202 return;
203 extensions_in_current_actions_.clear();
206 void ScriptBadgeController::Observe(
207 int type,
208 const content::NotificationSource& source,
209 const content::NotificationDetails& details) {
210 DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_UNLOADED);
211 const Extension* extension =
212 content::Details<UnloadedExtensionInfo>(details)->extension;
213 if (extensions_in_current_actions_.erase(extension->id()))
214 NotifyChange();
217 ExtensionAction* ScriptBadgeController::AddExtensionToCurrentActions(
218 const std::string& extension_id) {
219 if (!extensions_in_current_actions_.insert(extension_id).second)
220 return NULL;
222 ExtensionService* service = GetExtensionService();
223 if (!service)
224 return NULL;
226 const Extension* extension = service->extensions()->GetByID(extension_id);
227 if (!extension)
228 return NULL;
230 return ExtensionActionManager::Get(profile())->GetScriptBadge(*extension);
233 bool ScriptBadgeController::MarkExtensionExecuting(
234 const std::string& extension_id) {
235 ExtensionAction* script_badge = AddExtensionToCurrentActions(extension_id);
236 if (!script_badge)
237 return false;
239 script_badge->SetAppearance(SessionID::IdForTab(web_contents()),
240 ExtensionAction::ACTIVE);
241 return true;
244 } // namespace extensions