Commit 0d3fa109 authored by Jon Mann's avatar Jon Mann Committed by Commit Bot

Wi-Fi List: Keep focus on active row when update is received.

This fixes a long standing bug where the focus moved back up
to the first network when an update to the list of available networks
came in.

Bug: 720274
Change-Id: Iee036aa649a74eef1b1743317a07b35061e08d3c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2480712Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Commit-Queue: Jon Mann <jonmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#819297}
parent 64537f00
......@@ -205,6 +205,7 @@ js_library("network_list") {
deps = [
":network_list_types",
"//ui/webui/resources/cr_elements:cr_scrollable_behavior",
"//ui/webui/resources/js:list_property_update_behavior",
]
}
......@@ -214,6 +215,7 @@ js_library("network_list_item") {
":network_list_types",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:i18n_behavior",
"//ui/webui/resources/js/cr/ui:focus_row_behavior",
]
}
......@@ -277,6 +279,10 @@ js_type_check("closure_compile_module") {
":network_siminfo.m",
":onc_mojo.m",
]
# closure_flags = default_closure_args + [
# "js_module_root=../../ui/webui/resources/js/",
# "js_module_root=./gen/ui/webui/resources/js/"]
}
js_library("mojo_interface_provider.m") {
......@@ -437,6 +443,7 @@ js_library("network_list.m") {
"//third_party/polymer/v3_0/components-chromium/iron-list:iron-list",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/cr_elements:cr_scrollable_behavior.m",
"//ui/webui/resources/js:list_property_update_behavior.m",
]
extra_deps = [ ":network_list_module" ]
}
......@@ -446,6 +453,7 @@ js_library("network_list_item.m") {
deps = [
":network_list_types.m",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js/cr/ui:focus_row_behavior.m",
]
extra_deps = [ ":network_list_item_module" ]
}
......
......@@ -6,6 +6,7 @@
<link rel="import" href="../../../cr_elements/shared_style_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
<link rel="import" href="../../../html/list_property_update_behavior.html">
<dom-module id="network-list">
<template>
......@@ -36,13 +37,18 @@
</style>
<div id="container" class="layout vertical flex" scrollable
no-bottom-scroll-border$="[[noBottomScrollBorder]]">
<iron-list id="networkList" selection-enabled items="[[listItems_]]"
scroll-target="container" selected-item="{{selectedItem}}">
<iron-list id="networkList" items="[[listItems_]]"
scroll-target="container" preserve-focus>
<template>
<network-list-item item="[[item]]"
show-technology-badge="[[showTechnologyBadge]]"
show-buttons="[[showButtons]]" tabindex$="[[tabIndex]]"
show-buttons="[[showButtons]]"
tabindex$="[[tabIndex]]"
focus-row-index="[[index]]"
iron-list-tab-index="[[tabIndex]]"
activation-unavailable="[[activationUnavailable]]"
last-focused="{{lastFocused_}}"
list-blurred="{{listBlurred_}}"
device-state="[[deviceState]]">
</network-list-item>
</template>
......
......@@ -74,12 +74,49 @@ Polymer({
return [];
},
},
/**
* Used by FocusRowBehavior to track the last focused element on a row.
* @private
*/
lastFocused_: Object,
/**
* Used by FocusRowBehavior to track if the list has been blurred.
* @private
*/
listBlurred_: Boolean,
},
behaviors: [CrScrollableBehavior],
behaviors: [CrScrollableBehavior, ListPropertyUpdateBehavior],
observers: ['updateListItems_(networks, customItems)'],
/** @type {ResizeObserver} used to observer size changes to this element */
resizeObserver_: null,
/** @override */
attached() {
// This is a required work around to get the iron-list to display on first
// view. Currently iron-list won't generate item elements on attach if the
// element is not visible. Because there are some instances where this
// component might not be visible when the items are bound, we listen for
// resize events and manually call notifyResize on the iron-list
this.resizeObserver_ = new ResizeObserver(entries => {
const networkList =
/** @type {IronListElement} */ (this.$$('#networkList'));
if (networkList) {
networkList.notifyResize();
}
});
this.resizeObserver_.observe(this);
},
/** @override */
detached() {
this.resizeObserver_.disconnect();
},
/** @private {boolean} */
focusRequested_: false,
......@@ -89,16 +126,15 @@ Polymer({
},
/** @private */
updateListItems_() {
this.saveScroll(/** @type {!IronListElement} */ (this.$.networkList));
const beforeNetworks = this.customItems.filter(function(item) {
return item.showBeforeNetworksList === true;
});
const afterNetworks = this.customItems.filter(function(item) {
return item.showBeforeNetworksList !== true;
});
this.listItems_ = beforeNetworks.concat(this.networks, afterNetworks);
this.restoreScroll(/** @type {!IronListElement} */ (this.$.networkList));
updateListItems_: function() {
const beforeNetworks =
this.customItems.filter(n => n.showBeforeNetworksList === true);
const afterNetworks =
this.customItems.filter(n => n.showBeforeNetworksList === false);
const newList = beforeNetworks.concat(this.networks, afterNetworks);
this.updateList('listItems_', item => item.guid, newList);
this.updateScrollableContents();
if (this.focusRequested_) {
this.async(function() {
......@@ -117,28 +153,4 @@ Polymer({
item.focus();
this.focusRequested_ = false;
},
/**
* Use iron-list selection (which is not the same as focus) to trigger
* tap (requires selection-enabled) or keyboard selection.
* @private
*/
selectedItemChanged_() {
if (this.selectedItem) {
this.onItemAction_(this.selectedItem);
}
},
/**
* @param {!NetworkList.NetworkListItemType} item
* @private
*/
onItemAction_(item) {
if (item.hasOwnProperty('customItemName')) {
this.fire('custom-item-selected', item);
} else {
this.fire('selected', item);
this.focusRequested_ = true;
}
},
});
......@@ -7,6 +7,7 @@
<link rel="import" href="../../../cr_elements/shared_style_css.html">
<link rel="import" href="../../../cr_elements/shared_vars_css.html">
<link rel="import" href="../../../html/i18n_behavior.html">
<link rel="import" href="../../../html/cr/ui/focus_row_behavior.html">
<link rel="import" href="cr_policy_network_behavior_mojo.html">
<link rel="import" href="network_icon.html">
<link rel="import" href="network_list_types.html">
......@@ -21,6 +22,7 @@
}
#divOuter {
height: 100%;
padding-inline-end: var(--cr-icon-ripple-padding);
}
......@@ -54,40 +56,60 @@
cr-policy-indicator {
padding: 0 var(--cr-controlled-by-spacing);
}
#wrapper {
height: 100%;
}
</style>
<div id="divOuter"
class="layout horizontal center flex" actionable>
<template is="dom-if" if="[[networkState]]">
<network-icon is-list-item
show-technology-badge="[[showTechnologyBadge]]"
network-state="[[networkState]]">
</network-icon>
</template>
<template is="dom-if" if="[[item.polymerIcon]]">
<iron-icon icon="[[item.polymerIcon]]"></iron-icon>
</template>
<div id="divText" class="layout horizontal flex">
<div aria-hidden="true">[[getItemName_(item)]]</div>
<div id="networkStateText"
class="cr-secondary-text"
hidden$="[[!isStateTextVisible_(networkState)]]"
active$="[[isStateTextActive_(networkState,
activationUnavailable)]]">
[[getNetworkStateText_(networkState, activationUnavailable)]]
<div id="wrapper" focus-row-container
class="layout horizontal center flex">
<div id="divOuter"
class="layout horizontal center flex"
actionable
focus-row-control
selectable
aria-label$="[[rowLabel]]"
role="button"
focus-type="rowWrapper"
on-keydown="onKeydown_"
on-click="onSelected_">
<template is="dom-if" if="[[networkState]]">
<network-icon is-list-item
show-technology-badge="[[showTechnologyBadge]]"
network-state="[[networkState]]">
</network-icon>
</template>
<template is="dom-if" if="[[item.polymerIcon]]">
<iron-icon icon="[[item.polymerIcon]]"></iron-icon>
</template>
<div id="divText" class="layout horizontal flex">
<div aria-hidden="true">[[getItemName_(item)]]</div>
<div id="networkStateText"
class="cr-secondary-text"
hidden$="[[!isStateTextVisible_(networkState)]]"
active$="[[isStateTextActive_(networkState,
activationUnavailable)]]">
[[getNetworkStateText_(networkState, activationUnavailable)]]
</div>
</div>
<template is="dom-if" if="[[isPolicySource(networkState.source)]]">
<cr-policy-indicator indicator-type="[[getIndicatorTypeForSource(
networkState.source)]]">
</cr-policy-indicator>
</template>
<template is="dom-if" if="[[isSubpageButtonVisible_(networkState, showButtons)]]" restamp>
<div>
<cr-icon-button class="subpage-arrow"
id="subpage-button"
on-click="onSubpageArrowClick_"
tabindex$="[[tabindex]]"
aria-label$="[[buttonLabel]]"
focus-row-control
focus-type="subpageButton">
</cr-icon-button>
</div>
</template>
</div>
<template is="dom-if" if="[[isPolicySource(networkState.source)]]">
<cr-policy-indicator indicator-type="[[getIndicatorTypeForSource(
networkState.source)]]">
</cr-policy-indicator>
</template>
<template is="dom-if"
if="[[isSubpageButtonVisible_(networkState, showButtons)]]" restamp>
<cr-icon-button class="subpage-arrow" id="subpage-button"
on-click="onSubpageArrowClick_" tabindex$="[[tabindex]]"
aria-label$="[[buttonLabel]]">
</cr-icon-button>
</template>
</div>
</template>
<script src="network_list_item.js"></script>
......
......@@ -13,6 +13,7 @@ Polymer({
behaviors: [
CrPolicyNetworkBehaviorMojo,
I18nBehavior,
cr.ui.FocusRowBehavior,
],
properties: {
......@@ -45,7 +46,6 @@ Polymer({
tabindex: {
type: Number,
value: -1,
reflectToAttribute: true,
},
/**
......@@ -53,11 +53,10 @@ Polymer({
* added as an attribute on this top-level network-list-item, and can
* be used by any sub-element which applies it.
*/
ariaLabel: {
rowLabel: {
type: String,
notify: true,
reflectToAttribute: true,
computed: 'getAriaLabel_(item, networkState)',
computed: 'getRowLabel_(item, networkState)',
},
buttonLabel: {
......@@ -162,7 +161,7 @@ Polymer({
* @return {string}
* @private
*/
getAriaLabel_() {
getRowLabel_() {
const NetworkType = chromeos.networkConfig.mojom.NetworkType;
const OncSource = chromeos.networkConfig.mojom.OncSource;
const SecurityType = chromeos.networkConfig.mojom.SecurityType;
......@@ -344,15 +343,11 @@ Polymer({
* @private
*/
onKeydown_(event) {
// The only key event handled by this element is pressing Enter when the
// subpage arrow is focused.
if (event.key !== 'Enter' ||
!this.isSubpageButtonVisible_(this.networkState, this.showButtons) ||
this.$$('#subpage-button') !== this.shadowRoot.activeElement) {
if (event.key !== 'Enter' && event.key !== ' ') {
return;
}
this.fireShowDetails_(event);
this.onSelected_(event);
// The default event for pressing Enter on a focused button is to simulate a
// click on the button. Prevent this action, since it would navigate a
......@@ -361,6 +356,22 @@ Polymer({
event.preventDefault();
},
/**
* @param {!Event} event
* @private
*/
onSelected_(event) {
if (this.isSubpageButtonVisible_(this.networkState, this.showButtons) &&
this.$$('#subpage-button') === this.shadowRoot.activeElement) {
this.fireShowDetails_(event);
} else if (this.item.hasOwnProperty('customItemName')) {
this.fire('custom-item-selected', this.item);
} else {
this.fire('selected', this.item);
this.focusRequested_ = true;
}
},
/**
* @param {!MouseEvent} event
* @private
......
......@@ -128,7 +128,7 @@ Polymer({
for (const network of networkList.children) {
if (network.is === 'network-list-item' &&
network.$$('#divText').children[0].innerText === name) {
return network;
return network.shadowRoot.getElementById('divOuter');
}
}
return null;
......
......@@ -39,5 +39,7 @@ cr_components_chromeos_auto_imports = [
"ui/webui/resources/cr_components/chromeos/quick_unlock/lock_screen_constants.html|recordLockScreenProgress,LockScreenProgress",
"ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.html|postDeviceDataToWebview",
"ui/webui/resources/html/assert.html|assert,assertNotReached",
"ui/webui/resources/html/cr/ui/focus_row_behavior.html|FocusRowBehavior",
"ui/webui/resources/html/list_property_update_behavior.html|ListPropertyUpdateBehavior",
"ui/webui/resources/html/polymer.html|Polymer,flush,html",
]
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