diff --git a/includes/menu/Definitions.php b/includes/menu/Definitions.php index afdbdaf..66105fb 100644 --- a/includes/menu/Definitions.php +++ b/includes/menu/Definitions.php @@ -118,9 +118,8 @@ final class Definitions { public function insertLogInOutMenuItem( Group $group ) { $group->insertEntry( new AuthMenuEntry( $this->user, - $this->context->getRequest(), $this->context, - $this->context->getTitle() + $this->newLogInOutQuery( $this->newReturnToQuery() ) ) ); } @@ -274,4 +273,44 @@ final class Definitions { ) ); } + /** + * @param array $returnToQuery + * @return array + */ + private function newLogInOutQuery( array $returnToQuery ): array { + $ret = []; + $title = $this->context->getTitle(); + $user = $this->user; + if ( $title && !$title->isSpecial( 'Userlogin' ) ) { + $ret[ 'returnto' ] = $title->getPrefixedText(); + } + if ( $user && $user->isLoggedIn() ) { + $ret['logoutToken'] = $user->getEditToken( 'logoutToken', $this->context->getRequest() ); + } else { + // unset campaign on login link so as not to interfere with A/B tests + unset( $returnToQuery['campaign'] ); + } + if ( !empty( $returnToQuery ) ) { + $ret['returntoquery'] = wfArrayToCgi( $returnToQuery ); + } + return $ret; + } + + /** + * Retrieve current query parameters from Request object so system can pass those + * to the Login/logout links + * Some parameters are disabled (like title), as the returnto will be replaced with + * the current page. + * @return array + */ + private function newReturnToQuery(): array { + $returnToQuery = []; + if ( !$this->context->getRequest()->wasPosted() ) { + $returnToQuery = $this->context->getRequest()->getValues(); + unset( $returnToQuery['title'] ); + unset( $returnToQuery['returnto'] ); + unset( $returnToQuery['returntoquery'] ); + } + return $returnToQuery; + } } diff --git a/includes/menu/Entries/AuthMenuEntry.php b/includes/menu/Entries/AuthMenuEntry.php index f8eb44f..141907b 100644 --- a/includes/menu/Entries/AuthMenuEntry.php +++ b/includes/menu/Entries/AuthMenuEntry.php @@ -18,66 +18,37 @@ namespace MediaWiki\Minerva\Menu\Entries; use MessageLocalizer; -use MinervaUI; -use SpecialPage; -use Title; use User; -use WebRequest; /** * Model for a menu entry that represents log-in / profile+logout pair of links */ -class AuthMenuEntry implements IProfileMenuEntry { +final class AuthMenuEntry extends CompositeMenuEntry implements IProfileMenuEntry { /** - * @var User + * @var ProfileMenuEntry */ - private $user; - /** - * @var WebRequest - */ - private $request; - /** - * @var Title - */ - private $title; - - /** - * @var MessageLocalizer - */ - private $messageLocalizer; - - /** - * Code used to track clicks on the link to profile page - * @var string - */ - private $profileTrackingCode = 'profile'; - - /** - * Custom profile URL, can be used to override where the profile link href - * @var string|null - */ - private $customProfileURL = null; - - /** - * Custom profile label, can be used to override the profile label - * @var string|null - */ - private $customProfileLabel = null; + private $profileMenuEntry; /** * Initialize the Auth menu entry * * @param User $user Currently logged in user/anon - * @param WebRequest $request Request to load the returnToQuery values * @param MessageLocalizer $messageLocalizer used for text translation - * @param Title|null $currentTitle The current title, will be used as returnTo + * @param array $authLinksQuery Mapping of URI query parameter names to values. */ - public function __construct( User $user, WebRequest $request, - \MessageLocalizer $messageLocalizer, Title $currentTitle = null ) { - $this->user = $user; - $this->request = $request; - $this->title = $currentTitle; - $this->messageLocalizer = $messageLocalizer; + public function __construct( + User $user, MessageLocalizer $messageLocalizer, array $authLinksQuery + ) { + $this->profileMenuEntry = new ProfileMenuEntry( $user ); + $entries = $user->isLoggedIn() + ? [ + $this->profileMenuEntry, + new LogOutMenuEntry( + $messageLocalizer, $authLinksQuery, 'element', 'truncated-text secondary-action' + ) + ] + : [ new LogInMenuEntry( $messageLocalizer, $authLinksQuery ) ]; + parent::__construct( $entries ); } /** @@ -90,111 +61,8 @@ class AuthMenuEntry implements IProfileMenuEntry { /** * @inheritDoc */ - public function overrideProfileURL( $customURL, $customLabel = null, - $trackingCode = self::DEFAULT_PROFILE_TRACKING_CODE ) { - $this->customProfileURL = $customURL; - $this->customProfileLabel = $customLabel; - $this->profileTrackingCode = $trackingCode; + public function overrideProfileURL( $customURL, $customLabel = null, $trackingCode = null ) { + $this->profileMenuEntry->overrideProfileURL( $customURL, $customLabel, $trackingCode ); return $this; } - - /** - * @inheritDoc - */ - public function getCSSClasses(): array { - return []; - } - - /** - * @inheritDoc - */ - public function getComponents(): array { - $authLinksQuery = []; - $returnToQuery = $this->getReturnToQuery(); - - // Don't ever redirect back to the login page (bug 55379) - if ( $this->title && !$this->title->isSpecial( 'Userlogin' ) ) { - $authLinksQuery[ 'returnto' ] = $this->title->getPrefixedText(); - } - - return $this->user->isLoggedIn() - ? $this->buildComponentsForLoggedIn( $returnToQuery, $authLinksQuery ) - : $this->buildComponentsForAnon( $returnToQuery, $authLinksQuery ); - } - - /** - * Retrieve current query parameters from Request object so system can pass those - * to the Login/logout links - * Some parameters are disabled (like title), as the returnto will be replaced with - * the current page. - * @return array - */ - private function getReturnToQuery(): array { - $returnToQuery = []; - - if ( !$this->request->wasPosted() ) { - $returnToQuery = $this->request->getValues(); - unset( $returnToQuery['title'] ); - unset( $returnToQuery['returnto'] ); - unset( $returnToQuery['returntoquery'] ); - } - return $returnToQuery; - } - - /** - * @param array $returnToQuery - * @param array $authLinksQuery - * @return array - * @throws \MWException - */ - private function buildComponentsForLoggedIn( array $returnToQuery, array $authLinksQuery ): array { - if ( !empty( $returnToQuery ) ) { - $authLinksQuery['returntoquery'] = wfArrayToCgi( $returnToQuery ); - } - $authLinksQuery['logoutToken'] = $this->user->getEditToken( 'logoutToken', $this->request ); - - $logoutURL = SpecialPage::getTitleFor( 'Userlogout' )->getLocalURL( $authLinksQuery ); - $username = $this->user->getName(); - $profileUrl = $this->customProfileURL ?? - Title::newFromText( $username, NS_USER )->getLocalURL(); - $profileLabel = $this->customProfileLabel ?? $username; - - return [ - [ - 'text' => $profileLabel, - 'href' => $profileUrl, - 'class' => MinervaUI::iconClass( 'profile', 'before', - 'truncated-text primary-action' ), - 'data-event-name' => $this->profileTrackingCode - ], - [ - 'text' => $this->messageLocalizer->msg( 'mobile-frontend-main-menu-logout' )->escaped(), - 'href' => $logoutURL, - 'class' => MinervaUI::iconClass( 'logout', 'element', - 'truncated-text secondary-action' ), - 'data-event-name' => 'logout' - ] - ]; - } - - /** - * @param array $returnToQuery - * @param $authLinksQuery - * @return array - */ - private function buildComponentsForAnon( array $returnToQuery, $authLinksQuery ): array { - // unset campaign on login link so as not to interfere with A/B tests - unset( $returnToQuery['campaign'] ); - if ( !empty( $returnToQuery ) ) { - $authLinksQuery['returntoquery'] = wfArrayToCgi( $returnToQuery ); - } - - return [ - 'text' => $this->messageLocalizer->msg( 'mobile-frontend-main-menu-login' )->escaped(), - 'href' => SpecialPage::getTitleFor( 'Userlogin' )->getLocalURL( $authLinksQuery ), - 'class' => MinervaUI::iconClass( 'login', 'before' ), - 'data-event-name' => 'login' - ]; - } - } diff --git a/includes/menu/Entries/CompositeMenuEntry.php b/includes/menu/Entries/CompositeMenuEntry.php new file mode 100644 index 0000000..c5c98bc --- /dev/null +++ b/includes/menu/Entries/CompositeMenuEntry.php @@ -0,0 +1,54 @@ +entries = $entries; + } + + /** + * @inheritDoc + */ + public function getCSSClasses(): array { + $classes = []; + foreach ( $this->entries as $entry ) { + $classes = array_merge( $classes, $entry->getCSSClasses() ); + } + return $classes; + } + + /** + * @inheritDoc + */ + public function getComponents(): array { + $components = []; + foreach ( $this->entries as $entry ) { + $components = array_merge( $components, $entry->getComponents() ); + } + return $components; + } +} diff --git a/includes/menu/Entries/LogInMenuEntry.php b/includes/menu/Entries/LogInMenuEntry.php new file mode 100644 index 0000000..ce6fa35 --- /dev/null +++ b/includes/menu/Entries/LogInMenuEntry.php @@ -0,0 +1,33 @@ +msg( 'mobile-frontend-main-menu-login' )->escaped(); + $url = SpecialPage::getTitleFor( 'Userlogin' )->getLocalURL( $authLinksQuery ); + parent::__construct( 'login', $text, $url ); + } +} diff --git a/includes/menu/Entries/LogOutMenuEntry.php b/includes/menu/Entries/LogOutMenuEntry.php new file mode 100644 index 0000000..177dcbb --- /dev/null +++ b/includes/menu/Entries/LogOutMenuEntry.php @@ -0,0 +1,37 @@ +msg( 'mobile-frontend-main-menu-logout' )->escaped(); + $url = SpecialPage::getTitleFor( 'Userlogout' )->getLocalURL( $authLinksQuery ); + parent::__construct( 'logout', $text, $url, true, null, $iconType, $classes ); + } +} diff --git a/includes/menu/Entries/MenuEntry.php b/includes/menu/Entries/MenuEntry.php index 6b581b8..91e0464 100644 --- a/includes/menu/Entries/MenuEntry.php +++ b/includes/menu/Entries/MenuEntry.php @@ -20,9 +20,18 @@ namespace MediaWiki\Minerva\Menu\Entries; /** * Model for a menu entry. */ -class MenuEntry implements IMenuEntry { +final class MenuEntry implements IMenuEntry { + /** + * @var string + */ private $name; + /** + * @var bool + */ private $isJSOnly; + /** + * @var array + */ private $components; /** @@ -83,5 +92,4 @@ class MenuEntry implements IMenuEntry { ] + $attrs; return $this; } - } diff --git a/includes/menu/Entries/ProfileMenuEntry.php b/includes/menu/Entries/ProfileMenuEntry.php new file mode 100644 index 0000000..1caf631 --- /dev/null +++ b/includes/menu/Entries/ProfileMenuEntry.php @@ -0,0 +1,92 @@ +user = $user; + } + + /** + * @inheritDoc + */ + public function getName() { + return 'profile'; + } + + /** + * @inheritDoc + */ + public function overrideProfileURL( $customURL, $customLabel = null, $trackingCode = null ) { + $this->customProfileURL = $customURL; + $this->customProfileLabel = $customLabel; + $this->profileTrackingCode = $trackingCode; + return $this; + } + + /** + * @inheritDoc + */ + public function getCSSClasses(): array { + return []; + } + + /** + * @inheritDoc + */ + public function getComponents(): array { + $username = $this->user->getName(); + return [ [ + 'text' => $this->customProfileLabel ?? $username, + 'href' => $this->customProfileURL ?? Title::newFromText( $username, NS_USER )->getLocalURL(), + 'class' => MinervaUI::iconClass( 'profile', 'before', 'truncated-text primary-action' ), + 'data-event-name' => + $this->profileTrackingCode ?? self::DEFAULT_PROFILE_TRACKING_CODE + ] ]; + } +} diff --git a/includes/menu/Entries/SingleMenuEntry.php b/includes/menu/Entries/SingleMenuEntry.php index c8ca57a..78c217a 100644 --- a/includes/menu/Entries/SingleMenuEntry.php +++ b/includes/menu/Entries/SingleMenuEntry.php @@ -41,13 +41,17 @@ class SingleMenuEntry implements IMenuEntry { * @param bool|string $trackClicks Should clicks be tracked. To override the tracking code * pass the tracking code as string * @param string|null $iconName The Icon name, if not defined, the $name will be used + * @param string $iconType 'before' or 'element' + * @param string $classes Additional CSS class names. */ - public function __construct( $name, $text, $url, $trackClicks = true, $iconName = null ) { + public function __construct( + $name, $text, $url, $trackClicks = true, $iconName = null, $iconType = 'before', $classes = '' + ) { $this->name = $name; $this->component = [ 'text' => $text, 'href' => $url, - 'class' => MinervaUI::iconClass( $iconName ?? $name, 'before' ), + 'class' => MinervaUI::iconClass( $iconName ?? $name, $iconType, $classes ), ]; if ( $trackClicks !== false ) { $this->component['data-event-name'] = $trackClicks === true ? $name : $trackClicks; diff --git a/includes/menu/Group.php b/includes/menu/Group.php index 1bfd8a4..5aba657 100644 --- a/includes/menu/Group.php +++ b/includes/menu/Group.php @@ -27,7 +27,7 @@ use MediaWiki\Minerva\Menu\Entries\MenuEntry; /** * Model for a menu that can be presented in a skin. */ -class Group { +final class Group { /** * @var IMenuEntry[] */