mediawiki-extensions-Revisi.../modules/ext.RevisionSlider.Slider.js
thiemowmde 3a9abded84 Clamp slider position when using the browser's back button
Steps to reproduce:
* Make the browser window very narrow so that RevisionSlider can't
  show the maximum number of gray bars.
* Go to a page with many revisions, open the RevisionSlider, and pin
  it.
* Click the "Older edit" navigation link.
* Now make the browser window larger. Note how RevisionSlider will
  have more space to show more gray bars.
* Use the browser's back button.

The pointer positions will jump to a random position.

The problematic code is in DiffPage.initOnPopState() where a "state"
object from the browser history is used to not only restore the
position of the blue and yellow pointers, but also the relative
starting position of the slider (the position you can manually change
with the large left/right arrow buttons). The way this relative
position is calculated depends on the number of revisions that fit
on a screen, which depends on the the available screen width. The
problem is that these numbers change after the state was recorded in
the browser history.

It might be that this patch still does not solve the issue in all
possible situations. But it already makes it behave much better.

Bug: T349208
Change-Id: If8e89457232061698c3821cae2d0aab3f7778b26
2023-10-25 15:03:44 +02:00

138 lines
3.3 KiB
JavaScript

const SliderView = require( './ext.RevisionSlider.SliderView.js' );
/**
* Module handling the slider logic of the RevisionSlider
*
* @class Slider
* @param {RevisionList} revisions
* @constructor
*/
function Slider( revisions ) {
this.revisions = revisions;
this.view = new SliderView( this );
}
$.extend( Slider.prototype, {
/**
* @type {RevisionList}
*/
revisions: null,
/**
* @type {number}
*/
oldestVisibleRevisionIndex: 0,
/**
* @type {number}
*/
revisionsPerWindow: 0,
/**
* @type {SliderView}
*/
view: null,
/**
* @return {RevisionList}
*/
getRevisionList: function () {
return this.revisions;
},
/**
* @return {SliderView}
*/
getView: function () {
return this.view;
},
/**
* Sets the number of revisions that are visible at once (depending on browser window size)
*
* @param {number} n
*/
setRevisionsPerWindow: function ( n ) {
this.revisionsPerWindow = n;
},
/**
* @return {number}
*/
getRevisionsPerWindow: function () {
return this.revisionsPerWindow;
},
/**
* Returns the index of the oldest revision that is visible in the current window
*
* @return {number}
*/
getOldestVisibleRevisionIndex: function () {
return this.oldestVisibleRevisionIndex;
},
/**
* Returns the index of the newest revision that is visible in the current window
*
* @return {number}
*/
getNewestVisibleRevisionIndex: function () {
return this.oldestVisibleRevisionIndex + this.revisionsPerWindow - 1;
},
/**
* @return {boolean}
*/
isAtStart: function () {
return this.getOldestVisibleRevisionIndex() === 0 || this.revisions.getLength() <= this.revisionsPerWindow;
},
/**
* @return {boolean}
*/
isAtEnd: function () {
return this.getNewestVisibleRevisionIndex() === this.revisions.getLength() - 1 || this.revisions.getLength() <= this.revisionsPerWindow;
},
/**
* Sets the index of the first revision that is visible in the current window
*
* @param {number} value
*/
setFirstVisibleRevisionIndex: function ( value ) {
const highestPossibleFirstRev = this.revisions.getLength() - this.revisionsPerWindow;
value = Math.min( Math.max( 0, value ), highestPossibleFirstRev );
this.oldestVisibleRevisionIndex = value;
},
/**
* Sets the new oldestVisibleRevisionIndex after sliding in a direction
*
* @param {number} direction - Either -1, 0 or 1
*/
slide: function ( direction ) {
const value = this.oldestVisibleRevisionIndex + direction * this.revisionsPerWindow;
this.setFirstVisibleRevisionIndex( value );
}
} );
module.exports = {
Api: require( './ext.RevisionSlider.Api.js' ),
DiffPage: require( './ext.RevisionSlider.DiffPage.js' ),
HelpDialog: require( './ext.RevisionSlider.HelpDialog.js' ),
makeRevisions: require( './ext.RevisionSlider.RevisionList.js' ).makeRevisions,
Revision: require( './ext.RevisionSlider.Revision.js' ).Revision,
RevisionList: require( './ext.RevisionSlider.RevisionList.js' ).RevisionList,
RevisionListView: require( './ext.RevisionSlider.RevisionListView.js' ),
setUserOffset: require( './ext.RevisionSlider.Revision.js' ).setUserOffset,
Slider: Slider,
SliderView: SliderView,
utils: require( './ext.RevisionSlider.util.js' ),
private: {
Pointer: require( './ext.RevisionSlider.Pointer.js' ),
PointerView: require( './ext.RevisionSlider.PointerView.js' )
}
};