Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2891859
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
18 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/phriction/controller/PhrictionController.php b/src/applications/phriction/controller/PhrictionController.php
index 26dccaea9c..de8d9f923d 100644
--- a/src/applications/phriction/controller/PhrictionController.php
+++ b/src/applications/phriction/controller/PhrictionController.php
@@ -1,105 +1,113 @@
<?php
/**
* @group phriction
*/
abstract class PhrictionController extends PhabricatorController {
public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView();
$page->setApplicationName(pht('Phriction'));
$page->setBaseURI('/w/');
$page->setTitle(idx($data, 'title'));
$page->setGlyph("\xE2\x9A\xA1");
$page->appendChild($view);
$page->setSearchDefaultScope(PhabricatorSearchScope::SCOPE_WIKI);
$response = new AphrontWebpageResponse();
return $response->setContent($page->render());
}
public function buildSideNavView($filter = null, $for_app = false) {
$user = $this->getRequest()->getUser();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI('/phriction/list/'));
if ($for_app) {
$nav->addFilter('', pht('Root Document'), '/w/');
$nav->addFilter('', pht('Create Document'), '/phriction/new');
}
$nav->addLabel(pht('Filters'));
$nav->addFilter('active', pht('Active Documents'));
$nav->addFilter('all', pht('All Documents'));
$nav->addFilter('updates', pht('Recently Updated'));
$nav->selectFilter($filter, 'active');
return $nav;
}
public function buildApplicationMenu() {
return $this->buildSideNavView(null, true)->getMenu();
}
public function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
+ if (get_class($this) != 'PhrictionListController') {
+ $crumbs->addAction(
+ id(new PhabricatorMenuItemView())
+ ->setName(pht('Document Index'))
+ ->setHref('/phriction/')
+ ->setIcon('transcript'));
+ }
+
$crumbs->addAction(
id(new PhabricatorMenuItemView())
->setName(pht('Create Document'))
->setHref('/phriction/new/?slug='.$this->getDocumentSlug())
->setWorkflow(true)
->setIcon('create'));
return $crumbs;
}
public function renderBreadcrumbs($slug) {
$ancestor_handles = array();
$ancestral_slugs = PhabricatorSlug::getAncestry($slug);
$ancestral_slugs[] = $slug;
if ($ancestral_slugs) {
$empty_slugs = array_fill_keys($ancestral_slugs, null);
$ancestors = id(new PhrictionDocument())->loadAllWhere(
'slug IN (%Ls)',
$ancestral_slugs);
$ancestors = mpull($ancestors, null, 'getSlug');
$ancestor_phids = mpull($ancestors, 'getPHID');
$handles = array();
if ($ancestor_phids) {
$handles = $this->loadViewerHandles($ancestor_phids);
}
$ancestor_handles = array();
foreach ($ancestral_slugs as $slug) {
if (isset($ancestors[$slug])) {
$ancestor_handles[] = $handles[$ancestors[$slug]->getPHID()];
} else {
$handle = new PhabricatorObjectHandle();
$handle->setName(PhabricatorSlug::getDefaultTitle($slug));
$handle->setURI(PhrictionDocument::getSlugURI($slug));
$ancestor_handles[] = $handle;
}
}
}
$breadcrumbs = array();
foreach ($ancestor_handles as $ancestor_handle) {
$breadcrumbs[] = id(new PhabricatorCrumbView())
->setName($ancestor_handle->getName())
->setHref($ancestor_handle->getUri());
}
return $breadcrumbs;
}
protected function getDocumentSlug() {
return '';
}
}
diff --git a/src/applications/phriction/controller/PhrictionDocumentController.php b/src/applications/phriction/controller/PhrictionDocumentController.php
index f6a6ca2d0a..3c206e0527 100644
--- a/src/applications/phriction/controller/PhrictionDocumentController.php
+++ b/src/applications/phriction/controller/PhrictionDocumentController.php
@@ -1,449 +1,441 @@
<?php
/**
* @group phriction
*/
final class PhrictionDocumentController
extends PhrictionController {
private $slug;
public function willProcessRequest(array $data) {
$this->slug = $data['slug'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$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 PhrictionDocument())->loadOneWhere(
'slug = %s',
$slug);
$version_note = null;
if (!$document) {
$document = new PhrictionDocument();
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;
$no_content_head = pht('No content here!');
$no_content_body = 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);
$no_content_text = hsprintf(
'<em>%s</em><br />%s',
$no_content_head,
$no_content_body);
$page_content = phutil_tag(
'div',
array('class' => 'phriction-content'),
$no_content_text);
$page_title = pht('Page Not Found');
} 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(), $user);
$version_note = new AphrontErrorView();
$version_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
$version_note->setTitle('Older Version');
$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();
$project_phid = null;
if (PhrictionDocument::isProjectSlug($slug)) {
$project = id(new PhabricatorProject())->loadOneWhere(
'phrictionSlug = %s',
PhrictionDocument::getProjectSlugIdentifier($slug));
if ($project) {
$project_phid = $project->getPHID();
}
}
$subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$document->getPHID());
$phids = array_filter(
array(
$content->getAuthorPHID(),
$project_phid,
));
if ($subscribers) {
$phids = array_merge($phids, $subscribers);
}
$handles = $this->loadViewerHandles($phids);
$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);
}
$project_info = null;
if ($project_phid) {
$project_info = hsprintf(
'<br />%s',
pht('This document is about the project %s.',
$handles[$project_phid]->renderLink()));
}
- $index_link = phutil_tag(
- 'a',
- array(
- 'href' => '/phriction/',
- ),
- pht('Document Index'));
-
$subscriber_view = null;
if ($subscribers) {
$subcriber_list = array();
foreach ($subscribers as $subscriber) {
$subcriber_list[] = $handles[$subscriber];
}
$subcriber_list = phutil_implode_html(', ',
mpull($subcriber_list, 'renderLink'));
$subscriber_view = array(
hsprintf('<br />Subscribers: '),
$subcriber_list,
);
}
$byline = hsprintf(
'<div class="phriction-byline">%s%s%s</div>',
pht('Last updated %s by %s.',
$when,
$handles[$content->getAuthorPHID()]->renderLink()),
$project_info,
$subscriber_view);
$doc_status = $document->getStatus();
$current_status = $content->getChangeType();
if ($current_status == PhrictionChangeType::CHANGE_EDIT ||
$current_status == PhrictionChangeType::CHANGE_MOVE_HERE) {
$core_content = $content->renderContent($user);
} else if ($current_status == PhrictionChangeType::CHANGE_DELETE) {
$notice = new AphrontErrorView();
$notice->setSeverity(AphrontErrorView::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 AphrontErrorView();
$notice->setSeverity(AphrontErrorView::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();
$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();
} else {
throw new Exception("Unknown document status '{$doc_status}'!");
}
$move_notice = null;
if ($current_status == PhrictionChangeType::CHANGE_MOVE_HERE) {
$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();
}
$page_content = hsprintf(
- '<div class="phriction-content">%s%s%s%s</div>',
- $index_link,
+ '<div class="phriction-content">%s%s%s</div>',
$byline,
$move_notice,
$core_content);
}
if ($version_note) {
$version_note = $version_note->render();
}
$children = $this->renderDocumentChildren($slug);
$crumbs = $this->buildApplicationCrumbs();
$crumb_views = $this->renderBreadcrumbs($slug);
foreach ($crumb_views as $view) {
$crumbs->addCrumb($view);
}
$actions = $this->buildActionView($user, $document);
$header = id(new PhabricatorHeaderView())
->setHeader($page_title);
return $this->buildApplicationPage(
array(
$crumbs->render(),
$header->render(),
$actions->render(),
$version_note,
$page_content,
$children,
),
array(
'title' => $page_title,
'device' => true,
));
}
private function buildActionView(
PhabricatorUser $user,
PhrictionDocument $document) {
$can_edit = PhabricatorPolicyFilter::hasCapability(
$user,
$document,
PhabricatorPolicyCapability::CAN_EDIT);
$slug = PhabricatorSlug::normalize($this->slug);
$action_view = id(new PhabricatorActionListView())
->setUser($user)
->setObject($document);
if (!$document->getID()) {
return $action_view->addAction(
id(new PhabricatorActionView())
->setName(pht('Create This Document'))
->setIcon('create')
->setHref('/phriction/edit/?slug='.$slug));
}
$action_view->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Document'))
->setIcon('edit')
->setHref('/phriction/edit/'.$document->getID().'/'));
if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) {
$action_view->addAction(
id(new PhabricatorActionView())
->setName(pht('Move Document'))
->setIcon('move')
->setHref('/phriction/move/'.$document->getID().'/')
->setWorkflow(true));
$action_view->addAction(
id(new PhabricatorActionView())
->setName(pht('Delete Document'))
->setIcon('delete')
->setHref('/phriction/delete/'.$document->getID().'/')
->setWorkflow(true));
}
return
$action_view->addAction(
id(new PhabricatorActionView())
->setName(pht('View History'))
->setIcon('history')
->setHref(PhrictionDocument::getSlugURI($slug, 'history')));
}
private function renderDocumentChildren($slug) {
$document_dao = new PhrictionDocument();
$content_dao = new PhrictionContent();
$conn = $document_dao->establishConnection('r');
$limit = 50;
$d_child = PhabricatorSlug::getDepth($slug) + 1;
$d_grandchild = PhabricatorSlug::getDepth($slug) + 2;
// 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)
AND d.status IN (%Ld)
ORDER BY d.depth, c.title LIMIT %d',
$document_dao->getTableName(),
$content_dao->getTableName(),
($slug == '/' ? '' : $slug),
$d_child,
$d_grandchild,
array(
PhrictionDocumentStatus::STATUS_EXISTS,
PhrictionDocumentStatus::STATUS_STUB,
),
$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) {
$ancestors = PhabricatorSlug::getAncestry($child['slug']);
$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,
'title' => PhabricatorSlug::getDefaultTitle($slug),
'empty' => true,
);
}
}
$children = isort($children, 'title');
$list = array();
foreach ($children as $child) {
$list[] = hsprintf('<li>');
$list[] = $this->renderChildDocumentLink($child);
$grand = idx($grandchildren, $child['slug'], array());
if ($grand) {
$list[] = hsprintf('<ul>');
foreach ($grand as $grandchild) {
$list[] = hsprintf('<li>');
$list[] = $this->renderChildDocumentLink($grandchild);
$list[] = hsprintf('</li>');
}
$list[] = hsprintf('</ul>');
}
$list[] = hsprintf('</li>');
}
if ($more_children) {
$list[] = phutil_tag('li', array(), pht('More...'));
}
return hsprintf(
'<div class="phriction-children">'.
'<div class="phriction-children-header">%s</div>'.
'%s'.
'</div>',
pht('Document Hierarchy'),
phutil_tag('ul', array(), $list));
}
private function renderChildDocumentLink(array $info) {
$title = nonempty($info['title'], pht('(Untitled Document)'));
$item = phutil_tag(
'a',
array(
'href' => PhrictionDocument::getSlugURI($info['slug']),
),
$title);
if (isset($info['empty'])) {
$item = phutil_tag('em', array(), $item);
}
return $item;
}
protected function getDocumentSlug() {
return $this->slug;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 15:51 (2 w, 6 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1126186
Default Alt Text
(18 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment