blob: 2350e62b44a9b78b47ac415338269a2871a372cc [file] [log] [blame]
// Copyright (c) 2012 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.
import {ArrayDataModel} from 'chrome://resources/js/cr/ui/array_data_model.m.js';
import {List} from 'chrome://resources/js/cr/ui/list.m.js';
import {getAllNodes, Timer} from './chrome_sync.js';
let currSearchId = 0;
function setQueryString(queryControl, query) {
queryControl.value = query;
}
function createDoQueryFunction(queryControl, submitControl, query) {
return function() {
setQueryString(queryControl, query);
submitControl.click();
};
}
/**
* Decorates the quick search controls
*
* @param {!NodeList<!Element>} quickLinkArray The <a> object which
* will be given a link to a quick filter option.
* @param {!HTMLButtonElement} submitControl
* @param {!HTMLInputElement} queryControl The <input> object of
* type=search where user's query is typed.
*/
export function decorateQuickQueryControls(
quickLinkArray, submitControl, queryControl) {
for (let index = 0; index < quickLinkArray.length; ++index) {
const quickQuery = quickLinkArray[index].getAttribute('data-query');
const quickQueryFunction =
createDoQueryFunction(queryControl, submitControl, quickQuery);
quickLinkArray[index].addEventListener('click', quickQueryFunction);
}
}
/**
* Runs a search with the given query.
*
* @param {string} query The regex to do the search with.
* @param {!Function} callback The callback called with the search results.
* not called if doSearch() is called again while the search is running.
*/
function doSearch(query, callback) {
const searchId = ++currSearchId;
try {
const regex = new RegExp(query);
getAllNodes(function(node_map) {
// Put all nodes into one big list that ignores the type.
const nodes = node_map
.map(function(x) {
return x.nodes;
})
.reduce(function(a, b) {
return a.concat(b);
});
if (currSearchId !== searchId) {
return;
}
callback(
nodes.filter(function(elem) {
return regex.test(JSON.stringify(elem, null, 2));
}),
null);
});
} catch (err) {
// Sometimes the provided regex is invalid. This and other errors will
// be caught and handled here.
callback([], err);
}
}
/**
* Decorates the various search controls.
*
* @param {!HTMLInputElement} queryControl The <input> object of
* type=search where the user's query is typed.
* @param {!HTMLButtonElement} submitControl The <button> object
* where the user can click to submit the query.
* @param {!HTMLElement} statusControl The <span> object display the
* search status.
* @param {!HTMLElement} resultsControl The <list> object which holds
* the list of returned results.
* @param {!HTMLPreElement} detailsControl The <pre> object which
* holds the details of the selected result.
*/
export function decorateSearchControls(
queryControl, submitControl, statusControl, resultsControl,
detailsControl) {
const resultsDataModel = new ArrayDataModel([]);
function searchFunction() {
const query = queryControl.value;
statusControl.textContent = '';
resultsDataModel.splice(0, resultsDataModel.length);
if (!query) {
return;
}
statusControl.textContent = 'Searching for ' + query + '...';
queryControl.removeAttribute('error');
const timer = new Timer();
doSearch(query, function(nodes, error) {
if (error) {
statusControl.textContent = 'Error: ' + error;
queryControl.setAttribute('error', '');
} else {
statusControl.textContent = 'Found ' + nodes.length + ' nodes in ' +
timer.getElapsedSeconds() + 's';
queryControl.removeAttribute('error');
// TODO(akalin): Write a nicer list display.
for (let i = 0; i < nodes.length; ++i) {
nodes[i].toString = function() {
return this.NON_UNIQUE_NAME;
};
}
resultsDataModel.push.apply(resultsDataModel, nodes);
// Workaround for http://crbug.com/83452 .
resultsControl.redraw();
}
});
}
submitControl.addEventListener('click', searchFunction);
// Decorate search box.
queryControl.onsearch = searchFunction;
queryControl.value = '';
// Decorate results list.
List.decorate(resultsControl);
resultsControl.dataModel = resultsDataModel;
resultsControl.selectionModel.addEventListener('change', function(event) {
detailsControl.textContent = '';
const selected = resultsControl.selectedItem;
if (selected) {
detailsControl.textContent = JSON.stringify(selected, null, 2);
}
});
}