mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/RevisionSlider
synced 2024-11-15 03:33:45 +00:00
Abort pending requests
Ensure all requests are abortable promises, and abort if a new, conflicting request is made. Change-Id: Ie05142f6da8cba6dde4f73c1b22960b726af4764
This commit is contained in:
parent
f6a44f43fe
commit
6997f135db
|
@ -14,19 +14,27 @@
|
||||||
* Fetches a batch of revision data, including a gender setting for users who edited the revision
|
* Fetches a batch of revision data, including a gender setting for users who edited the revision
|
||||||
*
|
*
|
||||||
* @param {string} pageName
|
* @param {string} pageName
|
||||||
* @param {Object} options - Options containing callbacks for `success` and `error` as well as
|
* @param {Object} options Options
|
||||||
* optional fields for: `dir (defaults to `older`), `limit` (defaults to 500), `startId`, `endId`,
|
* @param {string} [options.dir='older'] Sort direction
|
||||||
* `knownUserGenders`
|
* @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 ) {
|
fetchRevisionData: function ( pageName, options ) {
|
||||||
var self = this;
|
var xhr, userXhr,
|
||||||
this.fetchRevisions( pageName, options )
|
deferred = $.Deferred(),
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
xhr = this.fetchRevisions( pageName, options )
|
||||||
.done( function ( data ) {
|
.done( function ( data ) {
|
||||||
var revs = data.query.pages[ 0 ].revisions,
|
var revs = data.query.pages[ 0 ].revisions,
|
||||||
/*jshint -W024 */
|
/*jshint -W024 */
|
||||||
revContinue = data.continue,
|
revContinue = data.continue,
|
||||||
/*jshint +W024 */
|
/*jshint +W024 */
|
||||||
genderData = typeof options.knownUserGenders !== 'undefined' ? options.knownUserGenders : {},
|
genderData = options.knownUserGenders || {},
|
||||||
userNames;
|
userNames;
|
||||||
|
|
||||||
if ( !revs ) {
|
if ( !revs ) {
|
||||||
|
@ -35,7 +43,7 @@
|
||||||
|
|
||||||
userNames = self.getUserNames( revs, genderData );
|
userNames = self.getUserNames( revs, genderData );
|
||||||
|
|
||||||
self.fetchUserGenderData( userNames )
|
userXhr = self.fetchUserGenderData( userNames )
|
||||||
.done( function ( data ) {
|
.done( function ( data ) {
|
||||||
var users = typeof data !== 'undefined' ? data.query.users : [];
|
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
|
* Fetches up to 500 revisions at a time
|
||||||
*
|
*
|
||||||
* @param {string} pageName
|
* @param {string} pageName
|
||||||
* @param {Object} options object containing optional options, fields: `dir` (defaults to `older`),
|
* @param {Object} [options] Options
|
||||||
* `limit` (defaults to 500), `startId`, `endId`
|
* @param {string} [options.dir='older'] Sort direction
|
||||||
* @return {jQuery}
|
* @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 ) {
|
fetchRevisions: function ( pageName, options ) {
|
||||||
var dir = options.dir !== undefined ? options.dir : 'older',
|
var dir, data;
|
||||||
data = {
|
|
||||||
action: 'query',
|
options = options || {};
|
||||||
prop: 'revisions',
|
dir = options.dir !== undefined ? options.dir : 'older';
|
||||||
format: 'json',
|
data = {
|
||||||
rvprop: 'ids|timestamp|user|comment|parsedcomment|size|flags',
|
action: 'query',
|
||||||
titles: pageName,
|
prop: 'revisions',
|
||||||
formatversion: 2,
|
format: 'json',
|
||||||
'continue': '',
|
rvprop: 'ids|timestamp|user|comment|parsedcomment|size|flags',
|
||||||
rvlimit: 500,
|
titles: pageName,
|
||||||
rvdir: dir
|
formatversion: 2,
|
||||||
};
|
'continue': '',
|
||||||
|
rvlimit: 500,
|
||||||
|
rvdir: dir
|
||||||
|
};
|
||||||
|
|
||||||
if ( options.startId !== undefined ) {
|
if ( options.startId !== undefined ) {
|
||||||
data.rvstartid = options.startId;
|
data.rvstartid = options.startId;
|
||||||
|
@ -98,7 +121,7 @@
|
||||||
* Fetches gender data for up to 500 user names
|
* Fetches gender data for up to 500 user names
|
||||||
*
|
*
|
||||||
* @param {string[]} users
|
* @param {string[]} users
|
||||||
* @return {jQuery}
|
* @return {jQuery.jqXHR}
|
||||||
*/
|
*/
|
||||||
fetchUserGenderData: function ( users ) {
|
fetchUserGenderData: function ( users ) {
|
||||||
if ( users.length === 0 ) {
|
if ( users.length === 0 ) {
|
||||||
|
@ -118,7 +141,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array} revs
|
* @param {Object[]} revs
|
||||||
* @param {Object} knownUserGenders
|
* @param {Object} knownUserGenders
|
||||||
* @return {string[]}
|
* @return {string[]}
|
||||||
*/
|
*/
|
||||||
|
@ -132,7 +155,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array} data
|
* @param {Object[]} data
|
||||||
* @return {Object}
|
* @return {Object}
|
||||||
*/
|
*/
|
||||||
getUserGenderData: function ( data ) {
|
getUserGenderData: function ( data ) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
var DiffPage = function () {
|
var DiffPage = function () {
|
||||||
|
this.lastRequest = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
$.extend( DiffPage.prototype, {
|
$.extend( DiffPage.prototype, {
|
||||||
|
@ -13,45 +14,58 @@
|
||||||
*
|
*
|
||||||
* @param {number} revId1
|
* @param {number} revId1
|
||||||
* @param {number} revId2
|
* @param {number} revId2
|
||||||
|
* @param {number} [retryAttempt=0]
|
||||||
*/
|
*/
|
||||||
refresh: function ( revId1, revId2 ) {
|
refresh: function ( revId1, revId2, retryAttempt ) {
|
||||||
var data = {
|
var self = this,
|
||||||
diff: Math.max( revId1, revId2 ),
|
retryLimit = 2,
|
||||||
oldid: Math.min( revId1, revId2 )
|
data = {
|
||||||
},
|
diff: Math.max( revId1, revId2 ),
|
||||||
|
oldid: Math.min( revId1, revId2 )
|
||||||
|
},
|
||||||
params = this.getExtraDiffPageParams();
|
params = this.getExtraDiffPageParams();
|
||||||
|
|
||||||
|
retryAttempt = retryAttempt || 0;
|
||||||
|
|
||||||
if ( Object.keys( params ).length > 0 ) {
|
if ( Object.keys( params ).length > 0 ) {
|
||||||
$.extend( data, params );
|
$.extend( data, params );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( this.lastRequest ) {
|
||||||
|
this.lastRequest.abort();
|
||||||
|
}
|
||||||
|
|
||||||
$( 'table.diff[data-mw="interface"]' )
|
$( 'table.diff[data-mw="interface"]' )
|
||||||
.append( $( '<tr>' ) )
|
.append( $( '<tr>' ) )
|
||||||
.append( $( '<td>' ) )
|
.append( $( '<td>' ) )
|
||||||
.append( $( '<div>' ).addClass( 'mw-revslider-darkness' ) );
|
.append( $( '<div>' ).addClass( 'mw-revslider-darkness' ) );
|
||||||
$.ajax( {
|
|
||||||
|
this.lastRequest = $.ajax( {
|
||||||
url: mw.util.wikiScript( 'index' ),
|
url: mw.util.wikiScript( 'index' ),
|
||||||
data: data,
|
data: data,
|
||||||
tryCount: 0,
|
tryCount: 0
|
||||||
retryLimit: 2,
|
} );
|
||||||
success: function ( data ) {
|
// Don't chain, so lastRequest is a jQuery.jqXHR object
|
||||||
var $container = $( '.mw-revslider-container' ),
|
this.lastRequest.then( function ( data ) {
|
||||||
$contentText = $( '#mw-content-text' ),
|
var $data,
|
||||||
scrollLeft = $container.find( '.mw-revslider-revisions-container' ).scrollLeft();
|
$container = $( '.mw-revslider-container' ),
|
||||||
|
$contentText = $( '#mw-content-text' ),
|
||||||
|
scrollLeft = $container.find( '.mw-revslider-revisions-container' ).scrollLeft();
|
||||||
|
|
||||||
data = $( data );
|
$data = $( data );
|
||||||
data.find( '.mw-revslider-container' )
|
$data.find( '.mw-revslider-container' ).replaceWith( $container );
|
||||||
.replaceWith( $container );
|
$contentText.html( $data.find( '#mw-content-text' ) )
|
||||||
$contentText.html( data.find( '#mw-content-text' ) )
|
.find( '.mw-revslider-revisions-container' ).scrollLeft( scrollLeft );
|
||||||
.find( '.mw-revslider-revisions-container' ).scrollLeft( scrollLeft );
|
|
||||||
|
|
||||||
mw.hook( 'wikipage.content' ).fire( $contentText );
|
mw.hook( 'wikipage.content' ).fire( $contentText );
|
||||||
},
|
}, function ( xhr ) {
|
||||||
error: function ( err ) {
|
$( 'table.diff[data-mw="interface"] .mw-revslider-darkness' ).remove();
|
||||||
|
if ( xhr.statusText !== 'abort' ) {
|
||||||
this.tryCount++;
|
this.tryCount++;
|
||||||
console.log( err );
|
|
||||||
mw.track( 'counter.MediaWiki.RevisionSlider.error.refresh' );
|
mw.track( 'counter.MediaWiki.RevisionSlider.error.refresh' );
|
||||||
if ( this.tryCount <= this.retryLimit ) {
|
if ( retryAttempt <= retryLimit ) {
|
||||||
console.log( 'Retrying request' );
|
console.log( 'Retrying request' );
|
||||||
$.ajax( this );
|
self.refresh( revId1, revId2, retryAttempt + 1 );
|
||||||
}
|
}
|
||||||
// TODO notify the user that we failed to update the diff?
|
// 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?
|
// This could also attempt to reload the page with the correct diff loaded without ajax?
|
||||||
|
|
|
@ -586,22 +586,21 @@
|
||||||
startId: revisions[ revisions.length - 1 ].getId(),
|
startId: revisions[ revisions.length - 1 ].getId(),
|
||||||
dir: 'newer',
|
dir: 'newer',
|
||||||
limit: revisionCount + 1,
|
limit: revisionCount + 1,
|
||||||
knownUserGenders: this.slider.getRevisions().getUserGenders(),
|
knownUserGenders: this.slider.getRevisions().getUserGenders()
|
||||||
success: function ( data ) {
|
} ).then( function ( data ) {
|
||||||
revs = data.revisions.slice( 1 );
|
revs = data.revisions.slice( 1 );
|
||||||
if ( revs.length === 0 ) {
|
if ( revs.length === 0 ) {
|
||||||
self.noMoreNewerRevisions = true;
|
self.noMoreNewerRevisions = true;
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
self.addRevisionsAtEnd( $slider, revs );
|
|
||||||
|
|
||||||
/*jshint -W024 */
|
|
||||||
if ( data.continue === undefined ) {
|
|
||||||
self.noMoreNewerRevisions = true;
|
|
||||||
}
|
|
||||||
/*jshint +W024 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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",
|
// 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
|
// this makes it possible to correctly set a size of the bar related to the oldest revision to add
|
||||||
limit: revisionCount + 2,
|
limit: revisionCount + 2,
|
||||||
knownUserGenders: this.slider.getRevisions().getUserGenders(),
|
knownUserGenders: this.slider.getRevisions().getUserGenders()
|
||||||
success: function ( data ) {
|
} ).then( function ( data ) {
|
||||||
revs = data.revisions.slice( 1 ).reverse();
|
revs = data.revisions.slice( 1 ).reverse();
|
||||||
if ( revs.length === 0 ) {
|
if ( revs.length === 0 ) {
|
||||||
self.noMoreOlderRevisions = true;
|
self.noMoreOlderRevisions = true;
|
||||||
return;
|
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 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
} );
|
} );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -13,48 +13,45 @@
|
||||||
|
|
||||||
api.fetchRevisionData( mw.config.get( 'wgPageName' ), {
|
api.fetchRevisionData( mw.config.get( 'wgPageName' ), {
|
||||||
startId: mw.config.values.extRevisionSliderNewRev,
|
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 ) {
|
mw.track( 'timing.MediaWiki.RevisionSlider.timing.initFetchRevisionData', mw.now() - startTime );
|
||||||
var revs,
|
|
||||||
revisionList,
|
|
||||||
$container,
|
|
||||||
slider;
|
|
||||||
|
|
||||||
mw.track( 'timing.MediaWiki.RevisionSlider.timing.initFetchRevisionData', mw.now() - startTime );
|
try {
|
||||||
|
revs = data.revisions;
|
||||||
|
revs.reverse();
|
||||||
|
|
||||||
try {
|
revisionList = new mw.libs.revisionSlider.RevisionList( mw.libs.revisionSlider.makeRevisions( revs ) );
|
||||||
revs = data.revisions;
|
|
||||||
revs.reverse();
|
|
||||||
|
|
||||||
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' );
|
if ( !mw.user.options.get( 'userjs-revslider-hidehelp' ) ) {
|
||||||
slider = new mw.libs.revisionSlider.Slider( revisionList );
|
mw.libs.revisionSlider.HelpDialog.show();
|
||||||
slider.getView().render( $container );
|
( new mw.Api() ).saveOption( 'userjs-revslider-hidehelp', true );
|
||||||
|
|
||||||
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' );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
$( '.mw-revslider-placeholder' ).remove();
|
||||||
},
|
mw.track( 'timing.MediaWiki.RevisionSlider.timing.init', mw.now() - startTime );
|
||||||
error: function ( err ) {
|
} catch ( err ) {
|
||||||
$( '.mw-revslider-placeholder' )
|
$( '.mw-revslider-placeholder' )
|
||||||
.text( mw.message( 'revisionslider-loading-failed' ).text() );
|
.text( mw.message( 'revisionslider-loading-failed' ).text() );
|
||||||
console.log( err );
|
console.log( err );
|
||||||
mw.track( 'counter.MediaWiki.RevisionSlider.error.init' );
|
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' );
|
||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue