Home | History | Annotate | Download | only in uber
      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.
      4 
      5 #include "chrome/browser/ui/webui/uber/uber_ui.h"
      6 
      7 #include "base/stl_util.h"
      8 #include "chrome/browser/chrome_notification_types.h"
      9 #include "chrome/browser/extensions/extension_service.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
     12 #include "chrome/browser/ui/webui/extensions/extensions_ui.h"
     13 #include "chrome/browser/ui/webui/options/options_ui.h"
     14 #include "chrome/common/chrome_switches.h"
     15 #include "chrome/common/extensions/manifest_url_handler.h"
     16 #include "chrome/common/url_constants.h"
     17 #include "chrome/grit/chromium_strings.h"
     18 #include "chrome/grit/generated_resources.h"
     19 #include "content/public/browser/navigation_controller.h"
     20 #include "content/public/browser/navigation_entry.h"
     21 #include "content/public/browser/notification_source.h"
     22 #include "content/public/browser/web_contents.h"
     23 #include "content/public/browser/web_ui.h"
     24 #include "content/public/browser/web_ui_data_source.h"
     25 #include "extensions/browser/extension_registry.h"
     26 #include "extensions/common/extension_set.h"
     27 #include "grit/browser_resources.h"
     28 
     29 using content::NavigationController;
     30 using content::NavigationEntry;
     31 using content::RenderViewHost;
     32 using content::WebContents;
     33 
     34 namespace {
     35 
     36 content::WebUIDataSource* CreateUberHTMLSource() {
     37   content::WebUIDataSource* source =
     38       content::WebUIDataSource::Create(chrome::kChromeUIUberHost);
     39 
     40   source->SetUseJsonJSFormatV2();
     41   source->SetJsonPath("strings.js");
     42   source->AddResourcePath("uber.js", IDR_UBER_JS);
     43   source->AddResourcePath("uber_utils.js", IDR_UBER_UTILS_JS);
     44   source->SetDefaultResource(IDR_UBER_HTML);
     45   source->OverrideContentSecurityPolicyFrameSrc("frame-src chrome:;");
     46 
     47   // Hack alert: continue showing "Loading..." until a real title is set.
     48   source->AddLocalizedString("pageTitle", IDS_TAB_LOADING_TITLE);
     49 
     50   source->AddString("extensionsFrameURL", chrome::kChromeUIExtensionsFrameURL);
     51   source->AddString("extensionsHost", chrome::kChromeUIExtensionsHost);
     52   source->AddString("helpFrameURL", chrome::kChromeUIHelpFrameURL);
     53   source->AddString("helpHost", chrome::kChromeUIHelpHost);
     54   source->AddString("historyFrameURL", chrome::kChromeUIHistoryFrameURL);
     55   source->AddString("historyHost", chrome::kChromeUIHistoryHost);
     56   source->AddString("settingsFrameURL", chrome::kChromeUISettingsFrameURL);
     57   source->AddString("settingsHost", chrome::kChromeUISettingsHost);
     58 
     59   return source;
     60 }
     61 
     62 // Determines whether the user has an active extension of the given type.
     63 bool HasExtensionType(Profile* profile, const std::string& extension_type) {
     64   const extensions::ExtensionSet& extension_set =
     65       extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
     66   for (extensions::ExtensionSet::const_iterator iter = extension_set.begin();
     67        iter != extension_set.end(); ++iter) {
     68     const extensions::URLOverrides::URLOverrideMap& map =
     69         extensions::URLOverrides::GetChromeURLOverrides(iter->get());
     70     if (ContainsKey(map, extension_type))
     71       return true;
     72   }
     73 
     74   return false;
     75 }
     76 
     77 content::WebUIDataSource* CreateUberFrameHTMLSource(Profile* profile) {
     78   content::WebUIDataSource* source =
     79       content::WebUIDataSource::Create(chrome::kChromeUIUberFrameHost);
     80 
     81   source->SetUseJsonJSFormatV2();
     82   source->SetJsonPath("strings.js");
     83   source->AddResourcePath("uber_frame.js", IDR_UBER_FRAME_JS);
     84   source->SetDefaultResource(IDR_UBER_FRAME_HTML);
     85 
     86   // TODO(jhawkins): Attempt to get rid of IDS_SHORT_PRODUCT_OS_NAME.
     87 #if defined(OS_CHROMEOS)
     88   source->AddLocalizedString("shortProductName", IDS_SHORT_PRODUCT_OS_NAME);
     89 #else
     90   source->AddLocalizedString("shortProductName", IDS_SHORT_PRODUCT_NAME);
     91 #endif  // defined(OS_CHROMEOS)
     92 
     93   // Group settings and help separately if settings in a window is enabled.
     94   std::string settings_group("settings_group");
     95   std::string other_group(
     96       ::switches::SettingsWindowEnabled() ? "other_group" : "settings_group");
     97   source->AddString("extensionsHost", chrome::kChromeUIExtensionsHost);
     98   source->AddLocalizedString("extensionsDisplayName",
     99                              IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE);
    100   source->AddString("extensionsGroup", other_group);
    101   source->AddString("helpHost", chrome::kChromeUIHelpHost);
    102   source->AddLocalizedString("helpDisplayName", IDS_ABOUT_TITLE);
    103   source->AddString("helpGroup", settings_group);
    104   source->AddString("historyHost", chrome::kChromeUIHistoryHost);
    105   source->AddLocalizedString("historyDisplayName", IDS_HISTORY_TITLE);
    106   source->AddString("historyGroup", other_group);
    107   source->AddString("settingsHost", chrome::kChromeUISettingsHost);
    108   source->AddLocalizedString("settingsDisplayName", IDS_SETTINGS_TITLE);
    109   source->AddString("settingsGroup", settings_group);
    110   bool overridesHistory =
    111       HasExtensionType(profile, chrome::kChromeUIHistoryHost);
    112   source->AddString("overridesHistory", overridesHistory ? "yes" : "no");
    113   source->DisableDenyXFrameOptions();
    114   source->OverrideContentSecurityPolicyFrameSrc("frame-src chrome:;");
    115 
    116   return source;
    117 }
    118 
    119 }  // namespace
    120 
    121 UberUI::UberUI(content::WebUI* web_ui) : WebUIController(web_ui) {
    122   Profile* profile = Profile::FromWebUI(web_ui);
    123   content::WebUIDataSource::Add(profile, CreateUberHTMLSource());
    124 
    125   RegisterSubpage(chrome::kChromeUIExtensionsFrameURL,
    126                   chrome::kChromeUIExtensionsHost);
    127   RegisterSubpage(chrome::kChromeUIHelpFrameURL,
    128                   chrome::kChromeUIHelpHost);
    129   RegisterSubpage(chrome::kChromeUIHistoryFrameURL,
    130                   chrome::kChromeUIHistoryHost);
    131   RegisterSubpage(chrome::kChromeUISettingsFrameURL,
    132                   chrome::kChromeUISettingsHost);
    133   RegisterSubpage(chrome::kChromeUIUberFrameURL,
    134                   chrome::kChromeUIUberHost);
    135 }
    136 
    137 UberUI::~UberUI() {
    138   STLDeleteValues(&sub_uis_);
    139 }
    140 
    141 void UberUI::RegisterSubpage(const std::string& page_url,
    142                              const std::string& page_host) {
    143   GURL page_gurl(page_url);
    144   content::WebUI* webui = web_ui()->GetWebContents()->CreateWebUI(page_gurl);
    145 
    146   webui->OverrideJavaScriptFrame(page_host);
    147   sub_uis_[page_url] = webui;
    148 }
    149 
    150 content::WebUI* UberUI::GetSubpage(const std::string& page_url) {
    151   if (!ContainsKey(sub_uis_, page_url))
    152     return NULL;
    153   return sub_uis_[page_url];
    154 }
    155 
    156 void UberUI::RenderViewCreated(RenderViewHost* render_view_host) {
    157   for (SubpageMap::iterator iter = sub_uis_.begin(); iter != sub_uis_.end();
    158        ++iter) {
    159     iter->second->GetController()->RenderViewCreated(render_view_host);
    160   }
    161 }
    162 
    163 void UberUI::RenderViewReused(RenderViewHost* render_view_host) {
    164   for (SubpageMap::iterator iter = sub_uis_.begin(); iter != sub_uis_.end();
    165        ++iter) {
    166     iter->second->GetController()->RenderViewReused(render_view_host);
    167   }
    168 }
    169 
    170 bool UberUI::OverrideHandleWebUIMessage(const GURL& source_url,
    171                                         const std::string& message,
    172                                         const base::ListValue& args) {
    173   // Find the appropriate subpage and forward the message.
    174   SubpageMap::iterator subpage = sub_uis_.find(source_url.GetOrigin().spec());
    175   if (subpage == sub_uis_.end()) {
    176     // The message was sent from the uber page itself.
    177     DCHECK_EQ(std::string(chrome::kChromeUIUberHost), source_url.host());
    178     return false;
    179   }
    180 
    181   // The message was sent from a subpage.
    182   // TODO(jam) fix this to use interface
    183   // return subpage->second->GetController()->OverrideHandleWebUIMessage(
    184   //     source_url, message, args);
    185   subpage->second->ProcessWebUIMessage(source_url, message, args);
    186   return true;
    187 }
    188 
    189 // UberFrameUI
    190 
    191 UberFrameUI::UberFrameUI(content::WebUI* web_ui) : WebUIController(web_ui) {
    192   Profile* profile = Profile::FromWebUI(web_ui);
    193   content::WebUIDataSource::Add(profile, CreateUberFrameHTMLSource(profile));
    194 
    195   // Register as an observer for when extensions are loaded and unloaded.
    196   registrar_.Add(this,
    197                  extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    198                  content::Source<Profile>(profile));
    199   registrar_.Add(this,
    200                  extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
    201                  content::Source<Profile>(profile));
    202 }
    203 
    204 UberFrameUI::~UberFrameUI() {
    205 }
    206 
    207 void UberFrameUI::Observe(int type,
    208                           const content::NotificationSource& source,
    209                           const content::NotificationDetails& details) {
    210   switch (type) {
    211     // We listen for notifications that indicate an extension has been loaded
    212     // (i.e., has been installed and/or enabled) or unloaded (i.e., has been
    213     // uninstalled and/or disabled). If one of these events has occurred, then
    214     // we must update the behavior of the History navigation element so that
    215     // it opens the history extension if one is installed and enabled or
    216     // opens the default history page if one is uninstalled or disabled.
    217     case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED:
    218     case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
    219       Profile* profile = Profile::FromWebUI(web_ui());
    220       bool overrides_history =
    221           HasExtensionType(profile, chrome::kChromeUIHistoryHost);
    222       web_ui()->CallJavascriptFunction(
    223           "uber_frame.setNavigationOverride",
    224           base::StringValue(chrome::kChromeUIHistoryHost),
    225           base::StringValue(overrides_history ? "yes" : "no"));
    226       break;
    227     }
    228     default:
    229       NOTREACHED();
    230   }
    231 }
    232