mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Echo
synced 2024-11-27 17:20:40 +00:00
Add a mark-all-read button and a settings menu to Special:Notifications
Add a global-wiki 'mark all as read' to the Special:Notifications page. The 'mark all as read' will makr all notifications in the given wiki. The context of the wiki changes when filters are chosen, and so the message of the button changes as well. Bug: T115528 Change-Id: Ibd9dcdf7072d6cbc1a268c18e558e6d0df28f929
This commit is contained in:
parent
c1365be90d
commit
545d4e67ae
|
@ -129,6 +129,7 @@ $wgResourceModules += array(
|
|||
'echo-badge-count',
|
||||
'echo-overlay-link',
|
||||
'echo-mark-all-as-read',
|
||||
'echo-mark-wiki-as-read',
|
||||
'echo-more-info',
|
||||
'echo-feedback',
|
||||
'echo-notification-alert',
|
||||
|
@ -298,6 +299,7 @@ $wgResourceModules += array(
|
|||
'ui/mw.echo.ui.PageFilterWidget.js',
|
||||
'ui/mw.echo.ui.CrossWikiUnreadFilterWidget.js',
|
||||
'ui/mw.echo.ui.NotificationsInboxWidget.js',
|
||||
'ui/mw.echo.ui.SpecialHelpMenuWidget.js',
|
||||
'special/ext.echo.special.js',
|
||||
),
|
||||
'styles' => array(
|
||||
|
@ -308,6 +310,7 @@ $wgResourceModules += array(
|
|||
'styles/mw.echo.ui.PageNotificationsOptionWidget.less',
|
||||
'styles/mw.echo.ui.PageFilterWidget.less',
|
||||
'styles/mw.echo.ui.CrossWikiUnreadFilterWidget.less',
|
||||
'styles/mw.echo.ui.SpecialHelpMenuWidget.less',
|
||||
),
|
||||
'dependencies' => array(
|
||||
'ext.echo.ui',
|
||||
|
@ -323,7 +326,10 @@ $wgResourceModules += array(
|
|||
'echo-specialpage-pagination-range',
|
||||
'echo-specialpage-pagefilters-title',
|
||||
'echo-specialpage-pagefilters-subtitle',
|
||||
'echo-mark-all-as-read',
|
||||
'echo-more-info',
|
||||
'echo-learn-more',
|
||||
'mypreferences',
|
||||
'echo-feedback',
|
||||
'echo-specialpage-section-markread',
|
||||
),
|
||||
|
|
|
@ -219,6 +219,7 @@
|
|||
"echo-overlay-title": "<b>Notifications</b>",
|
||||
"echo-overlay-title-overflow": "<b>{{PLURAL:$1|Notification|Notifications}}</b> (showing $1 of $2 unread)",
|
||||
"echo-mark-all-as-read": "Mark all as read",
|
||||
"echo-mark-wiki-as-read": "Mark all as read in selected wiki: $1",
|
||||
"echo-date-today": "Today",
|
||||
"echo-date-yesterday": "Yesterday",
|
||||
"echo-load-more-error": "An error occurred while fetching more results.",
|
||||
|
|
|
@ -210,6 +210,7 @@
|
|||
"echo-overlay-title": "Title at the top of the notifications overlay. Should include bold tags.\n{{Identical|Notification}}",
|
||||
"echo-overlay-title-overflow": "Title at the top of the notifications overlay when there are additional unread notifications that are not being shown.\n\nParameters:\n* $1 - the number of unread notifications being shown\n* $2 - the total number of unread notifications that exist",
|
||||
"echo-mark-all-as-read": "Text for button that marks all unread notifications as read. Keep this short as possible.\n{{Identical|Mark all as read}}",
|
||||
"echo-mark-wiki-as-read": "Text for button that marks all unread notifications as read in a specific wiki. Keep this short as possible.\n{{Identical|Mark all as read}}\n\nParameters:\n* $1 - The human readable name of the selected wiki",
|
||||
"echo-date-today": "The header text for today's notification section.\n{{Identical|Today}}",
|
||||
"echo-date-yesterday": "The header text for yesterday's notification section.\n{{Identical|Yesterday}}",
|
||||
"echo-load-more-error": "Error message for errors in loading more notifications",
|
||||
|
|
|
@ -249,12 +249,6 @@
|
|||
* for that type in the given source
|
||||
*/
|
||||
mw.echo.api.EchoApi.prototype.markAllRead = function ( source, type ) {
|
||||
// FIXME: This specific method sends an operation
|
||||
// to the API that marks all notifications of the given type as read regardless
|
||||
// of whether they were actually seen by the user.
|
||||
// We should consider removing the use of this method and, instead,
|
||||
// using strictly the 'markItemsRead' by giving the API only the
|
||||
// notifications that are available to the user.
|
||||
return this.network.getApiHandler( source ).markAllRead( type );
|
||||
};
|
||||
|
||||
|
@ -264,11 +258,13 @@
|
|||
*
|
||||
* @param {string} source Notifications source
|
||||
* @param {string} type Notification type
|
||||
* @param {boolean} [localOnly] Fetches only the count of local notifications,
|
||||
* and ignores cross-wiki notifications.
|
||||
* @return {jQuery.Promise} A promise that is resolved with the number of
|
||||
* unread notifications for the given type and source.
|
||||
*/
|
||||
mw.echo.api.EchoApi.prototype.fetchUnreadCount = function ( source, type ) {
|
||||
return this.network.getApiHandler( source ).fetchUnreadCount( type );
|
||||
mw.echo.api.EchoApi.prototype.fetchUnreadCount = function ( source, type, localOnly ) {
|
||||
return this.network.getApiHandler( source ).fetchUnreadCount( type, localOnly );
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -55,12 +55,12 @@
|
|||
* @inheritdoc
|
||||
*/
|
||||
mw.echo.api.LocalAPIHandler.prototype.markAllRead = function ( type ) {
|
||||
var data = {
|
||||
action: 'echomarkread',
|
||||
sections: this.normalizedType[ type ]
|
||||
};
|
||||
type = Array.isArray( type ) ? type : [ type ];
|
||||
|
||||
return this.api.postWithToken( 'csrf', data )
|
||||
return this.api.postWithToken( 'csrf', {
|
||||
action: 'echomarkread',
|
||||
sections: type.join( '|' )
|
||||
} )
|
||||
.then( function ( result ) {
|
||||
return OO.getProp( result.query, 'echomarkread', type, 'rawcount' ) || 0;
|
||||
} );
|
||||
|
@ -84,9 +84,13 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* Fetch the number of unread notifications.
|
||||
*
|
||||
* @param {string} type Notification type, 'alert', 'message' or 'all'
|
||||
* @param {boolean} [ignoreCrossWiki] Ignore cross-wiki notifications when fetching the count.
|
||||
* If set to false (by default) it counts notifications across all wikis.
|
||||
*/
|
||||
mw.echo.api.LocalAPIHandler.prototype.fetchUnreadCount = function ( type ) {
|
||||
mw.echo.api.LocalAPIHandler.prototype.fetchUnreadCount = function ( type, ignoreCrossWiki ) {
|
||||
var normalizedType = this.normalizedType[ type ],
|
||||
apiData = {
|
||||
action: 'query',
|
||||
|
@ -96,10 +100,13 @@
|
|||
notmessageunreadfirst: 1,
|
||||
notlimit: this.limit,
|
||||
notprop: 'count',
|
||||
notcrosswikisummary: 1,
|
||||
uselang: this.userLang
|
||||
};
|
||||
|
||||
if ( !ignoreCrossWiki ) {
|
||||
apiData.notcrosswikisummary = 1;
|
||||
}
|
||||
|
||||
return this.api.get( apiData )
|
||||
.then( function ( result ) {
|
||||
if ( type === 'message' || type === 'alert' ) {
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
filtersModel.setReadState( values[ 0 ] );
|
||||
} else if ( filter === 'sourcePage' ) {
|
||||
filtersModel.setCurrentSourcePage( values[ 0 ], values[ 1 ] );
|
||||
this.manager.getLocalCounter().setSource( filtersModel.getSourcePagesModel().getCurrentSource() );
|
||||
}
|
||||
|
||||
// Reset pagination
|
||||
|
@ -191,6 +192,9 @@
|
|||
// Update the pagination
|
||||
pagination.setNextPageContinue( data.continue );
|
||||
|
||||
// Update the local counter
|
||||
controller.manager.getLocalCounter().update();
|
||||
|
||||
return dateItemIds;
|
||||
} );
|
||||
};
|
||||
|
@ -374,6 +378,49 @@
|
|||
return this.markItemsRead( itemIds, model.getName(), isRead );
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark all notifications of a certain source as read, even those that
|
||||
* are not currently displayed.
|
||||
*
|
||||
* @param {string} [source] Notification source. If not given, the currently
|
||||
* selected source is used.
|
||||
* @return {jQuery.Promise} A promise that is resolved after
|
||||
* all notifications for the given source were marked as read
|
||||
*/
|
||||
mw.echo.Controller.prototype.markAllRead = function ( source ) {
|
||||
var model,
|
||||
controller = this,
|
||||
itemIds = [],
|
||||
readState = this.manager.getFiltersModel().getReadState(),
|
||||
localCounter = this.manager.getLocalCounter();
|
||||
|
||||
source = source || this.manager.getFiltersModel().getSourcePagesModel().getCurrentSource();
|
||||
|
||||
this.manager.getNotificationsBySource( source ).forEach( function ( notification ) {
|
||||
if ( !notification.isRead() ) {
|
||||
itemIds = itemIds.concat( notification.getAllIds() );
|
||||
notification.toggleRead( true );
|
||||
|
||||
if ( readState === 'unread' ) {
|
||||
// Remove the items if we are in 'unread' filter state
|
||||
model = controller.manager.getNotificationModel( notification.getModelName() );
|
||||
model.discardItems( notification );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
// Update pagination count
|
||||
this.manager.updateCurrentPageItemCount();
|
||||
|
||||
localCounter.estimateChange( -itemIds.length );
|
||||
return this.api.markAllRead(
|
||||
source,
|
||||
this.getTypes()
|
||||
)
|
||||
.then( this.refreshUnreadCount.bind( this ) )
|
||||
.then( localCounter.update.bind( localCounter, true ) );
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark all local notifications as read
|
||||
*
|
||||
|
@ -381,16 +428,35 @@
|
|||
* local notifications have been marked as read.
|
||||
*/
|
||||
mw.echo.Controller.prototype.markLocalNotificationsRead = function () {
|
||||
var itemIds = [];
|
||||
var modelName, model,
|
||||
itemIds = [],
|
||||
readState = this.manager.getFiltersModel().getReadState(),
|
||||
modelItems = {};
|
||||
|
||||
this.manager.getLocalNotifications().forEach( function ( notification ) {
|
||||
if ( !notification.isRead() ) {
|
||||
itemIds = itemIds.concat( notification.getAllIds() );
|
||||
notification.toggleRead( true );
|
||||
|
||||
modelName = notification.getModelName();
|
||||
modelItems[ modelName ] = modelItems[ modelName ] || [];
|
||||
modelItems[ modelName ].push( notification );
|
||||
}
|
||||
} );
|
||||
|
||||
// Remove the items if we are in 'unread' filter state
|
||||
if ( readState === 'unread' ) {
|
||||
for ( modelName in modelItems ) {
|
||||
model = this.manager.getNotificationModel( modelName );
|
||||
model.discardItems( modelItems[ modelName ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Update pagination count
|
||||
this.manager.updateCurrentPageItemCount();
|
||||
|
||||
this.manager.getUnreadCounter().estimateChange( -itemIds.length );
|
||||
this.manager.getLocalCounter().estimateChange( -itemIds.length );
|
||||
return this.api.markItemsRead( itemIds, 'local', true ).then( this.refreshUnreadCount.bind( this ) );
|
||||
};
|
||||
|
||||
|
@ -498,6 +564,11 @@
|
|||
this.manager.updateCurrentPageItemCount();
|
||||
|
||||
this.manager.getUnreadCounter().estimateChange( isRead ? -allIds.length : allIds.length );
|
||||
if ( modelName !== 'xwiki' ) {
|
||||
// For the local counter, we should only estimate the change if the items
|
||||
// are not cross-wiki
|
||||
this.manager.getLocalCounter().estimateChange( isRead ? -allIds.length : allIds.length );
|
||||
}
|
||||
|
||||
return this.api.markItemsRead( allIds, model.getSource(), isRead ).then( this.refreshUnreadCount.bind( this ) );
|
||||
};
|
||||
|
@ -526,6 +597,8 @@
|
|||
sourceModel = xwikiModel.getList().getGroupByName( source );
|
||||
notifs = sourceModel.findByIds( itemIds );
|
||||
sourceModel.discardItems( notifs );
|
||||
// Update pagination count
|
||||
this.manager.updateCurrentPageItemCount();
|
||||
|
||||
return this.api.markItemsRead( itemIds, source, true )
|
||||
.then( this.refreshUnreadCount.bind( this ) );
|
||||
|
|
|
@ -117,6 +117,20 @@
|
|||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all items in the cross wiki notification bundle
|
||||
*
|
||||
* @return {mw.echo.dm.NotificationItem[]} All items across all sources
|
||||
*/
|
||||
mw.echo.dm.CrossWikiNotificationItem.prototype.getItems = function () {
|
||||
var notifications = [];
|
||||
this.list.getItems().forEach( function ( sourceList ) {
|
||||
notifications = notifications.concat( sourceList.getItems() );
|
||||
} );
|
||||
|
||||
return notifications;
|
||||
};
|
||||
|
||||
/**
|
||||
* This item is a group.
|
||||
* This method is required for all models that are managed by the
|
||||
|
|
|
@ -50,6 +50,9 @@
|
|||
|
||||
// Events
|
||||
this.seenTimeModel.connect( this, { update: 'onSeenTimeUpdate' } );
|
||||
|
||||
this.localCounter = config.localCounter || new mw.echo.dm.UnreadNotificationCounter();
|
||||
this.localCounter.connect( this, { countChange: [ 'emit', 'localCountChange' ] } );
|
||||
};
|
||||
|
||||
OO.initClass( mw.echo.dm.ModelManager );
|
||||
|
@ -93,6 +96,12 @@
|
|||
* A specific item inside a notifications model has been updated
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event localCountChange
|
||||
*
|
||||
* There was a change in the count of local unread notifications
|
||||
*/
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
|
@ -161,14 +170,17 @@
|
|||
this.emit( 'update', this.getAllNotificationModels() );
|
||||
};
|
||||
|
||||
mw.echo.dm.ModelManager.prototype.onModelItemUpdate = function ( modelId, item ) {
|
||||
var model = this.getNotificationModel( modelId );
|
||||
/**
|
||||
* Respond to model update event
|
||||
*
|
||||
* @param {string} modelName Model name
|
||||
* @param {mw.echo.dm.notificationItem} item Notification item
|
||||
* @fires modelUpdate
|
||||
*/
|
||||
mw.echo.dm.ModelManager.prototype.onModelItemUpdate = function ( modelName, item ) {
|
||||
this.checkLocalUnreadTalk();
|
||||
|
||||
if ( model.getSource() === 'local' ) {
|
||||
this.checkLocalUnreadTalk();
|
||||
}
|
||||
|
||||
this.emit( 'modelItemUpdate', modelId, item );
|
||||
this.emit( 'modelItemUpdate', modelName, item );
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -195,6 +207,7 @@
|
|||
|
||||
return count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a notification model.
|
||||
*
|
||||
|
@ -381,6 +394,15 @@
|
|||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the local counter
|
||||
*
|
||||
* @return {mw.echo.dm.UnreadNotificationCounter} Local counter
|
||||
*/
|
||||
mw.echo.dm.ModelManager.prototype.getLocalCounter = function () {
|
||||
return this.localCounter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all local notifications
|
||||
*
|
||||
|
@ -438,6 +460,7 @@
|
|||
*/
|
||||
mw.echo.dm.ModelManager.prototype.getSeenTimeModel = function () {
|
||||
return this.seenTimeModel;
|
||||
|
||||
};
|
||||
|
||||
} )( mediaWiki, jQuery );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
( function ( mw ) {
|
||||
( function ( mw, $ ) {
|
||||
/**
|
||||
* Echo notification UnreadNotificationCounter model
|
||||
*
|
||||
|
@ -9,17 +9,26 @@
|
|||
* @param {Object} api An instance of EchoAPI.
|
||||
* @param {string} type The notification type 'message', 'alert', or 'all'.
|
||||
* @param {number} max Maximum number supported. Above this number there is no precision, we only know it is 'more than max'.
|
||||
* @param {Object} config Configuration object
|
||||
* @cfg {boolean} [localOnly=false] The update only takes into account
|
||||
* local notifications and ignores the number of cross-wiki notifications.
|
||||
* @cfg {string} [source='local'] The source for this counter. Specifically important if the counter
|
||||
* is set to be counting only local notifications
|
||||
*/
|
||||
mw.echo.dm.UnreadNotificationCounter = function mwEchoDmUnreadNotificationCounter( api, type, max ) {
|
||||
mw.echo.dm.UnreadNotificationCounter = function mwEchoDmUnreadNotificationCounter( api, type, max, config ) {
|
||||
config = config || {};
|
||||
|
||||
// Mixin constructor
|
||||
OO.EventEmitter.call( this );
|
||||
|
||||
this.api = api;
|
||||
this.type = type;
|
||||
this.max = max;
|
||||
this.prioritizer = new mw.echo.api.PromisePrioritizer();
|
||||
|
||||
this.count = 0;
|
||||
this.source = 'local';
|
||||
this.localOnly = config.localOnly === undefined ? false : !!config.localOnly;
|
||||
this.source = config.source || 'local';
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
@ -81,12 +90,35 @@
|
|||
|
||||
/**
|
||||
* Request that this counter update itself from the API
|
||||
*
|
||||
* @return {jQuery.Promise} Promise that is resolved when the actual unread
|
||||
* count is fetched, with the actual unread notification count.
|
||||
*/
|
||||
mw.echo.dm.UnreadNotificationCounter.prototype.update = function () {
|
||||
var model = this;
|
||||
this.api.fetchUnreadCount( this.source, this.type ).then( function ( actualCount ) {
|
||||
|
||||
if ( !this.api ) {
|
||||
return $.Deferred().reject();
|
||||
}
|
||||
|
||||
return this.prioritizer.prioritize( this.api.fetchUnreadCount(
|
||||
this.source,
|
||||
this.type,
|
||||
this.localOnly
|
||||
) ).then( function ( actualCount ) {
|
||||
model.setCount( actualCount, false );
|
||||
|
||||
return actualCount;
|
||||
} );
|
||||
};
|
||||
|
||||
}( mediaWiki ) );
|
||||
/**
|
||||
* Set the source for this counter
|
||||
*
|
||||
* @param {string} source Source name
|
||||
*/
|
||||
mw.echo.dm.UnreadNotificationCounter.prototype.setSource = function ( source ) {
|
||||
this.source = source;
|
||||
};
|
||||
|
||||
}( mediaWiki, jQuery ) );
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.client-js #mw-indicator-mw-helplink {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Custom header styling for Vector and Monobook skins */
|
||||
.mw-special-Notifications.skin-vector #firstHeading,
|
||||
.mw-special-Notifications.skin-monobook #firstHeading {
|
||||
|
|
|
@ -4,30 +4,47 @@
|
|||
* Echo Special:Notifications page initialization
|
||||
*/
|
||||
$( document ).ready( function () {
|
||||
var limitNotifications = 50,
|
||||
var prefLink, specialPageContainer,
|
||||
limitNotifications = 50,
|
||||
$content = $( '#mw-content-text' ),
|
||||
echoApi = new mw.echo.api.EchoApi( { limit: limitNotifications, bundle: false } ),
|
||||
unreadCounter = new mw.echo.dm.UnreadNotificationCounter( echoApi, [ 'message', 'alert' ], limitNotifications ),
|
||||
modelManager = new mw.echo.dm.ModelManager( unreadCounter, {
|
||||
type: [ 'message', 'alert' ],
|
||||
itemsPerPage: limitNotifications
|
||||
itemsPerPage: limitNotifications,
|
||||
localCounter: new mw.echo.dm.UnreadNotificationCounter(
|
||||
echoApi,
|
||||
[ 'message', 'alert' ],
|
||||
limitNotifications,
|
||||
{
|
||||
localOnly: true,
|
||||
source: 'local'
|
||||
}
|
||||
)
|
||||
} ),
|
||||
controller = new mw.echo.Controller(
|
||||
echoApi,
|
||||
modelManager
|
||||
),
|
||||
specialPageContainer = new mw.echo.ui.NotificationsInboxWidget(
|
||||
controller,
|
||||
modelManager,
|
||||
{
|
||||
limit: limitNotifications,
|
||||
$overlay: mw.echo.ui.$overlay
|
||||
}
|
||||
);
|
||||
|
||||
prefLink = new mw.Uri( $( '#pt-preferences a' ).prop( 'href' ) );
|
||||
prefLink.fragment = 'mw-prefsection-echo';
|
||||
|
||||
specialPageContainer = new mw.echo.ui.NotificationsInboxWidget(
|
||||
controller,
|
||||
modelManager,
|
||||
{
|
||||
limit: limitNotifications,
|
||||
$overlay: mw.echo.ui.$overlay,
|
||||
prefLink: prefLink.toString(),
|
||||
helpLink: $( '#mw-indicator-mw-helplink a' ).prop( 'href' )
|
||||
}
|
||||
);
|
||||
|
||||
// Overlay
|
||||
$( 'body' ).append( mw.echo.ui.$overlay );
|
||||
|
||||
// Notifications
|
||||
$content.empty().append( specialPageContainer.$element );
|
||||
} );
|
||||
} )( jQuery, mediaWiki );
|
||||
|
|
|
@ -39,6 +39,10 @@
|
|||
margin-right: auto;
|
||||
margin-top: 3 * @specialpage-separation-unit;
|
||||
}
|
||||
|
||||
&-settings {
|
||||
padding-left: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
41
modules/styles/mw.echo.ui.SpecialHelpMenuWidget.less
Normal file
41
modules/styles/mw.echo.ui.SpecialHelpMenuWidget.less
Normal file
|
@ -0,0 +1,41 @@
|
|||
@import '../echo.variables';
|
||||
|
||||
.mw-echo-ui-specialHelpMenuWidget {
|
||||
.oo-ui-popupWidget-body {
|
||||
// Override clippable inline rules
|
||||
overflow-y: hidden !important;
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
&-markAllRead-label {
|
||||
&-title {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&-subtitle {
|
||||
display: block;
|
||||
color: @grey-light;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
&-menu {
|
||||
.oo-ui-buttonWidget {
|
||||
display: block;
|
||||
padding: 0.5em;
|
||||
margin-right: 0;
|
||||
|
||||
.oo-ui-labelElement-label {
|
||||
white-space: normal;
|
||||
// Width of the popup (300px) minus the
|
||||
// width of the icon (1.875em) minus the
|
||||
// padding of the button (0.5em * 2)
|
||||
width: ~'calc(300px - 1.875em - 1em)';
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #DDDDDD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,6 +58,16 @@
|
|||
}
|
||||
);
|
||||
|
||||
// Settings menu
|
||||
this.settingsMenu = new mw.echo.ui.SpecialHelpMenuWidget(
|
||||
this.manager,
|
||||
{
|
||||
framed: true,
|
||||
helpLink: config.helpLink,
|
||||
prefLink: config.prefLink
|
||||
}
|
||||
);
|
||||
|
||||
// Filter by read state
|
||||
this.readStateSelectWidget = new mw.echo.ui.ReadStateButtonSelectWidget();
|
||||
|
||||
|
@ -70,11 +80,15 @@
|
|||
// Events
|
||||
this.readStateSelectWidget.connect( this, { filter: 'onReadStateFilter' } );
|
||||
this.xwikiUnreadWidget.connect( this, { filter: 'onSourcePageFilter' } );
|
||||
this.manager.connect( this, { modelItemUpdate: 'onManagerModelItemUpdate' } );
|
||||
this.manager.connect( this, {
|
||||
modelItemUpdate: 'updatePaginationLabels',
|
||||
localCountChange: 'updatePaginationLabels'
|
||||
} );
|
||||
this.manager.getFiltersModel().connect( this, { update: 'updateReadStateSelectWidget' } );
|
||||
this.manager.getPaginationModel().connect( this, { update: 'onPaginationModelUpdate' } );
|
||||
this.manager.getPaginationModel().connect( this, { update: 'updatePaginationLabels' } );
|
||||
this.topPaginationWidget.connect( this, { change: 'populateNotifications' } );
|
||||
this.bottomPaginationWidget.connect( this, { change: 'populateNotifications' } );
|
||||
this.settingsMenu.connect( this, { markAllRead: 'onSettingsMarkAllRead' } );
|
||||
|
||||
this.topPaginationWidget.setDisabled( true );
|
||||
this.bottomPaginationWidget.setDisabled( true );
|
||||
|
@ -102,7 +116,11 @@
|
|||
$( '<div>' )
|
||||
.addClass( 'mw-echo-ui-notificationsInboxWidget-main-toolbar-pagination' )
|
||||
.addClass( 'mw-echo-ui-notificationsInboxWidget-cell' )
|
||||
.append( this.topPaginationWidget.$element )
|
||||
.append( this.topPaginationWidget.$element ),
|
||||
$( '<div>' )
|
||||
.addClass( 'mw-echo-ui-notificationsInboxWidget-main-toolbar-settings' )
|
||||
.addClass( 'mw-echo-ui-notificationsInboxWidget-cell' )
|
||||
.append( this.settingsMenu.$element )
|
||||
)
|
||||
),
|
||||
this.noticeMessageWidget.$element,
|
||||
|
@ -157,21 +175,24 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* Respond to pagination model update event
|
||||
* Update pagination messages
|
||||
*/
|
||||
mw.echo.ui.NotificationsInboxWidget.prototype.onPaginationModelUpdate = function () {
|
||||
mw.echo.ui.NotificationsInboxWidget.prototype.updatePaginationLabels = function () {
|
||||
this.resetMessageLabel();
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to a change in model item
|
||||
*/
|
||||
mw.echo.ui.NotificationsInboxWidget.prototype.onManagerModelItemUpdate = function () {
|
||||
// Update the pagination label
|
||||
this.topPaginationWidget.updateLabel();
|
||||
this.bottomPaginationWidget.updateLabel();
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to mark all read for selected wiki
|
||||
*/
|
||||
mw.echo.ui.NotificationsInboxWidget.prototype.onSettingsMarkAllRead = function () {
|
||||
this.pushPending();
|
||||
this.controller.markAllRead()
|
||||
.always( this.popPending.bind( this ) );
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to unread page filter
|
||||
*
|
||||
|
|
139
modules/ui/mw.echo.ui.SpecialHelpMenuWidget.js
Normal file
139
modules/ui/mw.echo.ui.SpecialHelpMenuWidget.js
Normal file
|
@ -0,0 +1,139 @@
|
|||
( function ( $, mw ) {
|
||||
/**
|
||||
* Widget for the settings menu in the Special:Notifications page
|
||||
*
|
||||
* @param {mw.echo.dm.ModelManager} manager Model manager
|
||||
* @param {Object} config Configuration object
|
||||
*/
|
||||
mw.echo.ui.SpecialHelpMenuWidget = function MwEchoUiSpecialHelpMenuWidget( manager, config ) {
|
||||
var $menu = $( '<div>' )
|
||||
.addClass( 'mw-echo-ui-specialHelpMenuWidget-menu' );
|
||||
|
||||
config = config || {};
|
||||
|
||||
// Parent constructor
|
||||
mw.echo.ui.SpecialHelpMenuWidget.parent.call( this, $.extend( {
|
||||
icon: 'advanced',
|
||||
popup: {
|
||||
$content: $menu,
|
||||
width: 300
|
||||
}
|
||||
}, config ) );
|
||||
|
||||
// Mixin constructors
|
||||
OO.ui.mixin.GroupWidget.call( this, $.extend( {}, config, { $group: $menu } ) );
|
||||
OO.ui.mixin.PendingElement.call( this, config );
|
||||
|
||||
this.manager = manager;
|
||||
|
||||
this.markAllReadButton = new OO.ui.ButtonWidget( {
|
||||
framed: false,
|
||||
icon: 'doubleCheck',
|
||||
label: this.getMarkAllReadButtonLabel()
|
||||
} );
|
||||
this.setPendingElement( this.$element );
|
||||
this.markAllReadButton.toggle( false );
|
||||
|
||||
this.addItems( [
|
||||
this.markAllReadButton,
|
||||
// Preferences link
|
||||
new OO.ui.ButtonWidget( {
|
||||
framed: false,
|
||||
icon: 'advanced',
|
||||
label: mw.msg( 'mypreferences' ),
|
||||
href: config.prefLink
|
||||
} ),
|
||||
// Help link
|
||||
new OO.ui.ButtonWidget( {
|
||||
framed: false,
|
||||
icon: 'help',
|
||||
label: mw.msg( 'echo-learn-more' ),
|
||||
href: config.helpLink
|
||||
} )
|
||||
] );
|
||||
|
||||
// Events
|
||||
this.markAllReadButton.connect( this, { click: 'onMarkAllreadButtonClick' } );
|
||||
this.manager.connect( this, {
|
||||
localCountChange: 'onLocalCountChange'
|
||||
} );
|
||||
this.manager.getFiltersModel().getSourcePagesModel().connect( this, { update: 'onSourcePageUpdate' } );
|
||||
|
||||
this.$element
|
||||
.addClass( 'mw-echo-ui-specialHelpMenuWidget' );
|
||||
};
|
||||
|
||||
/* Initialization */
|
||||
|
||||
OO.inheritClass( mw.echo.ui.SpecialHelpMenuWidget, OO.ui.PopupButtonWidget );
|
||||
OO.mixinClass( mw.echo.ui.SpecialHelpMenuWidget, OO.ui.mixin.GroupElement );
|
||||
OO.mixinClass( mw.echo.ui.SpecialHelpMenuWidget, OO.ui.mixin.PendingElement );
|
||||
|
||||
/* Events */
|
||||
|
||||
/**
|
||||
* @event markAllRead
|
||||
*
|
||||
* Mark all notifications as read in the selected wiki
|
||||
*/
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
* Respond to source page change
|
||||
*/
|
||||
mw.echo.ui.SpecialHelpMenuWidget.prototype.onSourcePageUpdate = function () {
|
||||
this.markAllReadButton.setLabel( this.getMarkAllReadButtonLabel() );
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to local counter update event
|
||||
*/
|
||||
mw.echo.ui.SpecialHelpMenuWidget.prototype.onLocalCountChange = function ( count ) {
|
||||
this.markAllReadButton.toggle( count > 0 );
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to mark all read button click
|
||||
*/
|
||||
mw.echo.ui.SpecialHelpMenuWidget.prototype.onMarkAllreadButtonClick = function () {
|
||||
this.popup.toggle( false );
|
||||
this.emit( 'markAllRead' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the button label
|
||||
*
|
||||
* @return {string} Mark all read button label
|
||||
*/
|
||||
mw.echo.ui.SpecialHelpMenuWidget.prototype.getMarkAllReadButtonLabel = function () {
|
||||
var pageModel = this.manager.getFiltersModel().getSourcePagesModel(),
|
||||
source = pageModel.getCurrentSource(),
|
||||
sourceTitle = pageModel.getSourceTitle( source );
|
||||
|
||||
return sourceTitle ?
|
||||
mw.msg( 'echo-mark-wiki-as-read', sourceTitle ) :
|
||||
mw.msg( 'echo-mark-all-as-read' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend the pushPending method to disable the mark all read button
|
||||
*/
|
||||
mw.echo.ui.SpecialHelpMenuWidget.prototype.pushPending = function () {
|
||||
this.markAllReadButton.setDisabled( true );
|
||||
|
||||
// Mixin method
|
||||
OO.ui.mixin.PendingElement.prototype.pushPending.call( this );
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend the popPending method to enable the mark all read button
|
||||
*/
|
||||
mw.echo.ui.SpecialHelpMenuWidget.prototype.popPending = function () {
|
||||
this.markAllReadButton.setDisabled( false );
|
||||
|
||||
// Mixin method
|
||||
OO.ui.mixin.PendingElement.prototype.popPending.call( this );
|
||||
};
|
||||
} )( jQuery, mediaWiki );
|
Loading…
Reference in a new issue