Merge "[UI] [new] add user menu"

This commit is contained in:
jenkins-bot 2019-07-24 18:41:46 +00:00 committed by Gerrit Code Review
commit 84b950da58
20 changed files with 375 additions and 25 deletions

View File

@ -47,6 +47,7 @@
"mobile-frontend-user-page-member-since": "{{GENDER:$2|Joined}} $1",
"mobile-frontend-user-page-talk": "Talk",
"mobile-frontend-user-page-uploads": "Uploads",
"minerva-user-menu-button": "User menu",
"minerva-page-actions-overflow": "Secondary page actions submenu",
"minerva-page-actions-info": "Page information",
"minerva-page-actions-permalink": "Permanent link",

View File

@ -56,6 +56,7 @@
"mobile-frontend-user-page-member-since": "Message below the heading. $1 is the user registration date. $2 is the gender associated with the user account.",
"mobile-frontend-user-page-talk": "Text of the link to the user's talk page\n{{Identical|Talk}}",
"mobile-frontend-user-page-uploads": "Text of the link to the user's uploads page\n{{Identical|Upload}}",
"minerva-user-menu-button": "Text describing the user menu",
"minerva-page-actions-overflow": "Text describing the secondary page menu button's action",
"minerva-page-actions-info": "In the secondary page menu, the page information button label",
"minerva-page-actions-permalink": "In the secondary page menu, the permanent link button label",

View File

@ -24,6 +24,8 @@ use IContextSource;
use MediaWiki\Special\SpecialPageFactory;
use MediaWiki\Minerva\Menu\Entries\AuthMenuEntry;
use MediaWiki\Minerva\Menu\Entries\HomeMenuEntry;
use MediaWiki\Minerva\Menu\Entries\LogInMenuEntry;
use MediaWiki\Minerva\Menu\Entries\LogOutMenuEntry;
use MediaWiki\Minerva\Menu\Entries\SingleMenuEntry;
use Message;
use MinervaUI;
@ -108,6 +110,32 @@ final class Definitions {
) );
}
/**
* Creates a log in or log out button.
*
* @param Group $group
* @throws MWException
*/
public function insertLogInMenuItem( Group $group ) {
$group->insertEntry( new LogInMenuEntry(
$this->context,
$this->newLogInOutQuery( $this->newReturnToQuery() )
) );
}
/**
* Creates a log in or log out button.
*
* @param Group $group
* @throws MWException
*/
public function insertLogOutMenuItem( Group $group ) {
$group->insertEntry( new LogOutMenuEntry(
$this->context,
$this->newLogInOutQuery( $this->newReturnToQuery() )
) );
}
/**
* Creates a login or logout button with a profile button.
*

View File

@ -97,13 +97,6 @@ final class AdvancedBuilder implements IBuilder {
private function getPersonalTools(): Group {
$group = new Group();
$this->definitions->insertAuthMenuItem( $group );
if ( $this->user->isLoggedIn() ) {
$this->definitions->insertWatchlistMenuItem( $group );
$this->definitions->insertContributionsMenuItem( $group );
}
// Allow other extensions to add or override tools
Hooks::run( 'MobileMenu', [ 'personal', &$group ] );
return $group;

View File

@ -121,7 +121,7 @@ class UserNamespaceOverflowBuilder implements IOverflowBuilder {
* Build entry based on the $toolbox element
*
* @param string $name
* @param string $icon Wikimedia UI icon name.
* @param string $icon Icon CSS class name.
* @param string $toolboxIdx
* @param array $toolbox An array of common toolbox items from the sidebar menu
* @return PageActionMenuEntry|null

View File

@ -0,0 +1,100 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\Minerva\Menu\User;
use IContextSource;
use MediaWiki\Minerva\Menu\Definitions;
use MediaWiki\Minerva\Menu\Entries\ProfileMenuEntry;
use MediaWiki\Minerva\Menu\Entries\SingleMenuEntry;
use MediaWiki\Minerva\Menu\Group;
use User;
/**
* Logged-in, advanced Mobile Contributions user menu config generator.
*/
final class AdvancedUserMenuBuilder implements IUserMenuBuilder {
/**
* @var IContextSource
*/
private $context;
/**
* @var User
*/
private $user;
/**
* @var Definitions
*/
private $definitions;
/**
* @var array|null
*/
private $sandbox;
/**
* @param IContextSource $context
* @param User $user
* @param Definitions $definitions A menu items definitions set
* @param array|null $sandbox
*/
public function __construct(
IContextSource $context, User $user, Definitions $definitions, $sandbox
) {
$this->context = $context;
$this->user = $user;
$this->definitions = $definitions;
$this->sandbox = $sandbox;
}
/**
* @inheritDoc
* @return Group
*/
public function getGroup(): Group {
$group = new Group();
$group->insertEntry( new ProfileMenuEntry( $this->user ) );
$group->insertEntry( new SingleMenuEntry(
'userTalk',
$this->context->msg( 'mobile-frontend-user-page-talk' )->escaped(),
$this->user->getUserPage()->getTalkPage()->getLocalURL(),
true,
null,
'before',
'wikimedia-ui-userTalk-base20'
) );
if ( $this->sandbox ) {
$group->insertEntry( new SingleMenuEntry(
'userSandbox',
$this->sandbox['text'],
$this->sandbox['href']
) );
}
$this->definitions->insertWatchlistMenuItem( $group );
$this->definitions->insertContributionsMenuItem( $group );
if ( $this->user->isAnon() ) {
$this->definitions->insertLogInMenuItem( $group );
} else {
$this->definitions->insertLogOutMenuItem( $group );
}
return $group;
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\Minerva\Menu\User;
use MediaWiki\Minerva\Menu\Group;
/**
* Nonspecific user menu builder.
*/
final class DefaultUserMenuBuilder implements IUserMenuBuilder {
/**
* @inheritDoc
* @return Group
*/
public function getGroup(): Group {
return new Group();
}
}

View File

@ -0,0 +1,30 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\Minerva\Menu\User;
use MediaWiki\Minerva\Menu\Group;
interface IUserMenuBuilder {
/**
* @return Group
*/
public function getGroup(): Group;
}

View File

@ -0,0 +1,77 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\Minerva\Menu\User;
use MinervaUI;
use TemplateParser;
use MessageLocalizer;
/**
* Director responsible for building the user menu.
*/
final class UserMenuDirector {
/**
* @var IUserMenuBuilder
*/
private $builder;
/**
* @var MessageLocalizer
*/
private $localizer;
/**
* @param IUserMenuBuilder $builder
* @param MessageLocalizer $localizer
*/
public function __construct( IUserMenuBuilder $builder, MessageLocalizer $localizer ) {
$this->builder = $builder;
$this->localizer = $localizer;
}
/**
* Build the menu data array that can be passed to views/javascript
* @return string|null
*/
public function renderMenuData() {
$entries = $this->builder->getGroup()->getEntries();
foreach ( $entries as &$entry ) {
foreach ( $entry['components'] as &$component ) {
$component['class'] .= ' toggle-list-item__anchor--menu';
}
}
$templateParser = new TemplateParser( __DIR__ . '/../../../components' );
return empty( $entries )
? null
: $templateParser->processTemplate( 'ToggleList', [
'class' => 'minerva-user-menu',
'checkboxID' => 'minerva-user-menu-checkbox',
'toggleID' => 'minerva-user-menu-toggle', // See minerva.mustache too.
'toggleClass' => MinervaUI::iconClass(
'page-actions-overflow', 'element', 'wikimedia-ui-' . 'userAvatar' . '-base20'
),
'listClass' => 'minerva-user-menu-list toggle-list__list--drop-down', // See ToggleList/*.less.
'text' => $this->localizer->msg( 'minerva-user-menu-button' )->escaped(),
'items' => $entries
] );
}
}

View File

@ -266,6 +266,7 @@ class MinervaTemplate extends BaseTemplate {
'postheadinghtml' => $data['postheadinghtml'] ?? '',
'haspageactions' => $hasPageActions,
'pageactionshtml' => $hasPageActions ? $this->getPageActionsHtml() : '',
'userMenuHTML' => $data['userMenuHTML'],
'subtitle' => $data['subtitle'],
'contenthtml' => $this->getContentHtml( $data ),
'secondaryactionshtml' => $this->getSecondaryActionsHtml(),

View File

@ -23,6 +23,10 @@ use MediaWiki\Minerva\Menu\Main\Director as MainMenuDirector;
use MediaWiki\Minerva\Permissions\IMinervaPagePermissions;
use MediaWiki\Minerva\SkinOptions;
use MediaWiki\Minerva\SkinUserPageHelper;
use MediaWiki\Minerva\Menu\User\UserMenuDirector;
use MediaWiki\Minerva\Menu\User\AdvancedUserMenuBuilder;
use MediaWiki\Minerva\Menu\User\DefaultUserMenuBuilder;
use MediaWiki\Minerva\Menu\Definitions;
/**
* Minerva: Born from the godhead of Jupiter with weapons!
@ -89,6 +93,29 @@ class SkinMinerva extends SkinTemplate {
return $this->mainMenu;
}
/**
* @param BaseTemplate $tpl
* @return string|null
*/
private function getUserMenuHTML( BaseTemplate $tpl ) {
$services = MediaWikiServices::getInstance();
$options = $services->getService( 'Minerva.SkinOptions' );
$context = RequestContext::getMain();
$definitions = new Definitions( $context, $services->getSpecialPageFactory() );
$director = new UserMenuDirector(
$options->get( SkinOptions::OPTION_AMC )
? new AdvancedUserMenuBuilder(
$context,
$this->getUser(),
$definitions,
$tpl->getPersonalTools()['sandbox']['links'][0] ?? null
)
: new DefaultUserMenuBuilder(),
$this
);
return $director->renderMenuData();
}
/**
* Returns the site name for the footer, either as a text or <img> tag
* @return string
@ -156,6 +183,9 @@ class SkinMinerva extends SkinTemplate {
// Set the links for the main menu
$tpl->set( 'mainMenu', $this->getMainMenu()->getMenuData() );
// Set the links for page secondary actions
$tpl->set( 'userMenuHTML', $this->getUserMenuHTML( $tpl ) );
// Set the links for page secondary actions
$tpl->set( 'secondary_actions', $this->getSecondaryActions( $tpl ) );
@ -774,14 +804,6 @@ class SkinMinerva extends SkinTemplate {
return [];
}
/**
* Minerva skin do use any of those, there is no need to calculate that
* @return array
*/
protected function buildPersonalUrls() {
return [];
}
/**
* Returns array of config variables that should be added only to this skin
* for use in JavaScript.

View File

@ -18,8 +18,15 @@
autocomplete="off" placeholder="{{placeholder}}" aria-label="{{placeholder}}"
value="{{search}}">
</div>
<div>{{{searchButton}}}</div>
{{^isAnon}}<div>{{#userNotificationsData}}{{>userNotifications}}{{/userNotificationsData}}</div>{{/isAnon}}
<nav class="minerva-user-navigation" aria-labelledby="minerva-user-menu-toggle"> {{! See ToggleList's toggleID. }}
<div>{{{searchButton}}}</div>
{{^isAnon}}
<div class="minerva-user-notifications">
{{#userNotificationsData}}{{>userNotifications}}{{/userNotificationsData}}
</div>
{{/isAnon}}
{{#userMenuHTML}}{{{userMenuHTML}}}{{/userMenuHTML}}
</nav>
</form>
</header>
<main id="content" class="mw-body">
@ -56,4 +63,4 @@
</div>
</div>
<div class="mw-notification-area" data-mw="interface"></div>
<!-- v:8.1.7 -->
<!-- v:8.1.8 -->

View File

@ -34,6 +34,7 @@
@menuWidthTablet: 600px;
@rightDrawerWidth: 60%;
@primaryNavBackgroundColor: @colorGray14;
@menuButtonIconSize: 3.5em;
// Headings
@firstHeadingFontSize: 2.6525em; // 42px
@ -52,7 +53,7 @@
@searchBoxWidth: 375/16em;
@iconSizeTotal: @iconSize + @iconGutterWidth + @iconGutterWidth;
@deviceWidthTabletEms: unit( @width-breakpoint-tablet / @fontSizeBrowserDefault, em );
@brandingBoxWidth: @deviceWidthTabletEms - ( @iconSizeTotal * 3 ) - @searchBoxWidth;
@brandingBoxWidth: @deviceWidthTabletEms - (3 * @menuButtonIconSize + @iconGutterWidth) - @searchBoxWidth;
@titleSectionSpacingTop: 20px;
@titleSectionSpacingBottom: 25px;

View File

@ -0,0 +1,11 @@
@import '../../minerva.less/minerva.variables';
// The list that opens underneath the button.
.minerva-user-menu-list {
top: 100%;
right: 0;
margin-right: @contentMargin / 2;
min-width: 200px;
// A variable max-height is set in JavaScript so a minimum height is needed.
min-height: 200px;
}

View File

@ -0,0 +1,26 @@
@import '../../minerva.less/minerva.variables';
// The top level user account button in the upper right near the notifications button.
.minerva-user-navigation {
display: flex;
height: @headerHeight;
// Fill empty space left / start so the buttons can stay right / end.
width: 100%;
// Keep space for at least two buttons.
min-width: 2 * @menuButtonIconSize;
// Center vertically.
align-items: center;
// Layout from right / end.
justify-content: flex-end;
// Show the list relative the button.
position: relative;
.mw-ui-icon-element {
display: block;
}
.toggle-list {
width: @menuButtonIconSize;
display: inline-block;
}
}

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><path d="M3 3h8V1H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8v-2H3z"/><path d="M13 5v4H5v2h8v4l6-5z"/></svg>

After

Width:  |  Height:  |  Size: 242 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>log out</title><path d="M17 17H9v2h8c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2H9v2h8z"/><path d="M7 15v-4h8V9H7V5l-6 5z"/></svg>

After

Width:  |  Height:  |  Size: 246 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><path d="M6.5 3.5L0 10l1.5 1.5 5 5L8 15l-5-5 5-5-1.5-1.5zm7 0L12 5l5 5-5 5 1.5 1.5L20 10l-6.5-6.5z"/></svg>

After

Width:  |  Height:  |  Size: 190 B

View File

@ -15,6 +15,7 @@
TitleUtil = require( './TitleUtil.js' ),
issues = require( './page-issues/index.js' ),
Toolbar = require( './Toolbar.js' ),
ToggleList = require( '../../components/ToggleList/ToggleList.js' ),
router = require( 'mediawiki.router' ),
CtaDrawer = mobile.CtaDrawer,
Button = mobile.Button,
@ -341,7 +342,8 @@
$( function () {
var $toc,
toolbarElement = document.querySelector( Toolbar.selector );
toolbarElement = document.querySelector( Toolbar.selector ),
userMenu = document.querySelector( '.minerva-user-menu' ); // See UserMenuDirector.
// Init:
// - main menu closes when you click outside of it
// - redirects show a toast.
@ -363,6 +365,10 @@
Toolbar.bind( window, toolbarElement, eventBus );
Toolbar.render( window, toolbarElement );
}
if ( userMenu ) {
ToggleList.bind( window, userMenu, eventBus, true );
ToggleList.render( userMenu, true );
}
initRedlinksCta();
initUserRedLinks();
initTabsScrollPosition();

View File

@ -203,6 +203,7 @@
"resources/skins.minerva.base.styles/reset.less",
"resources/skins.minerva.base.styles/ui.less",
"resources/skins.minerva.base.styles/pageactions.less",
"resources/skins.minerva.base.styles/userMenu.less",
"resources/skins.minerva.base.styles/common.less",
"resources/skins.minerva.base.styles/images.less",
"resources/skins.minerva.base.styles/footer.less",
@ -259,7 +260,8 @@
"resources/skins.minerva.amc.styles/index.less",
"components/ToggleList/ToggleList.less",
"components/ToggleList/DropDownList.less",
"components/ToggleList/MenuListItem.less"
"components/ToggleList/MenuListItem.less",
"resources/skins.minerva.amc.styles/userMenu.less"
]
},
"wikimedia.ui": {
@ -268,7 +270,7 @@
"defaultColor": "#54595d",
"class": "ResourceLoaderOOUIIconPackModule",
"icons": [ "articleRedirect", "info", "link", "listBullet",
"logoWikidata", "logoWikimedia", "quotes", "upload", "userAvatar" ]
"logoWikidata", "logoWikimedia", "quotes", "upload", "userAvatar", "userTalk" ]
},
"skins.minerva.icons.images": {
"class": "ResourceLoaderImageModule",
@ -387,7 +389,12 @@
"images": {
"login": "resources/skins.minerva.mainMenu.icons/login.svg",
"home": "resources/skins.minerva.mainMenu.icons/home.svg",
"logout": "resources/skins.minerva.mainMenu.icons/logout.svg",
"logout": {
"file": {
"ltr": "resources/skins.minerva.mainMenu.icons/logOut-ltr.svg",
"rtl": "resources/skins.minerva.mainMenu.icons/logOut-rtl.svg"
}
},
"nearby": "resources/skins.minerva.mainMenu.icons/nearby.svg",
"random": "resources/skins.minerva.mainMenu.icons/random.svg",
"settings": "resources/skins.minerva.mainMenu.icons/settings.svg",
@ -409,7 +416,8 @@
"ltr": "resources/skins.minerva.mainMenu.icons/communityportal-ltr.svg",
"rtl": "resources/skins.minerva.mainMenu.icons/communityportal-rtl.svg"
}
}
},
"userSandbox": "resources/skins.minerva.mainMenu.icons/userSandbox.svg"
}
},
"skins.minerva.mainMenu.styles": {