User:Teester/HoverDiff.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
var hovering = false;
var domElement;
var domElementName;
var hoverdiffPointerInTopHalf = false;
function getUrlParameter(url, sParam) {
var sURLVariables = url.split('&');
for (var i = 0; i < sURLVariables.length; i++) {
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : sParameterName[1];
}
}
}
function writeIntoDocument(data) {
title = data.compare["*"];
if (title.match("<!-- diff cache key")) {
var indexLocation = title.match("<!-- diff cache key").index;
title = title.substring(0, indexLocation) + "<tr><td colspan='4'>{{Reflist}}</td></tr>";
}
this.pageTitle = data.compare.totitle;
title = title.replace(/</g, "<");
title = title.replace(/>/g," >");
title = title.replace(/<!--.*-- >/g, "");
title = title.replace(/<ref name=([\x00-\xFF]*?)\/ >/g, "");
title = title.replace(/href="https:\/\//g, 'href="bibbles');
title = title.replace(/href="http:\/\//g, 'href="bibble');
title = encodeURIComponent(title);
title = title.replace(/#/g, "%23");
if (title.match("%3Cdiv%3E%5B%5BCategory%3A")) {
parsed(title);
} else {
$.ajax({
type: "POST",
datatype: "json",
url: "/w/api.php",
data: "action=parse&disablelimitreport=true&title=" + this.pageTitle + "&format=json&disabletidy=true&contentmodel=wikitext&prop=text&text=" + title
})
.done(function( data ) {
title = data.parse.text["*"];
parsed(title);
})
.fail(function() {
parsed(title);
});
}
}
function parsed(data) {
data = data.substring(29, data.length-6);
try {
title = decodeURIComponent(data);
} catch (err) {
title = data;
}
title = title.replace(/</g, "<");
title = title.replace(/>/g, ">");
title = title.replace(/&/g, "&");
//Headings
title = title.replace(/<div>====/g, "<div><span class=\"mw-headline\"><h4>");
title = title.replace(/====<\/div>/g, "<\/div><\/span><\/h4>");
title = title.replace(/<div>===/g, "<div><span class=\"mw-headline\"><h3>");
title = title.replace(/===<\/div>/g, "<\/div><\/span><\/h3>");
title = title.replace(/<div>==/g, "<div><span class=\"mw-headline\"><h2>");
title = title.replace(/==<\/div>/g, "<\/div><\/span><\/h2>");
//For a wikidata parsing bug
title = title.replace(/bibbles/g, "http://");
title = title.replace(/bibble/g, "https://");
addPopupToPage(title);
}
function addPopupToPage(content) {
if (this.hoverdiffPointerInTopHalf === true) {
divClass = "hoverdiff-diff hoverdiff hoverdiff-fade-in-up hoverdiff-standard-y";
} else {
divClass = "hoverdiff-diff hoverdiff hoverdiff-fade-in-down hoverdiff-flipped-y";
}
stylesheet = getStylesheet();
$('html > head').append("<style>"+stylesheet+"</style>");
var svg = '<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0"><defs><clippath id="hoverdiff-mask"><polygon points="0 8, 10 8, 18 0, 26 8, 1000 8, 1000 1000, 0 1000"/></clippath><clippath id="hoverdiff-mask-flip"><polygon points="0 8, 274 8, 282 0, 290 8, 1000 8, 1000 1000, 0 1000"/></clippath><clippath id="hoverdiff-landscape-mask"><polygon points="0 8, 174 8, 182 0, 190 8, 1000 8, 1000 1000, 0 1000"/></clippath><clippath id="hoverdiff-landscape-mask-flip"><polygon points="0 0, 1000 0, 1000 242, 190 242, 182 250, 174 242, 0 242"/></clippath></defs></svg>';
if (this.hoverdiffPointerInTopHalf === true) {
hoverdiffLocation = "top:" + (this.domElement.position().top + 25) + "px;left:" + this.domElement.position().left + "px;";
} else {
height = this.domElement.closest(this.domElementName).height();
if (this.domElementName == ".mw-body") {
height = height-50;
}
if (this.domElementName == "#mw-content-text") {
height = height + 35;
}
hoverdiffLocation = "bottom:" + (height - this.domElement.position().top + 10) + "px;left:" + this.domElement.position().left + "px;";
}
html = "<div id='hoverdiff-svg'>" + svg + "</div><div class='" + divClass + "' role='tooltip' style='" + hoverdiffLocation + ";max-width:"+ window.innerWidth*0.7 +"px;max-height:300px;'><div class='hoverdiff-container'><div class='hoverdiff-extract' style='max-height:280px;overflow:auto;'><table class='hoverdiff-table'></table></div></div></div>" ;
this.domElement.append(html);
$(".hoverdiff-table").append(content);
$(".diff-addedline div").css("background-color", "#7fd7c4");
$(".diff-deletedline div").css("background-color", "#e88e89");
scrollToChanges();
}
function getStylesheet() {
var stylesheet = "@keyframes hoverdiff-fade-in-up {0% {opacity:0;transform:translate(0,20px)} 100% {opacity:1;transform:translate(0,0)}} ";
stylesheet += "@keyframes hoverdiff-fade-out-down { 0% {opacity:1; transform:translate(0,0)} 100% { opacity:0; transform:translate(0,20px)}}";
stylesheet += "@keyframes hoverdiff-fade-in-down {0% {opacity:0;transform:translate(0,-20px)} 100% {opacity:1;transform:translate(0,0)}} ";
stylesheet += "@keyframes hoverdiff-fade-out-up { 0% {opacity:1; transform:translate(0,0)} 100% { opacity:0; transform:translate(0,-20px)}}";
stylesheet += ".hoverdiff-fade-in-up { animation:hoverdiff-fade-in-up 0.2s ease forwards}";
stylesheet += ".hoverdiff-fade-out-down { animation:hoverdiff-fade-out-down 0.2s ease forwards}";
stylesheet += ".hoverdiff-fade-in-down { animation:hoverdiff-fade-in-down 0.2s ease forwards}";
stylesheet += ".hoverdiff-fade-out-up { animation:hoverdiff-fade-out-up 0.2s ease forwards}";
stylesheet += ".hoverdiff .hoverdiff-extract { margin:16px; display:block; color:#222222; text-decoration:none; position:relative;}";
stylesheet += ".hoverdiff {background:#fff; position:absolute; z-index:110; box-shadow:0 30px 90px -20px rgba(0,0,0,0.3),0 0 1px #a2a9b1; padding:10px; font-size:14px; line-height:20px; min-width:300px;border-radius:2px;}";
stylesheet += ".hoverdiff .hoverdiff-container {color:#222222; margin-top:-9px; padding-top:9px; text-decoration:none}";
stylesheet += ".hoverdiff.hoverdiff-standard-y:before { content:''; position:absolute; border:8px solid transparent; border-top:0; border-bottom:8px solid #a2a9b1; top:-8px; left:10px}";
stylesheet += ".hoverdiff.hoverdiff-standard-y:after { content:''; position:absolute; border:11px solid transparent; border-top:0; border-bottom:11px solid #ffffff; top:-7px; left:7px}";
stylesheet += ".hoverdiff.hoverdiff-flipped-y:before { content:''; position:absolute; border:8px solid transparent; border-bottom:0; border-top:8px solid #a2a9b1; bottom:-8px; left:10px}";
stylesheet += ".hoverdiff.hoverdiff-flipped-y:after { content:''; position:absolute; border:11px solid transparent; border-bottom:0; border-top:11px solid #ffffff; bottom:-7px; left:7px}";
stylesheet += "#hoverdiff-svg {position:absolute;top:-1000px}";
stylesheet += ".hoverdiff-table { table-layout: fixed; }";
stylesheet += ".hoverdiff-table td { max-width:" + window.innerWidth*0.375 + "px; }";
return stylesheet;
}
function scrollToChanges() {
var container = $(".hoverdiff-extract");
var diffChange = $(".diffchange").offset().top;
if (diffChange === 0) { diffChange = 100000; }
var diffAdded = $(".diff-addedline").offset().top;
if (diffAdded === 0) { diffAdded = 100000; }
var diffDeleted = $(".diff-deletedline").offset().top;
if (diffDeleted === 0) { diffDeleted = 100000; }
var scrollTo = Math.min(diffChange, diffAdded, diffDeleted);
if (scrollTo == 100000) { scrollTo = 0; }
container.animate({scrollTop: scrollTo - container.offset().top + container.scrollTop() - 25, scrollLeft: 0}, 0);
}
function getDiff(url) {
oldid = getUrlParameter(url, "oldid");
diff = getUrlParameter(url, "diff");
if (diff == "prev") {
diff = "torelative=" + diff;
} else {
diff = "torev=" + diff;
}
$.ajax({
datatype: "json",
url: "/w/api.php?action=compare&frompst=true&topst=true&fromrev=" + oldid + "&" + diff + "&format=json"
})
.done(function( data ) {
writeIntoDocument(data);
})
.fail(function() {
console.log( 'The ajax request failed.' );
});
}
$( document ).ajaxComplete(function (){
$('.mw-changeslist-diff').hover( function(event){
if ($(".mw-changeslist").length) {
domElementName = ".mw-changeslist";
} else {
domElementName = "#mw-content-text";
}
domElement = $(this);
if (event.originalEvent.clientY < window.innerHeight / 2) {
hoverdiffPointerInTopHalf = true;
} else {
hoverdiffPointerInTopHalf = false;
}
var e = $(this);
addDiff(e);
},
function() {
removeDiff();
});
$('.mw-changeslist-groupdiff').hover( function(event){
if ($(".mw-changeslist").length) {
domElementName = ".mw-changeslist";
} else {
domElementName = "#mw-content-text";
}
domElement = $(this);
if (event.originalEvent.clientY < window.innerHeight / 2) {
hoverdiffPointerInTopHalf = true;
} else {
hoverdiffPointerInTopHalf = false;
}
var e = $(this);
addDiff(e);
},
function() {
removeDiff();
});
$('.hoverdiff-diff').hover( function(){
domElementName = ".hoverdiff-diff";
removeTimer();
},
function() {
removeDiff();
});
});
$('.mw-history-histlinks a').hover( function(event){
domElementName = ".mw-body";
domElement = $(this);
if (event.originalEvent.clientY < window.innerHeight / 2) {
hoverdiffPointerInTopHalf = true;
} else {
hoverdiffPointerInTopHalf = false;
}
var e = $(this);
addDiff(e);
},
function() {
removeDiff();
});
$('.mw-changeslist-diff').hover( function(event){
if ($(".mw-changeslist").length) {
domElementName = ".mw-changeslist";
} else {
domElementName = "#mw-content-text";
}
domElement = $(this);
if (event.originalEvent.clientY < window.innerHeight / 2) {
hoverdiffPointerInTopHalf = true;
} else {
hoverdiffPointerInTopHalf = false;
}
var e = $(this);
addDiff(e);
},
function() {
removeDiff();
});
$('.mw-changeslist-groupdiff').hover( function(event){
if ($(".mw-changeslist").length) {
domElementName = ".mw-changeslist";
} else {
domElementName = "#mw-content-text";
}
domElement = $(this);
if (event.originalEvent.clientY < window.innerHeight / 2) {
hoverdiffPointerInTopHalf = true;
} else {
hoverdiffPointerInTopHalf = false;
}
var e = $(this);
addDiff(e);
},
function() {
removeDiff();
});
function addDiff(e) {
if (this.hovering === false) {
if ($(".hoverdiff-diff").length === 0) {
this.hovering = true;
this.timer = setTimeout(function() {
e.removeAttr("title");
getDiff(e.attr('href'));
}, 250);
}
}
}
function removeTimer() {
if (this.timer){
this.hovering = false;
clearTimeout(this.timer);
}
}
function removeDiff() {
removeTimer();
this.timer = setTimeout(function() {
$(".hoverdiff-diff").remove();
}, 250);
}