Remove WebUI NTP on Android.
Relanding https://codereview.chromium.org/256763004/
Original CL got reverted because it landed at the same time as
https://codereview.chromium.org/215733002
Chrome for Android has transitioned to using native NTP. This CL removes
the WebUI classes and resources.
[email protected],[email protected],[email protected]
BUG=284770
Review URL: https://codereview.chromium.org/259393006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267346 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/android/new_tab_page_prefs.cc b/chrome/browser/android/new_tab_page_prefs.cc
index dacf2ab2..8da809a2e 100644
--- a/chrome/browser/android/new_tab_page_prefs.cc
+++ b/chrome/browser/android/new_tab_page_prefs.cc
@@ -107,6 +107,12 @@
prefs::kNtpCollapsedSyncPromo,
false,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterDictionaryPref(
+ prefs::kNtpCollapsedForeignSessions,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterDictionaryPref(
+ prefs::kNtpMostVisitedURLsBlacklist,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
// static
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index f5495f48..0a2e6d73 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -61,9 +61,6 @@
<structure name="IDR_NEW_TAB_4_HTML" file="resources\ntp4\new_tab.html" flattenhtml="true" type="chrome_html" />
<structure name="IDR_NEW_TAB_4_THEME_CSS" file="resources\ntp4\new_tab_theme.css" flattenhtml="true" type="chrome_html" />
</if>
- <if expr="is_android">
- <structure name="IDR_NEW_TAB_ANDROID_HTML" file="resources\ntp_android\new_tab.html" flattenhtml="true" type="chrome_html" />
- </if>
<if expr="chromeos">
<structure name="IDR_OOBE_HTML" file="resources\chromeos\login\oobe.html" flattenhtml="true" type="chrome_html" variables="OOBE=oobe" expand_variables="true"/>
<structure name="IDR_OOBE_JS" file="resources\chromeos\login\oobe.js" flattenhtml="true" type="chrome_html" />
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index c17fae006..704fade1 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -1020,7 +1020,6 @@
ThemeSource* theme_source = new ThemeSource(profile_);
content::URLDataSource::Add(profile_, theme_source);
}
-#endif
// Same for chrome://thumb/ resources.
if (extensions::PermissionsData::HasHostPermission(
@@ -1028,6 +1027,7 @@
ThumbnailSource* thumbnail_source = new ThumbnailSource(profile_, false);
content::URLDataSource::Add(profile_, thumbnail_source);
}
+#endif
}
void ExtensionService::NotifyExtensionUnloaded(
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index c865132..001c77ed 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -127,7 +127,6 @@
#if defined(OS_ANDROID)
#include "chrome/browser/android/bookmarks/partner_bookmarks_shim.h"
#include "chrome/browser/android/new_tab_page_prefs.h"
-#include "chrome/browser/ui/webui/ntp/android/promo_handler.h"
#else
#include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
#include "chrome/browser/profile_resetter/automatic_profile_resetter_factory.h"
@@ -360,7 +359,7 @@
MediaStreamDevicesController::RegisterProfilePrefs(registry);
NetPrefObserver::RegisterProfilePrefs(registry);
NetworkTimeService::RegisterProfilePrefs(registry);
- NewTabUI::RegisterProfilePrefs(registry);
+
password_manager::PasswordManager::RegisterProfilePrefs(registry);
PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
PrefsTabHelper::RegisterProfilePrefs(registry);
@@ -409,7 +408,6 @@
chrome_variations::VariationsService::RegisterProfilePrefs(registry);
NewTabPagePrefs::RegisterProfilePrefs(registry);
PartnerBookmarksShim::RegisterProfilePrefs(registry);
- PromoHandler::RegisterProfilePrefs(registry);
#else
AppShortcutManager::RegisterProfilePrefs(registry);
autofill::GeneratedCreditCardBubbleController::RegisterUserPrefs(registry);
@@ -419,6 +417,7 @@
extensions::ExtensionSettingsHandler::RegisterProfilePrefs(registry);
extensions::TabsCaptureVisibleTabFunction::RegisterProfilePrefs(registry);
first_run::RegisterProfilePrefs(registry);
+ NewTabUI::RegisterProfilePrefs(registry);
notifier::ChromeNotifierService::RegisterProfilePrefs(registry);
PepperFlashSettingsManager::RegisterProfilePrefs(registry);
PinnedTabCodec::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 8fc7da79..6bca265 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -202,8 +202,8 @@
MediaGalleriesPreferencesFactory::GetInstance();
notifier::ChromeNotifierServiceFactory::GetInstance();
notifier::SyncedNotificationAppInfoServiceFactory::GetInstance();
-#endif
NTPResourceCacheFactory::GetInstance();
+#endif
PasswordStoreFactory::GetInstance();
#if !defined(OS_ANDROID)
PinnedTabServiceFactory::GetInstance();
diff --git a/chrome/browser/resources/ntp_android/OWNERS b/chrome/browser/resources/ntp_android/OWNERS
deleted file mode 100644
index bd8e7857..0000000
--- a/chrome/browser/resources/ntp_android/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
[email protected]
[email protected]
-
diff --git a/chrome/browser/resources/ntp_android/bookmarks.css b/chrome/browser/resources/ntp_android/bookmarks.css
deleted file mode 100644
index 6f61af7c2..0000000
--- a/chrome/browser/resources/ntp_android/bookmarks.css
+++ /dev/null
@@ -1,268 +0,0 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-/* Begin top bar */
-
-#bookmarks_title_wrapper {
- border-bottom: 1px solid #d0d0d0;
- display: -webkit-box;
- font-size: 17px;
- height: 44px;
- line-height: 44px;
- overflow: hidden;
- white-space: nowrap;
-}
-
-.section-title {
- -webkit-box-flex: 1;
- -webkit-box-orient: horizontal;
- display: -webkit-box;
- overflow: hidden;
- position: absolute;
-}
-
-.section-title-mask {
- -webkit-box-flex: 1;
- overflow: hidden;
- position: relative;
-}
-
-.overflow-left-mask {
- background: linear-gradient(
- to right,
- rgba(50,50,50,0.3),
- rgba(0,0,0,0)
- );
- height: 100%;
- left: 0;
- position: absolute;
- top: 0;
- width: 10px;
-}
-
-.overflow-right-mask {
- background: linear-gradient(
- to right,
- rgba(0,0,0,0),
- rgba(50,50,50,0.2)
- );
- height: 100%;
- position: absolute;
- right: 0;
- top: 0;
- width: 10px;
-}
-
-.bookmark-separator {
- background-image: url(images/breadcrumb_mdpi.png);
- background-position: center;
- background-repeat: no-repeat;
- background-size: 8px 20px; /* this matches the background image size */
- height: 44px;
- width: 10px;
-}
-
-html[dir='rtl'] .bookmark-separator {
- -webkit-transform: scaleX(-1);
-}
-
-#bookmarks_title_wrapper .title-crumb {
- color: #555;
- margin: 0 10px;
-}
-
-#bookmarks_title_wrapper .title-crumb-active {
- font-weight: bold;
- margin-right: 0;
- padding-right: 10px;
-}
-
-/* Begin Bookmark Cell Items */
-
-.favicon-cell {
- -webkit-tap-highlight-color: transparent;
- display: inline-block;
- height: 105px;
- padding: 11px;
- text-align: center;
- vertical-align: top;
- width: 80px;
-}
-
-.favicon-cell-active {
- -webkit-tap-highlight-color: transparent;
- background: rgba(51, 181, 229, .4);
-}
-
-.favicon-box {
- -webkit-border-radius: 10px;
- -webkit-box-orient: vertical;
- -webkit-box-pack: center;
- background-repeat: no-repeat;
- background-size: 100% 100%;
- display: -webkit-box;
- height: 64px; /* icon container size */
- margin: auto; /* horizontally center */
- position: relative;
- text-align: center;
- width: 64px; /* icon container size */
-}
-
-.favicon-box.folder {
- background-image: url(images/bookmark_folder_mdpi.png);
-}
-
-.favicon-cell .title {
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 2;
- display: -webkit-box;
- height: 30px;
- line-height: 18px;
- overflow: hidden;
- padding-bottom: 8px;
- padding-top: 10px;
- text-overflow: ellipsis;
- word-wrap: break-word;
-}
-
-.favicon-icon {
- background-position: center;
- background-repeat: no-repeat;
- height: 100%;
- width: 100%;
-}
-
-.favicon-icon.document {
- left: 0;
- position: absolute;
- top: 0;
-}
-
-.bookmark-border {
- background-image: url(images/bookmark_border_mdpi.png);
- background-size: 100%;
- height: 64px;
- left: 0;
- position: absolute;
- top: 0;
- width: 64px;
-}
-
-.favicon-box.document {
- /* a 'document' favicon looks like a little web page with the favicon
- in top left corner */
- background-image: url(images/bookmark_bg_mdpi.png);
- margin: auto; /* horizontally center */
- margin-bottom: 0;
- margin-top: 0;
-}
-
-.favicon-box.document .fold-container {
- position: absolute;
- right: 7px;
- top: 3px;
-}
-
-.favicon-box.document .fold {
- box-shadow: 0 4px 2px -2px rgba(0, 0, 0, 0.2);
- height: 12px;
- width: 12px;
-}
-
-.favicon-box.document .active-shade {
- /* Shade overlay for favicon's when pressed */
- background-color: #000;
- height: 100%;
- left: 0;
- opacity: 0;
- position: absolute;
- top: 0;
- width: 100%;
-}
-
-.favicon-box.document .active-shade:active {
- opacity: 0.15;
-}
-
-.favicon-box.document .color-strip {
- /* the color strip is an overlay across the bottom of the icon */
- border-bottom-left-radius: 2px;
- border-bottom-right-radius: 2px;
- bottom: 3px;
- height: 4px;
- left: 7px;
- position: absolute;
- width: 50px;
-}
-
-.favicon-box.document .favicon-icon {
- background-size: 16px 16px;
-}
-
-.favicon-icon.touch-icon {
- background-size: 100%;
- border-radius: 16px; /* remove any junk in the corners of the favicon */
- height: 57px; /* touch-icon size */
- margin: auto; /* horizontally center */
- margin-bottom: 4px;
- margin-top: 3px; /* (64 - 57) / 2 = 3.5 */
- width: 57px; /* touch-icon size */
-}
-
-@media screen and (-webkit-min-device-pixel-ratio: 1.32) {
- .favicon-box.document {
- background-image: url(images/bookmark_bg_tvdpi.png);
- }
- .bookmark-border {
- background-image: url(images/bookmark_border_tvdpi.png);
- }
- .favicon-box.folder {
- background-image: url(images/bookmark_folder_tvdpi.png);
- }
- .bookmark-separator {
- background-image: url(images/breadcrumb_tvdpi.png);
- }
-
- /* tweaked spacing, presumably because of rounding error */
- .favicon-box {
- width: 65px;
- }
- .favicon-box.document .fold-container {
- right: 8px;
- }
- .favicon-box.document .color-strip {
- left: 8px;
- width: 48px;
- }
-}
-
-@media screen and (-webkit-min-device-pixel-ratio: 1.5) {
- .favicon-box.document {
- background-image: url(images/bookmark_bg_hdpi.png);
- }
- .bookmark-border {
- background-image: url(images/bookmark_border_hdpi.png);
- }
- .favicon-box.folder {
- background-image: url(images/bookmark_folder_hdpi.png);
- }
- .bookmark-separator {
- background-image: url(images/breadcrumb_hdpi.png);
- }
-}
-
-@media screen and (-webkit-min-device-pixel-ratio: 2.0) {
- .favicon-box.document {
- background-image: url(images/bookmark_bg_xhdpi.png);
- }
- .bookmark-border {
- background-image: url(images/bookmark_border_xhdpi.png);
- }
- .favicon-box.folder {
- background-image: url(images/bookmark_folder_xhdpi.png);
- }
- .bookmark-separator {
- background-image: url(images/breadcrumb_xhdpi.png);
- }
-}
diff --git a/chrome/browser/resources/ntp_android/bookmarks_tablet.css b/chrome/browser/resources/ntp_android/bookmarks_tablet.css
deleted file mode 100644
index 141b958..0000000
--- a/chrome/browser/resources/ntp_android/bookmarks_tablet.css
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-/* Don't apply tablet styles to TVDPI devices */
-@media only screen and (-webkit-min-device-pixel-ratio: 1.35),
- only screen and (-webkit-max-device-pixel-ratio: 1.30) {
- body[device='tablet'] .favicon-cell {
- height: 120px;
- padding-left: 36px;
- padding-right: 36px;
- width: 98px;
- }
- body[device='tablet'] #bookmarks_title_wrapper .title-crumb {
- margin: 0 25px;
- }
-}
-
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_bg_hdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_bg_hdpi.png
deleted file mode 100644
index cfa6c7b..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_bg_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_bg_mdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_bg_mdpi.png
deleted file mode 100644
index b26489a3..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_bg_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_bg_tvdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_bg_tvdpi.png
deleted file mode 100644
index fbd0758..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_bg_tvdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_bg_xhdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_bg_xhdpi.png
deleted file mode 100644
index a50dbb58..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_bg_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_border_hdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_border_hdpi.png
deleted file mode 100644
index 6c37481..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_border_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_border_mdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_border_mdpi.png
deleted file mode 100644
index 3a42c37..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_border_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_border_tvdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_border_tvdpi.png
deleted file mode 100644
index 175c28c9..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_border_tvdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_border_xhdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_border_xhdpi.png
deleted file mode 100644
index b9bcae3..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_border_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_folder_hdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_folder_hdpi.png
deleted file mode 100644
index b548843..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_folder_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_folder_mdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_folder_mdpi.png
deleted file mode 100644
index d908689..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_folder_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_folder_tvdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_folder_tvdpi.png
deleted file mode 100644
index 1f5d802..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_folder_tvdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/bookmark_folder_xhdpi.png b/chrome/browser/resources/ntp_android/images/bookmark_folder_xhdpi.png
deleted file mode 100644
index 87a8dd34..0000000
--- a/chrome/browser/resources/ntp_android/images/bookmark_folder_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/breadcrumb_hdpi.png b/chrome/browser/resources/ntp_android/images/breadcrumb_hdpi.png
deleted file mode 100644
index faae43a1..0000000
--- a/chrome/browser/resources/ntp_android/images/breadcrumb_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/breadcrumb_mdpi.png b/chrome/browser/resources/ntp_android/images/breadcrumb_mdpi.png
deleted file mode 100644
index b9a03055..0000000
--- a/chrome/browser/resources/ntp_android/images/breadcrumb_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/breadcrumb_tvdpi.png b/chrome/browser/resources/ntp_android/images/breadcrumb_tvdpi.png
deleted file mode 100644
index 0990077..0000000
--- a/chrome/browser/resources/ntp_android/images/breadcrumb_tvdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/breadcrumb_xhdpi.png b/chrome/browser/resources/ntp_android/images/breadcrumb_xhdpi.png
deleted file mode 100644
index 45edcee..0000000
--- a/chrome/browser/resources/ntp_android/images/breadcrumb_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/default_thumbnail.png b/chrome/browser/resources/ntp_android/images/default_thumbnail.png
deleted file mode 100644
index e2534e0a..0000000
--- a/chrome/browser/resources/ntp_android/images/default_thumbnail.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_closed_hdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_closed_hdpi.png
deleted file mode 100644
index a0a086a..0000000
--- a/chrome/browser/resources/ntp_android/images/disclosure_closed_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_closed_mdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_closed_mdpi.png
deleted file mode 100644
index 42e633e..0000000
--- a/chrome/browser/resources/ntp_android/images/disclosure_closed_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_closed_xhdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_closed_xhdpi.png
deleted file mode 100644
index 55eab9a..0000000
--- a/chrome/browser/resources/ntp_android/images/disclosure_closed_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_open_hdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_open_hdpi.png
deleted file mode 100644
index 1636fb8..0000000
--- a/chrome/browser/resources/ntp_android/images/disclosure_open_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_open_mdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_open_mdpi.png
deleted file mode 100644
index b1218a5..0000000
--- a/chrome/browser/resources/ntp_android/images/disclosure_open_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/disclosure_open_xhdpi.png b/chrome/browser/resources/ntp_android/images/disclosure_open_xhdpi.png
deleted file mode 100644
index 67573e0..0000000
--- a/chrome/browser/resources/ntp_android/images/disclosure_open_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/sent_hdpi.png b/chrome/browser/resources/ntp_android/images/sent_hdpi.png
deleted file mode 100644
index 4ef1e012e..0000000
--- a/chrome/browser/resources/ntp_android/images/sent_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/sent_mdpi.png b/chrome/browser/resources/ntp_android/images/sent_mdpi.png
deleted file mode 100644
index e8631c8..0000000
--- a/chrome/browser/resources/ntp_android/images/sent_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/sent_xhdpi.png b/chrome/browser/resources/ntp_android/images/sent_xhdpi.png
deleted file mode 100644
index 1f024cb4..0000000
--- a/chrome/browser/resources/ntp_android/images/sent_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_hdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_hdpi.png
deleted file mode 100644
index b7f337af..0000000
--- a/chrome/browser/resources/ntp_android/images/syncfographic_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_mdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_mdpi.png
deleted file mode 100644
index 7bc97e8..0000000
--- a/chrome/browser/resources/ntp_android/images/syncfographic_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_hdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_hdpi.png
deleted file mode 100644
index c6c4391..0000000
--- a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_hdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_mdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_mdpi.png
deleted file mode 100644
index d23a041c9..0000000
--- a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_mdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_xhdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_xhdpi.png
deleted file mode 100644
index 8ec1bde..0000000
--- a/chrome/browser/resources/ntp_android/images/syncfographic_sw600dp_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/syncfographic_xhdpi.png b/chrome/browser/resources/ntp_android/images/syncfographic_xhdpi.png
deleted file mode 100644
index d6aa1464..0000000
--- a/chrome/browser/resources/ntp_android/images/syncfographic_xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/images/welcome_thumb.png b/chrome/browser/resources/ntp_android/images/welcome_thumb.png
deleted file mode 100644
index 9997667..0000000
--- a/chrome/browser/resources/ntp_android/images/welcome_thumb.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp_android/incognito_tab.css b/chrome/browser/resources/ntp_android/incognito_tab.css
deleted file mode 100644
index 810bd8c..0000000
--- a/chrome/browser/resources/ntp_android/incognito_tab.css
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-html[dir='ltr'] #incognito_container .icon {
- -webkit-transform: scale(-1, 1);
- float: right;
- margin: 0 6px 0 3px;
-}
-
-html[dir='rtl'] #incognito_container .icon {
- float: left;
- margin: 0 3px 0 6px;
-}
-
-#incognito_container .content {
- background-color: #eee;
- border-radius: 5px 5px;
- color: black;
- margin-left: auto;
- margin-right: auto;
- margin-top: 66px;
- max-width: 600px;
- padding: 10px;
-}
-
-body[device='phone'] #incognito_container .content {
- margin: 10px;
-}
diff --git a/chrome/browser/resources/ntp_android/mockdata.js b/chrome/browser/resources/ntp_android/mockdata.js
deleted file mode 100644
index 071f2b0..0000000
--- a/chrome/browser/resources/ntp_android/mockdata.js
+++ /dev/null
@@ -1,1571 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// File Description:
-// Helper functionality to allow testing the Android NTP from any device.
-
-var gmailURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6Q0I4ODgwMUFERUU1MTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6Q0I4ODgwMUJERUU1MTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDQjg4ODAxOERFRTUxMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDQjg4ODAxOURFRT' +
- 'UxMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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' +
- 'Jggg==';
-var docsURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6ODExMDRCNzNERUU2MTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6ODExMDRCNzRERUU2MTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDQjg4ODAxQ0RFRTUxMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4MTEwNEI3MkRFRT' +
- 'YxMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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';
-var calendarURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6Q0I4ODgwMTZERUU1MTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6Q0I4ODgwMTdERUU1MTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDQjg4ODAxNERFRTUxMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDQjg4ODAxNURFRT' +
- 'UxMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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' +
- 'z1APxfgAEAbKBAmArJGeAAAAAASUVORK5CYII=';
-var acid3URI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6MjVCMjQ2NENFMTQ0MTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6MjVCMjQ2NERFMTQ0MTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyNUIyNDY0QUUxNDQxMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoyNUIyNDY0QkUxND' +
- 'QxMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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';
-var nytimesURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6MjVCMjQ2NDRFMTQ0MTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6MjVCMjQ2NDVFMTQ0MTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QTJCNkM5REUwODExMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QTJCNkM5RUUwOD' +
- 'ExMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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';
-var picasaURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6RDE1MkQ1NTRFMTQ1MTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6RDE1MkQ1NTVFMTQ1MTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEMTUyRDU1MkUxNDUxMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEMTUyRDU1M0UxND' +
- 'UxMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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';
-var ipadURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6NDNENTU5MDBERjBFMTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6OUEyQjZDOTRFMDgxMTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0M0Q1NThGRURGMEUxMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0M0Q1NThGRkRGME' +
- 'UxMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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';
-var computerURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6OUEyQjZDOUJFMDgxMTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6OUEyQjZDOUNFMDgxMTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QTJCNkM5OUUwODExMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QTJCNkM5QUUwOD' +
- 'ExMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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' +
- '8TYADca8cY9ZLO9gAAAABJRU5ErkJggg==';
-var laptopURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGX' +
- 'RFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS' +
- '54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3' +
- 'prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9Ik' +
- 'Fkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMC' +
- 'AgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5Lz' +
- 'AyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG' +
- '1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaH' +
- 'R0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy' +
- '5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD' +
- '0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC' +
- '5paWQ6OUEyQjZDOTdFMDgxMTFERjk1QUNDNjkwRjdDRDZDOEEiIHhtcE1NOkRvY3VtZW50SU' +
- 'Q9InhtcC5kaWQ6OUEyQjZDOThFMDgxMTFERjk1QUNDNjkwRjdDRDZDOEEiPiA8eG1wTU06RG' +
- 'VyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QTJCNkM5NUUwODExMURGOT' +
- 'VBQ0M2OTBGN0NENkM4QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QTJCNkM5NkUwOD' +
- 'ExMURGOTVBQ0M2OTBGN0NENkM4QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPi' +
- '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';
-var twitterURI =
- 'data:image/vnd.microsoft.icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAA' +
- 'QAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A///' +
- '/AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD' +
- '///8A/v7+D/7+/j/+/v5g/v7+YP7+/mD+/v5I/v7+KP///wD///8A////AP///wD///8A///' +
- '/AP///wD+/v4H/v7+UPbv4pHgx47B1K9Y3tWwWN7Ur1je3sKCx+rbuKj+/v5n/v7+GP///wD' +
- '///8A////AP///wD+/v4Y+fbweM2ycMe2iB7/vI0f/8STIf/KlyL/zJki/8yZIv/LmCL/0ah' +
- 'K5/Hp1JH+/v4Y////AP///wD///8A7OTTaquHN+CujkXPs5ZTv6N6G/+2iB7/xpUh/8yZIv/' +
- 'MmSL/zJki/8yZIv/Kmy738OjUi////wD///8A////AMKtfY7w6+Ef////AP///wD///8A3sq' +
- 'bp8iWIf/MmSL/zJki/8yZIv/MmSL/y5gi/8mePO7+/v4w////AP///wD///8A////AP///wD' +
- '+/v4H/v7+V9CtWN3KmCL/zJki/8yZIv/MmSL/zJki/8yZIv/JlyH/5tSqp/7+/mD+/v4////' +
- '/AP///wD///8A+PXvJtGyZdXNnS/3y5gi/8qYIv/LmCL/zJki/8yZIv/MmSL/y5gi/82iPO7' +
- 'LqVfe0byMmf///wD///8A/v7+D/Do1JHKmy73ypci/8KSIP+/jyD/xpQh/8uYIv/MmSL/zJk' +
- 'i/8qYIv+/jyD/rIEd/9nKqH7///8A////APPu4TzAlSz3wZEg/7mLH/+sgR3/uZdGz7mLH//' +
- 'JlyH/zJki/8yZIv/GlSH/to0r9eXbxD/Vx6dg////AP7+/h/p38WhtIsq9al/HP+kfyjuyba' +
- 'Kgf///wCzjzjlwJAg/8qYIv/JlyH/u4wf/8CkYrn///8A////AP///wDj2sRMnHUa/7meYa7' +
- 'Vx6dg////AP///wD///8A2MmnYK6DHf++jiD/vo4g/62CHf/k2sQ/////AP///wD///8A8Ov' +
- 'hH/f07w////8A////AP///wD///8A////AP///wC/p3Cfpnwc/66GKvPg1LZ8////AP///wD' +
- '///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ANXHp2DJtoqByLW' +
- 'Kgf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD' +
- '///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A///' +
- '/AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AADgPwAAwA8AAIAHAAB' +
- '4BwAA+AMAAPAAAADgAQAA4AMAAMEDAADPhwAA/48AAP/nAAD//wAA//8AAA==';
-var thumbnailURI =
- 'data:image/jpeg;base64,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' +
- 'IGqEn7yatahQooooAooooAooooAooooAooooAooooAooooAooooD//Z';
-var faviconURI =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACdU' +
- 'lEQVQ4jY2Ta2iNARjHf+97ttNh5rC5xFyzXMsXtSQSUT5QPoxcUjS3j0T2ASVJTdkH5bJcas' +
- 'IkpLZl5CxsEofNzpiwyWm2s43mPXZs5/K+798H5lbGr54vz9P/99RTjyEpDPj5Bz1xm5fvP5' +
- 'OXm/VrO5oGZAMZ/xJ0RROU3HlLS0eMVfPGk2YaAGkmYA8UfBn+QNGlWkYPTWfb0incCLZR+b' +
- 'S9f2ybA4UdV8T6UpTeamDfmQB5U4axfM5YKuoiRD7FAfiroKb+DfPWH2LkUC/nCldSFWzh6t' +
- '0m1i2YSKYvnernnT8FSdum9EYN2/aeZueh89TUvWbS2BF09/SyYf855s7MIX/hLM7fDuExxN' +
- 'yp2TSEo6QcF1zJ2nP0sshaJjIWi8GL5Jucr8p79XoQahGzC/Tg2RsFX7VrzpYShSPdevbO0t' +
- 'aSJ+qw+iyzN56k9Pp9kPv9njbxzo8Un61gdu44fBk+gk1hJozy4/EYtH7oIWuIF49p0JtwMD' +
- '2mSZY/A1I2YHwr22XMqOGkbIeU4zBkkJek7eAC3nQPtiMkYRhg+rxpHN61hnHTJ0NmJvj9zF' +
- '+xgKLda7l48xGu47IkbwYNLR0gyM0ZTsSKAwb+wekgyZKkyMeoyqvrFHj4QomUrWvVdWLaBh' +
- 'UeuyZJWn3girYXl0uSjlc16+DVF3JdWT8Ef1JZG9KOojJ96UvoSFmtZm08robmiNq6+1RwMq' +
- 'g7oU5JAwj6KSl/ogmri3U50ChJ2lvWqMILIfUm7f8TNL3rUtXjZsWTjk4H3mrTicdqDP+IWE' +
- 'iKDSToJ9DYqc2ngnre+tu+mKH/fOcvCRsrZpOT7fu1Hf0K5C7pVCUOwRoAAAAASUVORK5CYI' +
- 'I=';
-
-var mockMostVisitedPages = [
- {
- title: 'Mail',
- url: 'http://mail.google.com',
- thumbnailUrl: thumbnailURI
- },
- {
- title: 'Docs',
- url: 'http://docs.google.com',
- thumbnailUrl: thumbnailURI
- },
- {
- title: 'Calendar',
- url: 'http://www.google.com/calendar',
- thumbnailUrl: thumbnailURI
- },
- {
- title: '',
- url: 'http://www.nytimes.com',
- thumbnailUrl: thumbnailURI
- },
- {
- title: 'Acid3 Test',
- url: 'http://acid3.acidtests.org/',
- thumbnailUrl: thumbnailURI
- },
- {
- title: 'CNN',
- url: 'http://www.cnn.com',
- thumbnailUrl: thumbnailURI
- },
- {
- title: 'Tech Crunch',
- url: 'http://techcrunch.com',
- thumbnailUrl: thumbnailURI
- },
-];
-
-var mockBookmarks = [
- {
- title: 'Bookmarks Bar',
- id: '1',
- root: true,
- bookmarks:
- [
- {
- title: 'Docs',
- url: 'http://docs.google.com',
- icon: docsURI,
- editable: true
- },
- {
- title: 'Calendar',
- url: 'http://www.google.com/calendar',
- icon: calendarURI,
- editable: true
- },
- {
- title: 'Recipes',
- folder: true,
- id: '2',
- editable: false
- },
- {
- title: 'Acid3 Test',
- url: 'http://acid3.acidtests.org/',
- icon: acid3URI,
- editable: true
- }
- ]
- },
- {
- title: 'Recipes',
- id: '2',
- root: false,
- bookmarks:
- [
- {
- title: 'Chicken Noodle Soup that happens to have a really long ' +
- 'name, it\'s so long it gets ellipsized',
- url: 'http://docs.google.com',
- icon: nytimesURI,
- editable: true
- },
- {
- title: 'Pizza',
- url: 'http://www.google.com/buzz',
- icon: ipadURI,
- editable: true
- },
- {
- title: 'Desserts Really Really Really Really Long Title',
- id: '3',
- folder: true,
- editable: true
- },
- {
- title: 'Empty',
- id: '4',
- folder: true,
- editable: true
- }
- ],
- hierarchy:
- [
- {
- root: true
- }
- ]
- },
- {
- title: 'Desserts Really Really Really Really Long Title',
- id: '3',
- root: false,
- bookmarks:
- [
- {
- title: '<b>Cake</b>',
- url: 'http://www.google.com',
- icon: gmailURI,
- editable: true
- },
- {
- title: 'Cupcake',
- url: 'http://www.google.com',
- icon: faviconURI,
- editable: true
- }
- ],
- hierarchy:
- [
- {
- title: 'Recipes',
- id: '2'
- },
- {
- root: true
- }
- ]
- },
- {
- title: 'Empty',
- id: '4',
- root: false,
- bookmarks: [],
- hierarchy:
- [
- {
- title: 'Recipes',
- id: '2'
- },
- {
- root: true
- }
- ]
- }
-];
-
-
-var mockRecents = [
- {
- title: 'Picasaweb has a really long title when i don\'t think it should',
- url: 'http://picasaweb.google.com/m/viewer',
- icon: picasaURI
- },
- {
- title: 'Acid3 Test',
- url: 'http://acid3.acidtests.org/',
- icon: twitterURI
- },
-];
-
-var mockSyncedDevices = [
- {title: 'iPad', icon: ipadURI},
- {title: 'Laptop', icon: laptopURI},
- {title: 'Desktop', icon: computerURI}
-];
-
-var mockForeignSessions = [
- { // Client 1
- name: 'Test Clientzor 1',
- tag: 'session_syncXch...',
- windows: [
- { // Window 1
- deviceType: 'tablet',
- sessionId: 1,
- tabs: [
- {
- title: 'chrome://setings/personal',
- url: 'chrome://settings/personal',
- icon: docsURI,
- sessionId: 2
- },
- {
- title: 'Amazon.com: The Hunger Games',
- url: 'http://www.amazon.com/Hunger-Games-Suzanne-Collins/dp/' +
- '0439023483',
- icon: docsURI,
- sessionId: 3
- },
- ],
- timestamp: 10
- },
- { // Window 2
- deviceType: 'tablet',
- sessionId: 3,
- tabs: [
- {
- title: 'Electronics store at Amazon.com',
- url: 'http://www.amazon.com/electronics-store/' +
- 'b?ie=UTF8&node=172282',
- icon: docsURI,
- sessionId: 4
- }
- ],
- timestamp: 50
- }
- ]
- },
- { // Client 2
- name: 'Moooo!',
- tag: 'session_syncXch...',
- windows: [
- { // Window 1
- deviceType: 'macosx',
- sessionId: 5,
- tabs: [
- {
- title: 'Amazon.com: Containment eBook',
- url: 'http://www.amazon.com/Containment-ebook/dp/B0039PT4BO',
- icon: gmailURI,
- sessionId: 6
- },
- ]
- }
- ],
- }
-];
-
-/////////////////////////////////////////////////////////////////////////////
-// Mocks section:
-// Definitions that allow the NTP to be tested from a desktop browser.
-/////////////////////////////////////////////////////////////////////////////
-PRESS_START_EVT = 'mousedown';
-PRESS_STOP_EVT = 'mouseup';
-PRESS_MOVE_EVT = 'mousemove';
-
-function getMockBookmarkData(folder_id) {
- if (folder_id != null) {
- for (var i = 0; i < mockBookmarks.length; ++i) {
- if (mockBookmarks[i].id == folder_id) {
- return mockBookmarks[i];
- }
- }
- }
-
- for (var i = 0; i < mockBookmarks.length; ++i) {
- if (mockBookmarks[i].root === true) {
- return mockBookmarks[i];
- }
- }
-
- // Shouldn't get here
- return null;
-}
-
-/**
- * Override the send function and return the appropriate mock data.
- * @param {string} funcName The name of the function being called.
- * @param {Array} opt_args Optional arguments to pass to the function.
- */
-window.chrome.send = function(funcName, opt_args) {
- if (funcName == 'getMostVisited') {
- ntp.setMostVisitedPages(mockMostVisitedPages, false, false);
- } else if (funcName == 'getRecentlyClosedTabs') {
- ntp.setRecentlyClosedTabs(mockRecents);
- } else if (funcName == 'getBookmarks') {
- if (opt_args && opt_args.length == 1) {
- ntp.bookmarks(getMockBookmarkData(opt_args[0]));
- } else {
- ntp.bookmarks(getMockBookmarkData(null));
- }
- } else if (funcName == 'getForeignSessions') {
- ntp.setForeignSessions(mockForeignSessions, true);
- ntp.snapshots([]);
- ntp.setSyncEnabled(true);
- } else if (funcName == 'openForeignSession') {
- // Try to find the requested session in mock data
- for (var i = 0; i < mockForeignSessions.length; i++) {
- var windows = mockForeignSessions[i].windows;
- for (var j = 0; j < windows.length; j++) {
- var tabs = windows[j].tabs;
- for (var k = 0; k < tabs.length; k++) {
- if (windows[j].sessionTag == opt_args[0] &&
- j == opt_args[1] &&
- tabs[k].sessionId == opt_args[2]) {
- window.location = tabs[k].url;
- }
- }
- }
- }
- } else if (funcName == 'getFaviconDominantColor') {
- // use setTimeout to post to end of event queue, so the item can be
- // inserted into doc.
- setTimeout(
- 'ntp.setFaviconDominantColor(' + opt_args[1] + ', "#FF0000");', 0);
- }
-};
-
-/**
- * Overrides getTouchEventX in ntp_android.js.
- * @param {BrowserEvent} evt The touch event triggered by the browser.
- * @return {number} The page Y coordinate of the "touch" event (we are dealing
- * with click events instead of touch events when mocking).
- */
-window.getTouchEventX = function(evt) {
- return evt.pageX;
-};
-
-/**
- * Overrides getTouchEventY in ntp_android.js.
- * @param {BrowserEvent} evt The touch event triggered by the browser.
- * @return {number} The page X coordinate of the "touch" event (we are dealing
- * with click events instead of touch events when mocking).
- */
-window.getTouchEventY = function(evt) {
- return evt.pageY;
-};
-
-/** Mock data, normally generated by native C++ code. */
-window.templateData = {
- device: 'tablet',
- title: 'New Tab',
- mostvisited: 'Most Visited',
- remotetabs: 'Open Tabs'
-};
diff --git a/chrome/browser/resources/ntp_android/mostvisited.css b/chrome/browser/resources/ntp_android/mostvisited.css
deleted file mode 100644
index 3ba48fe4..0000000
--- a/chrome/browser/resources/ntp_android/mostvisited.css
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-/* begin: show/hide selected ntp section */
-body[device='phone'] .main-section {
- display: none;
-}
-
-body[device='phone'] .main-section.selected {
- display: block;
-}
-/* end: show/hide selected ntp section */
-
-.thumbnail-cell {
- -webkit-tap-highlight-color: transparent;
- position: relative;
-}
-
-.thumbnail-cell-shade {
- height: 100%;
- left: 0;
- position: absolute;
- top: 0;
- width: 100%;
-}
-
-.thumbnail-cell-shade-active {
- background: rgba(51, 181, 229, 0.4);
-}
-
-body[device='phone'] .thumbnail-cell {
- display: inline-block;
- position: relative;
- text-align: center;
- vertical-align: top;
-}
-
-body[device='phone'] #most_visited_list .thumbnail-container {
- border: 1px solid #999;
-}
-
-body[device='phone'] #most_visited_list:active .thumbnail-container {
- -webkit-box-shadow: inset 0 1px 10px rgba(0, 0, 0, 0.2);
- background:
- linear-gradient(
- to bottom,
- rgba(0, 0, 0, 0.05)),
- rgba(0, 0, 0, 0.05))),
- linear-gradient(
- 225deg,
- rgba(255, 255, 255, 0),
- ba(255, 255, 255, 1.0)),
- linear-gradient(
- to bottom,
- rgba(255, 255, 255, 0),
- rgba(255, 255, 255, 0) 150px,
- rgba(255, 255, 255, 1.0)) 155px;
- rgba(255, 255, 255, 1.0));
-}
-
-/* This is the div that gets the background set as a thumbnail */
-body[device='phone'] #most_visited_list .thumbnail {
- background-image: url(images/default_thumbnail.png);
- background-position: center top;
- background-repeat: no-repeat;
- background-size: cover;
- cursor: pointer;
-}
-
-body[device='phone'] #most_visited_list .inner-border {
- background: linear-gradient(
- to bottom,
- rgba(0, 0, 0, 0),
- rgba(0, 0, 0, 0.05));
- border: 1px solid rgba(255, 255, 255, .8);
- left: 1px;
- position: absolute;
- top: 1px;
-}
-
-body[device='phone'] #most_visited_list .title-spacer {
- height: 20px;
- width: 0;
-}
-
-body[device='phone'] #most_visited_list .title {
- overflow-x: hidden;
- overflow-y: visible;
- position: absolute;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-body[device='phone'] .recently-closed-title-container {
- border-bottom: 1px solid #c1c1c1;
- color: rgba(0, 0, 0, 0.5);
- font-size: 16px;
- padding-bottom: 10px;
- padding-left: 10px;
-}
diff --git a/chrome/browser/resources/ntp_android/mostvisited_tablet.css b/chrome/browser/resources/ntp_android/mostvisited_tablet.css
deleted file mode 100644
index 5702227..0000000
--- a/chrome/browser/resources/ntp_android/mostvisited_tablet.css
+++ /dev/null
@@ -1,171 +0,0 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-/* begin: show/hide selected ntp section */
-body[device='tablet'] .main-section {
- display: none;
-}
-
-body[device='tablet'] .main-section.selected {
- display: block;
-}
-/* end: show/hide selected ntp section */
-
-/* begin: rules to make most visited container stay at bottom */
-body[device='tablet'] .main-section.selected#most_visited_container {
- display: -webkit-box;
-}
-
-body[device='tablet'] #most_visited_container {
- -webkit-box-orient: vertical;
-}
-
-body[device='tablet'] #recently_closed_container {
- -webkit-box-flex: 0;
- margin-bottom: 10px;
-}
-
-body[device='tablet'] .box-spacer {
- -webkit-box-flex: 1.0;
-}
-
-body[device='tablet'] #most_visited_list {
- -webkit-box-flex: 0;
-}
-/* end: rules to make most visited container stay at bottom */
-
-body[device='tablet'] #most_visited_container {
- overflow: hidden;
-}
-
-body[device='tablet'] #most_visited_list {
- margin-top: 15px;
-}
-
-body[device='tablet'] .thumbnail-cell {
- float: left;
- height: 210px;
- padding: 20px;
- text-align: center;
- width: 230px;
-}
-
-html[dir='rtl'] body[device='tablet'] .thumbnail-cell {
- float: right;
-}
-
-body[device='tablet'] #most_visited_list .thumbnail-container {
- border: 1px solid #999;
- height: 160px;
- position: relative;
- width: 100%;
-}
-
-body[device='tablet'] #most_visited_list .thumbnail {
- background-image: url(images/default_thumbnail.png);
- background-position: center center;
- background-repeat: no-repeat;
- background-size: cover;
- cursor: pointer;
- height: 100%;
- width: 100%;
-}
-
-body[device='tablet'] #most_visited_list .inner-border {
- background: linear-gradient(
- to bottom,
- rgba(0, 0, 0, 0),
- rgba(0, 0, 0, 0.05));
- border: 1px solid rgba(255, 255, 255, 0.8);
- height: 158px;
- left: 0;
- position: absolute;
- top: 0;
- width: 228px;
-}
-
-body[device='tablet'] #most_visited_list .title-spacer {
- height: 35px;
- width: 0;
-}
-
-body[device='tablet'] #most_visited_list .title {
- left: -10px;
- overflow-x: hidden;
- overflow-y: visible;
- position: relative;
- text-overflow: ellipsis;
- top: -2px;
- white-space: nowrap;
- width: 250px;
-}
-
-html[dir='rtl'] body[device='tablet'] #most_visited_list .title {
- right: -10px;
-}
-
-body[device='tablet'] .recently-closed-title-container {
- color: rgba(0, 0, 0, 0.5);
- display: inline-block;
- margin-top: 25px;
- padding-bottom: 10px;
- padding-left: 6px; /* match recently closed border & margin */
- position: relative;
- width: 100%;
-}
-
-html[dir='rtl'] body[device='tablet'] .recently-closed-title-container {
- padding-right: 6px;
-}
-
-body[device='tablet'] .recently-closed-title-container .title {
- display: block;
- font-size: 16px;
-}
-
-body[device='tablet'] #recently_closed_list .cell {
- border: 1px solid rgba(0, 0, 0, 0.25);
- border-width: 1px;
- float: left;
- height: 16px;
- margin: 5px;
- overflow: hidden;
- padding: 5px;
- width: 188px;
-}
-
-html[dir='rtl'] body[device='tablet'] #recently_closed_list .cell {
- float: right;
-}
-
-body[device='tablet'] #recently_closed_list .title {
- color: blue;
- font-size: 12pt;
- overflow: hidden;
- padding-left: 2px;
- text-align: left;
- text-overflow: ellipsis;
-}
-
-html[dir='rtl'] body[device='tablet'] #recently_closed_list .title {
- padding-right: 2px;
- text-align: right;
-}
-
-body[device='tablet'] #recently_closed_list .icon {
- background-position: bottom left;
- background-repeat: no-repeat;
- background-size: 16px 16px;
- float: left;
- height: 16px;
- margin: 2px;
- position: relative;
- top: -1px;
- width: 16px;
-}
-
-html[dir='rtl'] body[device='tablet'] #recently_closed_list .icon {
- float: right;
-}
-
diff --git a/chrome/browser/resources/ntp_android/new_tab.html b/chrome/browser/resources/ntp_android/new_tab.html
deleted file mode 100644
index a18705f..0000000
--- a/chrome/browser/resources/ntp_android/new_tab.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<!DOCTYPE html>
-<html i18n-values="dir:textdirection;">
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0,
- maximum-scale=1.0, user-scalable=no">
- <title i18n-content="title"></title>
- <link rel="stylesheet" href="ntp_android.css">
- <link rel="stylesheet" href="bookmarks.css">
- <link rel="stylesheet" href="bookmarks_tablet.css">
- <link rel="stylesheet" href="mostvisited.css">
- <link rel="stylesheet" href="mostvisited_tablet.css">
- <link rel="stylesheet" href="opentabs.css">
- <link rel="stylesheet" href="opentabs_tablet.css">
- <link rel="stylesheet" href="incognito_tab.css">
- <!-- template data placeholder -->
- <script src="../../../../ui/webui/resources/js/cr.js"></script>
- <script src="../../../../ui/webui/resources/js/parse_html_subset.js"></script>
- <script src="ntp_android.js"></script>
- <script>
- if (document.location.host != "newtab") {
- document.write('<script src="mockdata.js"><\/script>');
- }
- </script>
- </head>
- <body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize;device:device">
- <div id="content-area" style="display:none">
- <div class="main-section" id="open_tabs_container">
- <div class="center-empty-container" id="sync_enable_sync" style="display: none;">
- <div class="center-empty-content" i18n-values=".innerHTML:syncEnableSync"></div>
- </div>
- <div class="center-empty-container" id="sync_promo" style="display: none;">
- <div id="promo_message_on_sync_promo_legacy" class="center-empty-content" i18n-values=".innerHTML:syncPromo"></div>
- <div id="promo_message_on_sync_promo_received" class="center-empty-content" style="display: none;"></div>
- </div>
- <div class="center-empty-container" id="sync_loading" style="display: none;">
- <div class="center-empty-content" i18n-values=".innerHTML:syncLoading"></div>
- </div>
- <div class="page-list" id="open_tabs_list" style="display: none;"></div>
- <div class="page-list" id="promo_vc_list" style="display: none;"></div>
- <div class="page-list" id="snapshots_list" style="display: none;"></div>
- </div>
- <div class="main-section" id="bookmarks_container">
- <div id="bookmarks_contents">
- <div class="section-title-wrapper" id="bookmarks_title_wrapper">
- <div class="section-title-mask">
- <div class="section-title"></div>
- <div class="overflow-left-mask"></div>
- <div class="overflow-right-mask"></div>
- </div>
- </div>
- <div class="icon-grid grid-set-top-margin grid-set-item-margins" id="bookmarks_list"></div>
- </div>
- </div>
- <div class="main-section" id="most_visited_container">
- <div class="icon-grid" id="most_visited_list"></div>
- <div class="box-spacer"></div>
- <div id="recently_closed_container" style="display:none;">
- <div class="recently-closed-title-container">
- <span class="title" i18n-content="recentlyclosed"></span>
- </div>
- <div class="page-list" id="recently_closed_list"></div>
- </div>
- <div id="promo_message_on_most_visited" class="promo-message" style="display: none;"></div>
- </div>
- <div class="main-section" id="incognito_container">
- <div class="content">
- <img src="../../../../ui/webui/resources/images/otr_icon_standalone.png" class="icon">
- <span i18n-values=".innerHTML:content"></span>
- </div>
- </div>
- </div>
- </body>
- <script src="../../../../ui/webui/resources/js/i18n_template.js"></script>
- <script src="../../../../ui/webui/resources/js/util.js"></script>
- <script>
- i18nTemplate.process(document, templateData);
- </script>
-</html>
diff --git a/chrome/browser/resources/ntp_android/ntp_android.css b/chrome/browser/resources/ntp_android/ntp_android.css
deleted file mode 100644
index adbfa4e..0000000
--- a/chrome/browser/resources/ntp_android/ntp_android.css
+++ /dev/null
@@ -1,87 +0,0 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-html {
- height: 100%;
- width: 100%;
-}
-
-body {
- -webkit-user-select: none;
- background: #fff;
- font-family: Droid Sans;
- margin: 0;
- padding: 0;
- padding-bottom: 44px;
- width: 100%;
-}
-
-.welcome-to-chrome {
- background: url(images/welcome_thumb.png);
-}
-
-.center-empty-container {
- -webkit-box-align: center;
- -webkit-box-orient: horizontal;
- -webkit-box-pack: center;
- display: -webkit-box;
- left: 0;
- position: absolute;
- top: 0;
- width: 100%;
-}
-
-.center-empty-content {
- font-size: 14pt;
- width: 275px;
-}
-
-.promo-action-target {
- -webkit-tap-highlight-color: transparent;
-}
-
-.promo-message {
- font-family: Arial, sans-serif;
- font-size: 12pt;
- margin: 16px 24px;
- text-align: center;
-}
-
-.promo-button {
- background: linear-gradient(
- to bottom, #f5f5f5, #f1f1f1);
- border: 1px solid #ccc;
- border-radius: 5px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08),
- inset 0 0 2px rgba(255, 255, 255, 0.6);
- font-size: 12pt;
- margin-left: auto;
- margin-right: auto;
- padding: 10px;
- text-align: center;
-}
-
-.promo-button-active {
- -webkit-tap-highlight-color: transparent;
- background: rgba(51, 181, 229, 0.4);
-}
-
-.promo-sync-graphic {
- background-image: -webkit-image-set(
- url('images/syncfographic_mdpi.png') 1x,
- url('images/syncfographic_hdpi.png') 1.5x,
- url('images/syncfographic_xhdpi.png') 2x);
- background-repeat: no-repeat;
- height: 130px;
-}
-
-body[device='tablet'] .promo-sync-graphic {
- background-image: -webkit-image-set(
- url('images/syncfographic_sw600dp_mdpi.png') 1x,
- url('images/syncfographic_sw600dp_hdpi.png') 1.5x,
- url('images/syncfographic_sw600dp_xhdpi.png') 2x);
- background-repeat: no-repeat;
- height: 260px;
- zoom: 0.5;
-}
diff --git a/chrome/browser/resources/ntp_android/ntp_android.js b/chrome/browser/resources/ntp_android/ntp_android.js
deleted file mode 100644
index c44298cf..0000000
--- a/chrome/browser/resources/ntp_android/ntp_android.js
+++ /dev/null
@@ -1,2736 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// File Description:
-// Contains all the necessary functions for rendering the NTP on mobile
-// devices.
-
-/**
- * The event type used to determine when a touch starts.
- * @type {string}
- */
-var PRESS_START_EVT = 'touchstart';
-
-/**
- * The event type used to determine when a touch finishes.
- * @type {string}
- */
-var PRESS_STOP_EVT = 'touchend';
-
-/**
- * The event type used to determine when a touch moves.
- * @type {string}
- */
-var PRESS_MOVE_EVT = 'touchmove';
-
-cr.define('ntp', function() {
- /**
- * Constant for the localStorage key used to specify the default bookmark
- * folder to be selected when navigating to the bookmark tab for the first
- * time of a new NTP instance.
- * @type {string}
- */
- var DEFAULT_BOOKMARK_FOLDER_KEY = 'defaultBookmarkFolder';
-
- /**
- * Constant for the localStorage key used to store whether or not sync was
- * enabled on the last call to syncEnabled().
- * @type {string}
- */
- var SYNC_ENABLED_KEY = 'syncEnabled';
-
- /**
- * The time before and item gets marked as active (in milliseconds). This
- * prevents an item from being marked as active when the user is scrolling
- * the page.
- * @type {number}
- */
- var ACTIVE_ITEM_DELAY_MS = 100;
-
- /**
- * The CSS class identifier for grid layouts.
- * @type {string}
- */
- var GRID_CSS_CLASS = 'icon-grid';
-
- /**
- * The element to center when centering a GRID_CSS_CLASS.
- */
- var GRID_CENTER_CSS_CLASS = 'center-icon-grid';
-
- /**
- * Attribute used to specify the number of columns to use in a grid. If
- * left unspecified, the grid will fill the container.
- */
- var GRID_COLUMNS = 'grid-columns';
-
- /**
- * Attribute used to specify whether the top margin should be set to match
- * the left margin of the grid.
- */
- var GRID_SET_TOP_MARGIN_CLASS = 'grid-set-top-margin';
-
- /**
- * Attribute used to specify whether the margins of individual items within
- * the grid should be adjusted to better fill the space.
- */
- var GRID_SET_ITEM_MARGINS = 'grid-set-item-margins';
-
- /**
- * The CSS class identifier for centered empty section containers.
- */
- var CENTER_EMPTY_CONTAINER_CSS_CLASS = 'center-empty-container';
-
- /**
- * The CSS class identifier for marking list items as active.
- * @type {string}
- */
- var ACTIVE_LIST_ITEM_CSS_CLASS = 'list-item-active';
-
- /**
- * Attributes set on elements representing data in a section, specifying
- * which section that element belongs to. Used for context menus.
- * @type {string}
- */
- var SECTION_KEY = 'sectionType';
-
- /**
- * Attribute set on an element that has a context menu. Specifies the URL for
- * which the context menu action should apply.
- * @type {string}
- */
- var CONTEXT_MENU_URL_KEY = 'url';
-
- /**
- * The list of main section panes added.
- * @type {Array.<Element>}
- */
- var panes = [];
-
- /**
- * The list of section prefixes, which are used to append to the hash of the
- * page to allow the native toolbar to see url changes when the pane is
- * switched.
- */
- var sectionPrefixes = [];
-
- /**
- * The next available index for new favicons. Users must increment this
- * value once assigning this index to a favicon.
- * @type {number}
- */
- var faviconIndex = 0;
-
- /**
- * The currently selected pane DOM element.
- * @type {Element}
- */
- var currentPane = null;
-
- /**
- * The index of the currently selected top level pane. The index corresponds
- * to the elements defined in {@see #panes}.
- * @type {number}
- */
- var currentPaneIndex;
-
- /**
- * The ID of the bookmark folder currently selected.
- * @type {string|number}
- */
- var bookmarkFolderId = null;
-
- /**
- * The current element active item.
- * @type {?Element}
- */
- var activeItem;
-
- /**
- * The element to be marked as active if no actions cancel it.
- * @type {?Element}
- */
- var pendingActiveItem;
-
- /**
- * The timer ID to mark an element as active.
- * @type {number}
- */
- var activeItemDelayTimerId;
-
- /**
- * Enum for the different load states based on the initialization of the NTP.
- * @enum {number}
- */
- var LoadStatusType = {
- LOAD_NOT_DONE: 0,
- LOAD_IMAGES_COMPLETE: 1,
- LOAD_BOOKMARKS_FINISHED: 2,
- LOAD_COMPLETE: 3 // An OR'd combination of all necessary states.
- };
-
- /**
- * The current loading status for the NTP.
- * @type {LoadStatusType}
- */
- var loadStatus_ = LoadStatusType.LOAD_NOT_DONE;
-
- /**
- * Whether the loading complete notification has been sent.
- * @type {boolean}
- */
- var finishedLoadingNotificationSent_ = false;
-
- /**
- * Whether the page title has been loaded.
- * @type {boolean}
- */
- var titleLoadedStatus_ = false;
-
- /**
- * Whether the NTP is in incognito mode or not.
- * @type {boolean}
- */
- var isIncognito = false;
-
- /**
- * Whether incognito mode is enabled. (It can be blocked e.g. with a policy.)
- * @type {boolean}
- */
- var isIncognitoEnabled = true;
-
- /**
- * Whether the initial history state has been replaced. The state will be
- * replaced once the bookmark data has loaded to ensure the proper folder
- * id is persisted.
- * @type {boolean}
- */
- var replacedInitialState = false;
-
- /**
- * Stores number of most visited pages.
- * @type {number}
- */
- var numberOfMostVisitedPages = 0;
-
- /**
- * Whether there are any recently closed tabs.
- * @type {boolean}
- */
- var hasRecentlyClosedTabs = false;
-
- /**
- * Whether promo is not allowed or not (external to NTP).
- * @type {boolean}
- */
- var promoIsAllowed = false;
-
- /**
- * Whether promo should be shown on Most Visited page (externally set).
- * @type {boolean}
- */
- var promoIsAllowedOnMostVisited = false;
-
- /**
- * Whether promo should be shown on Open Tabs page (externally set).
- * @type {boolean}
- */
- var promoIsAllowedOnOpenTabs = false;
-
- /**
- * Whether promo should show a virtual computer on Open Tabs (externally set).
- * @type {boolean}
- */
- var promoIsAllowedAsVirtualComputer = false;
-
- /**
- * Promo-injected title of a virtual computer on an open tabs pane.
- * @type {string}
- */
- var promoInjectedComputerTitleText = '';
-
- /**
- * Promo-injected last synced text of a virtual computer on an open tabs pane.
- * @type {string}
- */
- var promoInjectedComputerLastSyncedText = '';
-
- /**
- * The different sections that are displayed.
- * @enum {number}
- */
- var SectionType = {
- BOOKMARKS: 'bookmarks',
- FOREIGN_SESSION: 'foreign_session',
- FOREIGN_SESSION_HEADER: 'foreign_session_header',
- MOST_VISITED: 'most_visited',
- PROMO_VC_SESSION_HEADER: 'promo_vc_session_header',
- RECENTLY_CLOSED: 'recently_closed',
- SNAPSHOTS: 'snapshots',
- UNKNOWN: 'unknown',
- };
-
- /**
- * The different ids used of our custom context menu. Sent to the ChromeView
- * and sent back when a menu is selected.
- * @enum {number}
- */
- var ContextMenuItemIds = {
- BOOKMARK_EDIT: 0,
- BOOKMARK_DELETE: 1,
- BOOKMARK_OPEN_IN_NEW_TAB: 2,
- BOOKMARK_OPEN_IN_INCOGNITO_TAB: 3,
- BOOKMARK_SHORTCUT: 4,
-
- MOST_VISITED_OPEN_IN_NEW_TAB: 10,
- MOST_VISITED_OPEN_IN_INCOGNITO_TAB: 11,
- MOST_VISITED_REMOVE: 12,
-
- RECENTLY_CLOSED_OPEN_IN_NEW_TAB: 20,
- RECENTLY_CLOSED_OPEN_IN_INCOGNITO_TAB: 21,
- RECENTLY_CLOSED_REMOVE: 22,
-
- FOREIGN_SESSIONS_REMOVE: 30,
-
- PROMO_VC_SESSION_REMOVE: 40,
- };
-
- /**
- * The URL of the element for the context menu.
- * @type {string}
- */
- var contextMenuUrl = null;
-
- var contextMenuItem = null;
-
- var currentSnapshots = null;
-
- var currentSessions = null;
-
- /**
- * The possible states of the sync section
- * @enum {number}
- */
- var SyncState = {
- INITIAL: 0,
- WAITING_FOR_DATA: 1,
- DISPLAYING_LOADING: 2,
- DISPLAYED_LOADING: 3,
- LOADED: 4,
- };
-
- /**
- * The current state of the sync section.
- */
- var syncState = SyncState.INITIAL;
-
- /**
- * Whether or not sync is enabled. It will be undefined until
- * setSyncEnabled() is called.
- * @type {?boolean}
- */
- var syncEnabled = undefined;
-
- /**
- * The current most visited data being displayed.
- * @type {Array.<Object>}
- */
- var mostVisitedData_ = [];
-
- /**
- * The current bookmark data being displayed. Keep a reference to this data
- * in case the sync enabled state changes. In this case, the bookmark data
- * will need to be refiltered.
- * @type {?Object}
- */
- var bookmarkData;
-
- /**
- * Keep track of any outstanding timers related to updating the sync section.
- */
- var syncTimerId = -1;
-
- /**
- * The minimum amount of time that 'Loading...' can be displayed. This is to
- * prevent flashing.
- */
- var SYNC_LOADING_TIMEOUT = 1000;
-
- /**
- * How long to wait for sync data to load before displaying the 'Loading...'
- * text to the user.
- */
- var SYNC_INITIAL_LOAD_TIMEOUT = 1000;
-
- /**
- * An array of images that are currently in loading state. Once an image
- * loads it is removed from this array.
- */
- var imagesBeingLoaded = new Array();
-
- /**
- * Flag indicating if we are on bookmark shortcut mode.
- * In this mode, only the bookmark section is available and selecting
- * a non-folder bookmark adds it to the home screen.
- * Context menu is disabled.
- */
- var bookmarkShortcutMode = false;
-
- function setIncognitoMode(incognito) {
- isIncognito = incognito;
- if (!isIncognito) {
- chrome.send('getMostVisited');
- chrome.send('getRecentlyClosedTabs');
- chrome.send('getForeignSessions');
- chrome.send('getPromotions');
- chrome.send('getIncognitoDisabled');
- }
- }
-
- function setIncognitoEnabled(item) {
- isIncognitoEnabled = item.incognitoEnabled;
- }
-
- /**
- * Flag set to true when the page is loading its initial set of images. This
- * is set to false after all the initial images have loaded.
- */
- function onInitialImageLoaded(event) {
- var url = event.target.src;
- for (var i = 0; i < imagesBeingLoaded.length; ++i) {
- if (imagesBeingLoaded[i].src == url) {
- imagesBeingLoaded.splice(i, 1);
- if (imagesBeingLoaded.length == 0) {
- // To send out the NTP loading complete notification.
- loadStatus_ |= LoadStatusType.LOAD_IMAGES_COMPLETE;
- sendNTPNotification();
- }
- }
- }
- }
-
- /**
- * Marks the given image as currently being loaded. Once all such images load
- * we inform the browser via a hash change.
- */
- function trackImageLoad(url) {
- if (finishedLoadingNotificationSent_)
- return;
-
- for (var i = 0; i < imagesBeingLoaded.length; ++i) {
- if (imagesBeingLoaded[i].src == url)
- return;
- }
-
- loadStatus_ &= (~LoadStatusType.LOAD_IMAGES_COMPLETE);
-
- var image = new Image();
- image.onload = onInitialImageLoaded;
- image.onerror = onInitialImageLoaded;
- image.src = url;
- imagesBeingLoaded.push(image);
- }
-
- /**
- * Initializes all the UI once the page has loaded.
- */
- function init() {
- // Special case to handle NTP caching.
- if (window.location.hash == '#cached_ntp')
- document.location.hash = '#most_visited';
- // Special case to show a specific bookmarks folder.
- // Used to show the mobile bookmarks folder after importing.
- var bookmarkIdMatch = window.location.hash.match(/#bookmarks:(\d+)/);
- if (bookmarkIdMatch && bookmarkIdMatch.length == 2) {
- localStorage.setItem(DEFAULT_BOOKMARK_FOLDER_KEY, bookmarkIdMatch[1]);
- document.location.hash = '#bookmarks';
- }
- // Special case to choose a bookmark for adding a shortcut.
- // See the doc of bookmarkShortcutMode for details.
- if (window.location.hash == '#bookmark_shortcut')
- bookmarkShortcutMode = true;
- // Make sure a valid section is always displayed. Both normal and
- // incognito NTPs have a bookmarks section.
- if (getPaneIndexFromHash() < 0)
- document.location.hash = '#bookmarks';
-
- // Initialize common widgets.
- var titleScrollers =
- document.getElementsByClassName('section-title-wrapper');
- for (var i = 0, len = titleScrollers.length; i < len; i++)
- initializeTitleScroller(titleScrollers[i]);
-
- // Initialize virtual computers for the sync promo.
- createPromoVirtualComputers();
-
- setCurrentBookmarkFolderData(
- localStorage.getItem(DEFAULT_BOOKMARK_FOLDER_KEY));
-
- addMainSection('incognito');
- addMainSection('most_visited');
- addMainSection('bookmarks');
- addMainSection('open_tabs');
-
- computeDynamicLayout();
-
- scrollToPane(getPaneIndexFromHash());
- updateSyncEmptyState();
-
- window.onpopstate = onPopStateHandler;
- window.addEventListener('hashchange', updatePaneOnHash);
- window.addEventListener('resize', windowResizeHandler);
-
- if (!bookmarkShortcutMode)
- window.addEventListener('contextmenu', contextMenuHandler);
- }
-
- function sendNTPTitleLoadedNotification() {
- if (!titleLoadedStatus_) {
- titleLoadedStatus_ = true;
- chrome.send('notifyNTPTitleLoaded');
- }
- }
-
- /**
- * Notifies the chrome process of the status of the NTP.
- */
- function sendNTPNotification() {
- if (loadStatus_ != LoadStatusType.LOAD_COMPLETE)
- return;
-
- if (!finishedLoadingNotificationSent_) {
- finishedLoadingNotificationSent_ = true;
- chrome.send('notifyNTPReady');
- } else {
- // Navigating after the loading complete notification has been sent
- // might break tests.
- chrome.send('NTPUnexpectedNavigation');
- }
- }
-
- /**
- * The default click handler for created item shortcuts.
- *
- * @param {Object} item The item specification.
- * @param {function} evt The browser click event triggered.
- */
- function itemShortcutClickHandler(item, evt) {
- // Handle the touch callback
- if (item['folder']) {
- browseToBookmarkFolder(item.id);
- } else {
- if (bookmarkShortcutMode) {
- chrome.send('createHomeScreenBookmarkShortcut', [item.id]);
- } else if (!!item.url) {
- window.location = item.url;
- }
- }
- }
-
- /**
- * Opens a recently closed tab.
- *
- * @param {Object} item An object containing the necessary information to
- * reopen a tab.
- */
- function openRecentlyClosedTab(item, evt) {
- chrome.send('openedRecentlyClosed');
- chrome.send('reopenTab', [item.sessionId]);
- }
-
- /**
- * Creates a 'div' DOM element.
- *
- * @param {string} className The CSS class name for the DIV.
- * @param {string=} opt_backgroundUrl The background URL to be applied to the
- * DIV if required.
- * @return {Element} The newly created DIV element.
- */
- function createDiv(className, opt_backgroundUrl) {
- var div = document.createElement('div');
- div.className = className;
- if (opt_backgroundUrl)
- div.style.backgroundImage = 'url(' + opt_backgroundUrl + ')';
- return div;
- }
-
- /**
- * Helper for creating new DOM elements.
- *
- * @param {string} type The type of Element to be created (i.e. 'div',
- * 'span').
- * @param {Object} params A mapping of element attribute key and values that
- * should be applied to the new element.
- * @return {Element} The newly created DOM element.
- */
- function createElement(type, params) {
- var el = document.createElement(type);
- if (typeof params === 'string') {
- el.className = params;
- } else {
- for (attr in params) {
- el[attr] = params[attr];
- }
- }
- return el;
- }
-
- /**
- * Adds a click listener to a specified element with the ability to override
- * the default value of itemShortcutClickHandler.
- *
- * @param {Element} el The element the click listener should be added to.
- * @param {Object} item The item data represented by the element.
- * @param {function(Object, string, BrowserEvent)=} opt_clickCallback The
- * click callback to be triggered upon selection.
- */
- function wrapClickHandler(el, item, opt_clickCallback) {
- el.addEventListener('click', function(evt) {
- var clickCallback =
- opt_clickCallback ? opt_clickCallback : itemShortcutClickHandler;
- clickCallback(item, evt);
- });
- }
-
- /**
- * Create a DOM element to contain a recently closed item for a tablet
- * device.
- *
- * @param {Object} item The data of the item used to generate the shortcut.
- * @param {function(Object, string, BrowserEvent)=} opt_clickCallback The
- * click callback to be triggered upon selection (if not provided it will
- * use the default -- itemShortcutClickHandler).
- * @return {Element} The shortcut element created.
- */
- function makeRecentlyClosedTabletItem(item, opt_clickCallback) {
- var cell = createDiv('cell');
-
- cell.setAttribute(CONTEXT_MENU_URL_KEY, item.url);
-
- var iconUrl = item.icon;
- if (!iconUrl) {
- iconUrl = 'chrome://touch-icon/size/16@' + window.devicePixelRatio +
- 'x/' + item.url;
- }
- var icon = createDiv('icon', iconUrl);
- trackImageLoad(iconUrl);
- cell.appendChild(icon);
-
- var title = createDiv('title');
- title.textContent = item.title;
- cell.appendChild(title);
-
- wrapClickHandler(cell, item, opt_clickCallback);
-
- return cell;
- }
-
- /**
- * Creates a shortcut DOM element based on the item specified item
- * configuration using the thumbnail layout used for most visited. Other
- * data types should not use this as they won't have a thumbnail.
- *
- * @param {Object} item The data of the item used to generate the shortcut.
- * @param {function(Object, string, BrowserEvent)=} opt_clickCallback The
- * click callback to be triggered upon selection (if not provided it will
- * use the default -- itemShortcutClickHandler).
- * @return {Element} The shortcut element created.
- */
- function makeMostVisitedItem(item, opt_clickCallback) {
- // thumbnail-cell -- main outer container
- // thumbnail-container -- container for the thumbnail
- // thumbnail -- the actual thumbnail image; outer border
- // inner-border -- inner border
- // title -- container for the title
- // img -- hack align title text baseline with bottom
- // title text -- the actual text of the title
- var thumbnailCell = createDiv('thumbnail-cell');
- var thumbnailContainer = createDiv('thumbnail-container');
- var backgroundUrl = item.thumbnailUrl || 'chrome://thumb/' + item.url;
- if (backgroundUrl == 'chrome://thumb/chrome://welcome/') {
- // Ideally, it would be nice to use the URL as is. However, as of now
- // theme support has been removed from Chrome. Instead, load the image
- // URL from a style and use it. Don't just use the style because
- // trackImageLoad(...) must be called with the background URL.
- var welcomeStyle = findCssRule('.welcome-to-chrome').style;
- var backgroundImage = welcomeStyle.backgroundImage;
- // trim the "url(" prefix and ")" suffix
- backgroundUrl = backgroundImage.substring(4, backgroundImage.length - 1);
- }
- trackImageLoad(backgroundUrl);
- var thumbnail = createDiv('thumbnail');
- // Use an Image object to ensure the thumbnail image actually exists. If
- // not, this will allow the default to show instead.
- var thumbnailImg = new Image();
- thumbnailImg.onload = function() {
- thumbnail.style.backgroundImage = 'url(' + backgroundUrl + ')';
- };
- thumbnailImg.src = backgroundUrl;
-
- thumbnailContainer.appendChild(thumbnail);
- var innerBorder = createDiv('inner-border');
- thumbnailContainer.appendChild(innerBorder);
- thumbnailCell.appendChild(thumbnailContainer);
- var title = createDiv('title');
- title.textContent = item.title;
- var spacerImg = createElement('img', 'title-spacer');
- spacerImg.alt = '';
- title.insertBefore(spacerImg, title.firstChild);
- thumbnailCell.appendChild(title);
-
- var shade = createDiv('thumbnail-cell-shade');
- thumbnailContainer.appendChild(shade);
- addActiveTouchListener(shade, 'thumbnail-cell-shade-active');
-
- wrapClickHandler(thumbnailCell, item, opt_clickCallback);
-
- thumbnailCell.setAttribute(CONTEXT_MENU_URL_KEY, item.url);
- thumbnailCell.contextMenuItem = item;
- return thumbnailCell;
- }
-
- /**
- * Creates a shortcut DOM element based on the item specified item
- * configuration using the favicon layout used for bookmarks.
- *
- * @param {Object} item The data of the item used to generate the shortcut.
- * @param {function(Object, string, BrowserEvent)=} opt_clickCallback The
- * click callback to be triggered upon selection (if not provided it will
- * use the default -- itemShortcutClickHandler).
- * @return {Element} The shortcut element created.
- */
- function makeBookmarkItem(item, opt_clickCallback) {
- var holder = createDiv('favicon-cell');
- addActiveTouchListener(holder, 'favicon-cell-active');
-
- holder.setAttribute(CONTEXT_MENU_URL_KEY, item.url);
- holder.contextMenuItem = item;
- var faviconBox = createDiv('favicon-box');
- if (item.folder) {
- faviconBox.classList.add('folder');
- } else {
- var iconUrl = item.icon || 'chrome://touch-icon/largest/' + item.url;
- var faviconIcon = createDiv('favicon-icon');
- faviconIcon.style.backgroundImage = 'url(' + iconUrl + ')';
- trackImageLoad(iconUrl);
-
- var image = new Image();
- image.src = iconUrl;
- image.onload = function() {
- var w = image.width;
- var h = image.height;
- if (Math.floor(w) <= 16 || Math.floor(h) <= 16) {
- // it's a standard favicon (or at least it's small).
- faviconBox.classList.add('document');
-
- faviconBox.appendChild(
- createDiv('color-strip colorstrip-' + faviconIndex));
- faviconBox.appendChild(createDiv('bookmark-border'));
- var foldDiv = createDiv('fold');
- foldDiv.id = 'fold_' + faviconIndex;
- foldDiv.style['background'] =
- '-webkit-canvas(fold_' + faviconIndex + ')';
-
- // Use a container so that the fold it self can be zoomed without
- // changing the positioning of the fold.
- var foldContainer = createDiv('fold-container');
- foldContainer.appendChild(foldDiv);
- faviconBox.appendChild(foldContainer);
-
- // FaviconWebUIHandler::HandleGetFaviconDominantColor expects
- // an URL that starts with chrome://favicon/size/.
- // The handler always loads 16x16 1x favicon and assumes that
- // the dominant color for all scale factors is the same.
- chrome.send('getFaviconDominantColor',
- [('chrome://favicon/size/16@1x/' + item.url), '' + faviconIndex]);
- faviconIndex++;
- } else if ((w == 57 && h == 57) || (w == 114 && h == 114)) {
- // it's a touch icon for 1x or 2x.
- faviconIcon.classList.add('touch-icon');
- } else {
- // It's an html5 icon (or at least it's larger).
- // Rescale it to be no bigger than 64x64 dip.
- var max = 64;
- if (w > max || h > max) {
- var scale = (w > h) ? (max / w) : (max / h);
- w *= scale;
- h *= scale;
- }
- faviconIcon.style.backgroundSize = w + 'px ' + h + 'px';
- }
- };
- faviconBox.appendChild(faviconIcon);
- }
- holder.appendChild(faviconBox);
-
- var title = createDiv('title');
- title.textContent = item.title;
- holder.appendChild(title);
-
- wrapClickHandler(holder, item, opt_clickCallback);
-
- return holder;
- }
-
- /**
- * Adds touch listeners to the specified element to apply a class when it is
- * selected (removing the class when no longer pressed).
- *
- * @param {Element} el The element to apply the class to when touched.
- * @param {string} activeClass The CSS class name to be applied when active.
- */
- function addActiveTouchListener(el, activeClass) {
- if (!window.touchCancelListener) {
- window.touchCancelListener = function(evt) {
- if (activeItemDelayTimerId) {
- clearTimeout(activeItemDelayTimerId);
- activeItemDelayTimerId = undefined;
- }
- if (!activeItem) {
- return;
- }
- activeItem.classList.remove(activeItem.dataset.activeClass);
- activeItem = null;
- };
- document.addEventListener('touchcancel', window.touchCancelListener);
- }
- el.dataset.activeClass = activeClass;
- el.addEventListener(PRESS_START_EVT, function(evt) {
- if (activeItemDelayTimerId) {
- clearTimeout(activeItemDelayTimerId);
- activeItemDelayTimerId = undefined;
- }
- activeItemDelayTimerId = setTimeout(function() {
- el.classList.add(activeClass);
- activeItem = el;
- }, ACTIVE_ITEM_DELAY_MS);
- });
- el.addEventListener(PRESS_STOP_EVT, function(evt) {
- if (activeItemDelayTimerId) {
- clearTimeout(activeItemDelayTimerId);
- activeItemDelayTimerId = undefined;
- }
- // Add the active class to ensure the pressed state is visible when
- // quickly tapping, which can happen if the start and stop events are
- // received before the active item delay timer has been executed.
- el.classList.add(activeClass);
- el.classList.add('no-active-delay');
- setTimeout(function() {
- el.classList.remove(activeClass);
- el.classList.remove('no-active-delay');
- }, 0);
- activeItem = null;
- });
- }
-
- /**
- * Creates a shortcut DOM element based on the item specified in the list
- * format.
- *
- * @param {Object} item The data of the item used to generate the shortcut.
- * @param {function(Object, string, BrowserEvent)=} opt_clickCallback The
- * click callback to be triggered upon selection (if not provided it will
- * use the default -- itemShortcutClickHandler).
- * @return {Element} The shortcut element created.
- */
- function makeListEntryItem(item, opt_clickCallback) {
- var listItem = createDiv('list-item');
- addActiveTouchListener(listItem, ACTIVE_LIST_ITEM_CSS_CLASS);
- listItem.setAttribute(CONTEXT_MENU_URL_KEY, item.url);
- var iconSize = item.iconSize || 64;
- var iconUrl = item.icon ||
- 'chrome://touch-icon/size/' + iconSize + '@1x/' + item.url;
- listItem.appendChild(createDiv('icon', iconUrl));
- trackImageLoad(iconUrl);
- var title = createElement('div', {
- textContent: item.title,
- className: 'title session_title'
- });
- listItem.appendChild(title);
-
- listItem.addEventListener('click', function(evt) {
- var clickCallback =
- opt_clickCallback ? opt_clickCallback : itemShortcutClickHandler;
- clickCallback(item, evt);
- });
- if (item.divider == 'section') {
- // Add a child div because the section divider has a gradient and
- // webkit doesn't seem to currently support borders with gradients.
- listItem.appendChild(createDiv('section-divider'));
- } else {
- listItem.classList.add('standard-divider');
- }
- return listItem;
- }
-
- /**
- * Creates a DOM list entry for a remote session or tab.
- *
- * @param {Object} item The data of the item used to generate the shortcut.
- * @param {function(Object, string, BrowserEvent)=} opt_clickCallback The
- * click callback to be triggered upon selection (if not provided it will
- * use the default -- itemShortcutClickHandler).
- * @return {Element} The shortcut element created.
- */
- function makeForeignSessionListEntry(item, opt_clickCallback) {
- // Session item
- var sessionOuterDiv = createDiv('list-item standard-divider');
- addActiveTouchListener(sessionOuterDiv, ACTIVE_LIST_ITEM_CSS_CLASS);
- sessionOuterDiv.contextMenuItem = item;
-
- var icon = createDiv('session-icon ' + item.iconStyle);
- sessionOuterDiv.appendChild(icon);
-
- var titleContainer = createElement('div', 'title');
- sessionOuterDiv.appendChild(titleContainer);
-
- // Extra container to allow title & last-sync time to stack vertically.
- var sessionInnerDiv = createDiv('session_container');
- titleContainer.appendChild(sessionInnerDiv);
-
- var title = createDiv('session-name');
- title.textContent = item.title;
- title.id = item.titleId || '';
- sessionInnerDiv.appendChild(title);
-
- var lastSynced = createDiv('session-last-synced');
- lastSynced.textContent =
- templateData.opentabslastsynced + ': ' + item.userVisibleTimestamp;
- lastSynced.id = item.userVisibleTimestampId || '';
- sessionInnerDiv.appendChild(lastSynced);
-
- sessionOuterDiv.addEventListener('click', function(evt) {
- var clickCallback =
- opt_clickCallback ? opt_clickCallback : itemShortcutClickHandler;
- clickCallback(item, evt);
- });
- return sessionOuterDiv;
- }
-
- /**
- * Saves the number of most visited pages and updates promo visibility.
- * @param {number} n Number of most visited pages.
- */
- function setNumberOfMostVisitedPages(n) {
- numberOfMostVisitedPages = n;
- updatePromoVisibility();
- }
-
- /**
- * Saves the recently closed tabs flag and updates promo visibility.
- * @param {boolean} anyTabs Whether there are any recently closed tabs.
- */
- function setHasRecentlyClosedTabs(anyTabs) {
- hasRecentlyClosedTabs = anyTabs;
- updatePromoVisibility();
- }
-
- /**
- * Updates the most visited pages.
- *
- * @param {Array.<Object>} List of data for displaying the list of most
- * visited pages (see C++ handler for model description).
- * @param {boolean} hasBlacklistedUrls Whether any blacklisted URLs are
- * present.
- */
- function setMostVisitedPages(data, hasBlacklistedUrls) {
- setNumberOfMostVisitedPages(data.length);
- // limit the number of most visited items to display
- if (isPhone() && data.length > 6) {
- data.splice(6, data.length - 6);
- } else if (isTablet() && data.length > 8) {
- data.splice(8, data.length - 8);
- }
-
- data.forEach(function(item, index) {
- item.mostVisitedIndex = index;
- });
-
- if (equals(data, mostVisitedData_))
- return;
-
- var clickFunction = function(item) {
- chrome.send('openedMostVisited');
- chrome.send('metricsHandler:recordInHistogram',
- ['NewTabPage.MostVisited', item.mostVisitedIndex, 8]);
- window.location = item.url;
- };
- populateData(findList('most_visited'), SectionType.MOST_VISITED, data,
- makeMostVisitedItem, clickFunction);
- computeDynamicLayout();
-
- mostVisitedData_ = data;
- }
-
- /**
- * Updates the recently closed tabs.
- *
- * @param {Array.<Object>} List of data for displaying the list of recently
- * closed tabs (see C++ handler for model description).
- */
- function setRecentlyClosedTabs(data) {
- var container = $('recently_closed_container');
- if (!data || data.length == 0) {
- // hide the recently closed section if it is empty.
- container.style.display = 'none';
- setHasRecentlyClosedTabs(false);
- } else {
- container.style.display = 'block';
- setHasRecentlyClosedTabs(true);
- var decoratorFunc = isPhone() ? makeListEntryItem :
- makeRecentlyClosedTabletItem;
- populateData(findList('recently_closed'), SectionType.RECENTLY_CLOSED,
- data, decoratorFunc, openRecentlyClosedTab);
- }
- computeDynamicLayout();
- }
-
- /**
- * Updates the bookmarks.
- *
- * @param {Array.<Object>} List of data for displaying the bookmarks (see
- * C++ handler for model description).
- */
- function bookmarks(data) {
- bookmarkFolderId = data.id;
- if (!replacedInitialState) {
- history.replaceState(
- {folderId: bookmarkFolderId, selectedPaneIndex: currentPaneIndex},
- null, null);
- replacedInitialState = true;
- }
- if (syncEnabled == undefined) {
- // Wait till we know whether or not sync is enabled before displaying any
- // bookmarks (since they may need to be filtered below)
- bookmarkData = data;
- return;
- }
-
- var titleWrapper = $('bookmarks_title_wrapper');
- setBookmarkTitleHierarchy(
- titleWrapper, data, data['hierarchy']);
-
- var filteredBookmarks = data.bookmarks;
- if (!syncEnabled) {
- filteredBookmarks = filteredBookmarks.filter(function(val) {
- return (val.type != 'BOOKMARK_BAR' && val.type != 'OTHER_NODE');
- });
- }
- if (bookmarkShortcutMode) {
- populateData(findList('bookmarks'), SectionType.BOOKMARKS,
- filteredBookmarks, makeBookmarkItem);
- } else {
- var clickFunction = function(item) {
- if (item['folder']) {
- browseToBookmarkFolder(item.id);
- } else if (!!item.url) {
- chrome.send('openedBookmark');
- window.location = item.url;
- }
- };
- populateData(findList('bookmarks'), SectionType.BOOKMARKS,
- filteredBookmarks, makeBookmarkItem, clickFunction);
- }
-
- var bookmarkContainer = $('bookmarks_container');
-
- // update the shadows on the breadcrumb bar
- computeDynamicLayout();
-
- if ((loadStatus_ & LoadStatusType.LOAD_BOOKMARKS_FINISHED) !=
- LoadStatusType.LOAD_BOOKMARKS_FINISHED) {
- loadStatus_ |= LoadStatusType.LOAD_BOOKMARKS_FINISHED;
- sendNTPNotification();
- }
- }
-
- /**
- * Checks if promo is allowed and MostVisited requirements are satisfied.
- * @return {boolean} Whether the promo should be shown on most_visited.
- */
- function shouldPromoBeShownOnMostVisited() {
- return promoIsAllowed && promoIsAllowedOnMostVisited &&
- numberOfMostVisitedPages >= 2 && !hasRecentlyClosedTabs;
- }
-
- /**
- * Checks if promo is allowed and OpenTabs requirements are satisfied.
- * @return {boolean} Whether the promo should be shown on open_tabs.
- */
- function shouldPromoBeShownOnOpenTabs() {
- var snapshotsCount =
- currentSnapshots == null ? 0 : currentSnapshots.length;
- var sessionsCount = currentSessions == null ? 0 : currentSessions.length;
- return promoIsAllowed && promoIsAllowedOnOpenTabs &&
- (snapshotsCount + sessionsCount != 0);
- }
-
- /**
- * Checks if promo is allowed and SyncPromo requirements are satisfied.
- * @return {boolean} Whether the promo should be shown on sync_promo.
- */
- function shouldPromoBeShownOnSync() {
- var snapshotsCount =
- currentSnapshots == null ? 0 : currentSnapshots.length;
- var sessionsCount = currentSessions == null ? 0 : currentSessions.length;
- return promoIsAllowed && promoIsAllowedOnOpenTabs &&
- (snapshotsCount + sessionsCount == 0);
- }
-
- /**
- * Records a promo impression on a given section if necessary.
- * @param {string} section Active section name to check.
- */
- function promoUpdateImpressions(section) {
- if (section == 'most_visited' && shouldPromoBeShownOnMostVisited())
- chrome.send('recordImpression', ['most_visited']);
- else if (section == 'open_tabs' && shouldPromoBeShownOnOpenTabs())
- chrome.send('recordImpression', ['open_tabs']);
- else if (section == 'open_tabs' && shouldPromoBeShownOnSync())
- chrome.send('recordImpression', ['sync_promo']);
- }
-
- /**
- * Updates the visibility on all promo-related items as necessary.
- */
- function updatePromoVisibility() {
- var mostVisitedEl = $('promo_message_on_most_visited');
- var openTabsVCEl = $('promo_vc_list');
- var syncPromoLegacyEl = $('promo_message_on_sync_promo_legacy');
- var syncPromoReceivedEl = $('promo_message_on_sync_promo_received');
- mostVisitedEl.style.display =
- shouldPromoBeShownOnMostVisited() ? 'block' : 'none';
- syncPromoReceivedEl.style.display =
- shouldPromoBeShownOnSync() ? 'block' : 'none';
- syncPromoLegacyEl.style.display =
- shouldPromoBeShownOnSync() ? 'none' : 'block';
- openTabsVCEl.style.display =
- (shouldPromoBeShownOnOpenTabs() && promoIsAllowedAsVirtualComputer) ?
- 'block' : 'none';
- }
-
- /**
- * Called from native.
- * Clears the promotion.
- */
- function clearPromotions() {
- setPromotions({});
- }
-
- /**
- * Set the element to a parsed and sanitized promotion HTML string.
- * @param {Element} el The element to set the promotion string to.
- * @param {string} html The promotion HTML string.
- * @throws {Error} In case of non supported markup.
- */
- function setPromotionHtml(el, html) {
- if (!el) return;
- el.innerHTML = '';
- if (!html) return;
- var tags = ['BR', 'DIV', 'BUTTON', 'SPAN'];
- var attrs = {
- class: function(node, value) { return true; },
- style: function(node, value) { return true; },
- };
- try {
- var fragment = parseHtmlSubset(html, tags, attrs);
- el.appendChild(fragment);
- } catch (err) {
- console.error(err.toString());
- // Ignore all errors while parsing or setting the element.
- }
- }
-
- /**
- * Called from native.
- * Sets the text for all promo-related items, updates
- * promo-send-email-target items to send email on click and
- * updates the visibility of items.
- * @param {Object} promotions Dictionary used to fill-in the text.
- */
- function setPromotions(promotions) {
- var mostVisitedEl = $('promo_message_on_most_visited');
- var openTabsEl = $('promo_message_on_open_tabs');
- var syncPromoReceivedEl = $('promo_message_on_sync_promo_received');
-
- promoIsAllowed = !!promotions.promoIsAllowed;
- promoIsAllowedOnMostVisited = !!promotions.promoIsAllowedOnMostVisited;
- promoIsAllowedOnOpenTabs = !!promotions.promoIsAllowedOnOpenTabs;
- promoIsAllowedAsVirtualComputer = !!promotions.promoIsAllowedAsVC;
-
- setPromotionHtml(mostVisitedEl, promotions.promoMessage);
- setPromotionHtml(openTabsEl, promotions.promoMessage);
- setPromotionHtml(syncPromoReceivedEl, promotions.promoMessageLong);
-
- promoInjectedComputerTitleText = promotions.promoVCTitle || '';
- promoInjectedComputerLastSyncedText = promotions.promoVCLastSynced || '';
- var openTabsVCTitleEl = $('promo_vc_title');
- if (openTabsVCTitleEl)
- openTabsVCTitleEl.textContent = promoInjectedComputerTitleText;
- var openTabsVCLastSyncEl = $('promo_vc_lastsync');
- if (openTabsVCLastSyncEl)
- openTabsVCLastSyncEl.textContent = promoInjectedComputerLastSyncedText;
-
- if (promoIsAllowed) {
- var promoButtonEls =
- document.getElementsByClassName('promo-button');
- for (var i = 0, len = promoButtonEls.length; i < len; i++) {
- promoButtonEls[i].onclick = executePromoAction;
- addActiveTouchListener(promoButtonEls[i], 'promo-button-active');
- }
- }
- updatePromoVisibility();
- }
-
- /**
- * On-click handler for promo email targets.
- * Performs the promo action "send email".
- * @param {Object} evt User interface event that triggered the action.
- */
- function executePromoAction(evt) {
- evt.preventDefault();
- chrome.send('promoActionTriggered');
- }
-
- /**
- * Called by the browser when a context menu has been selected.
- *
- * @param {number} itemId The id of the item that was selected, as specified
- * when chrome.send('showContextMenu') was called.
- */
- function onCustomMenuSelected(itemId) {
- if (contextMenuUrl != null) {
- switch (itemId) {
- case ContextMenuItemIds.BOOKMARK_OPEN_IN_NEW_TAB:
- case ContextMenuItemIds.BOOKMARK_OPEN_IN_INCOGNITO_TAB:
- chrome.send('openedBookmark');
- break;
-
- case ContextMenuItemIds.MOST_VISITED_OPEN_IN_NEW_TAB:
- case ContextMenuItemIds.MOST_VISITED_OPEN_IN_INCOGNITO_TAB:
- chrome.send('openedMostVisited');
- if (contextMenuItem) {
- chrome.send('metricsHandler:recordInHistogram',
- ['NewTabPage.MostVisited',
- contextMenuItem.mostVisitedIndex,
- 8]);
- }
- break;
-
- case ContextMenuItemIds.RECENTLY_CLOSED_OPEN_IN_NEW_TAB:
- case ContextMenuItemIds.RECENTLY_CLOSED_OPEN_IN_INCOGNITO_TAB:
- chrome.send('openedRecentlyClosed');
- break;
- }
- }
-
- switch (itemId) {
- case ContextMenuItemIds.BOOKMARK_OPEN_IN_NEW_TAB:
- case ContextMenuItemIds.MOST_VISITED_OPEN_IN_NEW_TAB:
- case ContextMenuItemIds.RECENTLY_CLOSED_OPEN_IN_NEW_TAB:
- if (contextMenuUrl != null)
- chrome.send('openInNewTab', [contextMenuUrl]);
- break;
-
- case ContextMenuItemIds.BOOKMARK_OPEN_IN_INCOGNITO_TAB:
- case ContextMenuItemIds.MOST_VISITED_OPEN_IN_INCOGNITO_TAB:
- case ContextMenuItemIds.RECENTLY_CLOSED_OPEN_IN_INCOGNITO_TAB:
- if (contextMenuUrl != null)
- chrome.send('openInIncognitoTab', [contextMenuUrl]);
- break;
-
- case ContextMenuItemIds.BOOKMARK_EDIT:
- if (contextMenuItem != null)
- chrome.send('editBookmark', [contextMenuItem.id]);
- break;
-
- case ContextMenuItemIds.BOOKMARK_DELETE:
- if (contextMenuUrl != null)
- chrome.send('deleteBookmark', [contextMenuItem.id]);
- break;
-
- case ContextMenuItemIds.MOST_VISITED_REMOVE:
- if (contextMenuUrl != null)
- chrome.send('blacklistURLFromMostVisited', [contextMenuUrl]);
- break;
-
- case ContextMenuItemIds.BOOKMARK_SHORTCUT:
- if (contextMenuUrl != null)
- chrome.send('createHomeScreenBookmarkShortcut', [contextMenuItem.id]);
- break;
-
- case ContextMenuItemIds.RECENTLY_CLOSED_REMOVE:
- chrome.send('clearRecentlyClosed');
- break;
-
- case ContextMenuItemIds.FOREIGN_SESSIONS_REMOVE:
- if (contextMenuItem != null) {
- chrome.send(
- 'deleteForeignSession', [contextMenuItem.sessionTag]);
- chrome.send('getForeignSessions');
- }
- break;
-
- case ContextMenuItemIds.PROMO_VC_SESSION_REMOVE:
- chrome.send('promoDisabled');
- break;
-
- default:
- log.error('Unknown context menu selected id=' + itemId);
- break;
- }
- }
-
- /**
- * Generates the full bookmark folder hierarchy and populates the scrollable
- * title element.
- *
- * @param {Element} wrapperEl The wrapper element containing the scrollable
- * title.
- * @param {string} data The current bookmark folder node.
- * @param {Array.<Object>=} opt_ancestry The folder ancestry of the current
- * bookmark folder. The list is ordered in order of closest descendant
- * (the root will always be the last node). The definition of each
- * element is:
- * - id {number}: Unique ID of the folder (N/A for root node).
- * - name {string}: Name of the folder (N/A for root node).
- * - root {boolean}: Whether this is the root node.
- */
- function setBookmarkTitleHierarchy(wrapperEl, data, opt_ancestry) {
- var title = wrapperEl.getElementsByClassName('section-title')[0];
- title.innerHTML = '';
- if (opt_ancestry) {
- for (var i = opt_ancestry.length - 1; i >= 0; i--) {
- var titleCrumb = createBookmarkTitleCrumb_(opt_ancestry[i]);
- title.appendChild(titleCrumb);
- title.appendChild(createDiv('bookmark-separator'));
- }
- }
- var titleCrumb = createBookmarkTitleCrumb_(data);
- titleCrumb.classList.add('title-crumb-active');
- title.appendChild(titleCrumb);
-
- // Ensure the last crumb is as visible as possible.
- var windowWidth =
- wrapperEl.getElementsByClassName('section-title-mask')[0].offsetWidth;
- var crumbWidth = titleCrumb.offsetWidth;
- var leftOffset = titleCrumb.offsetLeft;
-
- var shiftLeft = windowWidth - crumbWidth - leftOffset;
- if (shiftLeft < 0) {
- if (crumbWidth > windowWidth)
- shifLeft = -leftOffset;
-
- // Queue up the scrolling initially to allow for the mask element to
- // be placed into the dom and it's size correctly calculated.
- setTimeout(function() {
- handleTitleScroll(wrapperEl, shiftLeft);
- }, 0);
- } else {
- handleTitleScroll(wrapperEl, 0);
- }
- }
-
- /**
- * Creates a clickable bookmark title crumb.
- * @param {Object} data The crumb data (see setBookmarkTitleHierarchy for
- * definition of the data object).
- * @return {Element} The clickable title crumb element.
- * @private
- */
- function createBookmarkTitleCrumb_(data) {
- var titleCrumb = createDiv('title-crumb');
- if (data.root) {
- titleCrumb.innerText = templateData.bookmarkstitle;
- } else {
- titleCrumb.innerText = data.title;
- }
- titleCrumb.addEventListener('click', function(evt) {
- browseToBookmarkFolder(data.root ? '0' : data.id);
- });
- return titleCrumb;
- }
-
- /**
- * Handles scrolling a title element.
- * @param {Element} wrapperEl The wrapper element containing the scrollable
- * title.
- * @param {number} scrollPosition The position to be scrolled to.
- */
- function handleTitleScroll(wrapperEl, scrollPosition) {
- var overflowLeftMask =
- wrapperEl.getElementsByClassName('overflow-left-mask')[0];
- var overflowRightMask =
- wrapperEl.getElementsByClassName('overflow-right-mask')[0];
- var title = wrapperEl.getElementsByClassName('section-title')[0];
- var titleMask = wrapperEl.getElementsByClassName('section-title-mask')[0];
- var titleWidth = title.scrollWidth;
- var containerWidth = titleMask.offsetWidth;
-
- var maxRightScroll = containerWidth - titleWidth;
- var boundedScrollPosition =
- Math.max(maxRightScroll, Math.min(scrollPosition, 0));
-
- overflowLeftMask.style.opacity =
- Math.min(
- 1,
- (Math.max(0, -boundedScrollPosition)) + 10 / 30);
-
- overflowRightMask.style.opacity =
- Math.min(
- 1,
- (Math.max(0, boundedScrollPosition - maxRightScroll) + 10) / 30);
-
- // Set the position of the title.
- if (titleWidth < containerWidth) {
- // left-align on LTR and right-align on RTL.
- title.style.left = '';
- } else {
- title.style.left = boundedScrollPosition + 'px';
- }
- }
-
- /**
- * Initializes a scrolling title element.
- * @param {Element} wrapperEl The wrapper element of the scrolling title.
- */
- function initializeTitleScroller(wrapperEl) {
- var title = wrapperEl.getElementsByClassName('section-title')[0];
-
- var inTitleScroll = false;
- var startingScrollPosition;
- var startingOffset;
- wrapperEl.addEventListener(PRESS_START_EVT, function(evt) {
- inTitleScroll = true;
- startingScrollPosition = getTouchEventX(evt);
- startingOffset = title.offsetLeft;
- });
- document.body.addEventListener(PRESS_STOP_EVT, function(evt) {
- if (!inTitleScroll)
- return;
- inTitleScroll = false;
- });
- document.body.addEventListener(PRESS_MOVE_EVT, function(evt) {
- if (!inTitleScroll)
- return;
- handleTitleScroll(
- wrapperEl,
- startingOffset - (startingScrollPosition - getTouchEventX(evt)));
- evt.stopPropagation();
- });
- }
-
- /**
- * Handles updates from the underlying bookmark model (calls originate
- * in the WebUI handler for bookmarks).
- *
- * @param {Object} status Describes the type of change that occurred. Can
- * contain the following fields:
- * - parent_id {string}: Unique id of the parent that was affected by
- * the change. If the parent is the bookmark
- * bar, then the ID will be 'root'.
- * - node_id {string}: The unique ID of the node that was affected.
- */
- function bookmarkChanged(status) {
- if (status) {
- var affectedParentNode = status['parent_id'];
- var affectedNodeId = status['node_id'];
- var shouldUpdate = (bookmarkFolderId == affectedParentNode ||
- bookmarkFolderId == affectedNodeId);
- if (shouldUpdate)
- setCurrentBookmarkFolderData(bookmarkFolderId);
- } else {
- // This typically happens when extensive changes could have happened to
- // the model, such as initial load, import and sync.
- setCurrentBookmarkFolderData(bookmarkFolderId);
- }
- }
-
- /**
- * Loads the bookarks data for a given folder.
- *
- * @param {string|number} folderId The ID of the folder to load (or null if
- * it should load the root folder).
- */
- function setCurrentBookmarkFolderData(folderId) {
- if (folderId != null) {
- chrome.send('getBookmarks', [folderId]);
- } else {
- chrome.send('getBookmarks');
- }
- try {
- if (folderId == null) {
- localStorage.removeItem(DEFAULT_BOOKMARK_FOLDER_KEY);
- } else {
- localStorage.setItem(DEFAULT_BOOKMARK_FOLDER_KEY, folderId);
- }
- } catch (e) {}
- }
-
- /**
- * Navigates to the specified folder and handles loading the required data.
- * Ensures the current folder can be navigated back to using the browser
- * controls.
- *
- * @param {string|number} folderId The ID of the folder to navigate to.
- */
- function browseToBookmarkFolder(folderId) {
- history.pushState(
- {folderId: folderId, selectedPaneIndex: currentPaneIndex},
- null, null);
- setCurrentBookmarkFolderData(folderId);
- }
-
- /**
- * Called to inform the page of the current sync status. If the state has
- * changed from disabled to enabled, it changes the current and default
- * bookmark section to the root directory. This makes desktop bookmarks are
- * visible.
- */
- function setSyncEnabled(enabled) {
- try {
- if (syncEnabled != undefined && syncEnabled == enabled) {
- // The value didn't change
- return;
- }
- syncEnabled = enabled;
-
- if (enabled) {
- if (!localStorage.getItem(SYNC_ENABLED_KEY)) {
- localStorage.setItem(SYNC_ENABLED_KEY, 'true');
- setCurrentBookmarkFolderData('0');
- }
- } else {
- localStorage.removeItem(SYNC_ENABLED_KEY);
- }
- updatePromoVisibility();
-
- if (bookmarkData) {
- // Bookmark data can now be displayed (or needs to be refiltered)
- bookmarks(bookmarkData);
- }
-
- updateSyncEmptyState();
- } catch (e) {}
- }
-
- /**
- * Handles adding or removing the 'nothing to see here' text from the session
- * list depending on the state of snapshots and sessions.
- *
- * @param {boolean} Whether the call is occuring because of a schedule
- * timeout.
- */
- function updateSyncEmptyState(timeout) {
- if (syncState == SyncState.DISPLAYING_LOADING && !timeout) {
- // Make sure 'Loading...' is displayed long enough
- return;
- }
-
- var openTabsList = findList('open_tabs');
- var snapshotsList = findList('snapshots');
- var syncPromo = $('sync_promo');
- var syncLoading = $('sync_loading');
- var syncEnableSync = $('sync_enable_sync');
-
- if (syncEnabled == undefined ||
- currentSnapshots == null ||
- currentSessions == null) {
- if (syncState == SyncState.INITIAL) {
- // Wait one second for sync data to come in before displaying loading
- // text.
- syncState = SyncState.WAITING_FOR_DATA;
- syncTimerId = setTimeout(function() { updateSyncEmptyState(true); },
- SYNC_INITIAL_LOAD_TIMEOUT);
- } else if (syncState == SyncState.WAITING_FOR_DATA && timeout) {
- // We've waited for the initial info timeout to pass and still don't
- // have data. So, display loading text so the user knows something is
- // happening.
- syncState = SyncState.DISPLAYING_LOADING;
- syncLoading.style.display = '-webkit-box';
- centerEmptySections(syncLoading);
- syncTimerId = setTimeout(function() { updateSyncEmptyState(true); },
- SYNC_LOADING_TIMEOUT);
- } else if (syncState == SyncState.DISPLAYING_LOADING) {
- // Allow the Loading... text to go away once data comes in
- syncState = SyncState.DISPLAYED_LOADING;
- }
- return;
- }
-
- if (syncTimerId != -1) {
- clearTimeout(syncTimerId);
- syncTimerId = -1;
- }
- syncState = SyncState.LOADED;
-
- // Hide everything by default, display selectively below
- syncEnableSync.style.display = 'none';
- syncLoading.style.display = 'none';
- syncPromo.style.display = 'none';
-
- var snapshotsCount =
- currentSnapshots == null ? 0 : currentSnapshots.length;
- var sessionsCount = currentSessions == null ? 0 : currentSessions.length;
-
- if (!syncEnabled) {
- syncEnableSync.style.display = '-webkit-box';
- centerEmptySections(syncEnableSync);
- } else if (sessionsCount + snapshotsCount == 0) {
- syncPromo.style.display = '-webkit-box';
- centerEmptySections(syncPromo);
- } else {
- openTabsList.style.display = sessionsCount == 0 ? 'none' : 'block';
- snapshotsList.style.display = snapshotsCount == 0 ? 'none' : 'block';
- }
- updatePromoVisibility();
- }
-
- /**
- * Called externally when updated snapshot data is available.
- *
- * @param {Object} data The snapshot data
- */
- function snapshots(data) {
- var list = findList('snapshots');
- list.innerHTML = '';
-
- currentSnapshots = data;
- updateSyncEmptyState();
-
- if (!data || data.length == 0)
- return;
-
- data.sort(function(a, b) {
- return b.createTime - a.createTime;
- });
-
- // Create the main container
- var snapshotsEl = createElement('div');
- list.appendChild(snapshotsEl);
-
- // Create the header container
- var headerEl = createDiv('session-header');
- snapshotsEl.appendChild(headerEl);
-
- // Create the documents container
- var docsEl = createDiv('session-children-container');
- snapshotsEl.appendChild(docsEl);
-
- // Create the container for the title & icon
- var headerInnerEl = createDiv('list-item standard-divider');
- addActiveTouchListener(headerInnerEl, ACTIVE_LIST_ITEM_CSS_CLASS);
- headerEl.appendChild(headerInnerEl);
-
- // Create the header icon
- headerInnerEl.appendChild(createDiv('session-icon documents'));
-
- // Create the header title
- var titleContainer = createElement('span', 'title');
- headerInnerEl.appendChild(titleContainer);
- var title = createDiv('session-name');
- title.textContent = templateData.receivedDocuments;
- titleContainer.appendChild(title);
-
- // Add support for expanding and collapsing the children
- var expando = createDiv();
- var expandoFunction = createExpandoFunction(expando, docsEl);
- headerInnerEl.addEventListener('click', expandoFunction);
- headerEl.appendChild(expando);
-
- // Support for actually opening the document
- var snapshotClickCallback = function(item) {
- if (!item)
- return;
- if (item.snapshotId) {
- window.location = 'chrome://snapshot/' + item.snapshotId;
- } else if (item.printJobId) {
- window.location = 'chrome://printjob/' + item.printJobId;
- } else {
- window.location = item.url;
- }
- }
-
- // Finally, add the list of documents
- populateData(docsEl, SectionType.SNAPSHOTS, data,
- makeListEntryItem, snapshotClickCallback);
- }
-
- /**
- * Create a function to handle expanding and collapsing a section
- *
- * @param {Element} expando The expando div
- * @param {Element} element The element to expand and collapse
- * @return {function()} A callback function that should be invoked when the
- * expando is clicked
- */
- function createExpandoFunction(expando, element) {
- expando.className = 'expando open';
- return function() {
- if (element.style.height != '0px') {
- // It seems that '-webkit-transition' only works when explicit pixel
- // values are used.
- setTimeout(function() {
- // If this is the first time to collapse the list, store off the
- // expanded height and also set the height explicitly on the style.
- if (!element.expandedHeight) {
- element.expandedHeight =
- element.clientHeight + 'px';
- element.style.height = element.expandedHeight;
- }
- // Now set the height to 0. Note, this is also done in a callback to
- // give the layout engine a chance to run after possibly setting the
- // height above.
- setTimeout(function() {
- element.style.height = '0px';
- }, 0);
- }, 0);
- expando.className = 'expando closed';
- } else {
- element.style.height = element.expandedHeight;
- expando.className = 'expando open';
- }
- }
- }
-
- /**
- * Initializes the promo_vc_list div to look like a foreign session
- * with a desktop.
- */
- function createPromoVirtualComputers() {
- var list = findList('promo_vc');
- list.innerHTML = '';
-
- // Set up the container and the "virtual computer" session header.
- var sessionEl = createDiv();
- list.appendChild(sessionEl);
- var sessionHeader = createDiv('session-header');
- sessionEl.appendChild(sessionHeader);
-
- // Set up the session children container and the promo as a child.
- var sessionChildren = createDiv('session-children-container');
- var promoMessage = createDiv('promo-message');
- promoMessage.id = 'promo_message_on_open_tabs';
- sessionChildren.appendChild(promoMessage);
- sessionEl.appendChild(sessionChildren);
-
- // Add support for expanding and collapsing the children.
- var expando = createDiv();
- var expandoFunction = createExpandoFunction(expando, sessionChildren);
-
- // Fill-in the contents of the "virtual computer" session header.
- var headerList = [{
- 'title': promoInjectedComputerTitleText,
- 'titleId': 'promo_vc_title',
- 'userVisibleTimestamp': promoInjectedComputerLastSyncedText,
- 'userVisibleTimestampId': 'promo_vc_lastsync',
- 'iconStyle': 'laptop'
- }];
-
- populateData(sessionHeader, SectionType.PROMO_VC_SESSION_HEADER, headerList,
- makeForeignSessionListEntry, expandoFunction);
- sessionHeader.appendChild(expando);
- }
-
- /**
- * Called externally when updated synced sessions data is available.
- *
- * @param {Object} data The snapshot data
- */
- function setForeignSessions(data, tabSyncEnabled) {
- var list = findList('open_tabs');
- list.innerHTML = '';
-
- currentSessions = data;
- updateSyncEmptyState();
-
- // Sort the windows within each client such that more recently
- // modified windows appear first.
- data.forEach(function(client) {
- if (client.windows != null) {
- client.windows.sort(function(a, b) {
- if (b.timestamp == null) {
- return -1;
- } else if (a.timestamp == null) {
- return 1;
- } else {
- return b.timestamp - a.timestamp;
- }
- });
- }
- });
-
- // Sort so more recently modified clients appear first.
- data.sort(function(aClient, bClient) {
- var aWindows = aClient.windows;
- var bWindows = bClient.windows;
- if (bWindows == null || bWindows.length == 0 ||
- bWindows[0].timestamp == null) {
- return -1;
- } else if (aWindows == null || aWindows.length == 0 ||
- aWindows[0].timestamp == null) {
- return 1;
- } else {
- return bWindows[0].timestamp - aWindows[0].timestamp;
- }
- });
-
- data.forEach(function(client, clientNum) {
-
- var windows = client.windows;
- if (windows == null || windows.length == 0)
- return;
-
- // Set up the container for the session header
- var sessionEl = createElement('div');
- list.appendChild(sessionEl);
- var sessionHeader = createDiv('session-header');
- sessionEl.appendChild(sessionHeader);
-
- // Set up the container for the session children
- var sessionChildren = createDiv('session-children-container');
- sessionEl.appendChild(sessionChildren);
-
- var clientName = 'Client ' + clientNum;
- if (client.name)
- clientName = client.name;
-
- var iconStyle;
- var deviceType = client.deviceType;
- if (deviceType == 'win' ||
- deviceType == 'macosx' ||
- deviceType == 'linux' ||
- deviceType == 'chromeos' ||
- deviceType == 'other') {
- iconStyle = 'laptop';
- } else if (deviceType == 'phone') {
- iconStyle = 'phone';
- } else if (deviceType == 'tablet') {
- iconStyle = 'tablet';
- } else {
- console.error('Unknown sync device type found: ', deviceType);
- iconStyle = 'laptop';
- }
- var headerList = [{
- 'title': clientName,
- 'userVisibleTimestamp': windows[0].userVisibleTimestamp,
- 'iconStyle': iconStyle,
- 'sessionTag': client.tag,
- }];
-
- var expando = createDiv();
- var expandoFunction = createExpandoFunction(expando, sessionChildren);
- populateData(sessionHeader, SectionType.FOREIGN_SESSION_HEADER,
- headerList, makeForeignSessionListEntry, expandoFunction);
- sessionHeader.appendChild(expando);
-
- // Populate the session children container
- var openTabsList = new Array();
- for (var winNum = 0; winNum < windows.length; winNum++) {
- win = windows[winNum];
- var tabs = win.tabs;
- for (var tabNum = 0; tabNum < tabs.length; tabNum++) {
- var tab = tabs[tabNum];
- // If this is the last tab in the window and there are more windows,
- // use a section divider.
- var needSectionDivider =
- (tabNum + 1 == tabs.length) && (winNum + 1 < windows.length);
- tab.icon = tab.icon || 'chrome://favicon/size/16@1x/' + tab.url;
-
- openTabsList.push({
- timestamp: tab.timestamp,
- title: tab.title,
- url: tab.url,
- sessionTag: client.tag,
- winNum: winNum,
- sessionId: tab.sessionId,
- icon: tab.icon,
- iconSize: 16,
- divider: needSectionDivider ? 'section' : 'standard',
- });
- }
- }
- var tabCallback = function(item, evt) {
- var buttonIndex = 0;
- var altKeyPressed = false;
- var ctrlKeyPressed = false;
- var metaKeyPressed = false;
- var shiftKeyPressed = false;
- if (evt instanceof MouseEvent) {
- buttonIndex = evt.button;
- altKeyPressed = evt.altKey;
- ctrlKeyPressed = evt.ctrlKey;
- metaKeyPressed = evt.metaKey;
- shiftKeyPressed = evt.shiftKey;
- }
- chrome.send('openedForeignSession');
- chrome.send('openForeignSession', [String(item.sessionTag),
- String(item.winNum), String(item.sessionId), buttonIndex,
- altKeyPressed, ctrlKeyPressed, metaKeyPressed, shiftKeyPressed]);
- };
- populateData(sessionChildren, SectionType.FOREIGN_SESSION, openTabsList,
- makeListEntryItem, tabCallback);
- });
- }
-
- /**
- * Updates the dominant favicon color for a given index.
- *
- * @param {number} index The index of the favicon whose dominant color is
- * being specified.
- * @param {string} color The string encoded color.
- */
- function setFaviconDominantColor(index, color) {
- var colorstrips = document.getElementsByClassName('colorstrip-' + index);
- for (var i = 0; i < colorstrips.length; i++)
- colorstrips[i].style.background = color;
-
- var id = 'fold_' + index;
- var fold = $(id);
- if (!fold)
- return;
- var zoom = window.getComputedStyle(fold).zoom;
- var scale = 1 / window.getComputedStyle(fold).zoom;
-
- // The width/height of the canvas. Set to 24 so it looks good across all
- // resolutions.
- var cw = 24;
- var ch = 24;
-
- // Get the fold canvas and create a path for the fold shape
- var ctx = document.getCSSCanvasContext(
- '2d', 'fold_' + index, cw * scale, ch * scale);
- ctx.beginPath();
- ctx.moveTo(0, 0);
- ctx.lineTo(0, ch * 0.75 * scale);
- ctx.quadraticCurveTo(
- 0, ch * scale,
- cw * .25 * scale, ch * scale);
- ctx.lineTo(cw * scale, ch * scale);
- ctx.closePath();
-
- // Create a gradient for the fold and fill it
- var gradient = ctx.createLinearGradient(cw * scale, 0, 0, ch * scale);
- if (color.indexOf('#') == 0) {
- var r = parseInt(color.substring(1, 3), 16);
- var g = parseInt(color.substring(3, 5), 16);
- var b = parseInt(color.substring(5, 7), 16);
- gradient.addColorStop(0, 'rgba(' + r + ', ' + g + ', ' + b + ', 0.6)');
- } else {
- // assume the color is in the 'rgb(#, #, #)' format
- var rgbBase = color.substring(4, color.length - 1);
- gradient.addColorStop(0, 'rgba(' + rgbBase + ', 0.6)');
- }
- gradient.addColorStop(1, color);
- ctx.fillStyle = gradient;
- ctx.fill();
-
- // Stroke the fold
- ctx.lineWidth = Math.floor(scale);
- ctx.strokeStyle = color;
- ctx.stroke();
- ctx.strokeStyle = 'rgba(0, 0, 0, 0.1)';
- ctx.stroke();
-
- }
-
- /**
- * Finds the list element corresponding to the given name.
- * @param {string} name The name prefix of the DOM element (<prefix>_list).
- * @return {Element} The list element corresponding with the name.
- */
- function findList(name) {
- return $(name + '_list');
- }
-
- /**
- * Render the given data into the given list, and hide or show the entire
- * container based on whether there are any elements. The decorator function
- * is used to create the element to be inserted based on the given data
- * object.
- *
- * @param {holder} The dom element that the generated list items will be put
- * into.
- * @param {SectionType} section The section that data is for.
- * @param {Object} data The data to be populated.
- * @param {function(Object, boolean)} decorator The function that will
- * handle decorating each item in the data.
- * @param {function(Object, Object)} opt_clickCallback The function that is
- * called when the item is clicked.
- */
- function populateData(holder, section, data, decorator,
- opt_clickCallback) {
- // Empty other items in the list, if present.
- holder.innerHTML = '';
- var fragment = document.createDocumentFragment();
- if (!data || data.length == 0) {
- fragment.innerHTML = '';
- } else {
- data.forEach(function(item) {
- var el = decorator(item, opt_clickCallback);
- el.setAttribute(SECTION_KEY, section);
- el.id = section + fragment.childNodes.length;
- fragment.appendChild(el);
- });
- }
- holder.appendChild(fragment);
- if (holder.classList.contains(GRID_CSS_CLASS))
- centerGrid(holder);
- centerEmptySections(holder);
- }
-
- /**
- * Given an element containing a list of child nodes arranged in
- * a grid, this will center the grid in the window based on the
- * remaining space.
- * @param {Element} el Container holding the grid cell items.
- */
- function centerGrid(el) {
- var childEl = el.firstChild;
- if (!childEl)
- return;
-
- // Find the element to actually set the margins on.
- var toCenter = el;
- var curEl = toCenter;
- while (curEl && curEl.classList) {
- if (curEl.classList.contains(GRID_CENTER_CSS_CLASS)) {
- toCenter = curEl;
- break;
- }
- curEl = curEl.parentNode;
- }
- var setItemMargins = el.classList.contains(GRID_SET_ITEM_MARGINS);
- var itemWidth = getItemWidth(childEl, setItemMargins);
- var windowWidth = document.documentElement.offsetWidth;
- if (itemWidth >= windowWidth) {
- toCenter.style.paddingLeft = '0';
- toCenter.style.paddingRight = '0';
- } else {
- var numColumns = el.getAttribute(GRID_COLUMNS);
- if (numColumns) {
- numColumns = parseInt(numColumns);
- } else {
- numColumns = Math.floor(windowWidth / itemWidth);
- }
-
- if (setItemMargins) {
- // In this case, try to size each item to fill as much space as
- // possible.
- var gutterSize =
- (windowWidth - itemWidth * numColumns) / (numColumns + 1);
- var childLeftMargin = Math.round(gutterSize / 2);
- var childRightMargin = Math.floor(gutterSize - childLeftMargin);
- var children = el.childNodes;
- for (var i = 0; i < children.length; i++) {
- children[i].style.marginLeft = childLeftMargin + 'px';
- children[i].style.marginRight = childRightMargin + 'px';
- }
- itemWidth += childLeftMargin + childRightMargin;
- }
-
- var remainder = windowWidth - itemWidth * numColumns;
- var leftPadding = Math.round(remainder / 2);
- var rightPadding = Math.floor(remainder - leftPadding);
- toCenter.style.paddingLeft = leftPadding + 'px';
- toCenter.style.paddingRight = rightPadding + 'px';
-
- if (toCenter.classList.contains(GRID_SET_TOP_MARGIN_CLASS)) {
- var childStyle = window.getComputedStyle(childEl);
- var childLeftPadding = parseInt(
- childStyle.getPropertyValue('padding-left'));
- toCenter.style.paddingTop =
- (childLeftMargin + childLeftPadding + leftPadding) + 'px';
- }
- }
- }
-
- /**
- * Finds and centers all child grid elements for a given node (the grids
- * do not need to be direct descendants and can reside anywhere in the node
- * hierarchy).
- * @param {Element} el The node containing the grid child nodes.
- */
- function centerChildGrids(el) {
- var grids = el.getElementsByClassName(GRID_CSS_CLASS);
- for (var i = 0; i < grids.length; i++)
- centerGrid(grids[i]);
- }
-
- /**
- * Finds and vertically centers all 'empty' elements for a given node (the
- * 'empty' elements do not need to be direct descendants and can reside
- * anywhere in the node hierarchy).
- * @param {Element} el The node containing the 'empty' child nodes.
- */
- function centerEmptySections(el) {
- if (el.classList &&
- el.classList.contains(CENTER_EMPTY_CONTAINER_CSS_CLASS)) {
- centerEmptySection(el);
- }
- var empties = el.getElementsByClassName(CENTER_EMPTY_CONTAINER_CSS_CLASS);
- for (var i = 0; i < empties.length; i++) {
- centerEmptySection(empties[i]);
- }
- }
-
- /**
- * Set the top of the given element to the top of the parent and set the
- * height to (bottom of document - top).
- *
- * @param {Element} el Container holding the centered content.
- */
- function centerEmptySection(el) {
- var parent = el.parentNode;
- var top = parent.offsetTop;
- var bottom = (
- document.documentElement.offsetHeight - getButtonBarPadding());
- el.style.height = (bottom - top) + 'px';
- el.style.top = top + 'px';
- }
-
- /**
- * Finds the index of the panel specified by its prefix.
- * @param {string} The string prefix for the panel.
- * @return {number} The index of the panel.
- */
- function getPaneIndex(panePrefix) {
- var pane = $(panePrefix + '_container');
-
- if (pane != null) {
- var index = panes.indexOf(pane);
-
- if (index >= 0)
- return index;
- }
- return 0;
- }
-
- /**
- * Finds the index of the panel specified by location hash.
- * @return {number} The index of the panel.
- */
- function getPaneIndexFromHash() {
- var paneIndex;
- if (window.location.hash == '#bookmarks') {
- paneIndex = getPaneIndex('bookmarks');
- } else if (window.location.hash == '#bookmark_shortcut') {
- paneIndex = getPaneIndex('bookmarks');
- } else if (window.location.hash == '#most_visited') {
- paneIndex = getPaneIndex('most_visited');
- } else if (window.location.hash == '#open_tabs') {
- paneIndex = getPaneIndex('open_tabs');
- } else if (window.location.hash == '#incognito') {
- paneIndex = getPaneIndex('incognito');
- } else {
- // Couldn't find a good section
- paneIndex = -1;
- }
- return paneIndex;
- }
-
- /**
- * Selects a pane from the top level list (Most Visited, Bookmarks, etc...).
- * @param {number} paneIndex The index of the pane to be selected.
- * @return {boolean} Whether the selected pane has changed.
- */
- function scrollToPane(paneIndex) {
- var pane = panes[paneIndex];
-
- if (pane == currentPane)
- return false;
-
- var newHash = '#' + sectionPrefixes[paneIndex];
- // If updated hash matches the current one in the URL, we need to call
- // updatePaneOnHash directly as updating the hash to the same value will
- // not trigger the 'hashchange' event.
- if (bookmarkShortcutMode || newHash == document.location.hash)
- updatePaneOnHash();
- computeDynamicLayout();
- promoUpdateImpressions(sectionPrefixes[paneIndex]);
- return true;
- }
-
- /**
- * Updates the pane based on the current hash.
- */
- function updatePaneOnHash() {
- var paneIndex = getPaneIndexFromHash();
- var pane = panes[paneIndex];
-
- if (currentPane)
- currentPane.classList.remove('selected');
- pane.classList.add('selected');
- currentPane = pane;
- currentPaneIndex = paneIndex;
-
- setScrollTopForDocument(document, 0);
-
- var panelPrefix = sectionPrefixes[paneIndex];
- var title = templateData[panelPrefix + '_document_title'];
- if (!title)
- title = templateData['title'];
- document.title = title;
-
- sendNTPTitleLoadedNotification();
-
- // TODO (dtrainor): Could potentially add logic to reset the bookmark state
- // if they are moving to that pane. This logic was in there before, but
- // was removed due to the fact that we have to go to this pane as part of
- // the history navigation.
- }
-
- /**
- * Adds a top level section to the NTP.
- * @param {string} panelPrefix The prefix of the element IDs corresponding
- * to the container of the content.
- * @param {boolean=} opt_canBeDefault Whether this section can be marked as
- * the default starting point for subsequent instances of the NTP. The
- * default value for this is true.
- */
- function addMainSection(panelPrefix) {
- var paneEl = $(panelPrefix + '_container');
- var paneIndex = panes.push(paneEl) - 1;
- sectionPrefixes.push(panelPrefix);
- }
-
- /**
- * Handles the dynamic layout of the components on the new tab page. Only
- * layouts that require calculation based on the screen size should go in
- * this function as it will be called during all resize changes
- * (orientation, keyword being displayed).
- */
- function computeDynamicLayout() {
- // Update the scrolling titles to ensure they are not in a now invalid
- // scroll position.
- var titleScrollers =
- document.getElementsByClassName('section-title-wrapper');
- for (var i = 0, len = titleScrollers.length; i < len; i++) {
- var titleEl =
- titleScrollers[i].getElementsByClassName('section-title')[0];
- handleTitleScroll(
- titleScrollers[i],
- titleEl.offsetLeft);
- }
-
- updateMostVisitedStyle();
- updateMostVisitedHeight();
- }
-
- /**
- * The centering of the 'recently closed' section is different depending on
- * the orientation of the device. In landscape, it should be left-aligned
- * with the 'most used' section. In portrait, it should be centered in the
- * screen.
- */
- function updateMostVisitedStyle() {
- if (isTablet()) {
- updateMostVisitedStyleTablet();
- } else {
- updateMostVisitedStylePhone();
- }
- }
-
- /**
- * Updates the style of the most visited pane for the phone.
- */
- function updateMostVisitedStylePhone() {
- var mostVisitedList = $('most_visited_list');
- var childEl = mostVisitedList.firstChild;
- if (!childEl)
- return;
-
- // 'natural' height and width of the thumbnail
- var thumbHeight = 72;
- var thumbWidth = 108;
- var labelHeight = 25;
- var labelWidth = thumbWidth + 20;
- var labelLeft = (thumbWidth - labelWidth) / 2;
- var itemHeight = thumbHeight + labelHeight;
-
- // default vertical margin between items
- var itemMarginTop = 0;
- var itemMarginBottom = 0;
- var itemMarginLeft = 20;
- var itemMarginRight = 20;
-
- var listHeight = 0;
-
- var screenHeight =
- document.documentElement.offsetHeight -
- getButtonBarPadding();
-
- if (isPortrait()) {
- mostVisitedList.setAttribute(GRID_COLUMNS, '2');
- listHeight = screenHeight * .85;
- // Ensure that listHeight is not too small and not too big.
- listHeight = Math.max(listHeight, (itemHeight * 3) + 20);
- listHeight = Math.min(listHeight, 420);
- // Size for 3 rows (4 gutters)
- itemMarginTop = (listHeight - (itemHeight * 3)) / 4;
- } else {
- mostVisitedList.setAttribute(GRID_COLUMNS, '3');
- listHeight = screenHeight;
-
- // If the screen height is less than targetHeight, scale the size of the
- // thumbnails such that the margin between the thumbnails remains
- // constant.
- var targetHeight = 220;
- if (screenHeight < targetHeight) {
- var targetRemainder = targetHeight - 2 * (thumbHeight + labelHeight);
- var scale = (screenHeight - 2 * labelHeight -
- targetRemainder) / (2 * thumbHeight);
- // update values based on scale
- thumbWidth = Math.round(thumbWidth * scale);
- thumbHeight = Math.round(thumbHeight * scale);
- labelWidth = thumbWidth + 20;
- itemHeight = thumbHeight + labelHeight;
- }
-
- // scale the vertical margin such that the items fit perfectly on the
- // screen
- var remainder = screenHeight - (2 * itemHeight);
- var margin = (remainder / 2);
- margin = margin > 24 ? 24 : margin;
- itemMarginTop = Math.round(margin / 2);
- itemMarginBottom = Math.round(margin - itemMarginTop);
- }
-
- mostVisitedList.style.minHeight = listHeight + 'px';
-
- modifyCssRule('body[device="phone"] .thumbnail-cell',
- 'height', itemHeight + 'px');
- modifyCssRule('body[device="phone"] #most_visited_list .thumbnail',
- 'height', thumbHeight + 'px');
- modifyCssRule('body[device="phone"] #most_visited_list .thumbnail',
- 'width', thumbWidth + 'px');
- modifyCssRule(
- 'body[device="phone"] #most_visited_list .thumbnail-container',
- 'height', thumbHeight + 'px');
- modifyCssRule(
- 'body[device="phone"] #most_visited_list .thumbnail-container',
- 'width', thumbWidth + 'px');
- modifyCssRule('body[device="phone"] #most_visited_list .title',
- 'width', labelWidth + 'px');
- modifyCssRule('body[device="phone"] #most_visited_list .title',
- 'left', labelLeft + 'px');
- modifyCssRule('body[device="phone"] #most_visited_list .inner-border',
- 'height', thumbHeight - 2 + 'px');
- modifyCssRule('body[device="phone"] #most_visited_list .inner-border',
- 'width', thumbWidth - 2 + 'px');
-
- modifyCssRule('body[device="phone"] .thumbnail-cell',
- 'margin-left', itemMarginLeft + 'px');
- modifyCssRule('body[device="phone"] .thumbnail-cell',
- 'margin-right', itemMarginRight + 'px');
- modifyCssRule('body[device="phone"] .thumbnail-cell',
- 'margin-top', itemMarginTop + 'px');
- modifyCssRule('body[device="phone"] .thumbnail-cell',
- 'margin-bottom', itemMarginBottom + 'px');
-
- centerChildGrids($('most_visited_container'));
- }
-
- /**
- * Updates the style of the most visited pane for the tablet.
- */
- function updateMostVisitedStyleTablet() {
- function setCenterIconGrid(el, set) {
- if (set) {
- el.classList.add(GRID_CENTER_CSS_CLASS);
- } else {
- el.classList.remove(GRID_CENTER_CSS_CLASS);
- el.style.paddingLeft = '0px';
- el.style.paddingRight = '0px';
- }
- }
- var isPortrait = document.documentElement.offsetWidth <
- document.documentElement.offsetHeight;
- var mostVisitedContainer = $('most_visited_container');
- var mostVisitedList = $('most_visited_list');
- var recentlyClosedContainer = $('recently_closed_container');
- var recentlyClosedList = $('recently_closed_list');
-
- setCenterIconGrid(mostVisitedContainer, !isPortrait);
- setCenterIconGrid(mostVisitedList, isPortrait);
- setCenterIconGrid(recentlyClosedContainer, isPortrait);
- if (isPortrait) {
- recentlyClosedList.classList.add(GRID_CSS_CLASS);
- } else {
- recentlyClosedList.classList.remove(GRID_CSS_CLASS);
- }
-
- // Make the recently closed list visually left align with the most recently
- // closed items in landscape mode. It will be reset by the grid centering
- // in portrait mode.
- if (!isPortrait)
- recentlyClosedContainer.style.paddingLeft = '14px';
- }
-
- /**
- * This handles updating some of the spacing to make the 'recently closed'
- * section appear at the bottom of the page.
- */
- function updateMostVisitedHeight() {
- if (!isTablet())
- return;
- // subtract away height of button bar
- var windowHeight = document.documentElement.offsetHeight;
- var padding = parseInt(window.getComputedStyle(document.body)
- .getPropertyValue('padding-bottom'));
- $('most_visited_container').style.minHeight =
- (windowHeight - padding) + 'px';
- }
-
- /**
- * Called by the native toolbar to open a different section. This handles
- * updating the hash url which in turns makes a history entry.
- *
- * @param {string} section The section to switch to.
- */
- var openSection = function(section) {
- if (!scrollToPane(getPaneIndex(section)))
- return;
- // Update the url so the native toolbar knows the pane has changed and
- // to create a history entry.
- document.location.hash = '#' + section;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // NTP Scoped Window Event Listeners.
- /////////////////////////////////////////////////////////////////////////////
-
- /**
- * Handles history on pop state changes.
- */
- function onPopStateHandler(event) {
- if (event.state != null) {
- var evtState = event.state;
- // Navigate back to the previously selected panel and ensure the same
- // bookmarks are loaded.
- var selectedPaneIndex = evtState.selectedPaneIndex == undefined ?
- 0 : evtState.selectedPaneIndex;
-
- scrollToPane(selectedPaneIndex);
- setCurrentBookmarkFolderData(evtState.folderId);
- } else {
- // When loading the page, replace the default state with one that
- // specifies the default panel loaded via localStorage as well as the
- // default bookmark folder.
- history.replaceState(
- {folderId: bookmarkFolderId, selectedPaneIndex: currentPaneIndex},
- null, null);
- }
- }
-
- /**
- * Handles window resize events.
- */
- function windowResizeHandler() {
- // Scroll to the current pane to refactor all the margins and offset.
- scrollToPane(currentPaneIndex);
- computeDynamicLayout();
- // Center the padding for each of the grid views.
- centerChildGrids(document);
- centerEmptySections(document);
- }
-
- /*
- * We implement the context menu ourselves.
- */
- function contextMenuHandler(evt) {
- var section = SectionType.UNKNOWN;
- contextMenuUrl = null;
- contextMenuItem = null;
- // The node with a menu have been tagged with their section and url.
- // Let's find these tags.
- var node = evt.target;
- while (node) {
- if (section == SectionType.UNKNOWN &&
- node.getAttribute &&
- node.getAttribute(SECTION_KEY) != null) {
- section = node.getAttribute(SECTION_KEY);
- if (contextMenuUrl != null)
- break;
- }
- if (contextMenuUrl == null) {
- contextMenuUrl = node.getAttribute(CONTEXT_MENU_URL_KEY);
- contextMenuItem = node.contextMenuItem;
- if (section != SectionType.UNKNOWN)
- break;
- }
- node = node.parentNode;
- }
-
- var menuOptions;
-
- if (section == SectionType.BOOKMARKS &&
- !contextMenuItem.folder && !isIncognito) {
- menuOptions = [
- [
- ContextMenuItemIds.BOOKMARK_OPEN_IN_NEW_TAB,
- templateData.elementopeninnewtab
- ]
- ];
- if (isIncognitoEnabled) {
- menuOptions.push([
- ContextMenuItemIds.BOOKMARK_OPEN_IN_INCOGNITO_TAB,
- templateData.elementopeninincognitotab
- ]);
- }
- if (contextMenuItem.editable) {
- menuOptions.push(
- [ContextMenuItemIds.BOOKMARK_EDIT, templateData.bookmarkedit],
- [ContextMenuItemIds.BOOKMARK_DELETE, templateData.bookmarkdelete]);
- }
- } else if (section == SectionType.BOOKMARKS &&
- !contextMenuItem.folder &&
- isIncognito) {
- menuOptions = [
- [
- ContextMenuItemIds.BOOKMARK_OPEN_IN_INCOGNITO_TAB,
- templateData.elementopeninincognitotab
- ]
- ];
- } else if (section == SectionType.BOOKMARKS &&
- contextMenuItem.folder &&
- contextMenuItem.editable &&
- !isIncognito) {
- menuOptions = [
- [ContextMenuItemIds.BOOKMARK_EDIT, templateData.editfolder],
- [ContextMenuItemIds.BOOKMARK_DELETE, templateData.deletefolder]
- ];
- } else if (section == SectionType.MOST_VISITED) {
- menuOptions = [
- [
- ContextMenuItemIds.MOST_VISITED_OPEN_IN_NEW_TAB,
- templateData.elementopeninnewtab
- ],
- ];
- if (isIncognitoEnabled) {
- menuOptions.push([
- ContextMenuItemIds.MOST_VISITED_OPEN_IN_INCOGNITO_TAB,
- templateData.elementopeninincognitotab
- ]);
- }
- menuOptions.push(
- [ContextMenuItemIds.MOST_VISITED_REMOVE, templateData.elementremove]);
- } else if (section == SectionType.RECENTLY_CLOSED) {
- menuOptions = [
- [
- ContextMenuItemIds.RECENTLY_CLOSED_OPEN_IN_NEW_TAB,
- templateData.elementopeninnewtab
- ],
- ];
- if (isIncognitoEnabled) {
- menuOptions.push([
- ContextMenuItemIds.RECENTLY_CLOSED_OPEN_IN_INCOGNITO_TAB,
- templateData.elementopeninincognitotab
- ]);
- }
- menuOptions.push(
- [ContextMenuItemIds.RECENTLY_CLOSED_REMOVE, templateData.removeall]);
- } else if (section == SectionType.FOREIGN_SESSION_HEADER) {
- menuOptions = [
- [
- ContextMenuItemIds.FOREIGN_SESSIONS_REMOVE,
- templateData.elementremove
- ]
- ];
- } else if (section == SectionType.PROMO_VC_SESSION_HEADER) {
- menuOptions = [
- [
- ContextMenuItemIds.PROMO_VC_SESSION_REMOVE,
- templateData.elementremove
- ]
- ];
- }
-
- if (menuOptions)
- chrome.send('showContextMenu', menuOptions);
-
- return false;
- }
-
- // Return an object with all the exports
- return {
- bookmarks: bookmarks,
- bookmarkChanged: bookmarkChanged,
- clearPromotions: clearPromotions,
- init: init,
- setIncognitoEnabled: setIncognitoEnabled,
- onCustomMenuSelected: onCustomMenuSelected,
- openSection: openSection,
- setFaviconDominantColor: setFaviconDominantColor,
- setForeignSessions: setForeignSessions,
- setIncognitoMode: setIncognitoMode,
- setMostVisitedPages: setMostVisitedPages,
- setPromotions: setPromotions,
- setRecentlyClosedTabs: setRecentlyClosedTabs,
- setSyncEnabled: setSyncEnabled,
- snapshots: snapshots
- };
-});
-
-/////////////////////////////////////////////////////////////////////////////
-//Utility Functions.
-/////////////////////////////////////////////////////////////////////////////
-
-/**
- * A best effort approach for checking simple data object equality.
- * @param {?} val1 The first value to check equality for.
- * @param {?} val2 The second value to check equality for.
- * @return {boolean} Whether the two objects are equal(ish).
- */
-function equals(val1, val2) {
- if (typeof val1 != 'object' || typeof val2 != 'object')
- return val1 === val2;
-
- // Object and array equality checks.
- var keyCountVal1 = 0;
- for (var key in val1) {
- if (!(key in val2) || !equals(val1[key], val2[key]))
- return false;
- keyCountVal1++;
- }
- var keyCountVal2 = 0;
- for (var key in val2)
- keyCountVal2++;
- if (keyCountVal1 != keyCountVal2)
- return false;
- return true;
-}
-
-/**
- * Alias for document.getElementById.
- * @param {string} id The ID of the element to find.
- * @return {HTMLElement} The found element or null if not found.
- */
-function $(id) {
- return document.getElementById(id);
-}
-
-/**
- * @return {boolean} Whether the device is currently in portrait mode.
- */
-function isPortrait() {
- return document.documentElement.offsetWidth <
- document.documentElement.offsetHeight;
-}
-
-/**
- * Determine if the page should be formatted for tablets.
- * @return {boolean} true if the device is a tablet, false otherwise.
- */
-function isTablet() {
- return document.body.getAttribute('device') == 'tablet';
-}
-
-/**
- * Determine if the page should be formatted for phones.
- * @return {boolean} true if the device is a phone, false otherwise.
- */
-function isPhone() {
- return document.body.getAttribute('device') == 'phone';
-}
-
-/**
- * Get the page X coordinate of a touch event.
- * @param {TouchEvent} evt The touch event triggered by the browser.
- * @return {number} The page X coordinate of the touch event.
- */
-function getTouchEventX(evt) {
- return (evt.touches[0] || e.changedTouches[0]).pageX;
-}
-
-/**
- * Get the page Y coordinate of a touch event.
- * @param {TouchEvent} evt The touch event triggered by the browser.
- * @return {number} The page Y coordinate of the touch event.
- */
-function getTouchEventY(evt) {
- return (evt.touches[0] || e.changedTouches[0]).pageY;
-}
-
-/**
- * @param {Element} el The item to get the width of.
- * @param {boolean} excludeMargin If true, exclude the width of the margin.
- * @return {number} The total width of a given item.
- */
-function getItemWidth(el, excludeMargin) {
- var elStyle = window.getComputedStyle(el);
- var width = el.offsetWidth;
- if (!width || width == 0) {
- width = parseInt(elStyle.getPropertyValue('width'));
- width +=
- parseInt(elStyle.getPropertyValue('border-left-width')) +
- parseInt(elStyle.getPropertyValue('border-right-width'));
- width +=
- parseInt(elStyle.getPropertyValue('padding-left')) +
- parseInt(elStyle.getPropertyValue('padding-right'));
- }
- if (!excludeMargin) {
- width += parseInt(elStyle.getPropertyValue('margin-left')) +
- parseInt(elStyle.getPropertyValue('margin-right'));
- }
- return width;
-}
-
-/**
- * @return {number} The padding height of the body due to the button bar
- */
-function getButtonBarPadding() {
- var body = document.getElementsByTagName('body')[0];
- var style = window.getComputedStyle(body);
- return parseInt(style.getPropertyValue('padding-bottom'));
-}
-
-/**
- * Modify a css rule
- * @param {string} selector The selector for the rule (passed to findCssRule())
- * @param {string} property The property to update
- * @param {string} value The value to update the property to
- * @return {boolean} true if the rule was updated, false otherwise.
- */
-function modifyCssRule(selector, property, value) {
- var rule = findCssRule(selector);
- if (!rule)
- return false;
- rule.style[property] = value;
- return true;
-}
-
-/**
- * Find a particular CSS rule. The stylesheets attached to the document
- * are traversed in reverse order. The rules in each stylesheet are also
- * traversed in reverse order. The first rule found to match the selector
- * is returned.
- * @param {string} selector The selector for the rule.
- * @return {Object} The rule if one was found, null otherwise
- */
-function findCssRule(selector) {
- var styleSheets = document.styleSheets;
- for (i = styleSheets.length - 1; i >= 0; i--) {
- var styleSheet = styleSheets[i];
- var rules = styleSheet.cssRules;
- if (rules == null)
- continue;
- for (j = rules.length - 1; j >= 0; j--) {
- if (rules[j].selectorText == selector)
- return rules[j];
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// NTP Entry point.
-/////////////////////////////////////////////////////////////////////////////
-
-/*
- * Handles initializing the UI when the page has finished loading.
- */
-window.addEventListener('DOMContentLoaded', function(evt) {
- ntp.init();
- $('content-area').style.display = 'block';
-});
diff --git a/chrome/browser/resources/ntp_android/opentabs.css b/chrome/browser/resources/ntp_android/opentabs.css
deleted file mode 100644
index cc005e3e..0000000
--- a/chrome/browser/resources/ntp_android/opentabs.css
+++ /dev/null
@@ -1,239 +0,0 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-.list-item {
- -webkit-tap-highlight-color: transparent;
- -webkit-transition: 300ms linear;
- -webkit-transition-property: background;
- background: transparent;
- height: 50px;
- padding-bottom: auto;
- padding-top: auto;
- position: relative; /* So the fader can be positioned at the end */
-}
-
-.list-item-active,
-.session-header .list-item.list-item-active {
- -webkit-tap-highlight-color: transparent;
- background: rgba(51, 181, 229, 0.4);
-}
-
-.list-item-active.no-active-delay {
- -webkit-transition: none;
-}
-
-.list-item.standard-divider {
- border-bottom: 1px solid #c1c1c1;
-}
-
-.list-item .section-divider {
- background-color: #777;
- bottom: 0;
- height: 2px;
- position: absolute;
- width: 100%;
-}
-
-.list-item .icon {
- background-position: center center;
- background-repeat: no-repeat;
- background-size: 24px;
- height: 48px;
- position: absolute;
- width: 48px;
-}
-
-html[dir='ltr'] .list-item .icon {
- left: 0;
-}
-
-html[dir='rtl'] .list-item .icon {
- right: 0;
-}
-
-.list-item .title {
- -webkit-box-align: center;
- color: #4c4c4c;
- display: -webkit-box;
- font-size: 16px;
- height: 100%;
- overflow: hidden;
- position: absolute;
- top: 0;
- white-space: nowrap;
-}
-
-html[dir='ltr'] .list-item .title {
- -webkit-mask-image: linear-gradient(
- to right,
- rgba(0,0,0,1),
- rgba(0,0,0,1) 85%,
- rgba(0,0,0,0) 95%,
- rgba(0,0,0,0))
- );
- left: 50px;
- right: 0;
-}
-
-html[dir='rtl'] .list-item .title {
- -webkit-mask-image: linear-gradient(
- to right,
- rgba(0,0,0,0)),
- rgba(0,0,0,0) 5%,
- rgba(0,0,0,1) 15%,
- rgba(0,0,0,1))
- );
- left: 0;
- right: 50px;
-}
-
-.list-item .session_container {
- width: 100%;
-}
-
-.list-item .session_title {
- display: inline-block;
- line-height: 50px;
-}
-
-.session-header .list-item {
- background: #ebebeb;
-}
-
-.title .session-name {
- color: #4c4c4c;
- font-weight: bold;
-}
-
-.title .session-last-synced {
- color: #8f8f8f;
- font-weight: bold;
-}
-
-.session-children-container {
- -webkit-transition: height 200ms ease-in-out;
- height: 100%; /* needed for collapse animation */
- overflow: hidden;
-}
-
-.session-header {
- position: relative;
-}
-
-.expando {
- background-size: 100%;
- height: 13px;
- margin-top: -6.5px;
- position: absolute;
- top: 50%;
- width: 14px;
-}
-
-html[dir='ltr'] .expando {
- right: 18.5px;
-}
-
-html[dir='rtl'] .expando {
- left: 18.5px;
-}
-
-.expando.open {
- background-image: url(images/disclosure_open_mdpi.png);
-}
-
-html[dir='rtl'] .expando.open {
- -webkit-transform: scaleX(-1);
-}
-
-.expando.closed {
- background-image: url(images/disclosure_closed_mdpi.png);
-}
-
-html[dir='rtl'] .expando.closed {
- -webkit-transform: scaleX(-1);
-}
-
-.session-icon.laptop {
- background-image: url(../../../../ui/webui/resources/images/laptop.png);
-}
-
-html[dir='rtl'] .session-icon.laptop {
- -webkit-transform: scaleX(-1);
-}
-
-.session-icon.tablet {
- background-image: url(../../../../ui/webui/resources/images/tablet.png);
-}
-
-html[dir='rtl'] .session-icon.tablet {
- -webkit-transform: scaleX(-1);
-}
-
-.session-icon.phone {
- background-image: url(../../../../ui/webui/resources/images/phone.png);
-}
-
-html[dir='rtl'] .session-icon.phone {
- -webkit-transform: scaleX(-1);
-}
-
-.session-icon.documents {
- background-image: url(images/sent_mdpi.png);
-}
-
-html[dir='rtl'] .session-icon.documents {
- -webkit-transform: scaleX(-1);
-}
-
-@media screen and (-webkit-min-device-pixel-ratio: 1.5) {
- .expando.open {
- background-image: url(images/disclosure_open_hdpi.png);
- }
- .expando.closed {
- background-image: url(images/disclosure_closed_hdpi.png);
- }
- .session-icon.laptop {
- background-image:
- url(../../../../ui/webui/resources/images/1.5x/laptop.png);
- }
- .session-icon.tablet {
- background-image:
- url(../../../../ui/webui/resources/images/1.5x/tablet.png);
- }
- .session-icon.phone {
- background-image: url(../../../../ui/webui/resources/images/1.5x/phone.png);
- }
- .session-icon.documents {
- background-image: url(images/sent_hdpi.png);
- }
-}
-
-@media screen and (-webkit-min-device-pixel-ratio: 2.0) {
- .expando.open {
- background-image: url(images/disclosure_open_xhdpi.png);
- }
- .expando.closed {
- background-image: url(images/disclosure_closed_xhdpi.png);
- }
- .session-icon.laptop {
- background-image: url(../../../../ui/webui/resources/images/2x/laptop.png);
- }
- .session-icon.tablet {
- background-image: url(../../../../ui/webui/resources/images/2x/tablet.png);
- }
- .session-icon.phone {
- background-image: url(../../../../ui/webui/resources/images/2x/phone.png);
- }
- .session-icon.documents {
- background-image: url(images/sent_xhdpi.png);
- }
-}
-
-.session-icon {
- background-position: center;
- background-repeat: no-repeat;
- background-size: 32px 32px;
- height: 48px;
- width: 48px;
-}
diff --git a/chrome/browser/resources/ntp_android/opentabs_tablet.css b/chrome/browser/resources/ntp_android/opentabs_tablet.css
deleted file mode 100644
index 7df6d62..0000000
--- a/chrome/browser/resources/ntp_android/opentabs_tablet.css
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-body[device='tablet'] #open_tabs_container {
- padding-bottom: 40px;
-}
-
-body[device='tablet'] #open_tabs_container .page-list>div {
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.16);
- margin: 40px auto 0 auto;
- max-width: 550px;
- min-width: 500px;
-}
-
-@media only screen and (min-device-width: 700px) {
- body[device='tablet'] #open_tabs_container .page-list>div {
- max-width: 650px;
- }
-}
-
-body[device='tablet'] .session-children-container>div:last-child {
- border-bottom: none;
-}
-
-body[device='tablet'] #open_tabs_container .session-header .list-item {
- background: #F2F2F2;
- border-bottom: 1px solid #E7E7E7;
- color: #777;
- font-size: 0.8em;
- padding: 20px 0 20px 0;
-}
-
-body[device='tablet'] #open_tabs_container .list-item {
- background: #FAFAFA;
- border: 1px solid #E0E0E0;
- border-bottom: none;
-}
-
-body[device='tablet'] #open_tabs_container .list-item-active,
-body[device='tablet'] #open_tabs_container .session-header
- .list-item.list-item-active {
- -webkit-tap-highlight-color: transparent;
- background: rgba(51, 181, 229, 0.4);
-}
-
-body[device='tablet'] .session-name {
- color: #333;
- font-size: 1.1em;
- font-weight: bold;
- line-height: 1.8em;
-}
-
-body[device='tablet'] .session-last-synced {
- font-weight: normal;
-}
-
-body[device='tablet'] #open_tabs_container .session-children-container
- .list-item:first-child {
- border-top: none;
-}
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 808a7d0..db35dd1d 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -109,9 +109,14 @@
content::URLDataSource::Add(profile_, new ThemeSource(profile_));
#endif // defined(ENABLE_THEMES)
+ // TODO(aurimas) remove this #if once instant_service.cc is no longer compiled
+ // on Android.
+#if !defined(OS_ANDROID)
content::URLDataSource::Add(profile_, new ThumbnailSource(profile_, false));
content::URLDataSource::Add(profile_, new ThumbnailSource(profile_, true));
content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_));
+#endif // !defined(OS_ANDROID)
+
content::URLDataSource::Add(
profile_, new FaviconSource(profile_, FaviconSource::FAVICON));
content::URLDataSource::Add(profile_, new LocalNtpSource(profile_));
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 1b68a2b..e9c9779 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -468,20 +468,29 @@
}
void SearchTabHelper::OnLogEvent(NTPLoggingEventType event) {
+// TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
+#if !defined(OS_ANDROID)
NTPUserDataLogger::GetOrCreateFromWebContents(
web_contents())->LogEvent(event);
+#endif
}
void SearchTabHelper::OnLogMostVisitedImpression(
int position, const base::string16& provider) {
+// TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
+#if !defined(OS_ANDROID)
NTPUserDataLogger::GetOrCreateFromWebContents(
web_contents())->LogMostVisitedImpression(position, provider);
+#endif
}
void SearchTabHelper::OnLogMostVisitedNavigation(
int position, const base::string16& provider) {
+// TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef.
+#if !defined(OS_ANDROID)
NTPUserDataLogger::GetOrCreateFromWebContents(
web_contents())->LogMostVisitedNavigation(position, provider);
+#endif
}
void SearchTabHelper::PasteIntoOmnibox(const base::string16& text) {
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index d64f4dbe..1f1e9421 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -37,7 +37,6 @@
#include "chrome/browser/ui/webui/invalidations_ui.h"
#include "chrome/browser/ui/webui/memory_internals/memory_internals_ui.h"
#include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
-#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
#include "chrome/browser/ui/webui/omnibox/omnibox_ui.h"
#include "chrome/browser/ui/webui/options/options_ui.h"
#include "chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h"
@@ -96,6 +95,7 @@
#if defined(OS_ANDROID)
#include "chrome/browser/ui/webui/welcome_ui_android.h"
#else
+#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
#include "chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui.h"
#include "chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_ui.h"
#include "chrome/browser/ui/webui/system_info_ui.h"
diff --git a/chrome/browser/ui/webui/metrics_handler.cc b/chrome/browser/ui/webui/metrics_handler.cc
index 4c0f944cf..99fb592 100644
--- a/chrome/browser/ui/webui/metrics_handler.cc
+++ b/chrome/browser/ui/webui/metrics_handler.cc
@@ -116,6 +116,9 @@
}
void MetricsHandler::HandleLogMouseover(const base::ListValue* args) {
+#if !defined(OS_ANDROID)
+ // Android uses native UI for NTP.
NTPUserDataLogger::GetOrCreateFromWebContents(
web_ui()->GetWebContents())->LogEvent(NTP_MOUSEOVER);
+#endif // !defined(OS_ANDROID)
}
diff --git a/chrome/browser/ui/webui/ntp/android/OWNERS b/chrome/browser/ui/webui/ntp/android/OWNERS
deleted file mode 100644
index 0d259ac..0000000
--- a/chrome/browser/ui/webui/ntp/android/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
[email protected]
[email protected]
[email protected]
diff --git a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc
deleted file mode 100644
index 51afaff..0000000
--- a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc
+++ /dev/null
@@ -1,583 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/android/bookmarks_handler.h"
-
-#include "base/logging.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/metrics/histogram.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "chrome/browser/android/tab_android.h"
-#include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/favicon/favicon_service_factory.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/favicon_source.h"
-#include "chrome/common/pref_names.h"
-#include "components/bookmarks/core/browser/bookmark_model.h"
-#include "components/bookmarks/core/browser/bookmark_utils.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/url_data_source.h"
-#include "content/public/browser/web_contents.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/color_analysis.h"
-#include "ui/gfx/favicon_size.h"
-
-using base::Int64ToString;
-using content::BrowserThread;
-
-namespace {
-
-static const char* kParentIdParam = "parent_id";
-static const char* kNodeIdParam = "node_id";
-
-// Defines actions taken by the user over the partner bookmarks on NTP for
-// NewTabPage.BookmarkActionAndroid histogram.
-// Should be kept in sync with the values in histograms.xml.
-enum PartnerBookmarkAction {
- BOOKMARK_ACTION_DELETE_BOOKMARK_PARTNER = 0,
- BOOKMARK_ACTION_DELETE_ROOT_FOLDER_PARTNER = 1,
- BOOKMARK_ACTION_EDIT_BOOKMARK_PARTNER = 2,
- BOOKMARK_ACTION_EDIT_ROOT_FOLDER_PARTNER = 3,
- BOOKMARK_ACTION_BUCKET_BOUNDARY = 4
-};
-
-// Helper to record a bookmark action in BookmarkActionAndroid histogram.
-void RecordBookmarkAction(PartnerBookmarkAction type) {
- UMA_HISTOGRAM_ENUMERATION("NewTabPage.BookmarkActionAndroid", type,
- BOOKMARK_ACTION_BUCKET_BOUNDARY);
-}
-
-std::string BookmarkTypeAsString(BookmarkNode::Type type) {
- switch (type) {
- case BookmarkNode::URL:
- return "URL";
- case BookmarkNode::FOLDER:
- return "FOLDER";
- case BookmarkNode::BOOKMARK_BAR:
- return "BOOKMARK_BAR";
- case BookmarkNode::OTHER_NODE:
- return "OTHER_NODE";
- case BookmarkNode::MOBILE:
- return "MOBILE";
- default:
- return "UNKNOWN";
- }
-}
-
-SkColor GetDominantColorForFavicon(scoped_refptr<base::RefCountedMemory> png) {
- color_utils::GridSampler sampler;
- // 100 here is the darkness_limit which represents the minimum sum of the RGB
- // components that is acceptable as a color choice. This can be from 0 to 765.
- // 665 here is the brightness_limit represents the maximum sum of the RGB
- // components that is acceptable as a color choice. This can be from 0 to 765.
- return color_utils::CalculateKMeanColorOfPNG(png, 100, 665, &sampler);
-}
-
-} // namespace
-
-BookmarksHandler::BookmarksHandler()
- : bookmark_model_(NULL),
- partner_bookmarks_shim_(NULL),
- bookmark_data_requested_(false),
- extensive_changes_(false) {
-}
-
-BookmarksHandler::~BookmarksHandler() {
- if (bookmark_model_)
- bookmark_model_->RemoveObserver(this);
-
- if (partner_bookmarks_shim_)
- partner_bookmarks_shim_->RemoveObserver(this);
-
- if (managed_bookmarks_shim_)
- managed_bookmarks_shim_->RemoveObserver(this);
-}
-
-void BookmarksHandler::RegisterMessages() {
- // Listen for the bookmark change. We need the both bookmark and folder
- // change, the NotificationService is not sufficient.
- Profile* profile = Profile::FromBrowserContext(
- web_ui()->GetWebContents()->GetBrowserContext());
-
- content::URLDataSource::Add(
- profile, new FaviconSource(profile, FaviconSource::ANY));
-
- bookmark_model_ = BookmarkModelFactory::GetForProfile(profile);
- if (bookmark_model_) {
- bookmark_model_->AddObserver(this);
- // Since a sync or import could have started before this class is
- // initialized, we need to make sure that our initial state is
- // up to date.
- extensive_changes_ = bookmark_model_->IsDoingExtensiveChanges();
- }
-
- // Create the partner Bookmarks shim as early as possible (but don't attach).
- if (!partner_bookmarks_shim_) {
- partner_bookmarks_shim_ = PartnerBookmarksShim::BuildForBrowserContext(
- chrome::GetBrowserContextRedirectedInIncognito(
- web_ui()->GetWebContents()->GetBrowserContext()));
- partner_bookmarks_shim_->AddObserver(this);
- }
-
- managed_bookmarks_shim_.reset(new ManagedBookmarksShim(profile->GetPrefs()));
- managed_bookmarks_shim_->AddObserver(this);
-
- // Register ourselves as the handler for the bookmark javascript callbacks.
- web_ui()->RegisterMessageCallback("getBookmarks",
- base::Bind(&BookmarksHandler::HandleGetBookmarks,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("deleteBookmark",
- base::Bind(&BookmarksHandler::HandleDeleteBookmark,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("editBookmark",
- base::Bind(&BookmarksHandler::HandleEditBookmark,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("createHomeScreenBookmarkShortcut",
- base::Bind(&BookmarksHandler::HandleCreateHomeScreenBookmarkShortcut,
- base::Unretained(this)));
-}
-
-void BookmarksHandler::HandleGetBookmarks(const base::ListValue* args) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- bookmark_data_requested_ = true;
- if (!AreModelsLoaded())
- return; // is handled in Loaded()/PartnerShimLoaded() callback.
-
- const BookmarkNode* node = GetNodeByID(args);
- if (node)
- QueryBookmarkFolder(node);
- else
- QueryInitialBookmarks();
-}
-
-void BookmarksHandler::HandleDeleteBookmark(const base::ListValue* args) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!AreModelsLoaded())
- return;
-
- const BookmarkNode* node = GetNodeByID(args);
- if (!node)
- return;
-
- if (!IsEditable(node)) {
- NOTREACHED();
- return;
- }
-
- if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
- if (partner_bookmarks_shim_->GetPartnerBookmarksRoot() == node)
- RecordBookmarkAction(BOOKMARK_ACTION_DELETE_ROOT_FOLDER_PARTNER);
- else
- RecordBookmarkAction(BOOKMARK_ACTION_DELETE_BOOKMARK_PARTNER);
- partner_bookmarks_shim_->RemoveBookmark(node);
- return;
- }
-
- const BookmarkNode* parent_node = node->parent();
- bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
-}
-
-void BookmarksHandler::HandleEditBookmark(const base::ListValue* args) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!AreModelsLoaded())
- return;
-
- const BookmarkNode* node = GetNodeByID(args);
- if (!node)
- return;
-
- if (!IsEditable(node)) {
- NOTREACHED();
- return;
- }
-
- TabAndroid* tab = TabAndroid::FromWebContents(web_ui()->GetWebContents());
- if (tab) {
- if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
- if (partner_bookmarks_shim_->GetPartnerBookmarksRoot() == node)
- RecordBookmarkAction(BOOKMARK_ACTION_EDIT_ROOT_FOLDER_PARTNER);
- else
- RecordBookmarkAction(BOOKMARK_ACTION_EDIT_BOOKMARK_PARTNER);
- }
- tab->EditBookmark(node->id(),
- GetTitle(node),
- node->is_folder(),
- partner_bookmarks_shim_->IsPartnerBookmark(node));
- }
-}
-
-bool BookmarksHandler::AreModelsLoaded() const {
- Profile* profile = Profile::FromBrowserContext(
- web_ui()->GetWebContents()->GetBrowserContext());
- if (!profile)
- return false;
-
- BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile);
- if (!model || !model->loaded())
- return false;
-
- return partner_bookmarks_shim_ && partner_bookmarks_shim_->IsLoaded();
-}
-
-void BookmarksHandler::NotifyModelChanged(const base::DictionaryValue& status) {
- DCHECK(AreModelsLoaded());
-
- if (bookmark_data_requested_ && !extensive_changes_)
- web_ui()->CallJavascriptFunction("ntp.bookmarkChanged", status);
-}
-
-std::string BookmarksHandler::GetBookmarkIdForNtp(const BookmarkNode* node) {
- DCHECK(AreModelsLoaded());
-
- std::string prefix;
- if (partner_bookmarks_shim_->IsPartnerBookmark(node))
- prefix = "p";
- else if (managed_bookmarks_shim_->IsManagedBookmark(node))
- prefix = "m";
- return prefix + Int64ToString(node->id());
-}
-
-void BookmarksHandler::SetParentInBookmarksResult(
- const BookmarkNode* parent,
- base::DictionaryValue* result) {
- result->SetString(kParentIdParam, GetBookmarkIdForNtp(parent));
-}
-
-void BookmarksHandler::PopulateBookmark(const BookmarkNode* node,
- base::ListValue* result) {
- if (!result)
- return;
-
- DCHECK(AreModelsLoaded());
- if (!IsReachable(node))
- return;
-
- base::DictionaryValue* filler_value = new base::DictionaryValue();
- filler_value->SetString("title", GetTitle(node));
- filler_value->SetBoolean("editable", IsEditable(node));
- if (node->is_url()) {
- filler_value->SetBoolean("folder", false);
- filler_value->SetString("url", node->url().spec());
- } else {
- filler_value->SetBoolean("folder", true);
- }
- filler_value->SetString("id", GetBookmarkIdForNtp(node));
- filler_value->SetString("type", BookmarkTypeAsString(node->type()));
- result->Append(filler_value);
-}
-
-void BookmarksHandler::PopulateBookmarksInFolder(
- const BookmarkNode* folder,
- base::DictionaryValue* result) {
- DCHECK(AreModelsLoaded());
- if (!IsReachable(folder))
- return;
-
- base::ListValue* bookmarks = new base::ListValue();
-
- // If this is the Mobile bookmarks folder then add the "Managed bookmarks"
- // folder first, so that it's the first entry.
- if (bookmark_model_ && folder == bookmark_model_->mobile_node() &&
- managed_bookmarks_shim_->HasManagedBookmarks()) {
- PopulateBookmark(managed_bookmarks_shim_->GetManagedBookmarksRoot(),
- bookmarks);
- }
-
- for (int i = 0; i < folder->child_count(); i++) {
- const BookmarkNode* bookmark= folder->GetChild(i);
- PopulateBookmark(bookmark, bookmarks);
- }
-
- // Make sure we iterate over the partner's attach point
- if (bookmark_model_ && folder == bookmark_model_->mobile_node() &&
- partner_bookmarks_shim_->HasPartnerBookmarks()) {
- PopulateBookmark(partner_bookmarks_shim_->GetPartnerBookmarksRoot(),
- bookmarks);
- }
-
- base::ListValue* folder_hierarchy = new base::ListValue();
- const BookmarkNode* parent = GetParentOf(folder);
-
- while (parent != NULL) {
- base::DictionaryValue* hierarchy_entry = new base::DictionaryValue();
- if (IsRoot(parent))
- hierarchy_entry->SetBoolean("root", true);
-
- hierarchy_entry->SetString("title", GetTitle(parent));
- hierarchy_entry->SetString("id", GetBookmarkIdForNtp(parent));
- folder_hierarchy->Append(hierarchy_entry);
- parent = GetParentOf(parent);
- }
-
- result->SetString("title", GetTitle(folder));
- result->SetString("id", GetBookmarkIdForNtp(folder));
- result->SetBoolean("root", IsRoot(folder));
- result->Set("bookmarks", bookmarks);
- result->Set("hierarchy", folder_hierarchy);
-}
-
-void BookmarksHandler::QueryBookmarkFolder(const BookmarkNode* node) {
- DCHECK(AreModelsLoaded());
- if (node->is_folder() && IsReachable(node)) {
- base::DictionaryValue result;
- PopulateBookmarksInFolder(node, &result);
- SendResult(result);
- } else {
- // If we receive an ID that no longer maps to a bookmark folder, just
- // return the initial bookmark folder.
- QueryInitialBookmarks();
- }
-}
-
-void BookmarksHandler::QueryInitialBookmarks() {
- DCHECK(AreModelsLoaded());
- base::DictionaryValue result;
- PopulateBookmarksInFolder(bookmark_model_->mobile_node(), &result);
- SendResult(result);
-}
-
-void BookmarksHandler::SendResult(const base::DictionaryValue& result) {
- web_ui()->CallJavascriptFunction("ntp.bookmarks", result);
-}
-
-void BookmarksHandler::BookmarkModelLoaded(BookmarkModel* model,
- bool ids_reassigned) {
- if (AreModelsLoaded())
- BookmarkModelChanged();
-}
-
-void BookmarksHandler::PartnerShimChanged(PartnerBookmarksShim* shim) {
- if (AreModelsLoaded())
- BookmarkModelChanged();
-}
-
-void BookmarksHandler::PartnerShimLoaded(PartnerBookmarksShim* shim) {
- if (AreModelsLoaded())
- BookmarkModelChanged();
-}
-
-void BookmarksHandler::ShimBeingDeleted(PartnerBookmarksShim* shim) {
- partner_bookmarks_shim_ = NULL;
-}
-
-void BookmarksHandler::OnManagedBookmarksChanged() {
- if (AreModelsLoaded())
- BookmarkModelChanged();
-}
-
-void BookmarksHandler::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
- extensive_changes_ = true;
-}
-
-void BookmarksHandler::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
- extensive_changes_ = false;
- if (AreModelsLoaded())
- BookmarkModelChanged();
-}
-
-void BookmarksHandler::BookmarkNodeRemoved(BookmarkModel* model,
- const BookmarkNode* parent,
- int old_index,
- const BookmarkNode* node) {
- if (!AreModelsLoaded())
- return;
-
- base::DictionaryValue result;
- SetParentInBookmarksResult(parent, &result);
- result.SetString(kNodeIdParam, Int64ToString(node->id()));
- NotifyModelChanged(result);
-}
-
-void BookmarksHandler::BookmarkAllNodesRemoved(BookmarkModel* model) {
- if (!AreModelsLoaded())
- return;
-
- if (bookmark_data_requested_ && !extensive_changes_)
- web_ui()->CallJavascriptFunction("ntp.bookmarkChanged");
-}
-
-void BookmarksHandler::BookmarkNodeAdded(
- BookmarkModel* model, const BookmarkNode* parent, int index) {
- if (!AreModelsLoaded())
- return;
-
- base::DictionaryValue result;
- SetParentInBookmarksResult(parent, &result);
- NotifyModelChanged(result);
-}
-
-void BookmarksHandler::BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node) {
- if (!AreModelsLoaded())
- return;
-
- DCHECK(!partner_bookmarks_shim_->IsPartnerBookmark(node));
- base::DictionaryValue result;
- SetParentInBookmarksResult(node->parent(), &result);
- result.SetString(kNodeIdParam, Int64ToString(node->id()));
- NotifyModelChanged(result);
-}
-
-void BookmarksHandler::BookmarkModelChanged() {
- if (!AreModelsLoaded())
- return;
-
- if (bookmark_data_requested_ && !extensive_changes_)
- web_ui()->CallJavascriptFunction("ntp.bookmarkChanged");
-}
-
-void BookmarksHandler::HandleCreateHomeScreenBookmarkShortcut(
- const base::ListValue* args) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!AreModelsLoaded())
- return;
-
- Profile* profile = Profile::FromBrowserContext(
- web_ui()->GetWebContents()->GetBrowserContext());
- if (!profile)
- return;
-
- const BookmarkNode* node = GetNodeByID(args);
- if (!node)
- return;
-
- FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
- profile, Profile::EXPLICIT_ACCESS);
- favicon_service->GetRawFaviconForURL(
- FaviconService::FaviconForURLParams(node->url(),
- favicon_base::TOUCH_PRECOMPOSED_ICON |
- favicon_base::TOUCH_ICON |
- favicon_base::FAVICON,
- 0), // request the largest icon.
- ui::SCALE_FACTOR_100P, // density doesn't matter for the largest icon.
- base::Bind(&BookmarksHandler::OnShortcutFaviconDataAvailable,
- base::Unretained(this),
- node),
- &cancelable_task_tracker_);
-}
-
-void BookmarksHandler::OnShortcutFaviconDataAvailable(
- const BookmarkNode* node,
- const favicon_base::FaviconBitmapResult& bitmap_result) {
- if (!AreModelsLoaded())
- return;
-
- SkColor color = SK_ColorWHITE;
- SkBitmap favicon_bitmap;
- if (bitmap_result.is_valid()) {
- color = GetDominantColorForFavicon(bitmap_result.bitmap_data);
- gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(),
- bitmap_result.bitmap_data->size(),
- &favicon_bitmap);
- }
- TabAndroid* tab = TabAndroid::FromWebContents(web_ui()->GetWebContents());
- if (tab) {
- tab->AddShortcutToBookmark(node->url(),
- GetTitle(node),
- favicon_bitmap, SkColorGetR(color),
- SkColorGetG(color), SkColorGetB(color));
- }
-}
-
-const BookmarkNode* BookmarksHandler::GetNodeByID(
- const base::ListValue* args) const {
- DCHECK(AreModelsLoaded());
-
- // Parses a bookmark ID passed back from the NTP. The IDs differ from the
- // normal int64 bookmark ID because we prepend a "p" if the ID represents a
- // partner bookmark, and an "m" if the ID represents a managed bookmark.
-
- if (!args || args->empty())
- return NULL;
-
- std::string string_id;
- if (!args->GetString(0, &string_id) || string_id.empty()) {
- NOTREACHED();
- return NULL;
- }
-
- bool is_partner = string_id[0] == 'p';
- bool is_managed = string_id[0] == 'm';
-
- if (is_partner || is_managed)
- string_id = string_id.substr(1);
-
- int64 id = 0;
- if (!base::StringToInt64(string_id, &id)) {
- NOTREACHED();
- return NULL;
- }
-
- if (is_managed)
- return managed_bookmarks_shim_->GetNodeByID(id);
-
- if (is_partner)
- return partner_bookmarks_shim_->GetNodeByID(id);
-
- return GetBookmarkNodeByID(bookmark_model_, id);
-}
-
-const BookmarkNode* BookmarksHandler::GetParentOf(
- const BookmarkNode* node) const {
- DCHECK(AreModelsLoaded());
- if (node == managed_bookmarks_shim_->GetManagedBookmarksRoot() ||
- node == partner_bookmarks_shim_->GetPartnerBookmarksRoot()) {
- return bookmark_model_->mobile_node();
- }
-
- return node->parent();
-}
-
-base::string16 BookmarksHandler::GetTitle(const BookmarkNode* node) const {
- DCHECK(AreModelsLoaded());
- if (partner_bookmarks_shim_->IsPartnerBookmark(node))
- return partner_bookmarks_shim_->GetTitle(node);
-
- return node->GetTitle();
-}
-
-bool BookmarksHandler::IsReachable(const BookmarkNode* node) const {
- DCHECK(AreModelsLoaded());
- if (!partner_bookmarks_shim_->IsPartnerBookmark(node))
- return true;
-
- return partner_bookmarks_shim_->IsReachable(node);
-}
-
-bool BookmarksHandler::IsEditable(const BookmarkNode* node) const {
- DCHECK(AreModelsLoaded());
-
- // Reserved system nodes and managed bookmarks are not editable.
- // Additionally, bookmark editing may be completely disabled
- // via a managed preference.
- if (!node ||
- (node->type() != BookmarkNode::FOLDER &&
- node->type() != BookmarkNode::URL)) {
- return false;
- }
-
- const PrefService* pref = Profile::FromBrowserContext(
- web_ui()->GetWebContents()->GetBrowserContext())->GetPrefs();
- if (!pref->GetBoolean(prefs::kEditBookmarksEnabled))
- return false;
-
- if (partner_bookmarks_shim_->IsPartnerBookmark(node))
- return true;
-
- return !managed_bookmarks_shim_->IsManagedBookmark(node);
-}
-
-bool BookmarksHandler::IsRoot(const BookmarkNode* node) const {
- DCHECK(AreModelsLoaded());
-
- return node->is_root() &&
- node != partner_bookmarks_shim_->GetPartnerBookmarksRoot() &&
- node != managed_bookmarks_shim_->GetManagedBookmarksRoot();
-}
diff --git a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h
deleted file mode 100644
index 679ca49..0000000
--- a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_BOOKMARKS_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_BOOKMARKS_HANDLER_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/task/cancelable_task_tracker.h"
-#include "base/values.h"
-#include "chrome/browser/android/bookmarks/managed_bookmarks_shim.h"
-#include "chrome/browser/android/bookmarks/partner_bookmarks_shim.h"
-#include "chrome/browser/favicon/favicon_service.h"
-#include "components/bookmarks/core/browser/base_bookmark_model_observer.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-// The handler for Javascript messages related to the bookmarks.
-//
-// In Javascript if getBookmarks() is called without any parameter, the 'Other
-// Bookmark' folder and bookmark bar's bookmarks and folders are returned.
-// If getBookmarks() is called with a valid bookmark folder id, the given
-// folder's bookmarks and sub folders of it are returned.
-//
-// All bookmarks and subfolder is returned by bookmarks() javascript callback
-// function.
-// The returned field 'folder' indicates whether the data is a folder. The
-// returned field 'root' indicates whether or not the bookmark list that was
-// returned is the root list or not. Besides these fields, a folder has id
-// and title fields; A bookmark has url and title fields.
-//
-// A sample result looks like:
-// {
-// title: 'Bookmark Bar',
-// id: '1',
-// root: true,
-// bookmarks: [
-// {
-// title: 'Cake',
-// url: 'http://www.google.com',
-// folder: false
-// },
-// {
-// title: 'Puppies',
-// folder: true,
-// id: '2'
-// }
-// ]
-// }
-class BookmarksHandler : public content::WebUIMessageHandler,
- public BaseBookmarkModelObserver,
- public PartnerBookmarksShim::Observer,
- public ManagedBookmarksShim::Observer {
- public:
- BookmarksHandler();
- virtual ~BookmarksHandler();
-
- // WebUIMessageHandler override and implementation.
- virtual void RegisterMessages() OVERRIDE;
-
- // Callback for the "getBookmarks" message.
- void HandleGetBookmarks(const base::ListValue* args);
- // Callback for the "deleteBookmark" message.
- void HandleDeleteBookmark(const base::ListValue* args);
- // Callback for the "editBookmark" message.
- void HandleEditBookmark(const base::ListValue* args);
- // Callback for the "createHomeScreenBookmarkShortcut" message. Used when
- // creating a shortcut on the home screen that should open the bookmark
- // specified in |args|.
- void HandleCreateHomeScreenBookmarkShortcut(const base::ListValue* args);
-
- // Override the methods of BookmarkModelObserver
- virtual void BookmarkModelLoaded(BookmarkModel* model,
- bool ids_reassigned) OVERRIDE;
- virtual void BookmarkModelChanged() OVERRIDE;
- virtual void ExtensiveBookmarkChangesBeginning(BookmarkModel* model) OVERRIDE;
- virtual void ExtensiveBookmarkChangesEnded(BookmarkModel* model) OVERRIDE;
- virtual void BookmarkNodeRemoved(BookmarkModel* model,
- const BookmarkNode* parent,
- int old_index,
- const BookmarkNode* node) OVERRIDE;
- virtual void BookmarkAllNodesRemoved(BookmarkModel* model) OVERRIDE;
- virtual void BookmarkNodeAdded(
- BookmarkModel* model, const BookmarkNode* parent, int index) OVERRIDE;
- virtual void BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node) OVERRIDE;
-
- // Override the methods of PartnerBookmarksShim::Observer
- virtual void PartnerShimChanged(PartnerBookmarksShim* shim) OVERRIDE;
- virtual void PartnerShimLoaded(PartnerBookmarksShim* shim) OVERRIDE;
- virtual void ShimBeingDeleted(PartnerBookmarksShim* shim) OVERRIDE;
-
- // Override the methods of ManagedBookmarksShim::Observer
- virtual void OnManagedBookmarksChanged() OVERRIDE;
-
- private:
- // The bookmark model being observed (if it has been attached).
- BookmarkModel* bookmark_model_;
-
- // Information about the Partner bookmarks (must check for IsLoaded())
- PartnerBookmarksShim* partner_bookmarks_shim_;
-
- // Contains the bookmarks managed via enterprise policy.
- scoped_ptr<ManagedBookmarksShim> managed_bookmarks_shim_;
-
- // Whether the bookmark data has been requested by the UI yet.
- bool bookmark_data_requested_;
-
- // Indicates that extensive changes to the BookmarkModel is on-going.
- bool extensive_changes_;
-
- // Used for loading bookmark node.
- base::CancelableTaskTracker cancelable_task_tracker_;
-
- // Returns true iff bookmark model and partner bookmarks shim are loaded.
- bool AreModelsLoaded() const;
-
- // Notify the UI that a change occurred to the bookmark model.
- void NotifyModelChanged(const base::DictionaryValue& status);
-
- // Generates the string encoded ID to be used by the NTP.
- std::string GetBookmarkIdForNtp(const BookmarkNode* node);
-
- // Sets the necessary parent information in the response object to be sent
- // to the UI renderer.
- void SetParentInBookmarksResult(const BookmarkNode* parent,
- base::DictionaryValue* result);
-
- // Convert the given bookmark |node| into a dictionary format to be returned
- // to JavaScript.
- void PopulateBookmark(const BookmarkNode* node, base::ListValue* result);
-
- // Given a bookmark folder node, |folder|, populate the |result| with the
- // structured JavaScript-formatted data regarding the folder.
- void PopulateBookmarksInFolder(const BookmarkNode* folder,
- base::DictionaryValue* result);
-
- // Sends all bookmarks and sub folders in the given folder back to the NTP.
- void QueryBookmarkFolder(const BookmarkNode* node);
-
- // Sends bookmark bar's bookmarks and sub folders and other folders back to
- // NTP.
- void QueryInitialBookmarks();
-
- // Sends the result back to Javascript
- void SendResult(const base::DictionaryValue& result);
-
- // Called once the favicon is loaded during creation of the bookmark shortcuts
- // and is available for use.
- void OnShortcutFaviconDataAvailable(
- const BookmarkNode* node,
- const favicon_base::FaviconBitmapResult& bitmap_result);
-
- // Looks at an optional bookmark ID in |args| and returns the corresponding
- // node if found, otherwise returns NULL.
- const BookmarkNode* GetNodeByID(const base::ListValue* args) const;
-
- // Returns the parent of |node|, or NULL if it's the root node.
- const BookmarkNode* GetParentOf(const BookmarkNode* node) const;
-
- // Returns the title of |node|, possibly remapped (if a partner bookmark).
- base::string16 GetTitle(const BookmarkNode* node) const;
-
- // Returns true if the node is reachable.
- bool IsReachable(const BookmarkNode* node) const;
-
- // Returns true if |node| can be modified by the user.
- bool IsEditable(const BookmarkNode* node) const;
-
- // Returns true if |node| is the real root node (not the root node of the
- // partner bookmarks shim nor the managed bookmark shim root).
- bool IsRoot(const BookmarkNode* node) const;
-
- DISALLOW_COPY_AND_ASSIGN(BookmarksHandler);
-};
-
-#endif // CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_BOOKMARKS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/android/context_menu_handler.cc b/chrome/browser/ui/webui/ntp/android/context_menu_handler.cc
deleted file mode 100644
index 8a25150..0000000
--- a/chrome/browser/ui/webui/ntp/android/context_menu_handler.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/android/context_menu_handler.h"
-
-#include "base/bind.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/prefs/incognito_mode_prefs.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/android/context_menu_helper.h"
-#include "chrome/common/pref_names.h"
-#include "content/public/browser/user_metrics.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/context_menu_params.h"
-#include "content/public/common/page_transition_types.h"
-
-ContextMenuHandler::ContextMenuHandler()
- : weak_ptr_factory_(this) {
-}
-
-ContextMenuHandler::~ContextMenuHandler() {
-}
-
-void ContextMenuHandler::RegisterMessages() {
- web_ui()->RegisterMessageCallback("showContextMenu",
- base::Bind(&ContextMenuHandler::HandleShowContextMenu,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("openInNewTab",
- base::Bind(&ContextMenuHandler::HandleOpenInNewTab,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("openInIncognitoTab",
- base::Bind(&ContextMenuHandler::HandleOpenInIncognitoTab,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("getIncognitoDisabled",
- base::Bind(&ContextMenuHandler::GetIncognitoDisabled,
- base::Unretained(this)));
-}
-
-void ContextMenuHandler::OnItemSelected(int item_id) {
- base::FundamentalValue value(item_id);
- web_ui()->CallJavascriptFunction("ntp.onCustomMenuSelected", value);
-}
-
-void ContextMenuHandler::GetIncognitoDisabled(
- const base::ListValue* args) {
- base::DictionaryValue value;
-
- const PrefService* pref = Profile::FromBrowserContext(
- web_ui()->GetWebContents()->GetBrowserContext())->GetPrefs();
-
- // Tell to ntp_android.js whether "open in new incognito tab" is allowed or
- // not in different context menus. This property can be disabled by
- // preferences (e.g. via policies).
- int pref_value = pref->GetInteger(prefs::kIncognitoModeAvailability);
- bool incognito_enabled = pref_value != IncognitoModePrefs::DISABLED;
- value.SetBoolean("incognitoEnabled", incognito_enabled);
- web_ui()->CallJavascriptFunction("ntp.setIncognitoEnabled", value);
-}
-
-void ContextMenuHandler::HandleShowContextMenu(
- const base::ListValue* menu_list_values) {
- if (menu_list_values->empty()) {
- LOG(WARNING) << "Ignoring request for empty context menu.";
- return;
- }
-
- // We expect menu_list_values to be of the form:
- // [ [ 1, "title1" ], [ 2, "title2" ], ...]
- // Where the first value in the sub-array is the item id and the second its
- // title.
- content::ContextMenuParams menu;
- for (size_t i = 0; i < menu_list_values->GetSize(); ++i) {
- base::ListValue* item_list_value = NULL;
- bool valid_value = menu_list_values->GetList(
- i, const_cast<const base::ListValue**>(&item_list_value));
- if (!valid_value) {
- LOG(ERROR) << "Invalid context menu request: menu item info " << i <<
- " is not a list.";
- return;
- }
-
- int id;
- if (!ExtractIntegerValue(item_list_value, &id)) {
- base::Value* value = NULL;
- item_list_value->Get(0, &value);
- LOG(ERROR) << "Invalid context menu request: menu item " << i <<
- " expected int value for first parameter (got " <<
- value->GetType() << ").";
- return;
- }
-
- content::MenuItem menu_item;
- menu_item.action = id;
- if (!item_list_value->GetString(1, &(menu_item.label))) {
- base::Value* value = NULL;
- item_list_value->Get(1, &value);
- LOG(ERROR) << "Invalid context menu request: menu item " << i <<
- " expected string value for second parameter (got " <<
- value->GetType() << ").";
- return;
- }
- menu.custom_items.push_back(menu_item);
- }
-
- ContextMenuHelper* context_menu_helper =
- ContextMenuHelper::FromWebContents(web_ui()->GetWebContents());
- if (context_menu_helper) {
- context_menu_helper->ShowCustomContextMenu(
- menu,
- base::Bind(&ContextMenuHandler::OnItemSelected,
- weak_ptr_factory_.GetWeakPtr()));
- }
-}
-
-void ContextMenuHandler::HandleOpenInNewTab(const base::ListValue* args) {
- OpenUrl(args, NEW_FOREGROUND_TAB);
-}
-
-void ContextMenuHandler::HandleOpenInIncognitoTab(const base::ListValue* args) {
- OpenUrl(args, OFF_THE_RECORD);
-}
-
-void ContextMenuHandler::OpenUrl(const base::ListValue* args,
- WindowOpenDisposition disposition) {
- base::string16 url = ExtractStringValue(args);
- if (!url.empty()) {
- web_ui()->GetWebContents()->OpenURL(content::OpenURLParams(
- GURL(url), content::Referrer(), disposition,
- content::PAGE_TRANSITION_AUTO_BOOKMARK, false));
- }
-}
diff --git a/chrome/browser/ui/webui/ntp/android/context_menu_handler.h b/chrome/browser/ui/webui/ntp/android/context_menu_handler.h
deleted file mode 100644
index 713cec9..0000000
--- a/chrome/browser/ui/webui/ntp/android/context_menu_handler.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_CONTEXT_MENU_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_CONTEXT_MENU_HANDLER_H_
-
-#include "base/memory/weak_ptr.h"
-#include "content/public/browser/web_ui_message_handler.h"
-#include "ui/base/window_open_disposition.h"
-
-namespace base {
-class ListValue;
-}
-
-// The handler for JavaScript messages related to the context menus.
-// It's the job of the actual HTML page to intercept the contextmenu event,
-// disable it and show its own custom menu.
-class ContextMenuHandler : public content::WebUIMessageHandler {
- public:
- ContextMenuHandler();
- virtual ~ContextMenuHandler();
-
- // WebUIMessageHandler override and implementation.
- virtual void RegisterMessages() OVERRIDE;
-
- // Invoked (by on_item_selected_callback_) when an item has been selected.
- void OnItemSelected(int item_id);
-
- // Callback for setting whether incognito mode is disabled.
- void GetIncognitoDisabled(const base::ListValue* args);
-
- // Callback for the "showContextMenu" message.
- void HandleShowContextMenu(const base::ListValue* args);
-
- // Below are the message that are so far only triggered by the context menu.
- // They should be moved to other files if they become used from other places.
-
- // Callback for the "openInNewTab" message.
- void HandleOpenInNewTab(const base::ListValue* args);
-
- // Callback for the "openInIncognitoTab" message.
- void HandleOpenInIncognitoTab(const base::ListValue* args);
-
- private:
- // Opens the URL stored as the first value of |args| with the given
- // |disposition|. The URL will always be opened as an AUTO_BOOKMARK.
- void OpenUrl(const base::ListValue* args, WindowOpenDisposition disposition);
-
- // Used to get a WeakPtr to self on the UI thread.
- base::WeakPtrFactory<ContextMenuHandler> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ContextMenuHandler);
-};
-
-#endif // CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_CONTEXT_MENU_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/android/navigation_handler.cc b/chrome/browser/ui/webui/ntp/android/navigation_handler.cc
deleted file mode 100644
index 2a99dc0..0000000
--- a/chrome/browser/ui/webui/ntp/android/navigation_handler.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/android/navigation_handler.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/values.h"
-#include "chrome/browser/google/google_util.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/user_metrics.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/common/page_transition_types.h"
-
-using base::UserMetricsAction;
-
-NavigationHandler::NavigationHandler() {}
-
-NavigationHandler::~NavigationHandler() {}
-
-void NavigationHandler::RegisterMessages() {
- web_ui()->RegisterMessageCallback(
- "openedMostVisited",
- base::Bind(&NavigationHandler::HandleOpenedMostVisited,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "openedRecentlyClosed",
- base::Bind(&NavigationHandler::HandleOpenedRecentlyClosed,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "openedBookmark",
- base::Bind(&NavigationHandler::HandleOpenedBookmark,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "openedForeignSession",
- base::Bind(&NavigationHandler::HandleOpenedForeignSession,
- base::Unretained(this)));
-}
-
-void NavigationHandler::HandleOpenedMostVisited(const base::ListValue* args) {
- content::RecordAction(UserMetricsAction("MobileNTPMostVisited"));
- RecordAction(ACTION_OPENED_MOST_VISITED_ENTRY);
-}
-
-void NavigationHandler::HandleOpenedRecentlyClosed(
- const base::ListValue* args) {
- content::RecordAction(UserMetricsAction("MobileNTPRecentlyClosed"));
- RecordAction(ACTION_OPENED_RECENTLY_CLOSED_ENTRY);
-}
-
-void NavigationHandler::HandleOpenedBookmark(const base::ListValue* args) {
- content::RecordAction(UserMetricsAction("MobileNTPBookmark"));
- RecordAction(ACTION_OPENED_BOOKMARK);
-}
-
-void NavigationHandler::HandleOpenedForeignSession(
- const base::ListValue* args) {
- content::RecordAction(UserMetricsAction("MobileNTPForeignSession"));
- RecordAction(ACTION_OPENED_FOREIGN_SESSION);
-}
-
-// static
-void NavigationHandler::RecordAction(Action action) {
- UMA_HISTOGRAM_ENUMERATION("NewTabPage.ActionAndroid", action, NUM_ACTIONS);
-}
diff --git a/chrome/browser/ui/webui/ntp/android/navigation_handler.h b/chrome/browser/ui/webui/ntp/android/navigation_handler.h
deleted file mode 100644
index 0d0372482..0000000
--- a/chrome/browser/ui/webui/ntp/android/navigation_handler.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_NAVIGATION_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_NAVIGATION_HANDLER_H_
-
-#include "base/compiler_specific.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-namespace base {
-class ListValue;
-}
-
-// Records a UMA stat ("NewTabPage.ActionAndroid") for the action the user takes
-// to navigate away from the NTP.
-class NavigationHandler : public content::WebUIMessageHandler {
- public:
- NavigationHandler();
- virtual ~NavigationHandler();
-
- // WebUIMessageHandler implementation.
- virtual void RegisterMessages() OVERRIDE;
-
- // Callback for "openedMostVisited".
- void HandleOpenedMostVisited(const base::ListValue* args);
-
- // Callback for "openedRecentlyClosed".
- void HandleOpenedRecentlyClosed(const base::ListValue* args);
-
- // Callback for "openedBookmark".
- void HandleOpenedBookmark(const base::ListValue* args);
-
- // Callback for "openedForeignSession".
- void HandleOpenedForeignSession(const base::ListValue* args);
-
- static void RecordActionForNavigation(const content::NavigationEntry& entry);
-
- private:
- // Possible actions taken by the user on the NTP. This enum is also defined in
- // histograms.xml. WARNING: these values must stay in sync with histograms.xml
- // and new actions can be added only at the end of the enum.
- enum Action {
- // User performed a search using the omnibox
- ACTION_SEARCHED_USING_OMNIBOX = 0,
- // User navigated to Google search homepage using the omnibox
- ACTION_NAVIGATED_TO_GOOGLE_HOMEPAGE = 1,
- // User navigated to any other page using the omnibox
- ACTION_NAVIGATED_USING_OMNIBOX = 2,
- // User opened a most visited page
- ACTION_OPENED_MOST_VISITED_ENTRY = 3,
- // User opened a recently closed tab
- ACTION_OPENED_RECENTLY_CLOSED_ENTRY = 4,
- // User opened a bookmark
- ACTION_OPENED_BOOKMARK = 5,
- // User opened a foreign session (from other devices section)
- ACTION_OPENED_FOREIGN_SESSION = 6,
- // The number of possible actions
- NUM_ACTIONS = 7
- };
-
- static void RecordAction(Action action);
-
- DISALLOW_COPY_AND_ASSIGN(NavigationHandler);
-};
-
-#endif // CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_NAVIGATION_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.cc b/chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.cc
deleted file mode 100644
index 01fd6b8..0000000
--- a/chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "chrome/browser/android/tab_android.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-
-NewTabPageReadyHandler::NewTabPageReadyHandler() {
-}
-
-NewTabPageReadyHandler::~NewTabPageReadyHandler() {
-}
-
-void NewTabPageReadyHandler::RegisterMessages() {
- web_ui()->RegisterMessageCallback("notifyNTPReady", base::Bind(
- &NewTabPageReadyHandler::HandleNewTabPageReady, base::Unretained(this)));
- web_ui()->RegisterMessageCallback("NTPUnexpectedNavigation", base::Bind(
- &NewTabPageReadyHandler::HandleNewTabPageUnexpectedNavigation,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("notifyNTPTitleLoaded", base::Bind(
- &NewTabPageReadyHandler::HandleNewTabPageTitleLoaded,
- base::Unretained(this)));
-}
-
-void NewTabPageReadyHandler::HandleNewTabPageTitleLoaded(
- const base::ListValue* args) {
- web_ui()->OverrideTitle(base::string16());
-}
-
-void NewTabPageReadyHandler::HandleNewTabPageReady(
- const base::ListValue* args) {
- TabAndroid* tab = TabAndroid::FromWebContents(web_ui()->GetWebContents());
- if (!tab)
- return;
- tab->OnNewTabPageReady();
-}
-
-void NewTabPageReadyHandler::HandleNewTabPageUnexpectedNavigation(
- const base::ListValue* args) {
- // NTP reached an unexpected state trying to send finish loading notification
- // a second time. The notification should be sent only when page is
- // completely done loading. This could otherwise create a race condition in
- // tests waiting for the NTP to have loaded (any navigation NTP does after
- // loading could interfere with the test navigation).
- NOTREACHED();
-}
diff --git a/chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.h b/chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.h
deleted file mode 100644
index 3778277..0000000
--- a/chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_NEW_TAB_PAGE_READY_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_NEW_TAB_PAGE_READY_HANDLER_H_
-
-#include "base/compiler_specific.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-namespace base {
-class ListValue;
-}
-
-// Sends a notification when the NTP is completely finished loading
-// and navigating.
-class NewTabPageReadyHandler : public content::WebUIMessageHandler {
- public:
- NewTabPageReadyHandler();
- virtual ~NewTabPageReadyHandler();
-
- // WebUIMessageHandler implementation.
- virtual void RegisterMessages() OVERRIDE;
-
- // Callback for "notifyNTPReady".
- void HandleNewTabPageReady(const base::ListValue* args);
-
- // Callback for "NTPUnexpectedNavigation".
- void HandleNewTabPageUnexpectedNavigation(const base::ListValue* args);
-
- // Callback for "notifyNTPTitleLoaded".
- void HandleNewTabPageTitleLoaded(const base::ListValue* args);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NewTabPageReadyHandler);
-};
-
-#endif // CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_NEW_TAB_PAGE_READY_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/android/ntp_resource_cache_android.cc b/chrome/browser/ui/webui/ntp/android/ntp_resource_cache_android.cc
deleted file mode 100644
index c76a5c69..0000000
--- a/chrome/browser/ui/webui/ntp/android/ntp_resource_cache_android.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
-
-#include "base/command_line.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/google/google_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/chrome_version_info.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_process_host.h"
-#include "grit/browser_resources.h"
-#include "grit/generated_resources.h"
-#include "ui/base/device_form_factor.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/webui/jstemplate_builder.h"
-#include "ui/base/webui/web_ui_util.h"
-
-using chrome::VersionInfo;
-using content::BrowserThread;
-
-namespace {
-
-const char kLearnMoreIncognitoUrl[] =
- "https://www.google.com/support/chrome/bin/answer.py?answer=95464";
-
-} // namespace
-
-NTPResourceCache::NTPResourceCache(Profile* profile) : profile_(profile) {}
-
-NTPResourceCache::~NTPResourceCache() {}
-
-NTPResourceCache::WindowType NTPResourceCache::GetWindowType(
- Profile* profile, content::RenderProcessHost* render_host) {
- if (render_host) {
- // Sometimes the |profile| is the parent (non-incognito) version of the user
- // so we check the |render_host| if it is provided.
- if (render_host->GetBrowserContext()->IsOffTheRecord())
- return NTPResourceCache::INCOGNITO;
- } else if (profile->IsOffTheRecord()) {
- return NTPResourceCache::INCOGNITO;
- }
- return NTPResourceCache::NORMAL;
-}
-
-base::RefCountedMemory* NTPResourceCache::GetNewTabHTML(WindowType win_type) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // Android uses same html/css for incognito NTP and normal NTP
- if (!new_tab_html_.get())
- CreateNewTabHTML();
- return new_tab_html_.get();
-}
-
-base::RefCountedMemory* NTPResourceCache::GetNewTabCSS(WindowType win_type) {
- // This is used for themes, which are not currently supported on Android.
- NOTIMPLEMENTED();
- return NULL;
-}
-
-void NTPResourceCache::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- // No notifications necessary in Android.
-}
-
-void NTPResourceCache::OnPreferenceChanged() {
- // No notifications necessary in Android.
-}
-
-void NTPResourceCache::CreateNewTabHTML() {
- // TODO(estade): these strings should be defined in their relevant handlers
- // (in GetLocalizedValues) and should have more legible names.
- // Show the profile name in the title and most visited labels if the current
- // profile is not the default.
- base::DictionaryValue localized_strings;
- localized_strings.SetBoolean("hasattribution", false);
- localized_strings.SetString("title",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
- localized_strings.SetString("mostvisited",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED));
- localized_strings.SetString("recentlyclosed",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED));
- localized_strings.SetString("opentabslastsynced",
- l10n_util::GetStringUTF16(IDS_SYNC_NTP_OPEN_TABS_LAST_SYNCED));
- localized_strings.SetString("elementopeninnewtab",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_CONTEXT_MENU_OPEN_IN_NEW_TAB));
- localized_strings.SetString("elementopeninincognitotab",
- l10n_util::GetStringUTF16(
- IDS_NEW_TAB_CONTEXT_MENU_OPEN_IN_INCOGNITO_TAB));
- localized_strings.SetString("elementremove",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_CONTEXT_MENU_REMOVE));
- localized_strings.SetString("removeall",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_CONTEXT_MENU_REMOVE_ALL));
- localized_strings.SetString("bookmarkedit",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_CONTEXT_MENU_EDIT_BOOKMARK));
- localized_strings.SetString("bookmarkdelete",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_CONTEXT_MENU_DELETE_BOOKMARK));
- localized_strings.SetString("bookmarkshortcut",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_CONTEXT_MENU_BOOKMARK_SHORTCUT));
- localized_strings.SetString("editfolder",
- l10n_util::GetStringUTF16(IDS_BOOKMARK_EDIT_FOLDER));
- localized_strings.SetString("deletefolder",
- l10n_util::GetStringUTF16(IDS_BOOKMARK_REMOVE_FOLDER));
- localized_strings.SetString("receivedDocuments",
- l10n_util::GetStringUTF16(IDS_RECEIVED_DOCUMENTS));
- localized_strings.SetString("syncPromo",
- l10n_util::GetStringUTF16(IDS_SYNC_PROMO_DESKTOP_INSTRUCTIONS));
- localized_strings.SetString("syncEnableSync",
- l10n_util::GetStringUTF16(IDS_SYNC_ENABLE_SYNC));
- localized_strings.SetString("bookmarkstitle",
- l10n_util::GetStringUTF16(IDS_ACCNAME_BOOKMARKS));
- localized_strings.SetString("incognito_document_title",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_INCOGNITO_TITLE));
- localized_strings.SetString("most_visited_document_title",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED_TITLE));
- localized_strings.SetString("bookmarks_document_title",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_BOOKMARKS_TITLE));
- localized_strings.SetString("open_tabs_document_title",
- l10n_util::GetStringUTF16(IDS_NEW_TAB_OTHER_SESSIONS_TITLE));
-
- webui::SetFontAndTextDirection(&localized_strings);
-
- base::StringPiece new_tab_html(ResourceBundle::GetSharedInstance().
- GetRawDataResource(IDR_NEW_TAB_ANDROID_HTML));
- localized_strings.SetString(
- "device",
- ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET ?
- "tablet" : "phone");
-
- const char* new_tab_link = kLearnMoreIncognitoUrl;
- base::string16 learnMoreLink = base::ASCIIToUTF16(
- google_util::AppendGoogleLocaleParam(GURL(new_tab_link)).spec());
- localized_strings.SetString("content",
- l10n_util::GetStringFUTF16(
- IDS_NEW_TAB_OTR_MESSAGE_MOBILE, learnMoreLink));
-
- // Load the new tab page appropriate for this build.
- std::string full_html;
-
- // Inject the template data into the HTML so that it is available before any
- // layout is needed.
- std::string json_html;
- webui::AppendJsonHtml(&localized_strings, &json_html);
-
- static const base::StringPiece template_data_placeholder(
- "<!-- template data placeholder -->");
- size_t pos = new_tab_html.find(template_data_placeholder);
-
- if (pos != base::StringPiece::npos) {
- full_html.assign(new_tab_html.data(), pos);
- full_html.append(json_html);
- size_t after_offset = pos + template_data_placeholder.size();
- full_html.append(new_tab_html.data() + after_offset,
- new_tab_html.size() - after_offset);
- } else {
- NOTREACHED();
- full_html.assign(new_tab_html.data(), new_tab_html.size());
- }
-
- new_tab_html_ = base::RefCountedString::TakeString(&full_html);
-}
diff --git a/chrome/browser/ui/webui/ntp/android/promo_handler.cc b/chrome/browser/ui/webui/ntp/android/promo_handler.cc
deleted file mode 100644
index 239ae31..0000000
--- a/chrome/browser/ui/webui/ntp/android/promo_handler.cc
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ntp/android/promo_handler.h"
-
-#include "base/logging.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/metrics/histogram.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/android/intent_helper.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/sync/glue/synced_session.h"
-#include "chrome/browser/sync/open_tabs_ui_delegate.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/web_resource/notification_promo.h"
-#include "chrome/browser/web_resource/notification_promo_mobile_ntp.h"
-#include "chrome/browser/web_resource/promo_resource_service.h"
-#include "chrome/common/pref_names.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/user_prefs/pref_registry_syncable.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/web_contents.h"
-
-using content::BrowserThread;
-
-namespace {
-
-// Promotion impression types for the NewTabPage.MobilePromo histogram.
-// Should be kept in sync with the values in histograms.xml
-enum PromoImpressionBuckets {
- PROMO_IMPRESSION_MOST_VISITED = 0,
- PROMO_IMPRESSION_OPEN_TABS = 1,
- PROMO_IMPRESSION_SYNC_PROMO = 2,
- PROMO_IMPRESSION_SEND_EMAIL_CLICKED = 3,
- PROMO_IMPRESSION_CLOSE_PROMO_CLICKED = 4,
- PROMO_IMPRESSION_BUCKET_BOUNDARY = 5
-};
-
-// Helper to record an impression in NewTabPage.MobilePromo histogram.
-void RecordImpressionOnHistogram(PromoImpressionBuckets type) {
- UMA_HISTOGRAM_ENUMERATION("NewTabPage.MobilePromo", type,
- PROMO_IMPRESSION_BUCKET_BOUNDARY);
-}
-
-// Helper to ask whether the promo is active.
-bool CanShowNotificationPromo() {
- NotificationPromo notification_promo;
- notification_promo.InitFromPrefs(NotificationPromo::MOBILE_NTP_SYNC_PROMO);
- return notification_promo.CanShow();
-}
-
-// Helper to send out promo resource change notification.
-void Notify(PromoHandler* ph, chrome::NotificationType notification_type) {
- content::NotificationService* service =
- content::NotificationService::current();
- service->Notify(notification_type,
- content::Source<PromoHandler>(ph),
- content::NotificationService::NoDetails());
-}
-
-// Replaces all formatting markup in the promo with the corresponding HTML.
-std::string ReplaceSimpleMarkupWithHtml(std::string text) {
- const std::string LINE_BREAK = "<br/>";
- const std::string SYNCGRAPHIC_IMAGE =
- "<div class=\"promo-sync-graphic\"></div>";
- const std::string BEGIN_HIGHLIGHT =
- "<div style=\"text-align: center\"><button class=\"promo-button\">";
- const std::string END_HIGHLIGHT = "</button></div>";
- const std::string BEGIN_LINK =
- "<span style=\"color: blue; text-decoration: underline;\">";
- const std::string END_LINK = "</span>";
- const std::string BEGIN_PROMO_AREA = "<div class=\"promo-action-target\">";
- const std::string END_PROMO_AREA = "</div>";
-
- ReplaceSubstringsAfterOffset(&text, 0, "LINE_BREAK", LINE_BREAK);
- ReplaceSubstringsAfterOffset(
- &text, 0, "SYNCGRAPHIC_IMAGE", SYNCGRAPHIC_IMAGE);
- ReplaceSubstringsAfterOffset(&text, 0, "BEGIN_HIGHLIGHT", BEGIN_HIGHLIGHT);
- ReplaceSubstringsAfterOffset(&text, 0, "END_HIGHLIGHT", END_HIGHLIGHT);
- ReplaceSubstringsAfterOffset(&text, 0, "BEGIN_LINK", BEGIN_LINK);
- ReplaceSubstringsAfterOffset(&text, 0, "END_LINK", END_LINK);
- return BEGIN_PROMO_AREA + text + END_PROMO_AREA;
-}
-
-} // namespace
-
-PromoHandler::PromoHandler() {
- // Watch for pref changes that cause us to need to re-inject promolines.
- registrar_.Add(this, chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED,
- content::NotificationService::AllSources());
-
- // Watch for sync service updates that could cause re-injections
- registrar_.Add(this, chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
- content::NotificationService::AllSources());
- registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED,
- content::NotificationService::AllSources());
-}
-
-PromoHandler::~PromoHandler() {
-}
-
-void PromoHandler::RegisterMessages() {
- web_ui()->RegisterMessageCallback("getPromotions",
- base::Bind(&PromoHandler::HandleGetPromotions,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("recordImpression",
- base::Bind(&PromoHandler::HandleRecordImpression,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("promoActionTriggered",
- base::Bind(&PromoHandler::HandlePromoActionTriggered,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback("promoDisabled",
- base::Bind(&PromoHandler::HandlePromoDisabled,
- base::Unretained(this)));
-}
-
-// static
-void PromoHandler::RegisterProfilePrefs(
- user_prefs::PrefRegistrySyncable* registry) {
- registry->RegisterBooleanPref(
- prefs::kNtpPromoDesktopSessionFound,
- false,
- user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-}
-
-void PromoHandler::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- if (chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED == type ||
- chrome::NOTIFICATION_SYNC_CONFIGURE_DONE == type ||
- chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED == type) {
- // A change occurred to one of the preferences we care about
- CheckDesktopSessions();
- InjectPromoDecorations();
- } else {
- NOTREACHED() << "Unknown pref changed.";
- }
-}
-
-void PromoHandler::HandlePromoSendEmail(const base::ListValue* args) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- Profile* profile = Profile::FromBrowserContext(
- web_ui()->GetWebContents()->GetBrowserContext());
- if (!profile)
- return;
-
- base::string16 data_subject, data_body, data_inv;
- if (!args || args->GetSize() < 3) {
- DVLOG(1) << "promoSendEmail: expected three args, got "
- << (args ? args->GetSize() : 0);
- return;
- }
-
- args->GetString(0, &data_subject);
- args->GetString(1, &data_body);
- args->GetString(2, &data_inv);
- if (data_inv.empty() || (data_subject.empty() && data_body.empty()))
- return;
-
- std::string data_email;
- ProfileSyncService* service =
- ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
- if (service && service->signin())
- data_email = service->signin()->GetAuthenticatedUsername();
-
- chrome::android::SendEmail(
- base::UTF8ToUTF16(data_email), data_subject, data_body, data_inv,
- base::string16());
- RecordImpressionOnHistogram(PROMO_IMPRESSION_SEND_EMAIL_CLICKED);
-}
-
-void PromoHandler::HandlePromoActionTriggered(const base::ListValue* /*args*/) {
- if (!CanShowNotificationPromo())
- return;
-
- NotificationPromoMobileNtp promo;
- if (!promo.InitFromPrefs())
- return;
-
- if (promo.action_type() == "ACTION_EMAIL")
- HandlePromoSendEmail(promo.action_args());
-}
-
-void PromoHandler::HandlePromoDisabled(const base::ListValue* /*args*/) {
- if (!CanShowNotificationPromo())
- return;
-
- NotificationPromo::HandleClosed(NotificationPromo::MOBILE_NTP_SYNC_PROMO);
- RecordImpressionOnHistogram(PROMO_IMPRESSION_CLOSE_PROMO_CLICKED);
-
- content::NotificationService* service =
- content::NotificationService::current();
- service->Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED,
- content::Source<PromoHandler>(this),
- content::NotificationService::NoDetails());
-}
-
-void PromoHandler::HandleGetPromotions(const base::ListValue* /*args*/) {
- CheckDesktopSessions();
- InjectPromoDecorations();
-}
-
-void PromoHandler::HandleRecordImpression(const base::ListValue* args) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(args && !args->empty());
- RecordPromotionImpression(base::UTF16ToASCII(ExtractStringValue(args)));
-}
-
-void PromoHandler::InjectPromoDecorations() {
- base::DictionaryValue result;
- if (FetchPromotion(&result))
- web_ui()->CallJavascriptFunction("ntp.setPromotions", result);
- else
- web_ui()->CallJavascriptFunction("ntp.clearPromotions");
-}
-
-void PromoHandler::RecordPromotionImpression(const std::string& id) {
- // Update number of views a promotion has received and trigger refresh
- // if it exceeded max_views set for the promotion.
- if (NotificationPromo::HandleViewed(
- NotificationPromo::MOBILE_NTP_SYNC_PROMO)) {
- Notify(this, chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED);
- }
-
- if (id == "most_visited")
- RecordImpressionOnHistogram(PROMO_IMPRESSION_MOST_VISITED);
- else if (id == "open_tabs")
- RecordImpressionOnHistogram(PROMO_IMPRESSION_OPEN_TABS);
- else if (id == "sync_promo")
- RecordImpressionOnHistogram(PROMO_IMPRESSION_SYNC_PROMO);
- else
- NOTREACHED() << "Unknown promotion impression: " << id;
-}
-
-bool PromoHandler::FetchPromotion(base::DictionaryValue* result) {
- DCHECK(result != NULL);
- if (!CanShowNotificationPromo())
- return false;
-
- NotificationPromoMobileNtp promo;
- if (!promo.InitFromPrefs())
- return false;
-
- DCHECK(!promo.text().empty());
- if (!DoesChromePromoMatchCurrentSync(
- promo.requires_sync(), promo.requires_mobile_only_sync())) {
- return false;
- }
-
- result->SetBoolean("promoIsAllowed", true);
- result->SetBoolean("promoIsAllowedOnMostVisited",
- promo.show_on_most_visited());
- result->SetBoolean("promoIsAllowedOnOpenTabs", promo.show_on_open_tabs());
- result->SetBoolean("promoIsAllowedAsVC", promo.show_as_virtual_computer());
- result->SetString("promoVCTitle", promo.virtual_computer_title());
- result->SetString("promoVCLastSynced", promo.virtual_computer_lastsync());
- result->SetString("promoMessage", ReplaceSimpleMarkupWithHtml(promo.text()));
- result->SetString("promoMessageLong",
- ReplaceSimpleMarkupWithHtml(promo.text_long()));
- return true;
-}
-
-bool PromoHandler::DoesChromePromoMatchCurrentSync(
- bool promo_requires_sync,
- bool promo_requires_no_active_desktop_sync_sessions) {
- Profile* profile = Profile::FromWebUI(web_ui());
- if (!profile)
- return false;
-
- // If the promo doesn't require any sync, the requirements are fulfilled.
- if (!promo_requires_sync)
- return true;
-
- // The promo requires the sync; check that the sync service is active.
- ProfileSyncService* service =
- ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
- if (!service || !service->ShouldPushChanges())
- return false;
-
- // If the promo doesn't have specific requirements for the sync, it matches.
- if (!promo_requires_no_active_desktop_sync_sessions)
- return true;
-
- // If the promo requires mobile-only sync,
- // check that no desktop sessions are found.
- PrefService* prefs = profile->GetPrefs();
- return !prefs || !prefs->GetBoolean(prefs::kNtpPromoDesktopSessionFound);
-}
-
-void PromoHandler::CheckDesktopSessions() {
- Profile* profile = Profile::FromWebUI(web_ui());
- if (!profile)
- return;
-
- // Check if desktop sessions have already been found.
- PrefService* prefs = profile->GetPrefs();
- if (!prefs || prefs->GetBoolean(prefs::kNtpPromoDesktopSessionFound))
- return;
-
- // Check if the sync is currently active.
- ProfileSyncService* service =
- ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
- if (!service || !service->ShouldPushChanges())
- return;
-
- // Check if the sync has any open sessions.
- browser_sync::OpenTabsUIDelegate* open_tabs =
- service->GetOpenTabsUIDelegate();
- if (!open_tabs)
- return;
-
- // Let's see if there are no desktop sessions.
- std::vector<const browser_sync::SyncedSession*> sessions;
- base::ListValue session_list;
- if (!open_tabs->GetAllForeignSessions(&sessions))
- return;
-
- for (size_t i = 0; i < sessions.size(); ++i) {
- const browser_sync::SyncedSession::DeviceType device_type =
- sessions[i]->device_type;
- if (device_type == browser_sync::SyncedSession::TYPE_WIN ||
- device_type == browser_sync::SyncedSession::TYPE_MACOSX ||
- device_type == browser_sync::SyncedSession::TYPE_LINUX) {
- // Found a desktop session: write out the pref.
- prefs->SetBoolean(prefs::kNtpPromoDesktopSessionFound, true);
- return;
- }
- }
-}
diff --git a/chrome/browser/ui/webui/ntp/android/promo_handler.h b/chrome/browser/ui/webui/ntp/android/promo_handler.h
deleted file mode 100644
index 33a7e9f..0000000
--- a/chrome/browser/ui/webui/ntp/android/promo_handler.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_PROMO_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_PROMO_HANDLER_H_
-
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
-// The handler for JavaScript messages related to the Android NTP promo.
-class PromoHandler : public content::WebUIMessageHandler,
- public content::NotificationObserver {
- public:
- PromoHandler();
- virtual ~PromoHandler();
-
- // WebUIMessageHandler implementation.
- virtual void RegisterMessages() OVERRIDE;
-
- // Register preferences.
- static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-
- private:
- // NotificationObserver override and implementation.
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
-
- // Callback for the "promoSendEmail" message.
- // |args| is a list [ subject, body, app-chooser-message ].
- void HandlePromoSendEmail(const base::ListValue* args);
-
- // Callback for the "promoActionTriggered" message.
- // No arguments.
- void HandlePromoActionTriggered(const base::ListValue* args);
-
- // Callback for the "promoDisabled" message.
- // No arguments.
- void HandlePromoDisabled(const base::ListValue* args);
-
- // Callback for the "getPromotions" message.
- // No arguments.
- void HandleGetPromotions(const base::ListValue* args);
-
- // Callback for the "recordImpression" message.
- // |args| is a list with a name of a page to record an impression from.
- void HandleRecordImpression(const base::ListValue* args);
-
- // Gathers the promotion information and updates the page.
- void InjectPromoDecorations();
-
- // Records an impression; could trigger a refresh if max_views are exceeded.
- void RecordPromotionImpression(const std::string& id);
-
- // Fetches the active promotion and defines what should be passed to JS.
- // Returns true if the promotion should be shown and the |result| is ready.
- bool FetchPromotion(base::DictionaryValue* result);
-
- // Returns true if the Chrome Promo is allowed.
- bool DoesChromePromoMatchCurrentSync(
- bool promo_requires_sync,
- bool promo_requires_no_active_desktop_sync_sessions);
-
- // Updates the profile preference if any desktop session was discovered.
- void CheckDesktopSessions();
-
- // Registrar to receive notification on promo changes.
- content::NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(PromoHandler);
-};
-
-#endif // CHROME_BROWSER_UI_WEBUI_NTP_ANDROID_PROMO_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/most_visited_handler.cc b/chrome/browser/ui/webui/ntp/most_visited_handler.cc
index fc5da40..11a6fcd 100644
--- a/chrome/browser/ui/webui/ntp/most_visited_handler.cc
+++ b/chrome/browser/ui/webui/ntp/most_visited_handler.cc
@@ -84,11 +84,6 @@
// Set up our sources for top-sites data.
content::URLDataSource::Add(profile, new ThumbnailListSource(profile));
-#if defined(OS_ANDROID)
- // Register chrome://touch-icon as a data source for touch icons or favicons.
- content::URLDataSource::Add(profile,
- new FaviconSource(profile, FaviconSource::ANY));
-#endif
// Register chrome://favicon as a data source for favicons.
content::URLDataSource::Add(
profile, new FaviconSource(profile, FaviconSource::FAVICON));
@@ -275,9 +270,6 @@
}
void MostVisitedHandler::MaybeRemovePageValues() {
-// The code below uses APIs not available on Android and the experiment should
-// not run there.
-#if !defined(OS_ANDROID)
if (!history::MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled())
return;
@@ -294,7 +286,6 @@
history::MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs(
open_urls,
pages_value_.get());
-#endif
}
// static
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index aab5d1d..065dcdf2 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -15,13 +15,19 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/metrics_handler.h"
+#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
+#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
#include "chrome/browser/ui/webui/ntp/favicon_webui_handler.h"
#include "chrome/browser/ui/webui/ntp/foreign_session_handler.h"
#include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
+#include "chrome/browser/ui/webui/ntp/new_tab_page_handler.h"
+#include "chrome/browser/ui/webui/ntp/new_tab_page_sync_handler.h"
+#include "chrome/browser/ui/webui/ntp/ntp_login_handler.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
#include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
#include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h"
+#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/user_prefs/pref_registry_syncable.h"
@@ -36,21 +42,6 @@
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
-#if !defined(OS_ANDROID)
-#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
-#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
-#include "chrome/browser/ui/webui/ntp/new_tab_page_handler.h"
-#include "chrome/browser/ui/webui/ntp/new_tab_page_sync_handler.h"
-#include "chrome/browser/ui/webui/ntp/ntp_login_handler.h"
-#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
-#else
-#include "chrome/browser/ui/webui/ntp/android/bookmarks_handler.h"
-#include "chrome/browser/ui/webui/ntp/android/context_menu_handler.h"
-#include "chrome/browser/ui/webui/ntp/android/navigation_handler.h"
-#include "chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.h"
-#include "chrome/browser/ui/webui/ntp/android/promo_handler.h"
-#endif
-
#if defined(ENABLE_THEMES)
#include "chrome/browser/ui/webui/theme_handler.h"
#endif
@@ -105,39 +96,22 @@
web_ui->AddMessageHandler(new MetricsHandler());
web_ui->AddMessageHandler(new MostVisitedHandler());
web_ui->AddMessageHandler(new RecentlyClosedTabsHandler());
-#if !defined(OS_ANDROID)
web_ui->AddMessageHandler(new FaviconWebUIHandler());
web_ui->AddMessageHandler(new NewTabPageHandler());
web_ui->AddMessageHandler(new CoreAppLauncherHandler());
if (NewTabUI::IsDiscoveryInNTPEnabled())
web_ui->AddMessageHandler(new SuggestionsHandler());
- // Android doesn't have a sync promo/username on NTP.
web_ui->AddMessageHandler(new NewTabPageSyncHandler());
- if (MightShowApps()) {
- ExtensionService* service = GetProfile()->GetExtensionService();
- // We might not have an ExtensionService (on ChromeOS when not logged in
- // for example).
- if (service)
- web_ui->AddMessageHandler(new AppLauncherHandler(service));
- }
-#endif
+ ExtensionService* service = GetProfile()->GetExtensionService();
+ // We might not have an ExtensionService (on ChromeOS when not logged in
+ // for example).
+ if (service)
+ web_ui->AddMessageHandler(new AppLauncherHandler(service));
}
-#if defined(OS_ANDROID)
- // These handlers are specific to the Android NTP page.
- web_ui->AddMessageHandler(new BookmarksHandler());
- web_ui->AddMessageHandler(new ContextMenuHandler());
- web_ui->AddMessageHandler(new FaviconWebUIHandler());
- web_ui->AddMessageHandler(new NavigationHandler());
- web_ui->AddMessageHandler(new NewTabPageReadyHandler());
- if (!GetProfile()->IsOffTheRecord())
- web_ui->AddMessageHandler(new PromoHandler());
-#else
- // Android uses native UI for sync setup.
if (NTPLoginHandler::ShouldShow(GetProfile()))
web_ui->AddMessageHandler(new NTPLoginHandler());
-#endif
#if defined(ENABLE_THEMES)
// The theme handler can require some CPU, so do it after hooking up the most
@@ -247,33 +221,18 @@
// static
void NewTabUI::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
-#if !defined(OS_ANDROID)
CoreAppLauncherHandler::RegisterProfilePrefs(registry);
NewTabPageHandler::RegisterProfilePrefs(registry);
if (NewTabUI::IsDiscoveryInNTPEnabled())
SuggestionsHandler::RegisterProfilePrefs(registry);
-#endif
MostVisitedHandler::RegisterProfilePrefs(registry);
browser_sync::ForeignSessionHandler::RegisterProfilePrefs(registry);
}
// static
-bool NewTabUI::MightShowApps() {
-// Android does not have apps.
-#if defined(OS_ANDROID)
- return false;
-#else
- return true;
-#endif
-}
-
-// static
bool NewTabUI::ShouldShowApps() {
// Ash shows apps in app list thus should not show apps page in NTP4.
-// Android does not have apps.
-#if defined(OS_ANDROID)
- return false;
-#elif defined(USE_ASH)
+#if defined(USE_ASH)
return chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH;
#else
return true;
@@ -372,14 +331,7 @@
if (!path.empty() && path[0] != '#') {
// A path under new-tab was requested; it's likely a bad relative
// URL from the new tab page, but in any case it's an error.
-
- // TODO(dtrainor): Can remove this #if check once we update the
- // accessibility script to no longer try to access urls like
- // '?2314124523523'.
- // See http://crbug.com/150252.
-#if !defined(OS_ANDROID)
NOTREACHED() << path << " should not have been requested on the NTP";
-#endif
callback.Run(NULL);
return;
}
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.h b/chrome/browser/ui/webui/ntp/new_tab_ui.h
index 7421f87..cbc3f8db 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.h
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.h
@@ -39,14 +39,6 @@
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
- // Returns whether or not this browser process might ever need to show apps
- // on the NTP. With Win8 running in immersive mode, for example, apps are
- // displayed on a ChromeOS-style apps bar and not on the NTP. In desktop,
- // however, apps are displayed on the NTP. Since they both share the same
- // browser process instance, a different decision is necessary for whether
- // or not to register app message handlers versus whether to show it on NTP.
- static bool MightShowApps();
-
// Returns whether or not to show apps pages.
static bool ShouldShowApps();
diff --git a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
index 65459a3..84f8290e 100644
--- a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
@@ -132,7 +132,6 @@
return;
if (username.empty()) {
-#if !defined(OS_ANDROID)
// The user isn't signed in, show the sign in promo.
if (signin::ShouldShowPromo(profile)) {
signin::Source source =
@@ -142,7 +141,6 @@
chrome::ShowBrowserSignin(browser, source);
RecordInHistogram(NTP_SIGN_IN_PROMO_CLICKED);
}
-#endif
} else if (args->GetSize() == 4) {
// The user is signed in, show the profiles menu.
double x = 0;
@@ -223,12 +221,8 @@
}
}
} else {
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
- // Android uses a custom sign in promo. Don't call the function
- // signin::ShouldShowPromo() since it does a bunch of checks that are not
- // required here. We only want to suppress this login status for users that
- // are not allowed to sign in. Chromeos does not show this status header
- // at all.
+#if !defined(OS_CHROMEOS)
+ // Chromeos does not show this status header.
SigninManager* signin = SigninManagerFactory::GetForProfile(
profile->GetOriginalProfile());
if (!profile->IsManaged() && signin->IsSigninAllowed()) {
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.h b/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
index cde7169..201da1a 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
@@ -76,7 +76,6 @@
scoped_refptr<base::RefCountedMemory> new_tab_html_;
-#if !defined(OS_ANDROID)
// Returns a message describing any newly-added sync types, or an empty
// string if all types have already been acknowledged.
base::string16 GetSyncTypeMessage();
@@ -97,7 +96,6 @@
content::NotificationRegistrar registrar_;
PrefChangeRegistrar profile_pref_change_registrar_;
PrefChangeRegistrar local_state_pref_change_registrar_;
-#endif
// Set based on platform_util::IsSwipeTrackingFromScrollEventsEnabled.
bool is_swipe_tracking_from_scroll_events_enabled_;
diff --git a/chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.cc b/chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.cc
index 8f17411..0121b91 100644
--- a/chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.cc
+++ b/chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.cc
@@ -18,10 +18,6 @@
#include "content/public/browser/web_ui.h"
#include "ui/base/webui/web_ui_util.h"
-#if defined(OS_ANDROID)
-#include "chrome/browser/sessions/session_restore.h"
-#endif
-
namespace {
void TabToValue(const TabRestoreService::Tab& tab,
@@ -76,23 +72,6 @@
double session_to_restore = 0.0;
CHECK(args->GetDouble(0, &session_to_restore));
-#if defined(OS_ANDROID)
- // Find and remove the corresponding tab entry from TabRestoreService.
- // We take ownership of the returned tab.
- scoped_ptr<TabRestoreService::Tab> tab_entry(
- tab_restore_service_->RemoveTabEntryById(static_cast<int>(
- session_to_restore)));
- if (tab_entry.get() == NULL)
- return;
-
- // RestoreForeignSessionTab needs a SessionTab.
- SessionTab session_tab;
- session_tab.current_navigation_index = tab_entry->current_navigation_index;
- session_tab.navigations = tab_entry->navigations;
-
- SessionRestore::RestoreForeignSessionTab(web_ui()->GetWebContents(),
- session_tab, NEW_FOREGROUND_TAB);
-#else
double index = -1.0;
CHECK(args->GetDouble(1, &index));
@@ -115,7 +94,6 @@
disposition);
// The current tab has been nuked at this point; don't touch any member
// variables.
-#endif
}
void RecentlyClosedTabsHandler::HandleClearRecentlyClosed(
@@ -134,7 +112,7 @@
void RecentlyClosedTabsHandler::TabRestoreServiceChanged(
TabRestoreService* service) {
- base::ListValue list_value;
+ base::ListValue list_value;
const int max_count = 10;
int added_count = 0;
// We filter the list of recently closed to only show 'interesting' entries,