chromium/third_party/google-closure-library/closure/goog/demos/depsgraph.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!--
Copyright The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<head>
<title>Deps Tree</title>
<script type="text/javascript" src="../base.js"></script>
<script type="text/javascript">
  goog.require('goog.object');
  goog.require('goog.array');
  goog.require('goog.debug');
  goog.require('goog.events');
</script>
<style type="text/css">

h1 {
  font: bold 24px verdana,sans-serif;
  margin: 0px;
  margin-bottom: 14px;
}

div {
  position: relative;
  font: normal 9px verdana,sans-serif;
  padding: 3px;
  margin: 5px;
  background-color: #EEE;
  border: 1px solid #999;
  cursor: pointer;
  color: #333;
}


div.hover {
  background-color: #EE6;
  border: 1px solid #990;
  color: #000;
}

div.hilite {
  background-color: #AFA;
  border: 1px solid #090;
}

div.infile {
  background-color: #FFA;
  border: 1px solid #990;
}

div.required {
  background-color: #FAA;
  border: 1px solid #900;
}

</style>
</head>
<body>
<h1>Closure Dependency Graph</h1>
<script type="text/javascript">

// HackHack
// Hacked together quickly to provide a quick visible analysis.  Not meant to be
// a complete or long lived tool.

var levels = [];
var visited = [];

var change = true;
var i = 0;
while (change) {
  change = false;
  levels[i] = [];
  var newVisited = goog.array.clone(visited);
  goog.object.forEach(goog.dependencies_.nameToPath, function(path, ns) {
    var deps = goog.object.clone(goog.dependencies_.requires[path]);
    goog.array.forEach(newVisited, function(value) {
      goog.object.remove(deps, value);
    });

    if (goog.object.getCount(deps) == 0 && !goog.object.contains(visited, ns)) {
      change = true;
      levels[i].push(ns);
      visited.push(ns);
    }
  });
  i++;
}

var errors = [];
goog.object.forEach(goog.dependencies_.nameToPath, function(path, ns) {
  if (!goog.array.contains(visited, ns)) {
    errors.push(ns);
  }
});
if (errors.length > 0) {
  alert('The following files were not added to dependency graph: \n' +
        errors.join('\n'));
}

document.write('<table><tr>')
goog.array.forEach(levels, function(level) {
  document.write('<td>');
  goog.array.forEach(level, function(ns) {
    document.write(
        goog.getMsg('<div id="{$ns}" class="dep">{$ns}</div>', {ns:ns}));
  });
});
document.write('</tr></table>')


var currentTarget = null;
var hilited = [];
var required = [];
var infile = [];
goog.events.listen(document, 'mouseover', handleMouse);
goog.events.listen(document, 'keydown', handleKeys);


function handleMouse(e) {
  highlightElement(e.target);
}

function handleKeys(e) {
  if (currentTarget) {
    switch (e.keyCode) {
      case 40:
        highlightElement(currentTarget.nextSibling);
        break;
    
      case 38:
        highlightElement(currentTarget.previousSibling);
        break;
    
      case 39:
        // right
        break;
    
      case 37:
        // left
        break;

      default:
        return;
    }
    e.preventDefault();
  }
}


function highlightElement(el) {
  if (el && el.id) {
    
    goog.array.forEach(hilited.concat(required).concat(infile), function(ns) {
      document.getElementById(ns).className = 'dep';
    });
    hilited.length = 0;
    required.length = 0;
    infile.length = 0;

    if (currentTarget) {
      currentTarget.className = 'dep';
    }

    highlightDeps(el.id);
    highlightRequired(el.id);
    highlightFile(el.id);
    
    el.className = 'dep hover';
    currentTarget = el;
  }
}

function highlightFile(ns) {
  var names = goog.dependencies_.pathToNames[goog.dependencies_.nameToPath[ns]];
  goog.object.forEach(names, function(value, name) {
    document.getElementById(name).className = 'dep infile';
    infile.push(name);
  });
}

function highlightRequired(ns) {
  goog.object.forEach(goog.dependencies_.requires, function(value, key) {
    if (goog.object.containsKey(value, ns)) {
      var names = goog.dependencies_.pathToNames[key];
      goog.object.forEach(names, function(val, id) {
        if (!goog.array.contains(required, id)) {
          document.getElementById(id).className = 'dep required';
          required.push(id);
          highlightRequired(id);
        }
      });
    }
  });  
}

function highlightDeps(ns) {
  var deps = goog.dependencies_.requires[goog.dependencies_.nameToPath[ns]];
  goog.object.forEach(deps, function(value, key) {
    if (!goog.array.contains(hilited, key)) {
      document.getElementById(key).className = 'dep hilite';
      hilited.push(key);
      highlightDeps(key);
    }
  });
}

</script>


<div class="hover">selected item</div>
<div class="infile">...is in same file as the selected item</div>
<div class="hilite">...is a dependency of the selected item</div>
<div class="required">the selected item is a dependency of...</div>
</body>
</html>