From 7e423c07b79a97fce98b70947c639522caf81c18 Mon Sep 17 00:00:00 2001 From: jdlrobson Date: Thu, 10 Jan 2019 14:59:56 -0800 Subject: [PATCH] Talk tabs in AMC mode A new feature/skin option is added that is enabled safely inside a MobileFrontend available/unavailable hook that changes the skin to place talk tabs at the top of the page. These new talk tabs purposely show on the main page, user page and standard pages and do not show on special pages. Depends-On: Ie1a583657176acc6f7046c569c2e94fa2f72ff93 Bug: T212216 Change-Id: I57b70cd325666a287678dc897159b5bf9d089b78 --- includes/MinervaHooks.php | 15 +++++++++++- includes/skins/MinervaTemplate.php | 6 ++++- includes/skins/SkinMinerva.php | 13 ++++++++++- includes/skins/minerva.mustache | 7 +++++- minerva.less/minerva.variables.less | 6 +++++ resources/skins.minerva.amc.styles/index.less | 4 ++++ resources/skins.minerva.amc.styles/tabs.less | 23 +++++++++++++++++++ .../pageactions.less | 2 +- resources/skins.minerva.talk/init.js | 20 ++++++++-------- skin.json | 14 +++++++++++ 10 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 resources/skins.minerva.amc.styles/index.less create mode 100644 resources/skins.minerva.amc.styles/tabs.less diff --git a/includes/MinervaHooks.php b/includes/MinervaHooks.php index ebd7086..42b2536 100644 --- a/includes/MinervaHooks.php +++ b/includes/MinervaHooks.php @@ -67,6 +67,13 @@ class MinervaHooks { $config->get( 'MinervaPageIssuesNewTreatment' ) ) ); + $featureManager->registerFeature( + new MobileFrontend\Features\Feature( + 'MinervaTalkAtTop', + 'skin-minerva', + $config->get( 'MinervaTalkAtTop' ) + ) + ); } catch ( RuntimeException $e ) { // features already registered... // due to a bug it's possible for this to run twice @@ -171,11 +178,17 @@ class MinervaHooks { ) { // setSkinOptions is not available if ( $skin instanceof SkinMinerva ) { - $featureManager = \MediaWiki\MediaWikiServices::getInstance() + $services = \MediaWiki\MediaWikiServices::getInstance(); + $featureManager = $services ->getService( 'MobileFrontend.FeaturesManager' ); + $userMode = $services->getService( 'MobileFrontend.AMC.UserMode' ); $isBeta = $mobileContext->isBetaGroupMember(); $skin->setSkinOptions( [ + SkinMinerva::OPTION_AMC => $userMode->isEnabled(), + SkinMinerva::OPTIONS_TALK_AT_TOP => $featureManager->isFeatureAvailableForCurrentUser( + 'MinervaTalkAtTop' + ), SkinMinerva::OPTIONS_MOBILE_BETA => $isBeta, SkinMinerva::OPTION_CATEGORIES diff --git a/includes/skins/MinervaTemplate.php b/includes/skins/MinervaTemplate.php index a3cf841..7058c09 100644 --- a/includes/skins/MinervaTemplate.php +++ b/includes/skins/MinervaTemplate.php @@ -231,6 +231,7 @@ class MinervaTemplate extends BaseTemplate { */ protected function render( $data ) { $templateParser = new TemplateParser( __DIR__ ); + $skin = $this->getSkin(); $internalBanner = $data[ 'internalBanner' ]; $preBodyHtml = isset( $data['prebodyhtml'] ) ? $data['prebodyhtml'] : ''; $hasHeadingHolder = $internalBanner || $preBodyHtml || isset( $data['page_actions'] ); @@ -270,7 +271,10 @@ class MinervaTemplate extends BaseTemplate { 'contenthtml' => $this->getContentHtml( $data ), 'secondaryactionshtml' => $this->getSecondaryActionsHtml(), 'footer' => $this->getFooterTemplateData( $data ), - 'isBeta' => $this->getSkin()->getSkinOption( SkinMinerva::OPTIONS_MOBILE_BETA ), + 'isBeta' => $skin->getSkinOption( SkinMinerva::OPTIONS_MOBILE_BETA ), + 'tabs' => !$this->isSpecialPage && $skin->getSkinOption( SkinMinerva::OPTIONS_TALK_AT_TOP ) ? [ + 'items' => array_values( $data['content_navigation']['namespaces'] ), + ] : false, ]; // begin rendering echo $templateParser->processTemplate( 'minerva', $templateData ); diff --git a/includes/skins/SkinMinerva.php b/includes/skins/SkinMinerva.php index 2c4a7aa..6428275 100644 --- a/includes/skins/SkinMinerva.php +++ b/includes/skins/SkinMinerva.php @@ -30,12 +30,15 @@ use MediaWiki\Minerva\SkinUserPageHelper; class SkinMinerva extends SkinTemplate { /** Set of keys for available skin options. See $skinOptions. */ const OPTION_MOBILE_OPTIONS = 'mobileOptionsLink'; + const OPTION_AMC = 'amc'; const OPTION_CATEGORIES = 'categories'; const OPTION_BACK_TO_TOP = 'backToTop'; const OPTION_PAGE_ISSUES = 'pageIssues'; const OPTION_SHARE_BUTTON = 'shareButton'; const OPTION_TOGGLING = 'toggling'; const OPTIONS_MOBILE_BETA = 'beta'; + const OPTIONS_TALK_AT_TOP = 'talkAtTop'; + /** @const LEAD_SECTION_NUMBER integer which corresponds to the lead section in editing mode */ const LEAD_SECTION_NUMBER = 0; @@ -106,6 +109,7 @@ class SkinMinerva extends SkinTemplate { /** Whether sections can be collapsed (requires MobileFrontend and MobileFormatter) */ self::OPTION_TOGGLING => false, self::OPTION_PAGE_ISSUES => false, + self::OPTIONS_TALK_AT_TOP => false, ]; /** @@ -144,6 +148,7 @@ class SkinMinerva extends SkinTemplate { */ protected function prepareQuickTemplate() { $out = $this->getOutput(); + // add head items $out->addMeta( 'viewport', 'initial-scale=1.0, user-scalable=yes, minimum-scale=0.25, ' . 'maximum-scale=5.0, width=device-width' @@ -1093,7 +1098,9 @@ class SkinMinerva extends SkinTemplate { // in stable it will link to the wikitext talk page $title = $this->getTitle(); $namespaces = $tpl->data['content_navigation']['namespaces']; - if ( !$this->getUserPageHelper()->isUserPage() && $this->isTalkAllowed() ) { + if ( !$this->getUserPageHelper()->isUserPage() && $this->isTalkAllowed() + && !$this->getSkinOption( self::OPTIONS_TALK_AT_TOP ) + ) { // FIXME [core]: This seems unnecessary.. $subjectId = $title->getNamespaceKey( '' ); $talkId = $subjectId === 'main' ? 'talk' : "{$subjectId}_talk"; @@ -1444,6 +1451,10 @@ class SkinMinerva extends SkinTemplate { $styles[] = 'skins.minerva.icons.loggedin'; } + if ( $this->getSkinOption( self::OPTION_AMC ) ) { + $styles[] = 'skins.minerva.amc.styles'; + } + return $styles; } } diff --git a/includes/skins/minerva.mustache b/includes/skins/minerva.mustache index df57f82..4c1b288 100644 --- a/includes/skins/minerva.mustache +++ b/includes/skins/minerva.mustache @@ -31,6 +31,11 @@
{{{headinghtml}}} {{{taglinehtml}}} + {{#tabs}} + {{#items}} + {{text}} + {{/items}} + {{/tabs}} {{{postheadinghtml}}} {{{subtitle}}} {{{pageactionshtml}}} @@ -47,4 +52,4 @@
- + diff --git a/minerva.less/minerva.variables.less b/minerva.less/minerva.variables.less index 4ad5bfa..eb08eb9 100644 --- a/minerva.less/minerva.variables.less +++ b/minerva.less/minerva.variables.less @@ -45,6 +45,12 @@ @titleSectionSpacingTop: 20px; @titleSectionSpacingBottom: 25px; +// Page actions +@pageActionsGutter: 0.5em; +@pageActionsHeight: @pageActionFontSize + (2 * @iconGutterWidth); +@tabBorderSize: ( 1em / 16px ) * 2; +@taglineFontSize: 0.85em; + // colors @chromeColor: @grayLightest; @semiTransparent: rgba( 0, 0, 0, 0.8 ); diff --git a/resources/skins.minerva.amc.styles/index.less b/resources/skins.minerva.amc.styles/index.less new file mode 100644 index 0000000..225376d --- /dev/null +++ b/resources/skins.minerva.amc.styles/index.less @@ -0,0 +1,4 @@ +@import '../../minerva.less/minerva.variables'; +@import '../../minerva.less/minerva.mixins'; + +@import "tabs.less"; diff --git a/resources/skins.minerva.amc.styles/tabs.less b/resources/skins.minerva.amc.styles/tabs.less new file mode 100644 index 0000000..e604836 --- /dev/null +++ b/resources/skins.minerva.amc.styles/tabs.less @@ -0,0 +1,23 @@ +.minerva__tab { + font-size: @taglineFontSize; + margin: 18px 10px 1px 0; + color: @colorGray5; + font-weight: bold; + padding-bottom: 6px; + display: inline-block; + + &:visited, + &:hover, + &:active, + &.new, + &.new:visited, + &.new:active, + &.new:hover { + color: @colorGray5; + text-decoration: none; + } + // note core doesn't use BEM. + &.selected { + border-bottom: @tabBorderSize solid @colorGray5; + } +} diff --git a/resources/skins.minerva.base.styles/pageactions.less b/resources/skins.minerva.base.styles/pageactions.less index 1ed5b3b..baf1c3d 100644 --- a/resources/skins.minerva.base.styles/pageactions.less +++ b/resources/skins.minerva.base.styles/pageactions.less @@ -26,7 +26,7 @@ .tagline { color: @colorGray5; - font-size: 0.85em; + font-size: @taglineFontSize; margin: 2px 0 12px; } } diff --git a/resources/skins.minerva.talk/init.js b/resources/skins.minerva.talk/init.js index fc93340..6789876 100644 --- a/resources/skins.minerva.talk/init.js +++ b/resources/skins.minerva.talk/init.js @@ -5,7 +5,7 @@ LoadingOverlay = mobile.LoadingOverlay, eventBus = new EventEmitter(), // eslint-disable-next-line jquery/no-global-selector - $talk = $( '.talk' ), + $talk = $( '.talk, [rel="discussion"]' ), // use the plain return value here - T128273 title = $talk.attr( 'data-title' ), overlayManager = M.require( 'skins.minerva.scripts/overlayManager' ), @@ -13,12 +13,10 @@ inTalkNamespace = false, pageTitle, talkTitle, talkNs, pageNs; - // if there's no title for any reason, don't do anything - if ( !title ) { - return; - } // T127190 - title = decodeURIComponent( title ); + if ( title ) { + title = decodeURIComponent( title ); + } // sanity check: the talk namespace needs to have the next higher integer // of the page namespace (the api should add topics only to the talk page of the current @@ -26,9 +24,13 @@ // (https://www.mediawiki.org/wiki/Manual:Using_custom_namespaces#Creating_a_custom_namespace) // The method to get associated namespaces will change later (maybe), see T487 pageTitle = mw.Title.newFromText( mw.config.get( 'wgPageName' ) ); - talkTitle = mw.Title.newFromText( title ); + talkTitle = title ? mw.Title.newFromText( title ) : pageTitle.getTalkPage(); - if ( !pageTitle || !talkTitle || pageTitle.getMainText() !== talkTitle.getMainText() ) { + // Check that there is a valid page and talk title + if ( !pageTitle || !talkTitle || + // the talk link points to something other than the current page + // so we chose to leave this as a normal link + pageTitle.getMainText() !== talkTitle.getMainText() ) { return; } talkNs = talkTitle.getNamespaceId(); @@ -42,7 +44,7 @@ overlayManager.add( /^\/talk\/?(.*)$/, function ( id ) { var talkOptions = { api: new mw.Api(), - title: title, + title: talkTitle.toText(), // T184273 using `getCurrentPage` because 'wgPageName' contains underscores instead of // spaces. currentPageTitle: M.getCurrentPage().title, diff --git a/skin.json b/skin.json index 10eccfa..223736f 100644 --- a/skin.json +++ b/skin.json @@ -35,6 +35,11 @@ "switch-language" ], "MinervaAlwaysShowLanguageButton": true, + "MinervaTalkAtTop": { + "base": false, + "beta": false, + "amc": true + }, "MinervaShowCategoriesButton": { "base": false, "beta": true @@ -207,6 +212,15 @@ "notifications": "resources/skins.minerva.icons.loggedin/bell.svg" } }, + "skins.minerva.amc.styles": { + "targets": [ + "mobile", + "desktop" + ], + "styles": [ + "resources/skins.minerva.amc.styles/index.less" + ] + }, "skins.minerva.icons.images": { "class": "ResourceLoaderImageModule", "selector": ".mw-ui-icon-minerva-{name}:before",