Last active
June 23, 2023 20:29
-
-
Save cyphr/6536814 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name JL&U Hacks | |
// @namespace stackexchange | |
// @description JL&U Hacks | |
// @include http://*japanese.stackexchange.com/* | |
// ==/UserScript== | |
$(function () { | |
var DEBUG_MODE = true; // DISABLE THIS BEFORE RELEASE! | |
var addCSS = function (css) { | |
var head = document.getElementsByTagName('head')[0] | |
if (head) { | |
var style = document.createElement('style'); | |
style.type = 'text/css'; | |
if (style.styleSheet){ | |
style.styleSheet.cssText = css; | |
} else { | |
style.appendChild(document.createTextNode(css)); | |
} | |
head.appendChild(style); | |
}; | |
var elm = $('<div></div>'); | |
elm.html('<style type="text/css">'+css+'</style>'); | |
$(document.body).append(elm); | |
} | |
var htmlEscape = function (i) { | |
return i.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); | |
} | |
var start = function () { | |
//add menu | |
if (!$("#upopup").length) { | |
$("#footer-menu .top-footer-links").prepend( | |
'<a id="upopuphyperlink">furigana options</a><div id="upopup" style="color:black;position:absolute;'+ | |
'display:none;background-color:#fff;border:1px solid #ccc;margin-top:3px;padding:5px;z-index:500;'+ | |
'box-shadow:1px 1px 2px rgba(0,0,0,0.2);"/>' | |
); | |
$('#upopuphyperlink').click(function() { | |
$("#upopup").css('top', $("#footer-menu .top-footer-links").offset().top - $("#upopup").height() - 10); | |
$('#upopup').toggle(); | |
}); | |
}; | |
//add options box | |
$("#upopup").append( | |
'<div>' + | |
'<h4>ruby options</h4>' + | |
'<input type="checkbox" id="udisableruby"><label for="udisableruby"> disable ruby entirely</label></input><br>' + | |
'<h4>other options</h4>' + | |
'<input type="checkbox" id="uhideruby"><label for="uhideruby"> hide ruby texts, only show when hover on kanji</label></input><br>' + | |
'<input type="button" id="usave" value="save and reload"/> <input type="button" onclick="$(\'#upopup\').hide()" value="close"/>' + | |
'</div>' | |
).find("div").css( | |
{ 'color': '#000' } | |
).find("a,input").css( | |
{ 'color': '#00f', 'text-shadow': 'none', 'vertical-align': 'middle', 'font-weight': 'normal' } | |
); | |
//restore previous settings/register save settings event etc | |
loadSettings(); | |
$("#usave").click(saveSettings); | |
var updDisabled = function () { | |
$("#uhideruby").prop('disabled', $("#udisableruby").prop('checked')) | |
} | |
updDisabled(); | |
$("#udisableruby").change(updDisabled); | |
if (!DEBUG_MODE && getSetting("udisableruby") == 1) { | |
// don't run if ruby disabled altogether | |
return | |
} | |
if (!/Chrome|IE/.test(navigator.userAgent)) { | |
addCSS( | |
'ruby{display:inline-table;text-align:center;text-indent:0;white-space:nowrap;margin:0;padding:0;line-height:1;height:1em;vertical-align:text-bottom;border:none;}' + | |
'rb{display:table-row-group;line-height:1;text-align:center;border:none;margin:0;padding:0;white-space:nowrap;}' + | |
'rt{display:table-header-group;font-size:0.75em;line-height:1.1;text-align:center;white-space:nowrap;border:none;margin:0;padding:0;}'); | |
} else { | |
//add different css for Chrome & IE (as they support ruby natively) | |
addCSS( | |
'ruby{line-height:1;height:1em;}' + | |
'rb{line-height:1;}' + | |
'rt{font-size:0.7em;line-height:1.1;}' + | |
(/IE/.test(navigator.userAgent) ? 'rt{font-family:"MS Gothic","MS ゴシック",sans-serif}' : '')); | |
}; | |
addCSS( | |
'span.hiddenruby:hover,span.hiddenruby-rp:hover{background:#CCFFCC;}'+ | |
'span.hiddenruby,span.hiddenruby-rp{cursor:default;border-bottom:1px dashed gray;}'+ | |
'span.tone-h{border-top:1px solid red;}'+ | |
'span.tone-l-change{border:solid red;border-width:0 0 1px 1px;}'+ | |
'span.tone-l{border-bottom:1px solid red;}'+ | |
'span.tone-h-change{border:solid red;border-width:1px 0 0 1px;}'+ | |
'.ushadow,#upop,.upop{-webkit-box-shadow: 0px 0px 7px rgba(50, 50, 50, 0.2);-moz-box-shadow: 0px 0px 7px rgba(50, 50, 50, 0.2);box-shadow: 0px 0px 7px rgba(50, 50, 50, 0.2);}'+ | |
'#upop,.upop{padding:2px 5px;font-size:1.3em;background:#FFFFF0;border-radius:3px;border:1px solid #ccc;}') | |
//ruby mode regex | |
var replaces = new RegExp( | |
"(?:[|\\[)([^\\]]+)\\]\\{([^}]+)\\}|([\u4e00-\ufeed\u3003\u3004\u3005\u3006\u3007\u3012]+[\u3041-\u30fe]*)\\s*[{\u3010]([.\u3001\u3002\u3041-\u30fe\uff0d-\uff0f\uff61hlHL]+)[}\u3011]|([\u3041-\u30fe]+)\\s*[{\u3010]([a-zA-Z\u0101-\u014d' ]+)[}\u3011]", "g"), | |
cache = [], | |
upop; | |
var rubyize = function(kanji, furigana) { | |
var n = furigana.match(/^\s*([hlHL]+)\s*$/) | |
if (n) { | |
// add tones if HL format | |
var o = '', | |
prev=null, | |
n = n[1].toLowerCase() | |
for (var i=0; i<Math.min(n.length, kanji.length); i++) { | |
if (n.charAt(i) == 'h') { | |
if (prev==='l') { | |
o += '<span class="tone-h-change">'+kanji.charAt(i)+'</span>'; | |
} else { | |
o += '<span class="tone-h">'+kanji.charAt(i)+'</span>'; | |
}; | |
} else if (n.charAt(i) == 'l') { | |
if (prev==='h') { | |
o += '<span class="tone-l-change">'+kanji.charAt(i)+'</span>'; | |
} else { | |
o += '<span class="tone-l">'+kanji.charAt(i)+'</span>'; | |
}; | |
}; | |
prev = n.charAt(i); | |
}; | |
o += kanji.slice(i, kanji.length); | |
return o; | |
} else { | |
return '<ruby><rb>' + kanji + '</rb><rt>' + furigana + '</rt></ruby>'; | |
}; | |
}; | |
var parse = function() { | |
$("span,code,p,li,b,i,a,div.excerpt").contents() | |
.filter(function () { | |
return ( | |
this.nodeType == 3 || this.nodeType == 1 | |
) && /[\u3000-\ufeed]/.test(this.data); | |
}) | |
.each(function () { | |
for (var i = 0; i < cache.length; i++) { | |
if (cache[i] == this && true) { | |
return; | |
} | |
} | |
var data_escaped = htmlEscape(this.data), | |
data = data_escaped.replace(replaces, function ($0, $1, $2, $3, $4, $5, $6, $7, $8) { | |
var kanji = $1 || $3 || $5 || $7, | |
furigana = $2 || $4 || $6 || $8; | |
if (getSetting("uhideruby") == 1 && !furigana.match(/^\s*[hlHL]+\s*$/)) { | |
return '<span class="hiddenruby-rp" title="' + furigana + '">' + kanji + '</span>'; | |
} | |
var kanjis = kanji.split(''), | |
furiganas = furigana.split(/[.\u3001\u3002\u30fb\uff0d-\uff0f\uff61]/); | |
if (kanjis.length == furiganas.length){ | |
return $.map(kanjis, function(k, i){ | |
return rubyize(k,furiganas[i]); | |
}).join(''); | |
} | |
return rubyize(kanji, furigana); | |
}); | |
if (data != data_escaped) { | |
$(this).replaceWith(data); | |
} | |
cache.push(this); | |
}); | |
// add faster popup windows as "title=" takes some time to appear | |
// "title=" also usually isn't usable on tablets | |
$('.hiddenruby-rp').each(function (e) { | |
// go through the "rp", aka "reprocess" classes | |
$(this).removeClass('hiddenruby-rp').addClass('hiddenruby'); | |
var title = String(this.title), | |
upop; | |
this.title = ''; | |
$(this).mouseover(function(e) { | |
$(document.body).append('<div id="upop" class="upop">'+htmlEscape(title)+'</div>'); | |
upop = $("#upop"); | |
upop.attr("id", ""); | |
upop.css({ | |
position: "absolute", | |
top: e.pageY+20+'px', | |
left: e.pageX+20+'px' | |
}); | |
}).mousemove(function(e) { | |
if (!upop) { | |
return; | |
} | |
upop.css({ | |
top:e.pageY+20+'px', | |
left:e.pageX+20+'px' | |
}); | |
}).mouseout(function() { | |
if (!upop) { | |
return; | |
} | |
upop.remove(); | |
}); | |
}); | |
}; | |
parse(); | |
setInterval(parse, 400); | |
}; | |
var loadSettings = function () { | |
try { | |
if (localStorage["udisableruby"] == 1) { | |
$("#udisableruby").attr("checked", true); | |
} | |
if (localStorage["uhideruby"] == 1) { | |
$("#uhideruby").attr("checked", true); | |
} | |
} catch (e) {} | |
}; | |
var getSetting = function (name) { | |
try { | |
return localStorage[name]; | |
} catch(e) { | |
switch(name) { | |
case "udisableruby": | |
case "uhideruby": | |
return 0; | |
} | |
}; | |
}; | |
var saveSettings = function () { | |
try { | |
localStorage["udisableruby"] = $("#udisableruby").attr("checked") ? 1 : 0; | |
localStorage["uhideruby"] = $("#uhideruby").attr("checked") ? 1 : 0; | |
location.reload(); | |
} catch(e) { | |
alert("Options can only be changed when localStorage is available. Please check your browser settings."); | |
}; | |
}; | |
if ($("#footer-menu .top-footer-links").length) { | |
start(); | |
} else { | |
var script = document.createElement("script"); | |
script.type = "text/javascript"; | |
script.textContent = "(" + start + ")();"; | |
document.getElementsByTagName("head")[0].appendChild(script); | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment