[Extensions] Make extension message bubble factory platform-abstract
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / chromevox / extensions / searchvox / results.js
blobdb2799e90cfbaa21bca71ff62f271e005a282a58
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.
6 /**
7 * @fileoverview Provides different rules for each type of result.
8 */
10 goog.provide('cvox.SearchResults');
11 goog.provide('cvox.UnknownResult');
13 goog.require('cvox.AbstractResult');
14 goog.require('cvox.ChromeVox');
15 goog.require('cvox.SearchUtil');
17 /**
18 * @constructor
20 cvox.SearchResults = function() {
23 /**
24 * Speaks a result based on given selectors.
25 * @param {Element} result Search result to be spoken.
26 * @param {Array} selectTexts Array of selectors or text to speak.
28 cvox.SearchResults.speakResultBySelectTexts = function(result, selectTexts) {
29 for (var j = 0; j < selectTexts.length; j++) {
30 var selectText = selectTexts[j];
31 if (selectText.select) {
32 var elems = result.querySelectorAll(selectText.select);
33 for (var i = 0; i < elems.length; i++) {
34 cvox.ChromeVox.speakNode(elems.item(i), cvox.QueueMode.QUEUE);
37 if (selectText.text) {
38 cvox.ChromeVox.tts.speak(selectText.text, cvox.QueueMode.QUEUE);
43 /**
44 * Unknown Result Type. This is used if we don't know what to do.
45 * @constructor
46 * @extends {cvox.AbstractResult}
48 cvox.UnknownResult = function() {
50 goog.inherits(cvox.UnknownResult, cvox.AbstractResult);
52 /* Normal Result Type. */
53 /**
54 * @constructor
55 * @extends {cvox.AbstractResult}
57 cvox.NormalResult = function() {
59 goog.inherits(cvox.NormalResult, cvox.AbstractResult);
61 /**
62 * Checks the result if it is a normal result.
63 * @param {Element} result Result to be checked.
64 * @return {boolean} Whether or not the element is a normal result.
65 * @override
67 cvox.NormalResult.prototype.isType = function(result) {
68 var NORMAL_SELECT = '.rc';
69 return result.querySelector(NORMAL_SELECT) !== null;
72 /**
73 * Speak a normal search result.
74 * @param {Element} result Normal result to be spoken.
75 * @return {boolean} Whether or not the result was spoken.
76 * @override
78 cvox.NormalResult.prototype.speak = function(result) {
79 if (!result) {
80 return false;
82 var NORMAL_TITLE_SELECT = '.rc .r';
83 var NORMAL_URL_SELECT = '.kv';
84 var NORMAL_DESC_SELECT = '.rc .st';
85 var SITE_LINK_SELECT = '.osl';
86 var MORE_RESULTS_SELECT = '.sld';
87 var MORE_RESULTS_LINK_SELECT = '.mrf';
89 var NORMAL_SELECTORS = [
90 { select: NORMAL_TITLE_SELECT },
91 { select: NORMAL_DESC_SELECT },
92 { select: NORMAL_URL_SELECT },
93 { select: SITE_LINK_SELECT },
94 { select: MORE_RESULTS_SELECT },
95 { select: MORE_RESULTS_LINK_SELECT }];
96 cvox.SearchResults.speakResultBySelectTexts(result, NORMAL_SELECTORS);
98 var DISCUSS_TITLE_SELECT = '.mas-1st-col div';
99 var DISCUSS_DATE_SELECT = '.mas-col div';
100 var discussTitles = result.querySelectorAll(DISCUSS_TITLE_SELECT);
101 var discussDates = result.querySelectorAll(DISCUSS_DATE_SELECT);
102 for (var i = 0; i < discussTitles.length; i++) {
103 cvox.ChromeVox.speakNode(discussTitles.item(i), cvox.QueueMode.QUEUE);
104 cvox.ChromeVox.speakNode(discussDates.item(i), cvox.QueueMode.QUEUE);
106 return true;
109 /* Weather Result */
111 * @constructor
112 * @extends {cvox.AbstractResult}
114 cvox.WeatherResult = function() {
116 goog.inherits(cvox.WeatherResult, cvox.AbstractResult);
119 * Checks the result if it is a weather result.
120 * @param {Element} result Result to be checked.
121 * @return {boolean} Whether or not the element is a weather result.
122 * @override
124 cvox.WeatherResult.prototype.isType = function(result) {
125 var WEATHER_SELECT = '#wob_wc';
126 return result.querySelector(WEATHER_SELECT) !== null;
130 * Speak a weather forecast.
131 * @param {Element} forecast Weather forecast to be spoken.
133 cvox.WeatherResult.speakForecast = function(forecast) {
134 if (!forecast) {
135 return;
137 var FORE_DAY_SELECT = '.vk_lgy';
138 var FORE_COND_SELECT = 'img';
139 var FORE_HIGH_SELECT = '.vk_gy';
140 var FORE_LOW_SELECT = '.vk_lgy';
142 var FORE_SELECTORS = [
143 { select: FORE_DAY_SELECT },
144 { select: FORE_COND_SELECT },
145 { select: FORE_HIGH_SELECT },
146 { select: FORE_LOW_SELECT }
148 cvox.SearchResults.speakResultBySelectTexts(forecast, FORE_SELECTORS);
152 * Speak a weather search result.
153 * @param {Element} result Weather result to be spoken.
154 * @return {boolean} Whether or not the result was spoken.
155 * @override
157 cvox.WeatherResult.prototype.speak = function(result) {
158 if (!result) {
159 return false;
161 /* TODO(peterxiao): Internationalization? */
162 var WEATHER_INTRO = 'The weather forcast for';
163 var WEATHER_TEMP_UNITS = 'degrees fahrenheit';
164 var WEATHER_PREC_INTRO = 'precipitation is';
165 var WEATHER_HUMID_INTRO = 'humidity is';
166 var WEATHER_WIND_INTRO = 'wind is';
167 var FORE_INTRO = 'Forecasts for this week';
168 var WEATHER_LOC_SELECT = '.vk_h';
169 var WEATHER_WHEN_SELECT = '#wob_dts';
170 var WEATHER_COND_SELECT = '#wob_dc';
171 var WEATHER_TEMP_SELECT = '#wob_tm';
172 var WEATHER_PREC_SELECT = '#wob_pp';
173 var WEATHER_HUMID_SELECT = '#wob_hm';
174 var WEATHER_WIND_SELECT = '#wob_ws';
176 var WEATHER_SELECT_TEXTS = [
177 { text: WEATHER_INTRO },
178 { select: WEATHER_LOC_SELECT },
179 { select: WEATHER_WHEN_SELECT },
180 { select: WEATHER_COND_SELECT },
181 { select: WEATHER_TEMP_SELECT },
182 { text: WEATHER_TEMP_UNITS },
183 { text: WEATHER_PREC_INTRO },
184 { select: WEATHER_PREC_SELECT },
185 { text: WEATHER_HUMID_INTRO },
186 { select: WEATHER_HUMID_SELECT },
187 { text: WEATHER_WIND_INTRO },
188 { select: WEATHER_WIND_SELECT }
190 cvox.SearchResults.speakResultBySelectTexts(result, WEATHER_SELECT_TEXTS);
192 var WEATHER_FORCAST_CLASS = 'wob_df';
193 var forecasts = result.getElementsByClassName(WEATHER_FORCAST_CLASS);
194 cvox.ChromeVox.tts.speak(FORE_INTRO, cvox.QueueMode.QUEUE);
195 for (var i = 0; i < forecasts.length; i++) {
196 var forecast = forecasts.item(i);
197 cvox.WeatherResult.speakForecast(forecast);
199 return true;
202 /* Knowledge Panel Result */
204 * @constructor
205 * @extends {cvox.AbstractResult}
207 cvox.KnowResult = function() {
209 goog.inherits(cvox.KnowResult, cvox.AbstractResult);
212 * Checks the result if it is a know result.
213 * @param {Element} result Result to be checked.
214 * @return {boolean} Whether or not the element is a know result.
215 * @override
217 cvox.KnowResult.prototype.isType = function(result) {
218 var KNOP_SELECT = '.kno-ec';
219 return result.querySelector(KNOP_SELECT) !== null;
223 * Speak a knowledge panel search result.
224 * @param {Element} result Knowledge panel result to be spoken.
225 * @return {boolean} Whether or not the result was spoken.
226 * @override
228 cvox.KnowResult.prototype.speak = function(result) {
229 cvox.ChromeVox.speakNode(result, cvox.QueueMode.QUEUE);
230 return true;
234 * Extracts the wikipedia URL from knowledge panel.
235 * @param {Element} result Result to extract from.
236 * @return {?string} URL.
237 * @override
239 cvox.KnowResult.prototype.getURL = function(result) {
240 var LINK_SELECTOR = '.q';
241 return cvox.SearchUtil.extractURL(result.querySelector(LINK_SELECTOR));
245 * Extracts the node to sync to in the knowledge panel.
246 * @param {Element} result Result.
247 * @return {?Node} Node to sync to.
248 * @override
250 cvox.KnowResult.prototype.getSyncNode = function(result) {
251 var HEADER_SELECTOR = '.kno-ecr-pt';
252 return result.querySelector(HEADER_SELECTOR);
255 /* Calculator Type */
257 * @constructor
258 * @extends {cvox.AbstractResult}
260 cvox.CalcResult = function() {
262 goog.inherits(cvox.CalcResult, cvox.AbstractResult);
265 * Checks the result if it is a calculator result.
266 * @param {Element} result Result to be checked.
267 * @return {boolean} Whether or not the element is a calculator result.
268 * @override
270 cvox.CalcResult.prototype.isType = function(result) {
271 var CALC_SELECT = '#cwmcwd';
272 return result.querySelector(CALC_SELECT) !== null;
276 * Speak a calculator search result.
277 * @param {Element} result Calculator result to be spoken.
278 * @return {boolean} Whether or not the result was spoken.
279 * @override
281 cvox.CalcResult.prototype.speak = function(result) {
282 if (!result) {
283 return false;
285 var CALC_QUERY_SELECT = '#cwles';
286 var CALC_RESULT_SELECT = '#cwos';
287 var CALC_SELECTORS = [
288 { select: CALC_QUERY_SELECT },
289 { select: CALC_RESULT_SELECT }
291 cvox.SearchResults.speakResultBySelectTexts(result, CALC_SELECTORS);
292 return true;
295 /* Game Type */
297 * @constructor
298 * @extends {cvox.AbstractResult}
300 cvox.GameResult = function() {
302 goog.inherits(cvox.GameResult, cvox.AbstractResult);
305 * Checks the result if it is a game result.
306 * @param {Element} result Result to be checked.
307 * @return {boolean} Whether or not the element is a game result.
308 * @override
310 cvox.GameResult.prototype.isType = function(result) {
311 var GAME_SELECT = '.xpdbox';
312 return result.querySelector(GAME_SELECT) !== null;
315 /* Image Type */
317 * @constructor
318 * @extends {cvox.AbstractResult}
320 cvox.ImageResult = function() {
322 goog.inherits(cvox.ImageResult, cvox.AbstractResult);
325 * Checks the result if it is a image result.
326 * @param {Element} result Result to be checked.
327 * @return {boolean} Whether or not the element is a image result.
328 * @override
330 cvox.ImageResult.prototype.isType = function(result) {
331 var IMAGE_CLASSES = 'rg_di';
332 return result.className === IMAGE_CLASSES;
336 * Speak an image result.
337 * @param {Element} result Image result to be spoken.
338 * @return {boolean} Whether or not the result was spoken.
339 * @override
341 cvox.ImageResult.prototype.speak = function(result) {
342 if (!result) {
343 return false;
345 /* Grab image result metadata. */
346 var META_CLASS = 'rg_meta';
347 var metaDiv = result.querySelector('.' + META_CLASS);
348 var metaJSON = metaDiv.innerHTML;
349 var metaData = JSON.parse(metaJSON);
351 var imageSelectTexts = [];
353 var filename = metaData['fn'];
354 if (filename) {
355 imageSelectTexts.push({ text: filename });
358 var rawDimensions = metaData['is'];
359 if (rawDimensions) {
360 /* Dimensions contain HTML codes, so we convert them. */
361 var tmpDiv = document.createElement('div');
362 tmpDiv.innerHTML = rawDimensions;
363 var dimensions = tmpDiv.textContent || tmpDiv.innerText;
364 imageSelectTexts.push({ text: dimensions });
367 var url = metaData['isu'];
368 if (url) {
369 imageSelectTexts.push({ text: url});
371 cvox.SearchResults.speakResultBySelectTexts(result, imageSelectTexts);
372 return true;
375 /* Category Result */
377 * @constructor
378 * @extends {cvox.AbstractResult}
380 cvox.CategoryResult = function() {
382 goog.inherits(cvox.CategoryResult, cvox.AbstractResult);
385 * Checks the result if it is a category result.
386 * @param {Element} result Result to be checked.
387 * @return {boolean} Whether or not the element is a category result.
388 * @override
390 cvox.CategoryResult.prototype.isType = function(result) {
391 var CATEGORY_CLASSES = 'rg_fbl nj';
392 return result.className === CATEGORY_CLASSES;
396 * Speak a category result.
397 * @param {Element} result Category result to be spoken.
398 * @return {boolean} Whether or not the result was spoken.
399 * @override
401 cvox.CategoryResult.prototype.speak = function(result) {
402 if (!result) {
403 return false;
405 var LABEL_SELECT = '.rg_bb_label';
406 var label = result.querySelector(LABEL_SELECT);
407 cvox.ChromeVox.speakNode(label, cvox.QueueMode.QUEUE);
408 return true;
411 /* Ad Result */
413 * @constructor
414 * @extends {cvox.AbstractResult}
416 cvox.AdResult = function() {
418 goog.inherits(cvox.AdResult, cvox.AbstractResult);
421 * Checks the result if it is an ad result.
422 * @param {Element} result Result to be checked.
423 * @return {boolean} Whether or not the element is an ad result.
424 * @override
426 cvox.AdResult.prototype.isType = function(result) {
427 var ADS_CLASS = 'ads-ad';
428 return result.className === ADS_CLASS;
432 * Speak an ad result.
433 * @param {Element} result Ad result to be spoken.
434 * @return {boolean} Whether or not the result was spoken.
435 * @override
437 cvox.AdResult.prototype.speak = function(result) {
438 if (!result) {
439 return false;
441 var HEADER_SELECT = 'h3';
442 var DESC_SELECT = '.ads-creative';
443 var URL_SELECT = '.ads-visurl';
444 var AD_SELECTS = [
445 { select: HEADER_SELECT },
446 { select: DESC_SELECT },
447 { select: URL_SELECT }];
448 cvox.SearchResults.speakResultBySelectTexts(result, AD_SELECTS);
449 return true;
453 * To add new result types, create a new object with the following properties:
454 * isType: Function to indicate if an element is the object's type.
455 * speak: Function that takes in a result and speaks the type to the user.
456 * getURL: Function that takes in a result and extracts the URL to follow.
458 cvox.SearchResults.RESULT_TYPES = [
459 cvox.UnknownResult,
460 cvox.NormalResult,
461 cvox.KnowResult,
462 cvox.WeatherResult,
463 cvox.AdResult,
464 cvox.CalcResult,
465 cvox.GameResult,
466 cvox.ImageResult,
467 cvox.CategoryResult