Commit bae4924a authored by hcarmona's avatar hcarmona Committed by Commit bot

Create implementation of the side panel using a dialog.

Using a dialog is a much cleaner solution because it handles all focus
trapping without attempting to capture TAB or require updating all
tabindex properties.

We removed the ability to swipe the drawer open in order to keep the
code simple.

BUG=633858
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2465433002
Cr-Commit-Position: refs/heads/master@{#438187}
parent 7f9d7dd4
......@@ -23,6 +23,10 @@
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
'target_name': 'dialog_drawer',
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
'target_name': 'extension_controlled_indicator',
'dependencies': [
......
<link rel="import" href="chrome://resources/html/polymer.html">
<dom-module name="dialog-drawer">
<template>
<style>
:host {
--drawer-width: 256px;
--transition-timing: 200ms ease;
background-color: #fff;
border: none;
bottom: 0;
left: calc(-1 * var(--drawer-width));
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
top: 0;
transition: left var(--transition-timing);
width: var(--drawer-width);
}
:host,
#container {
height: 100%;
}
:host(.opening) {
left: 0;
}
:host([align=right]) {
left: auto;
right: calc(-1 * var(--drawer-width));
transition: right var(--transition-timing);
}
:host(.opening[align=right]) {
right: 0;
}
:host::backdrop {
background: rgba(0, 0, 0, 0.5);
bottom: 0;
left: 0;
opacity: 0;
position: absolute;
right: 0;
top: 0;
transition: opacity var(--transition-timing);
}
:host(.opening)::backdrop {
opacity: 1;
}
</style>
<div id="container" on-tap="onContainerTap_">
<content></content>
</div>
</template>
</dom-module>
<script src="dialog_drawer.js"></script>
// Copyright 2016 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.
Polymer({
is: 'dialog-drawer',
extends: 'dialog',
properties: {
/** Enables notifications for |Dialog.open|. */
open: {
type: Boolean,
notify: true,
},
/** The alignment of the drawer on the screen ('left' or 'right'). */
align: {
type: String,
value: 'left',
reflectToAttribute: true,
},
},
listeners: {
'cancel': 'onDialogCancel_',
'tap': 'onDialogTap_',
'transitionend': 'onDialogTransitionEnd_',
},
/** Toggles the drawer open and close. */
toggle: function() {
if (this.open)
this.closeDrawer();
else
this.openDrawer();
},
/** Shows drawer and slides it into view. */
openDrawer: function() {
if (!this.open) {
this.showModal();
this.classList.add('opening');
}
},
/** Slides the drawer away, then closes it after the transition has ended. */
closeDrawer: function() {
if (this.open) {
this.classList.remove('opening');
this.classList.add('closing');
}
},
/**
* Stop propagation of a tap event inside the container. This will allow
* |onDialogTap_| to only be called when clicked outside the container.
* @param {!Event} event
* @private
*/
onContainerTap_: function(event) {
event.stopPropagation();
},
/**
* Close the dialog when tapped outside the container.
* @private
*/
onDialogTap_: function() {
this.closeDrawer();
},
/**
* Overrides the default cancel machanism to allow for a close animation.
* @param {!Event} event
* @private
*/
onDialogCancel_: function(event) {
event.preventDefault();
this.closeDrawer();
},
/**
* Closes the dialog when the closing animation is over.
* @private
*/
onDialogTransitionEnd_: function() {
if (this.classList.contains('closing')) {
this.classList.remove('closing');
this.close();
}
},
});
......@@ -374,6 +374,12 @@
<structure name="IDR_SETTINGS_CONTROLS_CHECKBOX_JS"
file="controls/settings_checkbox.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_CONTROLS_DIALOG_DRAWER_HTML"
file="controls/dialog_drawer.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_CONTROLS_DIALOG_DRAWER_JS"
file="controls/dialog_drawer.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_CONTROLS_DROPDOWN_MENU_HTML"
file="controls/settings_dropdown_menu.html"
type="chrome_html" />
......
......@@ -6,12 +6,12 @@
{
'target_name': 'settings_ui',
'dependencies': [
'<(DEPTH)/third_party/polymer/v1_0/components-chromium/app-layout/app-drawer/compiled_resources2.gyp:app-drawer-extracted',
'<(DEPTH)/ui/webui/resources/cr_elements/cr_toolbar/compiled_resources2.gyp:cr_toolbar',
'<(DEPTH)/ui/webui/resources/cr_elements/cr_toolbar/compiled_resources2.gyp:cr_toolbar_search_field',
'../compiled_resources2.gyp:direction_delegate',
'../compiled_resources2.gyp:global_scroll_target_behavior',
'../prefs/compiled_resources2.gyp:prefs',
'../controls/compiled_resources2.gyp:dialog_drawer',
'../settings_main/compiled_resources2.gyp:settings_main',
'settings_ui_types',
],
......
<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/app-layout/app-drawer/app-drawer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-header-panel/paper-header-panel.html">
<link rel="import" href="/controls/dialog_drawer.html">
<link rel="import" href="/direction_delegate.html">
<link rel="import" href="/global_scroll_target_behavior.html">
<link rel="import" href="/i18n_setup.html">
......@@ -51,11 +51,11 @@
width: 100%;
}
app-drawer {
dialog[is='dialog-drawer'] {
z-index: 2;
}
app-drawer .drawer-header {
dialog[is='dialog-drawer'] .drawer-header {
align-items: center;
display: flex;
font-size: 123.08%; /* go to 16px from 13px */
......@@ -75,12 +75,12 @@
--iron-icon-fill-color: white;
}
app-drawer .drawer-header {
dialog[is='dialog-drawer'] .drawer-header {
-webkit-padding-start: 24px;
border-bottom: var(--settings-separator-line);
}
app-drawer .drawer-content {
dialog[is='dialog-drawer'] .drawer-content {
height: calc(100% - 56px);
overflow: auto;
}
......@@ -95,7 +95,7 @@
on-search-changed="onSearchChanged_"
show-menu>
</cr-toolbar>
<app-drawer swipe-open>
<dialog id="drawer" is="dialog-drawer">
<div class="drawer-header">$i18n{settings}</div>
<div class="drawer-content">
<template is="dom-if" id="drawerTemplate">
......@@ -106,7 +106,7 @@
</settings-menu>
</template>
</div>
</app-drawer>
</dialog>
<paper-header-panel id="headerPanel" mode="waterfall">
<settings-main id="main" prefs="{{prefs}}"
toolbar-spinner-active="{{toolbarSpinnerActive_}}"
......
......@@ -79,13 +79,12 @@ Polymer({
*/
ready: function() {
// Lazy-create the drawer the first time it is opened or swiped into view.
var drawer = assert(this.$$('app-drawer'));
listenOnce(drawer, 'track opened-changed', function() {
listenOnce(this.$.drawer, 'open-changed', function() {
this.$.drawerTemplate.if = true;
}.bind(this));
window.addEventListener('popstate', function(e) {
drawer.close();
this.$.drawer.closeDrawer();
}.bind(this));
if (loadTimeData.getBoolean('isGuest')) {
......@@ -188,17 +187,17 @@ Polymer({
*/
onIronActivate_: function(event) {
if (event.detail.item.id != 'advancedPage')
this.$$('app-drawer').close();
this.$.drawer.closeDrawer();
},
/** @private */
onMenuButtonTap_: function() {
this.$$('app-drawer').toggle();
this.$.drawer.toggle();
},
/** @private */
directionDelegateChanged_: function() {
this.$$('app-drawer').align = this.directionDelegate.isRtl() ?
this.$.drawer.align = this.directionDelegate.isRtl() ?
'right' : 'left';
},
});
......@@ -13,7 +13,7 @@ cr.define('settings_rtl_tests', function() {
suite('settings drawer panel RTL tests', function() {
test('test i18n processing flips drawer panel', function() {
var ui = document.createElement('settings-ui');
var appDrawer = ui.$$('app-drawer');
var appDrawer = ui.$.drawer;
assertEquals('left', appDrawer.align);
ui.directionDelegate = new TestDirectionDelegate(true /* isRtl */);
......
......@@ -47,35 +47,35 @@ TEST_F('SettingsUIBrowserTest', 'MAYBE_All', function() {
test('app drawer', function(done) {
assertEquals(null, ui.$$('settings-menu'));
var drawer = assert(ui.$$('app-drawer'));
assertFalse(drawer.opened);
var drawer = ui.$.drawer;
assertFalse(!!drawer.open);
// Slide the drawer partway open. (These events are copied from Polymer's
// app-drawer tests.)
drawer.fire('track', {state: 'start'});
drawer.fire('track', {state: 'track', dx: 10, ddx: 10});
drawer.fire('track', {state: 'end', dx: 10, ddx: 0});
drawer.openDrawer();
// Menu is rendered asynchronously, but the drawer stays closed.
Polymer.dom.flush();
assertFalse(drawer.opened);
// Validate that dialog is open and menu is shown so it will animate.
assertTrue(drawer.open);
assertTrue(!!ui.$$('settings-menu'));
// Slide most of the way open.
drawer.fire('track', {state: 'start'});
drawer.fire('track', {state: 'track', dx: 200, ddx: 200});
drawer.fire('track', {state: 'end', dx: 200, ddx: 0});
// Drawer is shown.
Polymer.dom.flush();
assertTrue(drawer.opened);
// Close the dialog after it fully opens.
drawer.addEventListener('transitionend', function() {
if (drawer.classList.contains('opening')) {
// Click away from the drawer. MockInteractions don't expose a way to
// click at a specific location.
var midScreen = MockInteractions.middleOfNode(ui);
drawer.dispatchEvent(new MouseEvent('click', {
'bubbles': true,
'cancelable': true,
'clientX': midScreen.x,
'clientY': midScreen.y,
}));
}
});
// Click away from the drawer.
MockInteractions.tap(drawer.$.scrim);
Polymer.Base.async(function() {
drawer.addEventListener('close', function() {
// Drawer is closed, but menu is still stamped so its contents remain
// visible as the drawer slides out.
assertFalse(drawer.opened);
assertFalse(drawer.open);
assertTrue(!!ui.$$('settings-menu'));
done();
});
......
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