Merge "Add mark-as-read button to notifications in Special:Notifications"

This commit is contained in:
jenkins-bot 2016-05-11 18:42:46 +00:00 committed by Gerrit Code Review
commit 4331c30993
12 changed files with 171 additions and 48 deletions

View file

@ -13,6 +13,7 @@ $specialPageAliases = array();
$specialPageAliases['en'] = array(
'Notifications' => array( 'Notifications' ),
'DisplayNotificationsConfiguration' => array( 'DisplayNotificationsConfiguration' ),
'NotificationsMarkRead' => array( 'NotificationsMarkRead' ),
);
/** Arabic (العربية) */
@ -258,4 +259,4 @@ $specialPageAliases['zh-hans'] = array(
/** Traditional Chinese (中文(繁體)‎) */
$specialPageAliases['zh-hant'] = array(
'Notifications' => array( '通知' ),
);
);

View file

@ -63,6 +63,7 @@ $wgAPIModules['echomarkseen'] = 'ApiEchoMarkSeen';
// Special page
$wgSpecialPages['Notifications'] = 'SpecialNotifications';
$wgSpecialPages['DisplayNotificationsConfiguration'] = 'SpecialDisplayNotificationsConfiguration';
$wgSpecialPages['NotificationsMarkRead'] = 'SpecialNotificationsMarkRead';
// Housekeeping hooks
$wgHooks['LoadExtensionSchemaUpdates'][] = 'EchoHooks::onLoadExtensionSchemaUpdates';

View file

@ -257,22 +257,6 @@ $wgResourceModules += array(
),
'targets' => array( 'desktop', 'mobile' ),
),
'ext.echo.special' => $echoResourceTemplate + array(
'scripts' => array(
'special/ext.echo.special.js',
),
'dependencies' => array(
'mediawiki.ui.button',
'mediawiki.api',
'ext.echo.ui',
),
'messages' => array(
'echo-load-more-error',
'echo-more-info',
'echo-feedback',
),
),
// HACK: OOUI has an icon pack for these, but it's unhelpfully large and we don't
// want to load more as render-blocking CSS than we have to (T112401)
'ext.echo.badgeicons' => $echoResourceTemplate + array(

View file

@ -3,7 +3,7 @@
// @codingStandardsIgnoreFile
global $wgAutoloadClasses;
$wgAutoloadClasses += array(
$wgAutoloadClasses += [
'ApiEchoMarkRead' => __DIR__ . '/includes/api/ApiEchoMarkRead.php',
'ApiEchoMarkReadTest' => __DIR__ . '/tests/phpunit/api/ApiEchoMarkReadTest.php',
'ApiEchoMarkSeen' => __DIR__ . '/includes/api/ApiEchoMarkSeen.php',
@ -114,5 +114,6 @@ $wgAutoloadClasses += array(
'SpecialDisplayNotificationsConfiguration' => __DIR__ . '/includes/special/SpecialDisplayNotificationsConfiguration.php',
'SpecialNotifications' => __DIR__ . '/includes/special/SpecialNotifications.php',
'SpecialNotificationsFormatter' => __DIR__ . '/includes/formatters/SpecialNotificationsFormatter.php',
'SpecialNotificationsMarkRead' => __DIR__ . '/includes/special/SpecialNotificationsMarkRead.php',
'SuppressionMaintenanceTest' => __DIR__ . '/tests/phpunit/maintenance/SupressionMaintenanceTest.php',
);
];

View file

@ -94,6 +94,9 @@
"echo-displaynotificationsconfiguration-mandatory-notification-methods-header": "Required notification methods",
"echo-displaynotificationsconfiguration-mandatory-notification-methods-by-category-legend": "Which notification methods are mandatory for each category",
"echo-specialpage": "Notifications",
"echo-specialpage-markasread": "Notification: Mark as read",
"echo-specialpage-markasread-invalid-id": "Invalid event ID",
"notificationsmarkread-legend": "Mark notification as read",
"echo-anon": "To receive notifications, [$1 create an account] or [$2 log in].",
"echo-none": "You have no notifications.",
"echo-more-info": "More info",

View file

@ -85,6 +85,9 @@
"echo-displaynotificationsconfiguration-mandatory-notification-methods-header": "Header on DisplayNotificationsConfiguration for section about which notification methods are required",
"echo-displaynotificationsconfiguration-mandatory-notification-methods-by-category-legend": "Explanatory text on DisplayNotificationsConfiguration regarding which notification methods are mandatory for each category",
"echo-specialpage": "Special page title for Special:Notifications.\n{{Identical|Notification}}",
"echo-specialpage-markasread": "Special page title for Special:NotificationsMarkRead for marking specific notification as read.",
"echo-specialpage-markasread-invalid-id": "Error message shown to users who try to mark a notification as read with an invalid event ID.",
"notificationsmarkread-legend": "Title for the form that marks a notification as read in [[Special:NotificationsMarkAsRead]]",
"echo-anon": "Error message shown to users who try to visit [[Special:Notifications]] as an anon.\n\nParameters:\n* $1 - URL of signup page, with returnto pointing to Special:Notifications\n* $2 - URL of login page, with returnto pointing to Special:Notifications",
"echo-none": "Message shown to users who have no notifications. Also shown in the overlay.",
"echo-more-info": "This is used for the title (mouseover text) of an icon that links to a page with more information about the Echo extension.\n{{Identical|More information}}",

View file

@ -422,6 +422,14 @@ abstract class EchoEventPresentationModel implements JsonSerializable {
return array();
}
/**
* Get the ID of the associated event
* @return int Event id
*/
public function getEventId() {
return $this->event->getId();
}
/**
* @return array
* @throws TimestampException

View file

@ -2,9 +2,15 @@
/**
* A formatter for Special:Notifications
*
* This formatter uses OOUI libraries. Any calls to this formatter must
* also call OutputPage::enableOOUI() before calling this formatter.
*/
class SpecialNotificationsFormatter extends EchoEventFormatter {
protected function formatModel( EchoEventPresentationModel $model ) {
$markReadSpecialPage = SpecialPage::getTitleFor( 'NotificationsMarkRead' );
$id = $model->getEventId();
$icon = Html::element(
'img',
array(
@ -13,6 +19,15 @@ class SpecialNotificationsFormatter extends EchoEventFormatter {
)
);
OutputPage::setupOOUI();
$markAsReadButton = new OOUI\ButtonWidget( array(
'icon' => 'close',
'framed' => false,
'href' => $markReadSpecialPage->getLocalUrl() . '/' . $id,
'classes' => array( 'mw-echo-markAsReadButton' ),
'title' => wfMessage( 'echo-notification-markasread' )
) );
$html = Xml::tags(
'div',
array( 'class' => 'mw-echo-title' ),
@ -70,8 +85,10 @@ class SpecialNotificationsFormatter extends EchoEventFormatter {
// Wrap everything in mw-echo-content class
$html = Xml::tags( 'div', array( 'class' => 'mw-echo-content' ), $html );
// And then add the icon in front and wrap with mw-echo-state class.
$html = Xml::tags( 'div', array( 'class' => 'mw-echo-state' ), $icon . $html );
// And then add the mark as read button
// and the icon in front and wrap with
// mw-echo-state class.
$html = Xml::tags( 'div', array( 'class' => 'mw-echo-state' ), $markAsReadButton . $icon . $html );
return $html;
}

View file

@ -27,6 +27,8 @@ class SpecialNotifications extends SpecialPage {
$out->addSubtitle( $this->buildSubtitle() );
$out->enableOOUI();
// The continue parameter to pull current set of data from, this
// would be used for browsers with javascript disabled
$continue = $this->getRequest()->getVal( 'continue', null );
@ -67,34 +69,41 @@ class SpecialNotifications extends SpecialPage {
// Add the notifications to the page (interspersed with date headers)
$dateHeader = '';
$notices = '';
$unread = array();
$echoSeenTime = EchoSeenTime::newFromUser( $user );
$seenTime = $echoSeenTime->getTime();
$notifArray = array();
foreach ( $notif as $row ) {
$class = 'mw-echo-notification';
if ( !isset( $row['read'] ) ) {
$class .= ' mw-echo-unread';
$class .= ' mw-echo-notification-unread';
if ( !$row['targetpages'] ) {
$unread[] = $row['id'];
}
}
if ( $seenTime !== null && $row['timestamp']['mw'] > $seenTime ) {
$class .= ' mw-echo-unseen';
$class .= ' mw-echo-notification-unseen';
}
if ( !$row['*'] ) {
continue;
}
// Output the date header if it has not been displayed
if ( $dateHeader !== $row['timestamp']['date'] ) {
$dateHeader = $row['timestamp']['date'];
$notices .= Html::rawElement( 'li', array( 'class' => 'mw-echo-date-section' ), $dateHeader );
$notifArray[ $dateHeader ] = array(
'notices' => array()
);
}
$notices .= Html::rawElement(
// Collect unread IDs
if ( !isset( $row['read'] ) ) {
$notifArray[ $dateHeader ][ 'unread' ][] = $row['id'];
}
$notifArray[ $dateHeader ][ 'notices' ][] = Html::rawElement(
'li',
array(
'class' => $class,
@ -105,6 +114,19 @@ class SpecialNotifications extends SpecialPage {
$row['*']
);
}
// Build the HTML
$notices = '';
foreach ( $notifArray as $section => $data ) {
$sectionTitle = Html::element( 'span', array( 'class' => 'mw-echo-date-section-text' ), $section );
// Heading
$notices .= Html::rawElement( 'li', array( 'class' => 'mw-echo-date-section' ), $sectionTitle );
// Notices
$notices .= join( "\n", $data[ 'notices' ] );
}
$html = Html::rawElement( 'ul', array( 'id' => 'mw-echo-special-container' ), $notices );
// Build the more link
@ -123,7 +145,6 @@ class SpecialNotifications extends SpecialPage {
}
$out->addHTML( $html );
$out->addModules( 'ext.echo.special' );
$out->addJsConfigVars(
array(
'wgEchoDisplayNum' => self::DISPLAY_NUM,
@ -133,15 +154,6 @@ class SpecialNotifications extends SpecialPage {
);
// For no-js support
$out->addModuleStyles( array( 'ext.echo.styles.notifications', 'ext.echo.styles.special' ) );
DeferredUpdates::addCallableUpdate( function () use ( $user, $echoSeenTime, $unread ) {
// Mark items as read
if ( $unread ) {
MWEchoNotifUser::newFromUser( $user )->markRead( $unread );
}
// Record time notifications have been seen
$echoSeenTime->setTime( wfTimestamp( TS_MW ) );
} );
}
/**
@ -153,7 +165,7 @@ class SpecialNotifications extends SpecialPage {
$lang = $this->getLanguage();
$subtitleLinks = array();
// More info link
$subtitleLinks[] = Html::rawElement(
$subtitleLinks[] = Html::element(
'a',
array(
'href' => $wgEchoHelpPage,
@ -165,7 +177,7 @@ class SpecialNotifications extends SpecialPage {
$this->msg( 'echo-more-info' )->text()
);
// Preferences link
$subtitleLinks[] = Html::rawElement(
$subtitleLinks[] = Html::element(
'a',
array(
'href' => SpecialPage::getTitleFor( 'Preferences' )->getLinkURL() . '#mw-prefsection-echo',

View file

@ -0,0 +1,76 @@
<?php
class SpecialNotificationsMarkRead extends FormSpecialPage {
protected $eventId;
public function __construct() {
parent::__construct( 'NotificationsMarkRead' );
}
public function execute( $par ) {
parent::execute( $par );
$out = $this->getOutput();
$out->setPageTitle( $this->msg( 'echo-specialpage-markasread' )->text() );
// Redirect to login page and inform user of the need to login
$this->requireLogin( 'echo-notification-loginrequired' );
}
public function isListed() {
return false;
}
/**
* Get an HTMLForm descriptor array
* @return array
*/
protected function getFormFields() {
return array(
'id' => array(
'type' => 'hidden',
'required' => true,
'default' => $this->par,
'filter-callback' => function ( $value, $alldata ) {
// Allow for a single value or a set of values
$result = explode( ',', $value );
return $result;
},
'validation-callback' => function ( $value, $alldata ) {
if ( (int)$value <= 0 ) {
return $this->msg( 'echo-specialpage-markasread-invalid-id' );
}
foreach ( $value as $val ) {
if ( (int)( $val ) <= 0 ) {
return $this->msg( 'echo-specialpage-markasread-invalid-id' );
}
}
return true;
}
)
);
}
protected function alterForm( HTMLForm $form ) {
$form->setSubmitText( $this->msg( 'echo-notification-markasread' ) );
}
/**
* Process the form on POST submission.
* @param array $data
* @param HTMLForm $form
* @return bool|string|array|Status As documented for HTMLForm::trySubmit.
*/
public function onSubmit( array $data /* $form = null */ ) {
// Allow for multiple IDs or a single ID
$ids = $data['id'];
$notifUser = MWEchoNotifUser::newFromUser( $this->getUser() );
return $notifUser->markRead( $ids );
}
public function onSuccess() {
$page = SpecialPage::getTitleFor( 'Notifications' );
$this->getOutput()->redirect( $page->getFullUrl() );
}
}

View file

@ -7,7 +7,8 @@
// not wrapped with a NotificationItemWidget.
.mw-echo-state {
display: block;
padding: 15px 40px 10px 10px;
width: 100%;
box-sizing: border-box;
.mw-echo-notification-primary-link {
display: none;
@ -35,10 +36,6 @@
overflow: hidden;
zoom: 1;
&.mw-echo-unread {
color: #252525;
}
span.autocomment {
color: inherit;
font-style: normal;

View file

@ -59,7 +59,7 @@
font-size: 1.1em;
text-transform: uppercase;
border-bottom: 1px solid #C9C9C9;
margin: 30px 0 5px 50px;
margin: 30px 0 5px 0;
color: #686868;
max-width: 550px;
}
@ -72,12 +72,17 @@ ul#mw-echo-special-container {
}
.mw-echo-notification {
padding: 15px 35px 10px 0;
padding: 30px 40px 15px 10px;
margin-right: 40px;
.mw-echo-markAsReadButton {
display: none;
}
}
#mw-echo-special-container {
.mw-echo-notification {
background-color: transparent;
background-color: #F1F1F1;
&:hover {
/* Fallback for IE<=8 */
@ -85,10 +90,25 @@ ul#mw-echo-special-container {
background-color: rgba(0, 0, 0, 0.035);
}
&.mw-echo-unread {
&-unread {
color: #252525;
background-color: transparent;
padding-right: 0;
.mw-echo-title {
font-weight: bold;
}
.mw-echo-markAsReadButton {
float: right;
display: inline-block;
margin-left: 1em;
opacity: 0.5;
&:hover {
opacity: 1;
}
}
}
}
}