OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // require: cr.js | 5 // require: cr.js |
6 // require: cr/ui.js | 6 // require: cr/ui.js |
7 // require: cr/ui/tree.js | 7 // require: cr/ui/tree.js |
8 | 8 |
9 cr.define('chrome.sync', function() { | 9 cr.define('chrome.sync', function() { |
10 /** | 10 /** |
11 * Gets all children of the given node and passes it to the given | 11 * Gets all children of the given node and passes it to the given |
12 * callback. | 12 * callback. |
13 * @param {Object} nodeInfo The info for the node whose children we | 13 * @param {string} id The id whose children we want. |
14 * want. | 14 * @param {function(Array.<!Object>)} callback The callback to call |
15 * @param {Function} callback The callback to call with the list of | 15 * with the list of children summaries. |
16 * children. | |
17 */ | 16 */ |
18 function getSyncNodeChildren(nodeInfo, callback) { | 17 function getSyncNodeChildrenSummaries(id, callback) { |
19 var timer = chrome.sync.makeTimer(); | 18 var timer = chrome.sync.makeTimer(); |
20 chrome.sync.getChildNodeIds(nodeInfo.id, function(childNodeIds) { | 19 chrome.sync.getChildNodeIds(id, function(childNodeIds) { |
21 console.debug('getChildNodeIds took ' + | 20 console.debug('getChildNodeIds took ' + |
22 timer.elapsedSeconds + 's to retrieve ' + | 21 timer.elapsedSeconds + 's to retrieve ' + |
23 childNodeIds.length + ' ids'); | 22 childNodeIds.length + ' ids'); |
24 timer = chrome.sync.makeTimer(); | 23 timer = chrome.sync.makeTimer(); |
25 chrome.sync.getNodesById(childNodeIds, function(children) { | 24 chrome.sync.getNodeSummariesById( |
26 console.debug('getNodesById took ' + | 25 childNodeIds, function(childrenSummaries) { |
27 timer.elapsedSeconds + 's to retrieve ' + | 26 console.debug('getNodeSummariesById took ' + |
28 children.length + ' nodes'); | 27 timer.elapsedSeconds + 's to retrieve summaries for ' + |
29 callback(children); | 28 childrenSummaries.length + ' nodes'); |
| 29 callback(childrenSummaries); |
30 }); | 30 }); |
31 }); | 31 }); |
32 } | 32 } |
33 | 33 |
34 /** | 34 /** |
35 * Makes a tree item from the given node info. | 35 * Creates a new sync node tree item. |
36 * @param {dictionary} nodeInfo The node info to create the tree | 36 * @param {{id: string, title: string, isFolder: boolean}} |
37 * item from. | 37 * nodeSummary The nodeSummary object for the node (as returned |
38 * @return {cr.ui.TreeItem} The created tree item. | 38 * by chrome.sync.getNodeSummariesById()). |
| 39 * @constructor |
| 40 * @extends {cr.ui.TreeItem} |
39 */ | 41 */ |
40 function makeNodeTreeItem(nodeInfo) { | 42 var SyncNodeTreeItem = function(nodeSummary) { |
41 var treeItem = new cr.ui.TreeItem({ | 43 var treeItem = new cr.ui.TreeItem({ |
42 label: nodeInfo.title, | 44 id_: nodeSummary.id |
43 detail: nodeInfo | |
44 }); | 45 }); |
| 46 treeItem.__proto__ = SyncNodeTreeItem.prototype; |
45 | 47 |
46 if (nodeInfo.isFolder) { | 48 treeItem.label = nodeSummary.title; |
| 49 if (nodeSummary.isFolder) { |
47 treeItem.mayHaveChildren_ = true; | 50 treeItem.mayHaveChildren_ = true; |
48 | 51 |
49 // Load children asynchronously on expand. | 52 // Load children asynchronously on expand. |
50 // TODO(akalin): Add a throbber while loading? | 53 // TODO(akalin): Add a throbber while loading? |
51 treeItem.triggeredLoad_ = false; | 54 treeItem.triggeredLoad_ = false; |
52 treeItem.addEventListener('expand', function(event) { | 55 treeItem.addEventListener('expand', |
53 if (!treeItem.triggeredLoad_) { | 56 treeItem.handleExpand_.bind(treeItem)); |
54 getSyncNodeChildren(nodeInfo, function(children) { | |
55 var timer = chrome.sync.makeTimer(); | |
56 for (var i = 0; i < children.length; ++i) { | |
57 var childTreeItem = makeNodeTreeItem(children[i]); | |
58 treeItem.add(childTreeItem); | |
59 } | |
60 console.debug('adding ' + children.length + ' children took ' + | |
61 timer.elapsedSeconds + 's'); | |
62 }); | |
63 treeItem.triggeredLoad_ = true; | |
64 } | |
65 }); | |
66 } else { | 57 } else { |
67 treeItem.classList.add('leaf'); | 58 treeItem.classList.add('leaf'); |
68 } | 59 } |
69 return treeItem; | 60 return treeItem; |
| 61 }; |
| 62 |
| 63 SyncNodeTreeItem.prototype = { |
| 64 __proto__: cr.ui.TreeItem.prototype, |
| 65 |
| 66 /** |
| 67 * Retrieves the details for this node. |
| 68 * @param {function(Object)} callback The callback that will be |
| 69 * called with the node details, or null if it could not be |
| 70 * retrieved. |
| 71 */ |
| 72 getDetails: function(callback) { |
| 73 chrome.sync.getNodeDetailsById([this.id_], function(nodeDetails) { |
| 74 callback(nodeDetails[0] || null); |
| 75 }); |
| 76 }, |
| 77 |
| 78 handleExpand_: function(event) { |
| 79 if (!this.triggeredLoad_) { |
| 80 getSyncNodeChildrenSummaries(this.id_, this.addChildNodes_.bind(this)); |
| 81 this.triggeredLoad_ = true; |
| 82 } |
| 83 }, |
| 84 |
| 85 /** |
| 86 * Adds children from the list of children summaries. |
| 87 * @param {Array.<{id: string, title: string, isFolder: boolean}>} |
| 88 * childrenSummaries The list of children summaries with which |
| 89 * to create the child nodes. |
| 90 */ |
| 91 addChildNodes_: function(childrenSummaries) { |
| 92 var timer = chrome.sync.makeTimer(); |
| 93 for (var i = 0; i < childrenSummaries.length; ++i) { |
| 94 var childTreeItem = new SyncNodeTreeItem(childrenSummaries[i]); |
| 95 this.add(childTreeItem); |
| 96 } |
| 97 console.debug('adding ' + childrenSummaries.length + |
| 98 ' children took ' + timer.elapsedSeconds + 's'); |
| 99 } |
| 100 }; |
| 101 |
| 102 /** |
| 103 * Updates the node detail view with the details for the given node. |
| 104 * @param {!Object} nodeDetails The details for the node we want |
| 105 * to display. |
| 106 */ |
| 107 function updateNodeDetailView(nodeDetails) { |
| 108 var nodeBrowser = document.getElementById('node-browser'); |
| 109 // TODO(akalin): Write a nicer detail viewer. |
| 110 nodeDetails.entry = JSON.stringify(nodeDetails.entry, null, 2); |
| 111 jstProcess(new JsEvalContext(nodeDetails), nodeBrowser); |
70 } | 112 } |
71 | 113 |
72 /** | 114 /** |
73 * Updates the node detail view with the info for the given node. | 115 * Creates a new sync node tree. |
74 * @param {dictionary} nodeInfo The info for the node we want to | 116 * @param {Object=} opt_propertyBag Optional properties. |
75 * display. | 117 * @constructor |
| 118 * @extends {cr.ui.Tree} |
76 */ | 119 */ |
77 function updateNodeDetailView(nodeInfo) { | 120 var SyncNodeTree = cr.ui.define('tree'); |
78 var nodeBrowser = document.getElementById('node-browser'); | 121 |
79 // TODO(akalin): Get rid of this hack. | 122 SyncNodeTree.prototype = { |
80 if (typeof nodeInfo.entry != 'string') | 123 __proto__: cr.ui.Tree.prototype, |
81 nodeInfo.entry = JSON.stringify(nodeInfo.entry, null, 2); | 124 |
82 jstProcess(new JsEvalContext(nodeInfo), nodeBrowser); | 125 decorate: function() { |
83 } | 126 cr.ui.Tree.prototype.decorate.call(this); |
| 127 this.addEventListener('change', this.handleChange_.bind(this)); |
| 128 chrome.sync.getRootNodeDetails(this.makeRoot_.bind(this)); |
| 129 }, |
| 130 |
| 131 /** |
| 132 * Creates the root of the tree. |
| 133 * @param {{id: string, title: string, isFolder: boolean}} |
| 134 * rootNodeSummary The summary info for the root node. |
| 135 */ |
| 136 makeRoot_: function(rootNodeSummary) { |
| 137 // The root node usually doesn't have a title. |
| 138 rootNodeSummary.title = rootNodeSummary.title || 'Root'; |
| 139 var rootTreeItem = new SyncNodeTreeItem(rootNodeSummary); |
| 140 this.add(rootTreeItem); |
| 141 }, |
| 142 |
| 143 handleChange_: function(event) { |
| 144 if (this.selectedItem) { |
| 145 this.selectedItem.getDetails(updateNodeDetailView); |
| 146 } |
| 147 } |
| 148 }; |
84 | 149 |
85 function decorateSyncNodeBrowser(syncNodeBrowser) { | 150 function decorateSyncNodeBrowser(syncNodeBrowser) { |
86 cr.ui.decorate(syncNodeBrowser, cr.ui.Tree); | 151 cr.ui.decorate(syncNodeBrowser, SyncNodeTree); |
87 | |
88 syncNodeBrowser.addEventListener('change', function(event) { | |
89 if (syncNodeBrowser.selectedItem) | |
90 updateNodeDetailView(syncNodeBrowser.selectedItem.detail); | |
91 }); | |
92 | |
93 chrome.sync.getRootNode(function(rootNodeInfo) { | |
94 var rootTreeItem = makeNodeTreeItem(rootNodeInfo); | |
95 rootTreeItem.label = 'Root'; | |
96 syncNodeBrowser.add(rootTreeItem); | |
97 }); | |
98 } | 152 } |
99 | 153 |
100 // This is needed because JsTemplate (which is needed by | 154 // This is needed because JsTemplate (which is needed by |
101 // updateNodeDetailView) is loaded at the end of the file after | 155 // updateNodeDetailView) is loaded at the end of the file after |
102 // everything else. | 156 // everything else. |
103 // | 157 // |
104 // TODO(akalin): Remove dependency on JsTemplate and get rid of | 158 // TODO(akalin): Remove dependency on JsTemplate and get rid of |
105 // this. | 159 // this. |
106 var domLoaded = false; | 160 var domLoaded = false; |
107 var pendingSyncNodeBrowsers = []; | 161 var pendingSyncNodeBrowsers = []; |
(...skipping 10 matching lines...) Expand all Loading... |
118 for (var i = 0; i < pendingSyncNodeBrowsers.length; ++i) { | 172 for (var i = 0; i < pendingSyncNodeBrowsers.length; ++i) { |
119 decorateSyncNodeBrowser(pendingSyncNodeBrowsers[i]); | 173 decorateSyncNodeBrowser(pendingSyncNodeBrowsers[i]); |
120 } | 174 } |
121 domLoaded = true; | 175 domLoaded = true; |
122 }); | 176 }); |
123 | 177 |
124 return { | 178 return { |
125 decorateSyncNodeBrowser: decorateSyncNodeBrowserAfterDOMLoad | 179 decorateSyncNodeBrowser: decorateSyncNodeBrowserAfterDOMLoad |
126 }; | 180 }; |
127 }); | 181 }); |
OLD | NEW |