spoken_messages.js revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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/**
6 * @fileoverview Useful abstraction when  speaking messages.
7 *
8 * Usage:
9 * $m('aria_role_link').withCount(document.links.length)
10 * .andPause()
11 * .andMessage('aria_role_forms')
12 * .withCount(document.forms.length)
13 * .andEnd()
14 * .speakFlush();
15 *
16 */
17
18goog.provide('cvox.SpokenMessages');
19
20goog.require('cvox.AbstractTts');
21goog.require('cvox.ChromeVox');
22goog.require('cvox.SpokenMessage');
23
24/**
25 * @type {Array}
26 */
27cvox.SpokenMessages.messages = [];
28
29/**
30 * Speaks the message chain and interrupts any on-going speech.
31 */
32cvox.SpokenMessages.speakFlush = function() {
33  cvox.SpokenMessages.speak(cvox.AbstractTts.QUEUE_MODE_FLUSH);
34};
35
36/**
37 * Speaks the message chain after on-going speech finishes.
38 */
39cvox.SpokenMessages.speakQueued = function() {
40  cvox.SpokenMessages.speak(cvox.AbstractTts.QUEUE_MODE_QUEUE);
41};
42
43/**
44 * Speak the message chain.
45 * @param {number} mode The speech queue mode.
46 */
47cvox.SpokenMessages.speak = function(mode) {
48  for (var i = 0; i < cvox.SpokenMessages.messages.length; ++i) {
49    var message = cvox.SpokenMessages.messages[i];
50
51    // An invalid message format.
52    if (!message || (!message.id && !message.raw))
53      throw 'Invalid message received.';
54
55    var finalText = '';
56    if (message.count != null) {
57      if (message.count <= 0) {
58        try {
59          finalText +=
60              cvox.ChromeVox.msgs.getMsg(message.id[0] + '_optional_default');
61        } catch(e) {
62          // The message doesn't exist.
63          continue;
64        }
65      } else if (message.count == 1) {
66        finalText += cvox.ChromeVox.msgs.getMsg(message.id[0] + '_singular');
67      } else {
68        finalText += cvox.ChromeVox.msgs.getMsg(message.id[0] + '_plural',
69                                                [message.count]);
70      }
71    } else {
72      if (message.raw) {
73        finalText += message.raw;
74      } else {
75        finalText +=
76            cvox.ChromeVox.msgs.getMsg.apply(cvox.ChromeVox.msgs, message.id);
77      }
78    }
79
80    cvox.ChromeVox.tts.speak(finalText, mode,
81                             cvox.AbstractTts.PERSONALITY_ANNOUNCEMENT);
82
83    // Always queue after the first message.
84    mode = cvox.AbstractTts.QUEUE_MODE_QUEUE;
85  }
86
87  cvox.SpokenMessages.messages = [];
88}
89
90  /**
91   * The newest message.
92   * @return {cvox.SpokenMessage} The newest (current) message.
93   */
94cvox.SpokenMessages.currentMessage = function() {
95  if (cvox.SpokenMessages.messages.length == 0)
96    throw 'Invalid usage of SpokenMessages; start the chain using $m()';
97  return cvox.SpokenMessages.messages[cvox.SpokenMessages.messages.length - 1];
98};
99
100/**
101 * Quantifies the current message.
102 * This will modify the way the message gets read.
103 * For example, if the count is 2, the message becomes pluralized according
104 * to our i18n resources. The message "2 links" is a possible output.
105 * @param {Number} count Quantifies current message.
106 * @return {Object} This object, useful for chaining.
107 */
108cvox.SpokenMessages.withCount = function(count) {
109  cvox.SpokenMessages.currentMessage().count = count;
110  return cvox.SpokenMessages;
111}
112
113/**
114 * Quantifies the current message.
115 * Modifies the message with a current index/total description (commonly seen
116 * in lists).
117 * @param {number} index The current item.
118 * @param {number} total The total number of items.
119 * @return {Object} This object, useful for chaining.
120 */
121cvox.SpokenMessages.andIndexTotal = function(index, total) {
122  var newMessage = new cvox.SpokenMessage();
123  newMessage.raw = cvox.ChromeVox.msgs.getMsg('index_total', [index, total]);
124  cvox.SpokenMessages.messages.push(newMessage);
125  return cvox.SpokenMessages;
126}
127
128/**
129 * Ends a message. with an appropriate marker.
130 * @return {Object} This object, useful for chaining.
131 */
132cvox.SpokenMessages.andEnd = function() {
133  return cvox.SpokenMessages.andMessage('end');
134};
135
136/**
137 * Adds a message.
138 * @param {string|Array} messageId The id of the message.
139 * @return {Object} This object, useful for chaining.
140 */
141cvox.SpokenMessages.andMessage = function(messageId) {
142  var newMessage = new cvox.SpokenMessage();
143  newMessage.id = typeof(messageId) == 'string' ? [messageId] : messageId;
144  cvox.SpokenMessages.messages.push(newMessage);
145  return cvox.SpokenMessages;
146};
147
148
149/**
150 * Adds a string as a message.
151 * @param {string} message An already localized string.
152 * @return {Object} This object, useful for chaining.
153 */
154cvox.SpokenMessages.andRawMessage = function(message) {
155  var newMessage = new cvox.SpokenMessage();
156  newMessage.raw = message;
157  cvox.SpokenMessages.messages.push(newMessage);
158  return cvox.SpokenMessages;
159}
160
161/**
162 * Pauses after the message, with an appropriate marker.
163 * @return {Object} This object, useful for chaining.
164 */
165cvox.SpokenMessages.andPause = function() {
166  return cvox.SpokenMessages.andMessage('pause');
167};
168
169cvox.$m = cvox.SpokenMessages.andMessage;
170