Home | History | Annotate | Download | only in common
      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 
      5 goog.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  */
     21 cvox.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  */
     77 cvox.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 
     83 cvox.ChromeVoxHTMLTimeWidget.prototype.forceInitTime_ = function() {
     84   this.timeElem_.setAttribute('value', '12:00');
     85 };
     86 
     87 cvox.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 
    117 cvox.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 
    191 cvox.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