Benutzer:TMg/cleanDiff.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
- Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
/**
* Säubert die Versionsvergleiche und entfernt Markierungen, wo sich nichts geändert hat. Siehe Diskussionsseite.
*/
( function( $, mw ) {
/* Quit as fast as possible if there is nothing to do. Doesn't use jQuery for performance reasons */
if ( !document.getElementsByClassName ) {
return;
}
var action = mw.config.get( 'wgAction' ),
live = mw.user.options.get( 'uselivepreview' ) && ( action === 'edit' || action === 'submit' );
if ( !live && !document.getElementsByClassName( 'diff' ).length ) {
return;
}
/* Borders around single characters and sequences of whitespace, punctuation and other non-letters */
var wsRegex = /[\wÀ-ÖØ-öø-\u02AF\u0370-\u1FFE\u2C00-\uFEFC]/,
wsClass = 'diffchange-extra',
wsCss = mw.user.options.get( 'gadget-old-diff-style' )
? 'td.diff-deletedline .diffchange.' + wsClass + ','
+ 'td.diff-addedline .diffchange.' + wsClass
+ '{ background: rgba(255, 0, 0, .1); border: 1px solid red;'
+ 'border-color: rgba(255, 0, 0, .5); border-radius: 2px; padding: 0 1px; }'
: '.' + wsClass + '{ border: 0 solid #FFD366; border-width: 0 2px; }'
+ '.diff-addedline .' + wsClass + ' { border-color: #99CFFF; }';
mw.loader.using( 'mediawiki.util', function () {
mw.util.addCSS( wsCss );
} );
mw.hook( 'wikipage.diff' ).add( function ( $diffs ) {
if ( !$diffs.length ) {
return;
}
var lines = $diffs[0].getElementsByTagName( 'TR' );
if ( !lines || lines.length < 3 ) {
return;
}
cleanDisconnectedLines( lines );
cleanChangedLines( lines );
createLinks( lines );
} );
function cleanDisconnectedLines( lines ) {
var moveUps = [],
moveDowns = [],
lastDels = [];
/* Warning, don't pre-calculate the length. It changes due to deleted nodes */
for ( var i = 0; i < lines.length; i++ ) {
var tr = lines[i],
tds,
dels = tr.getElementsByClassName( 'diff-deletedline' ),
adds = tr.getElementsByClassName( 'diff-addedline' ),
emps = tr.getElementsByClassName( 'diff-empty' ),
isDel = dels.length === 1 && !adds.length && emps.length === 1,
isAdd = !dels.length && adds.length === 1 && emps.length === 1,
isChange = dels.length === 1 && adds.length === 1 && !emps.length;
/* Sonderfall, wenn angeblich eine Leerzeile durch eine gefüllte ersetzt
und danach eine gefüllte Zeile gelöscht wurde */
if ( moveUps.length > 0 && isDel && dels[0].firstChild ) {
/* Markierung der Löschung nachholen, die Ersetzung ist schon markiert */
markAllChanged( dels[0] );
var moveUp = moveUps.shift() ;
tds = moveUp.getElementsByTagName( 'TD' );
tr.appendChild( tds[2] );
tr.appendChild( tds[2] );
moveUp.appendChild( emps[0] );
continue;
} else if ( isChange && dels[0].firstChild.nodeType === 1 && !dels[0].firstChild.firstChild ) {
/* Angebliche Änderungen sammeln, wenn die linke Seite leer ist */
moveUps.push( tr );
} else if ( !isDel ) {
moveUps = [];
}
/* Sonderfall, wenn angeblich eine gefüllte durch eine Leerzeile ersetzt
und danach eine gefüllte Zeile eingefügt wurde */
if ( moveDowns.length > 0 && isAdd && adds[0].firstChild ) {
/* Markierung der Einfügung nachholen, die Ersetzung ist schon markiert */
markAllChanged( adds[0] );
var moveDown = moveDowns.shift();
tds = moveDown.getElementsByTagName( 'TD' );
tr.insertBefore( tds[1], tr.firstChild );
tr.insertBefore( tds[0], tr.firstChild );
moveDown.insertBefore( emps[0], moveDown.firstChild );
continue;
} else if ( isChange && adds[0].firstChild.nodeType === 1 && !adds[0].firstChild.firstChild ) {
/* Angebliche Änderungen sammeln, wenn die rechte Seite leer ist */
moveDowns.push( tr );
} else if ( !isAdd ) {
moveDowns = [];
}
var cons = tr.getElementsByClassName( 'diff-context' );
/* Einfügungen sowie leere Kontextzeilen nach oben schieben,
wenn zuvor passende Löschungen gefunden wurden */
if ( lastDels.length > 0 && ( isAdd || ( cons.length === 2 && !cons[0].firstChild && !cons[1].firstChild ) ) ) {
var lastDel = lastDels.shift();
/* Leere rechte Seite der Löschung wegwerfen */
tds = lastDel.getElementsByTagName( 'TD' );
while ( tds.length > 2 ) {
lastDel.removeChild( tds[2] );
}
tds = tr.getElementsByTagName( 'TD' );
if ( tds.length === 4 ) {
/* Die beiden Hälften der Kontextzeile als Löschung und Einfügung markieren */
tds[0].firstChild.data = '−';
tds[1].className = 'diff-deletedline';
tds[2].firstChild.data = '+';
tds[3].className = 'diff-addedline';
/* Rechte Hälfte der Kontextzeile nach oben zur vorher gefundenen Löschung schieben */
lastDel.appendChild( tds[2] );
lastDel.appendChild( tds[2] );
/* Die unten verbliebene linke Hälfte der Kontextzeile vervollständigen */
var td = document.createElement( 'TD' );
td.colSpan = 2;
td.className = 'diff-empty';
tr.appendChild( td );
} else {
/* Einfügung nach oben zur Löschung schieben */
lastDel.appendChild( tds[1] );
lastDel.appendChild( tds[1] );
/* Leeren Rest der Einfügung wegwerfen */
tr.parentNode.removeChild( tr );
/* Korrektur, weil die iterierte NodeList soeben ihre Länge verändert hat */
i--;
}
markAllChanged( lastDel );
} else if ( isDel ) {
lastDels.push( tr );
} else {
lastDels = [];
}
}
}
function markAllChanged( e ) {
/* Alles als Änderung markieren. Schrumpfung der Markierung passiert losgelöst davon sowieso noch */
var divs = e.getElementsByTagName( 'DIV' );
for ( var i = divs.length; i--; ) {
var div = divs[i];
if ( div.getElementsByTagName( 'SPAN' ).length > 0 ) {
continue;
}
var span = document.createElement( 'SPAN' );
span.className = 'diffchange diffchange-inline';
/* Include possible <a> elements, e.g. because of [[User:Schnark/js/linkUnlinked.js]] */
while ( div.firstChild ) span.appendChild( div.firstChild );
div.appendChild( span );
}
}
function cleanChangedLines( lines ) {
for ( var i = 0, length = lines.length; i < length; i++ ) {
var del = lines[i].getElementsByClassName( 'diff-deletedline' ),
add = lines[i].getElementsByClassName( 'diff-addedline' );
if ( del && add && del.length > 0 && add.length > 0 ) {
var dels = del[0].getElementsByClassName( 'diffchange' ),
adds = add[0].getElementsByClassName( 'diffchange' );
/*
* Vor der Fehlerbehebung vom 20. Januar 2012 wurden solche
* Phantom-Änderungen durch Leerzeichen am Zeilenende ausgelöst.
*/
if ( !dels.length && !adds.length ) {
cleanChangedLineEnding( del[0], add[0] );
} else {
cleanChangedLine( dels, adds );
}
cleanWhitespaceChanges( dels );
cleanWhitespaceChanges( adds );
}
}
}
function cleanChangedLine( dels, adds ) {
var l1 = Math.min( dels.length, adds.length ),
l2 = l1 + 1;
for ( var i = 0; i < l1; i++ ) {
if ( cleanChange( dels[i], adds[i] ) ) {
l2 = l1 - i;
}
}
/* Zweite Suche nach zueinander passenden Änderungen vom Zeilenende */
for ( i = 1; i < l2; i++ ) {
cleanChange( dels[dels.length - i], adds[adds.length - i] );
}
}
function cleanChange( d, a ) {
var e1, e2, t1, t2, l,
p1 = 0,
p2 = 0;
/* Keine Optimierung, wenn sich der Text davor/dahinter geändert hat, dann ist es eine Verschiebung */
if ( d.previousSibling && d.previousSibling.nodeType === 3 && a.previousSibling && a.previousSibling.nodeType === 3 ) {
t1 = d.previousSibling.data;
t2 = a.previousSibling.data;
l = Math.min( t1.length, t2.length );
if ( t1.slice( t1.length - l ) !== t2.slice( t2.length - l ) ) {
return false;
}
}
if ( d.nextSibling && d.nextSibling.nodeType === 3 && a.nextSibling && a.nextSibling.nodeType === 3 ) {
t1 = d.nextSibling.data;
t2 = a.nextSibling.data;
l = Math.min( t1.length, t2.length );
if ( t1.slice( 0, l ) !== t2.slice( 0, l ) ) {
return false;
}
}
e1 = d;
e2 = a;
while ( e1.firstChild ) e1 = e1.firstChild;
while ( e2.firstChild ) e2 = e2.firstChild;
/* Keine Optimierung versuchen, wenn beides gleich ist und nichts mehr übrig bleiben würde */
if ( !e1 || !e2 || !e1.data || !e2.data || e1.data === e2.data ) {
return true;
}
t1 = e1.data;
t2 = e2.data;
l = Math.min( t1.length, t2.length );
while ( p1 < l && t1.charAt( p1 ) === t2.charAt( p1 ) ) {
p1++;
}
l -= p1;
while ( p2 < l && t1.charAt( t1.length - 1 - p2 ) === t2.charAt( t2.length - 1 - p2 ) ) {
p2++;
}
/* Vorzeitig abbrechen, wenn keine Übereinstimmung gefunden wurde */
if ( !p1 && !p2 ) {
return false;
}
if ( p1 > 0 ) {
d.parentNode.insertBefore( document.createTextNode( t1.substr( 0, p1 ) ), d );
a.parentNode.insertBefore( document.createTextNode( t2.substr( 0, p1 ) ), a );
}
if ( p2 > 0 ) {
d.parentNode.insertBefore( document.createTextNode( t1.substr( t1.length - p2 ) ), d.nextSibling );
a.parentNode.insertBefore( document.createTextNode( t2.substr( t2.length - p2 ) ), a.nextSibling );
}
e1.data = t1.substring( p1, t1.length - p2 );
e2.data = t2.substring( p1, t2.length - p2 );
return true;
}
function cleanWhitespaceChanges( a ) {
for ( var i = 0, length = a.length; i < length; i++ ) {
var e = a[i].firstChild;
if ( e.nodeType === 3 && ( e.data.length < 2 || !wsRegex.test( e.data ) ) ) {
a[i].className += ' ' + wsClass;
}
}
}
function cleanChangedLineEnding( del, add ) {
while ( del && del.nodeType === 1 ) del = del.lastChild;
while ( add && add.nodeType === 1 ) add = add.lastChild;
if ( !del || !add || del.nodeType !== 3 || add.nodeType !== 3 || del.data === add.data ) {
return;
}
var p = 0,
t1 = del.data,
t2 = add.data,
l = Math.min( t1.length, t2.length );
while ( p < l && t1.charAt( p ) === t2.charAt( p ) ) {
p++;
}
if ( p > 0 ) {
del.data = t1.substr( 0, p );
add.data = t2.substr( 0, p );
var span = document.createElement( 'SPAN' );
span.className = 'diffchange diffchange-inline ' + wsClass;
span.appendChild( document.createTextNode( t1.substr( p ).replace( / /g, '\xA0' ) ) );
if ( span.firstChild.data.length > 0 ) {
del.parentNode.appendChild( span );
}
span = span.cloneNode( true );
span.firstChild.data = t2.substr( p ).replace( / /g, '\xA0' );
if ( span.firstChild.data.length > 0 ) {
add.parentNode.appendChild( span );
}
}
}
function createLinks( lines ) {
/* Off by default because of a Firefox bug */
var limit = typeof window.cleanDiffLinkLimit !== 'undefined' ? window.cleanDiffLinkLimit : -1;
if ( lines.length > limit ) {
return;
}
for ( var i = lines.length; --i; ) {
$( 'DIV', lines[i] ).html( function( i, html ) {
return html.replace(
/<[^>]*|(\[\[(?:<\/span>)?)((?:[:\w\xC0-\uD7FF]|<span[^>]*>[:\w\xC0-\uD7FF][^&<=>[\]{|}]*<\/span>)(?:[^&<=>[\]{|}]+|<span[^>]*>[^&<=>[\]{|}]*<\/span>)*)(?=(?:<span[^>]*>)?[\]|])/g,
function( $0, $1, $2 ) {
return $2
? $1 + '<a href="' + mw.util.getUrl( $2.replace( /<[^>]*>*/g, '' ) )
+ '">' + $2 + '<\/a>'
: $0;
} );
} );
}
}
} )( jQuery, mediaWiki );