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