protected function renderInput()
 {
     $name = $this->getName();
     $values = nonempty($this->getValue(), array());
     assert_instances_of($values, 'PhabricatorObjectHandle');
     if ($this->getID()) {
         $id = $this->getID();
     } else {
         $id = celerity_generate_unique_node_id();
     }
     $placeholder = null;
     if (!strlen($this->placeholder)) {
         if ($this->datasource) {
             $placeholder = $this->datasource->getPlaceholderText();
         }
     } else {
         $placeholder = $this->placeholder;
     }
     $template = new AphrontTokenizerTemplateView();
     $template->setName($name);
     $template->setID($id);
     $template->setValue($values);
     $username = null;
     if ($this->user) {
         $username = $this->user->getUsername();
     }
     $datasource_uri = null;
     if ($this->datasource) {
         $datasource_uri = $this->datasource->getDatasourceURI();
     }
     if (!$this->disableBehavior) {
         Javelin::initBehavior('aphront-basic-tokenizer', array('id' => $id, 'src' => $datasource_uri, 'value' => mpull($values, 'getFullName', 'getPHID'), 'icons' => mpull($values, 'getIcon', 'getPHID'), 'limit' => $this->limit, 'username' => $username, 'placeholder' => $placeholder));
     }
     return $template->render();
 }
 public function renderPropertyViewValue(array $handles)
 {
     $requested_object = $this->getObject()->getRequestedObject();
     if (!$requested_object instanceof DifferentialRevision) {
         return null;
     }
     $diff_rev = $requested_object;
     $diffs = $diff_rev->loadRelatives(new DifferentialDiff(), 'revisionID', 'getID', 'creationMethod <> "commit"');
     $all_changesets = array();
     $most_recent_changesets = null;
     foreach ($diffs as $diff) {
         $changesets = $diff->loadRelatives(new DifferentialChangeset(), 'diffID');
         $all_changesets += $changesets;
         $most_recent_changesets = $changesets;
     }
     // The score is based on all changesets for all versions of this diff
     $all_changes = $this->countLinesAndPaths($all_changesets);
     $points = self::LINES_WEIGHT * $all_changes['code']['lines'] + self::PATHS_WEIGHT * count($all_changes['code']['paths']);
     // The blurb is just based on the most recent version of the diff
     $mr_changes = $this->countLinesAndPaths($most_recent_changesets);
     $test_tag = '';
     if ($mr_changes['tests']['paths']) {
         Javelin::initBehavior('phabricator-tooltips');
         require_celerity_resource('aphront-tooltip-css');
         $test_blurb = pht('%d line(s)', $mr_changes['tests']['lines']) . ' and ' . pht('%d path(s)', count($mr_changes['tests']['paths'])) . " contain changes to test code:\n";
         foreach ($mr_changes['tests']['paths'] as $mr_test_path) {
             $test_blurb .= pht("%s\n", $mr_test_path);
         }
         $test_tag = javelin_tag('span', array('sigil' => 'has-tooltip', 'meta' => array('tip' => $test_blurb, 'align' => 'E', 'size' => 'auto'), 'style' => ''), ' + tests');
     }
     $blurb = hsprintf('%s%s.', pht('%d line(s)', $mr_changes['code']['lines']) . ' and ' . pht('%d path(s)', count($mr_changes['code']['paths'])) . ' over ' . pht('%d diff(s)', count($diffs)), $test_tag);
     return id(new AphrontProgressBarView())->setValue($points)->setMax(self::MAX_POINTS)->setCaption($blurb)->render();
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $timer = id(new PhabricatorTimer())->load($this->id);
     if (!$timer) {
         return new Aphront404Response();
     }
     require_celerity_resource('phabricator-countdown-css');
     $chrome_visible = $request->getBool('chrome', true);
     $chrome_new = $chrome_visible ? false : null;
     $chrome_link = phutil_render_tag('a', array('href' => $request->getRequestURI()->alter('chrome', $chrome_new), 'class' => 'phabricator-timer-chrome-link'), $chrome_visible ? 'Disable Chrome' : 'Enable Chrome');
     $content = '<div class="phabricator-timer">
     <h1 class="phabricator-timer-header">' . phutil_escape_html($timer->getTitle()) . ' &middot; ' . phabricator_datetime($timer->getDatePoint(), $user) . '</h1>
     <div class="phabricator-timer-pane">
       <table class="phabricator-timer-table">
         <tr>
           <th>Days</th>
           <th>Hours</th>
           <th>Minutes</th>
           <th>Seconds</th>
         </tr>
         <tr>
           <td id="phabricator-timer-days"></td>
           <td id="phabricator-timer-hours"></td>
           <td id="phabricator-timer-minutes"></td>
           <td id="phabricator-timer-seconds"></td>
       </table>
     </div>' . $chrome_link . '</div>';
     Javelin::initBehavior('countdown-timer', array('timestamp' => $timer->getDatepoint()));
     $panel = $content;
     return $this->buildStandardPageResponse($panel, array('title' => 'Countdown: ' . $timer->getTitle(), 'chrome' => $chrome_visible));
 }
 public function buildMainMenuItems(PhabricatorUser $user, PhabricatorController $controller = null)
 {
     $application = null;
     if ($controller) {
         $application = $controller->getCurrentApplication();
     }
     $items = array();
     $help_id = celerity_generate_unique_node_id();
     Javelin::initBehavior('aphlict-dropdown', array('bubbleID' => $help_id, 'dropdownID' => 'phabricator-help-menu', 'applicationClass' => __CLASS__, 'local' => true, 'desktop' => true, 'right' => true));
     $item = id(new PHUIListItemView())->setIcon('fa-life-ring')->addClass('core-menu-item')->setID($help_id)->setOrder(200);
     $hide = true;
     if ($application) {
         $help_name = pht('%s Help', $application->getName());
         $item->setName($help_name)->setHref('/help/documentation/' . get_class($application) . '/')->setAural($help_name);
         $help_items = $application->getHelpMenuItems($user);
         if ($help_items) {
             $hide = false;
         }
     }
     if ($hide) {
         $item->setStyle('display: none');
     }
     $items[] = $item;
     return $items;
 }
 protected function renderInput()
 {
     $drop_id = celerity_generate_unique_node_id();
     Javelin::initBehavior('conpherence-drag-and-drop-photo', array('target' => $drop_id, 'form_pane' => 'conpherence-form', 'upload_uri' => '/file/dropupload/', 'activated_class' => 'conpherence-dialogue-upload-photo'));
     require_celerity_resource('conpherence-update-css');
     return phutil_tag('div', array('id' => $drop_id, 'class' => 'conpherence-dialogue-drag-photo'), pht('Drag and drop an image here to upload it.'));
 }
 private function buildPropertyView(PhameBlog $blog)
 {
     $viewer = $this->getViewer();
     require_celerity_resource('aphront-tooltip-css');
     Javelin::initBehavior('phabricator-tooltips');
     $properties = id(new PHUIPropertyListView())->setUser($viewer)->setObject($blog);
     $domain = $blog->getDomain();
     if (!$domain) {
         $domain = phutil_tag('em', array(), pht('No external domain'));
     }
     $properties->addProperty(pht('Domain'), $domain);
     $feed_uri = PhabricatorEnv::getProductionURI($this->getApplicationURI('blog/feed/' . $blog->getID() . '/'));
     $properties->addProperty(pht('Atom URI'), javelin_tag('a', array('href' => $feed_uri, 'sigil' => 'has-tooltip', 'meta' => array('tip' => pht('Atom URI does not support custom domains.'), 'size' => 320)), $feed_uri));
     $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions($viewer, $blog);
     $properties->addProperty(pht('Editable By'), $descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
     $engine = id(new PhabricatorMarkupEngine())->setViewer($viewer)->addObject($blog, PhameBlog::MARKUP_FIELD_DESCRIPTION)->process();
     $properties->invokeWillRenderEvent();
     $description = $blog->getDescription();
     if (strlen($description)) {
         $description = new PHUIRemarkupView($viewer, $description);
         $properties->addSectionHeader(pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
         $properties->addTextContent($description);
     }
     return $properties;
 }
 private function renderThumbnail(PholioImage $image)
 {
     $thumbfile = $image->getFile();
     $preview_key = PhabricatorFileThumbnailTransform::TRANSFORM_THUMBGRID;
     $xform = PhabricatorFileTransform::getTransformByKey($preview_key);
     Javelin::initBehavior('phabricator-tooltips');
     $attributes = array('class' => 'pholio-mock-thumb-grid-image', 'src' => $thumbfile->getURIForTransform($xform));
     if ($image->getFile()->isViewableImage()) {
         $dimensions = $xform->getTransformedDimensions($thumbfile);
         if ($dimensions) {
             list($x, $y) = $dimensions;
             $attributes += array('width' => $x, 'height' => $y, 'style' => 'top: ' . floor((100 - $y) / 2) . 'px');
         }
     } else {
         // If this is a PDF or a text file or something, we'll end up using a
         // generic thumbnail which is always sized correctly.
         $attributes += array('width' => 100, 'height' => 100);
     }
     $tag = phutil_tag('img', $attributes);
     $classes = array('pholio-mock-thumb-grid-item');
     if ($image->getIsObsolete()) {
         $classes[] = 'pholio-mock-thumb-grid-item-obsolete';
     }
     $inline_count = null;
     if ($image->getInlineComments()) {
         $inline_count[] = phutil_tag('span', array('class' => 'pholio-mock-thumb-grid-comment-count'), pht('%s', new PhutilNumber(count($image->getInlineComments()))));
     }
     return javelin_tag('a', array('sigil' => 'mock-thumbnail has-tooltip', 'class' => implode(' ', $classes), 'href' => '#', 'meta' => array('imageID' => $image->getID(), 'tip' => $image->getName(), 'align' => 'N')), array($tag, $inline_count));
 }
Пример #8
0
 public function render()
 {
     require_celerity_resource('aphront-form-view-css');
     Javelin::initBehavior('aphront-form-disable-on-submit');
     $layout = id(new AphrontFormLayoutView())->setBackgroundShading(true)->setPadded(true)->appendChild($this->renderDataInputs())->appendChild($this->renderChildren());
     return javelin_render_tag('form', array('action' => $this->action, 'method' => $this->method, 'enctype' => $this->encType, 'sigil' => $this->workflow ? 'workflow' : null, 'id' => $this->id), $layout->render());
 }
 public function render()
 {
     $viewer = $this->getViewer();
     if (!$viewer->isLoggedIn()) {
         return null;
     }
     $instructions_id = 'phabricator-global-drag-and-drop-upload-instructions';
     require_celerity_resource('global-drag-and-drop-css');
     $hint_text = $this->getHintText();
     if (!strlen($hint_text)) {
         $hint_text = "⇪ " . pht('Drop Files to Upload');
     }
     // Use the configured default view policy. Drag and drop uploads use
     // a more restrictive view policy if we don't specify a policy explicitly,
     // as the more restrictive policy is correct for most drop targets (like
     // Pholio uploads and Remarkup text areas).
     $view_policy = $this->getViewPolicy();
     if ($view_policy === null) {
         $view_policy = PhabricatorFile::initializeNewFile()->getViewPolicy();
     }
     $submit_uri = $this->getSubmitURI();
     $done_uri = '/file/query/authored/';
     Javelin::initBehavior('global-drag-and-drop', array('ifSupported' => $this->showIfSupportedID, 'instructions' => $instructions_id, 'uploadURI' => '/file/dropupload/', 'submitURI' => $submit_uri, 'browseURI' => $done_uri, 'viewPolicy' => $view_policy, 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold()));
     return phutil_tag('div', array('id' => $instructions_id, 'class' => 'phabricator-global-upload-instructions', 'style' => 'display: none;'), $hint_text);
 }
Пример #10
0
 public function render()
 {
     $content = $this->renderChildren();
     if (!$content) {
         return null;
     }
     require_celerity_resource('aphront-list-filter-view-css');
     $content = phutil_tag('div', array('class' => 'aphront-list-filter-view-content'), $content);
     $classes = array();
     $classes[] = 'aphront-list-filter-view';
     if ($this->showAction !== null) {
         $classes[] = 'aphront-list-filter-view-collapsible';
         Javelin::initBehavior('phabricator-reveal-content');
         $hide_action_id = celerity_generate_unique_node_id();
         $show_action_id = celerity_generate_unique_node_id();
         $content_id = celerity_generate_unique_node_id();
         $hide_action = javelin_tag('a', array('class' => 'button grey', 'sigil' => 'reveal-content', 'id' => $hide_action_id, 'href' => $this->showHideHref, 'meta' => array('hideIDs' => array($hide_action_id), 'showIDs' => array($content_id, $show_action_id))), $this->showAction);
         $content_description = phutil_tag('div', array('class' => 'aphront-list-filter-description'), $this->showHideDescription);
         $show_action = javelin_tag('a', array('class' => 'button grey', 'sigil' => 'reveal-content', 'style' => 'display: none;', 'href' => '#', 'id' => $show_action_id, 'meta' => array('hideIDs' => array($content_id, $show_action_id), 'showIDs' => array($hide_action_id))), $this->hideAction);
         $reveal_block = phutil_tag('div', array('class' => 'aphront-list-filter-reveal'), array($content_description, $hide_action, $show_action));
         $content = array($reveal_block, phutil_tag('div', array('id' => $content_id, 'style' => 'display: none;'), $content));
     }
     $content = phutil_tag('div', array('class' => implode(' ', $classes)), $content);
     return phutil_tag('div', array('class' => 'aphront-list-filter-wrap'), $content);
 }
Пример #11
0
 public function render()
 {
     require_celerity_resource('phabricator-source-code-view-css');
     require_celerity_resource('syntax-highlighting-css');
     Javelin::initBehavior('phabricator-oncopy', array());
     $line_number = $this->start;
     $rows = array();
     foreach ($this->lines as $line) {
         $hit_limit = $this->limit && $line_number == $this->limit && count($this->lines) != $this->limit;
         if ($hit_limit) {
             $content_number = '';
             $content_line = phutil_tag('span', array('class' => 'c'), pht('...'));
         } else {
             $content_number = $line_number;
             $content_line = $line;
         }
         $row_attributes = array();
         if (isset($this->highlights[$line_number])) {
             $row_attributes['class'] = 'phabricator-source-highlight';
         }
         // TODO: Provide nice links.
         $th = phutil_tag('th', array('class' => 'phabricator-source-line', 'style' => 'background-color: #fff;'), $content_number);
         $td = phutil_tag('td', array('class' => 'phabricator-source-code'), $content_line);
         $rows[] = phutil_tag('tr', $row_attributes, array($th, $td));
         if ($hit_limit) {
             break;
         }
         $line_number++;
     }
     $classes = array();
     $classes[] = 'phabricator-source-code-view';
     $classes[] = 'remarkup-code';
     $classes[] = 'PhabricatorMonospaced';
     return phutil_tag('div', array('class' => 'phabricator-source-code-container', 'style' => 'background-color: black; color: white;'), phutil_tag('table', array('class' => implode(' ', $classes), 'style' => 'background-color: black'), phutil_implode_html('', $rows)));
 }
 protected function getTagAttributes()
 {
     $classes = array('phui-segment-bar-segment-view');
     if ($this->color) {
         $classes[] = $this->color;
     }
     // Convert width to a percentage, and round it up slightly so that bars
     // are full if they have, e.g., three segments at 1/3 + 1/3 + 1/3.
     $width = 100 * $this->width;
     $width = ceil(100 * $width) / 100;
     $width = sprintf('%.2f%%', $width);
     $left = 100 * $this->position;
     $left = floor(100 * $left) / 100;
     $left = sprintf('%.2f%%', $left);
     $tooltip = $this->tooltip;
     if (strlen($tooltip)) {
         Javelin::initBehavior('phabricator-tooltips');
         $sigil = 'has-tooltip';
         $meta = array('tip' => $tooltip, 'align' => 'E');
     } else {
         $sigil = null;
         $meta = null;
     }
     return array('class' => implode(' ', $classes), 'style' => "left: {$left}; width: {$width};", 'sigil' => $sigil, 'meta' => $meta);
 }
 /**
  * Format the tasks data for display on the page.
  *
  * @returns PHUIObjectBoxView
  */
 public function buildTasksTable()
 {
     Javelin::initBehavior('tasks-table', array(), 'sprint');
     $table = id(new SprintTableView($this->tableData->getRows()))->setHeaders(array(pht('Task'), pht('Epoch Created'), pht('Date Created'), pht('Epoch Updated'), pht('Last Update'), pht('Assigned to'), pht('NumPriority'), pht('Priority'), pht('Points'), pht('Status')))->setTableId('tasks-list')->setClassName('display')->setColumnVisibility(array(true, true, true, true, true, true, true, true, true, true));
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Tasks in this Sprint'))->setTable($table);
     return $box;
 }
 public function render()
 {
     require_celerity_resource('differential-changeset-view-css');
     require_celerity_resource('syntax-highlighting-css');
     if ($this->revisionID) {
         $edit = true;
     } else {
         $edit = false;
     }
     $changeset = $this->changeset;
     $class = 'differential-changeset';
     if (!$edit) {
         $class .= ' differential-changeset-immutable';
     }
     $buttons = null;
     if ($this->buttons) {
         $buttons = '<div class="differential-changeset-buttons">' . implode('', $this->buttons) . '</div>';
     }
     $id = $this->getID();
     if ($this->symbolIndex) {
         Javelin::initBehavior('repository-crossreference', array('container' => $id) + $this->symbolIndex);
     }
     $display_filename = $changeset->getDisplayFilename();
     $output = javelin_render_tag('div', array('sigil' => 'differential-changeset', 'meta' => array('left' => $this->changeset->getID(), 'right' => $this->changeset->getID()), 'class' => $class, 'id' => $id), phutil_render_tag('a', array('name' => $changeset->getAnchorName()), '') . $buttons . '<h1>' . phutil_escape_html($display_filename) . '</h1>' . '<div style="clear: both;"></div>' . $this->renderChildren());
     return $output;
 }
 protected function renderInput()
 {
     $name = $this->getName();
     $values = nonempty($this->getValue(), array());
     if ($this->getID()) {
         $id = $this->getID();
     } else {
         $id = celerity_generate_unique_node_id();
     }
     $placeholder = null;
     if (!$this->placeholder) {
         $placeholder = $this->getDefaultPlaceholder();
     }
     $template = new AphrontTokenizerTemplateView();
     $template->setName($name);
     $template->setID($id);
     $template->setValue($values);
     $username = null;
     if ($this->user) {
         $username = $this->user->getUsername();
     }
     if (!$this->disableBehavior) {
         Javelin::initBehavior('aphront-basic-tokenizer', array('id' => $id, 'src' => $this->datasource, 'value' => $values, 'limit' => $this->limit, 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'username' => $username, 'placeholder' => $placeholder));
     }
     return $template->render();
 }
Пример #16
0
 private function renderNotificationMenu()
 {
     $user = $this->user;
     require_celerity_resource('phabricator-notification-css');
     require_celerity_resource('phabricator-notification-menu-css');
     $indicator_id = celerity_generate_unique_node_id();
     $dropdown_id = celerity_generate_unique_node_id();
     $menu_id = celerity_generate_unique_node_id();
     $notification_count = id(new PhabricatorFeedStoryNotification())->countUnread($user);
     $classes = array('phabricator-main-menu-alert-indicator');
     if ($notification_count) {
         $classes[] = 'phabricator-main-menu-alert-indicator-unread';
     }
     $notification_indicator = javelin_render_tag('span', array('id' => $indicator_id, 'class' => implode(' ', $classes)), $notification_count);
     $classes = array();
     $classes[] = 'phabricator-main-menu-alert-item';
     $classes[] = 'phabricator-main-menu-alert-item-notification';
     $classes[] = 'autosprite';
     $classes[] = 'main-menu-item-icon-notifications';
     $notification_icon = javelin_render_tag('a', array('href' => '/notification/', 'class' => implode(' ', $classes), 'id' => $menu_id), $notification_indicator);
     $notification_menu = javelin_render_tag('div', array('class' => 'phabricator-main-menu-alert'), $notification_icon);
     Javelin::initBehavior('aphlict-dropdown', array('menuID' => $menu_id, 'indicatorID' => $indicator_id, 'dropdownID' => $dropdown_id));
     $notification_dropdown = javelin_render_tag('div', array('id' => $dropdown_id, 'class' => 'phabricator-notification-menu', 'sigil' => 'phabricator-notification-menu', 'style' => 'display: none;'), '');
     return array($notification_menu, $notification_dropdown);
 }
 protected function processDiffusionRequest(AphrontRequest $request)
 {
     $user = $request->getUser();
     $drequest = $this->getDiffusionRequest();
     $callsign = $drequest->getRepository()->getCallsign();
     $repository = $drequest->getRepository();
     $commit = $drequest->loadCommit();
     $data = $commit->loadCommitData();
     $page_title = pht('Edit Diffusion Commit');
     if (!$commit) {
         return new Aphront404Response();
     }
     $commit_phid = $commit->getPHID();
     $edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
     $current_proj_phids = PhabricatorEdgeQuery::loadDestinationPHIDs($commit_phid, $edge_type);
     if ($request->isFormPost()) {
         $xactions = array();
         $proj_phids = $request->getArr('projects');
         $xactions[] = id(new PhabricatorAuditTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $edge_type)->setNewValue(array('=' => array_fuse($proj_phids)));
         $editor = id(new PhabricatorAuditEditor())->setActor($user)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request);
         $xactions = $editor->applyTransactions($commit, $xactions);
         return id(new AphrontRedirectResponse())->setURI('/r' . $callsign . $commit->getCommitIdentifier());
     }
     $tokenizer_id = celerity_generate_unique_node_id();
     $form = id(new AphrontFormView())->setUser($user)->setAction($request->getRequestURI()->getPath())->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Projects'))->setName('projects')->setValue($current_proj_phids)->setID($tokenizer_id)->setCaption(javelin_tag('a', array('href' => '/project/create/', 'mustcapture' => true, 'sigil' => 'project-create'), pht('Create New Project')))->setDatasource(new PhabricatorProjectDatasource()));
     $reason = $data->getCommitDetail('autocloseReason', false);
     $reason = PhabricatorRepository::BECAUSE_AUTOCLOSE_FORCED;
     if ($reason !== false) {
         switch ($reason) {
             case PhabricatorRepository::BECAUSE_REPOSITORY_IMPORTING:
                 $desc = pht('No, Repository Importing');
                 break;
             case PhabricatorRepository::BECAUSE_AUTOCLOSE_DISABLED:
                 $desc = pht('No, Autoclose Disabled');
                 break;
             case PhabricatorRepository::BECAUSE_NOT_ON_AUTOCLOSE_BRANCH:
                 $desc = pht('No, Not On Autoclose Branch');
                 break;
             case PhabricatorRepository::BECAUSE_AUTOCLOSE_FORCED:
                 $desc = pht('Yes, Forced Via bin/repository CLI Tool.');
                 break;
             case null:
                 $desc = pht('Yes');
                 break;
             default:
                 $desc = pht('Unknown');
                 break;
         }
         $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: Autoclose');
         $doc_link = phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Learn More'));
         $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Autoclose?'))->setValue(array($desc, " · ", $doc_link)));
     }
     Javelin::initBehavior('project-create', array('tokenizerID' => $tokenizer_id));
     $submit = id(new AphrontFormSubmitControl())->setValue(pht('Save'))->addCancelButton('/r' . $callsign . $commit->getCommitIdentifier());
     $form->appendChild($submit);
     $crumbs = $this->buildCrumbs(array('commit' => true));
     $crumbs->addTextCrumb(pht('Edit'));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText($page_title)->setForm($form);
     return $this->buildApplicationPage(array($crumbs, $form_box), array('title' => $page_title));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $project = id(new PhabricatorProjectQuery())->setViewer($viewer)->withIDs(array($this->id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$project) {
         return new Aphront404Response();
     }
     $edit_uri = $this->getApplicationURI('edit/' . $project->getID() . '/');
     require_celerity_resource('project-icon-css');
     Javelin::initBehavior('phabricator-tooltips');
     $project_icons = PhabricatorProjectIcon::getIconMap();
     if ($request->isFormPost()) {
         $v_icon = $request->getStr('icon');
         return id(new AphrontAjaxResponse())->setContent(array('value' => $v_icon, 'display' => PhabricatorProjectIcon::renderIconForChooser($v_icon)));
     }
     $ii = 0;
     $buttons = array();
     foreach ($project_icons as $icon => $label) {
         $view = id(new PHUIIconView())->setIconFont($icon);
         $aural = javelin_tag('span', array('aural' => true), pht('Choose "%s" Icon', $label));
         if ($icon == $project->getIcon()) {
             $class_extra = ' selected';
         } else {
             $class_extra = null;
         }
         $buttons[] = javelin_tag('button', array('class' => 'icon-button' . $class_extra, 'name' => 'icon', 'value' => $icon, 'type' => 'submit', 'sigil' => 'has-tooltip', 'meta' => array('tip' => $label)), array($aural, $view));
         if (++$ii % 4 == 0) {
             $buttons[] = phutil_tag('br');
         }
     }
     $buttons = phutil_tag('div', array('class' => 'icon-grid'), $buttons);
     return $this->newDialog()->setTitle(pht('Choose Project Icon'))->appendChild($buttons)->addCancelButton($edit_uri);
 }
Пример #19
0
 public function buildResponseString()
 {
     $console = $this->getConsole();
     if ($console) {
         // NOTE: We're stripping query parameters here both for readability and
         // to mitigate BREACH and similar attacks. The parameters are available
         // in the "Request" tab, so this should not impact usability. See T3684.
         $uri = $this->getRequest()->getRequestURI();
         $uri = new PhutilURI($uri);
         $uri->setQueryParams(array());
         Javelin::initBehavior('dark-console', array('uri' => (string) $uri, 'key' => $console->getKey($this->getRequest()), 'color' => $console->getColor(), 'quicksand' => $this->getRequest()->isQuicksand()));
     }
     // Flatten the response first, so we initialize any behaviors and metadata
     // we need to.
     $content = array('payload' => $this->content);
     $this->encodeJSONForHTTPResponse($content);
     $response = CelerityAPI::getStaticResourceResponse();
     $request = $this->getRequest();
     if ($request) {
         $viewer = $request->getViewer();
         if ($viewer) {
             $postprocessor_key = $viewer->getUserSetting(PhabricatorAccessibilitySetting::SETTINGKEY);
             if (strlen($postprocessor_key)) {
                 $response->setPostprocessorKey($postprocessor_key);
             }
         }
     }
     $object = $response->buildAjaxResponse($content['payload'], $this->error);
     $response_json = $this->encodeJSONForHTTPResponse($object);
     return $this->addJSONShield($response_json);
 }
 protected function renderInput()
 {
     Javelin::initBehavior('choose-control');
     $set = $this->getIconSet();
     $input_id = celerity_generate_unique_node_id();
     $display_id = celerity_generate_unique_node_id();
     $is_disabled = $this->getDisabled();
     $classes = array();
     $classes[] = 'button';
     $classes[] = 'grey';
     if ($is_disabled) {
         $classes[] = 'disabled';
     }
     $button = javelin_tag('a', array('href' => '#', 'class' => implode(' ', $classes), 'sigil' => 'phui-form-iconset-button'), $set->getChooseButtonText());
     $icon = $set->getIcon($this->getValue());
     if ($icon) {
         $display = $set->renderIconForControl($icon);
     } else {
         $display = null;
     }
     $display_cell = phutil_tag('td', array('class' => 'phui-form-iconset-display-cell', 'id' => $display_id), $display);
     $button_cell = phutil_tag('td', array('class' => 'phui-form-iconset-button-cell'), $button);
     $row = phutil_tag('tr', array(), array($display_cell, $button_cell));
     $layout = javelin_tag('table', array('class' => 'phui-form-iconset-table', 'sigil' => 'phui-form-iconset', 'meta' => array('uri' => $set->getSelectURI(), 'inputID' => $input_id, 'displayID' => $display_id)), $row);
     $hidden_input = phutil_tag('input', array('type' => 'hidden', 'disabled' => $is_disabled ? 'disabled' : null, 'name' => $this->getName(), 'value' => $this->getValue(), 'id' => $input_id));
     return array($hidden_input, $layout);
 }
 protected function getTagContent()
 {
     if ($this->previewURI === null) {
         throw new PhutilInvalidStateException('setPreviewURI');
     }
     if ($this->controlID === null) {
         throw new PhutilInvalidStateException('setControlID');
     }
     $preview_id = celerity_generate_unique_node_id();
     require_celerity_resource('phui-remarkup-preview-css');
     Javelin::initBehavior('remarkup-preview', array('previewID' => $preview_id, 'controlID' => $this->controlID, 'uri' => $this->previewURI));
     $loading = phutil_tag('div', array('class' => 'phui-preview-loading-text'), nonempty($this->loadingText, pht('Loading preview...')));
     $preview = phutil_tag('div', array('id' => $preview_id, 'class' => 'phabricator-remarkup phui-preview-body'), $loading);
     if (!$this->previewType) {
         $header = null;
         if ($this->header) {
             $header = phutil_tag('div', array('class' => 'phui-preview-header'), $this->header);
         }
         $content = array($header, $preview);
     } else {
         if ($this->previewType == self::DOCUMENT) {
             $header = id(new PHUIHeaderView())->setHeader(pht('%s (Preview)', $this->header));
             $content = id(new PHUIDocumentViewPro())->setHeader($header)->appendChild($preview);
         }
     }
     return id(new PHUIObjectBoxView())->appendChild($content)->setCollapsed(true);
 }
Пример #22
0
 public function handleRequest(AphrontRequest $request)
 {
     $user = $request->getUser();
     $id = $request->getURIData('id');
     if ($id) {
         $post = id(new PhamePostQuery())->setViewer($user)->withIDs(array($id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
         if (!$post) {
             return new Aphront404Response();
         }
         $cancel_uri = $this->getApplicationURI('/post/view/' . $id . '/');
         $submit_button = pht('Save Changes');
         $page_title = pht('Edit Post');
     } else {
         $blog = id(new PhameBlogQuery())->setViewer($user)->withIDs(array($request->getInt('blog')))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_JOIN))->executeOne();
         if (!$blog) {
             return new Aphront404Response();
         }
         $post = PhamePost::initializePost($user, $blog);
         $cancel_uri = $this->getApplicationURI('/blog/view/' . $blog->getID() . '/');
         $submit_button = pht('Save Draft');
         $page_title = pht('Create Post');
     }
     $title = $post->getTitle();
     $phame_title = $post->getPhameTitle();
     $body = $post->getBody();
     $comments_widget = $post->getCommentsWidget();
     $e_title = true;
     $e_phame_title = true;
     $validation_exception = null;
     if ($request->isFormPost()) {
         $title = $request->getStr('title');
         $phame_title = $request->getStr('phame_title');
         $phame_title = PhabricatorSlug::normalize($phame_title);
         $body = $request->getStr('body');
         $comments_widget = $request->getStr('comments_widget');
         $xactions = array(id(new PhamePostTransaction())->setTransactionType(PhamePostTransaction::TYPE_TITLE)->setNewValue($title), id(new PhamePostTransaction())->setTransactionType(PhamePostTransaction::TYPE_PHAME_TITLE)->setNewValue($phame_title), id(new PhamePostTransaction())->setTransactionType(PhamePostTransaction::TYPE_BODY)->setNewValue($body), id(new PhamePostTransaction())->setTransactionType(PhamePostTransaction::TYPE_COMMENTS_WIDGET)->setNewValue($comments_widget));
         $editor = id(new PhamePostEditor())->setActor($user)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true);
         try {
             $editor->applyTransactions($post, $xactions);
             $uri = $this->getApplicationURI('/post/view/' . $post->getID() . '/');
             return id(new AphrontRedirectResponse())->setURI($uri);
         } catch (PhabricatorApplicationTransactionValidationException $ex) {
             $validation_exception = $ex;
             $e_title = $validation_exception->getShortMessage(PhamePostTransaction::TYPE_TITLE);
             $e_phame_title = $validation_exception->getShortMessage(PhamePostTransaction::TYPE_PHAME_TITLE);
         }
     }
     $handle = id(new PhabricatorHandleQuery())->setViewer($user)->withPHIDs(array($post->getBlogPHID()))->executeOne();
     $form = id(new AphrontFormView())->setUser($user)->addHiddenInput('blog', $request->getInt('blog'))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Blog'))->setValue($handle->renderLink()))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Title'))->setName('title')->setValue($title)->setID('post-title')->setError($e_title))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Phame Title'))->setName('phame_title')->setValue(rtrim($phame_title, '/'))->setID('post-phame-title')->setCaption(pht('Up to 64 alphanumeric characters ' . 'with underscores for spaces. ' . 'Formatting is enforced.'))->setError($e_phame_title))->appendChild(id(new PhabricatorRemarkupControl())->setLabel(pht('Body'))->setName('body')->setValue($body)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setID('post-body')->setUser($user)->setDisableMacros(true))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Comments Widget'))->setName('comments_widget')->setvalue($comments_widget)->setOptions($post->getCommentsWidgetOptionsForSelect()))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button));
     $loading = phutil_tag_div('aphront-panel-preview-loading-text', pht('Loading preview...'));
     $preview_panel = phutil_tag_div('aphront-panel-preview', array(phutil_tag_div('phame-post-preview-header', pht('Post Preview')), phutil_tag('div', array('id' => 'post-preview'), $loading)));
     require_celerity_resource('phame-css');
     Javelin::initBehavior('phame-post-preview', array('preview' => 'post-preview', 'body' => 'post-body', 'title' => 'post-title', 'phame_title' => 'post-phame-title', 'uri' => '/phame/post/preview/'));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText($page_title)->setValidationException($validation_exception)->setForm($form);
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb($page_title, $this->getApplicationURI('/post/view/' . $id . '/'));
     $nav = $this->renderSideNavFilterView(null);
     $nav->appendChild(array($crumbs, $form_box, $preview_panel));
     return $this->buildApplicationPage($nav, array('title' => $page_title));
 }
Пример #23
0
 protected function getTagContent()
 {
     require_celerity_resource('phui-document-view-css');
     require_celerity_resource('phui-document-view-pro-css');
     Javelin::initBehavior('phabricator-reveal-content');
     $classes = array();
     $classes[] = 'phui-document-view';
     $classes[] = 'phui-document-view-pro';
     $book = null;
     if ($this->bookname) {
         $book = pht('%s (%s)', $this->bookname, $this->bookdescription);
     }
     $main_content = $this->renderChildren();
     if ($book) {
         $this->header->setSubheader($book);
     }
     $table_of_contents = null;
     if ($this->toc) {
         $toc = array();
         $toc_id = celerity_generate_unique_node_id();
         $toc[] = id(new PHUIButtonView())->setTag('a')->setIconFont('fa-align-left')->setColor(PHUIButtonView::SIMPLE)->addClass('phui-document-toc')->addSigil('jx-toggle-class')->setMetaData(array('map' => array($toc_id => 'phui-document-toc-open')));
         $toc[] = phutil_tag('div', array('class' => 'phui-list-sidenav phui-document-toc-list'), $this->toc);
         $table_of_contents = phutil_tag('div', array('class' => 'phui-document-toc-container', 'id' => $toc_id), $toc);
     }
     $content_inner = phutil_tag('div', array('class' => 'phui-document-inner'), array($table_of_contents, $this->header, $main_content));
     $content = phutil_tag('div', array('class' => 'phui-document-content'), $content_inner);
     $view = phutil_tag('div', array('class' => implode(' ', $classes)), $content);
     $list = null;
     if ($this->propertyList) {
         $list = phutil_tag_div('phui-document-properties', $this->propertyList);
     }
     return array($view, $list);
 }
 public function render()
 {
     $viewer = $this->getViewer();
     $this->requireResource('differential-revision-add-comment-css');
     $revision = $this->revision;
     $action = null;
     if ($this->draft) {
         $action = idx($this->draft->getMetadata(), 'action');
     }
     $enable_reviewers = DifferentialAction::allowReviewers($action);
     $enable_ccs = $action == DifferentialAction::ACTION_ADDCCS;
     $add_reviewers_labels = array('add_reviewers' => pht('Add Reviewers'), 'request_review' => pht('Add Reviewers'), 'resign' => pht('Suggest Reviewers'));
     $mailable_source = new PhabricatorMetaMTAMailableDatasource();
     // TODO: This should be a reviewers datasource, but it's a mess.
     $reviewer_source = new PhabricatorMetaMTAMailableDatasource();
     $form = new AphrontFormView();
     $form->setWorkflow(true)->setViewer($viewer)->setAction($this->actionURI)->addHiddenInput('revision_id', $revision->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Action'))->setName('action')->setValue($action)->setID('comment-action')->setOptions($this->actions))->appendControl(id(new AphrontFormTokenizerControl())->setLabel($enable_reviewers ? $add_reviewers_labels[$action] : $add_reviewers_labels['add_reviewers'])->setName('reviewers')->setControlID('add-reviewers')->setControlStyle($enable_reviewers ? null : 'display: none')->setID('add-reviewers-tokenizer')->setDisableBehavior(true)->setDatasource($reviewer_source))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Add Subscribers'))->setName('ccs')->setControlID('add-ccs')->setControlStyle($enable_ccs ? null : 'display: none')->setID('add-ccs-tokenizer')->setDisableBehavior(true)->setDatasource($mailable_source))->appendChild(id(new PhabricatorRemarkupControl())->setName('comment')->setID('comment-content')->setLabel(pht('Comment'))->setValue($this->draft ? $this->draft->getDraft() : null)->setViewer($viewer))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Submit')));
     Javelin::initBehavior('differential-add-reviewers-and-ccs', array('dynamic' => array('add-reviewers-tokenizer' => array('actions' => array('request_review' => 1, 'add_reviewers' => 1, 'resign' => 1), 'src' => $reviewer_source->getDatasourceURI(), 'value' => $this->reviewers, 'row' => 'add-reviewers', 'labels' => $add_reviewers_labels, 'placeholder' => $reviewer_source->getPlaceholderText()), 'add-ccs-tokenizer' => array('actions' => array('add_ccs' => 1), 'src' => $mailable_source->getDatasourceURI(), 'value' => $this->ccs, 'row' => 'add-ccs', 'placeholder' => $mailable_source->getPlaceholderText())), 'select' => 'comment-action'));
     $diff = $revision->loadActiveDiff();
     $rev_id = $revision->getID();
     Javelin::initBehavior('differential-feedback-preview', array('uri' => '/differential/comment/preview/' . $rev_id . '/', 'preview' => 'comment-preview', 'action' => 'comment-action', 'content' => 'comment-content', 'previewTokenizers' => array('reviewers' => 'add-reviewers-tokenizer', 'ccs' => 'add-ccs-tokenizer'), 'inlineuri' => '/differential/comment/inline/preview/' . $rev_id . '/', 'inline' => 'inline-comment-preview'));
     $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
     $header_text = $is_serious ? pht('Add Comment') : pht('Leap Into Action!');
     $header = id(new PHUIHeaderView())->setHeader($header_text);
     $anchor = id(new PhabricatorAnchorView())->setAnchorName('comment')->setNavigationMarker(true);
     $loading = phutil_tag('span', array('class' => 'aphront-panel-preview-loading-text'), pht('Loading comment preview...'));
     $preview = phutil_tag_div('aphront-panel-preview aphront-panel-flush', array(phutil_tag('div', array('id' => 'comment-preview'), $loading), phutil_tag('div', array('id' => 'inline-comment-preview'))));
     $comment_box = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($anchor)->appendChild($form);
     if ($this->errorView) {
         $comment_box->setInfoView($this->errorView);
     }
     return array($comment_box, $preview);
 }
 protected function getTagContent()
 {
     if ($this->previewURI === null) {
         throw new PhutilInvalidStateException('setPreviewURI');
     }
     if ($this->controlID === null) {
         throw new PhutilInvalidStateException('setControlID');
     }
     $preview_id = celerity_generate_unique_node_id();
     require_celerity_resource('phui-remarkup-preview-css');
     Javelin::initBehavior('remarkup-preview', array('previewID' => $preview_id, 'controlID' => $this->controlID, 'uri' => $this->previewURI));
     $loading = phutil_tag('div', array('class' => 'phui-preview-loading-text'), nonempty($this->loadingText, pht('Loading preview...')));
     $header = null;
     if ($this->header) {
         $header = phutil_tag('div', array('class' => 'phui-preview-header'), $this->header);
     }
     $preview = phutil_tag('div', array('id' => $preview_id, 'class' => 'phabricator-remarkup'), $loading);
     $content = array($header, $preview);
     switch ($this->skin) {
         case 'document':
             $content = id(new PHUIDocumentView())->appendChild($content)->setFontKit(PHUIDocumentView::FONT_SOURCE_SANS);
             break;
         default:
             $content = id(new PHUIBoxView())->appendChild($content)->setBorder(true)->addMargin(PHUI::MARGIN_LARGE)->addPadding(PHUI::PADDING_LARGE)->addClass('phui-panel-preview');
             break;
     }
     return $content;
 }
 public function getTokensForTask($task)
 {
     $tokens_given = id(new PhabricatorTokenGivenQuery())->setViewer($this->viewer)->withObjectPHIDs(array($task->getPHID()))->execute();
     if (!$tokens_given) {
         return null;
     }
     $tokens = id(new PhabricatorTokenQuery())->setViewer($this->viewer)->withPHIDs(mpull($tokens_given, 'getTokenPHID'))->execute();
     $tokens = mpull($tokens, null, 'getPHID');
     $author_phids = mpull($tokens_given, 'getAuthorPHID');
     $handles = id(new PhabricatorHandleQuery())->setViewer($this->viewer)->withPHIDs($author_phids)->execute();
     Javelin::initBehavior('phabricator-tooltips');
     $list = array();
     foreach ($tokens_given as $token_given) {
         if (!idx($tokens, $token_given->getTokenPHID())) {
             continue;
         }
         $token = $tokens[$token_given->getTokenPHID()];
         $aural = javelin_tag('span', array('aural' => true), pht('"%s" token, awarded by %s.', $token->getName(), $handles[$token_given->getAuthorPHID()]->getName()));
         $tokenslabel = 'Tokens:';
         $tokensvalue = phutil_tag('dd', array('class' => 'phui-card-list-value'), array($token->renderIcon(), ' '));
         $tokenskey = phutil_tag('dt', array('class' => 'phui-card-list-key'), array($tokenslabel, ' '));
         $list[] = javelin_tag('dl', array('sigil' => 'has-tooltip', 'class' => 'token-icon', 'meta' => array('tip' => $handles[$token_given->getAuthorPHID()]->getName())), array($aural, $tokenskey, $tokensvalue));
     }
     return $list;
 }
 public function renderEditControl(array $handles)
 {
     $engines = id(new PhutilSymbolLoader())->setAncestorClass('PhabricatorApplicationSearchEngine')->loadObjects();
     $value = $this->getFieldValue();
     $queries = array();
     $seen = false;
     foreach ($engines as $engine_class => $engine) {
         $engine->setViewer($this->getViewer());
         $engine_queries = $engine->loadEnabledNamedQueries();
         $query_map = mpull($engine_queries, 'getQueryName', 'getQueryKey');
         asort($query_map);
         foreach ($query_map as $key => $name) {
             $queries[$engine_class][] = array('key' => $key, 'name' => $name);
             if ($key == $value) {
                 $seen = true;
             }
         }
     }
     if (strlen($value) && !$seen) {
         $name = pht('Custom Query ("%s")', $value);
     } else {
         $name = pht('(None)');
     }
     $options = array($value => $name);
     $app_control_key = $this->getFieldConfigValue('control.application');
     Javelin::initBehavior('dashboard-query-panel-select', array('applicationID' => $this->getFieldControlID($app_control_key), 'queryID' => $this->getFieldControlID(), 'options' => $queries, 'value' => array('key' => strlen($value) ? $value : null, 'name' => $name)));
     return id(new AphrontFormSelectControl())->setID($this->getFieldControlID())->setLabel($this->getFieldName())->setCaption($this->getCaption())->setName($this->getFieldKey())->setValue($this->getFieldValue())->setOptions($options);
 }
 private function renderTransactionInfo()
 {
     $info = array();
     if ($this->contentSource) {
         $content_source = new PhabricatorContentSourceView();
         $content_source->setContentSource($this->contentSource);
         $content_source->setUser($this->user);
         $source = $content_source->render();
         if ($source) {
             $info[] = $source;
         }
     }
     if ($this->isPreview) {
         $info[] = 'PREVIEW';
     } else {
         if ($this->epoch) {
             $info[] = phabricator_datetime($this->epoch, $this->user);
         }
     }
     if ($this->anchorName) {
         Javelin::initBehavior('phabricator-watch-anchor');
         $anchor = id(new PhabricatorAnchorView())->setAnchorName($this->anchorName)->render();
         $info[] = hsprintf('%s%s', $anchor, phutil_tag('a', array('href' => '#' . $this->anchorName), $this->anchorText));
     }
     $info = phutil_implode_html(" · ", $info);
     return phutil_tag('span', array('class' => 'phabricator-transaction-info'), $info);
 }
 public function render()
 {
     $rows = array();
     $any_hidden = false;
     foreach ($this->rows as $row) {
         $style = idx($row, 'style');
         switch ($style) {
             case 'section':
                 $cells = phutil_render_tag('th', array('colspan' => 2), idx($row, 'name'));
                 break;
             default:
                 $name = phutil_render_tag('th', array(), idx($row, 'name'));
                 $value = phutil_render_tag('td', array(), idx($row, 'value'));
                 $cells = $name . $value;
                 break;
         }
         $show = idx($row, 'show');
         $rows[] = javelin_render_tag('tr', array('style' => $show ? null : 'display: none', 'sigil' => $show ? null : 'differential-results-row-toggle', 'class' => 'differential-results-row-' . $style), $cells);
         if (!$show) {
             $any_hidden = true;
         }
     }
     if ($any_hidden) {
         $show_more = javelin_render_tag('a', array('href' => '#', 'mustcapture' => true), $this->showMoreString);
         $hide_more = javelin_render_tag('a', array('href' => '#', 'mustcapture' => true), 'Hide');
         $rows[] = javelin_render_tag('tr', array('class' => 'differential-results-row-show', 'sigil' => 'differential-results-row-show'), '<th colspan="2">' . $show_more . '</td>');
         $rows[] = javelin_render_tag('tr', array('class' => 'differential-results-row-show', 'sigil' => 'differential-results-row-hide', 'style' => 'display: none'), '<th colspan="2">' . $hide_more . '</th>');
         Javelin::initBehavior('differential-show-field-details');
     }
     require_celerity_resource('differential-results-table-css');
     return javelin_render_tag('table', array('class' => 'differential-results-table', 'sigil' => 'differential-results-table'), implode("\n", $rows));
 }
 public function render()
 {
     $this->requireResource('differential-core-view-css');
     $this->requireResource('differential-table-of-contents-css');
     $this->requireResource('phui-text-css');
     Javelin::initBehavior('phabricator-tooltips');
     $items = $this->items;
     $rows = array();
     foreach ($items as $item) {
         $item->setUser($this->getUser());
         $rows[] = $item->render();
     }
     // Check if any item has content in these columns. If no item does, we'll
     // just hide them.
     $any_coverage = false;
     $any_context = false;
     $any_package = false;
     foreach ($items as $item) {
         if ($item->getContext() !== null) {
             $any_context = true;
         }
         if (strlen($item->getCoverage())) {
             $any_coverage = true;
         }
         if ($item->getPackage() !== null) {
             $any_package = true;
         }
     }
     $reveal_link = javelin_tag('a', array('sigil' => 'differential-reveal-all', 'mustcapture' => true, 'class' => 'button differential-toc-reveal-all'), pht('Show All Context'));
     $buttons = phutil_tag('div', array('class' => 'differential-toc-buttons grouped'), $reveal_link);
     $table = id(new AphrontTableView($rows))->setHeaders(array(null, null, null, null, pht('Path'), pht('Coverage (All)'), pht('Coverage (Touched)'), null))->setColumnClasses(array('center', 'differential-toc-char center', 'differential-toc-prop center', 'differential-toc-ftype center', 'differential-toc-file wide', 'differential-toc-cov', 'differential-toc-cov', 'center'))->setColumnVisibility(array($any_context, true, true, true, true, $any_coverage, $any_coverage, $any_package))->setDeviceVisibility(array(true, true, true, true, true, false, false, true));
     $anchor = id(new PhabricatorAnchorView())->setAnchorName('toc')->setNavigationMarker(true);
     return id(new PHUIObjectBoxView())->setHeaderText(pht('Table of Contents'))->setTable($table)->appendChild($anchor)->appendChild($buttons);
 }