From dd94512837d7009fad772f77953dea6e7eca9950 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 7 Dec 2012 13:32:14 -0800 Subject: [PATCH] Abstract and further merge filter menus Summary: - Adds `PhabricatorMenuItemView` which is a non-hacky object representing a single menu item. - Adds `PhabricatorMenuView`, a collection of items. - Deletes some busted/old interfaces full of garbage nonsense. - Merges menu item styles from `aphront-side-nav-view-css` and `phabricator-nav-view-css`. These are old-style and new-style rules which got partially updated recently. - The new-style menus have a darker background (#ececec) than the old-style menus (#f7f7f7) so some of the highlight/hover colors weren't visible. I shuffled them around but something or other might need further adjustment. Test Plan: looked at every menu I could Reviewers: chad Reviewed By: chad CC: aran Maniphest Tasks: T1960 Differential Revision: https://secure.phabricator.com/D4036 --- src/__celerity_resource_map__.php | 153 +++++++++--------- src/__phutil_library_map__.php | 2 + .../DifferentialRevisionViewController.php | 4 +- .../PhabricatorOwnersController.php | 26 +-- .../PhabricatorOwnersDetailController.php | 10 +- .../PhabricatorOwnersEditController.php | 10 +- .../PhabricatorOwnersListController.php | 14 +- src/view/layout/AphrontSideNavFilterView.php | 141 ++++++---------- src/view/layout/PhabricatorMenuItemView.php | 92 +++++++++++ src/view/layout/PhabricatorMenuView.php | 42 +++++ .../rsrc/css/aphront/phabricator-nav-view.css | 22 --- webroot/rsrc/css/aphront/side-nav-view.css | 37 +---- .../css/layout/phabricator-filetree-view.css | 3 +- .../rsrc/css/layout/phabricator-menu-view.css | 38 +++++ 14 files changed, 323 insertions(+), 271 deletions(-) create mode 100644 src/view/layout/PhabricatorMenuItemView.php create mode 100644 src/view/layout/PhabricatorMenuView.php create mode 100644 webroot/rsrc/css/layout/phabricator-menu-view.css diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 033a720c57..aa5cd65356 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -702,7 +702,7 @@ celerity_register_resource_map(array( ), 'aphront-side-nav-view-css' => array( - 'uri' => '/res/3e641619/rsrc/css/aphront/side-nav-view.css', + 'uri' => '/res/f697dc9b/rsrc/css/aphront/side-nav-view.css', 'type' => 'css', 'requires' => array( @@ -1613,7 +1613,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-phabricator-nav' => array( - 'uri' => '/res/3d04f9ab/rsrc/js/application/core/behavior-phabricator-nav.js', + 'uri' => '/res/0afb1ca0/rsrc/js/application/core/behavior-phabricator-nav.js', 'type' => 'js', 'requires' => array( @@ -2531,7 +2531,7 @@ celerity_register_resource_map(array( ), 'phabricator-filetree-view-css' => array( - 'uri' => '/res/214cbf2b/rsrc/css/layout/phabricator-filetree-view.css', + 'uri' => '/res/d05c5c2b/rsrc/css/layout/phabricator-filetree-view.css', 'type' => 'css', 'requires' => array( @@ -2620,9 +2620,18 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/DropdownMenuItem.js', ), + 'phabricator-menu-view-css' => + array( + 'uri' => '/res/d72130a1/rsrc/css/layout/phabricator-menu-view.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/layout/phabricator-menu-view.css', + ), 'phabricator-nav-view-css' => array( - 'uri' => '/res/84381dcf/rsrc/css/aphront/phabricator-nav-view.css', + 'uri' => '/res/68187089/rsrc/css/aphront/phabricator-nav-view.css', 'type' => 'css', 'requires' => array( @@ -3163,7 +3172,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - '2859135c' => + '58a04024' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3202,10 +3211,10 @@ celerity_register_resource_map(array( 31 => 'phabricator-filetree-view-css', 32 => 'phabricator-nav-view-css', ), - 'uri' => '/res/pkg/2859135c/core.pkg.css', + 'uri' => '/res/pkg/58a04024/core.pkg.css', 'type' => 'css', ), - 'a29ae2c4' => + 'd0aed73b' => array( 'name' => 'core.pkg.js', 'symbols' => @@ -3242,7 +3251,7 @@ celerity_register_resource_map(array( 29 => 'phabricator-textareautils', 30 => 'phabricator-file-upload', ), - 'uri' => '/res/pkg/a29ae2c4/core.pkg.js', + 'uri' => '/res/pkg/d0aed73b/core.pkg.js', 'type' => 'js', ), '3c5efda9' => @@ -3392,21 +3401,21 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => '7839ae2d', - 'aphront-crumbs-view-css' => '2859135c', - 'aphront-dialog-view-css' => '2859135c', - 'aphront-error-view-css' => '2859135c', - 'aphront-form-view-css' => '2859135c', + 'aphront-crumbs-view-css' => '58a04024', + 'aphront-dialog-view-css' => '58a04024', + 'aphront-error-view-css' => '58a04024', + 'aphront-form-view-css' => '58a04024', 'aphront-headsup-action-list-view-css' => '47549184', - 'aphront-headsup-view-css' => '2859135c', - 'aphront-list-filter-view-css' => '2859135c', - 'aphront-pager-view-css' => '2859135c', - 'aphront-panel-view-css' => '2859135c', - 'aphront-side-nav-view-css' => '2859135c', - 'aphront-table-view-css' => '2859135c', - 'aphront-tokenizer-control-css' => '2859135c', - 'aphront-tooltip-css' => '2859135c', - 'aphront-typeahead-control-css' => '2859135c', - 'autosprite-css' => '2859135c', + 'aphront-headsup-view-css' => '58a04024', + 'aphront-list-filter-view-css' => '58a04024', + 'aphront-pager-view-css' => '58a04024', + 'aphront-panel-view-css' => '58a04024', + 'aphront-side-nav-view-css' => '58a04024', + 'aphront-table-view-css' => '58a04024', + 'aphront-tokenizer-control-css' => '58a04024', + 'aphront-tooltip-css' => '58a04024', + 'aphront-typeahead-control-css' => '58a04024', + 'autosprite-css' => '58a04024', 'differential-changeset-view-css' => '47549184', 'differential-core-view-css' => '47549184', 'differential-inline-comment-editor' => '7ecd31fa', @@ -3421,18 +3430,18 @@ celerity_register_resource_map(array( 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', 'inline-comment-summary-css' => '47549184', - 'javelin-aphlict' => 'a29ae2c4', + 'javelin-aphlict' => 'd0aed73b', 'javelin-behavior' => '20727878', - 'javelin-behavior-aphlict-dropdown' => 'a29ae2c4', - 'javelin-behavior-aphlict-listen' => 'a29ae2c4', - 'javelin-behavior-aphront-basic-tokenizer' => 'a29ae2c4', + 'javelin-behavior-aphlict-dropdown' => 'd0aed73b', + 'javelin-behavior-aphlict-listen' => 'd0aed73b', + 'javelin-behavior-aphront-basic-tokenizer' => 'd0aed73b', 'javelin-behavior-aphront-drag-and-drop' => '7ecd31fa', 'javelin-behavior-aphront-drag-and-drop-textarea' => '7ecd31fa', - 'javelin-behavior-aphront-form-disable-on-submit' => 'a29ae2c4', + 'javelin-behavior-aphront-form-disable-on-submit' => 'd0aed73b', 'javelin-behavior-audit-preview' => '5e68be89', 'javelin-behavior-dark-console' => '3c5efda9', 'javelin-behavior-dark-console-ajax' => '3c5efda9', - 'javelin-behavior-device' => 'a29ae2c4', + 'javelin-behavior-device' => 'd0aed73b', 'javelin-behavior-differential-accept-with-errors' => '7ecd31fa', 'javelin-behavior-differential-add-reviewers-and-ccs' => '7ecd31fa', 'javelin-behavior-differential-comment-jump' => '7ecd31fa', @@ -3448,27 +3457,27 @@ celerity_register_resource_map(array( 'javelin-behavior-diffusion-commit-graph' => '5e68be89', 'javelin-behavior-diffusion-pull-lastmodified' => '5e68be89', 'javelin-behavior-error-log' => '3c5efda9', - 'javelin-behavior-konami' => 'a29ae2c4', - 'javelin-behavior-lightbox-attachments' => 'a29ae2c4', + 'javelin-behavior-konami' => 'd0aed73b', + 'javelin-behavior-lightbox-attachments' => 'd0aed73b', 'javelin-behavior-maniphest-batch-selector' => '7707de41', 'javelin-behavior-maniphest-subpriority-editor' => '7707de41', 'javelin-behavior-maniphest-transaction-controls' => '7707de41', 'javelin-behavior-maniphest-transaction-expand' => '7707de41', 'javelin-behavior-maniphest-transaction-preview' => '7707de41', - 'javelin-behavior-phabricator-active-nav' => 'a29ae2c4', - 'javelin-behavior-phabricator-autofocus' => 'a29ae2c4', - 'javelin-behavior-phabricator-keyboard-shortcuts' => 'a29ae2c4', - 'javelin-behavior-phabricator-nav' => 'a29ae2c4', + 'javelin-behavior-phabricator-active-nav' => 'd0aed73b', + 'javelin-behavior-phabricator-autofocus' => 'd0aed73b', + 'javelin-behavior-phabricator-keyboard-shortcuts' => 'd0aed73b', + 'javelin-behavior-phabricator-nav' => 'd0aed73b', 'javelin-behavior-phabricator-object-selector' => '7ecd31fa', - 'javelin-behavior-phabricator-oncopy' => 'a29ae2c4', - 'javelin-behavior-phabricator-remarkup-assist' => 'a29ae2c4', - 'javelin-behavior-phabricator-search-typeahead' => 'a29ae2c4', - 'javelin-behavior-phabricator-tooltips' => 'a29ae2c4', - 'javelin-behavior-phabricator-watch-anchor' => 'a29ae2c4', - 'javelin-behavior-refresh-csrf' => 'a29ae2c4', + 'javelin-behavior-phabricator-oncopy' => 'd0aed73b', + 'javelin-behavior-phabricator-remarkup-assist' => 'd0aed73b', + 'javelin-behavior-phabricator-search-typeahead' => 'd0aed73b', + 'javelin-behavior-phabricator-tooltips' => 'd0aed73b', + 'javelin-behavior-phabricator-watch-anchor' => 'd0aed73b', + 'javelin-behavior-refresh-csrf' => 'd0aed73b', 'javelin-behavior-repository-crossreference' => '7ecd31fa', - 'javelin-behavior-toggle-class' => 'a29ae2c4', - 'javelin-behavior-workflow' => 'a29ae2c4', + 'javelin-behavior-toggle-class' => 'd0aed73b', + 'javelin-behavior-workflow' => 'd0aed73b', 'javelin-color' => '20727878', 'javelin-dom' => '20727878', 'javelin-event' => '20727878', @@ -3489,42 +3498,42 @@ celerity_register_resource_map(array( 'javelin-util' => '20727878', 'javelin-vector' => '20727878', 'javelin-workflow' => '20727878', - 'lightbox-attachment-css' => '2859135c', + 'lightbox-attachment-css' => '58a04024', 'maniphest-task-summary-css' => '7839ae2d', 'maniphest-transaction-detail-css' => '7839ae2d', - 'phabricator-app-buttons-css' => '2859135c', - 'phabricator-busy' => 'a29ae2c4', + 'phabricator-app-buttons-css' => '58a04024', + 'phabricator-busy' => 'd0aed73b', 'phabricator-content-source-view-css' => '47549184', - 'phabricator-core-buttons-css' => '2859135c', - 'phabricator-core-css' => '2859135c', - 'phabricator-directory-css' => '2859135c', + 'phabricator-core-buttons-css' => '58a04024', + 'phabricator-core-css' => '58a04024', + 'phabricator-directory-css' => '58a04024', 'phabricator-drag-and-drop-file-upload' => '7ecd31fa', - 'phabricator-dropdown-menu' => 'a29ae2c4', - 'phabricator-file-upload' => 'a29ae2c4', - 'phabricator-filetree-view-css' => '2859135c', - 'phabricator-flag-css' => '2859135c', - 'phabricator-form-view-css' => '2859135c', - 'phabricator-header-view-css' => '2859135c', - 'phabricator-jump-nav' => '2859135c', - 'phabricator-keyboard-shortcut' => 'a29ae2c4', - 'phabricator-keyboard-shortcut-manager' => 'a29ae2c4', - 'phabricator-main-menu-view' => '2859135c', - 'phabricator-menu-item' => 'a29ae2c4', - 'phabricator-nav-view-css' => '2859135c', - 'phabricator-notification' => 'a29ae2c4', - 'phabricator-notification-css' => '2859135c', - 'phabricator-notification-menu-css' => '2859135c', + 'phabricator-dropdown-menu' => 'd0aed73b', + 'phabricator-file-upload' => 'd0aed73b', + 'phabricator-filetree-view-css' => '58a04024', + 'phabricator-flag-css' => '58a04024', + 'phabricator-form-view-css' => '58a04024', + 'phabricator-header-view-css' => '58a04024', + 'phabricator-jump-nav' => '58a04024', + 'phabricator-keyboard-shortcut' => 'd0aed73b', + 'phabricator-keyboard-shortcut-manager' => 'd0aed73b', + 'phabricator-main-menu-view' => '58a04024', + 'phabricator-menu-item' => 'd0aed73b', + 'phabricator-nav-view-css' => '58a04024', + 'phabricator-notification' => 'd0aed73b', + 'phabricator-notification-css' => '58a04024', + 'phabricator-notification-menu-css' => '58a04024', 'phabricator-object-selector-css' => '47549184', - 'phabricator-paste-file-upload' => 'a29ae2c4', - 'phabricator-prefab' => 'a29ae2c4', + 'phabricator-paste-file-upload' => 'd0aed73b', + 'phabricator-prefab' => 'd0aed73b', 'phabricator-project-tag-css' => '7839ae2d', - 'phabricator-remarkup-css' => '2859135c', + 'phabricator-remarkup-css' => '58a04024', 'phabricator-shaped-request' => '7ecd31fa', - 'phabricator-standard-page-view' => '2859135c', - 'phabricator-textareautils' => 'a29ae2c4', - 'phabricator-tooltip' => 'a29ae2c4', - 'phabricator-transaction-view-css' => '2859135c', - 'sprite-icon-css' => '2859135c', - 'syntax-highlighting-css' => '2859135c', + 'phabricator-standard-page-view' => '58a04024', + 'phabricator-textareautils' => 'd0aed73b', + 'phabricator-tooltip' => 'd0aed73b', + 'phabricator-transaction-view-css' => '58a04024', + 'sprite-icon-css' => '58a04024', + 'syntax-highlighting-css' => '58a04024', ), )); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 69d56f210a..7345a8c7a3 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -838,6 +838,7 @@ phutil_register_library_map(array( 'PhabricatorMarkupEngine' => 'infrastructure/markup/PhabricatorMarkupEngine.php', 'PhabricatorMarkupInterface' => 'infrastructure/markup/PhabricatorMarkupInterface.php', 'PhabricatorMenuItemView' => 'view/layout/PhabricatorMenuItemView.php', + 'PhabricatorMenuView' => 'view/layout/PhabricatorMenuView.php', 'PhabricatorMercurialGraphStream' => 'applications/repository/daemon/PhabricatorMercurialGraphStream.php', 'PhabricatorMetaMTAAttachment' => 'applications/metamta/storage/PhabricatorMetaMTAAttachment.php', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/PhabricatorMetaMTAController.php', @@ -2063,6 +2064,7 @@ phutil_register_library_map(array( 'PhabricatorMainMenuView' => 'AphrontView', 'PhabricatorMarkupCache' => 'PhabricatorCacheDAO', 'PhabricatorMenuItemView' => 'AphrontView', + 'PhabricatorMenuView' => 'AphrontView', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'PhabricatorTestCase', diff --git a/src/applications/differential/controller/DifferentialRevisionViewController.php b/src/applications/differential/controller/DifferentialRevisionViewController.php index 097d836eab..59abfaf29a 100644 --- a/src/applications/differential/controller/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/DifferentialRevisionViewController.php @@ -979,9 +979,7 @@ final class DifferentialRevisionViewController extends DifferentialController { $nav->setBaseURI(new PhutilURI('/D'.$revision->getID())); $nav->setFlexible(true); - $nav->addFilter('top', 'D'.$revision->getID(), '#top', - $relative = false, - 'phabricator-active-nav-focus'); + $nav->addFilter('top', 'D'.$revision->getID(), '#top'); $tree = new PhutilFileTree(); foreach ($changesets as $changeset) { diff --git a/src/applications/owners/controller/PhabricatorOwnersController.php b/src/applications/owners/controller/PhabricatorOwnersController.php index 2b6c9df6c3..05a3beeef6 100644 --- a/src/applications/owners/controller/PhabricatorOwnersController.php +++ b/src/applications/owners/controller/PhabricatorOwnersController.php @@ -28,32 +28,22 @@ abstract class PhabricatorOwnersController extends PhabricatorController { } public function renderSideNav() { - $package_views = array( - array('name' => 'Owned', - 'key' => 'view/owned'), - array('name' => 'All', - 'key' => 'view/all'), - ); - - $package_views = - array_merge($this->getExtraPackageViews(), - $package_views); - - $base_uri = new PhutilURI('/owners/'); $nav = new AphrontSideNavFilterView(); - $nav->setBaseUri($base_uri); + $base_uri = new PhutilURI('/owners/'); + $nav->setBaseURI($base_uri); $nav->addLabel('Packages'); - $nav->addFilters($package_views); + $this->getExtraPackageViews($nav); + $nav->addFilter('view/owned', 'Owned'); + $nav->addFilter('view/all', 'All'); - $filter = $this->getSideNavFilter(); - $nav->selectFilter($filter, 'view/owned'); + $nav->selectFilter($this->getSideNavFilter(), 'view/owned'); return $nav; } - protected function getExtraPackageViews() { - return array(); + protected function getExtraPackageViews(AphrontSideNavFilterView $view) { + return; } } diff --git a/src/applications/owners/controller/PhabricatorOwnersDetailController.php b/src/applications/owners/controller/PhabricatorOwnersDetailController.php index a7b0f7a277..0334958dc5 100644 --- a/src/applications/owners/controller/PhabricatorOwnersDetailController.php +++ b/src/applications/owners/controller/PhabricatorOwnersDetailController.php @@ -82,6 +82,9 @@ final class PhabricatorOwnersDetailController $path_links = array(); foreach ($paths as $path) { $repo = $repositories[$path->getRepositoryPHID()]; + if (!$repo) { + continue; + } $href = DiffusionRequest::generateDiffusionURI( array( 'callsign' => $repo->getCallsign(), @@ -223,12 +226,9 @@ final class PhabricatorOwnersDetailController )); } - protected function getExtraPackageViews() { + protected function getExtraPackageViews(AphrontSideNavFilterView $view) { $package = $this->package; - return array( - array('name' => 'Details', - 'key' => 'package/'.$package->getID(), - )); + $view->addFilter('package/'.$package->getID(), 'Details'); } } diff --git a/src/applications/owners/controller/PhabricatorOwnersEditController.php b/src/applications/owners/controller/PhabricatorOwnersEditController.php index 94af80fffb..77f1a00bc5 100644 --- a/src/applications/owners/controller/PhabricatorOwnersEditController.php +++ b/src/applications/owners/controller/PhabricatorOwnersEditController.php @@ -256,15 +256,11 @@ final class PhabricatorOwnersEditController )); } - protected function getExtraPackageViews() { + protected function getExtraPackageViews(AphrontSideNavFilterView $view) { if ($this->id) { - $extra = array(array('name' => 'Edit', - 'key' => 'edit/'.$this->id)); + $view->addFilter('edit/'.$this->id, 'Edit'); } else { - $extra = array(array('name' => 'New', - 'key' => 'new')); + $view->addFilter('new', 'New'); } - - return $extra; } } diff --git a/src/applications/owners/controller/PhabricatorOwnersListController.php b/src/applications/owners/controller/PhabricatorOwnersListController.php index 8dc157715c..e9c13438df 100644 --- a/src/applications/owners/controller/PhabricatorOwnersListController.php +++ b/src/applications/owners/controller/PhabricatorOwnersListController.php @@ -308,17 +308,9 @@ final class PhabricatorOwnersListController return $panel; } - protected function getExtraPackageViews() { - switch ($this->view) { - case 'search': - $extra = array(array('name' => 'Search Results', - 'key' => 'view/search')); - break; - default: - $extra = array(); - break; + protected function getExtraPackageViews(AphrontSideNavFilterView $view) { + if ($this->view == 'search') { + $view->addFilter('view/search', 'Search Results'); } - - return $extra; } } diff --git a/src/view/layout/AphrontSideNavFilterView.php b/src/view/layout/AphrontSideNavFilterView.php index 1c3078bf15..1cfbfec430 100644 --- a/src/view/layout/AphrontSideNavFilterView.php +++ b/src/view/layout/AphrontSideNavFilterView.php @@ -28,6 +28,11 @@ final class AphrontSideNavFilterView extends AphrontView { private $flexible; private $user; private $active; + private $menu; + + public function __construct() { + $this->menu = new PhabricatorMenuView(); + } public function setActive($active) { $this->active = $active; @@ -49,50 +54,49 @@ final class AphrontSideNavFilterView extends AphrontView { return $this; } - public function addFilter( - $key, - $name, - $uri = null, - $relative = false, - $class = null) { - - $this->items[] = array( - 'filter', - $key, - $name, - 'uri' => $uri, - 'relative' => $relative, - 'class' => $class, - ); - + public function addMenuItem(PhabricatorMenuItemView $item) { + $this->menu->addMenuItem($item); return $this; } - public function addFilters(array $views) { - foreach ($views as $view) { - $uri = isset($view['uri']) ? $view['uri'] : null; - $relative = isset($view['relative']) ? $view['relative'] : false; - $this->addFilter( - $view['key'], - $view['name'], - $uri, - $relative); + public function addFilter( + $key, + $name, + $uri = null) { + + $item = id(new PhabricatorMenuItemView()) + ->setKey($key) + ->setName($name); + + if ($uri) { + $item->setHref($uri); + } else { + $href = clone $this->baseURI; + $href->setPath(rtrim($href->getPath().$key, '/').'/'); + $href = (string)$href; + + $item->setHref($href); } + + return $this->addMenuItem($item); } public function addCustomBlock($block) { - $this->items[] = array('custom', null, $block); + $this->menu->appendChild($block); return $this; } public function addLabel($name) { - $this->items[] = array('label', null, $name); - return $this; + return $this->addMenuItem( + id(new PhabricatorMenuItemView()) + ->setType(PhabricatorMenuItemView::TYPE_LABEL) + ->setName($name)); } public function addSpacer() { - $this->items[] = array('spacer', null, null); - return $this; + return $this->addMenuItem( + id(new PhabricatorMenuItemView()) + ->setType(PhabricatorMenuItemView::TYPE_SPACER)); } public function setBaseURI(PhutilURI $uri) { @@ -106,21 +110,14 @@ final class AphrontSideNavFilterView extends AphrontView { public function selectFilter($key, $default = null) { $this->selectedFilter = $default; - if ($key !== null) { - foreach ($this->items as $item) { - if ($item[0] == 'filter') { - if ($item[1] == $key) { - $this->selectedFilter = $key; - break; - } - } - } + if ($this->menu->getItem($key)) { + $this->selectedFilter = $key; } return $this->selectedFilter; } public function render() { - if ($this->items) { + if ($this->menu->getItems()) { if (!$this->baseURI) { throw new Exception("Call setBaseURI() before render()!"); } @@ -129,6 +126,11 @@ final class AphrontSideNavFilterView extends AphrontView { } } + $selected_item = $this->menu->getItem($this->selectedFilter); + if ($selected_item) { + $selected_item->addClass('phabricator-menu-item-selected'); + } + if ($this->flexNav) { return $this->renderFlexNav(); } else { @@ -136,59 +138,6 @@ final class AphrontSideNavFilterView extends AphrontView { } } - private function renderNavItems() { - $results = array(); - foreach ($this->items as $item) { - list($type, $key, $name) = $item; - switch ($type) { - case 'custom': - $results[] = $name; - break; - case 'spacer': - $results[] = '
'; - break; - case 'label': - $results[] = phutil_render_tag( - 'span', - array(), - phutil_escape_html($name)); - break; - case 'filter': - $class = ($key == $this->selectedFilter) - ? 'aphront-side-nav-selected' - : null; - - $class = trim($class.' '.idx($item, 'class', '')); - - if (empty($item['uri'])) { - $href = clone $this->baseURI; - $href->setPath(rtrim($href->getPath().$key, '/').'/'); - $href = (string)$href; - } else { - if (empty($item['relative'])) { - $href = $item['uri']; - } else { - $href = clone $this->baseURI; - $href->setPath($href->getPath().$item['uri']); - $href = (string)$href; - } - } - - $results[] = phutil_render_tag( - 'a', - array( - 'href' => $href, - 'class' => $class, - ), - phutil_escape_html($name)); - break; - default: - throw new Exception("Unknown item type '{$type}'."); - } - } - return $results; - } - private function renderFlexNav() { $user = $this->user; @@ -219,7 +168,7 @@ final class AphrontSideNavFilterView extends AphrontView { } $nav_menu = null; - if ($this->items) { + if ($this->menu->getItems()) { $local_id = celerity_generate_unique_node_id(); $nav_classes[] = 'has-local-nav'; $local_menu = phutil_render_tag( @@ -228,7 +177,7 @@ final class AphrontSideNavFilterView extends AphrontView { 'class' => 'phabricator-nav-col phabricator-nav-local', 'id' => $local_id, ), - self::renderSingleView($this->renderNavItems())); + self::renderSingleView($this->menu)); } Javelin::initBehavior( @@ -282,7 +231,7 @@ final class AphrontSideNavFilterView extends AphrontView { ''. ''. ''. '
'. - self::renderSingleView($this->renderNavItems()). + self::renderSingleView($this->menu). ''. $this->renderChildren(). diff --git a/src/view/layout/PhabricatorMenuItemView.php b/src/view/layout/PhabricatorMenuItemView.php new file mode 100644 index 0000000000..0347f778fc --- /dev/null +++ b/src/view/layout/PhabricatorMenuItemView.php @@ -0,0 +1,92 @@ +key = $key; + return $this; + } + + public function getKey() { + return $this->key; + } + + public function setType($type) { + $this->type = $type; + return $this; + } + + public function getType() { + return $this->type; + } + + public function setHref($href) { + $this->href = $href; + return $this; + } + + public function getHref() { + return $this->href; + } + + public function setName($name) { + $this->name = $name; + return $this; + } + + public function getName() { + return $this->name; + } + + public function setIsExternal($is_external) { + $this->isExternal = $is_external; + return $this; + } + + public function getIsExternal() { + return $this->isExternal; + } + + public function addClass($class) { + $this->classes[] = $class; + return $this; + } + + protected function canAppendChild() { + return false; + } + + public function render() { + $classes = array( + 'phabricator-menu-item-view', + 'phabricator-menu-item-'.$this->type, + ); + + $external = null; + if ($this->isExternal) { + $external = " \xE2\x86\x97"; + } + + $classes = array_merge($classes, $this->classes); + + return phutil_render_tag( + $this->href ? 'a' : 'div', + array( + 'class' => implode(' ', $classes), + 'href' => $this->href, + ), + phutil_escape_html($this->name.$external)); + } + +} diff --git a/src/view/layout/PhabricatorMenuView.php b/src/view/layout/PhabricatorMenuView.php new file mode 100644 index 0000000000..22fb460d6c --- /dev/null +++ b/src/view/layout/PhabricatorMenuView.php @@ -0,0 +1,42 @@ +getKey(); + if ($key !== null) { + if (isset($this->map[$key])) { + throw new Exception( + "Menu contains duplicate items with key '{$key}'!"); + } + $this->map[$key] = $item; + } + + $this->items[] = $item; + $this->appendChild($item); + + return $this; + } + + public function getItem($key) { + return idx($this->map, $key); + } + + public function getItems() { + return $this->items; + } + + public function render() { + require_celerity_resource('phabricator-menu-view-css'); + return phutil_render_tag( + 'div', + array( + 'class' => 'phabricator-menu-view', + ), + $this->renderChildren()); + } + +} diff --git a/webroot/rsrc/css/aphront/phabricator-nav-view.css b/webroot/rsrc/css/aphront/phabricator-nav-view.css index ffda6019f4..0988936a44 100644 --- a/webroot/rsrc/css/aphront/phabricator-nav-view.css +++ b/webroot/rsrc/css/aphront/phabricator-nav-view.css @@ -59,11 +59,6 @@ display: none; } -.phabricator-nav-col a, -.phabricator-nav-col span { - display: block; -} - .has-local-nav .phabricator-nav-content { margin-left: 180px; } @@ -84,23 +79,6 @@ margin-left: 2.5em !important; } -.phabricator-nav-col span { - display: block; - font-weight: bold; - padding: 6px 6px 6px 12px; - color: #222222; -} - -.phabricator-nav-col a { - display: block; - padding: 3px 6px 3px 24px; - font-weight: bold; -} - -.phabricator-nav-col a.aphront-side-nav-selected { - background-color: #a1bbe5; -} - .device-desktop .phabricator-nav-head { display: none; } diff --git a/webroot/rsrc/css/aphront/side-nav-view.css b/webroot/rsrc/css/aphront/side-nav-view.css index 3349744bfc..96db7fbf14 100644 --- a/webroot/rsrc/css/aphront/side-nav-view.css +++ b/webroot/rsrc/css/aphront/side-nav-view.css @@ -15,40 +15,5 @@ th.aphront-side-nav-navigation { border-right: 1px solid #ccc; padding-bottom: 8em; background: #f7f7f7; -} - -th.aphront-side-nav-navigation a, -th.aphront-side-nav-navigation span { - display: block; - margin: 0 0 2px; - min-width: 165px; - padding: 3px 8px 3px 24px; - font-weight: bold; - white-space: nowrap; - text-decoration: none; -} - -th.aphront-side-nav-navigation span { - padding-left: 12px; - padding-top: 6px; - color: #333; - text-transform: uppercase; - font-size: 11px; -} - -th.aphront-side-nav-navigation a:hover { - text-decoration: none; - background: #e7e7e7; -} - -th.aphront-side-nav-navigation hr { - height: 1px; - background: #eee; - border: 0; - margin: 12px 0px; -} - -th.aphront-side-nav-navigation a.aphront-side-nav-selected, -th.aphront-side-nav-navigation a.aphront-side-nav-selected:hover { - background: #d7d7d7; + min-width: 175px; } diff --git a/webroot/rsrc/css/layout/phabricator-filetree-view.css b/webroot/rsrc/css/layout/phabricator-filetree-view.css index c59882a836..ba232afea6 100644 --- a/webroot/rsrc/css/layout/phabricator-filetree-view.css +++ b/webroot/rsrc/css/layout/phabricator-filetree-view.css @@ -17,6 +17,7 @@ .phabricator-filetree .phabricator-filetree-item { margin: 0; padding: 0; + display: block; } .phabricator-filetree span.phabricator-filetree-icon { @@ -30,7 +31,7 @@ .phabricator-filetree span.phabricator-filetree-name { padding: 0; - margin-left: 20px; + margin-left: 4px; font-size: 11px; font-weight: normal; line-height: 20px; diff --git a/webroot/rsrc/css/layout/phabricator-menu-view.css b/webroot/rsrc/css/layout/phabricator-menu-view.css new file mode 100644 index 0000000000..87fddf0d2f --- /dev/null +++ b/webroot/rsrc/css/layout/phabricator-menu-view.css @@ -0,0 +1,38 @@ +/** + * @provides phabricator-menu-view-css + */ + +.phabricator-menu-item-view { + display: block; + margin: 0 0 2px; + white-space: nowrap; + text-decoration: none; + font-weight: bold; + font-size: 13px; +} + +.phabricator-menu-item-type-link { + padding: 3px 8px 3px 24px; +} + +.phabricator-menu-item-type-label { + padding: 6px 8px 3px 12px; + color: #333333; + text-transform: uppercase; + font-size: 11px; +} + +.phabricator-menu-item-type-spacer { + padding: 8px 0; +} + +.device-desktop a.phabricator-menu-item-type-link:hover { + text-decoration: none; + /* TODO: Swap this back to #e7e7e7? */ + background: #a1bbe5; +} + +.phabricator-menu-item-selected, +.device-desktop a.phabricator-menu-item-selected:hover { + background: #d7d7d7; +}