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 7 cr.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