Make "Add topic" button sticky

Bug: T316175
Change-Id: Ie5198e902ec3fa7a7eba56cef6c6f0ef71ef7314
This commit is contained in:
Ed Sanders 2022-11-01 13:55:45 +00:00
parent bbdc49f87a
commit b132522fa9
4 changed files with 160 additions and 63 deletions

View file

@ -399,7 +399,6 @@
"RevisionDataUpdates": "dataupdates",
"LoadExtensionSchemaUpdates": "installer",
"ParserAfterTidy": "parser",
"ArticleViewHeader": "page",
"BeforeDisplayNoArticleText": "page",
"BeforePageDisplay": "page",
"GetActionName": "page",

View file

@ -23,7 +23,6 @@ use MediaWiki\Hook\BeforePageDisplayHook;
use MediaWiki\Hook\OutputPageBeforeHTMLHook;
use MediaWiki\Hook\TitleGetEditNoticesHook;
use MediaWiki\MediaWikiServices;
use MediaWiki\Page\Hook\ArticleViewHeaderHook;
use MediaWiki\Page\Hook\BeforeDisplayNoArticleTextHook;
use MediaWiki\User\UserNameUtils;
use MediaWiki\User\UserOptionsLookup;
@ -31,14 +30,12 @@ use OOUI\ButtonWidget;
use OOUI\HtmlSnippet;
use OOUI\MessageWidget;
use OutputPage;
use ParserOutput;
use RequestContext;
use Skin;
use SpecialPage;
use Title;
class PageHooks implements
ArticleViewHeaderHook,
BeforeDisplayNoArticleTextHook,
BeforePageDisplayHook,
GetActionNameHook,
@ -269,6 +266,39 @@ class PageHooks implements
}
}
if ( $output->getSkin()->getSkinName() === 'minerva' ) {
$title = $output->getTitle();
if (
HookUtils::isFeatureEnabledForOutput( $output, HookUtils::NEWTOPICTOOL ) &&
// Only add the button if "New section" tab would be shown in a normal skin.
HookUtils::shouldShowNewSectionTab( $output->getContext() )
) {
$output->enableOOUI();
$output->addModuleStyles( [
// For speechBubbleAdd
'oojs-ui.styles.icons-alerts',
] );
$output->addBodyClasses( 'ext-discussiontools-init-new-topic-opened' );
// Minerva doesn't show a new topic button by default, unless the MobileFrontend
// talk page feature is enabled, but we shouldn't depend on code from there.
$text .= Html::rawElement( 'div',
[ 'class' => 'ext-discussiontools-init-new-topic' ],
( new ButtonWidget( [
'classes' => [ 'ext-discussiontools-init-new-topic-button' ],
'href' => $title->getLinkURL( [ 'action' => 'edit', 'section' => 'new' ] ),
'icon' => 'speechBubbleAdd',
'label' => $output->getContext()->msg( 'skin-action-addsection' )->text(),
'flags' => [ 'progressive', 'primary' ],
'infusable' => true,
] ) )
// For compatibility with Minerva click tracking (T295490)
->setAttributes( [ 'data-event-name' => 'talkpage.add-topic' ] )
);
}
}
return true;
}
@ -412,44 +442,6 @@ class PageHooks implements
return $wrapped;
}
/**
* @param Article $article
* @param bool|ParserOutput &$outputDone
* @param bool &$pcache
* @return bool|void
*/
public function onArticleViewHeader( $article, &$outputDone, &$pcache ) {
$context = $article->getContext();
$output = $context->getOutput();
if ( $output->getSkin()->getSkinName() === 'minerva' ) {
$title = $article->getTitle();
if (
HookUtils::isFeatureEnabledForOutput( $output, HookUtils::NEWTOPICTOOL ) &&
// Only add the button if "New section" tab would be shown in a normal skin.
HookUtils::shouldShowNewSectionTab( $context )
) {
$output->enableOOUI();
// Minerva doesn't show a new topic button by default, unless the MobileFrontend
// talk page feature is enabled, but we shouldn't depend on code from there.
$output->addHTML(
Html::rawElement( 'div',
[ 'class' => 'ext-discussiontools-init-new-topic' ],
( new ButtonWidget( [
'href' => $title->getLinkURL( [ 'action' => 'edit', 'section' => 'new' ] ),
'label' => $context->msg( 'skin-action-addsection' )->text(),
'flags' => [ 'progressive', 'primary' ],
] ) )
// For compatibility with Minerva click tracking (T295490)
->setAttributes( [ 'data-event-name' => 'talkpage.add-topic' ] )
)
);
}
}
}
/**
* @param Title $title Title object for the page the edit notices are for
* @param int $oldid Revision ID that the edit notices are for (or 0 for latest)

View file

@ -185,10 +185,6 @@ h1, h2, h3, h4, h5, h6 {
}
}
.ext-discussiontools-init-new-topic {
margin: 0.5em 0;
}
// Topic subscriptions (link)
.ext-discussiontools-init-section-subscribe {
display: none;
@ -728,20 +724,78 @@ h1, h2, h3, h4, h5, h6 {
.ext-discussiontools-init-readAsWikiPage {
display: block;
/* Not sticky per T309889 */
width: 100%;
padding: 1em;
color: @colorProgressive;
background: @colorGray15;
border-top: 1px solid @colorGray14;
text-align: center;
// Match Minerva styles
max-width: 993.3px;
margin-left: auto;
margin-right: auto;
// Avoid smooshing with content / empty state (T320755)
margin-top: 32px;
margin-bottom: -32px; // stylelint-disable-line declaration-block-no-redundant-longhand-properties
}
}
.minerva-footer-button() {
width: 100%;
padding: 1em;
box-sizing: content-box;
color: @colorProgressive;
background: @colorGray15;
border-top: 1px solid @colorGray14;
text-align: center;
// Match Minerva styles
max-width: 993.3px;
// stylelint-disable-next-line declaration-no-important
margin-left: -16px !important;
// stylelint-disable-next-line declaration-no-important
margin-right: -16px !important;
}
.ext-discussiontools-init-readAsWikiPage {
/* Not sticky per T309889 */
.minerva-footer-button();
// Avoid smooshing with content / empty state (T320755)
margin-top: 32px;
margin-bottom: -32px;
}
.ext-discussiontools-init-new-topic {
.minerva-footer-button();
// margin: 0.5em 0 !important;
// stylelint-disable-next-line declaration-no-important
display: block !important;
// stylelint-disable-next-line plugin/no-unsupported-browser-features
position: sticky;
// Required for IntersectionObserver trick
bottom: -1px;
transition: transform 250ms, opacity 250ms;
transform: translateY( 100% );
opacity: 0;
// Avoid smooshing with content / empty state (T320755)
margin-top: 32px;
& + .ext-discussiontools-init-readAsWikiPage {
margin-top: 0;
}
.ext-discussiontools-init-new-topic-open &,
.ext-discussiontools-init-new-topic-opened &,
.client-nojs & {
transform: translateY( 0 );
opacity: 1;
}
.ext-discussiontools-init-new-topic-close & {
transform: translateY( 100% );
opacity: 0;
}
.ext-discussiontools-init-new-topic-closed &,
.ext-discussiontools-init-virtual-keyboard-open &,
&-pinned.oo-ui-buttonElement {
transform: translateY( 0 );
opacity: 1;
position: static;
transition: none;
}
.ext-discussiontools-init-replylink-open & {
.ext-discussiontools-fake-disabled();
transform: translateY( 0 );
opacity: 1;
position: static;
}
// Always hide the table of content. This is usually hidden by the mf-section-0 rules,

View file

@ -1,4 +1,4 @@
var $readAsWikiPage, ledeSectionDialog;
var newTopicButton, $readAsWikiPage, ledeSectionDialog;
var viewportScrollContainer = null;
var wasKeyboardOpen = null;
var initialClientHeight = null;
@ -81,6 +81,53 @@ function init( $container ) {
} );
} );
}
if (
!newTopicButton &&
// eslint-disable-next-line no-jquery/no-global-selector
$( '.ext-discussiontools-init-new-topic-button' ).length
) {
// eslint-disable-next-line no-jquery/no-global-selector
newTopicButton = OO.ui.infuse( $( '.ext-discussiontools-init-new-topic-button' ) );
// For compatibility with Minerva click tracking (T295490)
newTopicButton.$element.attr( 'data-event-name', 'talkpage.add-topic' );
var $scrollContainer = $( OO.ui.Element.static.getClosestScrollableContainer( document.body ) );
var $scrollListener = $scrollContainer.is( 'html, body' ) ? $( OO.ui.Element.static.getWindow( $scrollContainer[ 0 ] ) ) : $scrollContainer;
var lastScrollTop = $scrollContainer.scrollTop();
var wasScrollDown = null;
var $body = $( document.body );
// TODO: Use ve.addPassiveEventListener
$scrollListener.on( 'scroll', OO.ui.throttle( function () {
var scrollTop = $scrollContainer.scrollTop();
var isScrollDown = scrollTop > lastScrollTop;
if ( isScrollDown !== wasScrollDown ) {
if ( !isScrollDown ) {
newTopicButton.$element.css( 'transition', 'none' );
}
$body.removeClass( [ 'ext-discussiontools-init-new-topic-closed', 'ext-discussiontools-init-new-topic-opened' ] );
requestAnimationFrame( function () {
newTopicButton.$element.css( 'transition', '' );
$body.addClass( isScrollDown ? 'ext-discussiontools-init-new-topic-close' : 'ext-discussiontools-init-new-topic-open' );
setTimeout( function () {
$body.removeClass( [ 'ext-discussiontools-init-new-topic-close', 'ext-discussiontools-init-new-topic-open' ] );
$body.addClass( isScrollDown ? 'ext-discussiontools-init-new-topic-closed' : 'ext-discussiontools-init-new-topic-opened' );
}, 250 );
} );
}
var observer = new IntersectionObserver(
function ( entries ) {
newTopicButton.$element.toggleClass( 'ext-discussiontools-init-new-topic-pinned', entries[ 0 ].intersectionRatio === 1 );
},
{ threshold: [ 1 ] }
);
observer.observe( newTopicButton.$element[ 0 ] );
lastScrollTop = scrollTop;
wasScrollDown = isScrollDown;
}, 200 ) );
}
if ( !$readAsWikiPage ) {
// Read as wiki page button, copied from renderReadAsWikiPageButton in Minerva
$readAsWikiPage = $( '<button>' )
@ -91,8 +138,13 @@ function init( $container ) {
$( document.body ).removeClass( 'ext-discussiontools-visualenhancements-enabled ext-discussiontools-replytool-enabled' );
} );
}
// eslint-disable-next-line no-jquery/no-global-selector
$( '#content' ).append( $readAsWikiPage );
if ( newTopicButton ) {
// eslint-disable-next-line no-jquery/no-global-selector
$( '.ext-discussiontools-init-new-topic' ).after( $readAsWikiPage );
} else {
// eslint-disable-next-line no-jquery/no-global-selector
$( '#mw-content-text' ).append( $readAsWikiPage );
}
}
module.exports = {