Benutzer:Jakob Warkotsch (WMDE)/rev-slider-prototype.js
Zur Navigation springen
Zur Suche springen
Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.
- Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
- Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
- Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
- Opera: Strg+F5
// <nowiki>
// Page title
var gPageName = mw.config.get( 'wgPageName' );
// Gives us the most current revision ID for the page
var gCurRevisionId = mw.config.get( 'wgCurRevisionId' );
// Action: view/query/history
var gAction = mw.config.get( 'wgAction' );
// User name
var gUserName = mw.config.get( 'wgUserName' );
// The URL of the page, relative to DOCUMENT_ROOT
var gScript = mw.config.get( 'wgScript' );
// Revision ID of right revision on diff page
var gRightRevID = mw.config.get( 'wgRevisionId' );
// Revision ID of left revision on diff page
var gLeftRevID = mw.util.getParamValue( 'oldid' );
// Get value of diff param in URL
var gDiff = mw.util.getParamValue( 'diff' );
// Page ID
var gPageID = mw.config.get( 'wgArticleID' );
// Server
var gServer = mw.config.get( 'wgServer' );
// Slider
var revisionWidth = 10,
POINTER_WIDTH = 30,
$container = null,
$revisionSlider = null,
revs = [],
pointerPosL = -1,
pointerPosR = -1;
// Function called when a tick on the slider is clicked
// Params: v1 - Left revision ID; v2 - Right revision ID
function refresh( v1, v2 ) {
if( v1 === -1 || v2 === -1 ) return;
var $url = gServer + gScript + '?title=' + gPageName + '&diff=' + v2 + '&oldid=' + v1;
location.href = $url;
}
// Formating date in JS
function formatDate( rawDate ) {
var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'June', 'July', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec' ];
var f = new Date( rawDate );
var fDate = f.getUTCDate();
var fMonth = f.getUTCMonth();
var fYear = f.getUTCFullYear();
var fHours = ( '0' + f.getUTCHours()).slice( -2 );
var fMinutes = ( '0' + f.getUTCMinutes()).slice( -2 );
return ( fHours + ':' + fMinutes + ', ' + fDate + ' ' + months[ fMonth ] + ' ' + fYear ).toString();
}
// Setting the tick marks on the slider
// Params: element - jQuery slider; revs - revisions data from API
function setSliderTicks( element, revs ) {
var $slider = $( element ),
revData = getComposedRevData( revs ),
maxChangeSizeLogged = Math.log( revData.maxChangeSize );
for( var i = 1; i < revs.length; i++ ) {
var diffSize = revs[ i ].size - revs[ i - 1 ].size,
relativeChangeSize = Math.ceil( 65.0 * Math.log( Math.abs( diffSize ) ) / maxChangeSizeLogged ) + 5,
section = getSection( revs[ i ].comment ),
html = '<b>' + formatDate( revs[ i ].timestamp ) + '</b><br>';
html += mw.html.escape( revs[ i ].user ) + '<br>';
if( revs[ i ].comment !== '' ) {
html += '<br><i>' + mw.html.escape( revs[ i ].parsedcomment ) + '</i>';
}
//html += '<br> ' + revs[i].minor ? '<b>K</b> ' : '';
html += '<br>' + diffSize + ' byte';
$( '<div class="ui-slider-tick-mark revision" title="<center>' + html + '</center>"/>' )
.css( {
'left': i + '%',
'height': relativeChangeSize + 'px',
'top': diffSize > 0 ? '-' + relativeChangeSize + 'px' : 0,
'background': revData.sectionMap.get( section ) ? revData.sectionMap.get( section ) : 'black'
//'opacity' : revs[i].minor ? 0.15 : 0.35
//'background' : i%2 == 1 ? 'white' : 'black'
} )
.tipsy( {
gravity: 's',
html: true,
fade: true
} )
.appendTo( $slider );
$( '<div class="stopper"/>' )
.css( 'left', (i - 1) + '.5%' )
.appendTo( $slider );
}
}
function getComposedRevData( revs ) {
var max = 0,
changeSize = 0,
section,
sectionMap = new Map(),
result;
for( i = 1; i < revs.length; i++ ) {
changeSize = Math.abs( revs[ i ].size - revs[ i - 1 ].size );
section = getSection( revs[ i ].comment );
if( changeSize > max ) {
max = changeSize;
}
if( section.length > 0 && !sectionMap.has( section ) ) {
sectionMap.set( section );
}
}
var i = 0;
sectionMap.forEach( function( item, key, sectionMap ) {
sectionMap.set( key, rainbow( sectionMap.size, i ) );
i++;
} );
for( i = 0; i < sectionMap.length; i++ ) {
sectionMap.set()
}
result = {
maxChangeSize: max,
sectionMap: sectionMap
};
return result;
}
function getSection( text ) {
text = text.match(
new RegExp(
'(/\\* [^\\*]* \\*/)',
'gi' ) );
if( !text ) {
return '';
}
return text[ 0 ].replace(
new RegExp( ' \\*/|/\\* ', 'ig' ),
'' );
}
var isPointerInRange = function( pointerPos, start, end ) {
return pointerPos >= start
&& pointerPos <= Math.min( revs.length, end );
};
var scroll = function( $container, direction ) {
$container.animate( {
scrollLeft: $container.scrollLeft() + ($container.width() * direction)
} );
};
var revisionOfPosition = function( pos ) {
return Math.floor( pos / revisionWidth );
};
var slideToPosition = function( $pointer, pos ) {
var containerOffset = $container.offset().left - $revisionSlider.offset().left,
left = (pos % 100) * revisionWidth;
$pointer.animate( { left: left + containerOffset } );
};
var slideToSide = function( $pointer, pointerPos, direction ) {
var containerOffset = $revisionSlider.find( '.arrow' ).outerWidth() + 20, // 20 == margin right
isLeft = pointerPos < revisionOfPosition( $container.scrollLeft() ) + direction * revisionOfPosition( $container.width() ),
sideFactor = isLeft ? -1 : 1,
sideOffset = 3 * revisionWidth * sideFactor / 2,
offsetRight = $pointer.hasClass( 'left-pointer' ) ? -revisionWidth : 0,
xPos = isLeft ? containerOffset : $container.width() + containerOffset;
$pointer.animate( { left: xPos + offsetRight + sideOffset } );
};
// Adding the initial barebones slider
// Params: revs - revisions data from API; vals - initial positions for the slider handles
function addSlider( revs ) {
var $revisions = $( '<div class="revisions"></div>' ).css( 'width', revs.length * revisionWidth ),
$leftPointer = $( '<div class="pointer left-pointer" />' ),
$rightPointer = $( '<div class="pointer right-pointer" />' );
$revisionSlider = $( '<div class="revision-slider" />' )
.append( $( '<a class="arrow left-arrow" data-dir="-1"></a>' ) )
.append( $( '<div class="revisions-container" />' ).append( $revisions ) )
.append( $( '<a class="arrow right-arrow" data-dir="1"></a>' ) )
.append( $( '<div style="clear: both" />' ) )
.append(
$( '<div class="pointer-container" />' )
.append( $leftPointer )
.append( $rightPointer )
);
$container = $revisionSlider.find( '.revisions-container' );
$revisionSlider.find( '.arrow' ).click( function() {
var direction = $( this ).data( 'dir' ),
newStart = revisionOfPosition(
Math.min( $container.find( '.revisions' ).width() - $container.width(), Math.max( 0, $container.scrollLeft() ) )
) + (direction * revisionOfPosition( $container.width() )),
newEnd = newStart + revisionOfPosition( $container.width() );
if( isPointerInRange( pointerPosL, newStart, newEnd ) ) {
slideToPosition( $leftPointer, pointerPosL );
} else {
slideToSide( $leftPointer, pointerPosL, direction );
}
if( isPointerInRange( pointerPosR, newStart, newEnd ) ) {
slideToPosition( $rightPointer, pointerPosR );
} else {
slideToSide( $rightPointer, pointerPosR, direction );
}
scroll( $container, direction );
} );
setSliderTicks( $revisions, revs );
$revisionSlider.find( '.pointer' ).draggable( {
axis: 'x',
snap: '.stopper',
containment: '.revisions-container',
stop: function() {
var posLeft = parseInt( $( this ).css( 'left' ) ),
offset = $revisionSlider.find( '.arrow' ).outerWidth() + 20,
pos = Math.round( (posLeft + $container.scrollLeft() - offset) / revisionWidth );
if( $( this ).hasClass( 'left-pointer' ) ) pointerPosL = pos;
else pointerPosR = pos;
// refresh( pointerPosL, pointerPosR );
}
} );
$html = $( '<td colspan="4" style="text-align:center;" class="slider"></td>' ).append( $revisionSlider );
$html2 = $( '<tr>' ).append( $html );
$legendHtml = $( '<td colspan="4" style="text-align:center; font-size: 0.75em; padding: 1em 0 0.5em;"></td>' ).append( getSectionLegend( revs ) );
$element = $( '.diff > tbody > tr' ).eq( 0 ).after( $legendHtml ).after( $html2 );
revisionWidth = $( '.slider' ).width() * 90 / 10000;
slideToSide( $leftPointer, -1, 1 );
slideToSide( $rightPointer, -1, 1 );
}
function getSectionLegend( revs ) {
var revData = getComposedRevData( revs ),
html = '';
revData.sectionMap.forEach( function( item, key, sectionMap ) {
html += '<span class="rvslider-legend-box" style="color:' + item + ';"> ■</span>' + key + '';
} );
return html;
}
// Driver function
mw.loader.using( [ 'jquery.ui', 'jquery.tipsy' ], function() {
$( document ).ready( function() {
$.ajax( {
url: mw.util.wikiScript( 'api' ),
data: {
action: 'query',
prop: 'revisions',
format: 'json',
rvprop: 'ids|timestamp|user|comment|parsedcomment|size|flags',
titles: gPageName,
formatversion: 2,
rvstartid: gCurRevisionId,
"continue": "",
rvlimit: "500"
},
success: function( data ) {
revs = data.query.pages[ 0 ].revisions;
if( !revs ) {
return;
}
revs.reverse();
addSlider( revs );
}
} );
} );
} );
// see http://stackoverflow.com/a/7419630/4782503
function rainbow( numOfSteps, step ) {
// This function generates vibrant, "evenly spaced" colours (i.e. no clustering). This is ideal for creating easily distinguishable vibrant markers in Google Maps and other apps.
// Adam Cole, 2011-Sept-14
// HSV to RBG adapted from: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
var r, g, b;
var h = step / numOfSteps;
var i = ~~(h * 6);
var f = h * 6 - i;
var q = 1 - f;
switch( i % 6 ) {
case 0:
r = 1;
g = f;
b = 0;
break;
case 1:
r = q;
g = 1;
b = 0;
break;
case 2:
r = 0;
g = 1;
b = f;
break;
case 3:
r = 0;
g = q;
b = 1;
break;
case 4:
r = f;
g = 0;
b = 1;
break;
case 5:
r = 1;
g = 0;
b = q;
break;
}
var c = "#" + ("00" + (~~(r * 255)).toString( 16 )).slice( -2 ) + ("00" + (~~(g * 255)).toString( 16 )).slice( -2 ) + ("00" + (~~(b * 255)).toString( 16 )).slice( -2 );
return (c);
}
// </nowiki>