mediawiki-extensions-Echo/includes/Special/SpecialNotifications.php
Jon Harald Søby 60748b0b25 Add PLURAL support for "mark all as read" buttons
Pass a relevant number of unread notifications to the messages
'echo-mark-all-as-read' and 'echo-mark-wiki-as-read' each time
they are used, in order to facilitate the use of PLURAL in
the messages. This allows translators to say e.g. "mark both as
read" when there are two unread notifications, for instance.

Bug: T321462
Change-Id: Ida65be2d7f2663d9802f71c7ea1eb588db8cd254
2023-04-29 01:31:14 +02:00

275 lines
7.7 KiB
PHP

<?php
namespace MediaWiki\Extension\Notifications\Special;
use EchoDataOutputFormatter;
use EchoSeenTime;
use Html;
use MediaWiki\Extension\Notifications\OOUI\LabelIconWidget;
use MWEchoEventLogging;
use MWEchoNotifUser;
use OOUI;
use SpecialPage;
class SpecialNotifications extends SpecialPage {
/**
* Number of notification records to display per page/load
*/
private const DISPLAY_NUM = 20;
public function __construct() {
parent::__construct( 'Notifications' );
}
/**
* @param string|null $par
*/
public function execute( $par ) {
$this->setHeaders();
$out = $this->getOutput();
$out->setPageTitle( $this->msg( 'echo-specialpage' )->text() );
$this->addHelpLink( 'Help:Notifications/Special:Notifications' );
$out->addJsConfigVars( 'wgNotificationsSpecialPageLinks', [
'preferences' => SpecialPage::getTitleFor( 'Preferences', false, 'mw-prefsection-echo' )->getLinkURL(),
] );
$user = $this->getUser();
if ( !$user->isRegistered() ) {
// Redirect to login page and inform user of the need to login
$this->requireLogin( 'echo-notification-loginrequired' );
return;
}
$out->addSubtitle( $this->buildSubtitle() );
$out->enableOOUI();
$pager = new NotificationPager( $this->getContext() );
$pager->setOffset( $this->getRequest()->getVal( 'offset' ) );
$pager->setLimit( $this->getRequest()->getInt( 'limit', self::DISPLAY_NUM ) );
$notifications = $pager->getNotifications();
$noJSDiv = new OOUI\Tag();
$noJSDiv->addClasses( [ 'mw-echo-special-nojs' ] );
// If there are no notifications, display a message saying so
if ( !$notifications ) {
// Wrap this with nojs so it is still hidden if JS is loading
$noJSDiv->appendContent(
new OOUI\LabelWidget( [ 'label' => $this->msg( 'echo-none' )->text() ] )
);
$out->addHTML( $noJSDiv );
$out->addModules( [ 'ext.echo.special' ] );
return;
}
$notif = [];
foreach ( $notifications as $notification ) {
$output = EchoDataOutputFormatter::formatOutput( $notification, 'special', $user, $this->getLanguage() );
if ( $output ) {
$notif[] = $output;
}
}
// Add the notifications to the page (interspersed with date headers)
$dateHeader = '';
$anyUnread = false;
$echoSeenTime = EchoSeenTime::newFromUser( $user );
$seenTime = $echoSeenTime->getTime();
$notifArray = [];
foreach ( $notif as $row ) {
if ( !$row['*'] ) {
continue;
}
$classes = [ 'mw-echo-notification' ];
if ( $seenTime !== null && $row['timestamp']['mw'] > $seenTime ) {
$classes[] = 'mw-echo-notification-unseen';
}
// Output the date header if it has not been displayed
if ( $dateHeader !== $row['timestamp']['date'] ) {
$dateHeader = $row['timestamp']['date'];
}
// Collect unread IDs
if ( !isset( $row['read'] ) ) {
$classes[] = 'mw-echo-notification-unread';
$anyUnread = true;
$notifArray[ $dateHeader ][ 'unread' ][] = $row['id'];
}
$li = new OOUI\Tag( 'li' );
$li
->addClasses( $classes )
->setAttributes( [
'data-notification-category' => $row['category'],
'data-notification-event' => $row['id'],
'data-notification-type' => $row['type']
] )
->appendContent( new OOUI\HtmlSnippet( $row['*'] ) );
// Store
$notifArray[ $dateHeader ][ 'notices' ][] = $li;
}
$markAllAsReadFormWrapper = '';
// Ensure there are some unread notifications
if ( $anyUnread ) {
$markReadSpecialPage = new SpecialNotificationsMarkRead();
$markReadSpecialPage->setContext( $this->getContext() );
$notifUser = MWEchoNotifUser::newFromUser( $user );
$unreadCount = $notifUser->getAlertCount() + $notifUser->getMessageCount();
$markAllAsReadText = $this
->msg( 'echo-mark-all-as-read' )
->numParams( $unreadCount )
->text();
$markAllAsReadLabelIcon = new LabelIconWidget( [
'label' => $markAllAsReadText,
'icon' => 'checkAll',
] );
$markAllAsReadForm = $markReadSpecialPage->getMinimalForm(
[ 'ALL' ],
$markAllAsReadText,
true,
$markAllAsReadLabelIcon->toString()
);
// First submission attempt
$formHtml = $markAllAsReadForm->prepareForm()->getHTML( false );
$markAllAsReadFormWrapper = new OOUI\Tag();
$markAllAsReadFormWrapper
->addClasses( [ 'mw-echo-special-markAllReadButton' ] )
->appendContent( new OOUI\HtmlSnippet( $formHtml ) );
}
// Build the list
$notices = new OOUI\Tag( 'ul' );
$notices->addClasses( [ 'mw-echo-special-notifications' ] );
$markReadSpecialPage = new SpecialNotificationsMarkRead();
$markReadSpecialPage->setContext( $this->getContext() );
foreach ( $notifArray as $section => $data ) {
$heading = ( new OOUI\Tag( 'li' ) )->addClasses( [ 'mw-echo-date-section' ] );
$dateTitle = new OOUI\LabelWidget( [
'classes' => [ 'mw-echo-date-section-text' ],
'label' => $section
] );
$heading->appendContent( $dateTitle );
// Mark all read button
if ( isset( $data[ 'unread' ] ) ) {
// tell the UI to show 'unread' notifications only (instead of 'all')
$out->addJsConfigVars( 'wgEchoReadState', 'unread' );
$markReadSectionText = $this->msg( 'echo-specialpage-section-markread' )->text();
$markAsReadLabelIcon = new LabelIconWidget( [
'label' => $markReadSectionText,
'icon' => 'checkAll',
] );
// There are unread notices. Add the 'mark section as read' button
$markSectionAsReadForm = $markReadSpecialPage->getMinimalForm(
$data[ 'unread' ],
$markReadSectionText,
true,
$markAsReadLabelIcon->toString()
);
// First submission attempt
$formHtml = $markSectionAsReadForm->prepareForm()->getHTML( false );
$formWrapper = new OOUI\Tag();
$formWrapper
->addClasses( [ 'mw-echo-markAsReadSectionButton' ] )
->appendContent( new OOUI\HtmlSnippet( $formHtml ) );
$heading->appendContent( $formWrapper );
}
// These two must be separate, because $data[ 'notices' ]
// is an array
$notices
->appendContent( $heading )
// @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset https://github.com/phan/phan/issues/4735
->appendContent( $data[ 'notices' ] );
}
$navBar = $pager->getNavigationBar();
$navTop = new OOUI\Tag();
$navBottom = new OOUI\Tag();
$container = new OOUI\Tag();
$navTop
->addClasses( [ 'mw-echo-special-navbar-top' ] )
->appendContent( new OOUI\HtmlSnippet( $navBar ) );
$navBottom
->addClasses( [ 'mw-echo-special-navbar-bottom' ] )
->appendContent( new OOUI\HtmlSnippet( $navBar ) );
// Put it all together
$container
->addClasses( [ 'mw-echo-special-container' ] )
->appendContent(
$navTop,
$markAllAsReadFormWrapper,
$notices,
$navBottom
);
// Wrap with nojs div
$noJSDiv->appendContent( $container );
$out->addHTML( $noJSDiv );
$out->addModules( [ 'ext.echo.special' ] );
// For no-js support
$out->addModuleStyles( [
'ext.echo.styles.notifications',
'ext.echo.styles.special',
'oojs-ui.styles.icons-alerts',
'oojs-ui.styles.icons-interactions',
] );
// Log visit
MWEchoEventLogging::logSpecialPageVisit( $user, $out->getSkin()->getSkinName() );
}
/**
* Build the subtitle (more info and preference links)
* @return string HTML for the subtitle
*/
public function buildSubtitle() {
$lang = $this->getLanguage();
$subtitleLinks = [];
// Preferences link
$subtitleLinks[] = Html::element(
'a',
[
'href' => SpecialPage::getTitleFor( 'Preferences', false, 'mw-prefsection-echo' )->getLinkURL(),
'id' => 'mw-echo-pref-link',
'class' => 'mw-echo-special-header-link',
'title' => $this->msg( 'preferences' )->text()
],
$this->msg( 'preferences' )->text()
);
// using pipeList to make it easier to add some links in the future
return $lang->pipeList( $subtitleLinks );
}
protected function getGroupName() {
return 'login';
}
}