diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 74353d4215..71113b0984 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -586,6 +586,7 @@ phutil_register_library_map(array(
'PhrictionDAO' => 'applications/phriction/storage/base',
'PhrictionDocument' => 'applications/phriction/storage/document',
'PhrictionDocumentController' => 'applications/phriction/controller/document',
+ 'PhrictionDocumentTestCase' => 'applications/phriction/storage/document/__tests__',
'PhrictionEditController' => 'applications/phriction/controller/edit',
'PhrictionHistoryController' => 'applications/phriction/controller/history',
'PhrictionListController' => 'applications/phriction/controller/list',
@@ -1085,6 +1086,7 @@ phutil_register_library_map(array(
'PhrictionDAO' => 'PhabricatorLiskDAO',
'PhrictionDocument' => 'PhrictionDAO',
'PhrictionDocumentController' => 'PhrictionController',
+ 'PhrictionDocumentTestCase' => 'PhabricatorTestCase',
'PhrictionEditController' => 'PhrictionController',
'PhrictionHistoryController' => 'PhrictionController',
'PhrictionListController' => 'PhrictionController',
diff --git a/src/applications/phriction/controller/document/PhrictionDocumentController.php b/src/applications/phriction/controller/document/PhrictionDocumentController.php
index 2da85b1d31..01e68e1568 100644
--- a/src/applications/phriction/controller/document/PhrictionDocumentController.php
+++ b/src/applications/phriction/controller/document/PhrictionDocumentController.php
@@ -42,6 +42,8 @@ class PhrictionDocumentController
'slug = %s',
$slug);
+ $breadcrumbs = $this->renderBreadcrumbs($slug);
+
if (!$document) {
$create_uri = '/phriction/edit/?slug='.$slug;
@@ -112,6 +114,7 @@ class PhrictionDocumentController
'
'.
$page_content;
@@ -124,4 +127,57 @@ class PhrictionDocumentController
}
+ private function renderBreadcrumbs($slug) {
+
+ $ancestor_handles = array();
+ $ancestral_slugs = PhrictionDocument::getSlugAncestry($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 = id(new PhabricatorObjectHandleData($ancestor_phids))
+ ->loadHandles();
+ }
+
+ $ancestor_handles = array();
+ foreach ($ancestral_slugs as $slug) {
+ if (isset($ancestors[$slug])) {
+ $ancestor_handles[] = $handles[$ancestors[$slug]->getPHID()];
+ } else {
+ $handle = new PhabricatorObjectHandle();
+ $handle->setName(PhrictionDocument::getDefaultSlugTitle($slug));
+ $handle->setURI(PhrictionDocument::getSlugURI($slug));
+ $ancestor_handles[] = $handle;
+ }
+ }
+ }
+
+ $breadcrumbs = array();
+ foreach ($ancestor_handles as $ancestor_handle) {
+ $breadcrumbs[] = $ancestor_handle->renderLink();
+ }
+
+ $list = phutil_render_tag(
+ 'a',
+ array(
+ 'href' => '/phriction/',
+ ),
+ 'Document Index');
+
+ return
+ ''.
+ $list.' · '.
+ ''.
+ implode(" \xC2\xBB ", $breadcrumbs).
+ ''.
+ '
';
+ }
+
}
diff --git a/src/applications/phriction/controller/document/__init__.php b/src/applications/phriction/controller/document/__init__.php
index 6d7452f7b7..17fc281f88 100644
--- a/src/applications/phriction/controller/document/__init__.php
+++ b/src/applications/phriction/controller/document/__init__.php
@@ -8,6 +8,7 @@
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/markup/engine');
+phutil_require_module('phabricator', 'applications/phid/handle');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/phriction/controller/base');
phutil_require_module('phabricator', 'applications/phriction/storage/content');
diff --git a/src/applications/phriction/controller/edit/PhrictionEditController.php b/src/applications/phriction/controller/edit/PhrictionEditController.php
index f7bad2cf12..0f7d7d2f4a 100644
--- a/src/applications/phriction/controller/edit/PhrictionEditController.php
+++ b/src/applications/phriction/controller/edit/PhrictionEditController.php
@@ -40,12 +40,9 @@ class PhrictionEditController
}
$content = id(new PhrictionContent())->load($document->getContentID());
} else if ($slug) {
- $document = null;
- if ($slug) {
- $document = id(new PhrictionDocument())->loadOneWhere(
- 'slug = %s',
- $slug);
- }
+ $document = id(new PhrictionDocument())->loadOneWhere(
+ 'slug = %s',
+ $slug);
if ($document) {
$content = id(new PhrictionContent())->load($document->getContentID());
@@ -56,14 +53,7 @@ class PhrictionEditController
$content = new PhrictionContent();
$content->setSlug($slug);
- $default_title = null;
- if ($slug) {
- $parts = explode('/', trim($slug, '/'));
- $default_title = end($parts);
- $default_title = str_replace('_', ' ', $default_title);
- $default_title = ucwords($default_title);
- }
- $default_title = nonempty($default_title, 'New Document');
+ $default_title = PhrictionDocument::getDefaultSlugTitle($slug);
$content->setTitle($default_title);
}
} else {
diff --git a/src/applications/phriction/storage/document/PhrictionDocument.php b/src/applications/phriction/storage/document/PhrictionDocument.php
index d65fcec63f..8dc1cb164f 100644
--- a/src/applications/phriction/storage/document/PhrictionDocument.php
+++ b/src/applications/phriction/storage/document/PhrictionDocument.php
@@ -57,7 +57,6 @@ class PhrictionDocument extends PhrictionDAO {
}
}
-
public static function normalizeSlug($slug) {
// TODO: We need to deal with unicode at some point, this is just a very
@@ -72,9 +71,51 @@ class PhrictionDocument extends PhrictionDAO {
return $slug.'/';
}
+ public static function getDefaultSlugTitle($slug) {
+ $parts = explode('/', trim($slug, '/'));
+ $default_title = end($parts);
+ $default_title = str_replace('_', ' ', $default_title);
+ $default_title = ucwords($default_title);
+ $default_title = nonempty($default_title, 'Untitled Document');
+ return $default_title;
+ }
+
+ public static function getSlugAncestry($slug) {
+ $slug = self::normalizeSlug($slug);
+
+ if ($slug == '/') {
+ return array();
+ }
+
+ $ancestors = array(
+ '/',
+ );
+
+ $slug = explode('/', $slug);
+ array_pop($slug);
+ array_pop($slug);
+
+ $accumulate = '';
+ foreach ($slug as $part) {
+ $accumulate .= $part.'/';
+ $ancestors[] = $accumulate;
+ }
+
+ return $ancestors;
+ }
+
+ public static function getSlugDepth($slug) {
+ $slug = self::normalizeSlug($slug);
+ if ($slug == '/') {
+ return 0;
+ } else {
+ return substr_count($slug, '/');
+ }
+ }
+
public function setSlug($slug) {
$this->slug = self::normalizeSlug($slug);
- $this->depth = substr_count($this->slug, '/');
+ $this->depth = self::getSlugDepth($slug);
return $this;
}
diff --git a/src/applications/phriction/storage/document/__init__.php b/src/applications/phriction/storage/document/__init__.php
index bf16f121cd..f1fb50f9da 100644
--- a/src/applications/phriction/storage/document/__init__.php
+++ b/src/applications/phriction/storage/document/__init__.php
@@ -10,5 +10,7 @@ phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phabricator', 'applications/phriction/storage/base');
+phutil_require_module('phutil', 'utils');
+
phutil_require_source('PhrictionDocument.php');
diff --git a/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php b/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php
new file mode 100644
index 0000000000..fb25732e02
--- /dev/null
+++ b/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php
@@ -0,0 +1,75 @@
+ '/',
+ '/' => '/',
+ '//' => '/',
+ '/derp/' => 'derp/',
+ 'derp' => 'derp/',
+ 'derp//derp' => 'derp/derp/',
+ 'DERP//DERP' => 'derp/derp/',
+ 'a B c' => 'a_b_c/',
+ );
+
+ foreach ($slugs as $slug => $normal) {
+ $this->assertEqual(
+ $normal,
+ PhrictionDocument::normalizeSlug($slug),
+ "Normalization of '{$slug}'");
+ }
+ }
+
+ public function testSlugAncestry() {
+ $slugs = array(
+ '/' => array(),
+ 'pokemon/' => array('/'),
+ 'pokemon/squirtle/' => array('/', 'pokemon/'),
+ );
+
+ foreach ($slugs as $slug => $ancestry) {
+ $this->assertEqual(
+ $ancestry,
+ PhrictionDocument::getSlugAncestry($slug),
+ "Ancestry of '{$slug}'");
+ }
+ }
+
+ public function testSlugDepth() {
+ $slugs = array(
+ '/' => 0,
+ 'a/' => 1,
+ 'a/b/' => 2,
+ 'a////b/' => 2,
+ );
+
+ foreach ($slugs as $slug => $depth) {
+ $this->assertEqual(
+ $depth,
+ PhrictionDocument::getSlugDepth($slug),
+ "Depth of '{$slug}'");
+ }
+ }
+
+}
diff --git a/src/applications/phriction/storage/document/__tests__/__init__.php b/src/applications/phriction/storage/document/__tests__/__init__.php
new file mode 100644
index 0000000000..aaec2c0220
--- /dev/null
+++ b/src/applications/phriction/storage/document/__tests__/__init__.php
@@ -0,0 +1,13 @@
+