Make documentation items in user menu update as you navigate in Quicksand
Summary: Ref T5867. I sure love Javascript. Test Plan: Navigated between Home, Diffusion and Differential, opening the user profile menu. Saw appropraite help items. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5867 Differential Revision: https://secure.phabricator.com/D17214
This commit is contained in:
		| @@ -10,7 +10,7 @@ return array( | ||||
|     'conpherence.pkg.css' => '0b64e988', | ||||
|     'conpherence.pkg.js' => '6249a1cf', | ||||
|     'core.pkg.css' => '85f51b68', | ||||
|     'core.pkg.js' => '2c684890', | ||||
|     'core.pkg.js' => '666970d7', | ||||
|     'darkconsole.pkg.js' => 'e7393ebb', | ||||
|     'differential.pkg.css' => '9535a7e6', | ||||
|     'differential.pkg.js' => 'ddfeb49b', | ||||
| @@ -374,7 +374,7 @@ return array( | ||||
|     'rsrc/image/texture/table_header_hover.png' => '038ec3b9', | ||||
|     'rsrc/image/texture/table_header_tall.png' => 'd56b434f', | ||||
|     'rsrc/js/application/aphlict/Aphlict.js' => '5359e785', | ||||
|     'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '2a171a9d', | ||||
|     'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2', | ||||
|     'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'fb20ac8d', | ||||
|     'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9', | ||||
|     'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'edd1ba66', | ||||
| @@ -530,6 +530,7 @@ return array( | ||||
|     'rsrc/js/core/behavior-toggle-class.js' => '92b9ec77', | ||||
|     'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', | ||||
|     'rsrc/js/core/behavior-tooltip.js' => '42fcb747', | ||||
|     'rsrc/js/core/behavior-user-menu.js' => '31420f77', | ||||
|     'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d', | ||||
|     'rsrc/js/core/behavior-workflow.js' => '0a3f3021', | ||||
|     'rsrc/js/core/phtize.js' => 'd254d646', | ||||
| @@ -595,7 +596,7 @@ return array( | ||||
|     'inline-comment-summary-css' => '51efda3a', | ||||
|     'javelin-aphlict' => '5359e785', | ||||
|     'javelin-behavior' => '61cbc29a', | ||||
|     'javelin-behavior-aphlict-dropdown' => '2a171a9d', | ||||
|     'javelin-behavior-aphlict-dropdown' => 'caade6f2', | ||||
|     'javelin-behavior-aphlict-listen' => 'fb20ac8d', | ||||
|     'javelin-behavior-aphlict-status' => '5e2634b9', | ||||
|     'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', | ||||
| @@ -719,6 +720,7 @@ return array( | ||||
|     'javelin-behavior-toggle-widget' => '3dbf94d5', | ||||
|     'javelin-behavior-typeahead-browse' => '635de1ec', | ||||
|     'javelin-behavior-typeahead-search' => '93d0c9e3', | ||||
|     'javelin-behavior-user-menu' => '31420f77', | ||||
|     'javelin-behavior-view-placeholder' => '47830651', | ||||
|     'javelin-behavior-workflow' => '0a3f3021', | ||||
|     'javelin-color' => '7e41274a', | ||||
| @@ -1114,17 +1116,6 @@ return array( | ||||
|       'javelin-install', | ||||
|       'javelin-util', | ||||
|     ), | ||||
|     '2a171a9d' => array( | ||||
|       'javelin-behavior', | ||||
|       'javelin-request', | ||||
|       'javelin-stratcom', | ||||
|       'javelin-vector', | ||||
|       'javelin-dom', | ||||
|       'javelin-uri', | ||||
|       'javelin-behavior-device', | ||||
|       'phabricator-title', | ||||
|       'phabricator-favicon', | ||||
|     ), | ||||
|     '2b8de964' => array( | ||||
|       'javelin-install', | ||||
|       'javelin-util', | ||||
| @@ -1144,6 +1135,9 @@ return array( | ||||
|     '2ee659ce' => array( | ||||
|       'javelin-install', | ||||
|     ), | ||||
|     '31420f77' => array( | ||||
|       'javelin-behavior', | ||||
|     ), | ||||
|     '320810c8' => array( | ||||
|       'javelin-install', | ||||
|       'javelin-dom', | ||||
| @@ -1999,6 +1993,17 @@ return array( | ||||
|       'javelin-stratcom', | ||||
|       'phabricator-phtize', | ||||
|     ), | ||||
|     'caade6f2' => array( | ||||
|       'javelin-behavior', | ||||
|       'javelin-request', | ||||
|       'javelin-stratcom', | ||||
|       'javelin-vector', | ||||
|       'javelin-dom', | ||||
|       'javelin-uri', | ||||
|       'javelin-behavior-device', | ||||
|       'phabricator-title', | ||||
|       'phabricator-favicon', | ||||
|     ), | ||||
|     'ccf1cbf8' => array( | ||||
|       'javelin-install', | ||||
|       'javelin-dom', | ||||
|   | ||||
| @@ -175,7 +175,9 @@ abstract class PhabricatorApplication | ||||
|       foreach ($articles as $article) { | ||||
|         $item = id(new PhabricatorActionView()) | ||||
|           ->setName($article['name']) | ||||
|           ->setHref($article['href']); | ||||
|           ->setHref($article['href']) | ||||
|           ->addSigil('help-item') | ||||
|           ->setOpenInNewWindow(true); | ||||
|         $items[] = $item; | ||||
|       } | ||||
|     } | ||||
| @@ -189,12 +191,21 @@ abstract class PhabricatorApplication | ||||
|         $href = '/applications/mailcommands/'.$class.'/'.$key.'/'; | ||||
|         $item = id(new PhabricatorActionView()) | ||||
|           ->setName($spec['name']) | ||||
|           ->setHref($href); | ||||
|           ->setHref($href) | ||||
|           ->addSigil('help-item') | ||||
|           ->setOpenInNewWindow(true); | ||||
|         $items[] = $item; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return $items; | ||||
|     if ($items) { | ||||
|       $divider = id(new PhabricatorActionView()) | ||||
|         ->addSigil('help-item') | ||||
|         ->setType(PhabricatorActionView::TYPE_DIVIDER); | ||||
|       array_unshift($items, $divider); | ||||
|     } | ||||
|  | ||||
|     return array_values($items); | ||||
|   } | ||||
|  | ||||
|   public function getHelpDocumentationArticles(PhabricatorUser $viewer) { | ||||
|   | ||||
| @@ -2,8 +2,6 @@ | ||||
|  | ||||
| final class PhabricatorHomeApplication extends PhabricatorApplication { | ||||
|  | ||||
|   private $application; | ||||
|  | ||||
|   const DASHBOARD_DEFAULT = 'dashboard:default'; | ||||
|  | ||||
|   public function getBaseURI() { | ||||
| @@ -53,25 +51,40 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { | ||||
|     } | ||||
|  | ||||
|     $image = $viewer->getProfileImageURI(); | ||||
|     if ($controller) { | ||||
|       $this->application = $controller->getCurrentApplication(); | ||||
|     } | ||||
|  | ||||
|     $profile_image = id(new PHUIIconView()) | ||||
|       ->setImage($image) | ||||
|       ->setHeadSize(PHUIIconView::HEAD_SMALL); | ||||
|  | ||||
|     if ($controller) { | ||||
|       $application = $controller->getCurrentApplication(); | ||||
|     } else { | ||||
|       $application = null; | ||||
|     } | ||||
|     $dropdown_menu = $this->renderUserDropdown($viewer, $application); | ||||
|  | ||||
|     $menu_id = celerity_generate_unique_node_id(); | ||||
|  | ||||
|     Javelin::initBehavior( | ||||
|       'user-menu', | ||||
|       array( | ||||
|         'menuID' => $menu_id, | ||||
|         'menu' => $dropdown_menu->getDropdownMenuMetadata(), | ||||
|       )); | ||||
|  | ||||
|     return id(new PHUIButtonView()) | ||||
|       ->setID($menu_id) | ||||
|       ->setTag('a') | ||||
|       ->setHref('/p/'.$viewer->getUsername().'/') | ||||
|       ->setIcon($profile_image) | ||||
|       ->addClass('phabricator-core-user-menu') | ||||
|       ->setNoCSS(true) | ||||
|       ->setDropdown(true) | ||||
|       ->setDropdownMenu($this->renderUserDropdown($viewer)); | ||||
|       ->setHasCaret(true) | ||||
|       ->setNoCSS(true); | ||||
|   } | ||||
|  | ||||
|   private function renderUserDropdown(PhabricatorUser $viewer) { | ||||
|   private function renderUserDropdown( | ||||
|     PhabricatorUser $viewer, | ||||
|     $application) { | ||||
|  | ||||
|     $view = id(new PhabricatorActionListView()) | ||||
|       ->setViewer($viewer); | ||||
| @@ -98,16 +111,10 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { | ||||
|         ->setHref('/people/manage/'.$viewer->getID().'/')); | ||||
|  | ||||
|     // Help Menus | ||||
|     if ($this->application) { | ||||
|       $application = $this->application; | ||||
|     if ($application) { | ||||
|       $help_links = $application->getHelpMenuItems($viewer); | ||||
|       if ($help_links) { | ||||
|         $view->addAction( | ||||
|           id(new PhabricatorActionView()) | ||||
|             ->setType(PhabricatorActionView::TYPE_DIVIDER)); | ||||
|  | ||||
|         foreach ($help_links as $link) { | ||||
|           $link->setOpenInNewWindow(true); | ||||
|           $view->addAction($link); | ||||
|         } | ||||
|       } | ||||
| @@ -116,11 +123,13 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { | ||||
|     // Logout Menu | ||||
|     $view->addAction( | ||||
|       id(new PhabricatorActionView()) | ||||
|         ->addSigil('logout-item') | ||||
|         ->setType(PhabricatorActionView::TYPE_DIVIDER)); | ||||
|  | ||||
|     $view->addAction( | ||||
|       id(new PhabricatorActionView()) | ||||
|         ->setName(pht('Log Out %s', $viewer->getUsername())) | ||||
|         ->addSigil('logout-item') | ||||
|         ->setHref('/logout/') | ||||
|         ->setWorkflow(true)); | ||||
|  | ||||
|   | ||||
| @@ -278,7 +278,7 @@ final class PhabricatorActionView extends AphrontView { | ||||
|           array($icon, $this->name, $caret)); | ||||
|       } | ||||
|     } else { | ||||
|       $item = phutil_tag( | ||||
|       $item = javelin_tag( | ||||
|         'span', | ||||
|         array( | ||||
|           'class' => 'phabricator-action-view-item', | ||||
|   | ||||
| @@ -767,22 +767,6 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView | ||||
|       ->setViewer($viewer); | ||||
|     $dropdown_query->execute(); | ||||
|  | ||||
|     $rendered_dropdowns = array(); | ||||
|     $applications = array( | ||||
|       'PhabricatorHomeApplication', | ||||
|     ); | ||||
|     foreach ($applications as $application_class) { | ||||
|       if (!PhabricatorApplication::isClassInstalledForViewer( | ||||
|         $application_class, | ||||
|         $viewer)) { | ||||
|         continue; | ||||
|       } | ||||
|       $application = PhabricatorApplication::getByClass($application_class); | ||||
|       $menu = $application->buildMainMenuExtraNodes($viewer, $controller); | ||||
|       // TODO: Doesn't work with Quicksand active. | ||||
|       $rendered_dropdowns[$application_class] = hsprintf('%s', $menu); | ||||
|     } | ||||
|  | ||||
|     $hisec_warning_config = $this->getHighSecurityWarningConfig(); | ||||
|  | ||||
|     $console_config = null; | ||||
| @@ -798,6 +782,7 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView | ||||
|  | ||||
|     $application_class = null; | ||||
|     $application_search_icon = null; | ||||
|     $application_help = null; | ||||
|     $controller = $this->getController(); | ||||
|     if ($controller) { | ||||
|       $application = $controller->getCurrentApplication(); | ||||
| @@ -806,6 +791,16 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView | ||||
|         if ($application->getApplicationSearchDocumentTypes()) { | ||||
|           $application_search_icon = $application->getIcon(); | ||||
|         } | ||||
|  | ||||
|         $help_items = $application->getHelpMenuItems($viewer); | ||||
|         if ($help_items) { | ||||
|           $help_list = id(new PhabricatorActionListView()) | ||||
|             ->setViewer($viewer); | ||||
|           foreach ($help_items as $help_item) { | ||||
|             $help_list->addAction($help_item); | ||||
|           } | ||||
|           $application_help = $help_list->getDropdownMenuMetadata(); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
| @@ -817,11 +812,11 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView | ||||
|         $dropdown_query->getConpherenceData(), | ||||
|       ), | ||||
|       'globalDragAndDrop' => $upload_enabled, | ||||
|       'aphlictDropdowns' => $rendered_dropdowns, | ||||
|       'hisecWarningConfig' => $hisec_warning_config, | ||||
|       'consoleConfig' => $console_config, | ||||
|       'applicationClass' => $application_class, | ||||
|       'applicationSearchIcon' => $application_search_icon, | ||||
|       'helpItems' => $application_help, | ||||
|     ) + $this->buildAphlictListenConfigData(); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -28,6 +28,7 @@ final class PHUIButtonView extends AphrontTagView { | ||||
|   private $name; | ||||
|   private $tooltip; | ||||
|   private $noCSS; | ||||
|   private $hasCaret; | ||||
|  | ||||
|   public function setName($name) { | ||||
|     $this->name = $name; | ||||
| @@ -93,6 +94,15 @@ final class PHUIButtonView extends AphrontTagView { | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function setHasCaret($has_caret) { | ||||
|     $this->hasCaret = $has_caret; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function getHasCaret() { | ||||
|     return $this->hasCaret; | ||||
|   } | ||||
|  | ||||
|   public function setIcon($icon, $first = true) { | ||||
|     if (!($icon instanceof PHUIIconView)) { | ||||
|       $icon = id(new PHUIIconView()) | ||||
| @@ -201,7 +211,7 @@ final class PHUIButtonView extends AphrontTagView { | ||||
|     } | ||||
|  | ||||
|     $caret = null; | ||||
|     if ($this->dropdown) { | ||||
|     if ($this->dropdown || $this->getHasCaret()) { | ||||
|       $caret = phutil_tag('span', array('class' => 'caret'), ''); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -91,24 +91,6 @@ JX.behavior('aphlict-dropdown', function(config, statics) { | ||||
|     null, | ||||
|     function (e) { | ||||
|       var data = e.getData(); | ||||
|       if (config.local && config.applicationClass) { | ||||
|         var local_dropdowns = data.newResponse.aphlictDropdowns; | ||||
|         if (local_dropdowns[config.applicationClass]) { | ||||
|           JX.DOM.replace( | ||||
|             dropdown, | ||||
|             JX.$H(local_dropdowns[config.applicationClass])); | ||||
|           dropdown = JX.$(config.dropdownID); | ||||
|           if (dropdown.childNodes.length === 0) { | ||||
|             JX.DOM.hide(bubble); | ||||
|           } else { | ||||
|             JX.DOM.show(bubble); | ||||
|           } | ||||
|         } else { | ||||
|           JX.DOM.hide(bubble); | ||||
|         } | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       if (!data.fromServer) { | ||||
|         return; | ||||
|       } | ||||
|   | ||||
							
								
								
									
										57
									
								
								webroot/rsrc/js/core/behavior-user-menu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								webroot/rsrc/js/core/behavior-user-menu.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /** | ||||
|  * @provides javelin-behavior-user-menu | ||||
|  * @requires javelin-behavior | ||||
|  */ | ||||
|  | ||||
| JX.behavior('user-menu', function(config) { | ||||
|   var node = JX.$(config.menuID); | ||||
|   var list = JX.$H(config.menu.items).getFragment().firstChild; | ||||
|  | ||||
|   var menu = new JX.PHUIXDropdownMenu(node); | ||||
|  | ||||
|   menu.listen('open', function() { | ||||
|     menu.setContent(list); | ||||
|   }); | ||||
|  | ||||
|   // When the user navigates to a new page, we may need to update the links | ||||
|   // to documentation in the menu. | ||||
|   JX.Stratcom.listen('quicksand-redraw', null, function(e) { | ||||
|     var data = e.getData(); | ||||
|  | ||||
|     var new_help = data.newResponse.helpItems; | ||||
|     var nodes; | ||||
|     if (new_help) { | ||||
|       nodes = JX.$H(new_help.items).getFragment().firstChild.children; | ||||
|     } else { | ||||
|       nodes = []; | ||||
|     } | ||||
|  | ||||
|     var ii; | ||||
|  | ||||
|     var tail = []; | ||||
|     for (ii = list.children.length - 1; ii >= 0; ii--) { | ||||
|       var node = list.children[ii]; | ||||
|  | ||||
|       // Remove any old help items. | ||||
|       if (JX.Stratcom.hasSigil(node.firstChild, 'help-item')) { | ||||
|         JX.DOM.remove(node); | ||||
|       } | ||||
|  | ||||
|       // Place the logout items aside, if any exist. | ||||
|       if (JX.Stratcom.hasSigil(node.firstChild, 'logout-item')) { | ||||
|         JX.DOM.remove(node); | ||||
|         tail.push(node); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     while (nodes.length) { | ||||
|       list.appendChild(nodes[0]); | ||||
|     } | ||||
|  | ||||
|     tail.reverse(); | ||||
|     for (ii = 0; ii < tail.length; ii++) { | ||||
|       list.appendChild(tail[ii]); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley