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.
5 goog
.provide('cvox.ChromeVoxHTMLDateWidget');
8 * @fileoverview Gives the user spoken feedback as they interact with the date
9 * widget (input type=date).
14 * A class containing the information needed to speak
15 * a text change event to the user.
18 * @param {Element} dateElem The time widget element.
19 * @param {cvox.TtsInterface} tts The TTS object from ChromeVox.
21 cvox
.ChromeVoxHTMLDateWidget = function(dateElem
, tts
){
24 * Currently selected field in the widget.
30 if (dateElem
.type
== 'month' || dateElem
.type
== 'week') {
34 * The maximum number of fields in the widget.
38 this.maxPos_
= maxpos
;
40 * The HTML node of the widget.
44 this.dateElem_
= dateElem
;
46 * A handle to the ChromeVox TTS object.
52 * The previous value of the year field.
58 * The previous value of the month field.
64 * The previous value of the week field.
70 * The previous value of the day field.
76 // Use listeners to make this work when running tests inside of ChromeVox.
77 this.keyListener_ = function(evt
) {
78 self
.eventHandler_(evt
);
80 this.blurListener_ = function(evt
) {
84 // Ensure we have a reasonable value to start with.
85 if (this.dateElem_
.value
.length
== 0) {
86 this.forceInitTime_();
89 // Move the cursor to the first position so that we are guaranteed to start
90 // off at the hours position.
91 for (var i
= 0; i
< this.maxPos_
; i
++) {
92 var evt
= document
.createEvent('KeyboardEvent');
93 evt
.initKeyboardEvent(
94 'keydown', true, true, window
, 'Left', 0, false, false, false, false);
95 this.dateElem_
.dispatchEvent(evt
);
96 evt
= document
.createEvent('KeyboardEvent');
97 evt
.initKeyboardEvent(
98 'keyup', true, true, window
, 'Left', 0, false, false, false, false);
99 this.dateElem_
.dispatchEvent(evt
);
102 this.dateElem_
.addEventListener('keydown', this.keyListener_
, false);
103 this.dateElem_
.addEventListener('keyup', this.keyListener_
, false);
104 this.dateElem_
.addEventListener('blur', this.blurListener_
, false);
109 * Removes the key listeners for the time widget.
112 cvox
.ChromeVoxHTMLDateWidget
.prototype.shutdown = function() {
113 this.dateElem_
.removeEventListener('blur', this.blurListener_
, false);
114 this.dateElem_
.removeEventListener('keydown', this.keyListener_
, false);
115 this.dateElem_
.removeEventListener('keyup', this.keyListener_
, false);
119 * Forces a sensible default value so that there is something there that can
120 * be inspected with JS.
123 cvox
.ChromeVoxHTMLDateWidget
.prototype.forceInitTime_ = function() {
124 var currentDate
= new Date();
125 var valueString
= '';
126 var yearString
= currentDate
.getFullYear() + '';
127 // Date.getMonth starts at 0, but the value for the HTML5 date widget needs to
129 var monthString
= currentDate
.getMonth() + 1 + '';
130 if (monthString
.length
< 2) {
131 monthString
= '0' + monthString
; // Month format is MM.
133 var dayString
= currentDate
.getDate() + '';
135 switch (this.dateElem_
.type
) {
137 valueString
= yearString
+ '-' + monthString
;
140 // Based on info from: http://www.merlyn.demon.co.uk/weekcalc.htm#WNR
141 currentDate
.setHours(0,0,0);
142 // Set to nearest Thursday: current date + 4 - current day number
143 // Make Sunday's day number 7
145 currentDate
.getDate() + 4 - (currentDate
.getDay()||7));
146 // Get first day of year
147 var yearStart
= new Date(currentDate
.getFullYear(),0,1);
148 // Calculate full weeks to nearest Thursday
150 Math
.ceil(( ( (currentDate
- yearStart
) / 86400000) + 1)/7) + '';
151 if (weekString
.length
< 2) {
152 weekString
= '0' + weekString
; // Week format is WXX.
154 weekString
= 'W' + weekString
;
155 valueString
= yearString
+ '-' + weekString
;
158 valueString
= yearString
+ '-' + monthString
+ '-' + dayString
;
161 this.dateElem_
.setAttribute('value', valueString
);
165 * Ensure that the position stays within bounds.
168 cvox
.ChromeVoxHTMLDateWidget
.prototype.handlePosChange_ = function() {
169 this.pos_
= Math
.max(this.pos_
, 0);
170 this.pos_
= Math
.min(this.pos_
, this.maxPos_
);
171 // TODO (clchen, dtseng): Make this logic i18n once there is a way to
172 // determine what the date format actually is. For now, assume that:
173 // date == mm/dd/yyyy
178 if (this.dateElem_
.type
== 'week') {
185 if (this.dateElem_
.type
== 'date') {
198 * Speaks any changes to the control.
200 * @param {boolean} shouldSpeakLabel Whether or not to speak the label.
202 cvox
.ChromeVoxHTMLDateWidget
.prototype.update_ = function(shouldSpeakLabel
) {
203 var splitDate
= this.dateElem_
.value
.split("-");
204 if (splitDate
.length
< 1){
205 this.forceInitTime_();
214 year
= parseInt(splitDate
[0], 10);
216 if (this.dateElem_
.type
== 'week') {
217 week
= parseInt(splitDate
[1].replace('W', ''), 10);
218 } else if (this.dateElem_
.type
== 'date') {
219 month
= parseInt(splitDate
[1], 10);
220 day
= parseInt(splitDate
[2], 10);
222 month
= parseInt(splitDate
[1], 10);
225 var changeMessage
= ''
227 if (shouldSpeakLabel
) {
228 changeMessage
= cvox
.DomUtil
.getName(this.dateElem_
, true, true) + '\n';
231 if (week
!= this.pWeek_
) {
232 changeMessage
= changeMessage
+
233 cvox
.ChromeVox
.msgs
.getMsg('datewidget_week') + week
+ '\n';
237 if (month
!= this.pMonth_
) {
241 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_january');
244 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_february');
247 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_march');
250 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_april');
253 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_may');
256 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_june');
259 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_july');
262 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_august');
265 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_september');
268 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_october');
271 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_november');
274 monthName
= cvox
.ChromeVox
.msgs
.getMsg('datewidget_december');
277 changeMessage
= changeMessage
+ monthName
+ '\n';
278 this.pMonth_
= month
;
281 if (day
!= this.pDay_
) {
282 changeMessage
= changeMessage
+ day
+ '\n';
286 if (year
!= this.pYear_
) {
287 changeMessage
= changeMessage
+ year
+ '\n';
291 if (changeMessage
.length
> 0) {
292 this.dateTts_
.speak(changeMessage
, 0, null);
297 * Handles user key events.
299 * @param {Event} evt The event to be handled.
301 cvox
.ChromeVoxHTMLDateWidget
.prototype.eventHandler_ = function(evt
) {
302 var shouldSpeakLabel
= false;
303 if (evt
.type
== 'keydown') {
304 // Handle tab/right arrow
305 if (((evt
.keyCode
== 9) && !evt
.shiftKey
) || (evt
.keyCode
== 39)) {
307 this.handlePosChange_();
308 shouldSpeakLabel
= true;
310 // Handle shift+tab/left arrow
311 if (((evt
.keyCode
== 9) && evt
.shiftKey
) || (evt
.keyCode
== 37)) {
313 this.handlePosChange_();
314 shouldSpeakLabel
= true;
316 // For all other cases, fall through and let update_ decide if there are any
317 // changes that need to be spoken.
319 this.update_(shouldSpeakLabel
);