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');
var live = mw.user.options.get('uselivepreview') && (action == 'edit' || action == 'submit');
if (!live && document.getElementsByClassName('diff').length <= 0) return;
/* Borders around single characters and sequences of whitespace, punctuation and other non-letters */
var wsRegex = /^(?:.|[^\w\xC0-\xD6\xD8-\xF6\u00F8-\u02AF\u0370-\u1FFE\u2C00-\uFEFC]+)$/;
var wsClass = 'diffchange-extra';
mw.util.addCSS(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; }');
if (live) $(mw).on('LivePreviewDone', cleanDiff);
cleanDiff();
function cleanDiff()
{
var diffs = document.getElementsByClassName('diff');
if (!diffs || diffs.length <= 0) 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];
var dels = tr.getElementsByClassName('diff-deletedline');
var adds = tr.getElementsByClassName('diff-addedline');
var emps = tr.getElementsByClassName('diff-empty');
var isDel = dels.length == 1 && adds.length == 0 && emps.length == 1;
var isAdd = dels.length == 0 && adds.length == 1 && emps.length == 1;
var isChange = dels.length == 1 && adds.length == 1 && emps.length == 0;
/* 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();
var tds = moveUp.getElementsByTagName('TD');
tr.appendChild(tds[2]);
tr.appendChild(tds[2]);
moveUp.appendChild(emps[0]);
continue;
}
/* Angebliche Änderungen sammeln, wenn die linke Seite leer ist */
else if (isChange && dels[0].firstChild.nodeType == 1 && !dels[0].firstChild.firstChild)
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();
var tds = moveDown.getElementsByTagName('TD');
tr.insertBefore(tds[1], tr.firstChild);
tr.insertBefore(tds[0], tr.firstChild);
moveDown.insertBefore(emps[0], moveDown.firstChild);
continue;
}
/* Angebliche Änderungen sammeln, wenn die rechte Seite leer ist */
else if (isChange && adds[0].firstChild.nodeType == 1 && !adds[0].firstChild.firstChild)
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 */
var tds = lastDel.getElementsByTagName('TD');
while (tds.length > 2) lastDel.removeChild(tds[2]);
var 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';
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');
var add = lines[i].getElementsByClassName('diff-addedline');
if (del && add && del.length > 0 && add.length > 0)
{
var dels = del[0].getElementsByClassName('diffchange');
var 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 <= 0 && adds.length <= 0) 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 (var i = 1; i < l2; i++)
cleanChange(dels[dels.length - i], adds[adds.length - i]);
}
function cleanChange(d, a)
{
/* 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)
{
var t1 = d.previousSibling.data, t2 = a.previousSibling.data;
var 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)
{
var t1 = d.nextSibling.data, t2 = a.nextSibling.data;
var l = Math.min(t1.length, t2.length);
if (t1.slice(0, l) != t2.slice(0, l)) return false;
}
var t1 = d.firstChild.data, t2 = a.firstChild.data;
/* Keine Optimierung versuchen, wenn beides gleich ist und nichts mehr übrig bleiben würde */
if (t1 == t2) return true;
var p1 = 0, p2 = 0, 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 <= 0 && p2 <= 0) 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);
}
d.firstChild.data = t1.substring(p1, t1.length - p2);
a.firstChild.data = t2.substring(p1, t2.length - p2);
return true;
}
function cleanWhitespaceChanges(a)
{
for (var i = 0, length = a.length; i < length; i++)
if (wsRegex.test(a[i].firstChild.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)
{
/* Die Funktion verbraucht drei Viertel der Zeit, deshalb bei langen Diffs abschalten */
var limit = typeof window.cleanDiffLinkLimit != 'undefined' ? window.cleanDiffLinkLimit : 100;
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>)*)(?=[<\]|])/g,
function($0, $1, $2)
{
return $2 ? $1 + '<a href="' + mw.util.wikiGetlink($2.replace(/<[^>]*>*/g, '')) +
'">' + $2 + '</a>' : $0;
});
});
}
})(jQuery, mediaWiki);