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