• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5goog.provide('cvox.ChromeVoxHTMLTimeWidget');
6
7/**
8 * @fileoverview Gives the user spoken feedback as they interact with the time
9 * widget (input type=time).
10 *
11 */
12
13/**
14 * A class containing the information needed to speak
15 * a text change event to the user.
16 *
17 * @constructor
18 * @param {Element} timeElem The time widget element.
19 * @param {cvox.TtsInterface} tts The TTS object from ChromeVox.
20 */
21cvox.ChromeVoxHTMLTimeWidget = function(timeElem, tts){
22  var self = this;
23  this.timeElem_ = timeElem;
24  this.timeTts_ = tts;
25  this.pHours_ = -1;
26  this.pMinutes_ = -1;
27  this.pSeconds_ = 0;
28  this.pMilliseconds_ = 0;
29  this.pAmpm_ = '';
30  this.pos_ = 0;
31  this.maxPos_ = 2;
32  this.keyListener_ = function(evt) {
33    self.eventHandler_(evt);
34  }
35  this.blurListener_ = function(evt) {
36    self.shutdown();
37  }
38  if (this.timeElem_.hasAttribute('step')) {
39  var step = this.timeElem_.getAttribute('step');
40    if (step > 0) { // 0 or invalid values show hh:mm AM/PM
41      if (step >= 1) {
42        this.maxPos_ = 3; // Anything larger than 1 shows hh:mm:ss AM/PM
43      } else {
44        this.maxPos_ = 4; // Anything less than 1 shows hh:mm:ss.ms AM/PM
45      }
46    }
47  }
48
49  // Ensure we have a reasonable value to start with.
50  if (this.timeElem_.value.length == 0) {
51    this.forceInitTime_();
52  }
53
54  // Move the cursor to the first position so that we are guaranteed to start
55  // off at the hours position.
56  for (var i = 0; i < this.maxPos_; i++) {
57    var evt = document.createEvent('KeyboardEvent');
58    evt.initKeyboardEvent(
59          'keydown', true, true, window, 'Left', 0, false, false, false, false);
60    this.timeElem_.dispatchEvent(evt);
61    evt = document.createEvent('KeyboardEvent');
62    evt.initKeyboardEvent(
63          'keyup', true, true, window, 'Left', 0, false, false, false, false);
64    this.timeElem_.dispatchEvent(evt);
65  }
66
67  this.timeElem_.addEventListener('keydown', this.keyListener_, false);
68  this.timeElem_.addEventListener('keyup', this.keyListener_, false);
69  this.timeElem_.addEventListener('blur', this.blurListener_, false);
70  this.update_(true);
71};
72
73/**
74 * Removes the key listeners for the time widget.
75 *
76 */
77cvox.ChromeVoxHTMLTimeWidget.prototype.shutdown = function() {
78  this.timeElem_.removeEventListener('blur', this.blurListener_, false);
79  this.timeElem_.removeEventListener('keydown', this.keyListener_, false);
80  this.timeElem_.removeEventListener('keyup', this.keyListener_, false);
81};
82
83cvox.ChromeVoxHTMLTimeWidget.prototype.forceInitTime_ = function() {
84  this.timeElem_.setAttribute('value', '12:00');
85};
86
87cvox.ChromeVoxHTMLTimeWidget.prototype.handlePosChange_ = function() {
88  if (this.pos_ < 0){
89    this.pos_ = 0;
90  }
91  if (this.pos_ > this.maxPos_){
92    this.pos_ = this.maxPos_;
93  }
94  // Reset the cached state of the new field so that the field will be spoken
95  // in the update.
96  if (this.pos_ == this.maxPos_){
97    this.pAmpm_ = '';
98    return;
99  }
100  switch (this.pos_){
101    case 0:
102      this.pHours_ = -1;
103      break;
104    case 1:
105      this.pMinutes_ = -1;
106      break;
107    case 2:
108      this.pSeconds_ = -1;
109      break;
110    case 3:
111      this.pMilliseconds_ = -1;
112      break;
113  }
114};
115
116
117cvox.ChromeVoxHTMLTimeWidget.prototype.update_ = function(shouldSpeakLabel) {
118  var splitTime = this.timeElem_.value.split(":");
119  if (splitTime.length < 1){
120    this.forceInitTime_();
121    return;
122  }
123
124  var hours = splitTime[0];
125  var minutes = -1;
126  var seconds = 0;
127  var milliseconds = 0;
128  var ampm = cvox.ChromeVox.msgs.getMsg('timewidget_am');
129  if (splitTime.length > 1) {
130    minutes = splitTime[1];
131  }
132  if (splitTime.length > 2) {
133    var splitSecondsAndMilliseconds = splitTime[2].split('.');
134    seconds = splitSecondsAndMilliseconds[0];
135    if (splitSecondsAndMilliseconds.length > 1){
136      milliseconds = splitSecondsAndMilliseconds[1];
137    }
138  }
139  if (hours > 12) {
140    hours = hours - 12;
141    ampm = cvox.ChromeVox.msgs.getMsg('timewidget_pm');
142  }
143  if (hours == 12) {
144    ampm = cvox.ChromeVox.msgs.getMsg('timewidget_pm');
145  }
146  if (hours == 0) {
147    hours = 12;
148    ampm = cvox.ChromeVox.msgs.getMsg('timewidget_am');
149  }
150
151  var changeMessage = '';
152
153  if (shouldSpeakLabel) {
154    changeMessage = cvox.DomUtil.getName(this.timeElem_, true, true) + '\n';
155  }
156
157  if (hours != this.pHours_) {
158    changeMessage = changeMessage + hours + ' ' +
159        cvox.ChromeVox.msgs.getMsg('timewidget_hours') + '\n';
160    this.pHours_ = hours;
161  }
162
163  if (minutes != this.pMinutes_) {
164    changeMessage = changeMessage + minutes + ' ' +
165        cvox.ChromeVox.msgs.getMsg('timewidget_minutes') + '\n';
166    this.pMinutes_ = minutes;
167  }
168
169  if (seconds != this.pSeconds_) {
170    changeMessage = changeMessage + seconds + ' ' +
171        cvox.ChromeVox.msgs.getMsg('timewidget_seconds') + '\n';
172    this.pSeconds_ = seconds;
173  }
174
175  if (milliseconds != this.pMilliseconds_) {
176    changeMessage = changeMessage + milliseconds + ' ' +
177        cvox.ChromeVox.msgs.getMsg('timewidget_milliseconds') + '\n';
178    this.pMilliseconds_ = milliseconds;
179  }
180
181  if (ampm != this.pAmpm_) {
182    changeMessage = changeMessage + ampm;
183    this.pAmpm_ = ampm;
184  }
185
186  if (changeMessage.length > 0) {
187    this.timeTts_.speak(changeMessage, 0, null);
188  }
189};
190
191cvox.ChromeVoxHTMLTimeWidget.prototype.eventHandler_ = function(evt) {
192  var shouldSpeakLabel = false;
193  if (evt.type == 'keydown') {
194    if (((evt.keyCode == 9) && !evt.shiftKey) || (evt.keyCode == 39)) {
195      this.pos_++;
196      this.handlePosChange_();
197      shouldSpeakLabel = true;
198    }
199    if (((evt.keyCode == 9) && evt.shiftKey) || (evt.keyCode == 37)) {
200      this.pos_--;
201      this.handlePosChange_();
202      shouldSpeakLabel = true;
203    }
204  }
205  this.update_(shouldSpeakLabel);
206};
207