Commit 62a0dcbd authored by akalin@chromium.org's avatar akalin@chromium.org

[Sync] Implement search frontend in chrome://sync-internals.

Add new 'Search' tab.

Refactor some javascript code slightly.

BUG=76812
TEST=


Review URL: http://codereview.chromium.org/7055023

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86384 0039d316-1c4b-4281-b951-d872f2087c98
parent 7f8a176d
......@@ -150,4 +150,21 @@ for (var i = 0; i < syncFunctions.length; ++i) {
chrome.sync[syncFunction] = makeSyncFunction(syncFunction);
}
/**
* Returns an object which measures elapsed time.
*/
chrome.sync.makeTimer = function() {
var start = new Date();
return {
/**
* @return {number} The number of seconds since the timer was
* created.
*/
get elapsedSeconds() {
return ((new Date()).getTime() - start.getTime()) / 1000.0;
}
};
};
})();
<p>
<input id="sync-search-query" type="search" incremental
placeholder="Search Sync Data">
<span id="sync-search-status"></span>
</p>
<div id="sync-results-container">
<list id="sync-results-list"></list>
<div id="sync-results-splitter"></div>
<div id="sync-result-details-container">
<pre id="sync-result-details"></pre>
</div>
</div>
<script>
// require: cr/ui.js
// require: util.js
cr.ui.decorate('#sync-results-splitter', cr.ui.Splitter);
chrome.sync.decorateSearchControls(
$('sync-search-query'),
$('sync-search-status'),
$('sync-results-list'),
$('sync-result-details'));
</script>
......@@ -4,8 +4,10 @@
<!-- If you change the title, make sure you also update
chrome/test/functional/special_tabs.py. -->
<title>Sync Internals</title>
<link rel="stylesheet" href="chrome://resources/css/list.css">
<link rel="stylesheet" href="chrome://resources/css/tabs.css">
<link rel="stylesheet" href="chrome://resources/css/tree.css">
<link rel="stylesheet" href="sync_search.css">
<link rel="stylesheet" href="sync_node_browser.css">
<script src="chrome://resources/css/tree.css.js"></script>
......@@ -15,11 +17,21 @@ chrome/test/functional/special_tabs.py. -->
<script src="chrome://resources/js/cr/ui.js"></script>
<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
<script src="chrome://resources/js/cr/ui/splitter.js"></script>
<!-- List stuff. -->
<script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
<script src="chrome://resources/js/cr/ui/list_item.js"></script>
<script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
<script src="chrome://resources/js/cr/ui/list.js"></script>
<script src="chrome://resources/js/cr/ui/tabs.js"></script>
<script src="chrome://resources/js/cr/ui/tree.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="chrome_sync.js"></script>
<script src="sync_log.js"></script>
<script src="sync_node_browser.js"></script>
<script src="sync_search.js"></script>
</head>
<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
......@@ -38,6 +50,7 @@ chrome/test/functional/special_tabs.py. -->
<tab>Notifications</tab>
<tab>Events</tab>
<tab>Sync Node Browser</tab>
<tab>Search</tab>
</tabs>
<tabpanels>
<tabpanel>
......@@ -55,10 +68,20 @@ chrome/test/functional/special_tabs.py. -->
<tabpanel>
<include src="sync_node_browser.html" />
</tabpanel>
<tabpanel>
<include src="search.html" />
</tabpanel>
</tabpanels>
</tabbox>
<script>
// Allow platform specific CSS rules.
//
// TODO(akalin): BMM and options page does something similar, too.
// Move this to util.js.
if (cr.isWindows)
document.documentElement.setAttribute('os', 'win');
cr.ui.decorate('tabbox', cr.ui.TabBox);
</script>
......
......@@ -7,33 +7,6 @@
// require: cr/ui/tree.js
cr.define('chrome.sync', function() {
// Allow platform specific CSS rules.
//
// TODO(akalin): BMM and options page does something similar, too.
// Move this to util.js.
if (cr.isWindows)
document.documentElement.setAttribute('os', 'win');
// TODO(akalin): Create SyncNodeTree/SyncNodeTreeItem classes that
// hide all these details.
/**
* Returns an object which measures elapsed time.
*/
var makeTimer = function() {
var start = new Date();
return {
/**
* @return {number} The number of seconds since the timer was
* created.
*/
get elapsedSeconds() {
return ((new Date()).getTime() - start.getTime()) / 1000.0;
}
};
};
/**
* Gets all children of the given node and passes it to the given
* callback.
......@@ -43,12 +16,12 @@ cr.define('chrome.sync', function() {
* children.
*/
function getSyncNodeChildren(nodeInfo, callback) {
var timer = makeTimer();
var timer = chrome.sync.makeTimer();
chrome.sync.getChildNodeIds(nodeInfo.id, function(childNodeIds) {
console.debug('getChildNodeIds took ' +
timer.elapsedSeconds + 's to retrieve ' +
childNodeIds.length + ' ids');
timer = makeTimer();
timer = chrome.sync.makeTimer();
chrome.sync.getNodesById(childNodeIds, function(children) {
console.debug('getNodesById took ' +
timer.elapsedSeconds + 's to retrieve ' +
......@@ -79,7 +52,7 @@ cr.define('chrome.sync', function() {
treeItem.addEventListener('expand', function(event) {
if (!treeItem.triggeredLoad_) {
getSyncNodeChildren(nodeInfo, function(children) {
var timer = makeTimer();
var timer = chrome.sync.makeTimer();
for (var i = 0; i < children.length; ++i) {
var childTreeItem = makeNodeTreeItem(children[i]);
treeItem.add(childTreeItem);
......
/*
Copyright (c) 2011 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.
*/
#sync-search-query {
width: 20em;
}
#sync-search-status {
color: #333;
font-style: italic;
}
#sync-results-container {
display: -webkit-box;
/* Should be > #sync-page's min-height. */
/* TODO(akalin): Find a less hacky way to do this. */
height: 750px;
}
#sync-results-list {
height: 100%;
width: 275px;
/* min-width and max-width are used by the split pane. */
min-width: 50px;
max-width: 50%;
overflow: auto;
box-sizing: border-box;
padding: 5px;
-webkit-padding-start: 10px;
}
#sync-results-splitter {
width: 5px;
background-color: #ebeff9;
cursor: col-resize;
}
/* Platform annotations are set in sync_node_browser.js. */
/* TODO(akalin): Make the BMM also use this style. */
html[os=win] #sync-results-splitter {
cursor: e-resize;
}
#sync-result-details-container {
height: 100%;
overflow: auto;
-webkit-box-flex: 1;
/* TODO(akalin): Figure out why this is needed, even with box-flex: 1. */
width: 100%;
}
// Copyright (c) 2011 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.
// require: cr.js
cr.define('chrome.sync', function() {
var currSearchId = 0;
/**
* Runs a search with the given query.
*
* @param {string} query The query to do the search with.
* item from.
* @param {function} doneCallback The callback called when the
* search is finished; not called if doSearch() is called again
* while the search is running.
*/
var doSearch = function(query, callback) {
var searchId = ++currSearchId;
chrome.sync.findNodesContainingString(query, function(ids) {
if (currSearchId != searchId) {
return;
}
chrome.sync.getNodesById(ids, function(nodeInfos) {
if (currSearchId != searchId) {
return;
}
callback(nodeInfos);
});
});
};
/**
* Decorates the various search controls.
*
* @param {object} queryControl The <input> object of type=search
* where the user types in his query.
* @param {object} statusControl The <span> object display the
* search status.
* @param {object} listControl The <list> object which holds the
* list of returned results.
* @param {object} detailsControl The <pre> object which holds the
* details of the selected result.
*/
function decorateSearchControls(queryControl, statusControl,
resultsControl, detailsControl) {
var resultsDataModel = new cr.ui.ArrayDataModel([]);
// Decorate search box.
queryControl.onsearch = function() {
var query = queryControl.value;
statusControl.innerText = '';
resultsDataModel.splice(0, resultsDataModel.length);
if (!query) {
return;
}
statusControl.innerText = 'Searching for ' + query + '...';
var timer = chrome.sync.makeTimer();
doSearch(query, function(nodeInfos) {
statusControl.innerText =
'Found ' + nodeInfos.length + ' nodes in '
+ timer.elapsedSeconds + 's';
// TODO(akalin): Write a nicer list display.
for (var i = 0; i < nodeInfos.length; ++i) {
nodeInfos[i].toString = function() {
return this.title;
}.bind(nodeInfos[i]);
}
resultsDataModel.push.apply(resultsDataModel, nodeInfos);
// Workaround for http://crbug.com/83452 .
resultsControl.redraw();
});
};
queryControl.value = '';
// Decorate results list.
cr.ui.List.decorate(resultsControl);
resultsControl.dataModel = resultsDataModel;
resultsControl.selectionModel.addEventListener('change', function(event) {
detailsControl.innerText = '';
var selected = resultsControl.selectedItem;
if (selected) {
detailsControl.innerText = JSON.stringify(selected, null, 2);
}
});
}
return {
decorateSearchControls: decorateSearchControls
};
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment