( function () {
/**
* Bundle notification item widget.
* This widget is expandable and displays
* inner notifications that constitute the bundle.
*
* @class
* @extends mw.echo.ui.NotificationItemWidget
*
* @constructor
* @param {mw.echo.Controller} controller Echo notifications controller
* @param {mw.echo.dm.BundleNotificationItem} model Notification group model
* @param {Object} [config] Configuration object
* @cfg {boolean} [animateSorting=false] Animate the sorting of items
*/
mw.echo.ui.BundleNotificationItemWidget = function MwEchoUiBundleNotificationItemWidget( controller, model, config ) {
config = config || {};
// Parent constructor
mw.echo.ui.BundleNotificationItemWidget.super.call( this, controller, model, config );
this.toggleMarkAsReadButtons( true );
this.listWidget = new mw.echo.ui.SortedListWidget(
// Sorting callback
function ( a, b ) {
// Reverse sorting
if ( b.getTimestamp() < a.getTimestamp() ) {
return -1;
} else if ( b.getTimestamp() > a.getTimestamp() ) {
return 1;
}
// Fallback on IDs
return b.getId() - a.getId();
},
// Config
{
classes: [ 'mw-echo-ui-bundleNotificationItemWidget-group' ],
timestamp: this.getTimestamp(),
$overlay: this.$overlay,
animated: !!config.animateSorting
}
);
this.listWidget.$element
// We have to manually set the display to 'none' here because
// otherwise the 'slideUp' and 'slideDown' jQuery effects don't
// work
.css( 'display', 'none' );
// Prevent clicks on the list padding area from activating the primary link
this.listWidget.$element.on( 'click', function ( e ) {
if ( e.target.closest( 'a' ) === this.$element[ 0 ] ) {
e.preventDefault();
}
}.bind( this ) );
// Initialize closed
this.expanded = false;
// Add "expand" button
this.toggleExpandButton = new OO.ui.ButtonOptionWidget( {
icon: 'expand',
framed: false,
classes: [ 'mw-echo-ui-notificationItemWidget-content-actions-button' ]
} );
this.updateExpandButton();
this.actionsButtonSelectWidget.addItems( [ this.toggleExpandButton ], 0 );
// Events
this.toggleExpandButton.connect( this, { click: 'expand' } );
if ( !this.model.getPrimaryUrl() ) {
// If there's no primary link, make sure a click
// triggers the 'expand' action
this.$content.on( 'click', this.expand.bind( this ) );
}
// Initialization
this.populateFromModel();
this.toggleExpanded( false );
this.toggleRead( false );
this.$element
.addClass( 'mw-echo-ui-bundleNotificationItemWidget' )
.append(
$( '
' )
.addClass( 'mw-echo-ui-bundleNotificationItemWidget-separator' ),
this.listWidget.$element
);
// Events
this.model.connect( this, { update: 'updateDataFromModel' } );
// Update read and seen states from the model
this.updateDataFromModel();
};
/* Initialization */
OO.inheritClass( mw.echo.ui.BundleNotificationItemWidget, mw.echo.ui.NotificationItemWidget );
/* Methods */
/**
* @inheritdoc
*/
mw.echo.ui.BundleNotificationItemWidget.prototype.markRead = function ( isRead ) {
this.controller.markEntireListModelRead( this.model.getModelName(), isRead );
};
/**
* Populate the items in this widget according to the data
* in the model
*/
mw.echo.ui.BundleNotificationItemWidget.prototype.populateFromModel = function () {
var widget = this;
this.getList().addItems( this.model.getList().getItems().map( function ( singleNotifModel ) {
return new mw.echo.ui.SingleNotificationItemWidget(
widget.controller,
singleNotifModel,
{
$overlay: widget.$overlay,
bundle: true
}
);
} ) );
};
/**
* Update item state when the item model changes.
*
* @fires OO.EventEmitter#sortChange
*/
mw.echo.ui.BundleNotificationItemWidget.prototype.updateDataFromModel = function () {
this.toggleRead( this.model.isRead() );
this.toggleSeen( this.model.isSeen() );
this.emit( 'sortChange' );
};
/**
* Toggle the visibility of the notification item list and the placeholder/error widget.
*
* @param {boolean} showList Show the list
*/
mw.echo.ui.BundleNotificationItemWidget.prototype.toggleListDisplay = function ( showList ) {
this.listWidget.toggle( showList );
};
/**
* Expand the group and fetch the list of notifications.
* Only fetch the first time we expand.
*/
mw.echo.ui.BundleNotificationItemWidget.prototype.expand = function () {
this.toggleExpanded( !this.expanded );
this.updateExpandButton();
this.$element.toggleClass( 'mw-echo-ui-bundleNotificationItemWidget-expanded', this.expanded );
if ( !this.expanded ) {
return;
}
};
/**
* Toggle the expand/collapsed state of this group widget
*
* @param {boolean} show Show the widget expanded
*/
mw.echo.ui.BundleNotificationItemWidget.prototype.toggleExpanded = function ( show ) {
this.expanded = show !== undefined ? !!show : !this.expanded;
if ( show ) {
// FIXME: Use CSS transition
// eslint-disable-next-line no-jquery/no-slide
this.getList().$element.slideDown();
} else {
// eslint-disable-next-line no-jquery/no-slide
this.getList().$element.slideUp();
}
};
/**
* Update the expand button label
*/
mw.echo.ui.BundleNotificationItemWidget.prototype.updateExpandButton = function () {
this.toggleExpandButton.setLabel(
this.expanded ?
mw.msg( 'notification-link-text-collapse-all' ) :
mw.msg( 'notification-link-text-expand-all' )
);
this.toggleExpandButton.setIcon(
this.expanded ?
'collapse' :
'expand'
);
// T258706
this.toggleExpandButton.setActive( false );
};
/**
* Get the list widget contained in this item
*
* @return {mw.echo.ui.SortedListWidget} List widget
*/
mw.echo.ui.BundleNotificationItemWidget.prototype.getList = function () {
return this.listWidget;
};
}() );