RCFilters UI: Implement conflict global result message
authorMoriel Schottlender <moriel@gmail.com>
Sat, 18 Mar 2017 00:29:07 +0000 (17:29 -0700)
committerMoriel Schottlender <moriel@gmail.com>
Sat, 18 Mar 2017 01:16:26 +0000 (18:16 -0700)
Bug: T156427
Change-Id: I7ae968477091db37e3e2d17fca6f212f919d90d8

languages/i18n/en.json
languages/i18n/qqq.json
resources/Resources.php
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterItem.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js
resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.less
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js

index 77e93ae..4658b00 100644 (file)
        "rcfilters-highlightmenu-title": "Select a color",
        "rcfilters-highlightmenu-help": "Select a color to highlight this property",
        "rcfilters-filterlist-noresults": "No filters found",
+       "rcfilters-noresults-conflict": "No results found because the search criteria are in conflict",
        "rcfilters-state-message-subset": "This filter has no effect because its results are included with those of the following, broader {{PLURAL:$2|filter|filters}} (try highlighting to distinguish it): $1",
        "rcfilters-state-message-fullcoverage": "Selecting all filters in a group is the same as selecting none, so this filter has no effect. Group includes: $1",
        "rcfilters-filtergroup-registration": "User registration",
index ead277d..4568251 100644 (file)
        "rcfilters-highlightmenu-title": "Title for the highlight menu used to select the highlight color for an individual filter.",
        "rcfilters-highlightmenu-help": "Tooltip for the highlight menu for individual filters.",
        "rcfilters-filterlist-noresults": "Message showing no results found for searching a filter.",
+       "rcfilters-noresults-conflict": "A message displayed in the results area when no results found because there are filters in conflict with one another.",
        "rcfilters-state-message-subset": "Tooltip shown when hovering over a filter tag when one or more broader filters that contain the hovered filter are also selected. This indicates that the hovered filter has no effect because all the results it matches are also matched by the broader filter(s).  Parameters:\n* $1 - Comma-separated string of selected broader filters that this filter is a subset of\n* $2 - Count of filters in $1, for PLURAL",
        "rcfilters-state-message-fullcoverage": "Tooltip shown when hovering over a filter tag when all the filters in its group are selected. This indicates that the hovered filter has no effect because the selected filters in the group cover all changes. Parameters:\n* $1 - Comma-separated string of selected filters in the group\n* $2 - Count of filters in $1, for PLURAL",
        "rcfilters-filtergroup-registration": "Title for the filter group for editor registration type.",
index 6a26ca2..80a4130 100644 (file)
@@ -1815,6 +1815,7 @@ return [
                        'rcfilters-highlightbutton-title',
                        'rcfilters-highlightmenu-title',
                        'rcfilters-highlightmenu-help',
+                       'rcfilters-noresults-conflict',
                        'rcfilters-state-message-subset',
                        'rcfilters-state-message-fullcoverage',
                        'recentchanges-noresult',
index 59f09bb..5f406bd 100644 (file)
                return this.param;
        };
 
+       /**
+        * Get the message for the display area for the currently active conflict
+        *
+        * @return {string} Conflict result message key
+        */
+       mw.rcfilters.dm.FilterItem.prototype.getCurrentConflictResultMessage = function () {
+               var details = {};
+
+               // First look in filter's own conflicts
+               details = this.getConflictDetails( this.getOwnConflicts(), 'globalDescription' );
+               if ( !details.message ) {
+                       // Fall back onto conflicts in the group
+                       details = this.getConflictDetails( this.getGroupModel().getConflicts(), 'globalDescription' );
+               }
+
+               return details.message;
+       };
+
        /**
         * Get the details of the active conflict on this filter
         *
index ca0282d..f916161 100644 (file)
                } );
        };
 
+       /**
+        * Get whether the model has any conflict in its items
+        *
+        * @return {boolean} There is a conflict
+        */
+       mw.rcfilters.dm.FiltersViewModel.prototype.hasConflict = function () {
+               return this.getItems().some( function ( filterItem ) {
+                       return filterItem.isSelected() && filterItem.isConflicted();
+               } );
+       };
+
+       /**
+        * Get the first item with a current conflict
+        *
+        * @return {mw.rcfilters.dm.FilterItem} Conflicted item
+        */
+       mw.rcfilters.dm.FiltersViewModel.prototype.getFirstConflictedItem = function () {
+               var conflictedItem;
+
+               $.each( this.getItems(), function ( index, filterItem ) {
+                       if ( filterItem.isSelected() && filterItem.isConflicted() ) {
+                               conflictedItem = filterItem;
+                               return false;
+                       }
+               } );
+
+               return conflictedItem;
+       };
+
        /**
         * Set filters and preserve a group relationship based on
         * the definition given by an object
index f8008b6..44c7bf0 100644 (file)
         * @param {Array} filterStructure Filter definition and structure for the model
         */
        mw.rcfilters.Controller.prototype.initialize = function ( filterStructure ) {
+               var $changesList = $( '.mw-changeslist' ).first().contents();
                // Initialize the model
                this.filtersModel.initializeFilters( filterStructure );
                this.updateStateBasedOnUrl();
+
+               // Update the changes list with the existing data
+               // so it gets processed
+               this.changesListModel.update(
+                       $changesList.length ? $changesList : 'NO_RESULTS',
+                       $( 'fieldset.rcoptions' ).first()
+               );
+
        };
 
        /**
index c18fe5e..29c3ed1 100644 (file)
@@ -1,6 +1,15 @@
 @import 'mw.rcfilters.mixins';
 
 .mw-rcfilters-ui-changesListWrapperWidget {
+       &-results {
+               width: 35em;
+               margin: 5em auto;
+               &-conflict {
+                       font-weight: bold;
+                       margin-bottom: 0.5em;
+               }
+       }
+
        &-highlighted {
                ul {
                        list-style: none;
index 84248e1..ec2ebe0 100644 (file)
         * @param {jQuery|string} $changesListContent The content of the updated changes list
         */
        mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onModelUpdate = function ( $changesListContent ) {
-               var isEmpty = $changesListContent === 'NO_RESULTS';
+               var conflictItem,
+                       $message = $( '<div>' )
+                               .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results' ),
+                       isEmpty = $changesListContent === 'NO_RESULTS';
 
                this.$element.toggleClass( 'mw-changeslist', !isEmpty );
                this.$element.toggleClass( 'mw-changeslist-empty', isEmpty );
                if ( isEmpty ) {
                        this.$changesListContent = null;
-                       this.$element.empty().append(
-                               document.createTextNode( mw.message( 'recentchanges-noresult' ).text() )
-                       );
+                       this.$element.empty();
+
+                       if ( this.filtersViewModel.hasConflict() ) {
+                               conflictItem = this.filtersViewModel.getFirstConflictedItem();
+
+                               $message
+                                       .append(
+                                               $( '<div>' )
+                                                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-conflict' )
+                                                       .text( mw.message( 'rcfilters-noresults-conflict' ).text() ),
+                                               $( '<div>' )
+                                                       .addClass( 'mw-rcfilters-ui-changesListWrapperWidget-results-message' )
+                                                       .text( mw.message( conflictItem.getCurrentConflictResultMessage() ).text() )
+                                       );
+                       } else {
+                               $message
+                                       .append(
+                                               $( '<div>' )
+                                                       .text( mw.message( 'recentchanges-noresult' ).text() )
+                                       );
+                       }
+
+                       this.$element.append( $message );
                } else {
                        this.$changesListContent = $changesListContent;
                        this.$element.empty().append( this.$changesListContent );