Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / chromeos / chromevox / chromevox / injected / api_implementation.js
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 Implentation of ChromeVox's public API.
7  *
8  */
9
10 goog.provide('cvox.ApiImplementation');
11 goog.provide('cvox.ApiImplementation.Math');
12
13 goog.require('cvox.ApiUtil');
14 goog.require('cvox.AriaUtil');
15 goog.require('cvox.BuildInfo');
16 goog.require('cvox.ChromeVox');
17 goog.require('cvox.ChromeVoxJSON');
18 goog.require('cvox.DomUtil');
19 goog.require('cvox.ScriptInstaller');
20
21 /**
22  * @constructor
23  */
24 cvox.ApiImplementation = function() {
25 };
26
27 /**
28  * The URL to the script loader.
29  * @type {string}
30  */
31 cvox.ApiImplementation.siteSpecificScriptLoader;
32
33 /**
34  * The URL base for the site-specific scripts.
35  * @type {string}
36  */
37 cvox.ApiImplementation.siteSpecificScriptBase;
38
39 /**
40  * Inject the API into the page and set up communication with it.
41  * @param {function()=} opt_onload A function called when the script is loaded.
42  */
43 cvox.ApiImplementation.init = function(opt_onload) {
44   window.addEventListener('message', cvox.ApiImplementation.portSetup, true);
45   var scripts = new Array();
46   scripts.push(cvox.ChromeVox.host.getFileSrc(
47       'chromevox/injected/api_util.js'));
48   scripts.push(cvox.ChromeVox.host.getApiSrc());
49   scripts.push(cvox.ApiImplementation.siteSpecificScriptLoader);
50
51   var apiScript = cvox.ScriptInstaller.installScript(scripts,
52       'cvoxapi', opt_onload, cvox.ApiImplementation.siteSpecificScriptBase);
53
54   if (!apiScript) {
55     // If the API script is already installed, just re-enable it.
56     window.location.href = 'javascript:cvox.Api.internalEnable();';
57   }
58 };
59
60 /**
61  * This method is called when the content script receives a message from
62  * the page.
63  * @param {Event} event The DOM event with the message data.
64  * @return {boolean} True if default event processing should continue.
65  */
66 cvox.ApiImplementation.portSetup = function(event) {
67   if (event.data == 'cvox.PortSetup') {
68     cvox.ApiImplementation.port = event.ports[0];
69     cvox.ApiImplementation.port.onmessage = function(event) {
70       cvox.ApiImplementation.dispatchApiMessage(
71           cvox.ChromeVoxJSON.parse(event.data));
72     };
73
74     // Stop propagation since it was our message.
75     event.stopPropagation();
76     return false;
77   }
78   return true;
79 };
80
81 /**
82  * Call the appropriate API function given a message from the page.
83  * @param {*} message The message.
84  */
85 cvox.ApiImplementation.dispatchApiMessage = function(message) {
86   var method;
87   switch (message['cmd']) {
88     case 'speak': method = cvox.ApiImplementation.speak; break;
89     case 'speakNodeRef': method = cvox.ApiImplementation.speakNodeRef; break;
90     case 'stop': method = cvox.ApiImplementation.stop; break;
91     case 'playEarcon': method = cvox.ApiImplementation.playEarcon; break;
92     case 'syncToNodeRef': method = cvox.ApiImplementation.syncToNodeRef; break;
93     case 'clickNodeRef': method = cvox.ApiImplementation.clickNodeRef; break;
94     case 'getBuild': method = cvox.ApiImplementation.getBuild; break;
95     case 'getVersion': method = cvox.ApiImplementation.getVersion; break;
96     case 'getCurrentNode': method = cvox.ApiImplementation.getCurrentNode;
97         break;
98     case 'getCvoxModKeys': method = cvox.ApiImplementation.getCvoxModKeys;
99         break;
100     case 'isKeyShortcut': method = cvox.ApiImplementation.isKeyShortcut; break;
101     case 'setKeyEcho': method = cvox.ApiImplementation.setKeyEcho; break;
102     case 'Math.defineRule':
103       method = cvox.ApiImplementation.Math.defineRule; break;
104       break;
105   }
106   if (!method) {
107     throw 'Unknown API call: ' + message['cmd'];
108   }
109
110   method.apply(cvox.ApiImplementation, message['args']);
111 };
112
113 /**
114  * Sets endCallback in properties to call callbackId's function.
115  * @param {Object} properties Speech properties to use for this utterance.
116  * @param {number} callbackId The callback Id.
117  * @private
118  */
119 function setupEndCallback_(properties, callbackId) {
120   var endCallback = function() {
121     cvox.ApiImplementation.port.postMessage(cvox.ChromeVoxJSON.stringify(
122         {
123           'id': callbackId
124         }));
125   };
126   if (properties) {
127     properties['endCallback'] = endCallback;
128   }
129 }
130
131 /**
132  * Speaks the given string using the specified queueMode and properties.
133  *
134  * @param {number} callbackId The callback Id.
135  * @param {string} textString The string of text to be spoken.
136  * @param {number=} queueMode Valid modes are 0 for flush; 1 for queue.
137  * @param {Object=} properties Speech properties to use for this utterance.
138  */
139 cvox.ApiImplementation.speak = function(
140     callbackId, textString, queueMode, properties) {
141   if (cvox.ChromeVox.isActive) {
142     if (!properties) {
143       properties = {};
144     }
145     setupEndCallback_(properties, callbackId);
146     cvox.ChromeVox.tts.speak(textString,
147                              /** @type {cvox.QueueMode} */ (queueMode),
148                              properties);
149   }
150 };
151
152 /**
153  * Speaks the given node.
154  *
155  * @param {Node} node The node that ChromeVox should be synced to.
156  * @param {number=} queueMode Valid modes are 0 for flush; 1 for queue.
157  * @param {Object=} properties Speech properties to use for this utterance.
158  */
159 cvox.ApiImplementation.speakNode = function(node, queueMode, properties) {
160   if (cvox.ChromeVox.isActive) {
161     cvox.ChromeVox.tts.speak(
162         cvox.DomUtil.getName(node),
163         /** @type {cvox.QueueMode} */ (queueMode),
164         properties);
165   }
166 };
167
168 /**
169  * Speaks the given node.
170  *
171  * @param {number} callbackId The callback Id.
172  * @param {Object} nodeRef A serializable reference to a node.
173  * @param {number=} queueMode Valid modes are 0 for flush; 1 for queue.
174  * @param {Object=} properties Speech properties to use for this utterance.
175  */
176 cvox.ApiImplementation.speakNodeRef = function(
177     callbackId, nodeRef, queueMode, properties) {
178   var node = cvox.ApiUtils.getNodeFromRef(nodeRef);
179   if (!properties) {
180     properties = {};
181   }
182   setupEndCallback_(properties, callbackId);
183   cvox.ApiImplementation.speakNode(node, queueMode, properties);
184 };
185
186 /**
187  * Stops speech.
188  */
189 cvox.ApiImplementation.stop = function() {
190   if (cvox.ChromeVox.isActive) {
191     cvox.ChromeVox.tts.stop();
192   }
193 };
194
195 /**
196  * Plays the specified earcon sound.
197  *
198  * @param {string} earcon An earcon name.
199  * Valid names are:
200  *   ALERT_MODAL
201  *   ALERT_NONMODAL
202  *   BULLET
203  *   BUSY_PROGRESS_LOOP
204  *   BUSY_WORKING_LOOP
205  *   BUTTON
206  *   CHECK_OFF
207  *   CHECK_ON
208  *   COLLAPSED
209  *   EDITABLE_TEXT
210  *   ELLIPSIS
211  *   EXPANDED
212  *   FONT_CHANGE
213  *   INVALID_KEYPRESS
214  *   LINK
215  *   LISTBOX
216  *   LIST_ITEM
217  *   NEW_MAIL
218  *   OBJECT_CLOSE
219  *   OBJECT_DELETE
220  *   OBJECT_DESELECT
221  *   OBJECT_OPEN
222  *   OBJECT_SELECT
223  *   PARAGRAPH_BREAK
224  *   SEARCH_HIT
225  *   SEARCH_MISS
226  *   SECTION
227  *   TASK_SUCCESS
228  *   WRAP
229  *   WRAP_EDGE
230  * This list may expand over time.
231  */
232 cvox.ApiImplementation.playEarcon = function(earcon) {
233   if (cvox.ChromeVox.isActive) {
234     cvox.ChromeVox.earcons.playEarconByName(earcon);
235   }
236 };
237
238 /**
239  * Synchronizes ChromeVox's internal cursor to a node by id.
240  *
241  * @param {Object} nodeRef A serializable reference to a node.
242  * @param {boolean=} speakNode If true, speaks out the node.
243  */
244 cvox.ApiImplementation.syncToNodeRef = function(nodeRef, speakNode) {
245   var node = cvox.ApiUtils.getNodeFromRef(nodeRef);
246   cvox.ApiImplementation.syncToNode(node, speakNode);
247 };
248
249 /**
250  * Synchronizes ChromeVox's internal cursor to the targetNode.
251  * Note that this will NOT trigger reading unless given the optional argument;
252  * it is for setting the internal ChromeVox cursor so that when the user resumes
253  * reading, they will be starting from a reasonable position.
254  *
255  * @param {Node} targetNode The node that ChromeVox should be synced to.
256  * @param {boolean=} opt_speakNode If true, speaks out the node.
257  * @param {number=} opt_queueMode The queue mode to use for speaking.
258  */
259 cvox.ApiImplementation.syncToNode = function(
260     targetNode, opt_speakNode, opt_queueMode) {
261   if (!cvox.ChromeVox.isActive) {
262     return;
263   }
264
265   if (opt_queueMode == undefined) {
266     opt_queueMode = cvox.QueueMode.CATEGORY_FLUSH;
267   }
268
269   cvox.ChromeVox.navigationManager.updateSelToArbitraryNode(targetNode, true);
270   cvox.ChromeVox.navigationManager.updateIndicator();
271
272   if (opt_speakNode == undefined) {
273     opt_speakNode = false;
274   }
275
276   // Don't speak anything if the node is hidden or invisible.
277   if (cvox.AriaUtil.isHiddenRecursive(targetNode)) {
278     opt_speakNode = false;
279   }
280
281   if (opt_speakNode) {
282     cvox.ChromeVox.navigationManager.speakDescriptionArray(
283         cvox.ApiImplementation.getDesc_(targetNode),
284         /** @type {cvox.QueueMode} */ (opt_queueMode),
285         null,
286         null,
287         cvox.TtsCategory.NAV);
288   }
289
290   cvox.ChromeVox.navigationManager.getBraille().write();
291
292   cvox.ChromeVox.navigationManager.updatePosition(targetNode);
293 };
294
295 /**
296  * Get the current node that ChromeVox is on.
297  * @param {number} callbackId The callback Id.
298  */
299 cvox.ApiImplementation.getCurrentNode = function(callbackId) {
300   var currentNode = cvox.ChromeVox.navigationManager.getCurrentNode();
301   cvox.ApiImplementation.port.postMessage(cvox.ChromeVoxJSON.stringify(
302       {
303         'id': callbackId,
304         'currentNode': cvox.ApiUtils.makeNodeReference(currentNode)
305       }));
306 };
307
308 /**
309  * Gets the predefined description set on a node by an api call, if such
310  * a call was made. Otherwise returns the description that the NavigationManager
311  * would speak.
312  * @param {Node} node The node for which to get the description.
313  * @return {Array.<cvox.NavDescription>} The description array.
314  * @private
315  */
316 cvox.ApiImplementation.getDesc_ = function(node) {
317   if (!node.hasAttribute('cvoxnodedesc')) {
318     return cvox.ChromeVox.navigationManager.getDescription();
319   }
320
321   var preDesc = cvox.ChromeVoxJSON.parse(node.getAttribute('cvoxnodedesc'));
322   var currentDesc = new Array();
323   for (var i = 0; i < preDesc.length; ++i) {
324     var inDesc = preDesc[i];
325     // TODO: this can probably be replaced with just NavDescription(inDesc)
326     // need test case to ensure this change will work
327     currentDesc.push(new cvox.NavDescription({
328       context: inDesc.context,
329       text: inDesc.text,
330       userValue: inDesc.userValue,
331       annotation: inDesc.annotation
332     }));
333   }
334   return currentDesc;
335 };
336
337 /**
338  * Simulate a click on an element.
339  *
340  * @param {Object} nodeRef A serializable reference to a node.
341  * @param {boolean} shiftKey Specifies if shift is held down.
342  */
343 cvox.ApiImplementation.clickNodeRef = function(nodeRef, shiftKey) {
344   cvox.DomUtil.clickElem(
345       cvox.ApiUtils.getNodeFromRef(nodeRef), shiftKey, false);
346 };
347
348 /**
349  * Get the ChromeVox build info string.
350  * @param {number} callbackId The callback Id.
351  */
352 cvox.ApiImplementation.getBuild = function(callbackId) {
353   cvox.ApiImplementation.port.postMessage(cvox.ChromeVoxJSON.stringify(
354       {
355         'id': callbackId,
356         'build': cvox.BuildInfo.build
357       }));
358 };
359
360 /**
361  * Get the ChromeVox version.
362  * @param {number} callbackId The callback Id.
363  */
364 cvox.ApiImplementation.getVersion = function(callbackId) {
365   var version = cvox.ChromeVox.version;
366   if (version == null) {
367     window.setTimeout(function() {
368       cvox.ApiImplementation.getVersion(callbackId);
369     }, 1000);
370     return;
371   }
372   cvox.ApiImplementation.port.postMessage(cvox.ChromeVoxJSON.stringify(
373       {
374         'id': callbackId,
375         'version': version
376       }));
377 };
378
379 /**
380  * Get the ChromeVox modifier keys.
381  * @param {number} callbackId The callback Id.
382  */
383 cvox.ApiImplementation.getCvoxModKeys = function(callbackId) {
384   cvox.ApiImplementation.port.postMessage(cvox.ChromeVoxJSON.stringify(
385       {
386         'id': callbackId,
387         'keyCodes': cvox.KeyUtil.cvoxModKeyCodes()
388       }));
389 };
390
391 /**
392  * Return if the keyEvent has a key binding.
393  * @param {number} callbackId The callback Id.
394  * @param {Event} keyEvent A key event.
395  */
396 cvox.ApiImplementation.isKeyShortcut = function(callbackId, keyEvent) {
397   var keySeq = cvox.KeyUtil.keyEventToKeySequence(keyEvent);
398   cvox.ApiImplementation.port.postMessage(cvox.ChromeVoxJSON.stringify(
399       {
400         'id': callbackId,
401         'isHandled': cvox.ChromeVoxKbHandler.handlerKeyMap.hasKey(keySeq)
402       }));
403 };
404
405 /**
406 * Set key echoing on key press.
407 * @param {boolean} keyEcho Whether key echoing should be on or off.
408 */
409 cvox.ApiImplementation.setKeyEcho = function(keyEcho) {
410   var msg = cvox.ChromeVox.keyEcho;
411   msg[document.location.href] = keyEcho;
412   cvox.ChromeVox.host.sendToBackgroundPage({
413   'target': 'Prefs',
414   'action': 'setPref',
415   'pref': 'keyEcho',
416   'value': JSON.stringify(msg)
417   });
418 };
419
420 /**
421  * @constructor
422  */
423 cvox.ApiImplementation.Math = function() {};
424
425 /**
426  * Defines a math speech rule.
427  * @param {string} name Rule name.
428  * @param {string} dynamic Dynamic constraint annotation. In the case of a
429  *      math rule it consists of a domain.style string.
430  * @param {string} action An action of rule components.
431  * @param {string} prec XPath or custom function constraining match.
432  * @param {...string} constraints Additional constraints.
433  */
434 cvox.ApiImplementation.Math.defineRule =
435     function(name, dynamic, action, prec, constraints) {
436   var mathStore = cvox.MathmlStore.getInstance();
437   var constraintList = Array.prototype.slice.call(arguments, 4);
438   var args = [name, dynamic, action, prec].concat(constraintList);
439
440   mathStore.defineRule.apply(mathStore, args);
441 };