• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2012 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 * Javascript for suggestions_internals.html, served from
7 * chrome://suggestions-internals/. This is used to debug suggestions ranking.
8 * When loaded, the page will show the current set of suggestions, along with a
9 * large set of information (e.g. all the signals that were taken into
10 * consideration for deciding which pages were selected to be shown to the user)
11 * that will aid in debugging and optimizing the algorithms.
12 */
13cr.define('suggestionsInternals', function() {
14  'use strict';
15
16  /**
17   * Register our event handlers.
18   */
19  function initialize() {
20    $('suggestions-form').addEventListener('submit', onRefreshClicked);
21    $('show-discarded').addEventListener('change', refresh);
22    refresh();
23  }
24
25  /**
26   * Called when the 'Refresh' button is clicked. Reloads the suggestions data.
27   */
28  function onRefreshClicked(event) {
29    refresh();
30    event.preventDefault();
31  }
32
33  /**
34   * Reloads the suggestions data by sending a 'getSuggestions' message to
35   * Chrome. The C++ code is then expected to call 'setSuggestions' when there
36   * are suggestions ready.
37   */
38  function refresh() {
39    chrome.send('getSuggestions');
40  }
41
42  /**
43   * A list of columns that we do not want to display.
44   * @type {Array.<string>}
45   * @const
46   */
47  var IGNORED_COLUMNS = [
48    'direction'
49  ];
50
51  /**
52   * A list specifying the name of the first columns to be displayed. If
53   * present, they will be displayed in this order, followed by the remaining
54   * columns.
55   * @type {Array.<string>}
56   * @const
57   */
58  var PREFERRED_COLUMN_ORDER = [
59    'title',
60    'url',
61    'score'
62  ];
63
64  function setBooleanColumn(column, value) {
65    if (value) {
66      column.innerText = 'Y';
67      column.classList.add('boolean-property-true');
68    } else {
69      column.innerText = 'N';
70      column.classList.add('boolean-property-false');
71    }
72  }
73
74  /**
75   * Called by Chrome code, with a ranked list of suggestions. The columns
76   * to be displayed are calculated automatically from the properties of the
77   * elements in the list, such that all properties have a column.
78   */
79  function setSuggestions(list) {
80    // Build a list of all the columns that will be displayed.
81    var columns = [];
82    list.forEach(function(entry) {
83      for (var column in entry) {
84        if (typeof entry[column] == 'object') {
85          // Expand one level deep
86          for (var subColumn in entry[column]) {
87            var path = column + '.' + subColumn;
88            if (columns.indexOf(path) < 0)
89              columns.push(path);
90          }
91        } else if (columns.indexOf(column) < 0) {
92          columns.push(column);
93        }
94      }
95    });
96
97    // Remove columns that we don't want to display.
98    columns = columns.filter(function(column) {
99      return IGNORED_COLUMNS.indexOf(column) < 0;
100    });
101
102    // Move the preferred columns to the start of the column list.
103    for (var i = PREFERRED_COLUMN_ORDER.length - 1; i >= 0; i--) {
104      var index = columns.indexOf(PREFERRED_COLUMN_ORDER[i]);
105      if (index >= 0)
106        columns.unshift(columns.splice(index, 1)[0]);
107    }
108
109    // Special columns.
110    columns.unshift('favicon');
111    columns.unshift('screenshot');
112    columns.unshift('rank');
113
114    // Erase whatever is currently being displayed.
115    var output = $('suggestions-debug-text');
116    output.innerHTML = '';
117
118    // Create the container table and add the header row.
119    var table = document.createElement('table');
120    table.className = 'suggestions-debug-table';
121    var header = document.createElement('tr');
122    columns.forEach(function(entry) {
123      var column = document.createElement('th');
124      column.innerText = entry;
125      header.appendChild(column);
126    });
127    table.appendChild(header);
128
129    // Add all the suggestions to the table.
130    var rank = 1;
131    list.forEach(function(entry) {
132      var row = document.createElement('tr');
133      columns.forEach(function(columnName) {
134        var column = document.createElement('td');
135        // Expand the path and find the data if it's there.
136        var path = columnName.split('.');
137        var data = entry;
138        for (var i = 0; i < path.length; ++i) {
139          if (data && data.hasOwnProperty(path[i]))
140            data = data[path[i]];
141          else
142            data = undefined;
143        }
144        // Only add the column if the current suggestion has this property
145        // (otherwise, leave the cell empty).
146        if (typeof(data) != 'undefined') {
147          if (typeof(data) == 'boolean') {
148            setBooleanColumn(column, data);
149          } else if (/^https?:\/\/.+$/.test(data)) {
150            // If the text is a URL, make it an anchor element.
151            var anchor = document.createElement('a');
152            anchor.href = data;
153            anchor.innerText = data;
154            column.appendChild(anchor);
155          } else {
156            column.innerText = data;
157          }
158        } else if (columnName == 'rank') {
159          column.innerText = rank++;
160        } else if (columnName == 'screenshot') {
161          var thumbnailUrl = 'chrome://thumb/' + entry.url;
162          var img = document.createElement('img');
163          img.onload = function() { setBooleanColumn(column, true); }
164          img.onerror = function() { setBooleanColumn(column, false); }
165          img.src = thumbnailUrl;
166        } else if (columnName == 'favicon') {
167          var faviconUrl = 'chrome://favicon/size/16@1x/' + entry.url;
168          column.style.backgroundImage = url(faviconUrl);
169          column.style.backgroundRepeat = 'no-repeat';
170          column.style.backgroundPosition = 'center center';
171        }
172        row.appendChild(column);
173      });
174      table.appendChild(row);
175    });
176
177    output.appendChild(table);
178  }
179
180  return {
181    initialize: initialize,
182    setSuggestions: setSuggestions
183  };
184});
185
186document.addEventListener('DOMContentLoaded', suggestionsInternals.initialize);
187