mediawiki-skins-Vector/includes/Components/VectorComponentUserLinks.php
bwang 9e4bdd00bf Remove custom handling of user links menu items and handle case when anon editor links are disabled
Rather than try to build individually build login, logout, and create account menu items, we handle them the same as all other user links menu items in Hooks.php. While Hooks isnt ideal, there currently isnt a good path for moving that code to SkinComponents until core provides menu data. In the meantime, this patch reduces code complexity and prevents bugs like T324638.
This approach also allows us to move user links logic from SkinVector22 to VectorComponentUserLinks.php, and ensures the user links dropdown contains multiple menus, which allows us to reuse styles from page tools dropdowns.

Expected 11 visual changes:
* minor visual change where the user links dropdown has an
additional 4px vertical padding.
This padding was originally added to the page tools dropdowns
per Alex's request, but Alex also said that dropdowns should share
the same spacing. This change makes the styles all consistent
* Order of talk and contribution links have been swapped

Bug: T289212
Bug: T319356
Bug: T328954
Change-Id: Iac0586893fec26a8a6c2c904ce08fbf1e19b339c
2023-02-09 13:37:17 -06:00

175 lines
5.7 KiB
PHP

<?php
namespace MediaWiki\Skins\Vector\Components;
use Linker;
use MediaWiki\Skin\SkinComponentLink;
use MediaWiki\Skins\Vector\Constants;
use MediaWiki\Skins\Vector\VectorServices;
use Message;
use MessageLocalizer;
use Title;
use User;
/**
* VectorComponentUserLinks component
*/
class VectorComponentUserLinks implements VectorComponent {
/** @var MessageLocalizer */
private $localizer;
/** @var User */
private $user;
/** @var array */
private $portletData;
/** @var array */
private $linkOptions;
/**
* @param MessageLocalizer $localizer
* @param User $user
* @param array $portletData
* @param array $linkOptions
*/
public function __construct(
MessageLocalizer $localizer,
User $user,
array $portletData,
array $linkOptions
) {
$this->localizer = $localizer;
$this->user = $user;
$this->portletData = $portletData;
$this->linkOptions = $linkOptions;
}
/**
* @param string $key
* @return Message
*/
private function msg( $key ): Message {
return $this->localizer->msg( $key );
}
/**
* @param bool $isDefaultAnonUserLinks
* @param bool $isAnonEditorLinksEnabled
* @return VectorComponentDropdown
*/
private function getDropdown( $isDefaultAnonUserLinks, $isAnonEditorLinksEnabled ) {
$user = $this->user;
$isAnon = !$user->isRegistered();
$class = 'vector-user-menu';
if ( VectorServices::getFeatureManager()->isFeatureEnabled( Constants::FEATURE_PAGE_TOOLS ) ) {
$class .= ' mw-ui-icon-flush-right';
}
$class .= !$isAnon ?
' vector-user-menu-logged-in' :
' vector-user-menu-logged-out';
// Hide entire user links dropdown on larger viewports if it only contains
// create account & login link, which are only shown on smaller viewports
if ( $isAnon && $isDefaultAnonUserLinks && !$isAnonEditorLinksEnabled ) {
$class .= ' user-links-collapsible-item';
}
$tooltip = '';
if ( $user->isTemp() ) {
$icon = 'userAnonymous';
} elseif ( !$isAnon ) {
$icon = 'userAvatar';
} else {
$icon = 'ellipsis';
// T287494 We use tooltip messages to provide title attributes on hover over certain menu icons.
// For modern Vector, the "tooltip-p-personal" key is set to "User menu" which is appropriate for
// the user icon (dropdown indicator for user links menu) for logged-in users.
// This overrides the tooltip for the user links menu icon which is an ellipsis for anonymous users.
$tooltip = Linker::tooltip( 'vector-anon-user-menu-title' ) ?? '';
}
return new VectorComponentDropdown(
'p-personal', $this->msg( 'personaltools' )->text(), $class, $icon, $tooltip
);
}
/**
* @param bool $isDefaultAnonUserLinks
* @param bool $isAnonEditorLinksEnabled
* @return array
*/
private function getDropdownMenus( $isDefaultAnonUserLinks, $isAnonEditorLinksEnabled ) {
$user = $this->user;
$isAnon = !$user->isRegistered();
$portletData = $this->portletData;
// Hide default user menu on larger viewports if it only contains
// create account & login link, which are only shown on smaller viewports
// FIXME: Replace array_merge with an add class helper function
$userMenuClass = $portletData[ 'data-user-menu' ][ 'class' ];
$userMenuClass = $isAnon && $isDefaultAnonUserLinks ?
$userMenuClass . ' user-links-collapsible-item' : $userMenuClass;
$dropdownMenus = [
new VectorComponentMenu( [
'label' => null,
'class' => $userMenuClass
] + $portletData[ 'data-user-menu' ] )
];
if ( $isAnon ) {
// T317789: The `anontalk` and `anoncontribs` links will not be added to
// the menu if `$wgGroupPermissions['*']['edit']` === false which can
// leave the menu empty due to our removal of other user menu items in
// `Hooks::updateUserLinksDropdownItems`. In this case, we do not want
// to render the anon "learn more" link.
if ( $isAnonEditorLinksEnabled ) {
$anonEditorLabelLinkData = [
'text' => $this->msg( 'vector-anon-user-menu-pages-learn' )->text(),
'href' => Title::newFromText( $this->msg( 'vector-intro-page' )->text() )->getLocalURL(),
'aria-label' => $this->msg( 'vector-anon-user-menu-pages-label' )->text(),
];
$anonEditorLabelLink = new SkinComponentLink(
'', $anonEditorLabelLinkData, $this->localizer, $this->linkOptions
);
$anonEditorLabelLinkHtml = $anonEditorLabelLink->getTemplateData()[ 'html' ];
$dropdownMenus[] = new VectorComponentMenu( [
'label' => $this->msg( 'vector-anon-user-menu-pages' )->text() . " " . $anonEditorLabelLinkHtml,
] + $portletData[ 'data-user-menu-anon-editor' ] );
}
} else {
if ( isset( $portletData[ 'data-user-menu-logout' ] ) ) {
$dropdownMenus[] = new VectorComponentMenu( [
'label' => null
] + $portletData[ 'data-user-menu-logout' ] );
}
}
return $dropdownMenus;
}
/**
* @inheritDoc
*/
public function getTemplateData(): array {
$portletData = $this->portletData;
$user = $this->user;
$isDefaultAnonUserLinks = count( $portletData['data-user-menu']['array-items'] ) === 2;
$isAnonEditorLinksEnabled = isset( $portletData['data-user-menu-anon-editor']['is-empty'] )
&& !$portletData['data-user-menu-anon-editor']['is-empty'];
$overflowMenu = new VectorComponentMenu( [
'label' => null,
] + $portletData[ 'data-vector-user-menu-overflow' ] );
return [
'is-temp-user' => $user->isTemp(),
'is-wide' => count( $overflowMenu ) > 3,
'data-user-links-overflow-menu' => $overflowMenu->getTemplateData(),
'data-user-links-dropdown' => $this->getDropdown( $isDefaultAnonUserLinks, $isAnonEditorLinksEnabled )
->getTemplateData(),
'data-user-links-dropdown-menus' => array_map( static function ( $menu ) {
return $menu->getTemplateData();
}, $this->getDropdownMenus( $isDefaultAnonUserLinks, $isAnonEditorLinksEnabled ) ),
];
}
}