diff --git a/modules/ext.RevisionSlider.Api.js b/modules/ext.RevisionSlider.Api.js index 24f9fd9a..318c8937 100644 --- a/modules/ext.RevisionSlider.Api.js +++ b/modules/ext.RevisionSlider.Api.js @@ -14,19 +14,27 @@ * Fetches a batch of revision data, including a gender setting for users who edited the revision * * @param {string} pageName - * @param {Object} options - Options containing callbacks for `success` and `error` as well as - * optional fields for: `dir (defaults to `older`), `limit` (defaults to 500), `startId`, `endId`, - * `knownUserGenders` + * @param {Object} options Options + * @param {string} [options.dir='older'] Sort direction + * @param {number} [options.limit=500] Result limit + * @param {number} [options.startId] Start ID + * @param {number} [options.endId] End ID + * @param {Object} [options.knownUserGenders] Known user genders */ fetchRevisionData: function ( pageName, options ) { - var self = this; - this.fetchRevisions( pageName, options ) + var xhr, userXhr, + deferred = $.Deferred(), + self = this; + + options = options || {}; + + xhr = this.fetchRevisions( pageName, options ) .done( function ( data ) { var revs = data.query.pages[ 0 ].revisions, /*jshint -W024 */ revContinue = data.continue, /*jshint +W024 */ - genderData = typeof options.knownUserGenders !== 'undefined' ? options.knownUserGenders : {}, + genderData = options.knownUserGenders || {}, userNames; if ( !revs ) { @@ -35,7 +43,7 @@ userNames = self.getUserNames( revs, genderData ); - self.fetchUserGenderData( userNames ) + userXhr = self.fetchUserGenderData( userNames ) .done( function ( data ) { var users = typeof data !== 'undefined' ? data.query.users : []; @@ -49,34 +57,49 @@ } } ); - options.success( { revisions: revs, 'continue': revContinue } ); + deferred.resolve( { revisions: revs, 'continue': revContinue } ); } ) - .fail( options.error ); + .fail( deferred.reject ); } ) - .fail( options.error ); + .fail( deferred.reject ); + + return deferred.promise( { + abort: function () { + xhr.abort(); + if ( userXhr ) { + userXhr.abort(); + } + } + } ); }, /** * Fetches up to 500 revisions at a time * * @param {string} pageName - * @param {Object} options object containing optional options, fields: `dir` (defaults to `older`), - * `limit` (defaults to 500), `startId`, `endId` - * @return {jQuery} + * @param {Object} [options] Options + * @param {string} [options.dir='older'] Sort direction + * @param {number} [options.limit=500] Result limit + * @param {number} [options.startId] Start ID + * @param {number} [options.endId] End ID + * @return {jQuery.jqXHR} */ fetchRevisions: function ( pageName, options ) { - var dir = options.dir !== undefined ? options.dir : 'older', - data = { - action: 'query', - prop: 'revisions', - format: 'json', - rvprop: 'ids|timestamp|user|comment|parsedcomment|size|flags', - titles: pageName, - formatversion: 2, - 'continue': '', - rvlimit: 500, - rvdir: dir - }; + var dir, data; + + options = options || {}; + dir = options.dir !== undefined ? options.dir : 'older'; + data = { + action: 'query', + prop: 'revisions', + format: 'json', + rvprop: 'ids|timestamp|user|comment|parsedcomment|size|flags', + titles: pageName, + formatversion: 2, + 'continue': '', + rvlimit: 500, + rvdir: dir + }; if ( options.startId !== undefined ) { data.rvstartid = options.startId; @@ -98,7 +121,7 @@ * Fetches gender data for up to 500 user names * * @param {string[]} users - * @return {jQuery} + * @return {jQuery.jqXHR} */ fetchUserGenderData: function ( users ) { if ( users.length === 0 ) { @@ -118,7 +141,7 @@ }, /** - * @param {Array} revs + * @param {Object[]} revs * @param {Object} knownUserGenders * @return {string[]} */ @@ -132,7 +155,7 @@ }, /** - * @param {Array} data + * @param {Object[]} data * @return {Object} */ getUserGenderData: function ( data ) { diff --git a/modules/ext.RevisionSlider.DiffPage.js b/modules/ext.RevisionSlider.DiffPage.js index c020c5b8..f72b0007 100644 --- a/modules/ext.RevisionSlider.DiffPage.js +++ b/modules/ext.RevisionSlider.DiffPage.js @@ -5,6 +5,7 @@ * @constructor */ var DiffPage = function () { + this.lastRequest = null; }; $.extend( DiffPage.prototype, { @@ -13,45 +14,58 @@ * * @param {number} revId1 * @param {number} revId2 + * @param {number} [retryAttempt=0] */ - refresh: function ( revId1, revId2 ) { - var data = { - diff: Math.max( revId1, revId2 ), - oldid: Math.min( revId1, revId2 ) - }, + refresh: function ( revId1, revId2, retryAttempt ) { + var self = this, + retryLimit = 2, + data = { + diff: Math.max( revId1, revId2 ), + oldid: Math.min( revId1, revId2 ) + }, params = this.getExtraDiffPageParams(); + + retryAttempt = retryAttempt || 0; + if ( Object.keys( params ).length > 0 ) { $.extend( data, params ); } + + if ( this.lastRequest ) { + this.lastRequest.abort(); + } + $( 'table.diff[data-mw="interface"]' ) .append( $( '' ) ) .append( $( '' ) ) .append( $( '
' ).addClass( 'mw-revslider-darkness' ) ); - $.ajax( { + + this.lastRequest = $.ajax( { url: mw.util.wikiScript( 'index' ), data: data, - tryCount: 0, - retryLimit: 2, - success: function ( data ) { - var $container = $( '.mw-revslider-container' ), - $contentText = $( '#mw-content-text' ), - scrollLeft = $container.find( '.mw-revslider-revisions-container' ).scrollLeft(); + tryCount: 0 + } ); + // Don't chain, so lastRequest is a jQuery.jqXHR object + this.lastRequest.then( function ( data ) { + var $data, + $container = $( '.mw-revslider-container' ), + $contentText = $( '#mw-content-text' ), + scrollLeft = $container.find( '.mw-revslider-revisions-container' ).scrollLeft(); - data = $( data ); - data.find( '.mw-revslider-container' ) - .replaceWith( $container ); - $contentText.html( data.find( '#mw-content-text' ) ) - .find( '.mw-revslider-revisions-container' ).scrollLeft( scrollLeft ); + $data = $( data ); + $data.find( '.mw-revslider-container' ).replaceWith( $container ); + $contentText.html( $data.find( '#mw-content-text' ) ) + .find( '.mw-revslider-revisions-container' ).scrollLeft( scrollLeft ); - mw.hook( 'wikipage.content' ).fire( $contentText ); - }, - error: function ( err ) { + mw.hook( 'wikipage.content' ).fire( $contentText ); + }, function ( xhr ) { + $( 'table.diff[data-mw="interface"] .mw-revslider-darkness' ).remove(); + if ( xhr.statusText !== 'abort' ) { this.tryCount++; - console.log( err ); mw.track( 'counter.MediaWiki.RevisionSlider.error.refresh' ); - if ( this.tryCount <= this.retryLimit ) { + if ( retryAttempt <= retryLimit ) { console.log( 'Retrying request' ); - $.ajax( this ); + self.refresh( revId1, revId2, retryAttempt + 1 ); } // TODO notify the user that we failed to update the diff? // This could also attempt to reload the page with the correct diff loaded without ajax? diff --git a/modules/ext.RevisionSlider.SliderView.js b/modules/ext.RevisionSlider.SliderView.js index 1f48dc5c..de3a15fd 100644 --- a/modules/ext.RevisionSlider.SliderView.js +++ b/modules/ext.RevisionSlider.SliderView.js @@ -586,22 +586,21 @@ startId: revisions[ revisions.length - 1 ].getId(), dir: 'newer', limit: revisionCount + 1, - knownUserGenders: this.slider.getRevisions().getUserGenders(), - success: function ( data ) { - revs = data.revisions.slice( 1 ); - if ( revs.length === 0 ) { - self.noMoreNewerRevisions = true; - return; - } - - self.addRevisionsAtEnd( $slider, revs ); - - /*jshint -W024 */ - if ( data.continue === undefined ) { - self.noMoreNewerRevisions = true; - } - /*jshint +W024 */ + knownUserGenders: this.slider.getRevisions().getUserGenders() + } ).then( function ( data ) { + revs = data.revisions.slice( 1 ); + if ( revs.length === 0 ) { + self.noMoreNewerRevisions = true; + return; } + + self.addRevisionsAtEnd( $slider, revs ); + + /*jshint -W024 */ + if ( data.continue === undefined ) { + self.noMoreNewerRevisions = true; + } + /*jshint +W024 */ } ); }, @@ -624,26 +623,25 @@ // fetch an extra revision if there are more older revision than the current "window", // this makes it possible to correctly set a size of the bar related to the oldest revision to add limit: revisionCount + 2, - knownUserGenders: this.slider.getRevisions().getUserGenders(), - success: function ( data ) { - revs = data.revisions.slice( 1 ).reverse(); - if ( revs.length === 0 ) { - self.noMoreOlderRevisions = true; - return; - } - - if ( revs.length === revisionCount + 1 ) { - precedingRevisionSize = revs[ 0 ].size; - revs = revs.slice( 1 ); - } - self.addRevisionsAtStart( $slider, revs, precedingRevisionSize ); - - /*jshint -W024 */ - if ( data.continue === undefined ) { - self.noMoreOlderRevisions = true; - } - /*jshint +W024 */ + knownUserGenders: this.slider.getRevisions().getUserGenders() + } ).then( function ( data ) { + revs = data.revisions.slice( 1 ).reverse(); + if ( revs.length === 0 ) { + self.noMoreOlderRevisions = true; + return; } + + if ( revs.length === revisionCount + 1 ) { + precedingRevisionSize = revs[ 0 ].size; + revs = revs.slice( 1 ); + } + self.addRevisionsAtStart( $slider, revs, precedingRevisionSize ); + + /*jshint -W024 */ + if ( data.continue === undefined ) { + self.noMoreOlderRevisions = true; + } + /*jshint +W024 */ } ); }, diff --git a/modules/ext.RevisionSlider.init.js b/modules/ext.RevisionSlider.init.js index 8a1e367a..204f69d9 100644 --- a/modules/ext.RevisionSlider.init.js +++ b/modules/ext.RevisionSlider.init.js @@ -13,48 +13,45 @@ api.fetchRevisionData( mw.config.get( 'wgPageName' ), { startId: mw.config.values.extRevisionSliderNewRev, - limit: mw.libs.revisionSlider.calculateRevisionsPerWindow( 160, 16 ), + limit: mw.libs.revisionSlider.calculateRevisionsPerWindow( 160, 16 ) + } ).then( function ( data ) { + var revs, + revisionList, + $container, + slider; - success: function ( data ) { - var revs, - revisionList, - $container, - slider; + mw.track( 'timing.MediaWiki.RevisionSlider.timing.initFetchRevisionData', mw.now() - startTime ); - mw.track( 'timing.MediaWiki.RevisionSlider.timing.initFetchRevisionData', mw.now() - startTime ); + try { + revs = data.revisions; + revs.reverse(); - try { - revs = data.revisions; - revs.reverse(); + revisionList = new mw.libs.revisionSlider.RevisionList( mw.libs.revisionSlider.makeRevisions( revs ) ); - revisionList = new mw.libs.revisionSlider.RevisionList( mw.libs.revisionSlider.makeRevisions( revs ) ); + $container = $( '.mw-revslider-slider-wrapper' ); + slider = new mw.libs.revisionSlider.Slider( revisionList ); + slider.getView().render( $container ); - $container = $( '.mw-revslider-slider-wrapper' ); - slider = new mw.libs.revisionSlider.Slider( revisionList ); - slider.getView().render( $container ); - - if ( !mw.user.options.get( 'userjs-revslider-hidehelp' ) ) { - mw.libs.revisionSlider.HelpDialog.show(); - ( new mw.Api() ).saveOption( 'userjs-revslider-hidehelp', true ); - } - - $( '.mw-revslider-placeholder' ).remove(); - mw.track( 'timing.MediaWiki.RevisionSlider.timing.init', mw.now() - startTime ); - } catch ( err ) { - $( '.mw-revslider-placeholder' ) - .text( mw.message( 'revisionslider-loading-failed' ).text() ); - console.log( err ); - mw.track( 'counter.MediaWiki.RevisionSlider.error.init' ); + if ( !mw.user.options.get( 'userjs-revslider-hidehelp' ) ) { + mw.libs.revisionSlider.HelpDialog.show(); + ( new mw.Api() ).saveOption( 'userjs-revslider-hidehelp', true ); } - initialized = true; - }, - error: function ( err ) { + $( '.mw-revslider-placeholder' ).remove(); + mw.track( 'timing.MediaWiki.RevisionSlider.timing.init', mw.now() - startTime ); + } catch ( err ) { $( '.mw-revslider-placeholder' ) .text( mw.message( 'revisionslider-loading-failed' ).text() ); console.log( err ); mw.track( 'counter.MediaWiki.RevisionSlider.error.init' ); } + + initialized = true; + }, function ( err ) { + $( '.mw-revslider-placeholder' ) + .text( mw.message( 'revisionslider-loading-failed' ).text() ); + console.log( err ); + mw.track( 'counter.MediaWiki.RevisionSlider.error.init' ); } ); };