diff --git a/Echo.i18n.php b/Echo.i18n.php index 28e2ea2e4..ce72ea261 100644 --- a/Echo.i18n.php +++ b/Echo.i18n.php @@ -143,6 +143,7 @@ $1', 'echo-overlay-link' => 'All notifications', 'echo-overlay-title' => 'Notifications', 'echo-overlay-title-overflow' => 'Notifications (showing $1 of $2 unread)', + 'echo-mark-all-as-read' => 'Mark all as read', // Special page 'echo-date-today' => 'Today', @@ -440,6 +441,7 @@ The new notification count next to notification link, for example: 99+ * $1 - the number of unread notifications being shown * $2 - the total number of unread notifications that exist {{Identical|Notification}}', + 'echo-mark-all-as-read' => 'Text for button that marks all unread notifications as read. Keep this short as possible.', 'echo-date-today' => "The header text for today's notification section", 'echo-date-yesterday' => "The header text for yesterday's notification section", 'echo-date-header' => '{{optional}} diff --git a/Echo.php b/Echo.php index 9f012e022..a23c3628b 100644 --- a/Echo.php +++ b/Echo.php @@ -129,6 +129,7 @@ $wgResourceModules += array( 'mediawiki.jqueryMsg', 'jquery.badge', 'ext.echo.icons', + 'mediawiki.ui', ), 'messages' => array( 'echo-link-new', @@ -137,6 +138,7 @@ $wgResourceModules += array( 'echo-overlay-title-overflow', 'echo-overlay-link', 'echo-none', + 'echo-mark-all-as-read', ), ), 'ext.echo.special' => $echoResourceTemplate + array( diff --git a/Hooks.php b/Hooks.php index d054b63a3..b91a880e5 100644 --- a/Hooks.php +++ b/Hooks.php @@ -620,7 +620,7 @@ class EchoHooks { * @return bool true in all cases */ public static function makeGlobalVariablesScript( &$vars, OutputPage $outputPage ) { - global $wgEchoShowFullNotificationsLink, $wgEchoHelpPage; + global $wgEchoShowFullNotificationsLink, $wgEchoHelpPage, $wgEchoMaxNotificationCount; $user = $outputPage->getUser(); // Provide info for the Overlay @@ -631,6 +631,7 @@ class EchoHooks { 'notifications-link-full' => $wgEchoShowFullNotificationsLink, 'timestamp' => $timestamp->getTimestamp( TS_UNIX ), 'notification-count' => EchoNotificationController::getFormattedNotificationCount( $user ), + 'max-notification-count' => $wgEchoMaxNotificationCount, ); $vars['wgEchoHelpPage'] = $wgEchoHelpPage; } diff --git a/api/ApiEchoNotifications.php b/api/ApiEchoNotifications.php index 64132a2d8..45a2c918b 100644 --- a/api/ApiEchoNotifications.php +++ b/api/ApiEchoNotifications.php @@ -14,6 +14,8 @@ class ApiEchoNotifications extends ApiQueryBase { $params = $this->extractRequestParams(); if ( count( $params['markread'] ) ) { EchoNotificationController::markRead( $user, $params['markread'] ); + } elseif ( $params['markallread'] ) { + EchoNotificationController::markAllRead( $user ); } $prop = $params['prop']; @@ -161,6 +163,10 @@ class ApiEchoNotifications extends ApiQueryBase { 'markread' => array( ApiBase::PARAM_ISMULTI => true, ), + 'markallread' => array( + ApiBase::PARAM_REQUIRED => false, + ApiBase::PARAM_TYPE => 'boolean' + ), 'format' => array( ApiBase::PARAM_TYPE => array( 'text', @@ -188,6 +194,7 @@ class ApiEchoNotifications extends ApiQueryBase { return array( 'prop' => 'Details to request.', 'markread' => 'A list of notification IDs to mark as read', + 'markallread' => "If set to true, marks all of a user's notifications as read", 'format' => 'If specified, notifications will be returned formatted this way.', 'index' => 'If specified, a list of notification IDs, in order, will be returned.', 'limit' => 'The maximum number of notifications to return.', diff --git a/controller/NotificationController.php b/controller/NotificationController.php index 481768e49..e9ce8553d 100644 --- a/controller/NotificationController.php +++ b/controller/NotificationController.php @@ -161,6 +161,25 @@ class EchoNotificationController { self::resetNotificationCount( $user, DB_MASTER ); } + /** + * @param $user User to mark all notifications read for + * @return boolean + */ + public static function markAllRead( $user ) { + global $wgEchoBackend, $wgEchoMaxNotificationCount; + + $notificationCount = self::getNotificationCount( $user ); + // Only update all the unread notifications if it isn't a huge number. + // TODO: Implement batched jobs it's over the maximum. + if ( $notificationCount <= $wgEchoMaxNotificationCount ) { + $wgEchoBackend->markAllRead( $user ); + self::resetNotificationCount( $user, DB_MASTER ); + return true; + } else { + return false; + } + } + /** * Recalculates the number of notifications that a user has. * diff --git a/includes/DbEchoBackend.php b/includes/DbEchoBackend.php index 32b249661..83cad7076 100644 --- a/includes/DbEchoBackend.php +++ b/includes/DbEchoBackend.php @@ -227,6 +227,23 @@ class MWDbEchoBackend extends MWEchoBackend { ); } + /** + * @param $user User + */ + public function markAllRead( $user ) { + $this->dbw->update( + 'echo_notification', + array( 'notification_read_timestamp' => $this->dbw->timestamp( wfTimestampNow() ) ), + array( + 'notification_user' => $user->getId(), + 'notification_read_timestamp' => NULL, + 'notification_bundle_base' => 1, + ), + __METHOD__, + array( 'LIMIT' => 500 ) + ); + } + /** * @param $user User object to check notifications for * @param $dbSource string use master or slave storage to pull count diff --git a/includes/EchoBackend.php b/includes/EchoBackend.php index a3dc9c383..2ee2ba113 100644 --- a/includes/EchoBackend.php +++ b/includes/EchoBackend.php @@ -115,6 +115,12 @@ abstract class MWEchoBackend { */ abstract public function markRead( $user, $eventIDs ); + /** + * Mark all unread notifications as read for a user + * @param $user User + */ + abstract public function markAllRead( $user ); + /** * Retrieves number of unread notifications that a user has. * @param $user User object to check notifications for diff --git a/modules/overlay/ext.echo.overlay.css b/modules/overlay/ext.echo.overlay.css index 4aeec019d..4c5af355c 100644 --- a/modules/overlay/ext.echo.overlay.css +++ b/modules/overlay/ext.echo.overlay.css @@ -58,9 +58,12 @@ .mw-echo-overlay-title { /*border-bottom: 1px solid #A7D7F9;*/ font-size: 13px; - padding: 15px 15px 15px 60px; + line-height: 15px; + height: 15px; + padding: 15px 15px 15px 28px; border-bottom: 1px solid #DDDDDD; font-weight: bold; + position: relative; } #mw-echo-overlay-footer { @@ -113,3 +116,13 @@ border-bottom: 1px solid #DDDDDD; padding: 15px 15px 10px 60px; } + +#mw-echo-mark-read-button { + position: absolute; + bottom: 12px; + right: 15px; + padding: 1px 8px; + font-size: 11px; + line-height: 15px; + font-weight: normal; +} diff --git a/modules/overlay/ext.echo.overlay.js b/modules/overlay/ext.echo.overlay.js index cfbd589aa..e57566e43 100644 --- a/modules/overlay/ext.echo.overlay.js +++ b/modules/overlay/ext.echo.overlay.js @@ -58,7 +58,9 @@ $title = $( '
' ), $ul = $( '' ), titleText = '', - $overlayFooter; + overflow = false, + $overlayFooter, + $markReadButton; $ul.css( 'max-height', notificationLimit * 95 + 'px' ); $.each( notifications.index, function( index, id ) { @@ -84,15 +86,57 @@ } ); if ( notifications.index.length > 0 ) { - if ( unreadTotalCount > unread.length ) { + if ( isNaN( unreadTotalCount ) || unreadTotalCount > unread.length ) { titleText = mw.msg( 'echo-overlay-title-overflow', unread.length, unreadTotalCount ); + overflow = true; } else { titleText = mw.msg( 'echo-overlay-title' ); } } else { titleText = mw.msg( 'echo-none' ); } - $title.text( titleText ); + + $markReadButton = $( '