mediawiki-extensions-Echo/modules/model/mw.echo.dm.ModelManager.js
Stephane Bisson f8a8d392d6 Expandable bundle
Support bundles being expandable
to show their sub-notifications.

Bug: T114356
Change-Id: I1507cae360f45cc87f2d60e966b4d047abfa202d
2016-06-28 15:37:54 -04:00

359 lines
9.2 KiB
JavaScript

( function ( mw ) {
/**
* A container that manages all models that are involved in creating
* the notification list. There are currently two types of models:
* * mw.echo.dm.SortedList - This currently includes the local model
* or any model that has individual messages.
* * mw.echo.dm.CrossWikiNotificationItem - This is a model for the
* cross wiki notification, which acts as an item but itself contains
* a list.
*
* All notification models that are managed by the manager must implement the
* following methods:
* * getName - This should retrieve the model's name for the manager to fetch
* * isGroup - This should be true for xwiki model and local bundles
* * hasUnseen - This should iterate in the model's items and check whether
* there are any unseen notifications within them.
* * getCount - Get a total count of available notifications currently in the model
*
* @class
* @mixins OO.EventEmitter
*
* @constructor
* @param {mw.echo.dm.UnreadNotificationCounter} counter Unread counter
* @param {Object} [config] Configuration object
* @cfg {string|string[]} [type="message"] The type of the notifications in
* the models that this manager handles.
*/
mw.echo.dm.ModelManager = function MwEchoDmModelManager( counter, config ) {
config = config || {};
// Mixin constructor
OO.EventEmitter.call( this );
this.counter = counter;
// Keep types in an array
this.types = config.type || 'message';
this.types = Array.isArray( this.types ) ?
config.type : [ this.types ];
this.notificationModels = {};
this.paginationModel = new mw.echo.dm.PaginationModel();
this.filtersModel = new mw.echo.dm.FiltersModel( {
selectedSource: mw.config.get( 'wgDBname' )
} );
// Properties
this.seenTime = mw.config.get( 'wgEchoSeenTime' ) || {};
};
OO.initClass( mw.echo.dm.ModelManager );
OO.mixinClass( mw.echo.dm.ModelManager, OO.EventEmitter );
/* Events */
/**
* @event update
* @param {Object[]} Current available notifications
*
* The model has been rebuilt or has been updated
*/
/**
* @event remove
* @param {string} Removed model
*
* A model has been removed
*/
/**
* @event seen
*
* All local notifications are seen
*/
/**
* @event allTalkRead
*
* There are no more local talk page notifications
*/
/* Methods */
/**
* Get the notifications
*
* @return {Object} Object of notification models and their symbolic names
*/
mw.echo.dm.ModelManager.prototype.getAllNotificationModels = function () {
return this.notificationModels;
};
/**
* Set the models in the manager.
*
* @param {Object} modelDefinitions An object defining the models
* The format for the definition object is:
* {
* 'modelId': {mw.echo.dm.SortedList},
* ...
* }
*/
mw.echo.dm.ModelManager.prototype.setNotificationModels = function ( modelDefinitions ) {
var modelId,
localModel;
this.resetNotificationModels();
for ( modelId in modelDefinitions ) {
this.notificationModels[ modelId ] = modelDefinitions[ modelId ];
}
localModel = this.getNotificationModel( 'local' );
if ( localModel ) {
localModel.aggregate( { update: 'itemUpdate' } );
localModel.connect( this, { itemUpdate: 'checkLocalUnreadTalk' } );
}
this.emit( 'update', this.getAllNotificationModels() );
};
/**
* Go over all the notification models and return the total number of
* available notifications.
*
* @return {number} A count of all notifications
*/
mw.echo.dm.ModelManager.prototype.getAllNotificationCount = function () {
var model,
count = 0,
models = this.getAllNotificationModels();
for ( model in models ) {
count += models[ model ].getCount();
}
return count;
};
/**
* Get a notification model.
*
* @param {string} modelName Unique model name
* @return {mw.echo.dm.SortedList} Notifications model
*/
mw.echo.dm.ModelManager.prototype.getNotificationModel = function ( modelName ) {
return this.notificationModels[ modelName ];
};
/**
* Get the pagination model
*
* @return {mw.echo.dm.PaginationModel} Pagination model
*/
mw.echo.dm.ModelManager.prototype.getPaginationModel = function () {
return this.paginationModel;
};
/**
* Get the filters model
*
* @return {mw.echo.dm.FiltersModel} Filters model
*/
mw.echo.dm.ModelManager.prototype.getFiltersModel = function () {
return this.filtersModel;
};
/**
* Remove a model from the manager
*
* @param {string} modelName Symbolic name of the model
* @fires remove
*/
mw.echo.dm.ModelManager.prototype.removeNotificationModel = function ( modelName ) {
delete this.notificationModels[ modelName ];
this.emit( 'remove', modelName );
};
/**
* Reset all models
*
* @private
*/
mw.echo.dm.ModelManager.prototype.resetNotificationModels = function () {
var model;
for ( model in this.notificationModels ) {
if ( this.notificationModels.hasOwnProperty( model ) ) {
this.notificationModels[ model ].disconnect( this );
delete this.notificationModels[ model ];
}
}
};
/**
* Get the unread notification counter
*
* @return {mw.echo.dm.UnreadNotificationCounter} Unread notification counter
*/
mw.echo.dm.ModelManager.prototype.getUnreadCounter = function () {
return this.counter;
};
/**
* Check if the local model has any unread notifications.
*
* @return {boolean} Local model has unread notifications.
*/
mw.echo.dm.ModelManager.prototype.hasLocalUnread = function () {
var isUnread = function ( item ) {
return !item.isRead();
};
return this.getLocalNotifications().some( isUnread );
};
/**
* Check whether there are talk notifications, and emit an event
* in case there aren't any left.
*
* @fires allTalkRead
*/
mw.echo.dm.ModelManager.prototype.checkLocalUnreadTalk = function () {
if ( !this.hasLocalUnreadTalk() ) {
this.emit( 'allTalkRead' );
}
};
/**
* Check if the local model has any unread talk page notifications.
*
* @return {boolean} Local model has unread talk page notifications.
*/
mw.echo.dm.ModelManager.prototype.hasLocalUnreadTalk = function () {
var isUnreadUserTalk = function ( item ) {
return !item.isRead() && item.getCategory() === 'edit-user-talk';
};
return this.getLocalNotifications().some( isUnreadUserTalk );
};
/**
* Check if a model has any unseen notifications.
*
* @param {string} modelId Model ID
* @return {boolean} The given model has unseen notifications.
*/
mw.echo.dm.ModelManager.prototype.hasUnseenInModel = function ( modelId ) {
var model = this.getNotificationModel( modelId || 'local' );
return model && model.hasUnseen();
};
/**
* Check if there are unseen notifications in any of the models
*
* @return {boolean} Local model has unseen notifications.
*/
mw.echo.dm.ModelManager.prototype.hasUnseenInAnyModel = function () {
var model,
models = this.getAllNotificationModels();
for ( model in models ) {
if ( models[ model ].hasUnseen() ) {
return true;
}
}
return false;
};
/**
* Update the local version of seenTime object.
*
* @private
* @param {string|string[]} type Type of notifications; could be a single type
* or an array of types.
* @param {string} time Seen time
*/
mw.echo.dm.ModelManager.prototype.updateSeenTimeObject = function ( type, time ) {
var i,
types = Array.isArray( type ) ? type : [ type ];
for ( i = 0; i < types.length; i++ ) {
if ( this.seenTime.hasOwnProperty( types[ i ] ) ) {
this.seenTime[ types[ i ] ] = time;
}
}
};
/**
* Set items in the local model as seen
*
* @private
*/
mw.echo.dm.ModelManager.prototype.setLocalModelItemsSeen = function () {
this.getLocalNotifications().forEach( function ( item ) {
item.toggleSeen( true );
} );
this.emit( 'seen' );
};
/**
* Get the system seen time
*
* @param {string|string[]} [type] Notification types
* @return {string} Mediawiki seen timestamp in Mediawiki timestamp format
*/
mw.echo.dm.ModelManager.prototype.getSeenTime = function ( type ) {
var types = type || this.getTypes();
types = Array.isArray( types ) ? types : [ types ];
// If the type that is set is an array [ 'alert', 'message' ]
// then the seen time will be the same to both, and we can
// return the value of the arbitrary first one.
return this.seenTime[ types[ 0 ] ];
};
/**
* Get the array of model types
*
* @return {string[]} Model types
*/
mw.echo.dm.ModelManager.prototype.getTypes = function () {
return this.types;
};
/**
* Get the model types string; 'message', 'alert', or 'all'
*
* @return {string} Model types
*/
mw.echo.dm.ModelManager.prototype.getTypeString = function () {
return (
this.types.length === 1 ?
this.types[ 0 ] :
'all'
);
};
/**
* Get all local notifications
*
* @return {mw.echo.dm.NotificationItem[]} all local notifications
*/
mw.echo.dm.ModelManager.prototype.getLocalNotifications = function () {
var notifications = [],
manager = this;
Object.keys( this.getAllNotificationModels() ).forEach( function ( modelName ) {
var model = manager.getNotificationModel( modelName );
if ( !model.isForeign() ) {
notifications = notifications.concat( model.getItems() );
}
} );
return notifications;
};
} )( mediaWiki, jQuery );