2011-07-11 17:54:22 +02:00
|
|
|
<?php
|
|
|
|
|
2011-09-14 17:02:31 +02:00
|
|
|
/**
|
|
|
|
* @group phriction
|
|
|
|
*/
|
2012-03-10 00:46:25 +01:00
|
|
|
final class PhrictionDocumentController
|
2011-07-11 17:54:22 +02:00
|
|
|
extends PhrictionController {
|
|
|
|
|
|
|
|
private $slug;
|
|
|
|
|
|
|
|
public function willProcessRequest(array $data) {
|
|
|
|
$this->slug = $data['slug'];
|
|
|
|
}
|
|
|
|
|
|
|
|
public function processRequest() {
|
2011-07-12 05:14:46 +02:00
|
|
|
$request = $this->getRequest();
|
2011-07-13 03:03:20 +02:00
|
|
|
$user = $request->getUser();
|
2011-07-12 05:14:46 +02:00
|
|
|
|
2012-04-10 23:18:20 +02:00
|
|
|
$slug = PhabricatorSlug::normalize($this->slug);
|
2011-07-11 17:54:22 +02:00
|
|
|
if ($slug != $this->slug) {
|
|
|
|
$uri = PhrictionDocument::getSlugURI($slug);
|
|
|
|
// Canonicalize pages to their one true URI.
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($uri);
|
|
|
|
}
|
|
|
|
|
2011-07-11 21:34:53 +02:00
|
|
|
require_celerity_resource('phriction-document-css');
|
|
|
|
|
|
|
|
$document = id(new PhrictionDocument())->loadOneWhere(
|
|
|
|
'slug = %s',
|
|
|
|
$slug);
|
|
|
|
|
2011-07-13 03:03:20 +02:00
|
|
|
$version_note = null;
|
2013-04-12 00:05:50 +02:00
|
|
|
$core_content = '';
|
|
|
|
$move_notice = '';
|
2013-05-09 23:40:43 +02:00
|
|
|
$properties = null;
|
2011-07-12 17:08:03 +02:00
|
|
|
|
2011-07-11 21:34:53 +02:00
|
|
|
if (!$document) {
|
2011-07-12 05:14:46 +02:00
|
|
|
|
2013-01-11 20:39:22 +01:00
|
|
|
$document = new PhrictionDocument();
|
|
|
|
|
2012-05-20 17:54:25 +02:00
|
|
|
if (PhrictionDocument::isProjectSlug($slug)) {
|
|
|
|
$project = id(new PhabricatorProject())->loadOneWhere(
|
|
|
|
'phrictionSlug = %s',
|
|
|
|
PhrictionDocument::getProjectSlugIdentifier($slug));
|
|
|
|
if (!$project) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$create_uri = '/phriction/edit/?slug='.$slug;
|
2013-03-07 17:28:46 +01:00
|
|
|
|
2013-05-09 23:40:43 +02:00
|
|
|
$notice = new AphrontErrorView();
|
|
|
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NODATA);
|
|
|
|
$notice->setTitle(pht('No content here!'));
|
|
|
|
$notice->appendChild(
|
|
|
|
pht(
|
|
|
|
'No document found at %s. You can <strong>'.
|
|
|
|
'<a href="%s">create a new document here</a></strong>.',
|
|
|
|
phutil_tag('tt', array(), $slug),
|
|
|
|
$create_uri));
|
|
|
|
$core_content = $notice;
|
|
|
|
|
2013-02-08 18:54:27 +01:00
|
|
|
$page_title = pht('Page Not Found');
|
2011-07-11 21:34:53 +02:00
|
|
|
} else {
|
2011-07-13 03:03:20 +02:00
|
|
|
$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()) {
|
2013-02-08 18:54:27 +01:00
|
|
|
$vdate = phabricator_datetime($content->getDateCreated(), $user);
|
2011-07-13 03:03:20 +02:00
|
|
|
$version_note = new AphrontErrorView();
|
|
|
|
$version_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
|
|
|
$version_note->setTitle('Older Version');
|
|
|
|
$version_note->appendChild(
|
2013-02-08 18:54:27 +01:00
|
|
|
pht('You are viewing an older version of this document, as it '.
|
|
|
|
'appeared on %s.', $vdate));
|
2011-07-13 03:03:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$content = id(new PhrictionContent())->load($document->getContentID());
|
|
|
|
}
|
2011-07-11 21:34:53 +02:00
|
|
|
$page_title = $content->getTitle();
|
2011-07-12 05:14:46 +02:00
|
|
|
|
Added subscriptions to Phriction documents
Summary:
Fixes T2694
added edge infrastructure for Phriction
added mail subject prefix option for Phriction
added messy mail support for subscribers
adds edges to the phriction db, along with the subscriber interface
which gives us subscriptions for free.
simple display of subscribers, adequate to the current design and
sufficient fallbacks for exceptional cases. @chad may
be mailed about that one more UI element may be added to his redesign
mail support is messy. not generic at all. only sends to subscribed non-authors.
Test Plan:
tried out all kinds of stuff. applied patch, subscribed, unsubscribed with multiple
accs. verified proper
edited documents, verified that mail was sent in MetaMTA. Verified
contents, tos and stuff by looking into the db, comparing PHIDs etc.
functional testing per serious MTA (that is, AWS SES) worked wonderfully.
Here's how the subscription list looks like:
{F36320, layout=link}
Reviewers: epriestley, chad, btrahan
Reviewed By: epriestley
CC: hfcorriez, aran, Korvin
Maniphest Tasks: T2686, T2694
Differential Revision: https://secure.phabricator.com/D5372
Conflicts:
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
2013-03-21 18:26:32 +01:00
|
|
|
$subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
|
|
|
$document->getPHID());
|
2013-05-09 23:40:43 +02:00
|
|
|
$properties = $this
|
|
|
|
->buildPropertyListView($document, $content, $slug, $subscribers);
|
2011-07-12 05:14:46 +02:00
|
|
|
|
2011-12-17 18:19:08 +01:00
|
|
|
$doc_status = $document->getStatus();
|
2013-03-07 17:28:46 +01:00
|
|
|
$current_status = $content->getChangeType();
|
|
|
|
if ($current_status == PhrictionChangeType::CHANGE_EDIT ||
|
|
|
|
$current_status == PhrictionChangeType::CHANGE_MOVE_HERE) {
|
|
|
|
|
2012-09-05 20:40:48 +02:00
|
|
|
$core_content = $content->renderContent($user);
|
2013-03-07 17:28:46 +01:00
|
|
|
} else if ($current_status == PhrictionChangeType::CHANGE_DELETE) {
|
2011-12-17 18:19:08 +01:00
|
|
|
$notice = new AphrontErrorView();
|
|
|
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
2013-03-07 17:28:46 +01:00
|
|
|
$notice->setTitle(pht('Document Deleted'));
|
2011-12-17 18:19:08 +01:00
|
|
|
$notice->appendChild(
|
2013-02-08 18:54:27 +01:00
|
|
|
pht('This document has been deleted. You can edit it to put new '.
|
|
|
|
'content here, or use history to revert to an earlier version.'));
|
2011-12-17 18:19:08 +01:00
|
|
|
$core_content = $notice->render();
|
2013-03-07 17:28:46 +01:00
|
|
|
} else if ($current_status == PhrictionChangeType::CHANGE_STUB) {
|
2013-03-04 16:31:59 +01:00
|
|
|
$notice = new AphrontErrorView();
|
|
|
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
2013-03-07 17:28:46 +01:00
|
|
|
$notice->setTitle(pht('Empty Document'));
|
2013-03-04 16:31:59 +01:00
|
|
|
$notice->appendChild(
|
|
|
|
pht('This document is empty. You can edit it to put some proper '.
|
|
|
|
'content here.'));
|
|
|
|
$core_content = $notice->render();
|
2013-03-07 17:28:46 +01:00
|
|
|
} else if ($current_status == PhrictionChangeType::CHANGE_MOVE_AWAY) {
|
2013-03-06 22:12:04 +01:00
|
|
|
$new_doc_id = $content->getChangeRef();
|
|
|
|
$new_doc = new PhrictionDocument();
|
|
|
|
$new_doc->load($new_doc_id);
|
|
|
|
|
|
|
|
$slug_uri = PhrictionDocument::getSlugURI($new_doc->getSlug());
|
|
|
|
|
|
|
|
$notice = new AphrontErrorView();
|
|
|
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
|
|
|
$notice->setTitle(pht('Document Moved'));
|
|
|
|
$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))));
|
|
|
|
$core_content = $notice->render();
|
2011-12-17 18:19:08 +01:00
|
|
|
} else {
|
|
|
|
throw new Exception("Unknown document status '{$doc_status}'!");
|
|
|
|
}
|
|
|
|
|
2013-03-06 22:12:04 +01:00
|
|
|
$move_notice = null;
|
2013-03-07 17:28:46 +01:00
|
|
|
if ($current_status == PhrictionChangeType::CHANGE_MOVE_HERE) {
|
2013-03-06 22:12:04 +01:00
|
|
|
$from_doc_id = $content->getChangeRef();
|
|
|
|
$from_doc = id(new PhrictionDocument())->load($from_doc_id);
|
|
|
|
$slug_uri = PhrictionDocument::getSlugURI($from_doc->getSlug());
|
|
|
|
|
|
|
|
$move_notice = id(new AphrontErrorView())
|
|
|
|
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
|
|
|
|
->appendChild(pht('This document was moved from %s',
|
|
|
|
phutil_tag('a', array('href' => $slug_uri), $slug_uri)))
|
|
|
|
->render();
|
|
|
|
}
|
2011-07-11 21:34:53 +02:00
|
|
|
}
|
|
|
|
|
2011-07-13 03:03:20 +02:00
|
|
|
if ($version_note) {
|
|
|
|
$version_note = $version_note->render();
|
|
|
|
}
|
|
|
|
|
2013-02-13 23:50:15 +01:00
|
|
|
$children = $this->renderDocumentChildren($slug);
|
2011-07-15 23:56:39 +02:00
|
|
|
|
2013-04-10 22:08:36 +02:00
|
|
|
$actions = $this->buildActionView($user, $document);
|
|
|
|
|
2013-01-11 20:39:22 +01:00
|
|
|
$crumbs = $this->buildApplicationCrumbs();
|
2013-04-10 22:08:36 +02:00
|
|
|
$crumbs->setActionList($actions);
|
2013-01-11 20:39:22 +01:00
|
|
|
$crumb_views = $this->renderBreadcrumbs($slug);
|
|
|
|
foreach ($crumb_views as $view) {
|
|
|
|
$crumbs->addCrumb($view);
|
|
|
|
}
|
|
|
|
|
|
|
|
$header = id(new PhabricatorHeaderView())
|
|
|
|
->setHeader($page_title);
|
|
|
|
|
2013-05-09 23:40:43 +02:00
|
|
|
$page_content = hsprintf(
|
|
|
|
'<div class="phriction-wrap">
|
|
|
|
<div class="phriction-content">
|
|
|
|
%s%s%s%s%s
|
|
|
|
</div>
|
|
|
|
<div class="phriction-fake-space"></div>
|
|
|
|
</div>',
|
|
|
|
$header,
|
|
|
|
$actions,
|
|
|
|
$properties,
|
|
|
|
$move_notice,
|
|
|
|
$core_content);
|
2013-04-12 00:05:50 +02:00
|
|
|
|
|
|
|
$core_page = phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'phriction-offset'
|
|
|
|
),
|
|
|
|
array(
|
|
|
|
$page_content,
|
|
|
|
$children,
|
|
|
|
));
|
|
|
|
|
2013-01-11 20:39:22 +01:00
|
|
|
return $this->buildApplicationPage(
|
2011-07-11 17:54:22 +02:00
|
|
|
array(
|
2013-02-13 23:50:15 +01:00
|
|
|
$crumbs->render(),
|
2013-04-12 00:05:50 +02:00
|
|
|
$core_page,
|
2013-01-11 20:39:22 +01:00
|
|
|
),
|
|
|
|
array(
|
|
|
|
'title' => $page_title,
|
|
|
|
'device' => true,
|
2013-04-12 00:05:50 +02:00
|
|
|
'dust' => true,
|
2011-07-11 17:54:22 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-05-09 23:40:43 +02:00
|
|
|
private function buildPropertyListView(
|
|
|
|
PhrictionDocument $document,
|
|
|
|
PhrictionContent $content,
|
|
|
|
$slug,
|
|
|
|
array $subscribers) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
$view = id(new PhabricatorPropertyListView())
|
|
|
|
->setUser($viewer)
|
|
|
|
->setObject($document);
|
|
|
|
|
|
|
|
$project_phid = null;
|
|
|
|
if (PhrictionDocument::isProjectSlug($slug)) {
|
|
|
|
$project = id(new PhabricatorProject())->loadOneWhere(
|
|
|
|
'phrictionSlug = %s',
|
|
|
|
PhrictionDocument::getProjectSlugIdentifier($slug));
|
|
|
|
if ($project) {
|
|
|
|
$project_phid = $project->getPHID();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$phids = array_filter(
|
|
|
|
array(
|
|
|
|
$content->getAuthorPHID(),
|
|
|
|
$project_phid,
|
|
|
|
));
|
|
|
|
|
|
|
|
if ($subscribers) {
|
|
|
|
$phids = array_merge($phids, $subscribers);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->loadHandles($phids);
|
|
|
|
|
|
|
|
$project_info = null;
|
|
|
|
if ($project_phid) {
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Project Info'),
|
|
|
|
$this->getHandle($project_phid)->renderLink());
|
|
|
|
}
|
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Last Author'),
|
|
|
|
$this->getHandle($content->getAuthorPHID())->renderLink());
|
|
|
|
|
|
|
|
$age = time() - $content->getDateCreated();
|
|
|
|
$age = floor($age / (60 * 60 * 24));
|
|
|
|
if ($age < 1) {
|
|
|
|
$when = pht('Today');
|
|
|
|
} else if ($age == 1) {
|
|
|
|
$when = pht('Yesterday');
|
|
|
|
} else {
|
|
|
|
$when = pht("%d Days Ago", $age);
|
|
|
|
}
|
|
|
|
$view->addProperty(pht('Last Updated'), $when);
|
|
|
|
|
|
|
|
if ($subscribers) {
|
|
|
|
$subscribers = $this->renderHandlesForPHIDs($subscribers);
|
|
|
|
$view->addProperty(pht('Subscribers'), $subscribers);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2013-01-11 20:39:22 +01:00
|
|
|
private function buildActionView(
|
|
|
|
PhabricatorUser $user,
|
|
|
|
PhrictionDocument $document) {
|
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
|
|
|
$user,
|
|
|
|
$document,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
2011-07-12 17:08:03 +02:00
|
|
|
|
2013-01-11 20:39:22 +01:00
|
|
|
$slug = PhabricatorSlug::normalize($this->slug);
|
2011-07-12 17:08:03 +02:00
|
|
|
|
2013-01-25 06:26:40 +01:00
|
|
|
$action_view = id(new PhabricatorActionListView())
|
2013-01-11 20:39:22 +01:00
|
|
|
->setUser($user)
|
2013-03-04 16:21:47 +01:00
|
|
|
->setObject($document);
|
|
|
|
|
|
|
|
if (!$document->getID()) {
|
|
|
|
return $action_view->addAction(
|
2013-01-11 20:39:22 +01:00
|
|
|
id(new PhabricatorActionView())
|
2013-03-07 17:28:46 +01:00
|
|
|
->setName(pht('Create This Document'))
|
2013-03-04 16:21:47 +01:00
|
|
|
->setIcon('create')
|
|
|
|
->setHref('/phriction/edit/?slug='.$slug));
|
|
|
|
}
|
|
|
|
|
|
|
|
$action_view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Edit Document'))
|
|
|
|
->setIcon('edit')
|
|
|
|
->setHref('/phriction/edit/'.$document->getID().'/'));
|
2013-01-25 06:26:40 +01:00
|
|
|
|
|
|
|
if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) {
|
2013-03-06 22:12:04 +01:00
|
|
|
$action_view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Move Document'))
|
|
|
|
->setIcon('move')
|
|
|
|
->setHref('/phriction/move/'.$document->getID().'/')
|
|
|
|
->setWorkflow(true));
|
|
|
|
|
2013-01-25 06:26:40 +01:00
|
|
|
$action_view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Delete Document'))
|
|
|
|
->setIcon('delete')
|
|
|
|
->setHref('/phriction/delete/'.$document->getID().'/')
|
|
|
|
->setWorkflow(true));
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
$action_view->addAction(
|
2013-01-11 20:39:22 +01:00
|
|
|
id(new PhabricatorActionView())
|
2013-01-25 06:26:40 +01:00
|
|
|
->setName(pht('View History'))
|
|
|
|
->setIcon('history')
|
|
|
|
->setHref(PhrictionDocument::getSlugURI($slug, 'history')));
|
2011-07-12 17:08:03 +02:00
|
|
|
}
|
|
|
|
|
2013-02-13 23:50:15 +01:00
|
|
|
private function renderDocumentChildren($slug) {
|
2011-07-15 23:56:39 +02:00
|
|
|
$document_dao = new PhrictionDocument();
|
|
|
|
$content_dao = new PhrictionContent();
|
|
|
|
$conn = $document_dao->establishConnection('r');
|
|
|
|
|
|
|
|
$limit = 50;
|
2012-04-10 23:18:20 +02:00
|
|
|
$d_child = PhabricatorSlug::getDepth($slug) + 1;
|
|
|
|
$d_grandchild = PhabricatorSlug::getDepth($slug) + 2;
|
2011-07-15 23:56:39 +02:00
|
|
|
|
|
|
|
// Select children and grandchildren.
|
|
|
|
$children = queryfx_all(
|
|
|
|
$conn,
|
|
|
|
'SELECT d.slug, d.depth, c.title FROM %T d JOIN %T c
|
|
|
|
ON d.contentID = c.id
|
|
|
|
WHERE d.slug LIKE %> AND d.depth IN (%d, %d)
|
2013-03-04 16:31:59 +01:00
|
|
|
AND d.status IN (%Ld)
|
2011-07-15 23:56:39 +02:00
|
|
|
ORDER BY d.depth, c.title LIMIT %d',
|
|
|
|
$document_dao->getTableName(),
|
|
|
|
$content_dao->getTableName(),
|
|
|
|
($slug == '/' ? '' : $slug),
|
|
|
|
$d_child,
|
|
|
|
$d_grandchild,
|
2013-03-04 16:31:59 +01:00
|
|
|
array(
|
|
|
|
PhrictionDocumentStatus::STATUS_EXISTS,
|
|
|
|
PhrictionDocumentStatus::STATUS_STUB,
|
|
|
|
),
|
2011-07-15 23:56:39 +02:00
|
|
|
$limit);
|
|
|
|
|
|
|
|
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['depth'] == $d_grandchild) {
|
|
|
|
$more_children = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$show_grandchildren = false;
|
|
|
|
} else {
|
|
|
|
$show_grandchildren = true;
|
|
|
|
$more_children = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$grandchildren = array();
|
|
|
|
foreach ($children as $key => $child) {
|
|
|
|
if ($child['depth'] == $d_child) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
unset($children[$key]);
|
|
|
|
if ($show_grandchildren) {
|
2012-04-10 23:18:20 +02:00
|
|
|
$ancestors = PhabricatorSlug::getAncestry($child['slug']);
|
2011-07-15 23:56:39 +02:00
|
|
|
$grandchildren[end($ancestors)][] = $child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fill in any missing children.
|
|
|
|
$known_slugs = ipull($children, null, 'slug');
|
|
|
|
foreach ($grandchildren as $slug => $ignored) {
|
|
|
|
if (empty($known_slugs[$slug])) {
|
|
|
|
$children[] = array(
|
|
|
|
'slug' => $slug,
|
|
|
|
'depth' => $d_child,
|
2012-04-10 23:18:20 +02:00
|
|
|
'title' => PhabricatorSlug::getDefaultTitle($slug),
|
2011-07-15 23:56:39 +02:00
|
|
|
'empty' => true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-31 20:52:24 +02:00
|
|
|
$children = isort($children, 'title');
|
|
|
|
|
2011-07-15 23:56:39 +02:00
|
|
|
$list = array();
|
|
|
|
foreach ($children as $child) {
|
2013-02-13 23:50:15 +01:00
|
|
|
$list[] = hsprintf('<li>');
|
2011-07-15 23:56:39 +02:00
|
|
|
$list[] = $this->renderChildDocumentLink($child);
|
|
|
|
$grand = idx($grandchildren, $child['slug'], array());
|
|
|
|
if ($grand) {
|
2013-02-13 23:50:15 +01:00
|
|
|
$list[] = hsprintf('<ul>');
|
2011-07-15 23:56:39 +02:00
|
|
|
foreach ($grand as $grandchild) {
|
2013-02-13 23:50:15 +01:00
|
|
|
$list[] = hsprintf('<li>');
|
2011-07-15 23:56:39 +02:00
|
|
|
$list[] = $this->renderChildDocumentLink($grandchild);
|
2013-02-13 23:50:15 +01:00
|
|
|
$list[] = hsprintf('</li>');
|
2011-07-15 23:56:39 +02:00
|
|
|
}
|
2013-02-13 23:50:15 +01:00
|
|
|
$list[] = hsprintf('</ul>');
|
2011-07-15 23:56:39 +02:00
|
|
|
}
|
2013-02-13 23:50:15 +01:00
|
|
|
$list[] = hsprintf('</li>');
|
2011-07-15 23:56:39 +02:00
|
|
|
}
|
|
|
|
if ($more_children) {
|
2013-02-13 23:50:15 +01:00
|
|
|
$list[] = phutil_tag('li', array(), pht('More...'));
|
2011-07-15 23:56:39 +02:00
|
|
|
}
|
|
|
|
|
2013-02-13 23:50:15 +01:00
|
|
|
return hsprintf(
|
2013-04-12 00:05:50 +02:00
|
|
|
'<div class="phriction-wrap">
|
|
|
|
<div class="phriction-children">
|
|
|
|
<div class="phriction-children-header">%s</div>
|
|
|
|
%s
|
|
|
|
</div>
|
|
|
|
</div>',
|
2013-02-13 23:50:15 +01:00
|
|
|
pht('Document Hierarchy'),
|
|
|
|
phutil_tag('ul', array(), $list));
|
2011-07-15 23:56:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private function renderChildDocumentLink(array $info) {
|
2013-02-08 18:54:27 +01:00
|
|
|
$title = nonempty($info['title'], pht('(Untitled Document)'));
|
2013-01-18 03:43:35 +01:00
|
|
|
$item = phutil_tag(
|
2011-07-15 23:56:39 +02:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => PhrictionDocument::getSlugURI($info['slug']),
|
|
|
|
),
|
2013-01-18 03:43:35 +01:00
|
|
|
$title);
|
2011-07-15 23:56:39 +02:00
|
|
|
|
|
|
|
if (isset($info['empty'])) {
|
2013-02-13 23:50:15 +01:00
|
|
|
$item = phutil_tag('em', array(), $item);
|
2011-07-15 23:56:39 +02:00
|
|
|
}
|
|
|
|
|
2013-02-13 23:50:15 +01:00
|
|
|
return $item;
|
2011-07-15 23:56:39 +02:00
|
|
|
}
|
|
|
|
|
2013-03-07 17:12:00 +01:00
|
|
|
protected function getDocumentSlug() {
|
|
|
|
return $this->slug;
|
|
|
|
}
|
|
|
|
|
2011-07-11 17:54:22 +02:00
|
|
|
}
|