Fix some notification badge related issue

* In some languages like persian, the number 0 is represented as '.', we can't compare
  '.' with either 0 or '0' to detect the no-notification status of the badge

* The markread API doesn't respect uselang param, it would return 0 instead of . in a url with uselang=fa

Note: we need to provide raw and formatted count in the API since client side javascript
      doesn't provide fancy function like $wgLang->formatNum()

bug: 54575

Change-Id: I0a49828253ec346ed27c5b9a976f8bdff4e1fa90
This commit is contained in:
bsitu 2013-09-24 17:18:02 -07:00
parent 70bbd32eea
commit 3b3ed1e3bc
6 changed files with 67 additions and 42 deletions

View file

@ -152,6 +152,16 @@ $wgResourceModules += array(
), ),
'targets' => array( 'desktop', 'mobile' ), 'targets' => array( 'desktop', 'mobile' ),
), ),
'ext.echo.desktop' => $echoResourceTemplate + array(
'scripts' => 'desktop/ext.echo.desktop.js',
'dependencies' => array(
'ext.echo.base',
'mediawiki.api',
'mediawiki.Uri',
'mediawiki.jqueryMsg',
'mediawiki.user',
),
),
'ext.echo.overlay' => $echoResourceTemplate + array( 'ext.echo.overlay' => $echoResourceTemplate + array(
'scripts' => array( 'scripts' => array(
'overlay/ext.echo.overlay.js', 'overlay/ext.echo.overlay.js',
@ -162,12 +172,8 @@ $wgResourceModules += array(
'monobook' => 'overlay/ext.echo.overlay.monobook.css', 'monobook' => 'overlay/ext.echo.overlay.monobook.css',
), ),
'dependencies' => array( 'dependencies' => array(
'ext.echo.base', 'ext.echo.desktop',
'mediawiki.api',
'mediawiki.Uri',
'mediawiki.util', 'mediawiki.util',
'mediawiki.jqueryMsg',
'mediawiki.user',
), ),
'messages' => array( 'messages' => array(
'echo-overlay-title', 'echo-overlay-title',
@ -185,12 +191,8 @@ $wgResourceModules += array(
), ),
'styles' => 'special/ext.echo.special.css', 'styles' => 'special/ext.echo.special.css',
'dependencies' => array( 'dependencies' => array(
'ext.echo.base', 'ext.echo.desktop',
'mediawiki.api',
'mediawiki.Uri',
'mediawiki.ui', 'mediawiki.ui',
'mediawiki.jqueryMsg',
'mediawiki.user',
), ),
'messages' => array( 'messages' => array(
'echo-load-more-error', 'echo-load-more-error',

View file

@ -29,7 +29,13 @@ class ApiEchoMarkRead extends ApiBase {
} }
} }
$result = array( 'result' => 'success', 'count' => $notifUser->getFormattedNotificationCount() ); $rawCount = $notifUser->getNotificationCount();
$result = array(
'result' => 'success',
'rawcount' => $rawCount,
'count' => EchoNotificationController::formatNotificationCount( $rawCount ),
);
$this->getResult()->addValue( 'query', $this->getModuleName(), $result ); $this->getResult()->addValue( 'query', $this->getModuleName(), $result );
} }
@ -45,6 +51,7 @@ class ApiEchoMarkRead extends ApiBase {
'token' => array( 'token' => array(
ApiBase::PARAM_REQUIRED => true, ApiBase::PARAM_REQUIRED => true,
), ),
'uselang' => null
); );
} }
@ -53,6 +60,7 @@ class ApiEchoMarkRead extends ApiBase {
'list' => 'A list of notification IDs to mark as read', 'list' => 'A list of notification IDs to mark as read',
'all' => "If set to true, marks all of a user's notifications as read", 'all' => "If set to true, marks all of a user's notifications as read",
'token' => 'edit token', 'token' => 'edit token',
'uselang' => 'the desired language to format the output'
); );
} }

View file

@ -50,7 +50,9 @@ class ApiEchoNotifications extends ApiQueryBase {
} }
if ( in_array( 'count', $prop ) ) { if ( in_array( 'count', $prop ) ) {
$result['count'] = $notifUser->getFormattedNotificationCount(); $rawCount = $notifUser->getNotificationCount();
$result['rawcount'] = $rawCount;
$result['count'] = EchoNotificationController::formatNotificationCount( $rawCount );
} }
if ( in_array( 'index', $prop ) ) { if ( in_array( 'index', $prop ) ) {

View file

@ -0,0 +1,20 @@
( function ( $, mw ) {
'use strict';
// Functions that are only available to echo desktop version
mw.echo.desktop = {
/**
* Append uselang param to API get/post data if applicable
* @param apiData {Object}
*/
appendUseLang: function ( apiData ) {
var curUri = new mw.Uri();
if ( curUri.query.uselang !== undefined ) {
apiData.uselang = curUri.query.uselang;
}
return apiData;
}
};
} )( jQuery, mediaWiki );

View file

@ -4,12 +4,15 @@
mw.echo.overlay = { mw.echo.overlay = {
updateCount: function ( newCount ) { /**
* @param newCount formatted count
* @param rawCount unformatted count
*/
updateCount: function ( newCount, rawCount ) {
var $badge = $( '.mw-echo-notifications-badge' ); var $badge = $( '.mw-echo-notifications-badge' );
$badge.text( newCount ); $badge.text( newCount );
// newCount could be '99+' or another string.
// Checking for number as well just to be paranoid. if ( rawCount !== '0' && rawCount !== 0 ) {
if ( newCount !== '0' && newCount !== 0 ) {
$badge.addClass( 'mw-echo-unread-notifications' ); $badge.addClass( 'mw-echo-unread-notifications' );
} else { } else {
$badge.removeClass( 'mw-echo-unread-notifications' ); $badge.removeClass( 'mw-echo-unread-notifications' );
@ -24,7 +27,6 @@
$prefLink = $( '#pt-preferences a' ), $prefLink = $( '#pt-preferences a' ),
count = 0, count = 0,
apiData, apiData,
curUri = new mw.Uri(),
api = new mw.Api( { ajax: { cache: false } } ); api = new mw.Api( { ajax: { cache: false } } );
// Set notification limit based on height of the window // Set notification limit based on height of the window
@ -44,14 +46,11 @@
'notprop' : 'index|list|count' 'notprop' : 'index|list|count'
}; };
if ( curUri.query.uselang !== undefined ) { api.get( mw.echo.desktop.appendUseLang( apiData ) ).done( function ( result ) {
apiData.uselang = curUri.query.uselang;
}
api.get( apiData ).done( function ( result ) {
var notifications = result.query.notifications, var notifications = result.query.notifications,
unread = [], unread = [],
unreadTotalCount = result.query.notifications.count, unreadTotalCount = result.query.notifications.count,
unreadRawTotalCount = result.query.notifications.rawcount,
$title = $( '<div class="mw-echo-overlay-title"></div>' ), $title = $( '<div class="mw-echo-overlay-title"></div>' ),
$ul = $( '<ul class="mw-echo-notifications"></ul>' ), $ul = $( '<ul class="mw-echo-notifications"></ul>' ),
titleText = '', titleText = '',
@ -60,7 +59,7 @@
$markReadButton; $markReadButton;
if ( unreadTotalCount !== undefined ) { if ( unreadTotalCount !== undefined ) {
mw.echo.overlay.updateCount( unreadTotalCount ); mw.echo.overlay.updateCount( unreadTotalCount, unreadRawTotalCount );
} }
$ul.css( 'max-height', notificationLimit * 95 + 'px' ); $ul.css( 'max-height', notificationLimit * 95 + 'px' );
$.each( notifications.index, function ( index, id ) { $.each( notifications.index, function ( index, id ) {
@ -123,7 +122,7 @@
} ); } );
if ( notifications.index.length > 0 ) { if ( notifications.index.length > 0 ) {
if ( isNaN( unreadTotalCount ) || unreadTotalCount > unread.length ) { if ( unreadRawTotalCount > unread.length ) {
titleText = mw.msg( 'echo-overlay-title-overflow', unread.length, unreadTotalCount ); titleText = mw.msg( 'echo-overlay-title-overflow', unread.length, unreadTotalCount );
overflow = true; overflow = true;
} else { } else {
@ -139,14 +138,14 @@
.text( mw.msg( 'echo-mark-all-as-read' ) ) .text( mw.msg( 'echo-mark-all-as-read' ) )
.click( function ( e ) { .click( function ( e ) {
e.preventDefault(); e.preventDefault();
api.post( { api.post( mw.echo.desktop.appendUseLang( {
'action' : 'echomarkread', 'action' : 'echomarkread',
'all' : true, 'all' : true,
'token': mw.user.tokens.get( 'editToken' ) 'token': mw.user.tokens.get( 'editToken' )
} ).done( function ( result ) { } ) ).done( function ( result ) {
if ( result.query.echomarkread.count !== undefined ) { if ( result.query.echomarkread.count !== undefined ) {
count = result.query.echomarkread.count; count = result.query.echomarkread.count;
mw.echo.overlay.updateCount( count ); mw.echo.overlay.updateCount( count, result.query.echomarkread.rawcount );
// Reset header to 'Notifications' // Reset header to 'Notifications'
$( '#mw-echo-overlay-title-text').msg( 'echo-overlay-title' ); $( '#mw-echo-overlay-title-text').msg( 'echo-overlay-title' );
} }
@ -158,9 +157,7 @@
// The only reason we limit it to the maximum is to prevent expensive // The only reason we limit it to the maximum is to prevent expensive
// database updates. If the count is more than the maximum, it could // database updates. If the count is more than the maximum, it could
// be thousands. // be thousands.
if ( overflow && if ( overflow && unreadRawTotalCount < mw.echo.overlay.configuration['max-notification-count']
!isNaN( unreadTotalCount ) &&
unreadTotalCount < mw.echo.overlay.configuration['max-notification-count']
) { ) {
// Add the 'mark all as read' button to the title area // Add the 'mark all as read' button to the title area
$title.append( $markReadButton ); $title.append( $markReadButton );
@ -239,14 +236,14 @@
// only need to mark as read if there is unread item // only need to mark as read if there is unread item
if ( unread.length > 0 ) { if ( unread.length > 0 ) {
api.post( { api.post( mw.echo.desktop.appendUseLang( {
'action' : 'echomarkread', 'action' : 'echomarkread',
'list' : unread.join( '|' ), 'list' : unread.join( '|' ),
'token': mw.user.tokens.get( 'editToken' ) 'token': mw.user.tokens.get( 'editToken' )
} ).done( function ( result ) { } ) ).done( function ( result ) {
if ( result.query.echomarkread.count !== undefined ) { if ( result.query.echomarkread.count !== undefined ) {
count = result.query.echomarkread.count; count = result.query.echomarkread.count;
mw.echo.overlay.updateCount( count ); mw.echo.overlay.updateCount( count, result.query.echomarkread.rawcount );
} }
} ); } );
} }

View file

@ -58,7 +58,7 @@
* Load more notification records. * Load more notification records.
*/ */
loadMore: function () { loadMore: function () {
var api = new mw.Api( { ajax: { cache: false } } ), curUri = new mw.Uri(), var api = new mw.Api( { ajax: { cache: false } } ),
notifications, data, container, $li, that = this, unread = [], apiData; notifications, data, container, $li, that = this, unread = [], apiData;
apiData = { apiData = {
@ -70,11 +70,7 @@
'notlimit': mw.config.get( 'wgEchoDisplayNum' ) 'notlimit': mw.config.get( 'wgEchoDisplayNum' )
}; };
if ( curUri.query.uselang !== undefined ) { api.get( mw.echo.desktop.appendUseLang( apiData ) ).done( function ( result ) {
apiData.uselang = curUri.query.uselang;
}
api.get( apiData ).done( function ( result ) {
container = $( '#mw-echo-special-container' ); container = $( '#mw-echo-special-container' );
notifications = result.query.notifications; notifications = result.query.notifications;
unread = []; unread = [];
@ -128,16 +124,16 @@
markAsRead: function ( unread ) { markAsRead: function ( unread ) {
var api = new mw.Api(), that = this; var api = new mw.Api(), that = this;
api.post( { api.post( mw.echo.desktop.appendUseLang( {
'action' : 'echomarkread', 'action' : 'echomarkread',
'list' : unread.join( '|' ), 'list' : unread.join( '|' ),
'token': mw.user.tokens.get( 'editToken' ) 'token': mw.user.tokens.get( 'editToken' )
} ).done( function ( result ) { } ) ).done( function ( result ) {
// update the badge if the link is enabled // update the badge if the link is enabled
if ( result.query.echomarkread.count !== undefined && if ( result.query.echomarkread.count !== undefined &&
$( '#pt-notifications').length && typeof mw.echo.overlay === 'object' $( '#pt-notifications').length && typeof mw.echo.overlay === 'object'
) { ) {
mw.echo.overlay.updateCount( result.query.echomarkread.count ); mw.echo.overlay.updateCount( result.query.echomarkread.count, result.query.echomarkread.rawcount );
} }
that.onSuccess(); that.onSuccess();
} ).fail( function () { } ).fail( function () {