public function build(array $changesets)
 {
     assert_instances_of($changesets, 'DifferentialChangeset');
     $nav = new AphrontSideNavFilterView();
     $nav->setBaseURI($this->getBaseURI());
     $nav->setFlexible(true);
     $nav->setCollapsed($this->collapsed);
     $anchor = $this->getAnchorName();
     $tree = new PhutilFileTree();
     foreach ($changesets as $changeset) {
         try {
             $tree->addPath($changeset->getFilename(), $changeset);
         } catch (Exception $ex) {
             // TODO: See T1702. When viewing the versus diff of diffs, we may
             // have files with the same filename. For example, if you have a setup
             // like this in SVN:
             //
             //  a/
             //    README
             //  b/
             //    README
             //
             // ...and you run "arc diff" once from a/, and again from b/, you'll
             // get two diffs with path README. However, in the versus diff view we
             // will compute their absolute repository paths and detect that they
             // aren't really the same file. This is correct, but causes us to
             // throw when inserting them.
             //
             // We should probably compute the smallest unique path for each file
             // and show these as "a/README" and "b/README" when diffed against
             // one another. However, we get this wrong in a lot of places (the
             // other TOC shows two "README" files, and we generate the same anchor
             // hash for both) so I'm just stopping the bleeding until we can get
             // a proper fix in place.
         }
     }
     require_celerity_resource('phabricator-filetree-view-css');
     $filetree = array();
     $path = $tree;
     while ($path = $path->getNextNode()) {
         $data = $path->getData();
         $name = $path->getName();
         $style = 'padding-left: ' . (2 + 3 * $path->getDepth()) . 'px';
         $href = null;
         if ($data) {
             $href = '#' . $data->getAnchorName();
             $title = $name;
             $icon = id(new PHUIIconView())->setIconFont('fa-file-text-o bluetext');
         } else {
             $name .= '/';
             $title = $path->getFullPath() . '/';
             $icon = id(new PHUIIconView())->setIconFont('fa-folder-open blue');
         }
         $name_element = phutil_tag('span', array('class' => 'phabricator-filetree-name'), $name);
         $filetree[] = javelin_tag($href ? 'a' : 'span', array('href' => $href, 'style' => $style, 'title' => $title, 'class' => 'phabricator-filetree-item'), array($icon, $name_element));
     }
     $tree->destroy();
     $filetree = phutil_tag('div', array('class' => 'phabricator-filetree'), $filetree);
     Javelin::initBehavior('phabricator-file-tree', array());
     $nav->addLabel(pht('Changed Files'));
     $nav->addCustomBlock($filetree);
     $nav->setActive(true);
     $nav->selectFilter(null);
     return $nav;
 }
 private function buildSideNavView(DifferentialRevision $revision, array $changesets)
 {
     $nav = new AphrontSideNavFilterView();
     $nav->setBaseURI(new PhutilURI('/D' . $revision->getID()));
     $nav->setFlexible(true);
     $nav->addFilter('top', 'D' . $revision->getID(), '#top', $relative = false, 'phabricator-active-nav-focus');
     $tree = new PhutilFileTree();
     foreach ($changesets as $changeset) {
         $tree->addPath($changeset->getFilename(), $changeset);
     }
     require_celerity_resource('phabricator-filetree-view-css');
     $filetree = array();
     $path = $tree;
     while ($path = $path->getNextNode()) {
         $data = $path->getData();
         $name = $path->getName();
         $style = 'padding-left: ' . (2 + 3 * $path->getDepth()) . 'px';
         $href = null;
         if ($data) {
             $href = '#' . $data->getAnchorName();
             $icon = 'phabricator-filetree-icon-file';
         } else {
             $name .= '/';
             $icon = 'phabricator-filetree-icon-dir';
         }
         $icon = phutil_render_tag('span', array('class' => 'phabricator-filetree-icon ' . $icon), '');
         $name_element = phutil_render_tag('span', array('class' => 'phabricator-filetree-name'), phutil_escape_html($name));
         $filetree[] = javelin_render_tag($href ? 'a' : 'span', array('href' => $href, 'style' => $style, 'title' => $name, 'class' => 'phabricator-filetree-item'), $icon . $name_element);
     }
     $tree->destroy();
     $filetree = '<div class="phabricator-filetree">' . implode("\n", $filetree) . '</div>';
     $nav->addFilter('toc', 'Table of Contents', '#toc');
     $nav->addCustomBlock($filetree);
     $nav->addFilter('comment', 'Add Comment', '#comment');
     $nav->setActive(true);
     return $nav;
 }
 private function buildSideNavView(DifferentialRevision $revision, array $changesets)
 {
     $nav = new AphrontSideNavFilterView();
     $nav->setBaseURI(new PhutilURI('/D' . $revision->getID()));
     $nav->setFlexible(true);
     $nav->addFilter('top', 'D' . $revision->getID(), '#top', $relative = false, 'phabricator-active-nav-focus');
     $tree = new PhutilFileTree();
     foreach ($changesets as $changeset) {
         try {
             $tree->addPath($changeset->getFilename(), $changeset);
         } catch (Exception $ex) {
             // TODO: See T1702. When viewing the versus diff of diffs, we may
             // have files with the same filename. For example, if you have a setup
             // like this in SVN:
             //
             //  a/
             //    README
             //  b/
             //    README
             //
             // ...and you run "arc diff" once from a/, and again from b/, you'll
             // get two diffs with path README. However, in the versus diff view we
             // will compute their absolute repository paths and detect that they
             // aren't really the same file. This is correct, but causes us to
             // throw when inserting them.
             //
             // We should probably compute the smallest unique path for each file
             // and show these as "a/README" and "b/README" when diffed against
             // one another. However, we get this wrong in a lot of places (the
             // other TOC shows two "README" files, and we generate the same anchor
             // hash for both) so I'm just stopping the bleeding until we can get
             // a proper fix in place.
         }
     }
     require_celerity_resource('phabricator-filetree-view-css');
     $filetree = array();
     $path = $tree;
     while ($path = $path->getNextNode()) {
         $data = $path->getData();
         $name = $path->getName();
         $style = 'padding-left: ' . (2 + 3 * $path->getDepth()) . 'px';
         $href = null;
         if ($data) {
             $href = '#' . $data->getAnchorName();
             $title = $name;
             $icon = 'phabricator-filetree-icon-file';
         } else {
             $name .= '/';
             $title = $path->getFullPath() . '/';
             $icon = 'phabricator-filetree-icon-dir';
         }
         $icon = phutil_render_tag('span', array('class' => 'phabricator-filetree-icon ' . $icon), '');
         $name_element = phutil_render_tag('span', array('class' => 'phabricator-filetree-name'), phutil_escape_html($name));
         $filetree[] = javelin_render_tag($href ? 'a' : 'span', array('href' => $href, 'style' => $style, 'title' => $title, 'class' => 'phabricator-filetree-item'), $icon . $name_element);
     }
     $tree->destroy();
     $filetree = '<div class="phabricator-filetree">' . implode("\n", $filetree) . '</div>';
     $nav->addFilter('toc', 'Table of Contents', '#toc');
     $nav->addCustomBlock($filetree);
     $nav->addFilter('comment', 'Add Comment', '#comment');
     $nav->setActive(true);
     return $nav;
 }