mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/RevisionSlider
synced 2024-11-15 11:40:43 +00:00
d737153e29
This adjusts the position of the tooltip depending on what is the position of the related revision bar in the plot, and on the size of the contents of the tooltip. This change makes the tooltip be always displayed below the revision plot, so it is visible to the user no matter if there is enough (visible) space above the plot. Also now it is checked if there is enough space on the left and right side of the browser window to display the tooltip centered horizontally. If not, this adjusts the horizontal position of the tooltip so that it does not get shown outside of the window. The latter in particular improves displaying of longer edit summaries in RTL mode. Apparently LTR-centered browsers took care of not showing the tooltip outside the right edge of the window but in the case of left edge the tooltip could run outside of the window leaving a part of summary not visible to the user without scrolling. Bug: T141071 Bug: T141093 Change-Id: I8d519c5fd42d8403b527fa97d72a5c46991fc27b
266 lines
7.1 KiB
JavaScript
266 lines
7.1 KiB
JavaScript
( function ( mw, $ ) {
|
|
/**
|
|
* @param {RevisionList} revisionList
|
|
* @constructor
|
|
*/
|
|
var RevisionListView = function ( revisionList ) {
|
|
this.revisionList = revisionList;
|
|
};
|
|
|
|
$.extend( RevisionListView.prototype, {
|
|
/**
|
|
* @type {RevisionList}
|
|
*/
|
|
revisionList: null,
|
|
|
|
/**
|
|
* @type {number}
|
|
*/
|
|
tooltipTimeout: -1,
|
|
|
|
/**
|
|
* @type {jQuery}
|
|
*/
|
|
currentTooltip: null,
|
|
|
|
/**
|
|
* @param {number} revisionTickWidth
|
|
* @return {jQuery}
|
|
*/
|
|
render: function ( revisionTickWidth ) {
|
|
var $html = $( '<div>' ).addClass( 'mw-revslider-revisions' ),
|
|
revs = this.revisionList.getRevisions(),
|
|
maxChangeSizeLogged = Math.log( this.revisionList.getBiggestChangeSize() ),
|
|
self = this,
|
|
i, diffSize, tooltip, relativeChangeSize,
|
|
showTooltip = function () {
|
|
self.showTooltip( $( this ) );
|
|
$( this ).tipsy( 'show' );
|
|
},
|
|
hideTooltip = function () {
|
|
self.hideTooltip( $( this ) );
|
|
},
|
|
tooltipGravity = function () {
|
|
// Returns a function setting a gravity of the tooltip so that it will be entirely visible
|
|
// Based on tipsy's own $.fn.tipsy.autoBounds, with considering the width of the
|
|
// inner contents of the tooltip, and assuming the gravity always starts with 'n'
|
|
return function () {
|
|
var dir = 'n',
|
|
$this = $( this ),
|
|
$tip = $this.tipsy( true ).$tip,
|
|
boundLeft = $( document ).scrollLeft() + $tip.outerWidth();
|
|
|
|
if ( $this.offset().left < boundLeft ) {
|
|
dir += 'w';
|
|
}
|
|
if ( $( window ).width() + $( document ).scrollLeft() - $this.offset().left < 0 ) {
|
|
dir += 'e';
|
|
}
|
|
|
|
return dir;
|
|
};
|
|
};
|
|
|
|
for ( i = 0; i < revs.length; i++ ) {
|
|
diffSize = revs[ i ].getRelativeSize();
|
|
relativeChangeSize = diffSize !== 0 ? Math.ceil( 65.0 * Math.log( Math.abs( diffSize ) ) / maxChangeSizeLogged ) + 5 : 0;
|
|
tooltip = this.makeTooltip( revs[ i ] );
|
|
|
|
$html
|
|
.append( $( '<div>' )
|
|
.addClass( 'mw-revslider-revision-wrapper' )
|
|
.attr( 'title', tooltip )
|
|
.width( revisionTickWidth )
|
|
.tipsy( {
|
|
gravity: tooltipGravity(),
|
|
html: true,
|
|
trigger: 'manual',
|
|
className: 'mw-revslider-revision-tooltip mw-revslider-revision-tooltip-' + ( i + 1 )
|
|
} )
|
|
.append( $( '<div>' )
|
|
.addClass( 'mw-revslider-revision' )
|
|
.attr( 'data-revid', revs[ i ].getId() )
|
|
.attr( 'data-pos', i + 1 )
|
|
.css( {
|
|
height: relativeChangeSize + 'px',
|
|
width: revisionTickWidth + 'px',
|
|
top: diffSize > 0 ? '-' + relativeChangeSize + 'px' : 0
|
|
} )
|
|
.addClass( diffSize > 0 ? 'mw-revslider-revision-up' : 'mw-revslider-revision-down' )
|
|
.append( $( '<div>' ).addClass( 'mw-revslider-revision-border-box' ) )
|
|
)
|
|
.mouseover( showTooltip )
|
|
.mouseout( hideTooltip )
|
|
);
|
|
}
|
|
|
|
this.keepTooltipsOnHover();
|
|
|
|
return $html;
|
|
},
|
|
|
|
/**
|
|
* Hides the current tooltip immediately
|
|
*/
|
|
hideCurrentTooltip: function () {
|
|
if ( this.tooltipTimeout !== -1 ) {
|
|
window.clearTimeout( this.tooltipTimeout );
|
|
this.currentTooltip.tipsy( 'hide' );
|
|
this.currentTooltip.removeClass( 'mw-revslider-revision-wrapper-hovered' );
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Hides the tooltip after 500ms
|
|
*
|
|
* @param {jQuery} $rev
|
|
*/
|
|
hideTooltip: function ( $rev ) {
|
|
this.tooltipTimeout = window.setTimeout( function () {
|
|
$rev.tipsy( 'hide' );
|
|
$rev.removeClass( 'mw-revslider-revision-wrapper-hovered' );
|
|
}, 500 );
|
|
},
|
|
|
|
/**
|
|
* Hides the previous tooltip and shows the new one
|
|
*
|
|
* @param {jQuery} $rev
|
|
*/
|
|
showTooltip: function ( $rev ) {
|
|
this.hideCurrentTooltip();
|
|
$rev.tipsy( 'show' );
|
|
$rev.addClass( 'mw-revslider-revision-wrapper-hovered' );
|
|
this.currentTooltip = $rev;
|
|
},
|
|
|
|
/**
|
|
* Sets event handlers on tooltips so they do not disappear when hovering over them
|
|
*/
|
|
keepTooltipsOnHover: function () {
|
|
var self = this;
|
|
|
|
$( document )
|
|
.on( 'mouseover', '.mw-revslider-revision-tooltip', function () {
|
|
window.clearTimeout( self.tooltipTimeout );
|
|
} )
|
|
.on( 'mouseout', '.mw-revslider-revision-tooltip', function () {
|
|
self.hideTooltip( self.currentTooltip );
|
|
} );
|
|
},
|
|
|
|
/**
|
|
* Generates the HTML for a tooltip that appears on hover above each revision on the slider
|
|
*
|
|
* @param {Revision} rev
|
|
* @return {string}
|
|
*/
|
|
makeTooltip: function ( rev ) {
|
|
var $tooltip = $( '<div>' )
|
|
.append(
|
|
$( '<p>' ).append(
|
|
mw.message( 'revisionslider-label-date', rev.getFormattedDate() ).parseDom()
|
|
),
|
|
this.makeUserLine( rev.getUser() ),
|
|
this.makeCommentLine( rev ),
|
|
this.makePageSizeLine( rev.getSize() ),
|
|
this.makeChangeSizeLine( rev.getRelativeSize() ),
|
|
rev.isMinor() ? $( '<p>' ).text( mw.message( 'revisionslider-minoredit' ).text() ) : ''
|
|
);
|
|
return $tooltip.html();
|
|
},
|
|
|
|
/**
|
|
* Generates a link to user page or to contributions page for IP addresses
|
|
*
|
|
* @param {string} user
|
|
* @return {string}
|
|
*/
|
|
getUserPage: function ( user ) {
|
|
return ( mw.util.isIPAddress( user, false ) ? 'Special:Contributions/' : 'User:' ) + mw.html.escape( user );
|
|
},
|
|
|
|
/**
|
|
* Generates the HTML for the user label
|
|
*
|
|
* @param {string} userString
|
|
* @return {string|jQuery}
|
|
*/
|
|
makeUserLine: function ( userString ) {
|
|
if ( !userString ) {
|
|
return '';
|
|
}
|
|
|
|
return $( '<bdi>' ).append( $( '<p>' ).append(
|
|
mw.message( 'revisionslider-label-username', mw.html.escape( userString ), this.getUserPage( userString ) ).parseDom()
|
|
) );
|
|
},
|
|
|
|
/**
|
|
* Generates the HTML for the comment label
|
|
*
|
|
* @param {Revision} rev
|
|
* @return {string|jQuery}
|
|
*/
|
|
makeCommentLine: function ( rev ) {
|
|
if ( rev.hasEmptyComment() ) {
|
|
return '';
|
|
}
|
|
|
|
return $( '<bdi>' ).append(
|
|
$( '<p>' ).append(
|
|
$( '<strong>' ).text( mw.message( 'revisionslider-label-comment' ).text() ),
|
|
$( '<em>' ).append(
|
|
rev.getParsedComment()
|
|
)
|
|
)
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Generates the HTML for the page size label
|
|
*
|
|
* @param {number} size
|
|
* @return {jQuery}
|
|
*/
|
|
makePageSizeLine: function ( size ) {
|
|
return $( '<p>' ).append(
|
|
mw.message( 'revisionslider-label-page-size', mw.language.convertNumber( size ), size ).parseDom()
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Generates the HTML for the change size label
|
|
*
|
|
* @param {number} relativeSize
|
|
* @return {jQuery}
|
|
*/
|
|
makeChangeSizeLine: function ( relativeSize ) {
|
|
var changeSizeClass = 'mw-revslider-change-none',
|
|
leadingSign = '',
|
|
$changeNumber;
|
|
|
|
if ( relativeSize > 0 ) {
|
|
changeSizeClass = 'mw-revslider-change-positive';
|
|
leadingSign = '+';
|
|
} else if ( relativeSize < 0 ) {
|
|
changeSizeClass = 'mw-revslider-change-negative';
|
|
}
|
|
|
|
$changeNumber = $( '<span>' )
|
|
.addClass( changeSizeClass )
|
|
.attr( {
|
|
dir: 'ltr' // Make sure that minus/plus is on the left
|
|
} )
|
|
.text( leadingSign + mw.language.convertNumber( relativeSize ) );
|
|
|
|
return $( '<p>' ).append(
|
|
mw.message( 'revisionslider-label-change-size', $changeNumber, relativeSize ).parseDom()
|
|
);
|
|
}
|
|
} );
|
|
|
|
mw.libs.revisionSlider = mw.libs.revisionSlider || {};
|
|
mw.libs.revisionSlider.RevisionListView = RevisionListView;
|
|
}( mediaWiki, jQuery ) );
|