blob: 869189d6db4b34c4968c98cd5f3ac3af6742245b [file] [log] [blame]
// Copyright 2014 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.
goog.provide('cvox.ChromeVoxHTMLTimeWidget');
/**
* @fileoverview Gives the user spoken feedback as they interact with the time
* widget (input type=time).
*
*/
/**
* A class containing the information needed to speak
* a text change event to the user.
*
* @constructor
* @param {Element} timeElem The time widget element.
* @param {cvox.TtsInterface} tts The TTS object from ChromeVox.
*/
cvox.ChromeVoxHTMLTimeWidget = function(timeElem, tts) {
var self = this;
this.timeElem_ = timeElem;
this.timeTts_ = tts;
this.pHours_ = -1;
this.pMinutes_ = -1;
this.pSeconds_ = 0;
this.pMilliseconds_ = 0;
this.pAmpm_ = '';
this.pos_ = 0;
this.maxPos_ = 2;
this.keyListener_ = function(evt) {
self.eventHandler_(evt);
};
this.blurListener_ = function(evt) {
self.shutdown();
};
if (this.timeElem_.hasAttribute('step')) {
var step = this.timeElem_.getAttribute('step');
if (step > 0) { // 0 or invalid values show hh:mm AM/PM
if (step >= 1) {
this.maxPos_ = 3; // Anything larger than 1 shows hh:mm:ss AM/PM
} else {
this.maxPos_ = 4; // Anything less than 1 shows hh:mm:ss.ms AM/PM
}
}
}
// Ensure we have a reasonable value to start with.
if (this.timeElem_.value.length == 0) {
this.forceInitTime_();
}
// Move the cursor to the first position so that we are guaranteed to start
// off at the hours position.
for (var i = 0; i < this.maxPos_; i++) {
var evt = document.createEvent('KeyboardEvent');
evt.initKeyboardEvent(
'keydown', true, true, window, 'Left', 0, false, false, false, false);
this.timeElem_.dispatchEvent(evt);
evt = document.createEvent('KeyboardEvent');
evt.initKeyboardEvent(
'keyup', true, true, window, 'Left', 0, false, false, false, false);
this.timeElem_.dispatchEvent(evt);
}
this.timeElem_.addEventListener('keydown', this.keyListener_, false);
this.timeElem_.addEventListener('keyup', this.keyListener_, false);
this.timeElem_.addEventListener('blur', this.blurListener_, false);
this.update_(true);
};
/**
* Removes the key listeners for the time widget.
*
*/
cvox.ChromeVoxHTMLTimeWidget.prototype.shutdown = function() {
this.timeElem_.removeEventListener('blur', this.blurListener_, false);
this.timeElem_.removeEventListener('keydown', this.keyListener_, false);
this.timeElem_.removeEventListener('keyup', this.keyListener_, false);
};
/**
* Initialize to midnight.
* @private
*/
cvox.ChromeVoxHTMLTimeWidget.prototype.forceInitTime_ = function() {
this.timeElem_.setAttribute('value', '12:00');
};
/**
* Called when the position changes.
* @private
*/
cvox.ChromeVoxHTMLTimeWidget.prototype.handlePosChange_ = function() {
if (this.pos_ < 0) {
this.pos_ = 0;
}
if (this.pos_ > this.maxPos_) {
this.pos_ = this.maxPos_;
}
// Reset the cached state of the new field so that the field will be spoken
// in the update.
if (this.pos_ == this.maxPos_) {
this.pAmpm_ = '';
return;
}
switch (this.pos_) {
case 0:
this.pHours_ = -1;
break;
case 1:
this.pMinutes_ = -1;
break;
case 2:
this.pSeconds_ = -1;
break;
case 3:
this.pMilliseconds_ = -1;
break;
}
};
/**
* @param {boolean} shouldSpeakLabel True if the label should be spoken.
* @private
*/
cvox.ChromeVoxHTMLTimeWidget.prototype.update_ = function(shouldSpeakLabel) {
var splitTime = this.timeElem_.value.split(':');
if (splitTime.length < 1) {
this.forceInitTime_();
return;
}
var hours = splitTime[0];
var minutes = -1;
var seconds = 0;
var milliseconds = 0;
var ampm = cvox.ChromeVox.msgs.getMsg('timewidget_am');
if (splitTime.length > 1) {
minutes = splitTime[1];
}
if (splitTime.length > 2) {
var splitSecondsAndMilliseconds = splitTime[2].split('.');
seconds = splitSecondsAndMilliseconds[0];
if (splitSecondsAndMilliseconds.length > 1) {
milliseconds = splitSecondsAndMilliseconds[1];
}
}
if (hours > 12) {
hours = hours - 12;
ampm = cvox.ChromeVox.msgs.getMsg('timewidget_pm');
}
if (hours == 12) {
ampm = cvox.ChromeVox.msgs.getMsg('timewidget_pm');
}
if (hours == 0) {
hours = 12;
ampm = cvox.ChromeVox.msgs.getMsg('timewidget_am');
}
var changeMessage = '';
if (shouldSpeakLabel) {
changeMessage = cvox.DomUtil.getName(this.timeElem_, true, true) + '\n';
}
if (hours != this.pHours_) {
changeMessage = changeMessage + hours + ' ' +
cvox.ChromeVox.msgs.getMsg('timewidget_hours') + '\n';
this.pHours_ = hours;
}
if (minutes != this.pMinutes_) {
changeMessage = changeMessage + minutes + ' ' +
cvox.ChromeVox.msgs.getMsg('timewidget_minutes') + '\n';
this.pMinutes_ = minutes;
}
if (seconds != this.pSeconds_) {
changeMessage = changeMessage + seconds + ' ' +
cvox.ChromeVox.msgs.getMsg('timewidget_seconds') + '\n';
this.pSeconds_ = seconds;
}
if (milliseconds != this.pMilliseconds_) {
changeMessage = changeMessage + milliseconds + ' ' +
cvox.ChromeVox.msgs.getMsg('timewidget_milliseconds') + '\n';
this.pMilliseconds_ = milliseconds;
}
if (ampm != this.pAmpm_) {
changeMessage = changeMessage + ampm;
this.pAmpm_ = ampm;
}
if (changeMessage.length > 0) {
this.timeTts_.speak(changeMessage, cvox.QueueMode.FLUSH, null);
}
};
/**
* @param {Object} evt The event to handle.
* @private
*/
cvox.ChromeVoxHTMLTimeWidget.prototype.eventHandler_ = function(evt) {
var shouldSpeakLabel = false;
if (evt.type == 'keydown') {
if (((evt.keyCode == 9) && !evt.shiftKey) || (evt.keyCode == 39)) {
this.pos_++;
this.handlePosChange_();
shouldSpeakLabel = true;
}
if (((evt.keyCode == 9) && evt.shiftKey) || (evt.keyCode == 37)) {
this.pos_--;
this.handlePosChange_();
shouldSpeakLabel = true;
}
}
this.update_(shouldSpeakLabel);
};