(re)Add JavaScript hooks to Notifications

Added the following Javascript hooks:
* ext.echo.notifications.beforeRender: Firing before a group of
  notification widgets are rendered, whether in the popup, in
  the special page, or in a cross-wiki bundle (which requires
  async loading)
* ext.echo.badge.countChange: Fired when the badge count changes
  with the notification type, count and the label count for
  display purposes.
* ext.echo.popup.onInitialize: Fired when the popup is opened and
  after notifications were fetched, with the context of the popup
  notification type.
* ext.echo.special.onInitialize: Fired when the special page is
  ready and notifications were fetched. Note that it will be fired
  whenever the special page is updated with notifications list,
  as well, like when changing filter, remote wiki or pagination.

The hooks were also documented in hooks.txt

Bug: T146296
Change-Id: Ie3dc97f97e8d1f90b67f62fcdc65dd29cb379aad
This commit is contained in:
Moriel Schottlender 2016-09-26 10:08:43 -07:00
parent 54d62d6938
commit e9264022a7
6 changed files with 75 additions and 24 deletions

View file

@ -2,6 +2,25 @@ hooks.txt
This documents Echo's client-side hooks:
'ext.echo.overlay.beforeShowingOverlay': Before showing the Echo overlay, it is
passed to this hook, which can modify the DOM or take other actions.
$overlay: the jQuery-wrapped element for the overlay
'ext.echo.notifications.beforeRender': Before notification widgets are rendered
the wrapper of the notifications and the individual notification jQuery elements
are passed to this hook, which can modify the DOM or take other actions.
* $wrapper: The jQuery object that is the wrapper for the notification items
* $elements: A jQuery group of all notification elements that are about to be rendered.
'ext.echo.badge.countChange': When the count changes in the Notifications popup
badge, this hook is fired with the new count.
* type: Notifications type that the badge represents. Can be 'message', 'alert' or 'all'
* count: The new numerical count in the notifications popup.
* label: The label for this number, for presentation purposes.
'ext.echo.popup.onInitialize': Fired when the popup is opened and after notifications
were fetched from the API.
* types: Notifications type that the badge represents. Can be 'message', 'alert' or 'all'
* controller: The instance of the controller responsible for the specific popup operations
'ext.echo.special.onInitialize': Fired when the special page is initialized. Note that this
is also fired whenever the special page notification display is changed, like when clicking
a filter, changing pagination, or viewing notifications for a remote wiki or page.
* types: Notifications type that the badge represents. Can be 'message', 'alert' or 'all'
* controller: The instance of the controller responsible for the specific popup operations

View file

@ -7,6 +7,8 @@
*
* @constructor
* @param {Object} [config] Configuration object
* @cfg {string} [type] The notification types this button represents;
* 'message', 'alert' or 'all'
* @cfg {string} [href] URL the badge links to
*/
mw.echo.ui.BadgeLinkWidget = function MwEchoUiBadgeLinkWidget( config ) {
@ -24,6 +26,8 @@
this.$element
.addClass( 'mw-echo-notifications-badge' );
this.count = 0;
this.type = config.type || 'alert';
this.setCount( config.numItems, config.label );
if ( config.href !== undefined && OO.ui.isSafeUrl( config.href ) ) {
@ -48,6 +52,13 @@
mw.echo.ui.BadgeLinkWidget.prototype.setCount = function ( numItems, label ) {
label = label || numItems;
if ( this.count !== numItems ) {
this.count = numItems;
// Fire badge count change hook
mw.hook( 'ext.echo.badge.countChange' ).fire( this.type, this.count, label );
}
this.$element
.toggleClass( 'mw-echo-notifications-badge-all-read', !numItems )
.attr( 'data-counter-num', numItems )

View file

@ -61,6 +61,7 @@
this.badgeButton = new mw.echo.ui.BadgeLinkWidget( {
label: this.badgeLabel,
type: this.manager.getTypeString(),
numItems: this.numItems,
flags: buttonFlags,
// The following messages can be used here:
@ -334,6 +335,9 @@
// Success
function () {
if ( widget.popup.isVisible() ) {
// Fire initialization hook
mw.hook( 'ext.echo.popup.onInitialize' ).fire( widget.manager.getTypeString(), widget.controller );
widget.popup.clip();
// Update seen time
return widget.controller.updateSeenTime();

View file

@ -243,6 +243,9 @@
.then(
// Success
function () {
// Fire initialization hook
mw.hook( 'ext.echo.special.onInitialize' ).fire( widget.controller.manager.getTypeString(), widget.controller );
widget.popPending();
// Update seen time
widget.controller.updateSeenTime();

View file

@ -1,4 +1,4 @@
( function ( mw ) {
( function ( mw, $ ) {
/**
* Notifications list widget.
* All of its items must be of the mw.echo.ui.NotificationItem type.
@ -101,8 +101,9 @@
* list.
*/
mw.echo.ui.NotificationsListWidget.prototype.resetDataFromModel = function ( models ) {
var i, modelId, model, subItems, subItem,
itemWidgets = [];
var i, modelId, model, subItems, subItem, widget,
itemWidgets = [],
$elements = $();
// Detach all attached models
for ( modelId in this.models ) {
@ -118,17 +119,17 @@
if ( model.isGroup() ) {
if ( model.isForeign() ) {
// One Widget to Rule Them All
itemWidgets.push( new mw.echo.ui.CrossWikiNotificationItemWidget(
widget = new mw.echo.ui.CrossWikiNotificationItemWidget(
this.controller,
model,
{
$overlay: this.$overlay,
animateSorting: this.animated
}
) );
);
} else {
// local bundle
itemWidgets.push( new mw.echo.ui.BundleNotificationItemWidget(
widget = new mw.echo.ui.BundleNotificationItemWidget(
this.controller,
model,
{
@ -136,27 +137,35 @@
bundle: false,
animateSorting: this.animated
}
) );
);
}
itemWidgets.push( widget );
$elements = $elements.add( widget.$element );
} else {
subItems = model.getItems();
// Separate widgets per item
for ( i = 0; i < subItems.length; i++ ) {
subItem = subItems[ i ];
itemWidgets.push( new mw.echo.ui.SingleNotificationItemWidget(
widget = new mw.echo.ui.SingleNotificationItemWidget(
this.controller,
subItem,
{
$overlay: this.$overlay,
bundle: false
}
) );
);
itemWidgets.push( widget );
$elements = $elements.add( widget.$element );
}
}
}
// Reset the current items and re-add the new item widgets
this.clearItems();
// fire render hook
mw.hook( 'ext.echo.notifications.beforeRender' ).fire( this.$element, $elements );
this.addItems( itemWidgets );
this.checkForEmptyNotificationsList();
@ -215,4 +224,4 @@
itemWidgets[ i ].resetInitiallyUnseen();
}
};
} )( mediaWiki );
} )( mediaWiki, jQuery );

View file

@ -152,26 +152,31 @@
* If this is empty, the widget will request all the items from the model.
*/
mw.echo.ui.SubGroupListWidget.prototype.resetItemsFromModel = function ( items ) {
var i,
itemWidgets = [];
var i, widget,
itemWidgets = [],
$elements = $();
items = items || this.model.getItems();
for ( i = 0; i < items.length; i++ ) {
itemWidgets.push(
new mw.echo.ui.SingleNotificationItemWidget(
this.controller,
items[ i ],
{
$overlay: this.$overlay,
bundle: items[ i ].isBundled()
}
)
widget = new mw.echo.ui.SingleNotificationItemWidget(
this.controller,
items[ i ],
{
$overlay: this.$overlay,
bundle: items[ i ].isBundled()
}
);
itemWidgets.push( widget );
$elements = $elements.add( widget.$element );
}
// Clear the current items if any exist
this.getListWidget().clearItems();
// fire render hook
mw.hook( 'ext.echo.notifications.beforeRender' ).fire( this.$element, $elements );
// Add the new items
this.getListWidget().addItems( itemWidgets );
};