Commit 749a93ee authored by Tibor Goldschwendt's avatar Tibor Goldschwendt Committed by Commit Bot

[webui][ntp] Add background image previews to customize dialog

This includes adding title navigation to the customize dialog to switch
between collections and images.

NOTE: This does not embed actual images. Will do this in a follow up CL.

Bug: 1032328
Change-Id: I3f9931aca673590dcd05dd4e4fa6dcf046aee3f1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2076554
Commit-Queue: Tibor Goldschwendt <tiborg@chromium.org>
Reviewed-by: default avatarEsmael Elmoslimany <aee@chromium.org>
Reviewed-by: default avatarAlex Gough <ajgo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#746634}
parent f836de5d
<style> <style>
#collections { #container {
--ntp-grid-gap: 8px;
padding: 4px; padding: 4px;
} }
ntp-grid {
--ntp-grid-gap: 8px;
}
.tile { .tile {
cursor: pointer; cursor: pointer;
outline-width: 0; outline-width: 0;
...@@ -36,10 +39,11 @@ ...@@ -36,10 +39,11 @@
min-height: 30px; min-height: 30px;
} }
</style> </style>
<ntp-grid id="collections" columns="3"> <ntp-grid id="collections" columns="3" hidden="[[selectedCollection]]">
<dom-repeat items="[[collections_]]"> <dom-repeat id="collectionsRepeat" items="[[collections_]]">
<template> <template>
<div class="tile" tabindex="0" title="[[item.label]]" role="button"> <div class="tile" tabindex="0" title="[[item.label]]" role="button"
on-click="onCollectionClick_">
<!-- TODO(crbug.com/1032328): Show image in an iframe. --> <!-- TODO(crbug.com/1032328): Show image in an iframe. -->
<div class="image">[[item.previewImageUrl.url]]</div> <div class="image">[[item.previewImageUrl.url]]</div>
<div class="label">[[item.label]]</div> <div class="label">[[item.label]]</div>
...@@ -47,3 +51,13 @@ ...@@ -47,3 +51,13 @@
</template> </template>
</dom-repeat> </dom-repeat>
</ntp-grid> </ntp-grid>
<ntp-grid id="images" columns="3" hidden="[[!selectedCollection]]">
<dom-repeat items="[[images_]]">
<template>
<div class="tile" tabindex="0" title="[[item.label]]" role="button">
<!-- TODO(crbug.com/1032328): Show image in an iframe. -->
<div class="image">[[item.previewImageUrl.url]]</div>
</div>
</template>
</dom-repeat>
</ntp-grid>
...@@ -19,8 +19,19 @@ class CustomizeBackgroundsElement extends PolymerElement { ...@@ -19,8 +19,19 @@ class CustomizeBackgroundsElement extends PolymerElement {
static get properties() { static get properties() {
return { return {
/** @private {newTabPage.mojom.BackgroundCollection} */
selectedCollection: {
notify: true,
observer: 'onSelectedCollectionChange_',
type: Object,
value: null,
},
/** @private {!Array<!newTabPage.mojom.BackgroundCollection>} */ /** @private {!Array<!newTabPage.mojom.BackgroundCollection>} */
collections_: Array, collections_: Array,
/** @private {!Array<!newTabPage.mojom.BackgroundImage>} */
images_: Array,
}; };
} }
...@@ -31,6 +42,33 @@ class CustomizeBackgroundsElement extends PolymerElement { ...@@ -31,6 +42,33 @@ class CustomizeBackgroundsElement extends PolymerElement {
this.collections_ = collections; this.collections_ = collections;
}); });
} }
/**
* @param {!Event} e
* @private
*/
onCollectionClick_(e) {
this.selectedCollection = this.$.collectionsRepeat.itemForElement(e.target);
}
/** @private */
async onSelectedCollectionChange_() {
this.images_ = [];
if (!this.selectedCollection) {
return;
}
const collectionId = this.selectedCollection.id;
const {images} =
await BrowserProxy.getInstance().handler.getBackgroundImages(
collectionId);
// We check the IDs match since the user may have already moved to a
// different collection before the results come back.
if (!this.selectedCollection ||
this.selectedCollection.id !== collectionId) {
return;
}
this.images_ = images;
}
} }
customElements.define( customElements.define(
......
<style> <style include="cr-icons">
::part(dialog) { ::part(dialog) {
min-width: 800px; min-width: 800px;
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
div[slot=title] { div[slot=title] {
align-items: center; align-items: center;
color: var(--ntp-primary-text-color);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
height: 80px; height: 80px;
...@@ -120,15 +121,29 @@ ...@@ -120,15 +121,29 @@
#themesIcon { #themesIcon {
-webkit-mask-image: url(icons/colors.svg); -webkit-mask-image: url(icons/colors.svg);
} }
#backButton {
--cr-icon-button-fill-color: var(--ntp-primary-text-color);
margin-inline-end: 4px;
/* So that the arrow aligns with the grid. */
margin-inline-start: -12px;
}
</style> </style>
<cr-dialog id="dialog" show-on-attach> <cr-dialog id="dialog" show-on-attach>
<div slot="title"> <div slot="title">
<div id="leftTitleSpacer"></div> <div id="leftTitleSpacer"></div>
<div id="title">$i18n{customizeThisPage}</div> <div id="title">
<div id="titleText" hidden="[[showTitleNavigation_]]">
$i18n{customizeThisPage}
</div>
<div id="titleNavigation" hidden="[[!showTitleNavigation_]]">
<cr-icon-button id="backButton" class="icon-arrow-back"
on-click="onBackClick_" title="$i18n{backButton}">
</cr-icon-button>
[[selectedCollection_.label]]
</div>
</div>
</div> </div>
<!-- TODO(crbug.com/1040256): Currently, the sidebar scrolls in sync with the
page content area. Fix, so that the page content can scroll
separately. -->
<div slot="body"> <div slot="body">
<div id="menuContainer"> <div id="menuContainer">
<div id="menu"> <div id="menu">
...@@ -153,7 +168,8 @@ ...@@ -153,7 +168,8 @@
<div id="pagesContainer"> <div id="pagesContainer">
<div id="pages"> <div id="pages">
<iron-pages selected="[[selectedPage_]]" attr-for-selected="page-name"> <iron-pages selected="[[selectedPage_]]" attr-for-selected="page-name">
<ntp-customize-backgrounds page-name="backgrounds"> <ntp-customize-backgrounds id="backgrounds" page-name="backgrounds"
selected-collection="{{selectedCollection_}}">
</ntp-customize-backgrounds> </ntp-customize-backgrounds>
<ntp-customize-shortcuts page-name="shortcuts"> <ntp-customize-shortcuts page-name="shortcuts">
</ntp-customize-shortcuts> </ntp-customize-shortcuts>
......
...@@ -39,6 +39,17 @@ class CustomizeDialogElement extends PolymerElement { ...@@ -39,6 +39,17 @@ class CustomizeDialogElement extends PolymerElement {
value: 'backgrounds', value: 'backgrounds',
observer: 'onSelectedPageChange_', observer: 'onSelectedPageChange_',
}, },
/** @private {newTabPage.mojom.BackgroundCollection} */
selectedCollection_: Object,
/** @private */
showTitleNavigation_: {
type: Boolean,
computed:
'computeShowTitleNavigation_(selectedPage_, selectedCollection_)',
value: false,
},
}; };
} }
...@@ -98,6 +109,16 @@ class CustomizeDialogElement extends PolymerElement { ...@@ -98,6 +109,16 @@ class CustomizeDialogElement extends PolymerElement {
onSelectedPageChange_() { onSelectedPageChange_() {
this.$.pages.scrollTop = 0; this.$.pages.scrollTop = 0;
} }
/** @private */
computeShowTitleNavigation_() {
return this.selectedPage_ === 'backgrounds' && this.selectedCollection_;
}
/** @private */
onBackClick_() {
this.selectedCollection_ = null;
}
} }
customElements.define(CustomizeDialogElement.is, CustomizeDialogElement); customElements.define(CustomizeDialogElement.is, CustomizeDialogElement);
<style> <style>
:host { :host {
--ntp-grid-gap: 0px; --ntp-grid-gap: 0px;
display: block;
} }
#grid { #grid {
......
...@@ -29,12 +29,22 @@ struct ThemeColors { ...@@ -29,12 +29,22 @@ struct ThemeColors {
// A collection of background images. // A collection of background images.
struct BackgroundCollection { struct BackgroundCollection {
// Collection identifier.
string id;
// Localized string of the collection name. // Localized string of the collection name.
string label; string label;
// URL to a preview image for the collection. Can point to untrusted content. // URL to a preview image for the collection. Can point to untrusted content.
url.mojom.Url preview_image_url; url.mojom.Url preview_image_url;
}; };
// A background image in a collection.
struct BackgroundImage {
// Localized string of extra image info.
string label;
// URL to a preview of the image. Can point to untrusted content.
url.mojom.Url preview_image_url;
};
// A predefined theme provided by Chrome. Created from data embedded in the // A predefined theme provided by Chrome. Created from data embedded in the
// Chrome binary. // Chrome binary.
struct ChromeTheme { struct ChromeTheme {
...@@ -127,6 +137,8 @@ interface PageHandler { ...@@ -127,6 +137,8 @@ interface PageHandler {
RevertThemeChanges(); RevertThemeChanges();
// Returns the collections of background images. // Returns the collections of background images.
GetBackgroundCollections() => (array<BackgroundCollection> collections); GetBackgroundCollections() => (array<BackgroundCollection> collections);
// Returns the images of a collection identified by |collection_id|.
GetBackgroundImages(string collection_id) => (array<BackgroundImage> images);
}; };
// WebUI-side handler for requests from the browser. // WebUI-side handler for requests from the browser.
......
...@@ -204,7 +204,7 @@ void NewTabPageHandler::UpdateMostVisitedTile( ...@@ -204,7 +204,7 @@ void NewTabPageHandler::UpdateMostVisitedTile(
void NewTabPageHandler::GetBackgroundCollections( void NewTabPageHandler::GetBackgroundCollections(
GetBackgroundCollectionsCallback callback) { GetBackgroundCollectionsCallback callback) {
if (!ntp_background_service_) { if (!ntp_background_service_ || background_collections_callback_) {
std::move(callback).Run( std::move(callback).Run(
std::vector<new_tab_page::mojom::BackgroundCollectionPtr>()); std::vector<new_tab_page::mojom::BackgroundCollectionPtr>());
return; return;
...@@ -213,6 +213,23 @@ void NewTabPageHandler::GetBackgroundCollections( ...@@ -213,6 +213,23 @@ void NewTabPageHandler::GetBackgroundCollections(
ntp_background_service_->FetchCollectionInfo(); ntp_background_service_->FetchCollectionInfo();
} }
void NewTabPageHandler::GetBackgroundImages(
const std::string& collection_id,
GetBackgroundImagesCallback callback) {
if (background_images_callback_) {
std::move(background_images_callback_)
.Run(std::vector<new_tab_page::mojom::BackgroundImagePtr>());
}
if (!ntp_background_service_) {
std::move(callback).Run(
std::vector<new_tab_page::mojom::BackgroundImagePtr>());
return;
}
images_request_collection_id_ = collection_id;
background_images_callback_ = std::move(callback);
ntp_background_service_->FetchCollectionImageInfo(collection_id);
}
void NewTabPageHandler::NtpThemeChanged(const NtpTheme& ntp_theme) { void NewTabPageHandler::NtpThemeChanged(const NtpTheme& ntp_theme) {
page_->SetTheme(MakeTheme(ntp_theme)); page_->SetTheme(MakeTheme(ntp_theme));
} }
...@@ -248,6 +265,7 @@ void NewTabPageHandler::OnCollectionInfoAvailable() { ...@@ -248,6 +265,7 @@ void NewTabPageHandler::OnCollectionInfoAvailable() {
std::vector<new_tab_page::mojom::BackgroundCollectionPtr> collections; std::vector<new_tab_page::mojom::BackgroundCollectionPtr> collections;
for (const auto& info : ntp_background_service_->collection_info()) { for (const auto& info : ntp_background_service_->collection_info()) {
auto collection = new_tab_page::mojom::BackgroundCollection::New(); auto collection = new_tab_page::mojom::BackgroundCollection::New();
collection->id = info.collection_id;
collection->label = info.collection_name; collection->label = info.collection_name;
collection->preview_image_url = GURL(info.preview_image_url); collection->preview_image_url = GURL(info.preview_image_url);
collections.push_back(std::move(collection)); collections.push_back(std::move(collection));
...@@ -255,7 +273,25 @@ void NewTabPageHandler::OnCollectionInfoAvailable() { ...@@ -255,7 +273,25 @@ void NewTabPageHandler::OnCollectionInfoAvailable() {
std::move(background_collections_callback_).Run(std::move(collections)); std::move(background_collections_callback_).Run(std::move(collections));
} }
void NewTabPageHandler::OnCollectionImagesAvailable() {} void NewTabPageHandler::OnCollectionImagesAvailable() {
if (!background_images_callback_) {
return;
}
std::vector<new_tab_page::mojom::BackgroundImagePtr> images;
if (ntp_background_service_->collection_images().empty()) {
std::move(background_images_callback_).Run(std::move(images));
}
auto collection_id =
ntp_background_service_->collection_images()[0].collection_id;
for (const auto& info : ntp_background_service_->collection_images()) {
DCHECK(info.collection_id == collection_id);
auto image = new_tab_page::mojom::BackgroundImage::New();
image->preview_image_url = GURL(info.thumbnail_image_url);
image->label = !info.attribution.empty() ? info.attribution[0] : "";
images.push_back(std::move(image));
}
std::move(background_images_callback_).Run(std::move(images));
}
void NewTabPageHandler::OnNextCollectionImageAvailable() {} void NewTabPageHandler::OnNextCollectionImageAvailable() {}
......
...@@ -59,6 +59,8 @@ class NewTabPageHandler : public content::WebContentsObserver, ...@@ -59,6 +59,8 @@ class NewTabPageHandler : public content::WebContentsObserver,
void RevertThemeChanges() override; void RevertThemeChanges() override;
void GetBackgroundCollections( void GetBackgroundCollections(
GetBackgroundCollectionsCallback callback) override; GetBackgroundCollectionsCallback callback) override;
void GetBackgroundImages(const std::string& collection_id,
GetBackgroundImagesCallback callback) override;
private: private:
// InstantServiceObserver: // InstantServiceObserver:
...@@ -76,6 +78,8 @@ class NewTabPageHandler : public content::WebContentsObserver, ...@@ -76,6 +78,8 @@ class NewTabPageHandler : public content::WebContentsObserver,
NtpBackgroundService* ntp_background_service_; NtpBackgroundService* ntp_background_service_;
GURL last_blacklisted_; GURL last_blacklisted_;
GetBackgroundCollectionsCallback background_collections_callback_; GetBackgroundCollectionsCallback background_collections_callback_;
std::string images_request_collection_id_;
GetBackgroundImagesCallback background_images_callback_;
mojo::Remote<new_tab_page::mojom::Page> page_; mojo::Remote<new_tab_page::mojom::Page> page_;
mojo::Receiver<new_tab_page::mojom::PageHandler> receiver_; mojo::Receiver<new_tab_page::mojom::PageHandler> receiver_;
......
...@@ -73,6 +73,7 @@ content::WebUIDataSource* CreateNewTabPageUiHtmlSource(Profile* profile) { ...@@ -73,6 +73,7 @@ content::WebUIDataSource* CreateNewTabPageUiHtmlSource(Profile* profile) {
{"urlField", IDS_NTP_CUSTOM_LINKS_URL}, {"urlField", IDS_NTP_CUSTOM_LINKS_URL},
// Customize button and dialog. // Customize button and dialog.
{"backButton", IDS_ACCNAME_BACK},
{"backgroundsMenuItem", IDS_NTP_CUSTOMIZE_MENU_BACKGROUND_LABEL}, {"backgroundsMenuItem", IDS_NTP_CUSTOMIZE_MENU_BACKGROUND_LABEL},
{"cancelButton", IDS_CANCEL}, {"cancelButton", IDS_CANCEL},
{"colorPickerLabel", IDS_NTP_CUSTOMIZE_COLOR_PICKER_LABEL}, {"colorPickerLabel", IDS_NTP_CUSTOMIZE_COLOR_PICKER_LABEL},
...@@ -80,17 +81,17 @@ content::WebUIDataSource* CreateNewTabPageUiHtmlSource(Profile* profile) { ...@@ -80,17 +81,17 @@ content::WebUIDataSource* CreateNewTabPageUiHtmlSource(Profile* profile) {
{"customizeThisPage", IDS_NTP_CUSTOM_BG_CUSTOMIZE_NTP_LABEL}, {"customizeThisPage", IDS_NTP_CUSTOM_BG_CUSTOMIZE_NTP_LABEL},
{"defaultThemeLabel", IDS_NTP_CUSTOMIZE_DEFAULT_LABEL}, {"defaultThemeLabel", IDS_NTP_CUSTOMIZE_DEFAULT_LABEL},
{"doneButton", IDS_DONE}, {"doneButton", IDS_DONE},
{"shortcutsMenuItem", IDS_NTP_CUSTOMIZE_MENU_SHORTCUTS_LABEL},
{"themesMenuItem", IDS_NTP_CUSTOMIZE_MENU_COLOR_LABEL},
{"thirdPartyThemeDescription", IDS_NTP_CUSTOMIZE_3PT_THEME_DESC},
{"uninstallThirdPartyThemeButton", IDS_NTP_CUSTOMIZE_3PT_THEME_UNINSTALL},
{"hideShortcuts", IDS_NTP_CUSTOMIZE_HIDE_SHORTCUTS_LABEL}, {"hideShortcuts", IDS_NTP_CUSTOMIZE_HIDE_SHORTCUTS_LABEL},
{"hideShortcutsDesc", IDS_NTP_CUSTOMIZE_HIDE_SHORTCUTS_DESC}, {"hideShortcutsDesc", IDS_NTP_CUSTOMIZE_HIDE_SHORTCUTS_DESC},
{"mostVisited", IDS_NTP_CUSTOMIZE_MOST_VISITED_LABEL}, {"mostVisited", IDS_NTP_CUSTOMIZE_MOST_VISITED_LABEL},
{"myShortcuts", IDS_NTP_CUSTOMIZE_MY_SHORTCUTS_LABEL}, {"myShortcuts", IDS_NTP_CUSTOMIZE_MY_SHORTCUTS_LABEL},
{"shortcutsCurated", IDS_NTP_CUSTOMIZE_MY_SHORTCUTS_DESC}, {"shortcutsCurated", IDS_NTP_CUSTOMIZE_MY_SHORTCUTS_DESC},
{"shortcutsMenuItem", IDS_NTP_CUSTOMIZE_MENU_SHORTCUTS_LABEL},
{"shortcutsOption", IDS_NTP_CUSTOMIZE_MENU_SHORTCUTS_LABEL}, {"shortcutsOption", IDS_NTP_CUSTOMIZE_MENU_SHORTCUTS_LABEL},
{"shortcutsSuggested", IDS_NTP_CUSTOMIZE_MOST_VISITED_DESC}, {"shortcutsSuggested", IDS_NTP_CUSTOMIZE_MOST_VISITED_DESC},
{"themesMenuItem", IDS_NTP_CUSTOMIZE_MENU_COLOR_LABEL},
{"thirdPartyThemeDescription", IDS_NTP_CUSTOMIZE_3PT_THEME_DESC},
{"uninstallThirdPartyThemeButton", IDS_NTP_CUSTOMIZE_3PT_THEME_UNINSTALL},
// Voice search. // Voice search.
{"audioError", IDS_NEW_TAB_VOICE_AUDIO_ERROR}, {"audioError", IDS_NEW_TAB_VOICE_AUDIO_ERROR},
......
...@@ -5,55 +5,136 @@ ...@@ -5,55 +5,136 @@
import 'chrome://new-tab-page/customize_backgrounds.js'; import 'chrome://new-tab-page/customize_backgrounds.js';
import {BrowserProxy} from 'chrome://new-tab-page/browser_proxy.js'; import {BrowserProxy} from 'chrome://new-tab-page/browser_proxy.js';
import {createTestProxy} from 'chrome://test/new_tab_page/test_support.js'; import {assertNotStyle, assertStyle, createTestProxy} from 'chrome://test/new_tab_page/test_support.js';
import {flushTasks} from 'chrome://test/test_util.m.js'; import {flushTasks, isVisible} from 'chrome://test/test_util.m.js';
function createCollection(id = 0, label = '', url = '') {
return {id: id, label: label, previewImageUrl: {url: url}};
}
suite('NewTabPageCustomizeBackgroundsTest', () => { suite('NewTabPageCustomizeBackgroundsTest', () => {
/** @type {TestProxy} */ /** @type {newTabPage.mojom.PageHandlerRemote} */
let testProxy; let handler;
async function createCustomizeBackgrounds() {
const customizeBackgrounds =
document.createElement('ntp-customize-backgrounds');
document.body.appendChild(customizeBackgrounds);
await handler.whenCalled('getBackgroundCollections');
await flushTasks();
return customizeBackgrounds;
}
setup(() => { setup(() => {
PolymerTest.clearBody(); PolymerTest.clearBody();
testProxy = createTestProxy(); const testProxy = createTestProxy();
handler = testProxy.handler;
handler.setResultFor('getBackgroundCollections', Promise.resolve({
collections: [],
}));
handler.setResultFor('getBackgroundImages', Promise.resolve({
images: [],
}));
BrowserProxy.instance_ = testProxy; BrowserProxy.instance_ = testProxy;
}); });
test('creating element shows background collection tiles', async () => { test('creating element shows background collection tiles', async () => {
// Arrange. // Arrange.
const collections = [ const collection = createCollection(0, 'col_0', 'https://col_0.jpg');
{ handler.setResultFor('getBackgroundCollections', Promise.resolve({
label: 'collection_0', collections: [collection],
previewImageUrl: {url: 'https://example.com/image_0.jpg'},
},
{
label: 'collection_1',
previewImageUrl: {url: 'https://example.com/image_1.jpg'},
},
];
const getBackgroundCollectionsCalled =
testProxy.handler.whenCalled('getBackgroundCollections');
testProxy.handler.setResultFor('getBackgroundCollections', Promise.resolve({
collections: collections,
})); }));
// Act. // Act.
const customizeBackgrounds = const customizeBackgrounds = await createCustomizeBackgrounds();
document.createElement('ntp-customize-backgrounds');
document.body.appendChild(customizeBackgrounds);
await getBackgroundCollectionsCalled;
await flushTasks();
// Assert. // Assert.
const tiles = customizeBackgrounds.shadowRoot.querySelectorAll('.tile'); assertTrue(isVisible(customizeBackgrounds.$.collections));
assertEquals(tiles.length, 2); assertStyle(customizeBackgrounds.$.images, 'display', 'none');
assertEquals(tiles[0].getAttribute('title'), 'collection_0'); const tiles =
assertEquals(tiles[1].getAttribute('title'), 'collection_1'); customizeBackgrounds.shadowRoot.querySelectorAll('#collections .tile');
assertEquals(tiles.length, 1);
assertEquals(tiles[0].getAttribute('title'), 'col_0');
assertEquals( assertEquals(
tiles[0].querySelector('.image').textContent.trim(), tiles[0].querySelector('.image').textContent.trim(),
'https://example.com/image_0.jpg'); 'https://col_0.jpg');
});
test('clicking collection selects collection', async function() {
// Arrange.
const collection = createCollection();
handler.setResultFor('getBackgroundCollections', Promise.resolve({
collections: [collection],
}));
const customizeBackgrounds = await createCustomizeBackgrounds();
// Act.
customizeBackgrounds.shadowRoot.querySelector('#collections .tile').click();
// Assert.
assertDeepEquals(customizeBackgrounds.selectedCollection, collection);
});
test('setting collection requests images', async function() {
// Arrange.
const customizeBackgrounds = await createCustomizeBackgrounds();
// Act.
customizeBackgrounds.selectedCollection = createCollection();
// Assert.
assertFalse(isVisible(customizeBackgrounds.$.collections));
await handler.whenCalled('getBackgroundImages');
});
test('Loading images shows image tiles', async function() {
// Arrange.
const image = {
label: 'image_0',
previewImageUrl: {url: 'https://example.com/image.png'},
};
handler.setResultFor('getBackgroundImages', Promise.resolve({
images: [image],
}));
const customizeBackgrounds = await createCustomizeBackgrounds();
customizeBackgrounds.selectedCollection = createCollection(0);
// Act.
const id = await handler.whenCalled('getBackgroundImages');
await flushTasks();
// Assert.
assertEquals(id, 0);
assertFalse(isVisible(customizeBackgrounds.$.collections));
assertTrue(isVisible(customizeBackgrounds.$.images));
const tiles =
customizeBackgrounds.shadowRoot.querySelectorAll('#images .tile');
assertEquals(tiles.length, 1);
assertEquals( assertEquals(
tiles[1].querySelector('.image').textContent.trim(), tiles[0].querySelector('.image').textContent.trim(),
'https://example.com/image_1.jpg'); 'https://example.com/image.png');
});
test('Going back shows collections', async function() {
// Arrange.
const image = {
label: 'image_0',
previewImageUrl: {url: 'https://example.com/image.png'},
};
const customizeBackgrounds = await createCustomizeBackgrounds();
handler.setResultFor('getBackgroundImages', Promise.resolve({
images: [image],
}));
customizeBackgrounds.selectedCollection = createCollection();
await flushTasks();
// Act.
customizeBackgrounds.selectedCollection = null;
await flushTasks();
// Assert.
assertNotStyle(customizeBackgrounds.$.collections, 'display', 'none');
assertStyle(customizeBackgrounds.$.images, 'display', 'none');
}); });
}); });
...@@ -6,7 +6,7 @@ import 'chrome://new-tab-page/customize_dialog.js'; ...@@ -6,7 +6,7 @@ import 'chrome://new-tab-page/customize_dialog.js';
import {BrowserProxy} from 'chrome://new-tab-page/browser_proxy.js'; import {BrowserProxy} from 'chrome://new-tab-page/browser_proxy.js';
import {createTestProxy} from 'chrome://test/new_tab_page/test_support.js'; import {createTestProxy} from 'chrome://test/new_tab_page/test_support.js';
import {flushTasks, waitAfterNextRender} from 'chrome://test/test_util.m.js'; import {flushTasks, isVisible, waitAfterNextRender} from 'chrome://test/test_util.m.js';
suite('NewTabPageCustomizeDialogTest', () => { suite('NewTabPageCustomizeDialogTest', () => {
/** @type {!CustomizeDialogElement} */ /** @type {!CustomizeDialogElement} */
...@@ -53,4 +53,46 @@ suite('NewTabPageCustomizeDialogTest', () => { ...@@ -53,4 +53,46 @@ suite('NewTabPageCustomizeDialogTest', () => {
assertEquals(shownPages.length, 1); assertEquals(shownPages.length, 1);
assertEquals(shownPages[0].getAttribute('page-name'), 'themes'); assertEquals(shownPages[0].getAttribute('page-name'), 'themes');
}); });
suite('scroll borders', () => {
/**
* @param {!HTMLElement} container
* @private
*/
async function testScrollBorders(container) {
const assertHidden = el => {
assertTrue(el.matches('[scroll-border]:not([show])'));
};
const assertShown = el => {
assertTrue(el.matches('[scroll-border][show]'));
};
const {firstElementChild: top, lastElementChild: bottom} = container;
const scrollableElement = top.nextSibling;
const dialogBody =
customizeDialog.shadowRoot.querySelector('div[slot=body]');
const heightWithBorders = `${scrollableElement.scrollHeight + 2}px`;
dialogBody.style.height = heightWithBorders;
assertHidden(top);
assertHidden(bottom);
dialogBody.style.height = '50px';
await waitAfterNextRender();
assertHidden(top);
assertShown(bottom);
scrollableElement.scrollTop = 1;
await waitAfterNextRender();
assertShown(top);
assertShown(bottom);
scrollableElement.scrollTop = scrollableElement.scrollHeight;
await waitAfterNextRender();
assertShown(top);
assertHidden(bottom);
dialogBody.style.height = heightWithBorders;
await waitAfterNextRender();
assertHidden(top);
assertHidden(bottom);
}
test('menu', () => testScrollBorders(customizeDialog.$.menuContainer));
test('pages', () => testScrollBorders(customizeDialog.$.pagesContainer));
});
}); });
...@@ -32,6 +32,17 @@ export function assertStyle(element, name, expected) { ...@@ -32,6 +32,17 @@ export function assertStyle(element, name, expected) {
assertEquals(expected, actual); assertEquals(expected, actual);
} }
/**
* Asserts the computed style for an element is not value.
* @param {!HTMLElement} element The element.
* @param {string} name The name of the style to assert.
* @param {string} not The value the style should not be.
*/
export function assertNotStyle(element, name, not) {
const actual = window.getComputedStyle(element).getPropertyValue(name).trim();
assertNotEquals(not, actual);
}
/** /**
* Asserts that an element is focused. * Asserts that an element is focused.
* @param {!HTMLElement} element The element to test. * @param {!HTMLElement} element The element to test.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment