• 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// require: cr.js
6
7cr.define('chrome.sync', function() {
8  var currSearchId = 0;
9
10  var setQueryString = function(queryControl, query) {
11    queryControl.value = query;
12  };
13
14  var createDoQueryFunction = function(queryControl, submitControl, query) {
15    return function() {
16      setQueryString(queryControl, query);
17      submitControl.click();
18    };
19  };
20
21  /**
22   * Decorates the quick search controls
23   *
24   * @param {Array of DOM elements} quickLinkArray The <a> object which
25   *     will be given a link to a quick filter option.
26   * @param {!HTMLInputElement} queryControl The <input> object of
27   *     type=search where the user types in his query.
28   */
29  var decorateQuickQueryControls = function(quickLinkArray, submitControl,
30                                            queryControl) {
31    for (var index = 0; index < allLinks.length; ++index) {
32      var quickQuery = allLinks[index].getAttribute('data-query');
33      var quickQueryFunction = createDoQueryFunction(queryControl,
34          submitControl, quickQuery);
35      allLinks[index].addEventListener('click', quickQueryFunction);
36    }
37  };
38
39  /**
40   * Runs a search with the given query.
41   *
42   * @param {string} query The regex to do the search with.
43   * @param {function} callback The callback called with the search results;
44   *     not called if doSearch() is called again while the search is running.
45   */
46  var doSearch = function(query, callback) {
47    var searchId = ++currSearchId;
48    try {
49      var regex = new RegExp(query);
50      chrome.sync.getAllNodes(function(node_map) {
51        // Put all nodes into one big list that ignores the type.
52        var nodes = node_map.
53            map(function(x) { return x.nodes; }).
54            reduce(function(a, b) { return a.concat(b); });
55
56        if (currSearchId != searchId) {
57          return;
58        }
59        callback(nodes.filter(function(elem) {
60          return regex.test(JSON.stringify(elem, null, 2));
61        }), null);
62      });
63    } catch (err) {
64      // Sometimes the provided regex is invalid.  This and other errors will
65      // be caught and handled here.
66      callback([], err);
67    }
68  };
69
70  /**
71   * Decorates the various search controls.
72   *
73   * @param {!HTMLInputElement} queryControl The <input> object of
74   *     type=search where the user types in his query.
75   * @param {!HTMLButtonElement} submitControl The <button> object
76   *     where the user can click to do his query.
77   * @param {!HTMLElement} statusControl The <span> object display the
78   *     search status.
79   * @param {!HTMLElement} listControl The <list> object which holds
80   *     the list of returned results.
81   * @param {!HTMLPreElement} detailsControl The <pre> object which
82   *     holds the details of the selected result.
83   */
84  function decorateSearchControls(queryControl, submitControl, statusControl,
85                                  resultsControl, detailsControl) {
86    var resultsDataModel = new cr.ui.ArrayDataModel([]);
87
88    var searchFunction = function() {
89      var query = queryControl.value;
90      statusControl.textContent = '';
91      resultsDataModel.splice(0, resultsDataModel.length);
92      if (!query) {
93        return;
94      }
95      statusControl.textContent = 'Searching for ' + query + '...';
96      queryControl.removeAttribute('error');
97      var timer = chrome.sync.makeTimer();
98      doSearch(query, function(nodes, error) {
99        if (error) {
100          statusControl.textContent = 'Error: ' + error;
101          queryControl.setAttribute('error', '');
102        } else {
103          statusControl.textContent =
104            'Found ' + nodes.length + ' nodes in ' +
105            timer.getElapsedSeconds() + 's';
106          queryControl.removeAttribute('error');
107
108          // TODO(akalin): Write a nicer list display.
109          for (var i = 0; i < nodes.length; ++i) {
110            nodes[i].toString = function() {
111              return this.NON_UNIQUE_NAME;
112            };
113          }
114          resultsDataModel.push.apply(resultsDataModel, nodes);
115          // Workaround for http://crbug.com/83452 .
116          resultsControl.redraw();
117        }
118      });
119    };
120
121    submitControl.addEventListener('click', searchFunction);
122    // Decorate search box.
123    queryControl.onsearch = searchFunction;
124    queryControl.value = '';
125
126    // Decorate results list.
127    cr.ui.List.decorate(resultsControl);
128    resultsControl.dataModel = resultsDataModel;
129    resultsControl.selectionModel.addEventListener('change', function(event) {
130      detailsControl.textContent = '';
131      var selected = resultsControl.selectedItem;
132      if (selected) {
133        detailsControl.textContent = JSON.stringify(selected, null, 2);
134      }
135    });
136  }
137
138  return {
139    decorateSearchControls: decorateSearchControls,
140    decorateQuickQueryControls: decorateQuickQueryControls
141  };
142});
143