Commit 5a6fcca5 authored by Akihiro Ota's avatar Akihiro Ota Committed by Commit Bot

ChromeVox: Interactive tutorial CSS and clean up.

This change does the following:
1. Adds CSS according to initial UI mocks
2. Adds JSDoc to member functions
3. Removes quotes from object keys
4. Removes underscores from function names.
5. Changes instances of "test" or "test area" to "practice" according
to UX feedback. We also make these changes in the code for consistency.
6. Changes many instances of "container" to "screen".
7. Rename "routing page" to "main menu" per UI feedback.
8. General clean up and use less verbose language.

--enable-experimental-accessibility-chromevox-tutorial flag.
Manually verify that tutorial loads with new UI. Move through the
tutorial using ChromeVox and verify no behavior change.

Bug: 1075752
Change-Id: I4895d7ad153a5adf1fc1471b637ca0156cea6b99
AX-Relnotes: N/A
Test: Run Chrome with the
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2304443Reviewed-by: default avatarAnastasia Helfinstein <anastasi@google.com>
Commit-Queue: Akihiro Ota <akihiroota@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790102}
parent de5b316d
......@@ -2,110 +2,171 @@
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<style>
#tutorialContainer {
background: linear-gradient(to bottom,rgba(255, 255, 255, 1) 40%,
rgba(215, 215, 215, 1) 100%);
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
#tutorial {
background: #FFF;
bottom: 0;
left: 0;
margin-bottom: 30px;
margin-top: 30px;
position: fixed;
right: 0;
top: 0;
}
#mainMenu {
margin: auto;
text-align: center;
width: 50%;
}
#routingPageContainer {
margin: auto;
text-align: center;
width: 50%;
#lessonMenu {
margin: auto;
text-align: center;
width: 50%;
}
#mainMenuContainer {
margin: auto;
text-align: center;
width: 50%;
#lessonShortcuts {
background: #FFF;
border-radius: 4px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
}
#lessonContainer {
margin: auto;
text-align: center;
width: 50%;
margin: auto;
text-align: center;
width: 50%;
}
#nav {
margin: auto;
text-align: center;
width: 50%;
}
h1 {
display: flex;
flex-direction: column;
font-family: Google Sans;
font-size: 24px;
line-height: 32px;
padding: 8px;
}
#navigationContainer {
margin: auto;
text-align: center;
width: 50%;
#mainMenuButtons {
background: #FFF;
border-radius: 4px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
}
#navSeparator {
background: rgb(232, 234, 237);
height: 1px;
margin: 10px;
}
#mainMenu cr-button,
#lessonMenu cr-button {
color: rgb(32, 33, 36);
font-family: Roboto;
font-size: 18px;
font-style: normal;
font-weight: normal;
line-height: 20px;
padding: 30px;
}
#navButtons cr-button {
color: rgb(26, 115, 232);
font-family: Roboto;
font-size: 13px;
font-style: normal;
font-weight: 500;
line-height: 20px;
margin-bottom: 10px;
margin-inline-end: 10px;
margin-inline-start: 10px;
margin-top: 10px;
}
</style>
<div id="tutorialContainer">
<div id="routingPageContainer"
hidden$="[[ shouldHideRoutingContainer_(activeContainer) ]]">
<h1 id="welcomeRoutingPage" tabindex="-1">[[ routingPageWelcome ]]</h1>
<h2>[[ chooseYourExperience ]]</h2>
<cr-button id="newUserButton" on-click="chooseCurriculum_">
[[ newUser ]]
</cr-button>
<cr-button id="experiencedUserButton" on-click="chooseCurriculum_">
[[ experiencedUser ]]
</cr-button>
<cr-button id="developerButton" on-click="chooseCurriculum_">
[[ developer ]]
</cr-button>
<div id="tutorial">
<div id="mainMenu"
hidden$="[[ shouldHideMainMenu(activeScreen) ]]">
<h1 id="mainMenuHeader" tabindex="-1">[[ chooseYourExperience ]]</h1>
<div id="mainMenuButtons">
<cr-button id="newUserButton" on-click="chooseCurriculum">
[[ newUser ]]
</cr-button>
<cr-button id="experiencedUserButton" on-click="chooseCurriculum">
[[ experiencedUser ]]
</cr-button>
<cr-button id="developerButton" on-click="chooseCurriculum">
[[ developer ]]
</cr-button>
</div>
</div>
<div id="mainMenuContainer"
hidden$="[[ shouldHideMainMenuContainer_(activeContainer) ]]">
<h1 id="welcomeMainMenu"
tabindex="-1">[[ computeMainMenuHeader_(curriculum, medium) ]]</h1>
<div id="lessonShortcuts"></div>
<div id="lessonMenu"
hidden$="[[ shouldHideLessonMenu(activeScreen) ]]">
<h1 id="lessonMenuHeader"
tabindex="-1">[[ computeLessonMenuHeader(curriculum, medium) ]]</h1>
<div id="lessonShortcuts"></div>
</div>
<div id="lessonContainer"
hidden$="[[ shouldHideLessonContainer_(activeContainer) ]]">
<!-- Use lessonData object to create all lessons -->
<template is="dom-repeat" items="[[ lessonData ]]" as="lesson"
index-as="index">
<tutorial-lesson
lesson-num="[[ index ]]"
title="[[ lesson.title ]]"
content="[[ lesson.content ]]"
medium="[[ lesson.medium ]]"
curriculums="[[ lesson.curriculums ]]"
test-area-title="[[ lesson.testAreaTitle ]]"
test-area-instructions="[[ lesson.testAreaInstructions ]]"
test-area-file="[[ lesson.testAreaFile ]]"
test-area-state="[[ lesson.testAreaState ]]"
hints="[[ lesson.hints ]]"
events="[[ lesson.events ]]"
active-lesson-num="[[ activeLessonNum ]]">
</tutorial-lesson>
</template>
hidden$="[[ shouldHideLessonContainer(activeScreen) ]]">
<!-- Use lessonData object to create all lessons -->
<template is="dom-repeat" items="[[ lessonData ]]" as="lesson"
index-as="index">
<tutorial-lesson
lesson-num="[[ index ]]"
title="[[ lesson.title ]]"
content="[[ lesson.content ]]"
medium="[[ lesson.medium ]]"
curriculums="[[ lesson.curriculums ]]"
practice-title="[[ lesson.practiceTitle ]]"
practice-instructions="[[ lesson.practiceInstructions ]]"
practice-file="[[ lesson.practiceFile ]]"
practice-state="[[ lesson.practiceState ]]"
hints="[[ lesson.hints ]]"
events="[[ lesson.events ]]"
active-lesson-num="[[ activeLessonNum ]]">
</tutorial-lesson>
</template>
</div>
<div id="navigationContainer">
<cr-button id="previousLesson" on-click="previousLesson_"
hidden$="[[
shouldHidePreviousLessonButton_(activeLessonIndex, activeContainer) ]]">
[[ previousLesson ]]
</cr-button>
<cr-button id="nextLesson" on-click="nextLesson_"
hidden$="[[
shouldHideNextLessonButton_(activeLessonIndex, activeContainer) ]]">
[[ nextLesson ]]
</cr-button>
<cr-button id="showRoutingPage" on-click="showRoutingContainer_"
hidden$="[[ !shouldHideRoutingContainer_(activeContainer) ]]">
[[ showRoutingPage ]]
</cr-button>
<cr-button id="showMainMenu" on-click="showMainMenuContainer_"
hidden$="[[ !shouldHideMainMenuContainer_(activeContainer) ]]">
[[ showMainMenu ]]
</cr-button>
<cr-button id="quit" on-click="quit_">[[ quitTutorial ]]</cr-button>
<div id="nav">
<div id="navSeparator">
</div>
<div id="navButtons">
<cr-button on-click="showPreviousLesson"
hidden$="[[
shouldHidePreviousLessonButton(activeLessonIndex, activeScreen) ]]">
[[ previousLesson ]]
</cr-button>
<cr-button on-click="showNextLesson"
hidden$="[[
shouldHideNextLessonButton(activeLessonIndex, activeScreen) ]]">
[[ nextLesson ]]
</cr-button>
<cr-button on-click="showLessonMenu"
hidden$="[[ !shouldHideLessonMenu(activeScreen) ]]">
[[ lessonMenu ]]
</cr-button>
<cr-button on-click="showMainMenu"
hidden$="[[ !shouldHideMainMenu(activeScreen) ]]">
[[ mainMenu ]]
</cr-button>
<cr-button on-click="exit">[[ exitTutorial ]]</cr-button>
</div>
</div>
</div>
\ No newline at end of file
......@@ -3,37 +3,40 @@
found in the LICENSE file. -->
<style>
#lessonTitle {
font-family: 'Roboto', sans-serif;
font-size: 30pt;
font-weight: bold;
#content {
display: block;
font-family: Google Sans;
font-size: 18px;
font-style: normal;
font-weight: 500;
line-height: 24px;
text-align: center;
}
#lessonContent {
display: block;
font-family: 'Roboto', sans-serif;
font-size: 16pt;
line-height: 150%;
#startPractice {
margin-bottom: 10px;
margin-inline-end: 10px;
margin-inline-start: 10px;
margin-top: 10px;
}
</style>
<div id="lessonContainer" hidden>
<h1 id="lessonTitle" tabindex="-1">[[title]]</h1>
<div id="lessonContent">
<template is="dom-repeat" items="[[ content ]]" as="text">
<p>[[ text ]]</p>
</template>
</div>
<cr-dialog id="testAreaContainer" close-text="Exit test area"
on-close="closeTestArea" show-close-button>
<div id="testAreaTitle" class="title"
slot="title">[[testAreaTitle]]</div>
<div class="body" slot="body">
<p id="testAreaInstructions">[[testAreaInstructions]]</p>
<div id="testArea"></div>
</div>
</cr-dialog>
<cr-button id="showTestArea" on-click="showTestArea"
hidden$="[[ shouldHideTestAreaButton_() ]]">Show test area</cr-button>
<div id="container" hidden>
<h1 id="title" tabindex="-1">[[ title ]]</h1>
<div id="content">
<template is="dom-repeat" items="[[ content ]]" as="text">
<p>[[ text ]]</p>
</template>
</div>
<cr-dialog id="practice" close-text="Exit practice area"
on-close="endPractice" show-close-button>
<div class="title" slot="title">[[ practiceTitle ]]</div>
<div class="body" slot="body">
<p>[[ practiceInstructions ]]</p>
<div id="practiceContent"></div>
</div>
</cr-dialog>
<cr-button id="startPractice" on-click="startPractice"
hidden$="[[ shouldHidePracticeButton() ]]">Practice Area</cr-button>
</div>
\ No newline at end of file
......@@ -23,13 +23,13 @@ export const TutorialLesson = Polymer({
curriculums: {type: Array},
testAreaTitle: {type: String},
practiceTitle: {type: String},
testAreaInstructions: {type: String},
practiceInstructions: {type: String},
testAreaFile: {type: String},
practiceFile: {type: String},
testAreaState: {type: Object},
practiceState: {type: Object},
events: {type: Array},
......@@ -43,16 +43,16 @@ export const TutorialLesson = Polymer({
// Observed properties.
activeLessonNum: {type: Number, observer: '_setVisibility'},
activeLessonNum: {type: Number, observer: 'setVisibility'},
},
/** @override */
ready() {
if (this.testAreaFile) {
this.populateTestArea_();
if (this.practiceFile) {
this.populatePracticeContent();
for (const evt of this.events) {
this.$.testArea.addEventListener(
evt, this.onTestAreaEvent.bind(this), true);
this.$.practiceContent.addEventListener(
evt, this.onPracticeEvent.bind(this), true);
}
}
},
......@@ -60,8 +60,9 @@ export const TutorialLesson = Polymer({
/**
* Updates this lessons visibility whenever the active lesson of the tutorial
* changes.
* @private
*/
_setVisibility() {
setVisibility() {
if (this.lessonNum === this.activeLessonNum) {
this.show();
} else {
......@@ -69,63 +70,70 @@ export const TutorialLesson = Polymer({
}
},
/** @private */
show() {
this.$.lessonContainer.hidden = false;
this.$.lessonTitle.focus();
this.$.container.hidden = false;
this.$.title.focus();
},
/** @private */
hide() {
this.$.lessonContainer.hidden = true;
this.$.container.hidden = true;
},
// Methods for managing the test area.
// Methods for managing the practice area.
/**
* Asynchronously populates test area.
* Asynchronously populates practice area.
* @private
*/
populateTestArea_() {
const path = '../i_tutorial/lessons/' + this.testAreaFile + '.html';
populatePracticeContent() {
const path = '../i_tutorial/lessons/' + this.practiceFile + '.html';
const xhr = new XMLHttpRequest();
xhr.open('GET', path, true);
xhr.onload = (evt) => {
if (xhr.readyState === 4 && xhr.status === 200) {
this.$.testArea.innerHTML = xhr.responseText;
this.$.practiceContent.innerHTML = xhr.responseText;
} else {
console.error(xhr.statusText);
}
};
xhr.onerror = function(evt) {
console.error('Failed to open test area file: ' + path);
console.error('Failed to open practice file: ' + path);
console.error(xhr.statusText);
};
xhr.send(null);
},
showTestArea() {
this.$.testAreaContainer.showModal();
/** @private */
startPractice() {
this.$.practice.showModal();
this.startHints();
},
closeTestArea() {
/** @private */
endPractice() {
this.stopHints();
this.$.showTestArea.focus();
this.$.startPractice.focus();
},
// Methods for tracking the state of the test area.
// Methods for tracking the state of the practice area.
/** @param {Event} event */
onTestAreaEvent(event) {
/**
* @param {Event} event
* @private
*/
onPracticeEvent(event) {
const elt = event.target.id;
const type = event.type;
// Maybe update goal state.
if (elt in this.testAreaState) {
if (type in this.testAreaState[elt]) {
this.testAreaState[elt][type] = true;
if (elt in this.practiceState) {
if (type in this.practiceState[elt]) {
this.practiceState[elt][type] = true;
}
}
......@@ -134,13 +142,16 @@ export const TutorialLesson = Polymer({
}
},
/** @return {boolean} */
/**
* @return {boolean}
* @private
*/
isGoalStateReached() {
if (this.goalStateReached === true) {
return true;
}
for (const [elt, state] of Object.entries(this.testAreaState)) {
for (const [elt, state] of Object.entries(this.practiceState)) {
for (const [evt, performed] of Object.entries(state)) {
if (performed == false) {
return false;
......@@ -150,6 +161,7 @@ export const TutorialLesson = Polymer({
return true;
},
/** @private */
onGoalStateReached() {
const previousState = this.goalStateReached;
this.goalStateReached = true;
......@@ -157,15 +169,15 @@ export const TutorialLesson = Polymer({
// Only perform when crossing the threshold from not reached to reached.
this.stopHints();
this.requestSpeech(
'You have passed this tutorial lesson. Find and press the close ' +
'test area button to continue');
'You have passed this tutorial lesson. Find and press the exit ' +
'practice area button to continue');
}
},
// Methods for managing hints.
/** @private */
startHints() {
this.hintCounter = 0;
this.hintIntervalId = setInterval(() => {
......@@ -175,9 +187,10 @@ export const TutorialLesson = Polymer({
}
this.requestSpeech(this.hints[this.hintCounter]);
this.hintCounter += 1;
}, 20000);
}, 20 * 1000);
},
/** @private */
stopHints() {
if (this.hintIntervalId) {
clearInterval(this.hintIntervalId);
......@@ -203,15 +216,19 @@ export const TutorialLesson = Polymer({
/**
* Requests speech from the Panel.
* @param {string} text
* @private
*/
requestSpeech(text) {
this.dispatchEvent(
new CustomEvent('request-speech', {composed: true, detail: {text}}));
},
/** @return {boolean} */
shouldHideTestAreaButton_() {
if (!this.testAreaFile) {
/**
* @return {boolean}
* @private
*/
shouldHidePracticeButton() {
if (!this.practiceFile) {
return true;
}
......
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