2016-05-10 12:42:05 +00:00
|
|
|
( function ( mw, $ ) {
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Module handling the view logic of the RevisionSlider slider
|
|
|
|
*
|
|
|
|
* @param {Slider} slider
|
|
|
|
* @constructor
|
|
|
|
*/
|
2016-05-10 12:42:05 +00:00
|
|
|
var SliderView = function ( slider ) {
|
|
|
|
this.slider = slider;
|
2016-05-20 10:42:01 +00:00
|
|
|
this.diffPage = new mw.libs.revisionSlider.DiffPage( this.slider.getRevisions() );
|
2016-05-10 12:42:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
$.extend( SliderView.prototype, {
|
|
|
|
revisionWidth: 16,
|
|
|
|
|
2016-08-09 16:34:53 +00:00
|
|
|
containerMargin: 140,
|
2016-05-10 12:42:05 +00:00
|
|
|
|
2016-08-05 16:14:28 +00:00
|
|
|
outerMargin: 20,
|
|
|
|
|
2016-05-10 12:42:05 +00:00
|
|
|
/**
|
|
|
|
* @type {jQuery}
|
|
|
|
*/
|
|
|
|
$element: null,
|
|
|
|
|
2016-05-20 10:42:01 +00:00
|
|
|
/**
|
|
|
|
* @type {DiffPage}
|
|
|
|
*/
|
|
|
|
diffPage: null,
|
|
|
|
|
2016-05-10 12:42:05 +00:00
|
|
|
/**
|
|
|
|
* @type {Slider}
|
|
|
|
*/
|
|
|
|
slider: null,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @type {Pointer}
|
|
|
|
*/
|
2016-05-21 00:10:08 +00:00
|
|
|
pointerOlder: null,
|
2016-05-10 12:42:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @type {Pointer}
|
|
|
|
*/
|
2016-05-21 00:10:08 +00:00
|
|
|
pointerNewer: null,
|
|
|
|
|
2016-08-05 08:45:37 +00:00
|
|
|
/**
|
|
|
|
* @type {OO.ui.ButtonWidget}
|
|
|
|
*/
|
|
|
|
backwardArrowButton: null,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @type {OO.ui.ButtonWidget}
|
|
|
|
*/
|
|
|
|
forwardArrowButton: null,
|
|
|
|
|
2016-05-21 00:10:08 +00:00
|
|
|
/**
|
|
|
|
* @type {string}
|
|
|
|
*
|
|
|
|
* Value of scrollLeft property when in RTL mode varies between browser. This identifies
|
|
|
|
* an implementation used by user's browser:
|
|
|
|
* - 'default': 0 is the left-most position, values increase when scrolling right (same as scrolling from left to right in LTR mode)
|
|
|
|
* - 'negative': 0 is right-most position, values decrease when scrolling left (ie. all values except 0 are negative)
|
|
|
|
* - 'reverse': 0 is right-most position, values incrase when scrolling left
|
|
|
|
*/
|
|
|
|
rtlScrollLeftType: 'default',
|
2016-05-10 12:42:05 +00:00
|
|
|
|
2016-06-27 14:00:13 +00:00
|
|
|
/**
|
|
|
|
* @type {boolean}
|
|
|
|
*/
|
|
|
|
noMoreNewerRevisions: false,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @type {boolean}
|
|
|
|
*/
|
|
|
|
noMoreOlderRevisions: false,
|
|
|
|
|
2016-10-13 04:07:28 +00:00
|
|
|
/**
|
|
|
|
* @type {string}
|
|
|
|
*/
|
|
|
|
dir: null,
|
|
|
|
|
2017-04-12 17:14:32 +00:00
|
|
|
/**
|
|
|
|
* @type {boolean}
|
|
|
|
*/
|
|
|
|
isDragged: false,
|
|
|
|
|
2017-05-18 01:25:42 +00:00
|
|
|
escapePressed: false,
|
|
|
|
|
2016-05-10 12:42:05 +00:00
|
|
|
render: function ( $container ) {
|
|
|
|
var containerWidth = this.calculateSliderContainerWidth(),
|
2016-05-12 11:34:16 +00:00
|
|
|
$revisions = this.slider.getRevisions().getView().render( this.revisionWidth ),
|
2017-03-24 13:48:57 +00:00
|
|
|
sliderArrowView = new mw.libs.revisionSlider.SliderArrowView( this ),
|
2016-05-10 12:42:05 +00:00
|
|
|
self = this;
|
|
|
|
|
2016-10-13 04:07:28 +00:00
|
|
|
this.dir = $container.css( 'direction' ) || 'ltr';
|
|
|
|
|
|
|
|
if ( this.dir === 'rtl' ) {
|
2016-05-21 00:10:08 +00:00
|
|
|
this.rtlScrollLeftType = this.determineRtlScrollType();
|
|
|
|
}
|
2016-05-10 12:42:05 +00:00
|
|
|
|
2016-08-15 15:09:42 +00:00
|
|
|
this.pointerOlder = this.pointerOlder || new mw.libs.revisionSlider.Pointer( 'mw-revslider-pointer-older' );
|
|
|
|
this.pointerNewer = this.pointerNewer || new mw.libs.revisionSlider.Pointer( 'mw-revslider-pointer-newer' );
|
2016-05-21 00:10:08 +00:00
|
|
|
|
2017-03-24 13:48:57 +00:00
|
|
|
this.backwardArrowButton = sliderArrowView.renderBackwardArrow();
|
|
|
|
this.forwardArrowButton = sliderArrowView.renderForwardArrow();
|
2017-03-03 13:55:42 +00:00
|
|
|
|
2017-03-22 17:46:16 +00:00
|
|
|
this.$element = $( '<div>' )
|
|
|
|
.addClass( 'mw-revslider-revision-slider' )
|
|
|
|
.css( {
|
|
|
|
direction: $container.css( 'direction' ),
|
|
|
|
width: ( containerWidth + this.containerMargin ) + 'px'
|
|
|
|
} )
|
2016-05-26 09:38:56 +00:00
|
|
|
.append(
|
2016-08-05 08:45:37 +00:00
|
|
|
this.backwardArrowButton.$element,
|
2017-03-22 12:26:04 +00:00
|
|
|
this.renderRevisionsContainer( containerWidth, $revisions ),
|
2016-08-05 08:45:37 +00:00
|
|
|
this.forwardArrowButton.$element,
|
2017-03-24 13:14:18 +00:00
|
|
|
mw.libs.revisionSlider.HelpButtonView.render(),
|
2016-05-30 10:06:44 +00:00
|
|
|
$( '<div>' ).css( { clear: 'both' } ),
|
2017-03-22 12:26:04 +00:00
|
|
|
this.renderPointerContainer( containerWidth ),
|
2016-11-02 18:22:40 +00:00
|
|
|
this.pointerOlder.getLine().render(), this.pointerNewer.getLine().render()
|
2016-05-12 11:34:16 +00:00
|
|
|
);
|
2016-05-10 12:42:05 +00:00
|
|
|
|
2017-03-23 11:46:04 +00:00
|
|
|
this.initPointers( $revisions );
|
2017-03-22 12:41:08 +00:00
|
|
|
|
2017-03-22 17:46:16 +00:00
|
|
|
this.$element.find( '.mw-revslider-revision-wrapper' ).on( 'click', null, { view: self, revisionsDom: $revisions }, this.revisionWrapperClickHandler );
|
2017-03-22 12:41:08 +00:00
|
|
|
|
2017-03-22 17:46:16 +00:00
|
|
|
this.slider.setRevisionsPerWindow( this.$element.find( '.mw-revslider-revisions-container' ).width() / this.revisionWidth );
|
2017-03-22 12:41:08 +00:00
|
|
|
|
|
|
|
this.initializePointers( this.getOldRevElement( $revisions ), this.getNewRevElement( $revisions ) );
|
|
|
|
this.resetRevisionStylesBasedOnPointerPosition( $revisions );
|
|
|
|
|
2017-03-22 17:46:16 +00:00
|
|
|
$container.html( this.$element );
|
2017-03-22 12:41:08 +00:00
|
|
|
|
|
|
|
this.slide( Math.floor( ( this.pointerNewer.getPosition() - 1 ) / this.slider.getRevisionsPerWindow() ), 0 );
|
|
|
|
this.diffPage.addHandlersToCoreLinks( this );
|
2017-05-08 15:45:07 +00:00
|
|
|
this.diffPage.replaceState( mw.config.get( 'extRevisionSliderNewRev' ), mw.config.get( 'extRevisionSliderOldRev' ), this );
|
2017-03-22 12:41:08 +00:00
|
|
|
this.diffPage.initOnPopState( this );
|
|
|
|
},
|
|
|
|
|
2017-03-23 11:46:04 +00:00
|
|
|
/**
|
|
|
|
* Renders the revisions container and adds the revisions to it
|
|
|
|
*
|
|
|
|
* @param {number} containerWidth
|
|
|
|
* @param {jQuery} $revisions
|
|
|
|
* @return {jQuery} the revisions container
|
|
|
|
*/
|
2017-05-04 20:57:38 +00:00
|
|
|
renderRevisionsContainer: function ( containerWidth, $revisions ) {
|
2017-03-22 12:41:08 +00:00
|
|
|
return $( '<div>' )
|
|
|
|
.addClass( 'mw-revslider-revisions-container' )
|
|
|
|
.css( {
|
|
|
|
width: containerWidth + 'px'
|
|
|
|
} )
|
|
|
|
.append( $revisions );
|
|
|
|
},
|
|
|
|
|
2017-03-23 11:46:04 +00:00
|
|
|
/**
|
|
|
|
* Renders the pointer container and adds the pointers to it
|
|
|
|
*
|
|
|
|
* @param {number} containerWidth
|
|
|
|
* @return {jQuery} the pointer container
|
|
|
|
*/
|
2017-05-04 20:57:38 +00:00
|
|
|
renderPointerContainer: function ( containerWidth ) {
|
2017-03-28 10:13:56 +00:00
|
|
|
var pointerContainerSideOffset = 53,
|
2017-03-22 12:41:08 +00:00
|
|
|
pointerContainerWidth = containerWidth + this.revisionWidth - 1,
|
|
|
|
pointerContainerStyle;
|
|
|
|
|
2017-03-28 10:13:56 +00:00
|
|
|
pointerContainerStyle = { left: pointerContainerSideOffset + 'px', width: pointerContainerWidth + 'px' };
|
2017-03-22 12:41:08 +00:00
|
|
|
if ( this.dir === 'rtl' ) {
|
|
|
|
// Due to properly limit dragging a pointer on the right side of the screen,
|
|
|
|
// there must some extra space added to the right of the revision bar container
|
|
|
|
// For this reason right position of the pointer container in the RTL mode is
|
|
|
|
// a bit moved off right compared to its left position in the LTR mode
|
2017-03-28 10:13:56 +00:00
|
|
|
pointerContainerSideOffset = pointerContainerSideOffset - this.revisionWidth + 1;
|
|
|
|
pointerContainerStyle = { right: pointerContainerSideOffset + 'px', width: pointerContainerWidth + 'px' };
|
2017-03-22 12:41:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $( '<div>' )
|
|
|
|
.addClass( 'mw-revslider-pointer-container' )
|
|
|
|
.css( pointerContainerStyle )
|
|
|
|
.append( this.pointerOlder.getView().render(), this.pointerNewer.getView().render() );
|
|
|
|
},
|
|
|
|
|
2017-03-23 11:46:04 +00:00
|
|
|
/**
|
|
|
|
* Initializes the pointer dragging logic
|
|
|
|
*
|
|
|
|
* @param {jQuery} $revisions
|
|
|
|
*/
|
2017-05-04 20:57:38 +00:00
|
|
|
initPointers: function ( $revisions ) {
|
2017-03-22 12:41:08 +00:00
|
|
|
var $pointers,
|
2017-05-18 01:25:42 +00:00
|
|
|
self = this;
|
2017-03-22 12:41:08 +00:00
|
|
|
|
2017-03-23 11:46:04 +00:00
|
|
|
$pointers = this.$element.find( '.mw-revslider-pointer' );
|
2017-03-22 12:41:08 +00:00
|
|
|
|
2017-05-04 20:57:38 +00:00
|
|
|
$( 'body' ).keydown( function ( e ) {
|
2016-12-07 20:56:36 +00:00
|
|
|
if ( e.which === 27 ) {
|
2017-05-18 01:25:42 +00:00
|
|
|
self.escapePressed = true;
|
2016-12-07 20:56:36 +00:00
|
|
|
$pointers.trigger( 'mouseup' );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
2017-05-18 01:25:42 +00:00
|
|
|
$pointers.draggable( this.buildDraggableOptions( $revisions, '.mw-revslider-pointer-container' ) );
|
2017-05-03 13:54:30 +00:00
|
|
|
$pointers.on(
|
|
|
|
'touchstart touchmove touchend',
|
|
|
|
mw.libs.revisionSlider.touchEventConverter
|
|
|
|
);
|
2017-03-23 16:42:49 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build options for the draggable
|
|
|
|
*
|
|
|
|
* @param {jQuery} $revisions
|
2017-03-23 13:53:13 +00:00
|
|
|
* @param {string} containmentClass
|
2017-03-23 16:42:49 +00:00
|
|
|
* @return {Object}
|
|
|
|
*/
|
2017-05-18 01:25:42 +00:00
|
|
|
buildDraggableOptions: function ( $revisions, containmentClass ) {
|
2017-03-23 16:42:49 +00:00
|
|
|
var lastValidLeftPos,
|
|
|
|
self = this;
|
|
|
|
|
|
|
|
return {
|
2016-05-10 12:42:05 +00:00
|
|
|
axis: 'x',
|
2016-05-26 09:50:51 +00:00
|
|
|
grid: [ this.revisionWidth, null ],
|
2017-03-23 13:53:13 +00:00
|
|
|
containment: containmentClass,
|
2017-05-04 20:57:38 +00:00
|
|
|
start: function () {
|
2017-04-12 17:14:32 +00:00
|
|
|
self.isDragged = true;
|
2017-04-05 16:01:09 +00:00
|
|
|
self.setPointerDragCursor();
|
2017-04-05 15:00:08 +00:00
|
|
|
self.fadeOutPointerLines();
|
2017-05-18 01:25:42 +00:00
|
|
|
self.escapePressed = false;
|
2016-06-03 08:55:17 +00:00
|
|
|
},
|
2017-05-04 20:57:38 +00:00
|
|
|
stop: function () {
|
2016-05-10 12:42:05 +00:00
|
|
|
var $p = $( this ),
|
2017-03-23 16:54:12 +00:00
|
|
|
relativeIndex = self.getRelativePointerIndex( $p ),
|
2016-05-10 12:42:05 +00:00
|
|
|
pointer = self.whichPointer( $p ),
|
2017-05-08 15:45:07 +00:00
|
|
|
diff, oldid;
|
2016-10-13 18:57:36 +00:00
|
|
|
|
2017-04-12 17:14:32 +00:00
|
|
|
self.isDragged = false;
|
2017-04-05 16:01:09 +00:00
|
|
|
self.removePointerDragCursor();
|
2016-12-07 20:56:36 +00:00
|
|
|
|
2017-05-18 01:25:42 +00:00
|
|
|
if ( self.escapePressed ) {
|
2016-12-07 20:56:36 +00:00
|
|
|
self.updatePointerPositionAttributes();
|
|
|
|
self.resetPointerStylesBasedOnPosition();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-11 09:04:13 +00:00
|
|
|
mw.track( 'counter.MediaWiki.RevisionSlider.event.pointerMove' );
|
2017-03-27 19:04:31 +00:00
|
|
|
pointer.setPosition( self.slider.getOldestVisibleRevisionIndex() + relativeIndex );
|
2016-10-13 13:46:35 +00:00
|
|
|
self.updatePointerPositionAttributes();
|
2016-05-17 12:29:08 +00:00
|
|
|
self.resetPointerStylesBasedOnPosition();
|
2016-05-19 16:39:58 +00:00
|
|
|
self.resetRevisionStylesBasedOnPointerPosition( $revisions );
|
2016-05-11 10:01:44 +00:00
|
|
|
|
2017-05-08 15:45:07 +00:00
|
|
|
diff = self.getRevElementAtPosition(
|
|
|
|
$revisions, self.pointerNewer.getPosition()
|
2017-03-23 16:42:49 +00:00
|
|
|
).data( 'revid' );
|
2016-10-13 13:46:35 +00:00
|
|
|
|
2017-05-08 15:45:07 +00:00
|
|
|
oldid = self.getRevElementAtPosition(
|
|
|
|
$revisions, self.pointerOlder.getPosition()
|
2017-03-23 16:42:49 +00:00
|
|
|
).data( 'revid' );
|
2016-05-11 10:01:44 +00:00
|
|
|
|
2017-05-08 15:45:07 +00:00
|
|
|
self.refreshRevisions( diff, oldid );
|
2016-06-03 08:55:17 +00:00
|
|
|
|
2016-11-02 18:22:40 +00:00
|
|
|
self.redrawPointerLines();
|
2016-05-13 09:43:01 +00:00
|
|
|
},
|
2017-05-04 20:57:38 +00:00
|
|
|
drag: function ( event, ui ) {
|
2017-04-06 11:47:59 +00:00
|
|
|
lastValidLeftPos = self.draggableDragAction(
|
|
|
|
event,
|
|
|
|
ui,
|
|
|
|
this,
|
|
|
|
lastValidLeftPos
|
2017-03-23 16:42:49 +00:00
|
|
|
);
|
2016-12-07 20:56:36 +00:00
|
|
|
},
|
2017-05-04 20:57:38 +00:00
|
|
|
revert: function () {
|
2017-05-18 01:25:42 +00:00
|
|
|
return self.escapePressed;
|
2016-05-20 10:42:01 +00:00
|
|
|
}
|
2017-03-23 16:42:49 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2017-05-04 20:57:38 +00:00
|
|
|
draggableDragAction: function ( event, ui, pointer, lastValidLeftPos ) {
|
2017-06-29 14:15:10 +00:00
|
|
|
var pos, $revisions, $hoveredRevisionWrapper;
|
2017-04-06 11:47:59 +00:00
|
|
|
|
2017-06-29 14:15:10 +00:00
|
|
|
pos = this.getRevisionPositionFromLeftOffset(
|
|
|
|
$( pointer ).offset().left + this.revisionWidth / 2
|
2017-04-06 11:47:59 +00:00
|
|
|
);
|
|
|
|
|
2017-06-29 14:15:10 +00:00
|
|
|
if ( pos === lastValidLeftPos ) {
|
|
|
|
return pos;
|
|
|
|
}
|
2017-04-06 11:47:59 +00:00
|
|
|
|
2017-06-29 14:15:10 +00:00
|
|
|
$revisions = this.getRevisionsElement();
|
|
|
|
$hoveredRevisionWrapper = this.getRevElementAtPosition( $revisions, pos ).parent();
|
|
|
|
this.slider.getRevisions().getView().showTooltip( $hoveredRevisionWrapper );
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
},
|
|
|
|
|
|
|
|
getRevisionPositionFromLeftOffset: function ( leftOffset ) {
|
|
|
|
var $revisions = this.getRevisionsElement(),
|
|
|
|
revisionsX = mw.libs.revisionSlider.correctElementOffsets( $revisions.offset() ).left,
|
|
|
|
pos = Math.ceil( Math.abs( leftOffset - revisionsX ) / this.revisionWidth );
|
|
|
|
|
|
|
|
if ( this.dir === 'rtl' ) {
|
|
|
|
// pre-loading the revisions on the right side leads to shifted position numbers
|
|
|
|
if ( this.slider.isAtStart() ) {
|
|
|
|
pos = this.slider.getRevisionsPerWindow() - pos + 1;
|
2017-04-06 11:47:59 +00:00
|
|
|
} else {
|
2017-06-29 14:15:10 +00:00
|
|
|
pos += this.slider.getRevisionsPerWindow();
|
2017-04-06 11:47:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-29 14:15:10 +00:00
|
|
|
return pos;
|
2017-04-06 11:47:59 +00:00
|
|
|
},
|
|
|
|
|
2017-05-04 20:57:38 +00:00
|
|
|
setPointerDragCursor: function () {
|
2017-04-05 16:01:09 +00:00
|
|
|
$( '.mw-revslider-revision-wrapper' )
|
|
|
|
.addClass( 'mw-revslider-pointer-cursor' );
|
|
|
|
},
|
|
|
|
|
2017-05-04 20:57:38 +00:00
|
|
|
removePointerDragCursor: function () {
|
2017-04-05 16:01:09 +00:00
|
|
|
$( '.mw-revslider-revision-wrapper' )
|
|
|
|
.removeClass( 'mw-revslider-pointer-cursor' );
|
|
|
|
},
|
|
|
|
|
2017-03-23 16:54:12 +00:00
|
|
|
/**
|
|
|
|
* Get the relative index for a pointer.
|
|
|
|
*
|
|
|
|
* @param {jQuery} $pointer
|
|
|
|
* @return {number}
|
|
|
|
*/
|
2017-05-04 20:57:38 +00:00
|
|
|
getRelativePointerIndex: function ( $pointer ) {
|
2017-03-23 16:54:12 +00:00
|
|
|
var pos = $pointer.position().left,
|
|
|
|
pointer = this.whichPointer( $pointer );
|
|
|
|
|
|
|
|
if ( this.dir === 'rtl' ) {
|
|
|
|
pos = pointer.getView().getAdjustedLeftPositionWhenRtl( pos );
|
|
|
|
}
|
|
|
|
return Math.ceil( ( pos + this.revisionWidth / 2 ) / this.revisionWidth );
|
|
|
|
},
|
|
|
|
|
2017-05-04 20:57:38 +00:00
|
|
|
getNewestVisibleRevisonLeftPos: function () {
|
2017-03-23 16:42:49 +00:00
|
|
|
return $( '.mw-revslider-revisions-container' ).width() - this.revisionWidth;
|
2017-03-22 12:26:04 +00:00
|
|
|
},
|
|
|
|
|
2016-06-27 14:00:13 +00:00
|
|
|
revisionWrapperClickHandler: function ( e ) {
|
2016-10-13 04:46:56 +00:00
|
|
|
var pClicked, pOther,
|
|
|
|
$revWrap = $( this ),
|
2016-06-27 14:00:13 +00:00
|
|
|
view = e.data.view,
|
|
|
|
$revisions = e.data.revisionsDom,
|
|
|
|
$clickedRev = $revWrap.find( '.mw-revslider-revision' ),
|
|
|
|
hasClickedTop = e.pageY - $revWrap.offset().top < $revWrap.height() / 2,
|
|
|
|
pOld = view.getOldRevPointer(),
|
2016-10-13 04:46:56 +00:00
|
|
|
pNew = view.getNewRevPointer(),
|
|
|
|
targetPos = +$clickedRev.attr( 'data-pos' );
|
2016-06-27 14:00:13 +00:00
|
|
|
|
2016-10-13 04:46:56 +00:00
|
|
|
pClicked = hasClickedTop ? pNew : pOld;
|
|
|
|
pOther = hasClickedTop ? pOld : pNew;
|
|
|
|
|
|
|
|
if ( targetPos === pOther.getPosition() ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pClicked.setPosition( targetPos );
|
|
|
|
view.updatePointerPositionAttributes();
|
2017-05-08 15:45:07 +00:00
|
|
|
|
|
|
|
if ( hasClickedTop ) {
|
|
|
|
view.refreshRevisions(
|
|
|
|
+$clickedRev.data( 'revid' ),
|
|
|
|
+view.getRevElementAtPosition( $revisions, pOther.getPosition() ).data( 'revid' )
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
view.refreshRevisions(
|
|
|
|
+view.getRevElementAtPosition( $revisions, pOther.getPosition() ).data( 'revid' ),
|
|
|
|
+$clickedRev.data( 'revid' )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-06-27 14:00:13 +00:00
|
|
|
view.resetPointerColorsBasedOnValues( view.pointerOlder.getPosition(), view.pointerNewer.getPosition() );
|
|
|
|
view.resetRevisionStylesBasedOnPointerPosition( $revisions );
|
|
|
|
view.alignPointers();
|
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Returns the pointer that points to the older revision
|
|
|
|
*
|
|
|
|
* @return {Pointer}
|
|
|
|
*/
|
2016-05-20 10:42:01 +00:00
|
|
|
getOldRevPointer: function () {
|
2016-05-21 00:10:08 +00:00
|
|
|
return this.pointerOlder.getPosition() <= this.pointerNewer.getPosition() ? this.pointerOlder : this.pointerNewer;
|
2016-05-20 10:42:01 +00:00
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Returns the pointer that points to the newer revision
|
|
|
|
*
|
|
|
|
* @return {Pointer}
|
|
|
|
*/
|
2016-05-20 10:42:01 +00:00
|
|
|
getNewRevPointer: function () {
|
2016-05-21 00:10:08 +00:00
|
|
|
return this.pointerOlder.getPosition() > this.pointerNewer.getPosition() ? this.pointerOlder : this.pointerNewer;
|
2016-05-20 10:42:01 +00:00
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Refreshes the diff page to show the diff for the specified revisions
|
|
|
|
*
|
2017-05-08 15:45:07 +00:00
|
|
|
* @param {number} diff
|
|
|
|
* @param {number} oldid
|
2016-06-17 13:06:12 +00:00
|
|
|
*/
|
2017-05-08 15:45:07 +00:00
|
|
|
refreshRevisions: function ( diff, oldid ) {
|
|
|
|
this.diffPage.refresh( diff, oldid, this );
|
|
|
|
this.diffPage.pushState( diff, oldid, this );
|
2016-05-20 10:42:01 +00:00
|
|
|
},
|
|
|
|
|
2017-02-02 17:24:51 +00:00
|
|
|
showNextDiff: function () {
|
|
|
|
this.pointerOlder.setPosition( this.pointerNewer.getPosition() );
|
|
|
|
this.pointerNewer.setPosition( this.pointerNewer.getPosition() + 1 );
|
|
|
|
this.resetAndRefreshRevisions();
|
|
|
|
},
|
|
|
|
|
|
|
|
showPrevDiff: function () {
|
|
|
|
this.pointerNewer.setPosition( this.pointerOlder.getPosition() );
|
|
|
|
this.pointerOlder.setPosition( this.pointerOlder.getPosition() - 1 );
|
|
|
|
this.resetAndRefreshRevisions();
|
|
|
|
},
|
|
|
|
|
2017-05-04 20:57:38 +00:00
|
|
|
resetAndRefreshRevisions: function () {
|
2017-02-02 17:24:51 +00:00
|
|
|
this.slide( 0 );
|
|
|
|
this.resetPointerStylesBasedOnPosition();
|
|
|
|
this.resetRevisionStylesBasedOnPointerPosition(
|
|
|
|
this.$element.find( 'div.mw-revslider-revisions' )
|
|
|
|
);
|
|
|
|
this.updatePointerPositionAttributes();
|
|
|
|
this.refreshRevisions(
|
2017-05-08 15:45:07 +00:00
|
|
|
$( '.mw-revslider-revision[data-pos="' + this.pointerNewer.getPosition() + '"]' ).attr( 'data-revid' ),
|
|
|
|
$( '.mw-revslider-revision[data-pos="' + this.pointerOlder.getPosition() + '"]' ).attr( 'data-revid' )
|
2017-02-02 17:24:51 +00:00
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* @param {jQuery} $revs
|
|
|
|
* @param {number} pos
|
|
|
|
* @return {jQuery}
|
|
|
|
*/
|
2016-05-20 10:42:01 +00:00
|
|
|
getRevElementAtPosition: function ( $revs, pos ) {
|
2016-07-01 10:13:53 +00:00
|
|
|
return $revs.find( 'div.mw-revslider-revision[data-pos="' + pos + '"]' );
|
2016-05-20 10:42:01 +00:00
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Gets the jQuery element of the older selected revision
|
|
|
|
*
|
|
|
|
* @param {jQuery} $revs
|
|
|
|
* @return {jQuery}
|
|
|
|
*/
|
2016-05-20 10:42:01 +00:00
|
|
|
getOldRevElement: function ( $revs ) {
|
2016-11-23 00:31:53 +00:00
|
|
|
return $revs.find( 'div.mw-revslider-revision[data-revid="' + mw.config.get( 'extRevisionSliderOldRev' ) + '"]' );
|
2016-05-20 10:42:01 +00:00
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Gets the jQuery element of the newer selected revision
|
|
|
|
*
|
|
|
|
* @param {jQuery} $revs
|
|
|
|
* @return {jQuery}
|
|
|
|
*/
|
2016-05-20 10:42:01 +00:00
|
|
|
getNewRevElement: function ( $revs ) {
|
2016-11-23 00:31:53 +00:00
|
|
|
return $revs.find( 'div.mw-revslider-revision[data-revid="' + mw.config.get( 'extRevisionSliderNewRev' ) + '"]' );
|
2016-05-10 12:42:05 +00:00
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Initializes the Pointer objects based on the selected revisions
|
|
|
|
*
|
|
|
|
* @param {jQuery} $oldRevElement
|
|
|
|
* @param {jQuery} $newRevElement
|
|
|
|
*/
|
2016-05-20 10:42:01 +00:00
|
|
|
initializePointers: function ( $oldRevElement, $newRevElement ) {
|
2016-08-15 15:09:42 +00:00
|
|
|
if ( this.pointerOlder.getPosition() !== 0 || this.pointerNewer.getPosition() !== 0 ) {
|
|
|
|
return;
|
|
|
|
}
|
2016-06-27 14:00:13 +00:00
|
|
|
if ( $oldRevElement.length === 0 && $newRevElement.length === 0 ) {
|
2016-05-12 11:29:45 +00:00
|
|
|
// Note: this is currently caught in init.js
|
2017-05-03 08:47:14 +00:00
|
|
|
throw new Error( 'RS-revs-not-specified' );
|
2016-06-27 14:00:13 +00:00
|
|
|
}
|
|
|
|
if ( $oldRevElement.length !== 0 ) {
|
|
|
|
this.pointerOlder.setPosition( $oldRevElement.data( 'pos' ) );
|
|
|
|
} else {
|
|
|
|
this.pointerOlder.setPosition( -1 );
|
2016-05-12 11:29:45 +00:00
|
|
|
}
|
2016-05-21 00:10:08 +00:00
|
|
|
this.pointerNewer.setPosition( $newRevElement.data( 'pos' ) );
|
2016-05-17 12:29:08 +00:00
|
|
|
this.resetPointerStylesBasedOnPosition();
|
2016-10-10 14:15:47 +00:00
|
|
|
this.updatePointerPositionAttributes();
|
2016-05-13 10:29:05 +00:00
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Adjusts the colors of the pointers without changing the upper/lower property based on values `p1` and `p2`.
|
|
|
|
* Used e.g. when pointers get dragged past one another.
|
|
|
|
*
|
|
|
|
* @param {number} p1
|
|
|
|
* @param {number} p2
|
|
|
|
*/
|
2016-05-20 10:42:01 +00:00
|
|
|
resetPointerColorsBasedOnValues: function ( p1, p2 ) {
|
|
|
|
if ( p1 > p2 ) {
|
2016-07-01 10:13:53 +00:00
|
|
|
this.pointerOlder.getView().getElement().removeClass( 'mw-revslider-pointer-oldid' ).addClass( 'mw-revslider-pointer-newid' );
|
|
|
|
this.pointerNewer.getView().getElement().removeClass( 'mw-revslider-pointer-newid' ).addClass( 'mw-revslider-pointer-oldid' );
|
2016-05-13 10:29:05 +00:00
|
|
|
} else {
|
2016-07-01 10:13:53 +00:00
|
|
|
this.pointerOlder.getView().getElement().removeClass( 'mw-revslider-pointer-newid' ).addClass( 'mw-revslider-pointer-oldid' );
|
|
|
|
this.pointerNewer.getView().getElement().removeClass( 'mw-revslider-pointer-oldid' ).addClass( 'mw-revslider-pointer-newid' );
|
2016-05-13 10:29:05 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Resets the pointer styles (upper/lower, blue/yellow) based on their position.
|
|
|
|
*/
|
2016-05-17 12:29:08 +00:00
|
|
|
resetPointerStylesBasedOnPosition: function () {
|
2016-07-01 10:13:53 +00:00
|
|
|
this.getNewRevPointer().getView().getElement().removeClass( 'mw-revslider-pointer-oldid' ).addClass( 'mw-revslider-pointer-newid' )
|
|
|
|
.removeClass( 'mw-revslider-pointer-lower' ).addClass( 'mw-revslider-pointer-upper' );
|
|
|
|
this.getOldRevPointer().getView().getElement().removeClass( 'mw-revslider-pointer-newid' ).addClass( 'mw-revslider-pointer-oldid' )
|
|
|
|
.removeClass( 'mw-revslider-pointer-upper' ).addClass( 'mw-revslider-pointer-lower' );
|
2016-05-10 12:42:05 +00:00
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Highlights revisions between the pointers
|
|
|
|
*
|
|
|
|
* @param {jQuery} $revisions
|
|
|
|
*/
|
2016-05-19 16:39:58 +00:00
|
|
|
resetRevisionStylesBasedOnPointerPosition: function ( $revisions ) {
|
2016-05-20 10:42:01 +00:00
|
|
|
var olderRevPosition = this.getOldRevPointer().getPosition(),
|
|
|
|
newerRevPosition = this.getNewRevPointer().getPosition(),
|
2016-05-19 16:39:58 +00:00
|
|
|
positionIndex = olderRevPosition + 1;
|
2016-05-20 10:42:01 +00:00
|
|
|
|
2016-07-01 10:13:53 +00:00
|
|
|
$revisions.find( 'div.mw-revslider-revision' )
|
|
|
|
.removeClass( 'mw-revslider-revision-intermediate mw-revslider-revision-old mw-revslider-revision-new' );
|
2016-05-20 10:42:01 +00:00
|
|
|
|
2016-07-01 10:13:53 +00:00
|
|
|
this.getRevElementAtPosition( $revisions, olderRevPosition ).addClass( 'mw-revslider-revision-old' );
|
|
|
|
this.getRevElementAtPosition( $revisions, newerRevPosition ).addClass( 'mw-revslider-revision-new' );
|
2016-05-19 16:39:58 +00:00
|
|
|
while ( positionIndex < newerRevPosition ) {
|
2016-07-01 10:13:53 +00:00
|
|
|
this.getRevElementAtPosition( $revisions, positionIndex ).addClass( 'mw-revslider-revision-intermediate' );
|
2016-05-19 16:39:58 +00:00
|
|
|
positionIndex++;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-10-10 14:15:47 +00:00
|
|
|
/**
|
|
|
|
* Updates value of pointers' position data attribute
|
|
|
|
*/
|
|
|
|
updatePointerPositionAttributes: function () {
|
|
|
|
this.getNewRevPointer().getView().getElement().attr(
|
|
|
|
'data-pos',
|
|
|
|
this.getNewRevPointer().getPosition()
|
|
|
|
);
|
|
|
|
|
|
|
|
this.getOldRevPointer().getView().getElement().attr(
|
|
|
|
'data-pos',
|
|
|
|
this.getOldRevPointer().getPosition()
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2016-11-02 18:22:40 +00:00
|
|
|
/**
|
|
|
|
* Redraws the lines for the pointers
|
|
|
|
*/
|
|
|
|
redrawPointerLines: function () {
|
2017-04-05 15:00:08 +00:00
|
|
|
this.fadeInPointerLines();
|
2016-11-02 18:22:40 +00:00
|
|
|
$( '.mw-revslider-pointer-line-upper, .mw-revslider-pointer-line-lower' )
|
|
|
|
.removeClass( 'mw-revslider-bottom-line mw-revslider-left-line mw-revslider-right-line' );
|
|
|
|
this.pointerOlder.getLine().drawLine();
|
|
|
|
this.pointerNewer.getLine().drawLine();
|
|
|
|
},
|
|
|
|
|
2017-04-05 15:00:08 +00:00
|
|
|
/**
|
|
|
|
* Fades out the lines for the pointers
|
|
|
|
*/
|
|
|
|
fadeOutPointerLines: function () {
|
|
|
|
$( '.mw-revslider-pointer-line' ).fadeTo( 0, 0.3 );
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fades in the lines for the pointers
|
|
|
|
*/
|
|
|
|
fadeInPointerLines: function () {
|
|
|
|
$( '.mw-revslider-pointer-line' ).fadeTo( 0, 1 );
|
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* @return {number}
|
|
|
|
*/
|
2016-05-10 12:42:05 +00:00
|
|
|
calculateSliderContainerWidth: function () {
|
2016-06-27 14:00:13 +00:00
|
|
|
return Math.min(
|
|
|
|
this.slider.getRevisions().getLength(),
|
2016-08-05 16:14:28 +00:00
|
|
|
mw.libs.revisionSlider.calculateRevisionsPerWindow( this.containerMargin + this.outerMargin, this.revisionWidth )
|
2016-06-27 14:00:13 +00:00
|
|
|
) * this.revisionWidth;
|
2016-05-10 12:42:05 +00:00
|
|
|
},
|
|
|
|
|
2016-05-10 19:33:40 +00:00
|
|
|
slide: function ( direction, duration ) {
|
2016-05-21 00:10:08 +00:00
|
|
|
var animateObj,
|
2016-07-01 10:13:53 +00:00
|
|
|
$animatedElement = this.$element.find( '.mw-revslider-revisions-container' ),
|
2016-05-21 00:10:08 +00:00
|
|
|
self = this;
|
2016-05-10 20:04:21 +00:00
|
|
|
|
2016-05-10 12:42:05 +00:00
|
|
|
this.slider.slide( direction );
|
2016-05-21 00:10:08 +00:00
|
|
|
this.pointerOlder.getView().getElement().draggable( 'disable' );
|
|
|
|
this.pointerNewer.getView().getElement().draggable( 'disable' );
|
2016-05-10 20:04:21 +00:00
|
|
|
|
2016-05-10 20:47:37 +00:00
|
|
|
if ( this.slider.isAtStart() ) {
|
2016-08-05 08:45:37 +00:00
|
|
|
this.backwardArrowButton.setDisabled( true );
|
2016-05-10 20:47:37 +00:00
|
|
|
} else {
|
2016-08-05 08:45:37 +00:00
|
|
|
this.backwardArrowButton.setDisabled( false );
|
2016-05-10 20:47:37 +00:00
|
|
|
}
|
|
|
|
if ( this.slider.isAtEnd() ) {
|
2016-08-05 08:45:37 +00:00
|
|
|
this.forwardArrowButton.setDisabled( true );
|
2016-05-10 20:47:37 +00:00
|
|
|
} else {
|
2016-08-05 08:45:37 +00:00
|
|
|
this.forwardArrowButton.setDisabled( false );
|
2016-05-10 20:47:37 +00:00
|
|
|
}
|
|
|
|
|
2017-03-27 19:04:31 +00:00
|
|
|
animateObj = { scrollLeft: this.slider.getOldestVisibleRevisionIndex() * this.revisionWidth };
|
2016-10-13 04:07:28 +00:00
|
|
|
if ( this.dir === 'rtl' ) {
|
2016-05-21 00:10:08 +00:00
|
|
|
animateObj.scrollLeft = this.getRtlScrollLeft( $animatedElement, animateObj.scrollLeft );
|
|
|
|
}
|
|
|
|
|
|
|
|
$animatedElement.animate(
|
|
|
|
animateObj,
|
2016-05-10 20:04:21 +00:00
|
|
|
duration,
|
|
|
|
null,
|
|
|
|
function () {
|
2016-05-21 00:10:08 +00:00
|
|
|
self.pointerOlder.getView().getElement().draggable( 'enable' );
|
|
|
|
self.pointerNewer.getView().getElement().draggable( 'enable' );
|
2016-06-27 14:00:13 +00:00
|
|
|
|
|
|
|
if ( self.slider.isAtStart() && !self.noMoreOlderRevisions ) {
|
|
|
|
self.addOlderRevisionsIfNeeded( $( '.mw-revslider-revision-slider' ) );
|
|
|
|
}
|
|
|
|
if ( self.slider.isAtEnd() && !self.noMoreNewerRevisions ) {
|
|
|
|
self.addNewerRevisionsIfNeeded( $( '.mw-revslider-revision-slider' ) );
|
|
|
|
}
|
2016-05-10 20:04:21 +00:00
|
|
|
}
|
|
|
|
);
|
2016-05-10 12:42:05 +00:00
|
|
|
|
2016-05-20 10:42:01 +00:00
|
|
|
this.alignPointers( duration );
|
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Based on jQuery RTL Scroll Type Detector plugin by othree: https://github.com/othree/jquery.rtl-scroll-type
|
|
|
|
*
|
|
|
|
* @return {string} - 'default', 'negative' or 'reverse'
|
|
|
|
*/
|
2016-05-21 00:10:08 +00:00
|
|
|
determineRtlScrollType: function () {
|
2017-06-21 13:17:43 +00:00
|
|
|
var isChrome = /chrom(e|ium)/.test( navigator.userAgent.toLowerCase() ),
|
|
|
|
$dummy;
|
|
|
|
|
|
|
|
// in Chrome V8 5.8.283 and 5.9.211 the detection below gives wrong results leading to strange behavior
|
|
|
|
// Chrome V8 6.0 seems to fix that issue so this workaround can be removed then
|
|
|
|
if ( isChrome ) {
|
|
|
|
return 'default';
|
|
|
|
}
|
|
|
|
|
|
|
|
$dummy = $( '<div>' )
|
2016-05-21 00:10:08 +00:00
|
|
|
.css( {
|
|
|
|
dir: 'rtl',
|
|
|
|
width: '1px',
|
|
|
|
height: '1px',
|
|
|
|
position: 'absolute',
|
|
|
|
top: '-1000px',
|
|
|
|
overflow: 'scroll'
|
|
|
|
} )
|
|
|
|
.text( 'A' )
|
|
|
|
.appendTo( 'body' )[ 0 ];
|
|
|
|
if ( $dummy.scrollLeft > 0 ) {
|
|
|
|
return 'default';
|
|
|
|
} else {
|
|
|
|
$dummy.scrollLeft = 1;
|
|
|
|
if ( $dummy.scrollLeft === 0 ) {
|
|
|
|
return 'negative';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 'reverse';
|
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* @param {jQuery} $element
|
|
|
|
* @param {number} scrollLeft
|
|
|
|
* @return {number}
|
|
|
|
*/
|
2016-05-21 00:10:08 +00:00
|
|
|
getRtlScrollLeft: function ( $element, scrollLeft ) {
|
|
|
|
if ( this.rtlScrollLeftType === 'reverse' ) {
|
|
|
|
return scrollLeft;
|
|
|
|
}
|
|
|
|
if ( this.rtlScrollLeftType === 'negative' ) {
|
|
|
|
return -scrollLeft;
|
|
|
|
}
|
|
|
|
return $element.prop( 'scrollWidth' ) - $element.width() - scrollLeft;
|
|
|
|
},
|
|
|
|
|
2016-05-20 10:42:01 +00:00
|
|
|
alignPointers: function ( duration ) {
|
|
|
|
var self = this;
|
|
|
|
|
2017-04-05 15:00:08 +00:00
|
|
|
this.fadeOutPointerLines();
|
|
|
|
|
2016-05-21 00:10:08 +00:00
|
|
|
this.pointerOlder.getView()
|
2016-05-20 10:42:01 +00:00
|
|
|
.slideToSideOrPosition( this.slider, duration )
|
|
|
|
.promise().done( function () {
|
|
|
|
self.resetPointerStylesBasedOnPosition();
|
2016-11-02 18:22:40 +00:00
|
|
|
self.redrawPointerLines();
|
2016-05-20 10:42:01 +00:00
|
|
|
} );
|
2016-05-21 00:10:08 +00:00
|
|
|
this.pointerNewer.getView()
|
2016-05-20 10:42:01 +00:00
|
|
|
.slideToSideOrPosition( this.slider, duration )
|
|
|
|
.promise().done( function () {
|
|
|
|
self.resetPointerStylesBasedOnPosition();
|
2016-11-02 18:22:40 +00:00
|
|
|
self.redrawPointerLines();
|
2016-05-20 10:42:01 +00:00
|
|
|
} );
|
2016-05-10 12:42:05 +00:00
|
|
|
},
|
|
|
|
|
2016-06-17 13:06:12 +00:00
|
|
|
/**
|
|
|
|
* Returns the Pointer object that belongs to the passed element
|
|
|
|
*
|
|
|
|
* @param {jQuery} $e
|
|
|
|
* @return {Pointer}
|
|
|
|
*/
|
2016-05-10 12:42:05 +00:00
|
|
|
whichPointer: function ( $e ) {
|
2016-07-02 20:14:00 +00:00
|
|
|
return $e.hasClass( 'mw-revslider-pointer-older' ) ? this.pointerOlder : this.pointerNewer;
|
2016-06-27 14:00:13 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {jQuery} $slider
|
|
|
|
*/
|
|
|
|
addNewerRevisionsIfNeeded: function ( $slider ) {
|
|
|
|
var api = new mw.libs.revisionSlider.Api( mw.util.wikiScript( 'api' ) ),
|
|
|
|
self = this,
|
|
|
|
revisions = this.slider.getRevisions().getRevisions(),
|
2016-08-05 16:14:28 +00:00
|
|
|
revisionCount = mw.libs.revisionSlider.calculateRevisionsPerWindow( this.containerMargin + this.outerMargin, this.revisionWidth ),
|
2016-06-27 14:00:13 +00:00
|
|
|
revs;
|
|
|
|
if ( this.noMoreNewerRevisions || !this.slider.isAtEnd() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
api.fetchRevisionData( mw.config.get( 'wgPageName' ), {
|
|
|
|
startId: revisions[ revisions.length - 1 ].getId(),
|
|
|
|
dir: 'newer',
|
|
|
|
limit: revisionCount + 1,
|
2016-08-15 18:15:30 +00:00
|
|
|
knownUserGenders: this.slider.getRevisions().getUserGenders()
|
|
|
|
} ).then( function ( data ) {
|
|
|
|
revs = data.revisions.slice( 1 );
|
|
|
|
if ( revs.length === 0 ) {
|
|
|
|
self.noMoreNewerRevisions = true;
|
|
|
|
return;
|
|
|
|
}
|
2016-06-27 14:00:13 +00:00
|
|
|
|
2016-08-15 18:15:30 +00:00
|
|
|
self.addRevisionsAtEnd( $slider, revs );
|
2016-06-27 14:00:13 +00:00
|
|
|
|
2016-11-19 13:37:20 +00:00
|
|
|
if ( data.continue === undefined ) {
|
2016-08-15 18:15:30 +00:00
|
|
|
self.noMoreNewerRevisions = true;
|
2016-06-27 14:00:13 +00:00
|
|
|
}
|
|
|
|
} );
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {jQuery} $slider
|
|
|
|
*/
|
|
|
|
addOlderRevisionsIfNeeded: function ( $slider ) {
|
|
|
|
var api = new mw.libs.revisionSlider.Api( mw.util.wikiScript( 'api' ) ),
|
|
|
|
self = this,
|
|
|
|
revisions = this.slider.getRevisions().getRevisions(),
|
2016-08-05 16:14:28 +00:00
|
|
|
revisionCount = mw.libs.revisionSlider.calculateRevisionsPerWindow( this.containerMargin + this.outerMargin, this.revisionWidth ),
|
2016-06-27 14:00:13 +00:00
|
|
|
revs,
|
|
|
|
precedingRevisionSize = 0;
|
|
|
|
if ( this.noMoreOlderRevisions || !this.slider.isAtStart() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
api.fetchRevisionData( mw.config.get( 'wgPageName' ), {
|
|
|
|
startId: revisions[ 0 ].getId(),
|
|
|
|
dir: 'older',
|
|
|
|
// 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,
|
2016-08-15 18:15:30 +00:00
|
|
|
knownUserGenders: this.slider.getRevisions().getUserGenders()
|
|
|
|
} ).then( function ( data ) {
|
|
|
|
revs = data.revisions.slice( 1 ).reverse();
|
|
|
|
if ( revs.length === 0 ) {
|
|
|
|
self.noMoreOlderRevisions = true;
|
|
|
|
return;
|
|
|
|
}
|
2016-06-27 14:00:13 +00:00
|
|
|
|
2016-08-15 18:15:30 +00:00
|
|
|
if ( revs.length === revisionCount + 1 ) {
|
|
|
|
precedingRevisionSize = revs[ 0 ].size;
|
|
|
|
revs = revs.slice( 1 );
|
|
|
|
}
|
|
|
|
self.addRevisionsAtStart( $slider, revs, precedingRevisionSize );
|
2016-06-27 14:00:13 +00:00
|
|
|
|
2016-11-19 13:37:20 +00:00
|
|
|
if ( data.continue === undefined ) {
|
2016-08-15 18:15:30 +00:00
|
|
|
self.noMoreOlderRevisions = true;
|
2016-06-27 14:00:13 +00:00
|
|
|
}
|
|
|
|
} );
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {jQuery} $slider
|
|
|
|
* @param {Array} revs
|
|
|
|
*/
|
|
|
|
addRevisionsAtEnd: function ( $slider, revs ) {
|
|
|
|
var revPositionOffset = this.slider.getRevisions().getLength(),
|
|
|
|
$revisions = $slider.find( '.mw-revslider-revisions-container .mw-revslider-revisions' ),
|
|
|
|
revisionsToRender,
|
|
|
|
$addedRevisions;
|
|
|
|
|
|
|
|
this.slider.getRevisions().push( mw.libs.revisionSlider.makeRevisions( revs ) );
|
|
|
|
|
|
|
|
// Pushed revisions have their relative sizes set correctly with regard to the last previously
|
|
|
|
// loaded revision. This should be taken into account when rendering newly loaded revisions (tooltip)
|
|
|
|
revisionsToRender = this.slider.getRevisions().slice( revPositionOffset );
|
|
|
|
|
2017-03-03 13:55:42 +00:00
|
|
|
$addedRevisions = new mw.libs.revisionSlider.RevisionListView( revisionsToRender, this.dir ).render( this.revisionWidth, revPositionOffset );
|
2016-06-27 14:00:13 +00:00
|
|
|
|
|
|
|
this.addClickHandlerToRevisions( $addedRevisions, $revisions, this.revisionWrapperClickHandler );
|
|
|
|
|
|
|
|
$addedRevisions.find( '.mw-revslider-revision-wrapper' ).each( function () {
|
|
|
|
$revisions.append( $( this ) );
|
|
|
|
} );
|
|
|
|
|
|
|
|
if ( this.shouldExpandSlider( $slider ) ) {
|
|
|
|
this.expandSlider( $slider );
|
|
|
|
}
|
|
|
|
|
|
|
|
this.slider.getRevisions().getView().adjustRevisionSizes( $slider );
|
|
|
|
|
|
|
|
if ( !this.slider.isAtEnd() ) {
|
2016-08-05 08:45:37 +00:00
|
|
|
this.forwardArrowButton.setDisabled( false );
|
2016-06-27 14:00:13 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {jQuery} $slider
|
|
|
|
* @param {Array} revs
|
|
|
|
* @param {number} precedingRevisionSize optional size of the revision preceding the first of revs,
|
|
|
|
* used to correctly determine first revision's relative size
|
|
|
|
*/
|
|
|
|
addRevisionsAtStart: function ( $slider, revs, precedingRevisionSize ) {
|
|
|
|
var self = this,
|
|
|
|
$revisions = $slider.find( '.mw-revslider-revisions-container .mw-revslider-revisions' ),
|
|
|
|
$revisionContainer = $slider.find( '.mw-revslider-revisions-container' ),
|
|
|
|
revisionsToRender,
|
|
|
|
$addedRevisions,
|
|
|
|
pOld, pNew,
|
2016-08-01 10:35:35 +00:00
|
|
|
revIdOld, revIdNew,
|
2016-06-27 14:00:13 +00:00
|
|
|
revisionStyleResetRequired = false,
|
|
|
|
$oldRevElement,
|
|
|
|
scrollLeft;
|
|
|
|
|
|
|
|
this.slider.getRevisions().unshift( mw.libs.revisionSlider.makeRevisions( revs ), precedingRevisionSize );
|
|
|
|
|
|
|
|
$slider.find( '.mw-revslider-revision' ).each( function () {
|
|
|
|
$( this ).attr( 'data-pos', parseInt( $( this ).attr( 'data-pos' ), 10 ) + revs.length );
|
|
|
|
} );
|
|
|
|
|
|
|
|
// Pushed (unshifted) revisions have their relative sizes set correctly with regard to the last previously
|
|
|
|
// loaded revision. This should be taken into account when rendering newly loaded revisions (tooltip)
|
|
|
|
revisionsToRender = this.slider.getRevisions().slice( 0, revs.length );
|
|
|
|
|
2017-03-03 13:55:42 +00:00
|
|
|
$addedRevisions = new mw.libs.revisionSlider.RevisionListView( revisionsToRender, this.dir ).render( this.revisionWidth );
|
2016-06-27 14:00:13 +00:00
|
|
|
|
|
|
|
pOld = this.getOldRevPointer();
|
|
|
|
pNew = this.getNewRevPointer();
|
|
|
|
|
|
|
|
if ( pOld.getPosition() !== -1 ) {
|
|
|
|
pOld.setPosition( pOld.getPosition() + revisionsToRender.getLength() );
|
|
|
|
} else {
|
|
|
|
// Special case: old revision has been previously not loaded, need to initialize correct position
|
|
|
|
$oldRevElement = this.getOldRevElement( $addedRevisions );
|
|
|
|
if ( $oldRevElement.length !== 0 ) {
|
|
|
|
pOld.setPosition( $oldRevElement.data( 'pos' ) );
|
|
|
|
revisionStyleResetRequired = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
pNew.setPosition( pNew.getPosition() + revisionsToRender.getLength() );
|
|
|
|
|
|
|
|
this.addClickHandlerToRevisions( $addedRevisions, $revisions, this.revisionWrapperClickHandler );
|
|
|
|
|
|
|
|
$( $addedRevisions.find( '.mw-revslider-revision-wrapper' ).get().reverse() ).each( function () { // TODO: this is horrible
|
|
|
|
$revisions.prepend( $( this ) );
|
|
|
|
} );
|
|
|
|
|
|
|
|
if ( revisionStyleResetRequired ) {
|
|
|
|
this.resetRevisionStylesBasedOnPointerPosition( $slider );
|
|
|
|
}
|
|
|
|
|
2017-03-27 19:04:31 +00:00
|
|
|
this.slider.setFirstVisibleRevisionIndex( this.slider.getOldestVisibleRevisionIndex() + revisionsToRender.getLength() );
|
2016-08-16 10:36:52 +00:00
|
|
|
|
2016-08-01 10:35:35 +00:00
|
|
|
revIdOld = self.getRevElementAtPosition( $revisions, pOld.getPosition() ).data( 'revid' );
|
|
|
|
revIdNew = self.getRevElementAtPosition( $revisions, pNew.getPosition() ).data( 'revid' );
|
2017-05-08 15:45:07 +00:00
|
|
|
this.diffPage.replaceState( revIdNew, revIdOld, this );
|
2016-06-27 14:00:13 +00:00
|
|
|
|
2017-03-27 19:04:31 +00:00
|
|
|
scrollLeft = this.slider.getOldestVisibleRevisionIndex() * this.revisionWidth;
|
2016-06-27 14:00:13 +00:00
|
|
|
$revisionContainer.scrollLeft( scrollLeft );
|
2016-10-13 04:07:28 +00:00
|
|
|
if ( this.dir === 'rtl' ) {
|
2016-06-27 14:00:13 +00:00
|
|
|
$revisionContainer.scrollLeft( self.getRtlScrollLeft( $revisionContainer, scrollLeft ) );
|
|
|
|
}
|
|
|
|
|
2016-08-16 10:36:52 +00:00
|
|
|
if ( this.shouldExpandSlider( $slider ) ) {
|
|
|
|
this.expandSlider( $slider );
|
|
|
|
}
|
|
|
|
|
2016-06-27 14:00:13 +00:00
|
|
|
this.slider.getRevisions().getView().adjustRevisionSizes( $slider );
|
|
|
|
|
2016-08-05 08:45:37 +00:00
|
|
|
this.backwardArrowButton.setDisabled( false );
|
2016-06-27 14:00:13 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {jQuery} $revisions
|
|
|
|
* @param {jQuery} $allRevisions
|
|
|
|
* @param {Function} clickHandler
|
|
|
|
*/
|
|
|
|
addClickHandlerToRevisions: function ( $revisions, $allRevisions, clickHandler ) {
|
|
|
|
var self = this;
|
|
|
|
$revisions.find( '.mw-revslider-revision-wrapper' ).on(
|
|
|
|
'click',
|
|
|
|
null,
|
|
|
|
{ view: self, revisionsDom: $allRevisions },
|
|
|
|
clickHandler
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {jQuery} $slider
|
2016-09-01 11:17:47 +00:00
|
|
|
* @return {boolean}
|
2016-06-27 14:00:13 +00:00
|
|
|
*/
|
|
|
|
shouldExpandSlider: function ( $slider ) {
|
2016-10-13 18:57:36 +00:00
|
|
|
var sliderWidth = $slider.width(),
|
2016-06-27 14:00:13 +00:00
|
|
|
maxAvailableWidth = this.calculateSliderContainerWidth() + this.containerMargin;
|
|
|
|
|
2016-08-16 10:36:52 +00:00
|
|
|
return !( this.noMoreNewerRevisions && this.noMoreOlderRevisions ) && sliderWidth < maxAvailableWidth;
|
2016-06-27 14:00:13 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {jQuery} $slider
|
|
|
|
*/
|
|
|
|
expandSlider: function ( $slider ) {
|
2016-08-16 10:36:52 +00:00
|
|
|
var containerWidth = this.calculateSliderContainerWidth(),
|
|
|
|
expandedRevisionWindowCapacity;
|
2016-06-27 14:00:13 +00:00
|
|
|
|
|
|
|
$slider.css( { width: ( containerWidth + this.containerMargin ) + 'px' } );
|
|
|
|
$slider.find( '.mw-revslider-revisions-container' ).css( { width: containerWidth + 'px' } );
|
|
|
|
$slider.find( '.mw-revslider-pointer-container' ).css( { width: containerWidth + this.revisionWidth - 1 + 'px' } );
|
|
|
|
|
2016-08-16 10:36:52 +00:00
|
|
|
expandedRevisionWindowCapacity = $slider.find( '.mw-revslider-revisions-container' ).width() / this.revisionWidth;
|
|
|
|
this.slider.setRevisionsPerWindow( expandedRevisionWindowCapacity );
|
2016-06-27 14:00:13 +00:00
|
|
|
|
2016-08-16 10:36:52 +00:00
|
|
|
this.slide( Math.floor( ( this.pointerNewer.getPosition() - 1 ) / expandedRevisionWindowCapacity ), 0 );
|
2017-06-29 14:15:10 +00:00
|
|
|
},
|
2016-06-27 14:00:13 +00:00
|
|
|
|
2017-06-29 14:15:10 +00:00
|
|
|
/**
|
|
|
|
* @return {jQuery}
|
|
|
|
*/
|
|
|
|
getRevisionsElement: function () {
|
|
|
|
return this.slider.getRevisions().getView().getElement();
|
|
|
|
}
|
2016-05-10 12:42:05 +00:00
|
|
|
} );
|
|
|
|
|
|
|
|
mw.libs.revisionSlider = mw.libs.revisionSlider || {};
|
|
|
|
mw.libs.revisionSlider.SliderView = SliderView;
|
|
|
|
}( mediaWiki, jQuery ) );
|