summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources/chromeos/chromevox/extensions/searchvox/results.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/resources/chromeos/chromevox/extensions/searchvox/results.js')
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/extensions/searchvox/results.js468
1 files changed, 468 insertions, 0 deletions
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/extensions/searchvox/results.js b/chromium/chrome/browser/resources/chromeos/chromevox/extensions/searchvox/results.js
new file mode 100644
index 00000000000..367220603a4
--- /dev/null
+++ b/chromium/chrome/browser/resources/chromeos/chromevox/extensions/searchvox/results.js
@@ -0,0 +1,468 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+/**
+ * @fileoverview Provides different rules for each type of result.
+ */
+
+goog.provide('cvox.SearchResults');
+goog.provide('cvox.UnknownResult');
+
+goog.require('cvox.AbstractResult');
+goog.require('cvox.ChromeVox');
+goog.require('cvox.SearchUtil');
+
+/**
+ * @constructor
+ */
+cvox.SearchResults = function() {
+};
+
+/**
+ * Speaks a result based on given selectors.
+ * @param {Element} result Search result to be spoken.
+ * @param {Array} selectTexts Array of selectors or text to speak.
+ */
+cvox.SearchResults.speakResultBySelectTexts = function(result, selectTexts) {
+ for (var j = 0; j < selectTexts.length; j++) {
+ var selectText = selectTexts[j];
+ if (selectText.select) {
+ var elems = result.querySelectorAll(selectText.select);
+ for (var i = 0; i < elems.length; i++) {
+ cvox.ChromeVox.speakNode(elems.item(i), 1);
+ }
+ }
+ if (selectText.text) {
+ cvox.ChromeVox.tts.speak(selectText.text, 1);
+ }
+ }
+};
+
+/**
+ * Unknown Result Type. This is used if we don't know what to do.
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.UnknownResult = function() {
+};
+goog.inherits(cvox.UnknownResult, cvox.AbstractResult);
+
+/* Normal Result Type. */
+/**
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.NormalResult = function() {
+};
+goog.inherits(cvox.NormalResult, cvox.AbstractResult);
+
+/**
+ * Checks the result if it is a normal result.
+ * @param {Element} result Result to be checked.
+ * @return {boolean} Whether or not the element is a normal result.
+ * @override
+ */
+cvox.NormalResult.prototype.isType = function(result) {
+ var NORMAL_SELECT = '.rc';
+ return result.querySelector(NORMAL_SELECT) !== null;
+};
+
+/**
+ * Speak a normal search result.
+ * @param {Element} result Normal result to be spoken.
+ * @return {boolean} Whether or not the result was spoken.
+ * @override
+ */
+cvox.NormalResult.prototype.speak = function(result) {
+ if (!result) {
+ return false;
+ }
+ var NORMAL_TITLE_SELECT = '.rc .r';
+ var NORMAL_URL_SELECT = '.kv';
+ var NORMAL_DESC_SELECT = '.rc .st';
+ var SITE_LINK_SELECT = '.osl';
+ var MORE_RESULTS_SELECT = '.sld';
+ var MORE_RESULTS_LINK_SELECT = '.mrf';
+
+ var NORMAL_SELECTORS = [
+ { select: NORMAL_TITLE_SELECT },
+ { select: NORMAL_DESC_SELECT },
+ { select: NORMAL_URL_SELECT },
+ { select: SITE_LINK_SELECT },
+ { select: MORE_RESULTS_SELECT },
+ { select: MORE_RESULTS_LINK_SELECT }];
+ cvox.SearchResults.speakResultBySelectTexts(result, NORMAL_SELECTORS);
+
+ var DISCUSS_TITLE_SELECT = '.mas-1st-col div';
+ var DISCUSS_DATE_SELECT = '.mas-col div';
+ var discussTitles = result.querySelectorAll(DISCUSS_TITLE_SELECT);
+ var discussDates = result.querySelectorAll(DISCUSS_DATE_SELECT);
+ for (var i = 0; i < discussTitles.length; i++) {
+ cvox.ChromeVox.speakNode(discussTitles.item(i), 1);
+ cvox.ChromeVox.speakNode(discussDates.item(i), 1);
+ }
+ return true;
+};
+
+/* Weather Result */
+/**
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.WeatherResult = function() {
+};
+goog.inherits(cvox.WeatherResult, cvox.AbstractResult);
+
+/**
+ * Checks the result if it is a weather result.
+ * @param {Element} result Result to be checked.
+ * @return {boolean} Whether or not the element is a weather result.
+ * @override
+ */
+cvox.WeatherResult.prototype.isType = function(result) {
+ var WEATHER_SELECT = '#wob_wc';
+ return result.querySelector(WEATHER_SELECT) !== null;
+};
+
+/**
+ * Speak a weather forecast.
+ * @param {Element} forecast Weather forecast to be spoken.
+ */
+cvox.WeatherResult.speakForecast = function(forecast) {
+ if (!forecast) {
+ return;
+ }
+ var FORE_DAY_SELECT = '.vk_lgy';
+ var FORE_COND_SELECT = 'img';
+ var FORE_HIGH_SELECT = '.vk_gy';
+ var FORE_LOW_SELECT = '.vk_lgy';
+
+ var FORE_SELECTORS = [
+ { select: FORE_DAY_SELECT },
+ { select: FORE_COND_SELECT },
+ { select: FORE_HIGH_SELECT },
+ { select: FORE_LOW_SELECT }
+ ];
+ cvox.SearchResults.speakResultBySelectTexts(forecast, FORE_SELECTORS);
+};
+
+/**
+ * Speak a weather search result.
+ * @param {Element} result Weather result to be spoken.
+ * @return {boolean} Whether or not the result was spoken.
+ * @override
+ */
+cvox.WeatherResult.prototype.speak = function(result) {
+ if (!result) {
+ return false;
+ }
+ /* TODO(peterxiao): Internationalization? */
+ var WEATHER_INTRO = 'The weather forcast for';
+ var WEATHER_TEMP_UNITS = 'degrees fahrenheit';
+ var WEATHER_PREC_INTRO = 'precipitation is';
+ var WEATHER_HUMID_INTRO = 'humidity is';
+ var WEATHER_WIND_INTRO = 'wind is';
+ var FORE_INTRO = 'Forecasts for this week';
+ var WEATHER_LOC_SELECT = '.vk_h';
+ var WEATHER_WHEN_SELECT = '#wob_dts';
+ var WEATHER_COND_SELECT = '#wob_dc';
+ var WEATHER_TEMP_SELECT = '#wob_tm';
+ var WEATHER_PREC_SELECT = '#wob_pp';
+ var WEATHER_HUMID_SELECT = '#wob_hm';
+ var WEATHER_WIND_SELECT = '#wob_ws';
+
+ var WEATHER_SELECT_TEXTS = [
+ { text: WEATHER_INTRO },
+ { select: WEATHER_LOC_SELECT },
+ { select: WEATHER_WHEN_SELECT },
+ { select: WEATHER_COND_SELECT },
+ { select: WEATHER_TEMP_SELECT },
+ { text: WEATHER_TEMP_UNITS },
+ { text: WEATHER_PREC_INTRO },
+ { select: WEATHER_PREC_SELECT },
+ { text: WEATHER_HUMID_INTRO },
+ { select: WEATHER_HUMID_SELECT },
+ { text: WEATHER_WIND_INTRO },
+ { select: WEATHER_WIND_SELECT }
+ ];
+ cvox.SearchResults.speakResultBySelectTexts(result, WEATHER_SELECT_TEXTS);
+
+ var WEATHER_FORCAST_CLASS = 'wob_df';
+ var forecasts = result.getElementsByClassName(WEATHER_FORCAST_CLASS);
+ cvox.ChromeVox.tts.speak(FORE_INTRO, 1);
+ for (var i = 0; i < forecasts.length; i++) {
+ var forecast = forecasts.item(i);
+ cvox.WeatherResult.speakForecast(forecast);
+ }
+ return true;
+};
+
+/* Knowledge Panel Result */
+/**
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.KnowResult = function() {
+};
+goog.inherits(cvox.KnowResult, cvox.AbstractResult);
+
+/**
+ * Checks the result if it is a know result.
+ * @param {Element} result Result to be checked.
+ * @return {boolean} Whether or not the element is a know result.
+ * @override
+ */
+cvox.KnowResult.prototype.isType = function(result) {
+ var KNOP_SELECT = '.kno-ec';
+ return result.querySelector(KNOP_SELECT) !== null;
+};
+
+/**
+ * Speak a knowledge panel search result.
+ * @param {Element} result Knowledge panel result to be spoken.
+ * @return {boolean} Whether or not the result was spoken.
+ * @override
+ */
+cvox.KnowResult.prototype.speak = function(result) {
+ cvox.ChromeVox.speakNode(result, 1);
+ return true;
+};
+
+/**
+ * Extracts the wikipedia URL from knowledge panel.
+ * @param {Element} result Result to extract from.
+ * @return {?string} URL.
+ * @override
+ */
+cvox.KnowResult.prototype.getURL = function(result) {
+ var LINK_SELECTOR = '.q';
+ return cvox.SearchUtil.extractURL(result.querySelector(LINK_SELECTOR));
+};
+
+/**
+ * Extracts the node to sync to in the knowledge panel.
+ * @param {Element} result Result.
+ * @return {?Node} Node to sync to.
+ * @override
+ */
+cvox.KnowResult.prototype.getSyncNode = function(result) {
+ var HEADER_SELECTOR = '.kno-ecr-pt';
+ return result.querySelector(HEADER_SELECTOR);
+};
+
+/* Calculator Type */
+/**
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.CalcResult = function() {
+};
+goog.inherits(cvox.CalcResult, cvox.AbstractResult);
+
+/**
+ * Checks the result if it is a calculator result.
+ * @param {Element} result Result to be checked.
+ * @return {boolean} Whether or not the element is a calculator result.
+ * @override
+ */
+cvox.CalcResult.prototype.isType = function(result) {
+ var CALC_SELECT = '#cwmcwd';
+ return result.querySelector(CALC_SELECT) !== null;
+};
+
+/**
+ * Speak a calculator search result.
+ * @param {Element} result Calculator result to be spoken.
+ * @return {boolean} Whether or not the result was spoken.
+ * @override
+ */
+cvox.CalcResult.prototype.speak = function(result) {
+ if (!result) {
+ return false;
+ }
+ var CALC_QUERY_SELECT = '#cwles';
+ var CALC_RESULT_SELECT = '#cwos';
+ var CALC_SELECTORS = [
+ { select: CALC_QUERY_SELECT },
+ { select: CALC_RESULT_SELECT }
+ ];
+ cvox.SearchResults.speakResultBySelectTexts(result, CALC_SELECTORS);
+ return true;
+};
+
+/* Game Type */
+/**
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.GameResult = function() {
+};
+goog.inherits(cvox.GameResult, cvox.AbstractResult);
+
+/**
+ * Checks the result if it is a game result.
+ * @param {Element} result Result to be checked.
+ * @return {boolean} Whether or not the element is a game result.
+ * @override
+ */
+cvox.GameResult.prototype.isType = function(result) {
+ var GAME_SELECT = '.xpdbox';
+ return result.querySelector(GAME_SELECT) !== null;
+};
+
+/* Image Type */
+/**
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.ImageResult = function() {
+};
+goog.inherits(cvox.ImageResult, cvox.AbstractResult);
+
+/**
+ * Checks the result if it is a image result.
+ * @param {Element} result Result to be checked.
+ * @return {boolean} Whether or not the element is a image result.
+ * @override
+ */
+cvox.ImageResult.prototype.isType = function(result) {
+ var IMAGE_CLASSES = 'rg_di';
+ return result.className === IMAGE_CLASSES;
+};
+
+/**
+ * Speak an image result.
+ * @param {Element} result Image result to be spoken.
+ * @return {boolean} Whether or not the result was spoken.
+ * @override
+ */
+cvox.ImageResult.prototype.speak = function(result) {
+ if (!result) {
+ return false;
+ }
+ /* Grab image result metadata. */
+ var META_CLASS = 'rg_meta';
+ var metaDiv = result.querySelector('.' + META_CLASS);
+ var metaJSON = metaDiv.innerHTML;
+ var metaData = JSON.parse(metaJSON);
+
+ var imageSelectTexts = [];
+
+ var filename = metaData['fn'];
+ if (filename) {
+ imageSelectTexts.push({ text: filename });
+ }
+
+ var rawDimensions = metaData['is'];
+ if (rawDimensions) {
+ /* Dimensions contain HTML codes, so we convert them. */
+ var tmpDiv = document.createElement('div');
+ tmpDiv.innerHTML = rawDimensions;
+ var dimensions = tmpDiv.textContent || tmpDiv.innerText;
+ imageSelectTexts.push({ text: dimensions });
+ }
+
+ var url = metaData['isu'];
+ if (url) {
+ imageSelectTexts.push({ text: url});
+ }
+ cvox.SearchResults.speakResultBySelectTexts(result, imageSelectTexts);
+ return true;
+};
+
+/* Category Result */
+/**
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.CategoryResult = function() {
+};
+goog.inherits(cvox.CategoryResult, cvox.AbstractResult);
+
+/**
+ * Checks the result if it is a category result.
+ * @param {Element} result Result to be checked.
+ * @return {boolean} Whether or not the element is a category result.
+ * @override
+ */
+cvox.CategoryResult.prototype.isType = function(result) {
+ var CATEGORY_CLASSES = 'rg_fbl nj';
+ return result.className === CATEGORY_CLASSES;
+};
+
+/**
+ * Speak a category result.
+ * @param {Element} result Category result to be spoken.
+ * @return {boolean} Whether or not the result was spoken.
+ * @override
+ */
+cvox.CategoryResult.prototype.speak = function(result) {
+ if (!result) {
+ return false;
+ }
+ var LABEL_SELECT = '.rg_bb_label';
+ var label = result.querySelector(LABEL_SELECT);
+ cvox.ChromeVox.speakNode(label, 1);
+ return true;
+};
+
+/* Ad Result */
+/**
+ * @constructor
+ * @extends {cvox.AbstractResult}
+ */
+cvox.AdResult = function() {
+};
+goog.inherits(cvox.AdResult, cvox.AbstractResult);
+
+/**
+ * Checks the result if it is an ad result.
+ * @param {Element} result Result to be checked.
+ * @return {boolean} Whether or not the element is an ad result.
+ * @override
+ */
+cvox.AdResult.prototype.isType = function(result) {
+ var ADS_CLASS = 'ads-ad';
+ return result.className === ADS_CLASS;
+};
+
+/**
+ * Speak an ad result.
+ * @param {Element} result Ad result to be spoken.
+ * @return {boolean} Whether or not the result was spoken.
+ * @override
+ */
+cvox.AdResult.prototype.speak = function(result) {
+ if (!result) {
+ return false;
+ }
+ var HEADER_SELECT = 'h3';
+ var DESC_SELECT = '.ads-creative';
+ var URL_SELECT = '.ads-visurl';
+ var AD_SELECTS = [
+ { select: HEADER_SELECT },
+ { select: DESC_SELECT },
+ { select: URL_SELECT }];
+ cvox.SearchResults.speakResultBySelectTexts(result, AD_SELECTS);
+ return true;
+};
+
+/**
+ * To add new result types, create a new object with the following properties:
+ * isType: Function to indicate if an element is the object's type.
+ * speak: Function that takes in a result and speaks the type to the user.
+ * getURL: Function that takes in a result and extracts the URL to follow.
+ */
+cvox.SearchResults.RESULT_TYPES = [
+ cvox.UnknownResult,
+ cvox.NormalResult,
+ cvox.KnowResult,
+ cvox.WeatherResult,
+ cvox.AdResult,
+ cvox.CalcResult,
+ cvox.GameResult,
+ cvox.ImageResult,
+ cvox.CategoryResult
+];