1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file.
4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// require: cr.js
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// require: cr/ui.js
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// require: cr/ui/tree.js
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsencr.define('chrome.sync', function() {
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Allow platform specific CSS rules.
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  //
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(akalin): BMM and options page does something similar, too.
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Move this to util.js.
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (cr.isWindows)
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    document.documentElement.setAttribute('os', 'win');
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(akalin): Create SyncNodeTree/SyncNodeTreeItem classes that
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // hide all these details.
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * Gets all children of the given node and passes it to the given
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * callback.
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @param {Object} nodeInfo The info for the node whose children we
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *     want.
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @param {Function} callback The callback to call with the list of
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *     children.
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function getSyncNodeChildren(nodeInfo, callback) {
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    var children = [];
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    function processChildInfo(childNodeInfo) {
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!childNodeInfo) {
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        callback(children);
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return;
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      children.push(childNodeInfo);
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      chrome.sync.getNodeById(childNodeInfo.successorId, processChildInfo);
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    };
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    chrome.sync.getNodeById(nodeInfo.firstChildId, processChildInfo);
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * Makes a tree item from the given node info.
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @param {dictionary} nodeInfo The node info to create the tree
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *    item from.
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @return {cr.ui.TreeItem} The created tree item.
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function makeNodeTreeItem(nodeInfo) {
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    var treeItem = new cr.ui.TreeItem({
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      label: nodeInfo.title,
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      detail: nodeInfo
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    });
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (nodeInfo.isFolder) {
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      treeItem.mayHaveChildren_ = true;
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Load children asynchronously on expand.
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // TODO(akalin): Add a throbber while loading?
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      treeItem.triggeredLoad_ = false;
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      treeItem.addEventListener('expand', function(event) {
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (!treeItem.triggeredLoad_) {
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          getSyncNodeChildren(nodeInfo, function(children) {
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            for (var i = 0; i < children.length; ++i) {
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              var childTreeItem = makeNodeTreeItem(children[i]);
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              treeItem.add(childTreeItem);
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            }
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          });
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          treeItem.triggeredLoad_ = true;
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      });
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      treeItem.classList.add('leaf');
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return treeItem;
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * Updates the node detail view with the info for the given node.
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @param {dictionary} nodeInfo The info for the node we want to
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *     display.
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function updateNodeDetailView(nodeInfo) {
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    var nodeBrowser = document.getElementById('node-browser');
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // TODO(akalin): Get rid of this hack.
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (typeof nodeInfo.entry != 'string')
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      nodeInfo.entry = JSON.stringify(nodeInfo.entry, null, 2);
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    jstProcess(new JsEvalContext(nodeInfo), nodeBrowser);
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function decorateSyncNodeBrowser(syncNodeBrowser) {
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    cr.ui.decorate(syncNodeBrowser, cr.ui.Tree);
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncNodeBrowser.addEventListener('change', function(event) {
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (syncNodeBrowser.selectedItem)
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        updateNodeDetailView(syncNodeBrowser.selectedItem.detail);
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    });
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    chrome.sync.getRootNode(function(rootNodeInfo) {
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var rootTreeItem = makeNodeTreeItem(rootNodeInfo);
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      rootTreeItem.label = 'Root';
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncNodeBrowser.add(rootTreeItem);
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    });
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This is needed because JsTemplate (which is needed by
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // updateNodeDetailView) is loaded at the end of the file after
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // everything else.
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  //
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(akalin): Remove dependency on JsTemplate and get rid of
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // this.
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  var domLoaded = false;
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  var pendingSyncNodeBrowsers = [];
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function decorateSyncNodeBrowserAfterDOMLoad(id) {
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    var e = document.getElementById(id);
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (domLoaded) {
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      decorateSyncNodeBrowser(e);
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      pendingSyncNodeBrowsers.push(e);
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  document.addEventListener('DOMContentLoaded', function() {
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (var i = 0; i < pendingSyncNodeBrowsers.length; ++i) {
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      decorateSyncNodeBrowser(pendingSyncNodeBrowsers[i]);
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    domLoaded = true;
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  });
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return {
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    decorateSyncNodeBrowser: decorateSyncNodeBrowserAfterDOMLoad
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen});
132