diff --git a/src/applications/diviner/controller/DivinerBookController.php b/src/applications/diviner/controller/DivinerBookController.php index 11d6a5bbfc..74b2a8f3d9 100644 --- a/src/applications/diviner/controller/DivinerBookController.php +++ b/src/applications/diviner/controller/DivinerBookController.php @@ -1,136 +1,128 @@ getViewer(); $book_name = $request->getURIData('book'); $book = id(new DivinerBookQuery()) ->setViewer($viewer) ->withNames(array($book_name)) ->needRepositories(true) ->executeOne(); if (!$book) { return new Aphront404Response(); } $actions = $this->buildActionView($viewer, $book); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); $crumbs->addTextCrumb( $book->getShortTitle(), '/book/'.$book->getName().'/'); - $action_button = id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('Actions')) - ->setHref('#') - ->setIcon('fa-bars') - ->addClass('phui-mobile-menu') - ->setDropdownMenu($actions); - $header = id(new PHUIHeaderView()) ->setHeader($book->getTitle()) ->setUser($viewer) ->setPolicyObject($book) ->setEpoch($book->getDateModified()) - ->addActionLink($action_button); + ->setActionList($actions); // TODO: This could probably look better. if ($book->getRepositoryPHID()) { $header->addTag( id(new PHUITagView()) ->setType(PHUITagView::TYPE_STATE) ->setBackgroundColor(PHUITagView::COLOR_BLUE) ->setName($book->getRepository()->getMonogram())); } $document = new PHUIDocumentViewPro(); $document->setHeader($header); $document->addClass('diviner-view'); $atoms = id(new DivinerAtomQuery()) ->setViewer($viewer) ->withBookPHIDs(array($book->getPHID())) ->withGhosts(false) ->withIsDocumentable(true) ->execute(); $atoms = msort($atoms, 'getSortKey'); $group_spec = $book->getConfig('groups'); if (!is_array($group_spec)) { $group_spec = array(); } $groups = mgroup($atoms, 'getGroupName'); $groups = array_select_keys($groups, array_keys($group_spec)) + $groups; if (isset($groups[''])) { $no_group = $groups['']; unset($groups['']); $groups[''] = $no_group; } $out = array(); foreach ($groups as $group => $atoms) { $group_name = $book->getGroupName($group); if (!strlen($group_name)) { $group_name = pht('Free Radicals'); } $section = id(new DivinerSectionView()) ->setHeader($group_name); $section->addContent($this->renderAtomList($atoms)); $out[] = $section; } $preface = $book->getPreface(); $preface_view = null; if (strlen($preface)) { $preface_view = new PHUIRemarkupView($viewer, $preface); } $document->appendChild($preface_view); $document->appendChild($out); return $this->buildApplicationPage( array( $crumbs, $document, ), array( 'title' => $book->getTitle(), )); } private function buildActionView( PhabricatorUser $user, DivinerLiveBook $book) { $can_edit = PhabricatorPolicyFilter::hasCapability( $user, $book, PhabricatorPolicyCapability::CAN_EDIT); $action_view = id(new PhabricatorActionListView()) ->setUser($user) ->setObject($book); $action_view->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Book')) ->setIcon('fa-pencil') ->setHref('/book/'.$book->getName().'/edit/') ->setDisabled(!$can_edit)); return $action_view; } } diff --git a/src/applications/phame/controller/blog/PhameBlogViewController.php b/src/applications/phame/controller/blog/PhameBlogViewController.php index 60972c57b8..ea0822b856 100644 --- a/src/applications/phame/controller/blog/PhameBlogViewController.php +++ b/src/applications/phame/controller/blog/PhameBlogViewController.php @@ -1,165 +1,156 @@ setupLiveEnvironment(); if ($response) { return $response; } $viewer = $this->getViewer(); $blog = $this->getBlog(); $is_live = $this->getIsLive(); $is_external = $this->getIsExternal(); $pager = id(new AphrontCursorPagerView()) ->readFromRequest($request); $post_query = id(new PhamePostQuery()) ->setViewer($viewer) ->withBlogPHIDs(array($blog->getPHID())); if ($is_live) { $post_query->withVisibility(PhameConstants::VISIBILITY_PUBLISHED); } $posts = $post_query->executeWithCursorPager($pager); $header = id(new PHUIHeaderView()) ->setHeader($blog->getName()) ->setUser($viewer); if (!$is_external) { if ($blog->isArchived()) { $header_icon = 'fa-ban'; $header_name = pht('Archived'); $header_color = 'dark'; } else { $header_icon = 'fa-check'; $header_name = pht('Active'); $header_color = 'bluegrey'; } $header->setStatus($header_icon, $header_color, $header_name); $actions = $this->renderActions($blog); - $action_button = id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('Actions')) - ->setHref('#') - ->setIcon('fa-bars') - ->addClass('phui-mobile-menu') - ->setDropdownMenu($actions); - - $header->addActionLink($action_button); - + $header->setActionList($actions); $header->setPolicyObject($blog); } if ($posts) { $post_list = id(new PhamePostListView()) ->setPosts($posts) ->setViewer($viewer) ->setIsExternal($is_external) ->setIsLive($is_live) ->setNodata(pht('This blog has no visible posts.')); } else { $create_button = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('Write a Post')) ->setHref($this->getApplicationURI('post/edit/?blog='.$blog->getID())) ->setColor(PHUIButtonView::GREEN); $post_list = id(new PHUIBigInfoView()) ->setIcon('fa-star') ->setTitle($blog->getName()) ->setDescription( pht('No one has written any blog posts yet.')); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $blog, PhabricatorPolicyCapability::CAN_EDIT); if ($can_edit) { $post_list->addAction($create_button); } } $page = id(new PHUIDocumentViewPro()) ->setHeader($header) ->appendChild($post_list); $description = null; if (strlen($blog->getDescription())) { $description = new PHUIRemarkupView( $viewer, $blog->getDescription()); } else { $description = phutil_tag('em', array(), pht('No description.')); } $about = id(new PhameDescriptionView()) ->setTitle(pht('About %s', $blog->getName())) ->setDescription($description) ->setImage($blog->getProfileImageURI()); $crumbs = $this->buildApplicationCrumbs(); $page = $this->newPage() ->setTitle($blog->getName()) ->setPageObjectPHIDs(array($blog->getPHID())) ->setCrumbs($crumbs) ->appendChild( array( $page, $about, )); if ($is_live) { $page ->setShowChrome(false) ->setShowFooter(false); } return $page; } private function renderActions(PhameBlog $blog) { $viewer = $this->getViewer(); $actions = id(new PhabricatorActionListView()) ->setObject($blog) ->setUser($viewer); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $blog, PhabricatorPolicyCapability::CAN_EDIT); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-plus') ->setHref($this->getApplicationURI('post/edit/?blog='.$blog->getID())) ->setName(pht('Write Post')) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); $actions->addAction( id(new PhabricatorActionView()) ->setUser($viewer) ->setIcon('fa-globe') ->setHref($blog->getLiveURI()) ->setName(pht('View Live'))); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setHref($this->getApplicationURI('blog/manage/'.$blog->getID().'/')) ->setName(pht('Manage Blog'))); return $actions; } } diff --git a/src/applications/phame/controller/post/PhamePostViewController.php b/src/applications/phame/controller/post/PhamePostViewController.php index 537bfbb713..a4231cc1ac 100644 --- a/src/applications/phame/controller/post/PhamePostViewController.php +++ b/src/applications/phame/controller/post/PhamePostViewController.php @@ -1,277 +1,268 @@ setupLiveEnvironment(); if ($response) { return $response; } $viewer = $request->getViewer(); $moved = $request->getStr('moved'); $post = $this->getPost(); $blog = $this->getBlog(); $is_live = $this->getIsLive(); $is_external = $this->getIsExternal(); $header = id(new PHUIHeaderView()) ->setHeader($post->getTitle()) ->setUser($viewer); if (!$is_external) { $actions = $this->renderActions($post); - - $action_button = id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('Actions')) - ->setHref('#') - ->setIcon('fa-bars') - ->addClass('phui-mobile-menu') - ->setDropdownMenu($actions); - $header->setPolicyObject($post); - $header->addActionLink($action_button); + $header->setActionList($actions); } $document = id(new PHUIDocumentViewPro()) ->setHeader($header); if ($moved) { $document->appendChild( id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->appendChild(pht('Post moved successfully.'))); } if ($post->isDraft()) { $document->appendChild( id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setTitle(pht('Draft Post')) ->appendChild( pht('Only you can see this draft until you publish it. '. 'Use "Publish" to publish this post.'))); } if (!$post->getBlog()) { $document->appendChild( id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setTitle(pht('Not On A Blog')) ->appendChild( pht('This post is not associated with a blog (the blog may have '. 'been deleted). Use "Move Post" to move it to a new blog.'))); } $engine = id(new PhabricatorMarkupEngine()) ->setViewer($viewer) ->addObject($post, PhamePost::MARKUP_FIELD_BODY) ->process(); $document->appendChild( phutil_tag( 'div', array( 'class' => 'phabricator-remarkup', ), $engine->getOutput($post, PhamePost::MARKUP_FIELD_BODY))); $blogger = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) ->withPHIDs(array($post->getBloggerPHID())) ->needProfileImage(true) ->executeOne(); $blogger_profile = $blogger->loadUserProfile(); $author = phutil_tag( 'a', array( 'href' => '/p/'.$blogger->getUsername().'/', ), $blogger->getUsername()); $date = phabricator_datetime($post->getDatePublished(), $viewer); if ($post->isDraft()) { $subtitle = pht('Unpublished draft by %s.', $author); } else { $subtitle = pht('Written by %s on %s.', $author, $date); } $user_icon = $blogger_profile->getIcon(); $user_icon = PhabricatorPeopleIconSet::getIconIcon($user_icon); $user_icon = id(new PHUIIconView())->setIcon($user_icon); $about = id(new PhameDescriptionView()) ->setTitle($subtitle) ->setDescription( array( $user_icon, ' ', $blogger_profile->getTitle(), )) ->setImage($blogger->getProfileImageURI()) ->setImageHref('/p/'.$blogger->getUsername()); $timeline = $this->buildTransactionTimeline( $post, id(new PhamePostTransactionQuery()) ->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT))); $timeline = phutil_tag_div('phui-document-view-pro-box', $timeline); if ($is_external) { $add_comment = null; } else { $add_comment = $this->buildCommentForm($post); $add_comment = phutil_tag_div('mlb mlt', $add_comment); } list($prev, $next) = $this->loadAdjacentPosts($post); $properties = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($post); $next_view = new PhameNextPostView(); if ($next) { $next_view->setNext($next->getTitle(), $next->getViewURI()); } if ($prev) { $next_view->setPrevious($prev->getTitle(), $prev->getViewURI()); } $document->setFoot($next_view); $crumbs = $this->buildApplicationCrumbs(); $page = $this->newPage() ->setTitle($post->getTitle()) ->setPageObjectPHIDs(array($post->getPHID())) ->setCrumbs($crumbs) ->appendChild( array( $document, $about, $properties, $timeline, $add_comment, )); if ($is_live) { $page ->setShowChrome(false) ->setShowFooter(false); } return $page; } private function renderActions(PhamePost $post) { $viewer = $this->getViewer(); $actions = id(new PhabricatorActionListView()) ->setObject($post) ->setUser($viewer); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $post, PhabricatorPolicyCapability::CAN_EDIT); $id = $post->getID(); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setHref($this->getApplicationURI('post/edit/'.$id.'/')) ->setName(pht('Edit Post')) ->setDisabled(!$can_edit)); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-arrows') ->setHref($this->getApplicationURI('post/move/'.$id.'/')) ->setName(pht('Move Post')) ->setDisabled(!$can_edit) ->setWorkflow(true)); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-history') ->setHref($this->getApplicationURI('post/history/'.$id.'/')) ->setName(pht('View History'))); if ($post->isDraft()) { $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-eye') ->setHref($this->getApplicationURI('post/publish/'.$id.'/')) ->setName(pht('Publish')) ->setDisabled(!$can_edit) ->setWorkflow(true)); } else { $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-eye-slash') ->setHref($this->getApplicationURI('post/unpublish/'.$id.'/')) ->setName(pht('Unpublish')) ->setDisabled(!$can_edit) ->setWorkflow(true)); } if ($post->isDraft()) { $live_name = pht('Preview'); } else { $live_name = pht('View Live'); } $actions->addAction( id(new PhabricatorActionView()) ->setUser($viewer) ->setIcon('fa-globe') ->setHref($post->getLiveURI()) ->setName($live_name)); return $actions; } private function buildCommentForm(PhamePost $post) { $viewer = $this->getViewer(); $draft = PhabricatorDraft::newFromUserAndKey( $viewer, $post->getPHID()); $box = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($viewer) ->setObjectPHID($post->getPHID()) ->setDraft($draft) ->setHeaderText(pht('Add Comment')) ->setAction($this->getApplicationURI('post/comment/'.$post->getID().'/')) ->setSubmitButtonName(pht('Add Comment')); return phutil_tag_div('phui-document-view-pro-box', $box); } private function loadAdjacentPosts(PhamePost $post) { $viewer = $this->getViewer(); $query = id(new PhamePostQuery()) ->setViewer($viewer) ->withVisibility(PhameConstants::VISIBILITY_PUBLISHED) ->withBlogPHIDs(array($post->getBlog()->getPHID())) ->setLimit(1); $prev = id(clone $query) ->setAfterID($post->getID()) ->execute(); $next = id(clone $query) ->setBeforeID($post->getID()) ->execute(); return array(head($prev), head($next)); } } diff --git a/src/applications/phriction/controller/PhrictionDocumentController.php b/src/applications/phriction/controller/PhrictionDocumentController.php index 7d98e9ed3b..7dae0fad03 100644 --- a/src/applications/phriction/controller/PhrictionDocumentController.php +++ b/src/applications/phriction/controller/PhrictionDocumentController.php @@ -1,488 +1,480 @@ getViewer(); $this->slug = $request->getURIData('slug'); $slug = PhabricatorSlug::normalize($this->slug); if ($slug != $this->slug) { $uri = PhrictionDocument::getSlugURI($slug); // Canonicalize pages to their one true URI. return id(new AphrontRedirectResponse())->setURI($uri); } require_celerity_resource('phriction-document-css'); $document = id(new PhrictionDocumentQuery()) ->setViewer($viewer) ->withSlugs(array($slug)) ->executeOne(); $version_note = null; $core_content = ''; $move_notice = ''; $properties = null; $content = null; $toc = null; if (!$document) { $document = PhrictionDocument::initializeNewDocument($viewer, $slug); if ($slug == '/') { $title = pht('Welcome to Phriction'); $subtitle = pht('Phriction is a simple and easy to use wiki for '. 'keeping track of documents and their changes.'); $page_title = pht('Welcome'); $create_text = pht('Edit this Document'); } else { $title = pht('No Document Here'); $subtitle = pht('There is no document here, but you may create it.'); $page_title = pht('Page Not Found'); $create_text = pht('Create this Document'); } $create_uri = '/phriction/edit/?slug='.$slug; $create_button = id(new PHUIButtonView()) ->setTag('a') ->setText($create_text) ->setHref($create_uri) ->setColor(PHUIButtonView::GREEN); $core_content = id(new PHUIBigInfoView()) ->setIcon('fa-book') ->setTitle($title) ->setDescription($subtitle) ->addAction($create_button); } else { $version = $request->getInt('v'); if ($version) { $content = id(new PhrictionContent())->loadOneWhere( 'documentID = %d AND version = %d', $document->getID(), $version); if (!$content) { return new Aphront404Response(); } if ($content->getID() != $document->getContentID()) { $vdate = phabricator_datetime($content->getDateCreated(), $viewer); $version_note = new PHUIInfoView(); $version_note->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $version_note->appendChild( pht('You are viewing an older version of this document, as it '. 'appeared on %s.', $vdate)); } } else { $content = id(new PhrictionContent())->load($document->getContentID()); } $page_title = $content->getTitle(); $properties = $this ->buildPropertyListView($document, $content, $slug); $doc_status = $document->getStatus(); $current_status = $content->getChangeType(); if ($current_status == PhrictionChangeType::CHANGE_EDIT || $current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $core_content = $content->renderContent($viewer); $toc = $this->getToc($content); } else if ($current_status == PhrictionChangeType::CHANGE_DELETE) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Document Deleted')); $notice->appendChild( pht('This document has been deleted. You can edit it to put new '. 'content here, or use history to revert to an earlier version.')); $core_content = $notice->render(); } else if ($current_status == PhrictionChangeType::CHANGE_STUB) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Empty Document')); $notice->appendChild( pht('This document is empty. You can edit it to put some proper '. 'content here.')); $core_content = $notice->render(); } else if ($current_status == PhrictionChangeType::CHANGE_MOVE_AWAY) { $new_doc_id = $content->getChangeRef(); $slug_uri = null; // If the new document exists and the viewer can see it, provide a link // to it. Otherwise, render a generic message. $new_docs = id(new PhrictionDocumentQuery()) ->setViewer($viewer) ->withIDs(array($new_doc_id)) ->execute(); if ($new_docs) { $new_doc = head($new_docs); $slug_uri = PhrictionDocument::getSlugURI($new_doc->getSlug()); } $notice = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE); if ($slug_uri) { $notice->appendChild( phutil_tag( 'p', array(), pht( 'This document has been moved to %s. You can edit it to put '. 'new content here, or use history to revert to an earlier '. 'version.', phutil_tag('a', array('href' => $slug_uri), $slug_uri)))); } else { $notice->appendChild( phutil_tag( 'p', array(), pht( 'This document has been moved. You can edit it to put new '. 'contne here, or use history to revert to an earlier '. 'version.'))); } $core_content = $notice->render(); } else { throw new Exception(pht("Unknown document status '%s'!", $doc_status)); } $move_notice = null; if ($current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $from_doc_id = $content->getChangeRef(); $slug_uri = null; // If the old document exists and is visible, provide a link to it. $from_docs = id(new PhrictionDocumentQuery()) ->setViewer($viewer) ->withIDs(array($from_doc_id)) ->execute(); if ($from_docs) { $from_doc = head($from_docs); $slug_uri = PhrictionDocument::getSlugURI($from_doc->getSlug()); } $move_notice = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE); if ($slug_uri) { $move_notice->appendChild( pht( 'This document was moved from %s.', phutil_tag('a', array('href' => $slug_uri), $slug_uri))); } else { // Render this for consistency, even though it's a bit silly. $move_notice->appendChild( pht('This document was moved from elsewhere.')); } } } $children = $this->renderDocumentChildren($slug); $actions = $this->buildActionView($viewer, $document); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); $crumb_views = $this->renderBreadcrumbs($slug); foreach ($crumb_views as $view) { $crumbs->addCrumb($view); } - $action_button = id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('Actions')) - ->setHref('#') - ->setIcon('fa-bars') - ->addClass('phui-mobile-menu') - ->setDropdownMenu($actions); - $header = id(new PHUIHeaderView()) ->setUser($viewer) ->setPolicyObject($document) ->setHeader($page_title) - ->addActionLink($action_button); + ->setActionList($actions); if ($content) { $header->setEpoch($content->getDateCreated()); } $prop_list = null; if ($properties) { $prop_list = new PHUIPropertyGroupView(); $prop_list->addPropertyList($properties); } $page_content = id(new PHUIDocumentViewPro()) ->setHeader($header) ->setToc($toc) ->appendChild( array( $version_note, $move_notice, $core_content, )); return $this->buildApplicationPage( array( $crumbs->render(), $page_content, $prop_list, $children, ), array( 'pageObjects' => array($document->getPHID()), 'title' => $page_title, )); } private function buildPropertyListView( PhrictionDocument $document, PhrictionContent $content, $slug) { $viewer = $this->getRequest()->getUser(); $view = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($document); $view->addProperty( pht('Last Author'), $viewer->renderHandle($content->getAuthorPHID())); return $view; } private function buildActionView( PhabricatorUser $viewer, PhrictionDocument $document) { $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $document, PhabricatorPolicyCapability::CAN_EDIT); $slug = PhabricatorSlug::normalize($this->slug); $action_view = id(new PhabricatorActionListView()) ->setUser($viewer) ->setObject($document); if (!$document->getID()) { return $action_view->addAction( id(new PhabricatorActionView()) ->setName(pht('Create This Document')) ->setIcon('fa-plus-square') ->setHref('/phriction/edit/?slug='.$slug)); } $action_view->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Document')) ->setDisabled(!$can_edit) ->setIcon('fa-pencil') ->setHref('/phriction/edit/'.$document->getID().'/')); if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) { $action_view->addAction( id(new PhabricatorActionView()) ->setName(pht('Move Document')) ->setDisabled(!$can_edit) ->setIcon('fa-arrows') ->setHref('/phriction/move/'.$document->getID().'/') ->setWorkflow(true)); $action_view->addAction( id(new PhabricatorActionView()) ->setName(pht('Delete Document')) ->setDisabled(!$can_edit) ->setIcon('fa-times') ->setHref('/phriction/delete/'.$document->getID().'/') ->setWorkflow(true)); } return $action_view->addAction( id(new PhabricatorActionView()) ->setName(pht('View History')) ->setIcon('fa-list') ->setHref(PhrictionDocument::getSlugURI($slug, 'history'))); } private function renderDocumentChildren($slug) { $d_child = PhabricatorSlug::getDepth($slug) + 1; $d_grandchild = PhabricatorSlug::getDepth($slug) + 2; $limit = 250; $query = id(new PhrictionDocumentQuery()) ->setViewer($this->getRequest()->getUser()) ->withDepths(array($d_child, $d_grandchild)) ->withSlugPrefix($slug == '/' ? '' : $slug) ->withStatuses(array( PhrictionDocumentStatus::STATUS_EXISTS, PhrictionDocumentStatus::STATUS_STUB, )) ->setLimit($limit) ->setOrder(PhrictionDocumentQuery::ORDER_HIERARCHY) ->needContent(true); $children = $query->execute(); if (!$children) { return; } // We're going to render in one of three modes to try to accommodate // different information scales: // // - If we found fewer than $limit rows, we know we have all the children // and grandchildren and there aren't all that many. We can just render // everything. // - If we found $limit rows but the results included some grandchildren, // we just throw them out and render only the children, as we know we // have them all. // - If we found $limit rows and the results have no grandchildren, we // have a ton of children. Render them and then let the user know that // this is not an exhaustive list. if (count($children) == $limit) { $more_children = true; foreach ($children as $child) { if ($child->getDepth() == $d_grandchild) { $more_children = false; } } $show_grandchildren = false; } else { $show_grandchildren = true; $more_children = false; } $children_dicts = array(); $grandchildren_dicts = array(); foreach ($children as $key => $child) { $child_dict = array( 'slug' => $child->getSlug(), 'depth' => $child->getDepth(), 'title' => $child->getContent()->getTitle(), ); if ($child->getDepth() == $d_child) { $children_dicts[] = $child_dict; continue; } else { unset($children[$key]); if ($show_grandchildren) { $ancestors = PhabricatorSlug::getAncestry($child->getSlug()); $grandchildren_dicts[end($ancestors)][] = $child_dict; } } } // Fill in any missing children. $known_slugs = mpull($children, null, 'getSlug'); foreach ($grandchildren_dicts as $slug => $ignored) { if (empty($known_slugs[$slug])) { $children_dicts[] = array( 'slug' => $slug, 'depth' => $d_child, 'title' => PhabricatorSlug::getDefaultTitle($slug), 'empty' => true, ); } } $children_dicts = isort($children_dicts, 'title'); $list = array(); foreach ($children_dicts as $child) { $list[] = hsprintf('