diff --git a/.storybook/icons.less b/.storybook/icons.less index 1890b6fd2..2e4e4e6f2 100644 --- a/.storybook/icons.less +++ b/.storybook/icons.less @@ -83,6 +83,10 @@ background-image: url("data:image/svg+xml;charset=utf8,%3C?xml version='1.0' encoding='UTF-8'?%3E%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Ctitle%3Euser avatar%3C/title%3E%3Cpath d='M10 11c-5.92 0-8 3-8 5v3h16v-3c0-2-2.08-5-8-5z'/%3E%3Ccircle cx='10' cy='5.5' r='4.5'/%3E%3C/svg%3E"); } +.mw-ui-icon-wikimedia-watchlist:before { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Ctitle%3E watchlist %3C/title%3E%3Cpath d='M1 3h16v2H1V3Zm0 6h6v2H1V9Zm0 6h8v2H1v-2Zm8-4.24h3.85L14.5 7l1.65 3.76H20l-3 3.17.9 4.05-3.4-2.14L11.1 18l.9-4.05-3-3.19Z'/%3E%3C/svg%3E") +} + .vector-user-menu-legacy #pt-anonuserpage, .vector-user-menu-legacy #pt-tmpuserpage, .vector-user-menu-legacy #pt-userpage a { diff --git a/includes/Hooks.php b/includes/Hooks.php index 063b0eb5b..e14ee3f9e 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -265,42 +265,66 @@ class Hooks implements } /** - * Updates personal navigation menu (user links) overflow items for modern Vector - * including 'notification', 'user-interface-preferences', 'user-page', 'vector-user-menu-overflow' + * Populates 'vector-user-menu-overflow' bucket for modern Vector with modified personal navigation (user links) + * menu items, including 'notification', 'user-interface-preferences', 'user-page', 'vector-user-menu-overflow' * + * @param SkinTemplate $sk * @param array &$content_navigation - * @suppress PhanTypeInvalidDimOffset False positives - * @suppress PhanTypeMismatchArgumentInternal False positives */ - private static function updateUserLinksOverflowItems( &$content_navigation ) { - // Upgrade preferences, notifications, and watchlist to icon buttons - // for extensions that have opted in. - if ( isset( $content_navigation['notifications'] ) ) { - self::updateMenuItems( $content_navigation, 'notifications' ); - } + private static function updateUserLinksOverflowItems( $sk, &$content_navigation ) { + $overflow = 'vector-user-menu-overflow'; + $content_navigation[$overflow] = []; + + // Logged in and logged out overflow items if ( isset( $content_navigation['user-interface-preferences']['uls'] ) ) { - $content_navigation['user-interface-preferences']['uls'] += [ + $content_navigation[$overflow]['uls'] = array_merge( + $content_navigation['user-interface-preferences']['uls'], [ 'collapsible' => true, - ]; - self::updateMenuItems( $content_navigation, 'user-interface-preferences' ); + ] ); } + + // Logged in overflow items if ( isset( $content_navigation['user-page']['userpage'] ) ) { - $content_navigation['user-page']['userpage'] = array_merge( $content_navigation['user-page']['userpage'], [ + $content_navigation[$overflow]['userpage'] = array_merge( + $content_navigation['user-page']['userpage'], [ 'button' => true, 'collapsible' => true, - 'icon' => null, + // Remove icon + 'icon' => '', ] ); - self::updateMenuItems( $content_navigation, 'user-page' ); } - if ( isset( $content_navigation['vector-user-menu-overflow']['watchlist'] ) ) { - $content_navigation['vector-user-menu-overflow']['watchlist'] += [ + if ( isset( $content_navigation['notifications'] ) ) { + foreach ( $content_navigation['notifications'] as $key => $data ) { + $content_navigation[$overflow][$key] = $data; + } + } + if ( isset( $content_navigation['user-menu']['watchlist'] ) ) { + $content_navigation[$overflow]['watchlist'] = array_merge( + $content_navigation['user-menu']['watchlist'], [ + 'id' => 'pt-watchlist-2', 'button' => true, 'collapsible' => true, 'text-hidden' => true, - 'id' => 'pt-watchlist-2', - ]; - self::updateMenuItems( $content_navigation, 'vector-user-menu-overflow' ); + ] ); } + + // Anon/temp overflow items + $user = $sk->getUser(); + $isTemp = $user->isTemp(); + $isRegistered = $user->isRegistered(); + $isCreateAccountAllowed = ( !$isRegistered || $isTemp ); + if ( isset( $content_navigation['user-menu']['createaccount'] ) && $isCreateAccountAllowed ) { + $content_navigation[$overflow]['createaccount'] = array_merge( + $content_navigation['user-menu']['createaccount'], [ + 'id' => 'pt-createaccount-2', + 'button' => true, + 'collapsible' => true, + // Remove icon + 'icon' => '', + ] ); + } + + self::updateMenuItems( $content_navigation, $overflow ); } /** @@ -318,18 +342,8 @@ class Hooks implements // users in legacy Vector. unset( $content_navigation['user-page'] ); } else { - if ( isset( $content_navigation['user-menu'] ) ) { - if ( isset( $content_navigation['user-menu']['watchlist'] ) ) { - // Copy watchlist data into 'vector-user-menu-overflow' - $content_navigation['vector-user-menu-overflow'] = [ - 'watchlist' => $content_navigation['user-menu']['watchlist'] - ]; - } - - self::updateUserLinksDropdownItems( $sk, $content_navigation ); - } - - self::updateUserLinksOverflowItems( $content_navigation ); + self::updateUserLinksOverflowItems( $sk, $content_navigation ); + self::updateUserLinksDropdownItems( $sk, $content_navigation ); } } diff --git a/includes/SkinVector.php b/includes/SkinVector.php index d06aba0bc..a633be1f0 100644 --- a/includes/SkinVector.php +++ b/includes/SkinVector.php @@ -253,15 +253,6 @@ abstract class SkinVector extends SkinMustache { return $this->makeLink( 'create-account', $createAccountData ); } - /** - * Returns HTML for the watchlist link inside user links - * @param array|null $watchlistMenuData (optional) - * @return string - */ - private function getWatchlistHTML( $watchlistMenuData = null ) { - return $watchlistMenuData ? $watchlistMenuData['html-items'] : ''; - } - /** * Returns HTML for the create account button, login button and learn more link inside the anon user menu * @param string[] $returnto array of query strings used to build the login link @@ -324,33 +315,7 @@ abstract class SkinVector extends SkinMustache { $isTempUser = $user->isTemp(); $returnto = $this->getReturnToParam(); $useCombinedLoginLink = $this->useCombinedLoginLink(); - $htmlCreateAccount = $this->getCreateAccountHTML( $returnto, false ); - - $templateParser = $this->getTemplateParser(); - // See T288428#7303233. The following conditional checks whether config is disabling account creation for - // anonymous users in modern Vector. This check excludes the use case of extensions using core and legacy hooks - // to remove the "Create account" link from the personal toolbar. Ideally this should be managed with a new hook - // that tracks account creation ability. - // Supporting removing items via hook involves unnecessary additional complexity we'd rather avoid at this time. - // (see https://gerrit.wikimedia.org/r/c/mediawiki/skins/Vector/+/713505/3) - // Account creation can be disabled by setting `$wgGroupPermissions['*']['createaccount'] = false;` - $isCreateAccountAllowed = ( $isAnon || $isTempUser ) - && $this->getAuthority()->isAllowed( 'createaccount' ); - $userMoreHtmlItems = $templateParser->processTemplate( 'UserLinks__more', [ - 'is-anon' => $isAnon, - 'is-create-account-allowed' => $isCreateAccountAllowed, - 'html-create-account' => $htmlCreateAccount, - 'data-user-interface-preferences' => $menuData[ 'data-user-interface-preferences' ], - 'data-notifications' => $menuData[ 'data-notifications' ], - 'data-user-page' => $menuData[ 'data-user-page' ], - 'html-vector-watchlist' => $this->getWatchlistHTML( $menuData[ 'data-vector-user-menu-overflow' ] ?? null ), - ] ); - $userMoreData = $this->decoratePortletData( 'data-user-more', [ - 'id' => 'p-personal-more', - 'class' => 'mw-portlet mw-portlet-personal-more vector-user-menu-more', - 'html-items' => $userMoreHtmlItems, - ] ); - + $userMenuOverflowData = $menuData[ 'data-vector-user-menu-overflow' ]; $userMenuData = $menuData[ 'data-user-menu' ]; if ( $isAnon || $isTempUser ) { $userMenuData[ 'html-before-portal' ] .= $this->getAnonMenuBeforePortletHTML( @@ -363,10 +328,10 @@ abstract class SkinVector extends SkinMustache { $userMenuData[ 'html-after-portal' ] .= $this->getLogoutHTML(); } - $moreItems = substr_count( $userMoreData['html-items'], ' $moreItems > 3, - 'data-user-more' => $userMoreData, + 'data-user-menu-overflow' => $menuData[ 'data-vector-user-menu-overflow' ], 'data-user-menu' => $userMenuData ]; } @@ -468,7 +433,6 @@ abstract class SkinVector extends SkinMustache { $skin = $this; $parentData = $this->decoratePortletsData( parent::getTemplateData() ); - $featureManager = VectorServices::getFeatureManager(); // SkinVector sometimes serves new Vector as part of removing the // skin version user preference. TCho avoid T302461 we need to unset it here. @@ -814,6 +778,9 @@ abstract class SkinVector extends SkinMustache { case 'p-cactions': $portletData['class'] .= ' vector-menu-dropdown-noicon'; break; + case 'p-vector-user-menu-overflow': + $portletData['class'] .= ' vector-user-menu-overflow'; + break; default: break; } @@ -880,7 +847,7 @@ abstract class SkinVector extends SkinMustache { case 'data-notifications': case 'data-personal': case 'data-user-page': - case 'data-user-more': + case 'data-vector-user-menu-overflow': $type = self::MENU_TYPE_DEFAULT; break; case 'data-languages': diff --git a/includes/templates/UserLinks.mustache b/includes/templates/UserLinks.mustache index 8e64f4f9b..bea3d43fc 100644 --- a/includes/templates/UserLinks.mustache +++ b/includes/templates/UserLinks.mustache @@ -1,4 +1,4 @@ -