Roll src/third_party/WebKit bf18a82:a9cee16 (svn 185297:185304)
[chromium-blink-merge.git] / chrome / browser / resources / sync_internals / sync_node_browser.js
blob369916457a58562f77250e86c7055e9e0174be87
1 // Copyright (c) 2011 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.
5 // require: cr.js
6 // require: cr/ui.js
7 // require: cr/ui/tree.js
9 (function() {
10 /**
11 * A helper function to determine if a node is the root of its type.
13 * @param {!Object} node The node to check.
15 var isTypeRootNode = function(node) {
16 return node.PARENT_ID == 'r' && node.UNIQUE_SERVER_TAG != '';
19 /**
20 * A helper function to determine if a node is a child of the given parent.
22 * @param {string} parentId The ID of the parent.
23 * @param {!Object} node The node to check.
25 var isChildOf = function(parentId, node) {
26 return node.PARENT_ID == parentId;
29 /**
30 * A helper function to sort sync nodes.
32 * Sorts by position index if possible, falls back to sorting by name, and
33 * finally sorting by METAHANDLE.
35 * If this proves to be slow and expensive, we should experiment with moving
36 * this functionality to C++ instead.
38 var nodeComparator = function(nodeA, nodeB) {
39 if (nodeA.hasOwnProperty('positionIndex') &&
40 nodeB.hasOwnProperty('positionIndex')) {
41 return nodeA.positionIndex - nodeB.positionIndex;
42 } else if (nodeA.NON_UNIQUE_NAME != nodeB.NON_UNIQUE_NAME) {
43 return nodeA.NON_UNIQUE_NAME.localeCompare(nodeB.NON_UNIQUE_NAME);
44 } else {
45 return nodeA.METAHANDLE - nodeB.METAHANDLE;
49 /**
50 * Updates the node detail view with the details for the given node.
51 * @param {!Object} node The struct representing the node we want to display.
53 function updateNodeDetailView(node) {
54 var nodeDetailsView = $('node-details');
55 nodeDetailsView.hidden = false;
56 jstProcess(new JsEvalContext(node.entry_), nodeDetailsView);
59 /**
60 * Updates the 'Last refresh time' display.
61 * @param {string} The text to display.
63 function setLastRefreshTime(str) {
64 $('node-browser-refresh-time').textContent = str;
67 /**
68 * Creates a new sync node tree item.
70 * @constructor
71 * @param {!Object} node The nodeDetails object for the node as returned by
72 * chrome.sync.getAllNodes().
73 * @extends {cr.ui.TreeItem}
75 var SyncNodeTreeItem = function(node) {
76 var treeItem = new cr.ui.TreeItem();
77 treeItem.__proto__ = SyncNodeTreeItem.prototype;
79 treeItem.entry_ = node;
80 treeItem.label = node.NON_UNIQUE_NAME;
81 if (node.IS_DIR) {
82 treeItem.mayHaveChildren_ = true;
84 // Load children on expand.
85 treeItem.expanded_ = false;
86 treeItem.addEventListener('expand',
87 treeItem.handleExpand_.bind(treeItem));
88 } else {
89 treeItem.classList.add('leaf');
91 return treeItem;
94 SyncNodeTreeItem.prototype = {
95 __proto__: cr.ui.TreeItem.prototype,
97 /**
98 * Finds the children of this node and appends them to the tree.
100 handleExpand_: function(event) {
101 var treeItem = this;
103 if (treeItem.expanded_) {
104 return;
106 treeItem.expanded_ = true;
108 var children = treeItem.tree.allNodes.filter(
109 isChildOf.bind(undefined, treeItem.entry_.ID));
110 children.sort(nodeComparator);
112 children.forEach(function(node) {
113 treeItem.add(new SyncNodeTreeItem(node));
119 * Creates a new sync node tree. Technically, it's a forest since it each
120 * type has its own root node for its own tree, but it still looks and acts
121 * mostly like a tree.
123 * @param {Object=} opt_propertyBag Optional properties.
124 * @constructor
125 * @extends {cr.ui.Tree}
127 var SyncNodeTree = cr.ui.define('tree');
129 SyncNodeTree.prototype = {
130 __proto__: cr.ui.Tree.prototype,
132 decorate: function() {
133 cr.ui.Tree.prototype.decorate.call(this);
134 this.addEventListener('change', this.handleChange_.bind(this));
135 this.allNodes = [];
138 populate: function(nodes) {
139 var tree = this;
141 // We store the full set of nodes in the SyncNodeTree object.
142 tree.allNodes = nodes;
144 var roots = tree.allNodes.filter(isTypeRootNode);
145 roots.sort(nodeComparator);
147 roots.forEach(function(typeRoot) {
148 tree.add(new SyncNodeTreeItem(typeRoot));
152 handleChange_: function(event) {
153 if (this.selectedItem) {
154 updateNodeDetailView(this.selectedItem);
160 * Clears any existing UI state. Useful prior to a refresh.
162 function clear() {
163 var treeContainer = $('sync-node-tree-container');
164 while (treeContainer.firstChild) {
165 treeContainer.removeChild(treeContainer.firstChild);
168 var nodeDetailsView = $('node-details');
169 nodeDetailsView.hidden = true;
173 * Fetch the latest set of nodes and refresh the UI.
175 function refresh() {
176 $('node-browser-refresh-button').disabled = true;
178 clear();
179 setLastRefreshTime('In progress since ' + (new Date()).toLocaleString());
181 chrome.sync.getAllNodes(function(nodeMap) {
182 // Put all nodes into one big list that ignores the type.
183 var nodes = nodeMap.
184 map(function(x) { return x.nodes; }).
185 reduce(function(a, b) { return a.concat(b); });
187 var treeContainer = $('sync-node-tree-container');
188 var tree = document.createElement('tree');
189 tree.setAttribute('id', 'sync-node-tree');
190 tree.setAttribute('icon-visibility', 'parent');
191 treeContainer.appendChild(tree);
193 cr.ui.decorate(tree, SyncNodeTree);
194 tree.populate(nodes);
196 setLastRefreshTime((new Date()).toLocaleString());
197 $('node-browser-refresh-button').disabled = false;
201 document.addEventListener('DOMContentLoaded', function(e) {
202 $('node-browser-refresh-button').addEventListener('click', refresh);
203 cr.ui.decorate('#sync-node-splitter', cr.ui.Splitter);
205 // Automatically trigger a refresh the first time this tab is selected.
206 $('sync-browser-tab').addEventListener('selectedChange', function f(e) {
207 if (this.selected) {
208 $('sync-browser-tab').removeEventListener('selectedChange', f);
209 refresh();
214 })();