mediawiki-extensions-Echo/modules/viewmodel/mw.echo.dm.NotificationGroupItem.js
Moriel Schottlender a4659baec5 Add OOUI widgets for cross-wiki bundled notifications
* Add the ability to use bundled expandable
  notification groups
* Display bundled cross-wiki notifications following
  the design

Bug: T115419
Bug: T115423
Bug: T115422
Change-Id: I8c3eba6d627c3f06d51d74fc9774e3fc2d02915d
2015-12-14 17:22:34 -08:00

184 lines
4.6 KiB
JavaScript

( function ( mw ) {
/**
* Echo notification group item model
*
* @class
* @inherits mw.echo.dm.NotificationItem
* @mixins mw.echo.dm.SortedList
*
* @constructor
* @param {mw.echo.dm.NetworkHandler} networkHandler The network handler
* @param {Object[]} sources An array of objects defining the sources
* of its item's sub-items.
* @param {number} id Notification id,
* @param {Object} [config] Configuration object
* @cfg {boolean} [removeReadNotifications=false] Completely remove notifications that are
* marked as read.
* @cfg {number} [count=0] The number of items this group contains. This is used for both the
* 'expand' label and also to potentially update the badge counters for local bundles.
*/
mw.echo.dm.NotificationGroupItem = function mwEchoDmNotificationGroupItem( networkHandler, sources, id, config ) {
var source, item,
items = [];
config = config || {};
// Parent
mw.echo.dm.NotificationGroupItem.parent.call( this, id, config );
// Mixin constructor
mw.echo.dm.SortedList.call( this );
this.setSortingCallback( function ( a, b ) {
var diff;
// Reverse sorting
diff = Number( b.getTimestamp() ) - Number( a.getTimestamp() );
if ( diff !== 0 ) {
return diff;
}
// Fallback on IDs
return b.getId() - a.getId();
} );
this.aggregate( {
empty: 'groupEmpty'
} );
this.connect( this, {
groupEmpty: 'onGroupEmpty'
} );
this.removeReadNotifications = !!config.removeReadNotifications;
this.sources = sources;
this.networkHandler = networkHandler;
this.notifModels = {};
this.count = config.count || 0;
// Create notification models for each source
for ( source in this.sources ) {
// Add external API handler
this.networkHandler.addApiHandler( source, { url: this.sources[ source ].url }, true );
// Create a notifications model
item = new mw.echo.dm.NotificationsModel(
this.networkHandler,
{
type: this.getType(),
source: source,
external: this.external,
title: this.sources[ source ].title,
removeReadNotifications: this.removeReadNotifications
}
);
items.push( item );
this.notifModels[source] = item;
}
this.addItems( items );
};
/* Inheritance */
OO.inheritClass( mw.echo.dm.NotificationGroupItem, mw.echo.dm.NotificationItem );
OO.mixinClass( mw.echo.dm.NotificationGroupItem, mw.echo.dm.SortedList );
/* Events */
/**
* The group is empty
*
* @event empty
*/
/* Methods */
/**
* Respond to notification model being empty
*
* @param {mw.echo.dm.NotificationModel} notifModel Notification model
*/
mw.echo.dm.NotificationGroupItem.prototype.onGroupEmpty = function ( notifModel ) {
if ( this.removeReadNotifications ) {
// This means the model is now empty. We should remove it as a group completely
this.removeItems( [ notifModel ] );
}
if ( this.isEmpty() ) {
this.emit( 'empty' );
}
};
/**
* Fetch items from each of the sources
*
* @return {jQuery.Promise} Promise that is resolved when all items are fetched
*/
mw.echo.dm.NotificationGroupItem.prototype.fetchAllNotificationsInGroups = function () {
var notifModel,
model = this,
sourceKeys = Object.keys( this.sources );
return this.networkHandler.fetchNotificationGroups( sourceKeys )
.then( function ( promises ) {
var i;
for ( i = 0; i < sourceKeys.length; i++ ) {
notifModel = model.getItemById( sourceKeys[ i ] );
if ( notifModel ) {
notifModel.fetchNotifications( promises[ i ] );
}
}
return promises;
} );
};
/**
* @inheritdoc
*/
mw.echo.dm.NotificationGroupItem.prototype.toggleRead = function ( read ) {
var i,
notifModels = this.getItems();
read = read !== undefined ? read : !this.read;
if ( this.read !== read ) {
// Mark sub items as read
for ( i = 0; i < notifModels.length; i++ ) {
notifModels[ i ].markAllRead();
}
}
// Parent method
mw.echo.dm.NotificationGroupItem.parent.prototype.toggleRead.call( this, read );
};
/**
* @inheritdoc
*/
mw.echo.dm.NotificationGroupItem.prototype.toggleSeen = function ( seen ) {
var i,
notifModels = this.getItems();
seen = seen !== undefined ? seen : !this.seen;
if ( this.seen !== seen ) {
// Mark sub items as seen
for ( i = 0; i < notifModels.length; i++ ) {
notifModels[ i ].updateSeenTime();
}
}
// Parent method
mw.echo.dm.NotificationGroupItem.parent.prototype.toggleSeen.call( this, seen );
};
/**
* Get the anticipated count of items in this group item
*
* @return {number} Anticipated item count
*/
mw.echo.dm.NotificationGroupItem.prototype.getCount = function () {
return this.count;
};
} )( mediaWiki );