Commit 9c953d1c authored by Yue Cen's avatar Yue Cen Committed by Commit Bot

Fast app reinstall: Fix A11y issues

- Screen reader will read the app name when the chip is focused.
- Navigate chips using tab.
- Toggle app to install / not install with space or enter key.
- Screen reader will read the title of recommend-apps and app-dowloading
screens.

Bug: 885219
Change-Id: I5ad9f79b33ae8a55fe4f5240692261e346461a22
Reviewed-on: https://chromium-review.googlesource.com/1234237Reviewed-by: default avatarAlexander Alekseev <alemate@chromium.org>
Commit-Queue: Yue Cen <rsgingerrs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#593670}
parent 08512341
......@@ -2,33 +2,47 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var selectedApps = /** @dict */ {};
function generateContents(appIcon, appTitle, appPackageName) {
var doc = document;
var recommendAppsContainer = doc.getElementById('recommend-apps-container');
var item = doc.createElement('div');
const doc = document;
const recommendAppsContainer = doc.getElementById('recommend-apps-container');
const item = doc.createElement('div');
item.classList.add('item');
item.classList.add('checked');
item.setAttribute('data-packagename', appPackageName);
var imagePicker = doc.createElement('div');
const imagePicker = doc.createElement('div');
imagePicker.classList.add('image-picker');
imagePicker.addEventListener('click', toggleCheckStatus);
imagePicker.addEventListener('click', toggleCheckStatus_);
item.appendChild(imagePicker);
var chip = doc.createElement('div');
const chip = doc.createElement('div');
chip.classList.add('chip');
chip.addEventListener('mousedown', addRippleCircle);
chip.addEventListener('mouseup', toggleCheckStatus);
chip.addEventListener('animationend', removeRippleCircle);
chip.tabIndex = 0;
chip.addEventListener('mousedown', addRippleCircle_);
chip.addEventListener('mouseup', toggleCheckStatus_);
chip.addEventListener('animationend', removeRippleCircle_);
// Add keyboard events
let keyEventFired = false;
chip.addEventListener('keydown', function(e) {
if (!keyEventFired && isConfirmKey_(e))
addRippleCircle_(e);
keyEventFired = true;
});
chip.addEventListener('keyup', function(e) {
if (isConfirmKey_(e)) {
toggleCheckStatus_(e);
keyEventFired = false;
}
});
item.appendChild(chip);
var img = doc.createElement('img');
const img = doc.createElement('img');
img.classList.add('app-icon');
img.setAttribute('src', decodeURIComponent(appIcon));
var title = doc.createElement('span');
const title = doc.createElement('span');
title.classList.add('app-title');
title.innerHTML = appTitle;
......@@ -38,47 +52,59 @@ function generateContents(appIcon, appTitle, appPackageName) {
recommendAppsContainer.appendChild(item);
}
// Add a layer on top of the chip to create the ripple effect.
function addRippleCircle(e) {
let chip = e.currentTarget;
let item = chip.parentNode;
let offsetX = e.pageX - item.offsetLeft;
let offsetY = e.pageY - item.offsetTop;
/**
* Add a layer on top of the chip to create the ripple effect.
* @param {!Event} e
* @private
*/
function addRippleCircle_(e) {
const chip = e.currentTarget;
const item = chip.parentNode;
const offsetX = e.pageX - item.offsetLeft;
const offsetY = e.pageY - item.offsetTop;
chip.style.setProperty('--x', offsetX);
chip.style.setProperty('--y', offsetY);
chip.innerHTML += '<div class="ripple"></div>';
}
// After the animation ends, remove the ripple layer.
function removeRippleCircle(e) {
let chip = e.currentTarget;
let rippleLayers = chip.querySelectorAll('.ripple');
for (let rippleLayer of rippleLayers) {
/**
* After the animation ends, remove the ripple layer.
* @param {!Event} e
* @private
*/
function removeRippleCircle_(e) {
const chip = e.currentTarget;
const rippleLayers = chip.querySelectorAll('.ripple');
for (const rippleLayer of rippleLayers) {
if (rippleLayer.className === 'ripple') {
rippleLayer.remove();
}
}
}
// Toggle the check status of an app. If an app is selected, add the "checked"
// class so that the checkmark is visible. Otherwise, remove the checked class.
function toggleCheckStatus(e) {
var item = e.currentTarget.parentNode;
/**
* Toggle the check status of an app. If an app is selected, add the "checked"
* lass so that the checkmark is visible. Otherwise, remove the checked class.
* @param {!Event} e
* @private
*/
function toggleCheckStatus_(e) {
const item = e.currentTarget.parentNode;
item.classList.toggle('checked');
}
function getSelectedPackages() {
var selectedPackages = [];
var checkedItems = document.getElementsByClassName('checked');
for (var checkedItem of checkedItems) {
const selectedPackages = [];
const checkedItems = document.getElementsByClassName('checked');
for (const checkedItem of checkedItems) {
selectedPackages.push(checkedItem.dataset.packagename);
}
return selectedPackages;
}
function toggleScrollShadow(container) {
function toggleScrollShadow_(container) {
const shadowThreshold = 5;
var doc = document;
const doc = document;
doc.getElementById('scroll-top')
.classList.toggle('shadow', container.scrollTop > shadowThreshold);
doc.getElementById('scroll-bottom')
......@@ -89,14 +115,21 @@ function toggleScrollShadow(container) {
shadowThreshold);
}
// Add the scroll shadow effect. This contains two parts. First initialize the
// effect after all the contents have been generated. Then attach it to the
// onscroll event.
/**
* Add the scroll shadow effect. This contains two parts. First initialize the
* effect after all the contents have been generated. Then attach it to the
* onscroll event.
*/
function addScrollShadowEffect() {
var doc = document;
var container = doc.getElementById('recommend-apps-container');
toggleScrollShadow(container);
const doc = document;
const container = doc.getElementById('recommend-apps-container');
toggleScrollShadow_(container);
container.onscroll = function() {
toggleScrollShadow(this);
toggleScrollShadow_(this);
};
}
\ No newline at end of file
}
function isConfirmKey_(e) {
return e.keyCode === 13 // Enter
|| e.keyCode === 32; // Space
}
......@@ -11,6 +11,7 @@
<link rel="stylesheet" href="app_downloading.css">
<link rel="stylesheet" href="oobe_flex_layout.css">
<oobe-dialog id="app-downloading-dialog" role="dialog" has-buttons
aria-label$="[[getDialogTitleA11yString_(numOfApps)]]"
no-footer-padding>
<iron-icon src="chrome://oobe/playstore.svg" slot="oobe-icon">
</iron-icon>
......
......@@ -36,5 +36,14 @@ Polymer({
/** @private */
hasSingleApp_: function(numOfApps) {
return numOfApps === 1;
}
},
/** @private */
getDialogTitleA11yString_: function(numOfApps) {
if (this.hasSingleApp_(numOfApps)) {
return this.i18n('appDownloadingScreenTitleSingular');
} else {
return this.i18n('appDownloadingScreenTitlePlural', numOfApps);
}
},
});
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