Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / third_party / chromevox / extensions / searchvox / results.js
blob405a6ec1bed49d7752a0a3d4ccfe15f23e0b2bdf
1 // Copyright 2012 Google Inc. All Rights Reserved.
3 /**
4 * @fileoverview Provides different rules for each type of result.
5 * @author peterxiao@google.com (Peter Xiao)
6 */
8 goog.provide('cvox.SearchResults');
9 goog.provide('cvox.UnknownResult');
11 goog.require('cvox.AbstractResult');
12 goog.require('cvox.ChromeVox');
13 goog.require('cvox.SearchUtil');
15 /**
16 * @constructor
18 cvox.SearchResults = function() {
21 /**
22 * Speaks a result based on given selectors.
23 * @param {Element} result Search result to be spoken.
24 * @param {Array} selectTexts Array of selectors or text to speak.
26 cvox.SearchResults.speakResultBySelectTexts = function(result, selectTexts) {
27 for (var j = 0; j < selectTexts.length; j++) {
28 var selectText = selectTexts[j];
29 if (selectText.select) {
30 var elems = result.querySelectorAll(selectText.select);
31 for (var i = 0; i < elems.length; i++) {
32 cvox.ChromeVox.speakNode(elems.item(i), 1);
35 if (selectText.text) {
36 cvox.ChromeVox.tts.speak(selectText.text, 1);
41 /**
42 * Unknown Result Type. This is used if we don't know what to do.
43 * @constructor
44 * @extends {cvox.AbstractResult}
46 cvox.UnknownResult = function() {
48 goog.inherits(cvox.UnknownResult, cvox.AbstractResult);
50 /* Normal Result Type. */
51 /**
52 * @constructor
53 * @extends {cvox.AbstractResult}
55 cvox.NormalResult = function() {
57 goog.inherits(cvox.NormalResult, cvox.AbstractResult);
59 /**
60 * Checks the result if it is a normal result.
61 * @param {Element} result Result to be checked.
62 * @return {boolean} Whether or not the element is a normal result.
63 * @override
65 cvox.NormalResult.prototype.isType = function(result) {
66 var NORMAL_SELECT = '.rc';
67 return result.querySelector(NORMAL_SELECT) !== null;
70 /**
71 * Speak a normal search result.
72 * @param {Element} result Normal result to be spoken.
73 * @return {boolean} Whether or not the result was spoken.
74 * @override
76 cvox.NormalResult.prototype.speak = function(result) {
77 if (!result) {
78 return false;
80 var NORMAL_TITLE_SELECT = '.rc .r';
81 var NORMAL_URL_SELECT = '.kv';
82 var NORMAL_DESC_SELECT = '.rc .st';
83 var SITE_LINK_SELECT = '.osl';
84 var MORE_RESULTS_SELECT = '.sld';
85 var MORE_RESULTS_LINK_SELECT = '.mrf';
87 var NORMAL_SELECTORS = [
88 { select: NORMAL_TITLE_SELECT },
89 { select: NORMAL_DESC_SELECT },
90 { select: NORMAL_URL_SELECT },
91 { select: SITE_LINK_SELECT },
92 { select: MORE_RESULTS_SELECT },
93 { select: MORE_RESULTS_LINK_SELECT }];
94 cvox.SearchResults.speakResultBySelectTexts(result, NORMAL_SELECTORS);
96 var DISCUSS_TITLE_SELECT = '.mas-1st-col div';
97 var DISCUSS_DATE_SELECT = '.mas-col div';
98 var discussTitles = result.querySelectorAll(DISCUSS_TITLE_SELECT);
99 var discussDates = result.querySelectorAll(DISCUSS_DATE_SELECT);
100 for (var i = 0; i < discussTitles.length; i++) {
101 cvox.ChromeVox.speakNode(discussTitles.item(i), 1);
102 cvox.ChromeVox.speakNode(discussDates.item(i), 1);
104 return true;
107 /* Weather Result */
109 * @constructor
110 * @extends {cvox.AbstractResult}
112 cvox.WeatherResult = function() {
114 goog.inherits(cvox.WeatherResult, cvox.AbstractResult);
117 * Checks the result if it is a weather result.
118 * @param {Element} result Result to be checked.
119 * @return {boolean} Whether or not the element is a weather result.
120 * @override
122 cvox.WeatherResult.prototype.isType = function(result) {
123 var WEATHER_SELECT = '#wob_wc';
124 return result.querySelector(WEATHER_SELECT) !== null;
128 * Speak a weather forecast.
129 * @param {Element} forecast Weather forecast to be spoken.
131 cvox.WeatherResult.speakForecast = function(forecast) {
132 if (!forecast) {
133 return;
135 var FORE_DAY_SELECT = '.vk_lgy';
136 var FORE_COND_SELECT = 'img';
137 var FORE_HIGH_SELECT = '.vk_gy';
138 var FORE_LOW_SELECT = '.vk_lgy';
140 var FORE_SELECTORS = [
141 { select: FORE_DAY_SELECT },
142 { select: FORE_COND_SELECT },
143 { select: FORE_HIGH_SELECT },
144 { select: FORE_LOW_SELECT }
146 cvox.SearchResults.speakResultBySelectTexts(forecast, FORE_SELECTORS);
150 * Speak a weather search result.
151 * @param {Element} result Weather result to be spoken.
152 * @return {boolean} Whether or not the result was spoken.
153 * @override
155 cvox.WeatherResult.prototype.speak = function(result) {
156 if (!result) {
157 return false;
159 /* TODO(peterxiao): Internationalization? */
160 var WEATHER_INTRO = 'The weather forcast for';
161 var WEATHER_TEMP_UNITS = 'degrees fahrenheit';
162 var WEATHER_PREC_INTRO = 'precipitation is';
163 var WEATHER_HUMID_INTRO = 'humidity is';
164 var WEATHER_WIND_INTRO = 'wind is';
165 var FORE_INTRO = 'Forecasts for this week';
166 var WEATHER_LOC_SELECT = '.vk_h';
167 var WEATHER_WHEN_SELECT = '#wob_dts';
168 var WEATHER_COND_SELECT = '#wob_dc';
169 var WEATHER_TEMP_SELECT = '#wob_tm';
170 var WEATHER_PREC_SELECT = '#wob_pp';
171 var WEATHER_HUMID_SELECT = '#wob_hm';
172 var WEATHER_WIND_SELECT = '#wob_ws';
174 var WEATHER_SELECT_TEXTS = [
175 { text: WEATHER_INTRO },
176 { select: WEATHER_LOC_SELECT },
177 { select: WEATHER_WHEN_SELECT },
178 { select: WEATHER_COND_SELECT },
179 { select: WEATHER_TEMP_SELECT },
180 { text: WEATHER_TEMP_UNITS },
181 { text: WEATHER_PREC_INTRO },
182 { select: WEATHER_PREC_SELECT },
183 { text: WEATHER_HUMID_INTRO },
184 { select: WEATHER_HUMID_SELECT },
185 { text: WEATHER_WIND_INTRO },
186 { select: WEATHER_WIND_SELECT }
188 cvox.SearchResults.speakResultBySelectTexts(result, WEATHER_SELECT_TEXTS);
190 var WEATHER_FORCAST_CLASS = 'wob_df';
191 var forecasts = result.getElementsByClassName(WEATHER_FORCAST_CLASS);
192 cvox.ChromeVox.tts.speak(FORE_INTRO, 1);
193 for (var i = 0; i < forecasts.length; i++) {
194 var forecast = forecasts.item(i);
195 cvox.WeatherResult.speakForecast(forecast);
197 return true;
200 /* Knowledge Panel Result */
202 * @constructor
203 * @extends {cvox.AbstractResult}
205 cvox.KnowResult = function() {
207 goog.inherits(cvox.KnowResult, cvox.AbstractResult);
210 * Checks the result if it is a know result.
211 * @param {Element} result Result to be checked.
212 * @return {boolean} Whether or not the element is a know result.
213 * @override
215 cvox.KnowResult.prototype.isType = function(result) {
216 var KNOP_SELECT = '.kno-ec';
217 return result.querySelector(KNOP_SELECT) !== null;
221 * Speak a knowledge panel search result.
222 * @param {Element} result Knowledge panel result to be spoken.
223 * @return {boolean} Whether or not the result was spoken.
224 * @override
226 cvox.KnowResult.prototype.speak = function(result) {
227 cvox.ChromeVox.speakNode(result, 1);
228 return true;
232 * Extracts the wikipedia URL from knowledge panel.
233 * @param {Element} result Result to extract from.
234 * @return {?string} URL.
235 * @override
237 cvox.KnowResult.prototype.getURL = function(result) {
238 var LINK_SELECTOR = '.q';
239 return cvox.SearchUtil.extractURL(result.querySelector(LINK_SELECTOR));
243 * Extracts the node to sync to in the knowledge panel.
244 * @param {Element} result Result.
245 * @return {?Node} Node to sync to.
246 * @override
248 cvox.KnowResult.prototype.getSyncNode = function(result) {
249 var HEADER_SELECTOR = '.kno-ecr-pt';
250 return result.querySelector(HEADER_SELECTOR);
253 /* Calculator Type */
255 * @constructor
256 * @extends {cvox.AbstractResult}
258 cvox.CalcResult = function() {
260 goog.inherits(cvox.CalcResult, cvox.AbstractResult);
263 * Checks the result if it is a calculator result.
264 * @param {Element} result Result to be checked.
265 * @return {boolean} Whether or not the element is a calculator result.
266 * @override
268 cvox.CalcResult.prototype.isType = function(result) {
269 var CALC_SELECT = '#cwmcwd';
270 return result.querySelector(CALC_SELECT) !== null;
274 * Speak a calculator search result.
275 * @param {Element} result Calculator result to be spoken.
276 * @return {boolean} Whether or not the result was spoken.
277 * @override
279 cvox.CalcResult.prototype.speak = function(result) {
280 if (!result) {
281 return false;
283 var CALC_QUERY_SELECT = '#cwles';
284 var CALC_RESULT_SELECT = '#cwos';
285 var CALC_SELECTORS = [
286 { select: CALC_QUERY_SELECT },
287 { select: CALC_RESULT_SELECT }
289 cvox.SearchResults.speakResultBySelectTexts(result, CALC_SELECTORS);
290 return true;
293 /* Game Type */
295 * @constructor
296 * @extends {cvox.AbstractResult}
298 cvox.GameResult = function() {
300 goog.inherits(cvox.GameResult, cvox.AbstractResult);
303 * Checks the result if it is a game result.
304 * @param {Element} result Result to be checked.
305 * @return {boolean} Whether or not the element is a game result.
306 * @override
308 cvox.GameResult.prototype.isType = function(result) {
309 var GAME_SELECT = '.xpdbox';
310 return result.querySelector(GAME_SELECT) !== null;
313 /* Image Type */
315 * @constructor
316 * @extends {cvox.AbstractResult}
318 cvox.ImageResult = function() {
320 goog.inherits(cvox.ImageResult, cvox.AbstractResult);
323 * Checks the result if it is a image result.
324 * @param {Element} result Result to be checked.
325 * @return {boolean} Whether or not the element is a image result.
326 * @override
328 cvox.ImageResult.prototype.isType = function(result) {
329 var IMAGE_CLASSES = 'rg_di';
330 return result.className === IMAGE_CLASSES;
334 * Speak an image result.
335 * @param {Element} result Image result to be spoken.
336 * @return {boolean} Whether or not the result was spoken.
337 * @override
339 cvox.ImageResult.prototype.speak = function(result) {
340 if (!result) {
341 return false;
343 /* Grab image result metadata. */
344 var META_CLASS = 'rg_meta';
345 var metaDiv = result.querySelector('.' + META_CLASS);
346 var metaJSON = metaDiv.innerHTML;
347 var metaData = JSON.parse(metaJSON);
349 var imageSelectTexts = [];
351 var filename = metaData['fn'];
352 if (filename) {
353 imageSelectTexts.push({ text: filename });
356 var rawDimensions = metaData['is'];
357 if (rawDimensions) {
358 /* Dimensions contain HTML codes, so we convert them. */
359 var tmpDiv = document.createElement('div');
360 tmpDiv.innerHTML = rawDimensions;
361 var dimensions = tmpDiv.textContent || tmpDiv.innerText;
362 imageSelectTexts.push({ text: dimensions });
365 var url = metaData['isu'];
366 if (url) {
367 imageSelectTexts.push({ text: url});
369 cvox.SearchResults.speakResultBySelectTexts(result, imageSelectTexts);
370 return true;
373 /* Category Result */
375 * @constructor
376 * @extends {cvox.AbstractResult}
378 cvox.CategoryResult = function() {
380 goog.inherits(cvox.CategoryResult, cvox.AbstractResult);
383 * Checks the result if it is a category result.
384 * @param {Element} result Result to be checked.
385 * @return {boolean} Whether or not the element is a category result.
386 * @override
388 cvox.CategoryResult.prototype.isType = function(result) {
389 var CATEGORY_CLASSES = 'rg_fbl nj';
390 return result.className === CATEGORY_CLASSES;
394 * Speak a category result.
395 * @param {Element} result Category result to be spoken.
396 * @return {boolean} Whether or not the result was spoken.
397 * @override
399 cvox.CategoryResult.prototype.speak = function(result) {
400 if (!result) {
401 return false;
403 var LABEL_SELECT = '.rg_bb_label';
404 var label = result.querySelector(LABEL_SELECT);
405 cvox.ChromeVox.speakNode(label, 1);
406 return true;
409 /* Ad Result */
411 * @constructor
412 * @extends {cvox.AbstractResult}
414 cvox.AdResult = function() {
416 goog.inherits(cvox.AdResult, cvox.AbstractResult);
419 * Checks the result if it is an ad result.
420 * @param {Element} result Result to be checked.
421 * @return {boolean} Whether or not the element is an ad result.
422 * @override
424 cvox.AdResult.prototype.isType = function(result) {
425 var ADS_CLASS = 'ads-ad';
426 return result.className === ADS_CLASS;
430 * Speak an ad result.
431 * @param {Element} result Ad result to be spoken.
432 * @return {boolean} Whether or not the result was spoken.
433 * @override
435 cvox.AdResult.prototype.speak = function(result) {
436 if (!result) {
437 return false;
439 var HEADER_SELECT = 'h3';
440 var DESC_SELECT = '.ads-creative';
441 var URL_SELECT = '.ads-visurl';
442 var AD_SELECTS = [
443 { select: HEADER_SELECT },
444 { select: DESC_SELECT },
445 { select: URL_SELECT }];
446 cvox.SearchResults.speakResultBySelectTexts(result, AD_SELECTS);
447 return true;
451 * To add new result types, create a new object with the following properties:
452 * isType: Function to indicate if an element is the object's type.
453 * speak: Function that takes in a result and speaks the type to the user.
454 * getURL: Function that takes in a result and extracts the URL to follow.
456 cvox.SearchResults.RESULT_TYPES = [
457 cvox.UnknownResult,
458 cvox.NormalResult,
459 cvox.KnowResult,
460 cvox.WeatherResult,
461 cvox.AdResult,
462 cvox.CalcResult,
463 cvox.GameResult,
464 cvox.ImageResult,
465 cvox.CategoryResult