RCFilters: fix call to changesListModel.update()
[lhc/web/wiklou.git] / resources / src / mediawiki.rcfilters / mw.rcfilters.Controller.js
index 0b2dd8d..5386291 100644 (file)
         * @param {Object} [tagList] Tag definition
         */
        mw.rcfilters.Controller.prototype.initialize = function ( filterStructure, namespaceStructure, tagList ) {
-               var parsedSavedQueries,
+               var parsedSavedQueries, pieces,
                        displayConfig = mw.config.get( 'StructuredChangeFiltersDisplayConfig' ),
                        defaultSavedQueryExists = mw.config.get( 'wgStructuredChangeFiltersDefaultSavedQueryExists' ),
                        controller = this,
                        views = {},
                        items = [],
-                       uri = new mw.Uri(),
-                       $changesList = $( '.mw-changeslist' ).first().contents();
+                       uri = new mw.Uri();
 
                // Prepare views
                if ( namespaceStructure ) {
                        // again
                        this.updateStateFromUrl( false );
 
+                       pieces = this._extractChangesListInfo( $( '#mw-content-text' ) );
+
                        // Update the changes list with the existing data
                        // so it gets processed
                        this.changesListModel.update(
-                               $changesList.length ? $changesList : 'NO_RESULTS',
-                               $( 'fieldset.cloptions' ).first(),
+                               pieces.changes,
+                               pieces.fieldset,
+                               pieces.noResultsDetails,
                                true // We're using existing DOM elements
                        );
                }
                }
        };
 
+       /**
+        * Extracts information from the changes list DOM
+        *
+        * @param {jQuery} $root Root DOM to find children from
+        * @return {Object} Information about changes list
+        * @return {Object|string} return.changes Changes list, or 'NO_RESULTS' if there are no results
+        *   (either normally or as an error)
+        * @return {string} [return.noResultsDetails] 'NO_RESULTS_NORMAL' for a normal 0-result set,
+        *   'NO_RESULTS_TIMEOUT' for no results due to a timeout, or omitted for more than 0 results
+        * @return {jQuery} return.fieldset Fieldset
+        */
+       mw.rcfilters.Controller.prototype._extractChangesListInfo = function ( $root ) {
+               var info, isTimeout,
+                       $changesListContents = $root.find( '.mw-changeslist' ).first().contents(),
+                       areResults = !!$changesListContents.length;
+
+               info = {
+                       changes: $changesListContents.length ? $changesListContents : 'NO_RESULTS',
+                       fieldset: $root.find( 'fieldset.cloptions' ).first()
+               };
+
+               if ( !areResults ) {
+                       isTimeout = !!$root.find( '.mw-changeslist-timeout' ).length;
+                       info.noResultsDetails = isTimeout ? 'NO_RESULTS_TIMEOUT' : 'NO_RESULTS_NORMAL';
+               }
+
+               return info;
+       };
+
        /**
         * Create filter data from a number, for the filters that are numerical value
         *
         * Reset to default filters
         */
        mw.rcfilters.Controller.prototype.resetToDefaults = function () {
-               this.filtersModel.updateStateFromParams( this._getDefaultParams() );
-
-               this.updateChangesList();
+               if ( this.applyParamChange( this._getDefaultParams() ) ) {
+                       // Only update the changes list if there was a change to actual filters
+                       this.updateChangesList();
+               }
        };
 
        /**
         * Empty all selected filters
         */
        mw.rcfilters.Controller.prototype.emptyFilters = function () {
-               var highlightedFilterNames = this.filtersModel
-                       .getHighlightedItems()
+               var highlightedFilterNames = this.filtersModel.getHighlightedItems()
                        .map( function ( filterItem ) { return { name: filterItem.getName() }; } );
 
-               this.filtersModel.updateStateFromParams( {} );
-
-               this.updateChangesList();
+               if ( this.applyParamChange( {} ) ) {
+                       // Only update the changes list if there was a change to actual filters
+                       this.updateChangesList();
+               }
 
                if ( highlightedFilterNames ) {
                        this._trackHighlight( 'clearAll', highlightedFilterNames );
                        return;
                }
 
-               // Apply parameters to model
-               this.filtersModel.updateStateFromParams( params );
-
-               this.updateChangesList();
+               if ( this.applyParamChange( params ) ) {
+                       // Update changes list only if there was a difference in filter selection
+                       this.updateChangesList();
+               }
 
                // Log filter grouping
                this.trackFilterGroupings( 'savedfilters' );
         * Check whether the current filter and highlight state exists
         * in the saved queries model.
         *
-        * @return {boolean} Query exists
+        * @return {mw.rcfilters.dm.SavedQueryItemModel} Matching item model
         */
        mw.rcfilters.Controller.prototype.findQueryMatchingCurrentState = function () {
                return this.savedQueriesModel.findMatchingQuery(
         * without adding an history entry.
         */
        mw.rcfilters.Controller.prototype.replaceUrl = function () {
-               this.uriProcessor.replaceUpdatedUri();
+               this.uriProcessor.updateURL();
        };
 
        /**
                                        this.changesListModel.update(
                                                $changesListContent,
                                                $fieldset,
+                                               pieces.noResultsDetails,
                                                false,
                                                // separator between old and new changes
                                                updateMode === this.SHOW_NEW_CHANGES || updateMode === this.LIVE_UPDATE
                return this._queryChangesList( 'updateChangesList' )
                        .then(
                                function ( data ) {
-                                       var $parsed = $( '<div>' ).append( $( $.parseHTML( data.content ) ) ),
-                                               pieces = {
-                                                       // Changes list
-                                                       changes: $parsed.find( '.mw-changeslist' ).first().contents(),
-                                                       // Fieldset
-                                                       fieldset: $parsed.find( 'fieldset.cloptions' ).first()
+                                       var $parsed;
+
+                                       // Status code 0 is not HTTP status code,
+                                       // but is valid value of XMLHttpRequest status.
+                                       // It is used for variety of network errors, for example
+                                       // when an AJAX call was cancelled before getting the response
+                                       if ( data && data.status === 0 ) {
+                                               return {
+                                                       changes: 'NO_RESULTS',
+                                                       // We need empty result set, to avoid exceptions because of undefined value
+                                                       fieldset: $( [] ),
+                                                       noResultsDetails: 'NO_RESULTS_NETWORK_ERROR'
                                                };
-
-                                       if ( pieces.changes.length === 0 ) {
-                                               pieces.changes = 'NO_RESULTS';
                                        }
 
-                                       return pieces;
-                               }
+                                       $parsed = $( '<div>' ).append( $( $.parseHTML( data.content ) ) );
+
+                                       return this._extractChangesListInfo( $parsed );
+
+                               }.bind( this )
                        );
        };
 
                }
        };
 
+       /**
+        * Apply a change of parameters to the model state, and check whether
+        * the new state is different than the old state.
+        *
+        * @param  {Object} newParamState New parameter state to apply
+        * @return {boolean} New applied model state is different than the previous state
+        */
+       mw.rcfilters.Controller.prototype.applyParamChange = function ( newParamState ) {
+               var after,
+                       before = this.filtersModel.getSelectedState();
+
+               this.filtersModel.updateStateFromParams( newParamState );
+
+               after = this.filtersModel.getSelectedState();
+
+               return !OO.compare( before, after );
+       };
+
        /**
         * Mark all changes as seen on Watchlist
         */