Merge "Refactor pageActions menu to accommodate AMC mode"
This commit is contained in:
commit
9067705cf8
|
@ -92,25 +92,15 @@ class MinervaTemplate extends BaseTemplate {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the HTML for rendering the available page actions
|
* Get the HTML for rendering the available page actions
|
||||||
* @param array $data Data used to build page actions
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function getPageActionsHtml( $data ) {
|
protected function getPageActionsHtml() {
|
||||||
|
$templateParser = new TemplateParser( __DIR__ );
|
||||||
$actions = $this->getPageActions();
|
$actions = $this->getPageActions();
|
||||||
$html = '';
|
$html = '';
|
||||||
$isJSOnly = true;
|
|
||||||
if ( $actions ) {
|
if ( $actions ) {
|
||||||
foreach ( $actions as $key => $val ) {
|
$html = $templateParser->processTemplate( 'pageActionMenu', [ 'pageactions' => $actions ] );
|
||||||
if ( isset( $val['is_js_only'] ) ) {
|
|
||||||
if ( !$val['is_js_only'] ) {
|
|
||||||
$isJSOnly = false;
|
|
||||||
}
|
|
||||||
unset( $val['is_js_only'] ); // no need to output this attribute
|
|
||||||
}
|
|
||||||
$html .= $this->makeListItem( $key, $val );
|
|
||||||
}
|
|
||||||
$additionalClasses = $isJSOnly ? 'jsonly' : '';
|
|
||||||
$html = '<ul id="page-actions" class="hlist ' . $additionalClasses . '">' . $html . '</ul>';
|
|
||||||
}
|
}
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1137,18 +1137,17 @@ class SkinMinerva extends SkinTemplate {
|
||||||
/**
|
/**
|
||||||
* Prepare configured and available page actions
|
* Prepare configured and available page actions
|
||||||
*
|
*
|
||||||
* When adding new page actions make sure each menu item has
|
* If a page action should display a placeholder element
|
||||||
* <code>is_js_only</code> key set to <code>true</code> or <code>false</code>.
|
* (i.e. it will be hydrated on the client with JS) add the 'jsonly' CSS class to
|
||||||
* The key will be used to decide whether to display the page actions
|
* the 'class' key of its array.
|
||||||
* wrapper on the front end. The key will be considered false if not set.
|
|
||||||
*
|
*
|
||||||
* @param BaseTemplate $tpl
|
* @param BaseTemplate $tpl
|
||||||
*/
|
*/
|
||||||
protected function preparePageActions( BaseTemplate $tpl ) {
|
protected function preparePageActions( BaseTemplate $tpl ) {
|
||||||
$menu = [];
|
$menu = [];
|
||||||
|
|
||||||
if ( $this->isAllowedPageAction( 'edit' ) ) {
|
if ( $this->isAllowedPageAction( 'switch-language' ) ) {
|
||||||
$menu['edit'] = $this->createEditPageAction();
|
$menu[] = $this->createSwitchLanguageAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->isAllowedPageAction( 'watch' ) ) {
|
if ( $this->isAllowedPageAction( 'watch' ) ) {
|
||||||
|
@ -1156,11 +1155,11 @@ class SkinMinerva extends SkinTemplate {
|
||||||
// Pass these actions in as context for #createWatchPageAction.
|
// Pass these actions in as context for #createWatchPageAction.
|
||||||
$actions = $tpl->data['content_navigation']['actions'];
|
$actions = $tpl->data['content_navigation']['actions'];
|
||||||
|
|
||||||
$menu['watch'] = $this->createWatchPageAction( $actions );
|
$menu[] = $this->createWatchPageAction( $actions );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->isAllowedPageAction( 'switch-language' ) ) {
|
if ( $this->isAllowedPageAction( 'edit' ) ) {
|
||||||
$menu['switch-language'] = $this->createSwitchLanguageAction();
|
$menu[] = $this->createEditPageAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
$tpl->set( 'page_actions', $menu );
|
$tpl->set( 'page_actions', $menu );
|
||||||
|
@ -1170,7 +1169,8 @@ class SkinMinerva extends SkinTemplate {
|
||||||
* Creates the "edit" page action: the well-known pencil icon that, when tapped, will open an
|
* Creates the "edit" page action: the well-known pencil icon that, when tapped, will open an
|
||||||
* editor with the lead section loaded.
|
* editor with the lead section loaded.
|
||||||
*
|
*
|
||||||
* @return array A map compatible with BaseTemplate#makeListItem
|
* @return array A map of HTML attributes and a "text" property to be used with the
|
||||||
|
* pageActionMenu.mustache template.
|
||||||
*/
|
*/
|
||||||
protected function createEditPageAction() {
|
protected function createEditPageAction() {
|
||||||
$title = $this->getTitle();
|
$title = $this->getTitle();
|
||||||
|
@ -1187,18 +1187,12 @@ class SkinMinerva extends SkinTemplate {
|
||||||
$userCanEdit = $userQuickEditCheck && !$userBlockInfo;
|
$userCanEdit = $userQuickEditCheck && !$userBlockInfo;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => 'ca-edit',
|
'id' => 'ca-edit',
|
||||||
'text' => '',
|
'href' => $title->getLocalURL( $editArgs ),
|
||||||
'itemtitle' => $this->msg( 'mobile-frontend-pageaction-edit-tooltip' ),
|
'class' => 'edit-page '
|
||||||
'class' => MinervaUI::iconClass( $userCanEdit ? 'edit-enabled' : 'edit', 'element' ),
|
. MinervaUI::iconClass( $userCanEdit ? 'edit-enabled' : 'edit', 'element' ),
|
||||||
'links' => [
|
'title' => $this->msg( 'mobile-frontend-pageaction-edit-tooltip' ),
|
||||||
'edit' => [
|
'text' => $this->msg( 'mobile-frontend-editor-edit' )
|
||||||
'href' => $title->getLocalURL( $editArgs ),
|
|
||||||
'msg' => 'mobile-frontend-editor-edit',
|
|
||||||
'class' => 'edit-page',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'is_js_only' => false,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1208,7 +1202,8 @@ class SkinMinerva extends SkinTemplate {
|
||||||
* will direct the user's UA to Special:Login.
|
* will direct the user's UA to Special:Login.
|
||||||
*
|
*
|
||||||
* @param array $actions
|
* @param array $actions
|
||||||
* @return array A map compatible with BaseTemplate#makeListItem
|
* @return array A map of HTML attributes and a "text" property to be used with the
|
||||||
|
* pageActionMenu.mustache template.
|
||||||
*/
|
*/
|
||||||
protected function createWatchPageAction( $actions ) {
|
protected function createWatchPageAction( $actions ) {
|
||||||
$title = $this->getTitle();
|
$title = $this->getTitle();
|
||||||
|
@ -1222,8 +1217,9 @@ class SkinMinerva extends SkinTemplate {
|
||||||
$baseResult = [
|
$baseResult = [
|
||||||
'id' => 'ca-watch',
|
'id' => 'ca-watch',
|
||||||
// Use blank icon to reserve space for watchstar icon once JS loads
|
// Use blank icon to reserve space for watchstar icon once JS loads
|
||||||
'class' => MinervaUI::iconClass( $icon, 'element', 'watch-this-article' ),
|
'class' => MinervaUI::iconClass( $icon, 'element', 'watch-this-article' ) . ' jsonly',
|
||||||
'is_js_only' => true
|
'title' => $this->msg( 'watchthispage' ),
|
||||||
|
'text' => $this->msg( 'watchthispage' )
|
||||||
];
|
];
|
||||||
|
|
||||||
if ( isset( $actions['watch'] ) ) {
|
if ( isset( $actions['watch'] ) ) {
|
||||||
|
@ -1231,11 +1227,10 @@ class SkinMinerva extends SkinTemplate {
|
||||||
} elseif ( isset( $actions['unwatch'] ) ) {
|
} elseif ( isset( $actions['unwatch'] ) ) {
|
||||||
$result = array_merge( $actions['unwatch'], $baseResult );
|
$result = array_merge( $actions['unwatch'], $baseResult );
|
||||||
$result['class'] .= ' watched';
|
$result['class'] .= ' watched';
|
||||||
|
$result[ 'text' ] = $this->msg( 'unwatchthispage' );
|
||||||
} else {
|
} else {
|
||||||
// placeholder for not logged in
|
// placeholder for not logged in
|
||||||
$result = array_merge( $baseResult, [
|
$result = array_merge( $baseResult, [
|
||||||
// FIXME: makeLink (used by makeListItem) when no text is present defaults to use the key
|
|
||||||
'text' => '',
|
|
||||||
'href' => $ctaUrl,
|
'href' => $ctaUrl,
|
||||||
] );
|
] );
|
||||||
}
|
}
|
||||||
|
@ -1247,26 +1242,26 @@ class SkinMinerva extends SkinTemplate {
|
||||||
* Creates the "switch-language" action: the icon that, when tapped, opens the language
|
* Creates the "switch-language" action: the icon that, when tapped, opens the language
|
||||||
* switcher.
|
* switcher.
|
||||||
*
|
*
|
||||||
* @return array A map compatible with BaseTemplate#makeListItem
|
* @return array A map of HTML attributes and a 'text' property to be used with the
|
||||||
|
* pageActionMenu.mustache template.
|
||||||
*/
|
*/
|
||||||
protected function createSwitchLanguageAction() {
|
protected function createSwitchLanguageAction() {
|
||||||
$languageSwitcherLinks = [];
|
$languageSwitcherLink = false;
|
||||||
$languageSwitcherClasses = 'language-selector';
|
$languageSwitcherClasses = ' language-selector';
|
||||||
|
|
||||||
if ( $this->doesPageHaveLanguages ) {
|
if ( $this->doesPageHaveLanguages ) {
|
||||||
$languageSwitcherLinks['mobile-frontend-language-article-heading'] = [
|
$languageSwitcherLink = SpecialPage::getTitleFor(
|
||||||
'href' => SpecialPage::getTitleFor( 'MobileLanguages', $this->getTitle() )->getLocalURL()
|
'MobileLanguages',
|
||||||
];
|
$this->getTitle()
|
||||||
|
)->getLocalURL();
|
||||||
} else {
|
} else {
|
||||||
$languageSwitcherClasses .= ' disabled';
|
$languageSwitcherClasses .= ' disabled';
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'text' => '',
|
'class' => MinervaUI::iconClass( 'language-switcher', 'element', $languageSwitcherClasses ),
|
||||||
'itemtitle' => $this->msg( 'mobile-frontend-language-article-heading' ),
|
'href' => $languageSwitcherLink,
|
||||||
'class' => MinervaUI::iconClass( 'language-switcher', 'element', $languageSwitcherClasses ),
|
'title' => $this->msg( 'mobile-frontend-language-article-heading' ),
|
||||||
'links' => $languageSwitcherLinks,
|
'text' => $this->msg( 'mobile-frontend-language-article-heading' )
|
||||||
'is_js_only' => false
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<nav class="page-actions-menu">
|
||||||
|
<ul id="page-actions" class="page-actions-menu__list">
|
||||||
|
{{#pageactions}}
|
||||||
|
<li class="page-actions-menu__list-item">
|
||||||
|
<a id="{{id}}" href="{{href}}" class="{{class}}" role="button" title="{{title}}">
|
||||||
|
{{text}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/pageactions}}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
|
@ -15,7 +15,70 @@
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#page-actions {
|
// used to disable the languages icon.
|
||||||
|
.mw-ui-icon-element.disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-actions-menu {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-top: 1px solid @colorGray14;
|
||||||
|
border-bottom: 1px solid @colorGray12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-actions-menu__list {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 44px; // total height is 46px. 2px added by border on .page-actions-menu
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-actions-menu__list-item {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-basis: 4em;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
// overriding default icon styles
|
||||||
|
.mw-ui-icon-element {
|
||||||
|
// The page actions menu icons are ever so slightly larger
|
||||||
|
// than standard icons.
|
||||||
|
@pageActionsIconSize: @iconSize + 0.15;
|
||||||
|
position: relative;
|
||||||
|
min-width: @pageActionsIconSize;
|
||||||
|
width: @pageActionsIconSize;
|
||||||
|
height: @pageActionsIconSize;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
margin: 0;
|
||||||
|
// `.mw-ui-icon` absolutely positions this pseudo-element but only
|
||||||
|
// positions right & left. This ensures icon stretches 100% height and
|
||||||
|
// stretches the entire height of its parent element.
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default layout - spacing out the first menu item
|
||||||
|
.page-actions-menu__list-item:first-child {
|
||||||
|
flex-grow: 1;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overriding common.less `display:inherit` (which causes `display: flex;` in this instance).
|
||||||
|
.client-js .jsonly#ca-watch {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: T213352 Delete this nested block after varnish cache has cleared and selectors
|
||||||
|
// no longer apply.
|
||||||
|
#page-actions:not( .page-actions-menu__list ) {
|
||||||
font-size: @pageActionFontSize;
|
font-size: @pageActionFontSize;
|
||||||
float: none;
|
float: none;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
@ -70,7 +133,7 @@
|
||||||
|
|
||||||
// FIXME: cached HTML. Can be removed when work on T212216
|
// FIXME: cached HTML. Can be removed when work on T212216
|
||||||
// has been deployed and varnish cache cleared.
|
// has been deployed and varnish cache cleared.
|
||||||
.heading-holder #page-actions:first-child {
|
.heading-holder #page-actions:not( .page-actions-menu__list ):first-child {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,12 @@
|
||||||
* @returns {jQuery.Object|null}
|
* @returns {jQuery.Object|null}
|
||||||
*/
|
*/
|
||||||
function downloadPageAction( skin, supportedNamespaces, windowObj ) {
|
function downloadPageAction( skin, supportedNamespaces, windowObj ) {
|
||||||
var icon, spinner = icons.spinner();
|
var icon, spinner = icons.spinner(),
|
||||||
|
// TODO: T213352 Temporary cache compatibility - to be deleted.
|
||||||
|
// Any conditionals using this boolean should be DELETED when the
|
||||||
|
// old page action menu is no longer being served to users.
|
||||||
|
// eslint-disable-next-line jquery/no-global-selector
|
||||||
|
oldPageActionsDOM = $( '#page-actions.hlist' ).length > 0;
|
||||||
if (
|
if (
|
||||||
isAvailable(
|
isAvailable(
|
||||||
windowObj, skin.page, navigator.userAgent,
|
windowObj, skin.page, navigator.userAgent,
|
||||||
|
@ -136,12 +141,17 @@
|
||||||
glyphPrefix: 'minerva',
|
glyphPrefix: 'minerva',
|
||||||
title: msg( 'minerva-download' ),
|
title: msg( 'minerva-download' ),
|
||||||
name: GLYPH,
|
name: GLYPH,
|
||||||
|
tagName: oldPageActionsDOM ? 'div' : 'button',
|
||||||
events: {
|
events: {
|
||||||
// will be bound to `this`
|
// will be bound to `this`
|
||||||
click: getOnClickHandler( skin, spinner )
|
click: getOnClickHandler( skin, spinner )
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
return $( '<li>' ).append( icon.$el ).append( spinner.$el.hide() );
|
if ( oldPageActionsDOM ) {
|
||||||
|
return $( '<li>' ).append( icon.$el ).append( spinner.$el.hide() );
|
||||||
|
} else {
|
||||||
|
return $( '<li>' ).addClass( 'page-actions-menu__list-item' ).append( icon.$el ).append( spinner.$el.hide() );
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,14 +236,19 @@
|
||||||
*/
|
*/
|
||||||
function appendDownloadButton() {
|
function appendDownloadButton() {
|
||||||
var $downloadAction = downloadPageAction( skin,
|
var $downloadAction = downloadPageAction( skin,
|
||||||
config.get( 'wgMinervaDownloadNamespaces', [] ), window );
|
config.get( 'wgMinervaDownloadNamespaces', [] ), window ),
|
||||||
|
// TODO: T213352 Temporary cache compatibility - to be deleted.
|
||||||
|
// Any conditionals using this boolean should be DELETED when the
|
||||||
|
// old page action menu is no longer being served to users.
|
||||||
|
// eslint-disable-next-line jquery/no-global-selector
|
||||||
|
oldPageActionsDOM = $( '#page-actions.hlist' ).length > 0;
|
||||||
|
|
||||||
if ( $downloadAction ) {
|
if ( $downloadAction ) {
|
||||||
// Because the page actions are floated to the right, their order in the
|
if ( oldPageActionsDOM ) {
|
||||||
// DOM is reversed in the display. The watchstar is last in the DOM and
|
$downloadAction.insertAfter( '#ca-watch' );
|
||||||
// left-most in the display. Since we want the download button to be to
|
} else {
|
||||||
// the left of the watchstar, we put it after it in the DOM.
|
$downloadAction.insertAfter( '.page-actions-menu__list-item:first-child' );
|
||||||
$downloadAction.insertAfter( '#ca-watch' );
|
}
|
||||||
track( 'minerva.downloadAsPDF', {
|
track( 'minerva.downloadAsPDF', {
|
||||||
action: 'buttonVisible'
|
action: 'buttonVisible'
|
||||||
} );
|
} );
|
||||||
|
|
Loading…
Reference in New Issue