Mooeypoo has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/298910

Change subject: Relate read-state filter and mark read/unread action
......................................................................

Relate read-state filter and mark read/unread action

When we are viewing a certain read state filter ('read' or 'unread')
the visibility of items should correspond to that state even when
the user marks a specific item as read/unread. That means that the
system should remove these items from view when the action is taken.

In this commit:
* The controller makes the judgment of whether to remove items when
  read/unread action is taken, based on whether a filter is set.
* We clean up the terminology of discard - no more 'remove' - to
  make sure we have consistency in the code.
* Related: The 'discard' event is now scoped within the hierarchy;
  meaning, lists emit 'discard' when an item is removed, grouplist
  emits 'discard' when a group is removed, and the manager emits
  'discard' when an entire notification model is removed. This
  means we can actually have proper hierarchy and organization with
  a single event, and not worry about clashing between the intentional
  'discard' action and the event 'remove' that is also used while
  resorting happens.
* The model manager emits a discard event when a model is removed
  so that the general list can listen to the manager and remove an
  entire batch of items if needed.

Bug: T136891
Change-Id: I247c618042ef256fadf09922f7b83bd1ad361f64
---
M modules/controller/mw.echo.Controller.js
M modules/model/mw.echo.dm.CrossWikiNotificationItem.js
M modules/model/mw.echo.dm.ModelManager.js
M modules/model/mw.echo.dm.NotificationGroupsList.js
M modules/model/mw.echo.dm.NotificationsList.js
M modules/special/ext.echo.special.js
M modules/ui/mw.echo.ui.CrossWikiNotificationItemWidget.js
M modules/ui/mw.echo.ui.DatedNotificationsWidget.js
M modules/ui/mw.echo.ui.NotificationsListWidget.js
9 files changed, 113 insertions(+), 45 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Echo 
refs/changes/10/298910/1

diff --git a/modules/controller/mw.echo.Controller.js 
b/modules/controller/mw.echo.Controller.js
index f51091b..63db45b 100644
--- a/modules/controller/mw.echo.Controller.js
+++ b/modules/controller/mw.echo.Controller.js
@@ -466,7 +466,9 @@
         *  for the set type of this controller, in the given source.
         */
        mw.echo.Controller.prototype.markItemsRead = function ( itemIds, 
modelName, isRead ) {
-               var model = this.manager.getNotificationModel( modelName ),
+               var items,
+                       model = this.manager.getNotificationModel( modelName ),
+                       readState = 
this.manager.getFiltersModel().getReadState(),
                        allIds = [];
 
                itemIds = Array.isArray( itemIds ) ? itemIds : [ itemIds ];
@@ -474,11 +476,22 @@
                // Default to true
                isRead = isRead === undefined ? true : isRead;
 
-               model.findByIds( itemIds ).forEach( function ( notification ) {
-                       allIds = allIds.concat( notification.getAllIds() );
-                       notification.toggleRead( isRead );
-               } );
-
+               items = model.findByIds( itemIds );
+               // If we are only looking at specific read state,
+               // then we need to make sure the items are removed
+               // from the visible list, because they no longer
+               // correspond with the chosen state filter
+               if ( readState === 'read' && !isRead ) {
+                       model.discardItems( items );
+               } else if ( readState === 'unread' && isRead ) {
+                       model.discardItems( items );
+               } else {
+                       // Toggle the read state of the items in the UI 
regularly
+                       items.forEach( function ( notification ) {
+                               allIds = allIds.concat( 
notification.getAllIds() );
+                               notification.toggleRead( isRead );
+                       } );
+               }
                this.manager.getUnreadCounter().estimateChange( isRead ? 
-allIds.length : allIds.length );
 
                return this.api.markItemsRead( allIds, model.getSource(), 
isRead ).then( this.refreshUnreadCount.bind( this ) );
@@ -505,7 +518,7 @@
 
                itemIds = Array.isArray( itemIds ) ? itemIds : [ itemIds ];
 
-               sourceModel = xwikiModel.getList().getGroupBySource( source );
+               sourceModel = xwikiModel.getList().getGroupByName( source );
                notifs = sourceModel.findByIds( itemIds );
                sourceModel.discardItems( notifs );
 
diff --git a/modules/model/mw.echo.dm.CrossWikiNotificationItem.js 
b/modules/model/mw.echo.dm.CrossWikiNotificationItem.js
index efe131f..b14fa39 100644
--- a/modules/model/mw.echo.dm.CrossWikiNotificationItem.js
+++ b/modules/model/mw.echo.dm.CrossWikiNotificationItem.js
@@ -22,7 +22,7 @@
 
                this.list = new mw.echo.dm.NotificationGroupsList();
 
-               this.list.connect( this, { remove: 'onListRemove' } );
+               this.list.connect( this, { discard: 'onListDiscard' } );
        };
 
        OO.inheritClass( mw.echo.dm.CrossWikiNotificationItem, 
mw.echo.dm.NotificationItem );
@@ -30,10 +30,10 @@
        /* Events */
 
        /**
-        * @event removeSource
-        * @param {string} name The symbolic name for the source that was 
removed
+        * @event discard
+        * @param {string} name The symbolic name for the list model that was 
discarded
         *
-        * Source list has been removed
+        * A sub list has been discarded
         */
 
        /* Methods */
@@ -42,11 +42,10 @@
         * Respond to list being removed from the cross-wiki bundle.
         *
         * @param {mw.echo.dm.NotificationGroupsList} sourceModel The source 
model that was removed
-        * @fires removeSource
+        * @fires discard
         */
-       mw.echo.dm.CrossWikiNotificationItem.prototype.onListRemove = function 
( sourceModel ) {
-               this.emit( 'removeSource', sourceModel.getName() );
-
+       mw.echo.dm.CrossWikiNotificationItem.prototype.onListDiscard = function 
( sourceModel ) {
+               this.emit( 'discard', sourceModel.getName() );
        };
 
        /**
@@ -82,7 +81,7 @@
         * @return {mw.echo.dm.NotificationGroupsList} Source item
         */
        mw.echo.dm.CrossWikiNotificationItem.prototype.getItemBySource = 
function ( sourceName ) {
-               return this.list.getGroupBySource( sourceName );
+               return this.list.getGroupByName( sourceName );
        };
 
        /**
@@ -128,4 +127,8 @@
                return true;
        };
 
+       mw.echo.dm.CrossWikiNotificationItem.prototype.isEmpty = function () {
+               return this.getList().isEmpty();
+       };
+
 } )( mediaWiki );
diff --git a/modules/model/mw.echo.dm.ModelManager.js 
b/modules/model/mw.echo.dm.ModelManager.js
index f119847..8facb76 100644
--- a/modules/model/mw.echo.dm.ModelManager.js
+++ b/modules/model/mw.echo.dm.ModelManager.js
@@ -61,10 +61,10 @@
         */
 
        /**
-        * @event remove
-        * @param {string} Removed model
+        * @event discard
+        * @param {string} modelId Discard model id
         *
-        * A model has been removed
+        * A model has been permanently removed
         */
 
        /**
@@ -80,6 +80,20 @@
         */
 
        /* Methods */
+
+       /**
+        * Respond to a notification model discarding items.
+        *
+        * @param {string} modelId Model name
+        */
+       mw.echo.dm.ModelManager.prototype.onModelDiscardItems = function ( 
modelId ) {
+               var model = this.getNotificationModel( modelId );
+
+               // If the model is empty, remove it
+               if ( model.isEmpty() ) {
+                       this.removeNotificationModel( modelId );
+               }
+       };
 
        /**
         * Get the notifications
@@ -108,6 +122,7 @@
 
                for ( modelId in modelDefinitions ) {
                        this.notificationModels[ modelId ] = modelDefinitions[ 
modelId ];
+                       this.notificationModels[ modelId ].connect( this, { 
discard: [ 'onModelDiscardItems', modelId ] } );
                }
 
                localModel = this.getNotificationModel( 'local' );
@@ -171,7 +186,8 @@
         */
        mw.echo.dm.ModelManager.prototype.removeNotificationModel = function ( 
modelName ) {
                delete this.notificationModels[ modelName ];
-               this.emit( 'remove', modelName );
+
+               this.emit( 'discard', modelName );
        };
 
        /**
diff --git a/modules/model/mw.echo.dm.NotificationGroupsList.js 
b/modules/model/mw.echo.dm.NotificationGroupsList.js
index 9cf4090..6fdbeb2 100644
--- a/modules/model/mw.echo.dm.NotificationGroupsList.js
+++ b/modules/model/mw.echo.dm.NotificationGroupsList.js
@@ -30,32 +30,40 @@
                        }
 
                        // Fallback on Source
-                       return b.getSource() - a.getSource();
+                       return b.getName() - a.getName();
                } );
 
                this.foreign = !!config.foreign;
                this.groups = {};
 
-               this.aggregate( { remove: 'groupRemoveItem' } );
-               this.connect( this, { groupRemoveItem: 'onGroupRemoveItem' } );
+               this.aggregate( { discard: 'groupDiscardItem' } );
+               this.connect( this, { groupDiscardItem: 'onGroupDiscardItem' } 
);
        };
 
        /* Initialization */
        OO.inheritClass( mw.echo.dm.NotificationGroupsList, 
mw.echo.dm.SortedList );
 
+       /* Events */
+
+       /**
+        * @event discard
+        *
+        * A group was permanently removed
+        */
+
        /* Methods */
 
        /**
-        * Handle a remove event from any list.
-        * This means that one of the sources has removed an item.
+        * Handle a discard event from any list.
+        * This means that one of the sources has discarded an item.
         *
         * @param {mw.echo.dm.NotificationsList} groupList List source model 
for the item
         */
-       mw.echo.dm.NotificationGroupsList.prototype.onGroupRemoveItem = 
function ( groupList ) {
+       mw.echo.dm.NotificationGroupsList.prototype.onGroupDiscardItem = 
function ( groupList ) {
                // Check if the list has anything at all
                if ( groupList.isEmpty() ) {
                        // Remove it
-                       this.removeItems( [ groupList ] );
+                       this.removeGroup( groupList.getName() );
                }
        };
 
@@ -108,7 +116,7 @@
         * @param {mw.echo.dm.NotificationItem[]} groupItems Items to add to 
this group
         */
        mw.echo.dm.NotificationGroupsList.prototype.addItemsToGroup = function 
( groupSource, groupItems ) {
-               var group = this.getGroupBySource( groupSource );
+               var group = this.getGroupByName( groupSource );
 
                if ( group ) {
                        group.addItems( groupItems );
@@ -118,28 +126,36 @@
         * Remove a group from the list. This is an easier to use alias
         * to 'removeItems()' method.
         *
-        * @param {string} groupSource Group source name
+        * Since this is an intentional action, we fire 'discard' event.
+        * The main reason for this is that the event 'remove' is a general
+        * event that is fired both when a user intends on removing an
+        * item and also when an item is temporarily removed to be re-added
+        * for the sake of sorting. To avoid ambiguity, we use 'discard' event.
+        *
+        * @param {string} groupName Group name
+        * @fires discard
         */
-       mw.echo.dm.NotificationGroupsList.prototype.removeGroup = function ( 
groupSource ) {
-               var group = this.getGroupBySource( groupSource );
+       mw.echo.dm.NotificationGroupsList.prototype.removeGroup = function ( 
groupName ) {
+               var group = this.getGroupByName( groupName );
 
                if ( group ) {
                        this.removeItems( group );
+                       this.emit( 'discard', group );
                }
        };
 
        /**
         * Get a group by its source identifier.
         *
-        * @param {string} groupSource Group source
+        * @param {string} groupName Group name
         * @return {mw.echo.dm.NotificationsList|null} Requested group, null if 
none was found.
         */
-       mw.echo.dm.NotificationGroupsList.prototype.getGroupBySource = function 
( groupSource ) {
+       mw.echo.dm.NotificationGroupsList.prototype.getGroupByName = function ( 
groupName ) {
                var i,
                        items = this.getItems();
 
                for ( i = 0; i < items.length; i++ ) {
-                       if ( items[ i ].getSource() === groupSource ) {
+                       if ( items[ i ].getName() === groupName ) {
                                return items[ i ];
                        }
                }
diff --git a/modules/model/mw.echo.dm.NotificationsList.js 
b/modules/model/mw.echo.dm.NotificationsList.js
index 3034149..2191910 100644
--- a/modules/model/mw.echo.dm.NotificationsList.js
+++ b/modules/model/mw.echo.dm.NotificationsList.js
@@ -79,6 +79,13 @@
         * An item in the list has been updated
         */
 
+       /**
+        * @event discard
+        * @param {mw.echo.dm.NotificationItem} item Item that was discarded
+        *
+        * An item was discarded
+        */
+
        /* Methods */
 
        /**
@@ -107,6 +114,10 @@
        mw.echo.dm.NotificationsList.prototype.discardItems = function ( items 
) {
                this.removeItems( items );
                this.emit( 'discard', items );
+
+               if ( this.isEmpty() ) {
+                       this.emit( 'empty' );
+               }
        };
 
        /**
diff --git a/modules/special/ext.echo.special.js 
b/modules/special/ext.echo.special.js
index 2374c9d..615719e 100644
--- a/modules/special/ext.echo.special.js
+++ b/modules/special/ext.echo.special.js
@@ -11,10 +11,7 @@
                        modelManager = new mw.echo.dm.ModelManager( 
unreadCounter, { type: [ 'message', 'alert' ] } ),
                        controller = new mw.echo.Controller(
                                echoApi,
-                               modelManager,
-                               {
-                                       type: [ 'message' ]
-                               }
+                               modelManager
                        ),
                        specialPageContainer = new 
mw.echo.ui.NotificationsInboxWidget(
                                controller,
diff --git a/modules/ui/mw.echo.ui.CrossWikiNotificationItemWidget.js 
b/modules/ui/mw.echo.ui.CrossWikiNotificationItemWidget.js
index 918e94d..072a123 100644
--- a/modules/ui/mw.echo.ui.CrossWikiNotificationItemWidget.js
+++ b/modules/ui/mw.echo.ui.CrossWikiNotificationItemWidget.js
@@ -82,7 +82,7 @@
                this.actionsButtonSelectWidget.addItems( [ 
this.toggleExpandButton ] );
 
                // Events
-               this.model.connect( this, { removeSource: 'onModelRemoveSource' 
} );
+               this.model.connect( this, { discard: 'onModelDiscard' } );
                this.toggleExpandButton.connect( this, { click: 'expand' } );
                this.$content.on( 'click', this.expand.bind( this ) );
 
@@ -120,11 +120,11 @@
        /**
         * Respond to model removing source group
         *
-        * @param {string} source Symbolic name of the source group
+        * @param {string} groupName Symbolic name of the group
         */
-       
mw.echo.ui.CrossWikiNotificationItemWidget.prototype.onModelRemoveSource = 
function ( source ) {
+       mw.echo.ui.CrossWikiNotificationItemWidget.prototype.onModelDiscard = 
function ( groupName ) {
                var list = this.getList(),
-                       group = list.getItemFromId( source );
+                       group = list.getItemFromId( groupName );
 
                list.removeItems( [ group ] );
 
diff --git a/modules/ui/mw.echo.ui.DatedNotificationsWidget.js 
b/modules/ui/mw.echo.ui.DatedNotificationsWidget.js
index 0755cad..ea3da89 100644
--- a/modules/ui/mw.echo.ui.DatedNotificationsWidget.js
+++ b/modules/ui/mw.echo.ui.DatedNotificationsWidget.js
@@ -42,7 +42,7 @@
                // Events
                this.manager.connect( this, {
                        update: 'populateFromModel',
-                       removeSource: 'onModelRemoveSource'
+                       discard: 'onManagerDiscardModel'
                } );
 
                this.$element
@@ -57,6 +57,16 @@
        OO.inheritClass( mw.echo.ui.DatedNotificationsWidget, OO.ui.Widget );
        OO.mixinClass( mw.echo.ui.DatedNotificationsWidget, 
OO.ui.mixin.PendingElement );
 
+       mw.echo.ui.DatedNotificationsWidget.prototype.onManagerDiscardModel = 
function ( modelId ) {
+               var group,
+                       model = this.models[ modelId ],
+                       list = this.getList();
+
+               if ( model ) {
+                       group = list.getItemFromId( model.getName() );
+                       list.removeItems( [ group ] );
+               }
+       };
        /**
         * Respond to model removing source group
         *
@@ -94,6 +104,8 @@
                                        $overlay: this.$overlay
                                }
                        );
+                       this.attachModel( model, models[ model ] );
+
                        subgroupWidget.resetItemsFromModel();
                        groupWidgets.push( subgroupWidget );
                }
diff --git a/modules/ui/mw.echo.ui.NotificationsListWidget.js 
b/modules/ui/mw.echo.ui.NotificationsListWidget.js
index 89df922..f273ec7 100644
--- a/modules/ui/mw.echo.ui.NotificationsListWidget.js
+++ b/modules/ui/mw.echo.ui.NotificationsListWidget.js
@@ -59,7 +59,7 @@
 
                this.manager.connect( this, {
                        update: 'resetDataFromModel',
-                       remove: 'onModelManagerRemove'
+                       discard: 'onModelManagerDiscard'
                } );
 
                this.$element
@@ -72,7 +72,7 @@
 
        /* Methods */
 
-       mw.echo.ui.NotificationsListWidget.prototype.onModelManagerRemove = 
function ( modelName ) {
+       mw.echo.ui.NotificationsListWidget.prototype.onModelManagerDiscard = 
function ( modelName ) {
                var i,
                        items = this.getItems();
 

-- 
To view, visit https://gerrit.wikimedia.org/r/298910
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I247c618042ef256fadf09922f7b83bd1ad361f64
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <mor...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to