mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 18:22:41 +01:00
Add hierarchical breadcrumbs to Phriction
Summary: Show ancestor pages when viewing a page in Phriction. Test Plan: https://secure.phabricator.com/file/view/PHID-FILE-042368dbadaa8ab826ec/ Reviewed By: hsb Reviewers: hsb, codeblock, jungejason, tuomaspelkonen, aran Commenters: aran CC: aran, hsb, epriestley Differential Revision: 654
This commit is contained in:
parent
4c44c44964
commit
73b0468f72
9 changed files with 205 additions and 16 deletions
|
@ -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',
|
||||
|
|
|
@ -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
|
|||
'<div class="phriction-header">'.
|
||||
$button.
|
||||
'<h1>'.phutil_escape_html($page_title).'</h1>'.
|
||||
$breadcrumbs.
|
||||
'</div>'.
|
||||
$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
|
||||
'<div class="phriction-breadcrumbs">'.
|
||||
$list.' · '.
|
||||
'<span class="phriction-document-crumbs">'.
|
||||
implode(" \xC2\xBB ", $breadcrumbs).
|
||||
'</span>'.
|
||||
'</div>';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @group markup
|
||||
*/
|
||||
class PhrictionDocumentTestCase extends PhabricatorTestCase {
|
||||
|
||||
public function testSlugNormalization() {
|
||||
$slugs = array(
|
||||
'' => '/',
|
||||
'/' => '/',
|
||||
'//' => '/',
|
||||
'/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}'");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/phriction/storage/document');
|
||||
phutil_require_module('phabricator', 'infrastructure/testing/testcase');
|
||||
|
||||
|
||||
phutil_require_source('PhrictionDocumentTestCase.php');
|
|
@ -29,3 +29,12 @@
|
|||
.phriction-content .phriction-link {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.phriction-breadcrumbs {
|
||||
font-size: 12px;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.phriction-document-crumbs a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue