Merge "Update: add secondary page actions submenu in AMC mode"

This commit is contained in:
jenkins-bot 2019-04-19 22:15:22 +00:00 committed by Gerrit Code Review
commit 55ad654176
27 changed files with 529 additions and 92 deletions

View File

@ -119,6 +119,19 @@ This will work for all pages except the main page.
```
Controls whether the history link appears in the page actions menu.
#### $wgMinervaOverflowInPageActions
* Type: `Array`
* Default:
```php
[
'beta' => false,
'base' => false,
'amc' => false,
]
```
Controls whether the overflow link appears in the page actions menu.
#### $wgMinervaShowShareButton
* Type: `Array`

View File

@ -6,7 +6,7 @@
"minerva-talk-add-topic": "Add discussion",
"mobile-frontend-cookies-required": "Cookies are required to switch view modes. Please enable them and try again.",
"mobile-frontend-editor-edit": "Edit",
"minerva-download": "Download",
"minerva-download": "Download PDF",
"skin-minerva-share": "Share",
"skin-minerva-mobile-option-MinervaShareButton": "Share",
"skin-minerva-mobile-option-MinervaShareButton-description": "Share current article via browser share feature (supported browsers only)",
@ -47,6 +47,14 @@
"mobile-frontend-user-page-member-since": "{{GENDER:$2|Joined}} $1",
"mobile-frontend-user-page-talk": "Talk",
"mobile-frontend-user-page-uploads": "Uploads",
"minerva-page-actions-overflow": "Secondary page actions submenu",
"minerva-page-actions-info": "Page information",
"minerva-page-actions-permalink": "Permanent link",
"minerva-page-actions-backlinks": "What links here",
"minerva-page-actions-cite": "Cite page",
"minerva-page-actions-uploads": "Uploads",
"minerva-page-actions-user-rights": "User rights",
"minerva-page-actions-logs": "Logs",
"skinname-minerva": "MinervaNeue",
"minerva-skin-desc": "A responsive mobile first skin",
"skin-minerva-issue-learn-more": "Learn more",

View File

@ -56,6 +56,14 @@
"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-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",
"minerva-page-actions-backlinks": "In the secondary page menu, the 'what links here' incoming links button label",
"minerva-page-actions-cite": "In the secondary page menu, the cite this page button label",
"minerva-page-actions-uploads": "In the secondary page menu for user pages, the user uploads button label",
"minerva-page-actions-user-rights": "In the secondary page menu for user pages, the user rights button label",
"minerva-page-actions-logs": "In the secondary page menu for user pages, the user logs button label",
"skinname-minerva": "{{name}}",
"minerva-skin-desc": "{{desc|name=Minerva Neue|url=https://www.mediawiki.org/wiki/Skin:Minerva_Neue|what=skin}}",
"skin-minerva-issue-learn-more": "Label for link that allows expanding of ambox issue templates.",

View File

@ -28,6 +28,8 @@ use MediaWiki\Minerva\SkinOptions;
* on<HookName>()
*/
class MinervaHooks {
const FEATURE_OVERFLOW_PAGE_ACTIONS = 'MinervaOverflowInPageActions';
/**
* Register mobile web beta features
* @see https://www.mediawiki.org/wiki/
@ -82,6 +84,13 @@ class MinervaHooks {
$config->get( 'MinervaHistoryInPageActions' )
)
);
$featureManager->registerFeature(
new MobileFrontend\Features\Feature(
self::FEATURE_OVERFLOW_PAGE_ACTIONS,
'skin-minerva',
$config->get( self::FEATURE_OVERFLOW_PAGE_ACTIONS )
)
);
} catch ( RuntimeException $e ) {
// features already registered...
// due to a bug it's possible for this to run twice
@ -222,6 +231,9 @@ class MinervaHooks {
SkinOptions::OPTIONS_HISTORY_PAGE_ACTIONS => $featureManager->isFeatureAvailableForCurrentUser(
'MinervaHistoryInPageActions'
),
SkinOptions::OPTION_OVERFLOW_SUBMENU => $featureManager->isFeatureAvailableForCurrentUser(
self::FEATURE_OVERFLOW_PAGE_ACTIONS
),
] );
}
}

View File

@ -34,6 +34,7 @@ final class SkinOptions {
const OPTIONS_MOBILE_BETA = 'beta';
const OPTIONS_TALK_AT_TOP = 'talkAtTop';
const OPTIONS_HISTORY_PAGE_ACTIONS = 'historyInPageActions';
const OPTION_OVERFLOW_SUBMENU = 'overflowSubmenu';
/** @var array skin specific options */
private $skinOptions = [
@ -56,6 +57,7 @@ final class SkinOptions {
self::OPTION_PAGE_ISSUES => false,
self::OPTIONS_TALK_AT_TOP => false,
self::OPTIONS_HISTORY_PAGE_ACTIONS => false,
self::OPTION_OVERFLOW_SUBMENU => false,
];
/**

View File

@ -98,11 +98,11 @@ class MinervaTemplate extends BaseTemplate {
*/
protected function getPageActionsHtml() {
$templateParser = new TemplateParser( __DIR__ );
$actions = $this->getPageActions();
$pageActions = $this->getPageActions();
$html = '';
if ( $actions ) {
$html = $templateParser->processTemplate( 'pageActionMenu', [ 'pageActions' => $actions ] );
if ( $pageActions && $pageActions['toolbar'] ) {
$html = $templateParser->processTemplate( 'pageActionMenu', $pageActions );
}
return $html;
}

View File

@ -29,7 +29,6 @@ use MediaWiki\Minerva\SkinUserPageHelper;
* @ingroup Skins
*/
class SkinMinerva extends SkinTemplate {
/** @const LEAD_SECTION_NUMBER integer which corresponds to the lead section
in editing mode */
const LEAD_SECTION_NUMBER = 0;
@ -231,6 +230,10 @@ class SkinMinerva extends SkinTemplate {
return $this->skinOptions->get( SkinOptions::OPTIONS_HISTORY_PAGE_ACTIONS );
}
if ( $action === SkinOptions::OPTION_OVERFLOW_SUBMENU ) {
return $this->skinOptions->get( SkinOptions::OPTION_OVERFLOW_SUBMENU );
}
if (
!in_array( $action, $config->get( 'MinervaPageActions' ) )
|| ( $this->getUserPageHelper()->isUserPage() && !$title->exists() )
@ -834,10 +837,11 @@ class SkinMinerva extends SkinTemplate {
* @param BaseTemplate $tpl
*/
protected function preparePageActions( BaseTemplate $tpl ) {
$menu = [];
$toolbar = [];
$overflowMenu = null;
if ( $this->isAllowedPageAction( 'switch-language' ) ) {
$menu[] = $this->createSwitchLanguageAction();
$toolbar[] = $this->createSwitchLanguageAction();
}
if ( $this->isAllowedPageAction( 'watch' ) ) {
@ -845,18 +849,25 @@ class SkinMinerva extends SkinTemplate {
// Pass these actions in as context for #createWatchPageAction.
$actions = $tpl->data['content_navigation']['actions'];
$menu[] = $this->createWatchPageAction( $actions );
$toolbar[] = $this->createWatchPageAction( $actions );
}
if ( $this->isAllowedPageAction( 'history' ) ) {
$menu[] = $this->getHistoryPageAction();
$toolbar[] = $this->getHistoryPageAction();
}
if ( $this->isAllowedPageAction( 'edit' ) ) {
$menu[] = $this->createEditPageAction();
$toolbar[] = $this->createEditPageAction();
}
$tpl->set( 'page_actions', $menu );
if ( $this->isAllowedPageAction( SkinOptions::OPTION_OVERFLOW_SUBMENU ) ) {
$overflowMenu = $this->newToolbarOverflowMenu( $tpl );
}
$tpl->set( 'page_actions', [
'toolbar' => $toolbar,
'overflowMenu' => $overflowMenu
] );
}
/**
@ -977,6 +988,85 @@ class SkinMinerva extends SkinTemplate {
];
}
/**
* Creates an overflow action: An icon that links to the overflow menu.
*
* @param BaseTemplate $tpl
* @return array|null A map of HTML attributes and a 'text' property to be used with the
* pageActionMenu.mustache template.
*/
private function newToolbarOverflowMenu( BaseTemplate $tpl ) {
$pageActions = $this->getUserPageHelper()->isUserPage()
? $this->getUserNamespaceOverflowPageActions( $tpl )
: $this->getDefaultOverflowPageActions( $tpl );
return empty( $pageActions ) ? null : [
'item-id' => 'page-actions-overflow',
'class' => MinervaUI::iconClass( 'page-actions-overflow' ),
'text' => $this->msg( 'minerva-page-actions-overflow' ),
'pageActions' => $pageActions
];
}
/**
* @param BaseTemplate $tpl
* @return array
*/
private function getDefaultOverflowPageActions( BaseTemplate $tpl ) {
return array_values( array_filter( [
$this->newOverflowPageAction( 'info', 'info', $tpl->data['nav_urls']['info']['href'] ?? null ),
$this->newOverflowPageAction(
'permalink', 'link', $tpl->data['nav_urls']['permalink']['href'] ?? null
),
$this->newOverflowPageAction(
'backlinks', 'articleRedirect', $tpl->data['nav_urls']['whatlinkshere']['href'] ?? null
),
$this->newOverflowPageAction(
'cite', 'quotes', $tpl->data['nav_urls']['citethispage']['href'] ?? null
)
] ) );
}
/**
* @param BaseTemplate $tpl
* @return array
*/
private function getUserNamespaceOverflowPageActions( BaseTemplate $tpl ) {
$pageUser = $this->getUserPageHelper()->getPageUser();
return [
$this->newOverflowPageAction(
'uploads', 'upload', SpecialPage::getTitleFor( 'Uploads', $pageUser )->getLocalURL()
),
$this->newOverflowPageAction(
'user-rights', 'userAvatar', $tpl->data['nav_urls']['userrights']['href'] ?? null
),
$this->newOverflowPageAction(
'logs', 'listBullet', $tpl->data['nav_urls']['log']['href'] ?? null
),
$this->newOverflowPageAction( 'info', 'info', $tpl->data['nav_urls']['info']['href'] ?? null ),
$this->newOverflowPageAction(
'permalink', 'link', $tpl->data['nav_urls']['permalink']['href'] ?? null
),
$this->newOverflowPageAction(
'backlinks', 'articleRedirect', $tpl->data['nav_urls']['whatlinkshere']['href'] ?? null
)
];
}
/**
* @param string $name
* @param string $icon Wikimedia UI icon name.
* @param string|null $href
* @return array
*/
private function newOverflowPageAction( $name, $icon, $href ) {
return $href ? [
'item-id' => 'page-actions-overflow-' . $name,
'class' => MinervaUI::iconClass( '', 'before', 'wikimedia-ui-' . $icon . '-base20' ),
'text' => $this->msg( 'minerva-page-actions-' . $name ),
'href' => $href
] : null;
}
/**
* Checks whether the editor can handle the existing content handler type.
*

View File

@ -1,11 +1,28 @@
<nav class="page-actions-menu">
<ul id="page-actions" class="page-actions-menu__list">
{{#pageActions}}
{{#toolbar}}
<li id="{{item-id}}" class="page-actions-menu__list-item">
<a id="{{id}}" href="{{href}}" class="{{class}}" role="button" title="{{title}}">
{{text}}
</a>
</li>
{{/pageActions}}
{{/toolbar}}
{{#overflowMenu}}
<li id="{{item-id}}" class="page-actions-menu__list-item">
<input type="checkbox" id="toolbar-overflow-menu__checkbox" role="button" aria-label="{{text}}" aria-expanded="false" >
<label class="toolbar-overflow-menu__button {{class}}" title="{{title}}" for="toolbar-overflow-menu__checkbox">
{{text}}
</label>
<ul class="toolbar-overflow-menu__list">
{{#pageActions}}
<li>
<a id="{{id}}" href="{{href}}" class="toolbar-overflow-menu__list-item {{class}}" title="{{title}}">
{{text}}
</a>
</li>
{{/pageActions}}
</ul>
</li>
{{/overflowMenu}}
</ul>
</nav>

View File

@ -1,7 +1,7 @@
@import 'mediawiki.ui/variables';
@z-indexBase: 0;
@z-indexOverOverlay: 2;
@z-indexOverOverlay: 3;
/**
* System font stack for sans-serif fonts
@ -38,7 +38,6 @@
// Headings
@firstHeadingFontSize: 2.6525em; // 42px
@pageActionFontSize: 1.1em; // Icons are 24px square.
@fontSizeH1: 1.7em;
@fontSizeH2: 1.5em;
@fontSizeH3: 1.2em;
@ -49,7 +48,7 @@
// Header
@headerHeight: 3.35em;
@headerMarginTop: -1px; // used to hide the header border top when a banner is not present
@headerMarginTop: -1px; // used to hide the header border top when a banner is not present
@searchBoxWidth: 375/16em;
@iconSizeTotal: @iconSize + @iconGutterWidth + @iconGutterWidth;
@deviceWidthTabletEms: unit( @width-breakpoint-tablet/16, em );
@ -61,6 +60,8 @@
// Page actions
@taglineFontSize: 0.85em;
@pageActionBorder: 1px;
@pageActionFontSize: 0.9em;
@pageActionToolbarHeight: 44px; // total height is 46px. 2px added by border on .page-actions-menu
// colors
@chromeColor: @grayLightest;
@ -125,7 +126,9 @@
@notificationColorUnread: #fff;
// z-index:
@z-indexOverlay: 1;
@z-indexOccluded: -1;
@z-indexDrawer: 1;
@z-indexOverlay: 2;
// Print specific
@colorPrintSubtle: #999;

View File

@ -21,8 +21,12 @@
opacity: 0.25;
}
#page-actions {
position: relative;
}
.page-actions-menu {
box-sizing: border-box;
.box-sizing( border-box );
border-top: 1px solid @colorGray14;
border-bottom: 1px solid @colorGray12;
}
@ -30,11 +34,10 @@
.page-actions-menu__list {
display: flex;
justify-content: space-between;
height: 44px; // total height is 46px. 2px added by border on .page-actions-menu
height: @pageActionToolbarHeight;
}
.page-actions-menu__list-item {
position: relative;
display: flex;
flex-basis: 4em;
justify-content: flex-end;
@ -68,6 +71,10 @@
}
}
.minerva--amc-enabled .page-actions-menu__list-item {
flex-basis: auto;
}
// Layout for less than 5 items - one item at the beginning, rest at the end.
// |1-----2--3--4|
.page-actions-menu__list-item:first-child {
@ -75,6 +82,99 @@
justify-content: flex-start;
}
// When AMC is enabled, space all items equally.
.minerva--amc-enabled .page-actions-menu__list-item:first-child {
flex-grow: 0;
}
#toolbar-overflow-menu__checkbox {
// Always occlude the checkbox. The checkbox display cannot be none since its focus state is used
// for other selectors.
position: absolute;
z-index: @z-indexOccluded;
opacity: 0;
}
.toolbar-overflow-menu__button {
// Use the hand icon for the overflow button which is actually a checkbox label.
cursor: pointer;
}
#toolbar-overflow-menu__checkbox:focus + .toolbar-overflow-menu__button {
// The overflow button / label itself cannot receive focus but the underlying checkbox can. Keep
// the button and checkbox focus presentation in sync. From
// resources/src/mediawiki.toc.styles/screen.less.
outline: dotted 1px; /* Firefox style for focus */
outline: auto @colorProgressiveHighlight; /* Webkit style for focus */
}
.touch-events #toolbar-overflow-menu__checkbox:focus + .toolbar-overflow-menu__button {
// Buttons have no focus outline on mobile.
outline: 0;
}
.toolbar-overflow-menu__list {
// The top of the menu is flush with the bottom of the page actions toolbar.
position: absolute;
top: 100%;
right: 0;
//
// A variable max-height is set in JavaScript so a minimum height is needed.
min-height: 200px;
//
// If the height exceeds the maximum allowed, add a vertical scrollbar.
overflow-y: auto;
//
// The menu floats over content but below overlays.
z-index: @z-indexDrawer;
//
font-size: @pageActionFontSize;
font-weight: bold;
background: @skinContentBgColor;
box-shadow: 0 5px 17px 0 rgba( 0, 0, 0, 0.24 ), 0 0 1px @colorGray10;
border-radius: @borderRadius;
//
// Animate menu visibility, opacity, and translation changes in and out. Visibility must be
// animated since it's a boolean and nothing can be seen in the hidden state.
visibility: hidden;
opacity: 0;
transform: translateY( -8px );
.transition( visibility .1s ease-in-out, opacity .1s ease-in-out, transform .1s ease-in-out; );
}
.toolbar-overflow-menu__list-item {
// Fill the list item cell.
.box-sizing( border-box );
display: inline-block;
width: 100%;
//
padding: 1em;
white-space: nowrap;
// Left-align text. Button elements are centered.
text-align: left;
//
color: @grayMediumDark;
&:visited, &:active {
// Visited and active links need extra specificity.
color: @grayMediumDark;
}
//
// Make the app feel like an app, not a JPEG. When hovering over a menu item, add a little
// interactivity.
&:hover {
text-decoration: none;
background: @grayLightest;
}
}
#toolbar-overflow-menu__checkbox:checked ~ .toolbar-overflow-menu__list {
// Reveal the overflow menu when checked.
visibility: visible;
opacity: 1;
transform: translateY( 0 );
}
// overriding common.less `display:inherit` (which causes `display: flex;` in this instance).
.client-js .jsonly#ca-watch {
display: list-item;

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" id="svg10"><title id="title2">ellipsis</title><circle cx="-10" cy="10" r="2" id="circle4" transform="rotate(-90)"/><circle cx="-17" cy="10" r="2" id="circle6" transform="rotate(-90)"/><circle cx="-3" cy="10" r="2" id="circle8" transform="rotate(-90)"/></svg>

After

Width:  |  Height:  |  Size: 395 B

View File

@ -0,0 +1,175 @@
( function ( M ) {
var
mobile = M.require( 'mobile.startup' ),
downloadPageAction = M.require( 'skins.minerva.scripts/downloadPageAction' ),
Icon = mobile.Icon,
skin = M.require( 'mobile.init/skin' ),
/** The top level menu. */
toolbarSelector = '.page-actions-menu',
/** The secondary overflow submenu component container. */
overflowSubmenuSelector = '#page-actions-overflow',
/** The visible label icon associated with the checkbox. */
overflowButtonSelector = '.toolbar-overflow-menu__button',
/** The underlying hidden checkbox that controls secondary overflow submenu visibility. */
overflowCheckboxSelector = '#toolbar-overflow-menu__checkbox',
overflowListSelector = '.toolbar-overflow-menu__list';
/**
* @param {Window} window
* @param {Element} toolbar
* @param {OO.EventEmitter} eventBus
* @return {void}
*/
function bind( window, toolbar, eventBus ) {
var
overflowSubmenu = toolbar.querySelector( overflowSubmenuSelector ),
overflowButton = toolbar.querySelector( overflowButtonSelector ),
overflowCheckbox = toolbar.querySelector( overflowCheckboxSelector ),
overflowList = toolbar.querySelector( overflowListSelector );
if ( overflowSubmenu ) {
bindOverflowSubmenu(
window, overflowSubmenu, overflowButton, overflowCheckbox, overflowList, eventBus
);
}
}
/**
* @param {Window} window
* @param {Element} toolbar
* @return {void}
*/
function render( window, toolbar ) {
var overflowList = toolbar.querySelector( overflowListSelector );
renderEditButton();
renderDownloadButton( window, overflowList );
if ( overflowList ) {
resizeOverflowList( overflowList );
}
}
/**
* Automatically dismiss the submenu when clicking or focusing elsewhere, resize the menu on
* scroll and window resize, and update the aria-expanded attribute based on submenu visibility.
* @param {Window} window
* @param {Element} submenu
* @param {Element} button
* @param {HTMLInputElement} checkbox
* @param {Element} list
* @param {OO.EventEmitter} eventBus
* @return {void}
*/
function bindOverflowSubmenu( window, submenu, button, checkbox, list, eventBus ) {
var
resize = resizeOverflowList.bind( undefined, list ),
updateAriaExpanded = function () {
checkbox.setAttribute( 'aria-expanded', ( !!checkbox.checked ).toString() );
};
window.addEventListener( 'click', function ( event ) {
if ( event.target !== button && event.target !== checkbox ) {
// Something besides the button or checkbox was tapped. Dismiss the submenu.
checkbox.checked = false;
updateAriaExpanded();
}
} );
// If focus is given to any element outside the menu, dismiss the submenu. Setting a
// focusout listener on submenu would be preferable, but this interferes with the click
// listener.
window.addEventListener( 'focusin', function ( event ) {
if ( event.target instanceof Node && !submenu.contains( event.target ) ) {
// Something besides the button or checkbox was focused. Dismiss the menu.
checkbox.checked = false;
updateAriaExpanded();
}
} );
eventBus.on( 'scroll:throttled', resize );
eventBus.on( 'resize:throttled', resize );
checkbox.addEventListener( 'change', updateAriaExpanded );
}
/**
* @param {HTMLElement} list
* @return {void}
*/
function resizeOverflowList( list ) {
var rect = list.getClientRects()[ 0 ];
if ( rect ) {
list.style.maxHeight = window.document.documentElement.clientHeight - rect.top + 'px';
}
}
/**
* Initialize page edit action link (#ca-edit)
*
* Mark the edit link as disabled if the user is not actually able to edit the page for some
* reason (e.g. page is protected or user is blocked).
*
* Note that the link is still clickable, but clicking it will probably open a view-source
* form or display an error message, rather than open an edit form.
*
* FIXME: Review this code as part of T206262
*
* @ignore
*/
function renderEditButton() {
var
// FIXME: create a utility method to generate class names instead of
// constructing temporary objects. This affects disabledEditIcon,
// enabledEditIcon, enabledEditIcon, and disabledClass and
// a number of other places in the code base.
disabledEditIcon = new Icon( {
name: 'edit',
glyphPrefix: 'minerva'
} ),
enabledEditIcon = new Icon( {
name: 'edit-enabled',
glyphPrefix: 'minerva'
} ),
enabledClass = enabledEditIcon.getGlyphClassName(),
disabledClass = disabledEditIcon.getGlyphClassName();
if ( mw.config.get( 'wgMinervaReadOnly' ) ) {
// eslint-disable-next-line no-jquery/no-global-selector
$( '#ca-edit' )
.removeClass( enabledClass )
.addClass( disabledClass );
}
}
/**
* Initialize and inject the download button
*
* There are many restrictions when we can show the download button, this function should handle
* all device/os/operating system related checks and if device supports printing it will inject
* the Download icon
* @param {Window} window
* @param {Element|null} overflowList
* @return {void}
*/
function renderDownloadButton( window, overflowList ) {
var $downloadAction = downloadPageAction( skin,
mw.config.get( 'wgMinervaDownloadNamespaces', [] ), window, !!overflowList );
if ( $downloadAction ) {
if ( overflowList ) {
$downloadAction.appendTo( overflowList );
} else {
$downloadAction.insertAfter( '.page-actions-menu__list-item:first-child' );
}
mw.track( 'minerva.downloadAsPDF', {
action: 'buttonVisible'
} );
}
}
M.define( 'skins.minerva.scripts/Toolbar', {
selector: toolbarSelector,
bind: bind,
render: render
} );
}( mw.mobileFrontend ) );

View File

@ -120,10 +120,17 @@
* @param {Skin} skin
* @param {number[]} supportedNamespaces
* @param {Window} [windowObj] window object
* @param {boolean} [hasText] Use icon + button style.
* @returns {jQuery.Object|null}
*/
function downloadPageAction( skin, supportedNamespaces, windowObj ) {
var icon, spinner = icons.spinner();
function downloadPageAction( skin, supportedNamespaces, windowObj, hasText ) {
var
modifier = hasText ? 'toolbar-overflow-menu__list-item' : 'mw-ui-icon-element',
icon,
spinner = icons.spinner( {
hasText: hasText,
modifier: modifier
} );
if (
isAvailable(
@ -139,11 +146,13 @@
events: {
// will be bound to `this`
click: getOnClickHandler( spinner )
}
},
hasText: hasText,
label: hasText ? mw.msg( 'minerva-download' ) : '',
modifier: modifier
} );
return $( '<li>' ).addClass( 'page-actions-menu__list-item' ).append( icon.$el ).append( spinner.$el.hide() );
} else {
return null;
}

View File

@ -1,17 +1,15 @@
( function ( M, track, config ) {
( function ( M ) {
var
mobile = M.require( 'mobile.startup' ),
PageGateway = mobile.PageGateway,
toast = mobile.toast,
time = mobile.time,
skin = M.require( 'mobile.init/skin' ),
TitleUtil = M.require( 'skins.minerva.scripts/TitleUtil' ),
issues = M.require( 'skins.minerva.scripts/pageIssues' ),
downloadPageAction = M.require( 'skins.minerva.scripts/downloadPageAction' ),
Toolbar = M.require( 'skins.minerva.scripts/Toolbar' ),
router = require( 'mediawiki.router' ),
OverlayManager = mobile.OverlayManager,
CtaDrawer = mobile.CtaDrawer,
Icon = mobile.Icon,
Button = mobile.Button,
Anchor = mobile.Anchor,
overlayManager = OverlayManager.getSingleton(),
@ -197,28 +195,6 @@
} );
}
/**
* Initialize and inject the download button
*
* There are many restrictions when we can show the download button, this function should handle
* all device/os/operating system related checks and if device supports printing it will inject
* the Download icon
* @ignore
*/
function appendDownloadButton() {
var $downloadAction = downloadPageAction( skin,
config.get( 'wgMinervaDownloadNamespaces', [] ), window );
if ( $downloadAction ) {
$downloadAction.insertAfter( '.page-actions-menu__list-item:first-child' );
track( 'minerva.downloadAsPDF', {
action: 'buttonVisible'
} );
}
}
/**
* Tests a URL to determine if it links to a local User namespace page or not.
*
@ -317,54 +293,19 @@
} );
}
/**
* Initialize page edit action link (#ca-edit)
*
* Mark the edit link as disabled if the user is not actually able to edit the page for some
* reason (e.g. page is protected or user is blocked).
*
* Note that the link is still clickable, but clicking it will probably open a view-source
* form or display an error message, rather than open an edit form.
*
* FIXME: Review this code as part of T206262
*
* @ignore
*/
function initEditLink() {
var
// FIXME: create a utility method to generate class names instead of
// constructing temporary objects. This affects disabledEditIcon,
// enabledEditIcon, enabledEditIcon, and disabledClass and
// a number of other places in the code base.
disabledEditIcon = new Icon( {
name: 'edit',
glyphPrefix: 'minerva'
} ),
enabledEditIcon = new Icon( {
name: 'edit-enabled',
glyphPrefix: 'minerva'
} ),
enabledClass = enabledEditIcon.getGlyphClassName(),
disabledClass = disabledEditIcon.getGlyphClassName();
if ( mw.config.get( 'wgMinervaReadOnly' ) ) {
// eslint-disable-next-line no-jquery/no-global-selector
$( '#ca-edit' )
.removeClass( enabledClass )
.addClass( disabledClass );
}
}
$( function () {
var toolbarElement = document.querySelector( Toolbar.selector );
// Update anything else that needs enhancing (e.g. watchlist)
initModifiedInfo();
initRegistrationInfo();
// eslint-disable-next-line no-jquery/no-global-selector
initHistoryLink( $( '.last-modifier-tagline a' ) );
appendDownloadButton();
if ( toolbarElement ) {
Toolbar.bind( window, toolbarElement, eventBus );
Toolbar.render( window, toolbarElement );
}
initRedlinksCta();
initUserRedLinks();
initEditLink();
// Setup the issues banner on the page
// Pages which dont exist (id 0) cannot have issues
if ( !page.isMissing ) {
@ -373,4 +314,4 @@
} );
M.define( 'skins.minerva.scripts/overlayManager', overlayManager );
}( mw.mobileFrontend, mw.track, mw.config ) );
}( mw.mobileFrontend ) );

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>article redirect</title><path d="M5 1a2 2 0 0 0-2 2v1c0 5 2 8 7 8V9l5 4-5 4v-3c-3.18 0-5.51-.85-7-2.68V17a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 290 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>article redirect</title><path d="M3 17c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-5.7c-1.5 1.8-3.8 2.7-7 2.7v3l-5-4 5-4v3c5 0 7-3 7-8V3c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2z"/></svg>

After

Width:  |  Height:  |  Size: 296 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>info</title><path d="M9.5 16A6.61 6.61 0 0 1 3 9.5 6.61 6.61 0 0 1 9.5 3 6.61 6.61 0 0 1 16 9.5 6.63 6.63 0 0 1 9.5 16zm0-14A7.5 7.5 0 1 0 17 9.5 7.5 7.5 0 0 0 9.5 2zm.5 6v4.08h1V13H8.07v-.92H9V9H8V8zM9 6h1v1H9z"/></svg>

After

Width:  |  Height:  |  Size: 348 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>link</title><path d="M4.83 15h2.91a4.88 4.88 0 0 1-1.55-2H5a3 3 0 1 1 0-6h3a3 3 0 0 1 2.82 4h2.1a4.82 4.82 0 0 0 .08-.83v-.34A4.83 4.83 0 0 0 8.17 5H4.83A4.83 4.83 0 0 0 0 9.83v.34A4.83 4.83 0 0 0 4.83 15z"/><path d="M15.17 5h-2.91a4.88 4.88 0 0 1 1.55 2H15a3 3 0 1 1 0 6h-3a3 3 0 0 1-2.82-4h-2.1a4.82 4.82 0 0 0-.08.83v.34A4.83 4.83 0 0 0 11.83 15h3.34A4.83 4.83 0 0 0 20 10.17v-.34A4.83 4.83 0 0 0 15.17 5z"/></svg>

After

Width:  |  Height:  |  Size: 545 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>bullet list</title><path d="M7 15h12v2H7zm0-6h12v2H7zm0-6h12v2H7z"/><circle cx="3" cy="4" r="2"/><circle cx="3" cy="10" r="2"/><circle cx="3" cy="16" r="2"/></svg>

After

Width:  |  Height:  |  Size: 291 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>bullet list</title><path d="M1 15h12v2H1zm0-6h12v2H1zm0-6h12v2H1z"/><circle cx="17" cy="4" r="2"/><circle cx="17" cy="10" r="2"/><circle cx="17" cy="16" r="2"/></svg>

After

Width:  |  Height:  |  Size: 294 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" stroke-width="30.2" viewBox="0 0 20 20"><title>Wikidata logo</title><path stroke="#000" stroke-width=".743" d="M.371 4v12.257m1.482 0V4m.74 0v12.257m.741 0V4m1.481 0v12.257m.741 0V4m.74 0v12.257M7.778 4v12.257m1.481 0V4m8.888 0v12.257m1.482 0V4M10.74 4v12.257m.741 0V4m.741 0v12.257m1.481 0V4m1.482 0v12.257m.74 0V4m.74 0v12.257"/></svg>

After

Width:  |  Height:  |  Size: 438 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>Wikimedia logo</title><clipPath id="a"><path d="M0-33l471 471v363h82V438l471-471v1057H0"/></clipPath><g clip-path="url(#a)" transform="matrix(.021 0 0 .021 -.756 -.588)"><path d="M511 224a288 288 0 1 0 2 0"/><path fill="none" stroke="#000" stroke-width="116" d="M511 102a410 410 0 1 0 2 0"/></g><circle cx="10" cy="3.32" r="3.32"/></svg>

After

Width:  |  Height:  |  Size: 465 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>quotes</title><path d="M7 6l1-2H6C3.79 4 2 6.79 2 9v7h7V9H5c0-3 2-3 2-3zm7 3c0-3 2-3 2-3l1-2h-2c-2.21 0-4 2.79-4 5v7h7V9z"/></svg>

After

Width:  |  Height:  |  Size: 258 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>quotes</title><path d="M11 9v7h7V9c0-2.2-1.8-5-4-5h-2l1 2s2 0 2 3zM2 9v7h7V9c0-2.2-1.8-5-4-5H3l1 2s2 0 2 3z"/></svg>

After

Width:  |  Height:  |  Size: 244 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>upload</title><path d="M17 12v5H3v-5H1v5a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5z"/><path d="M10 1L5 7h4v8h2V7h4z"/></svg>

After

Width:  |  Height:  |  Size: 244 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>user avatar</title><path d="M10 11c-5.92 0-8 3-8 5v3h16v-3c0-2-2.08-5-8-5z"/><circle cx="10" cy="5.5" r="4.5"/></svg>

After

Width:  |  Height:  |  Size: 245 B

View File

@ -45,6 +45,11 @@
"beta": false,
"amc": true
},
"MinervaOverflowInPageActions": {
"base": false,
"beta": false,
"amc": false
},
"MinervaShowCategoriesButton": {
"base": false,
"beta": true
@ -231,6 +236,44 @@
"resources/skins.minerva.amc.styles/index.less"
]
},
"wikimedia.ui": {
"class": "ResourceLoaderImageModule",
"selectorWithoutVariant": ".wikimedia-ui-{name}:before",
"selectorWithVariant": ".wikimedia-ui-{name}-{variant}:before",
"useDataURI": false,
"variants": {
"base20": {
"color": "#54595d",
"global": true
}
},
"images": {
"articleRedirect": {
"file": {
"ltr": "resources/wikimedia.ui/articleRedirect-ltr.svg",
"rtl": "resources/wikimedia.ui/articleRedirect-rtl.svg"
}
},
"info": "resources/wikimedia.ui/info.svg",
"link": "resources/wikimedia.ui/link.svg",
"listBullet": {
"file": {
"ltr": "resources/wikimedia.ui/listBullet-ltr.svg",
"rtl": "resources/wikimedia.ui/listBullet-rtl.svg"
}
},
"logo-Wikidata": "resources/wikimedia.ui/logo-Wikidata.svg",
"logo-Wikimedia": "resources/wikimedia.ui/logo-Wikimedia.svg",
"quotes": {
"file": {
"ltr": "resources/wikimedia.ui/quotes-ltr.svg",
"rtl": "resources/wikimedia.ui/quotes-rtl.svg"
}
},
"upload": "resources/wikimedia.ui/upload.svg",
"userAvatar": "resources/wikimedia.ui/userAvatar.svg"
}
},
"skins.minerva.icons.images": {
"class": "ResourceLoaderImageModule",
"selectorWithoutVariant": ".mw-ui-icon-minerva-{name}:before",
@ -255,7 +298,8 @@
"clock": {
"file": "resources/skins.minerva.icons.images/clock.svg",
"variants": [ "invert" ]
}
},
"page-actions-overflow": "resources/skins.minerva.icons.images/page-actions-overflow.svg"
}
},
"skins.minerva.icons.images.scripts": {
@ -373,6 +417,7 @@
"desktop"
],
"dependencies": [
"wikimedia.ui",
"skins.minerva.mainMenu.icons",
"skins.minerva.mainMenu.styles",
"jquery.cookie",
@ -431,6 +476,7 @@
"resources/skins.minerva.scripts/pageIssues.js",
"resources/skins.minerva.scripts/UriUtil.js",
"resources/skins.minerva.scripts/TitleUtil.js",
"resources/skins.minerva.scripts/Toolbar.js",
"resources/skins.minerva.scripts/init.js",
"resources/skins.minerva.scripts/initLogging.js",
"resources/skins.minerva.scripts/mobileRedirect.js",