Commit 7d416b78 authored by John Lee's avatar John Lee Committed by Commit Bot

Tab Strip WebUI: Add ability to close tabs

This CL also removes some accessibility features as tabs are not
focusable only through the keyboard, and overall accessibility is still
being decided on.

Bug: 989131
Change-Id: I4aae2fd35000866dca0c641ce59c93a05e191a3f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1747732Reviewed-by: default avatarEsmael Elmoslimany <aee@chromium.org>
Commit-Queue: John Lee <johntlee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#686215}
parent 5baf7df7
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
<header id="title"> <header id="title">
<span id="favicon"></span> <span id="favicon"></span>
<h2 id="titleText"></h2> <h2 id="titleText"></h2>
<button id="close" aria-label="Close tab"> <button id="close">
<span id="closeIcon"></span> <span id="closeIcon"></span>
</button> </button>
</header> </header>
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import {CustomElement} from './custom_element.js'; import {CustomElement} from './custom_element.js';
import {TabsApiProxy} from './tabs_api_proxy.js';
export class TabElement extends CustomElement { export class TabElement extends CustomElement {
static get template() { static get template() {
...@@ -12,16 +13,21 @@ export class TabElement extends CustomElement { ...@@ -12,16 +13,21 @@ export class TabElement extends CustomElement {
constructor() { constructor() {
super(); super();
/** @private {!HTMLElement} */
this.closeButtonEl_ =
/** @type {!HTMLElement} */ (this.shadowRoot.querySelector('#close'));
/** @private {!Tab} */ /** @private {!Tab} */
this.tab_; this.tab_;
/** @private {!TabsApiProxy} */
this.tabsApi_ = TabsApiProxy.getInstance();
/** @private {!HTMLElement} */ /** @private {!HTMLElement} */
this.titleTextEl_ = /** @type {!HTMLElement} */ ( this.titleTextEl_ = /** @type {!HTMLElement} */ (
this.shadowRoot.querySelector('#titleText')); this.shadowRoot.querySelector('#titleText'));
}
connectedCallback() { this.closeButtonEl_.addEventListener('click', this.onClose_.bind(this));
this.setAttribute('tabindex', 0);
} }
/** @return {!Tab} */ /** @return {!Tab} */
...@@ -40,6 +46,16 @@ export class TabElement extends CustomElement { ...@@ -40,6 +46,16 @@ export class TabElement extends CustomElement {
this.tab_ = Object.freeze(tab); this.tab_ = Object.freeze(tab);
} }
/** @private */
onClose_() {
// There is no tab data and therefore nothing to close
if (!this.tab_) {
return;
}
this.tabsApi_.closeTab(this.tab_.id);
}
} }
customElements.define('tabstrip-tab', TabElement); customElements.define('tabstrip-tab', TabElement);
...@@ -28,6 +28,16 @@ export class TabsApiProxy { ...@@ -28,6 +28,16 @@ export class TabsApiProxy {
}); });
}); });
} }
/**
* @param {number} tabId
* @return {!Promise}
*/
closeTab(tabId) {
return new Promise(resolve => {
chrome.tabs.remove(tabId, resolve);
});
}
} }
addSingletonGetter(TabsApiProxy); addSingletonGetter(TabsApiProxy);
...@@ -3,31 +3,43 @@ ...@@ -3,31 +3,43 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'chrome://tab-strip/tab.js'; import 'chrome://tab-strip/tab.js';
import {TabsApiProxy} from 'chrome://tab-strip/tabs_api_proxy.js';
import {TestTabsApiProxy} from './test_tabs_api_proxy.js';
suite('Tab', function() { suite('Tab', function() {
let testTabsApiProxy;
let tabElement; let tabElement;
const tab = {
id: 1001,
title: 'My title',
};
setup(() => { setup(() => {
document.body.innerHTML = ''; document.body.innerHTML = '';
testTabsApiProxy = new TestTabsApiProxy();
TabsApiProxy.instance_ = testTabsApiProxy;
tabElement = document.createElement('tabstrip-tab'); tabElement = document.createElement('tabstrip-tab');
tabElement.tab = tab;
document.body.appendChild(tabElement); document.body.appendChild(tabElement);
}); });
test('sets the tabindex', () => {
assertEquals(tabElement.getAttribute('tabindex'), '0');
});
test('sets the title', () => { test('sets the title', () => {
const expectedTitle = 'My title';
tabElement.tab = {title: expectedTitle};
assertEquals( assertEquals(
expectedTitle, tab.title, tabElement.shadowRoot.querySelector('#titleText').innerText);
tabElement.shadowRoot.querySelector('#titleText').innerText);
}); });
test('exposes the tab ID to an attribute', () => { test('exposes the tab ID to an attribute', () => {
tabElement.tab = {id: 1001}; tabElement.tab = {id: 1001};
assertEquals('1001', tabElement.getAttribute('data-tab-id')); assertEquals('1001', tabElement.getAttribute('data-tab-id'));
}); });
test('closes the tab', () => {
tabElement.shadowRoot.querySelector('#close').click();
return testTabsApiProxy.whenCalled('closeTab').then(tabId => {
assertEquals(tabId, tab.id);
});
});
}); });
...@@ -22,7 +22,10 @@ class EventDispatcher { ...@@ -22,7 +22,10 @@ class EventDispatcher {
export class TestTabsApiProxy extends TestBrowserProxy { export class TestTabsApiProxy extends TestBrowserProxy {
constructor() { constructor() {
super(['getCurrentWindow']); super([
'closeTab',
'getCurrentWindow',
]);
this.callbackRouter = { this.callbackRouter = {
onCreated: new EventDispatcher(), onCreated: new EventDispatcher(),
...@@ -33,6 +36,11 @@ export class TestTabsApiProxy extends TestBrowserProxy { ...@@ -33,6 +36,11 @@ export class TestTabsApiProxy extends TestBrowserProxy {
this.currentWindow_; this.currentWindow_;
} }
closeTab(tabId) {
this.methodCalled('closeTab', tabId);
return Promise.resolve();
}
getCurrentWindow() { getCurrentWindow() {
this.methodCalled('getCurrentWindow'); this.methodCalled('getCurrentWindow');
return Promise.resolve(this.currentWindow_); return Promise.resolve(this.currentWindow_);
......
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