Merge "RCFilters: Add 'enhanced' view (Group by pages)"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 2 Aug 2017 01:19:59 +0000 (01:19 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 2 Aug 2017 01:19:59 +0000 (01:19 +0000)
1  2 
languages/i18n/en.json
languages/i18n/qqq.json
resources/Resources.php
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js
resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js

diff --combined languages/i18n/en.json
        "recentchanges-submit": "Show",
        "rcfilters-legend-heading": "<strong>List of abbreviations:</strong>",
        "rcfilters-other-review-tools": "<strong>Other review tools:</strong>",
+       "rcfilters-group-results-by-page": "Group results by page",
+       "rcfilters-grouping-title": "Grouping",
        "rcfilters-activefilters": "Active filters",
        "rcfilters-advancedfilters": "Advanced filters",
        "rcfilters-limit-title": "Changes to show",
 -      "rcfilters-limit-shownum": "Show last $1 changes",
 +      "rcfilters-limit-shownum": "Show last {{PLURAL:$1|change|$1 changes}}",
        "rcfilters-days-title": "Recent days",
        "rcfilters-hours-title": "Recent hours",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|day|days}}",
        "rcfilters-tag-prefix-tags": "#$1",
        "rcfilters-exclude-button-off": "Exclude selected",
        "rcfilters-exclude-button-on": "Excluding selected",
 +      "rcfilters-view-advanced-filters-label": "Advanced filters",
        "rcfilters-view-tags": "Tagged edits",
        "rcfilters-view-namespaces-tooltip": "Filter results by namespace",
        "rcfilters-view-tags-tooltip": "Filter results using edit tags",
diff --combined languages/i18n/qqq.json
        "recentchanges-submit": "Label for submit button in [[Special:RecentChanges]]\n{{Identical|Show}}",
        "rcfilters-legend-heading": "Used as a heading for legend box on [[Special:RecentChanges]] and [[Special:Watchlist]] when RCFilters are enabled.",
        "rcfilters-other-review-tools": "Used as a heading for the community collection of other links on [[Special:RecentChanges]] when RCFilters are enabled.",
+       "rcfilters-group-results-by-page": "A label for the checkbox describing whether the results in [[Special:RecentChanges]] are grouped by page when RCFilters are enabled.",
+       "rcfilters-grouping-title": "Title for the section showing display options for grouping results in [[Special:RecentChanges]] when RCFilters are enabled.",
        "rcfilters-activefilters": "Title for the filters selection showing the active filters.",
        "rcfilters-advancedfilters": "Title for the buttons allowing the user to switch to the various advanced filters views.",
        "rcfilters-limit-title": "Title for the options to change the number of results shown.",
        "rcfilters-tag-prefix-tags": "Prefix for the edit tags in [[Special:RecentChanges]]. Edit tags use a hash (#) as prefix. Please keep this format.\n\nParameters:\n* $1 - Tag display name.",
        "rcfilters-exclude-button-off": "Title for the button that excludes selected namespaces, when it is not yet active.",
        "rcfilters-exclude-button-on": "Title for the button that excludes selected namespaces, when it is not yet active.",
 +      "rcfilters-view-advanced-filters-label": "Label for the view switch that changes between advanced filters in [[Special:RecentChanges]]",
        "rcfilters-view-tags": "Title for the tags view in [[Special:RecentChanges]]\n{{Identical|Tag}}",
        "rcfilters-view-namespaces-tooltip": "Tooltip for the button that loads the namespace view in [[Special:RecentChanges]]",
        "rcfilters-view-tags-tooltip": "Tooltip for the button that loads the tags view in [[Special:RecentChanges]]",
diff --combined resources/Resources.php
@@@ -1423,6 -1423,7 +1423,6 @@@ return 
                'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.css',
                'dependencies' => [
                        'mediawiki.action.edit.styles',
 -                      'jquery.accessKeyLabel',
                        'jquery.textSelection',
                        'jquery.byteLimit',
                        'mediawiki.widgets.visibleByteLimit',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.MenuSelectWidget.less',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ViewSwitchWidget.less',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ValuePickerWidget.less',
+                       'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesLimitPopupWidget.less',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.DatePopupWidget.less',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.FilterWrapperWidget.less',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.less',
                'messages' => [
                        'rcfilters-activefilters',
                        'rcfilters-advancedfilters',
+                       'rcfilters-group-results-by-page',
+                       'rcfilters-grouping-title',
                        'rcfilters-limit-title',
                        'rcfilters-limit-shownum',
                        'rcfilters-days-title',
                        'rcfilters-tag-prefix-tags',
                        'rcfilters-exclude-button-off',
                        'rcfilters-exclude-button-on',
 +                      'rcfilters-view-advanced-filters-label',
                        'rcfilters-view-tags',
                        'rcfilters-view-namespaces-tooltip',
                        'rcfilters-view-tags-tooltip',
@@@ -17,9 -17,6 +17,9 @@@
         * @cfg {boolean} [hidden] This group is hidden from the regular menu views
         * @cfg {boolean} [allowArbitrary] Allows for an arbitrary value to be added to the
         *  group from the URL, even if it wasn't initially set up.
 +       * @cfg {number} [range] An object defining minimum and maximum values for numeric
 +       *  groups. { min: x, max: y }
 +       * @cfg {number} [minValue] Minimum value for numeric groups
         * @cfg {string} [separator='|'] Value separator for 'string_options' groups
         * @cfg {boolean} [active] Group is active
         * @cfg {boolean} [fullCoverage] This filters in this group collectively cover all results
@@@ -47,7 -44,6 +47,7 @@@
                this.title = config.title || name;
                this.hidden = !!config.hidden;
                this.allowArbitrary = !!config.allowArbitrary;
 +              this.numericRange = config.range;
                this.separator = config.separator || '|';
                this.labelPrefixKey = config.labelPrefixKey;
  
                                // Store the default parameter state
                                // For this group type, parameter values are direct
                                // We need to convert from a boolean to a string ('1' and '0')
-                               model.defaultParams[ filter.name ] = String( Number( !!filter.default ) );
+                               model.defaultParams[ filter.name ] = String( Number( filter.default || 0 ) );
                        }
                } );
  
                return this.allowArbitrary;
        };
  
 +      /**
 +       * Get group maximum value for numeric groups
 +       *
 +       * @return {number|null} Group max value
 +       */
 +      mw.rcfilters.dm.FilterGroup.prototype.getMaxValue = function () {
 +              return this.numericRange && this.numericRange.max !== undefined ?
 +                      this.numericRange.max : null;
 +      };
 +
 +      /**
 +       * Get group minimum value for numeric groups
 +       *
 +       * @return {number|null} Group max value
 +       */
 +      mw.rcfilters.dm.FilterGroup.prototype.getMinValue = function () {
 +              return this.numericRange && this.numericRange.min !== undefined ?
 +                      this.numericRange.min : null;
 +      };
 +
        /**
         * Get group name
         *
@@@ -33,7 -33,6 +33,7 @@@
         */
        mw.rcfilters.Controller.prototype.initialize = function ( filterStructure, namespaceStructure, tagList ) {
                var parsedSavedQueries, limitDefault,
 +                      displayConfig = mw.config.get( 'StructuredChangeFiltersDisplayConfig' ),
                        controller = this,
                        views = {},
                        items = [],
                                        hidden: true,
                                        allowArbitrary: true,
                                        validate: $.isNumeric,
 +                                      range: {
 +                                              min: 1,
 +                                              max: 1000
 +                                      },
                                        sortFunc: function ( a, b ) { return Number( a.name ) - Number( b.name ); },
                                        'default': String( limitDefault ),
 -                                      isSticky: true,
 -                                      filters: [ 50, 100, 250, 500 ].map( function ( num ) {
 +                                      // Temporarily making this not sticky until we resolve the problem
 +                                      // with the misleading preference. Note that if this is to be permanent
 +                                      // we should remove all sticky behavior methods completely
 +                                      // See T172156
 +                                      // isSticky: true,
 +                                      filters: displayConfig.arrayLimit.map( function ( num ) {
                                                return controller._createFilterDataFromNumber( num, num );
                                        } )
                                },
                                        hidden: true,
                                        allowArbitrary: true,
                                        validate: $.isNumeric,
 +                                      range: {
 +                                              min: 0,
 +                                              max: displayConfig.maxLimit
 +                                      },
                                        sortFunc: function ( a, b ) { return Number( a.name ) - Number( b.name ); },
                                        numToLabelFunc: function ( i ) {
                                                return Number( i ) < 1 ?
                                                        Number( i );
                                        },
                                        'default': mw.user.options.get( 'rcdays', '30' ),
 -                                      isSticky: true,
 +                                      // Temporarily making this not sticky while limit is not sticky, see above
 +                                      // isSticky: true,
                                        filters: [
                                                // Hours (1, 2, 6, 12)
 -                                              0.04166, 0.0833, 0.25, 0.5,
 -                                              // Days
 -                                              1, 3, 7, 14, 30
 -                                      ].map( function ( num ) {
 -                                              return controller._createFilterDataFromNumber(
 -                                                      num,
 -                                                      // Convert fractions of days to number of hours for the labels
 -                                                      num < 1 ? Math.round( num * 24 ) : num
 -                                              );
 -                                      } )
 +                                              0.04166, 0.0833, 0.25, 0.5
 +                                      // Days
 +                                      ].concat( displayConfig.arrayDays )
 +                                              .map( function ( num ) {
 +                                                      return controller._createFilterDataFromNumber(
 +                                                              num,
 +                                                              // Convert fractions of days to number of hours for the labels
 +                                                              num < 1 ? Math.round( num * 24 ) : num
 +                                                      );
 +                                              } )
                                }
                        ]
                };
  
+               views.display = {
+                       groups: [
+                               {
+                                       name: 'display',
+                                       type: 'boolean',
+                                       title: '', // Because it's a hidden group, this title actually appears nowhere
+                                       hidden: true,
+                                       isSticky: true,
+                                       filters: [
+                                               {
+                                                       name: 'enhanced',
+                                                       'default': String( mw.user.options.get( 'usenewrc', 0 ) )
+                                               }
+                                       ]
+                               }
+                       ]
+               };
                // Before we do anything, we need to see if we require additional items in the
                // groups that have 'AllowArbitrary'. For the moment, those are only single_option
                // groups; if we ever expand it, this might need further generalization:
  
                arbitraryValues = Array.isArray( arbitraryValues ) ? arbitraryValues : [ arbitraryValues ];
  
 +              // Normalize the arbitrary values
 +              if ( groupData.range ) {
 +                      arbitraryValues = arbitraryValues.map( function ( val ) {
 +                              if ( val < 0 ) {
 +                                      return groupData.range.min; // Min
 +                              } else if ( val >= groupData.range.max ) {
 +                                      return groupData.range.max; // Max
 +                              }
 +                              return val;
 +                      } );
 +              }
 +
                // This is only true for single_option group
                // We assume these are the only groups that will allow for
                // arbitrary, since it doesn't make any sense for the other
                                // but if that value isn't already in the definition
                                groupData.filters
                                        .map( function ( filterData ) {
 -                                              return filterData.name;
 +                                              return String( filterData.name );
                                        } )
 -                                      .indexOf( val ) === -1
 +                                      .indexOf( String( val ) ) === -1
                        ) {
                                // Add the filter information
                                groupData.filters.push( controller._createFilterDataFromNumber(
         */
        mw.rcfilters.Controller.prototype.toggleInvertedNamespaces = function () {
                this.filtersModel.toggleInvertedNamespaces();
 -              this.updateChangesList();
 +
 +              if (
 +                      this.filtersModel.getFiltersByView( 'namespaces' )
 +                              .filter( function ( filterItem ) {
 +                                      return filterItem.isSelected();
 +                              } )
 +                              .length
 +              ) {
 +                      // Only re-fetch results if there are namespace items that are actually selected
 +                      this.updateChangesList();
 +              }
        };
  
        /**
         */
        mw.rcfilters.Controller.prototype.applySavedQuery = function ( queryID ) {
                var data, highlights,
 -                      queryItem = this.savedQueriesModel.getItemByID( queryID );
 +                      queryItem = this.savedQueriesModel.getItemByID( queryID ),
 +                      currentMatchingQuery = this.findQueryMatchingCurrentState();
  
 -              if ( queryItem ) {
 +              if (
 +                      queryItem &&
 +                      (
 +                              // If there's already a query, don't reload it
 +                              // if it's the same as the one that already exists
 +                              !currentMatchingQuery ||
 +                              currentMatchingQuery.getID() !== queryItem.getID()
 +                      )
 +              ) {
                        data = queryItem.getData();
                        highlights = data.highlights;
  
                // the initial defaults or from the URL value that is being normalized
                this.updateDaysDefault( this.filtersModel.getGroup( 'days' ).getSelectedItems()[ 0 ].getParamName() );
                this.updateLimitDefault( this.filtersModel.getGroup( 'limit' ).getSelectedItems()[ 0 ].getParamName() );
+               // TODO: Make these automatic by having the model go over sticky
+               // items and update their default values automatically
        };
  
        /**
         * Update the limit default value
         *
 -       * @param {number} newValue New value
 +       * param {number} newValue New value
         */
 -      mw.rcfilters.Controller.prototype.updateLimitDefault = function ( newValue ) {
 +      mw.rcfilters.Controller.prototype.updateLimitDefault = function ( /* newValue */ ) {
 +              // HACK: Temporarily remove this from being sticky
 +              // See T172156
 +
 +              /*
                if ( !$.isNumeric( newValue ) ) {
                        return;
                }
                        // Update the preference for this session
                        mw.user.options.set( 'rcfilters-rclimit', newValue );
                }
 +              */
 +              return;
        };
  
        /**
         * Update the days default value
         *
 -       * @param {number} newValue New value
 +       * param {number} newValue New value
         */
 -      mw.rcfilters.Controller.prototype.updateDaysDefault = function ( newValue ) {
 +      mw.rcfilters.Controller.prototype.updateDaysDefault = function ( /* newValue */ ) {
 +              // HACK: Temporarily remove this from being sticky
 +              // See T172156
 +
 +              /*
                if ( !$.isNumeric( newValue ) ) {
                        return;
                }
                        // Update the preference for this session
                        mw.user.options.set( 'rcdays', newValue );
                }
 +              */
 +              return;
        };
  
+       /**
+        * Update the group by page default value
+        *
+        * @param {number} newValue New value
+        */
+       mw.rcfilters.Controller.prototype.updateGroupByPageDefault = function ( newValue ) {
+               if ( !$.isNumeric( newValue ) ) {
+                       return;
+               }
+               newValue = Number( newValue );
+               if ( mw.user.options.get( 'usenewrc' ) !== newValue ) {
+                       // Save the preference
+                       new mw.Api().saveOption( 'usenewrc', newValue );
+                       // Update the preference for this session
+                       mw.user.options.set( 'usenewrc', newValue );
+               }
+       };
        /**
         * Synchronize the URL with the current state of the filters
         * without adding an history entry.