Overlays component information on reviews when show info is pressed.
当前为
// ==UserScript==
// @name WK Overlay
// @namespace wkoverlay
// @version 0.2.1
// @description Overlays component information on reviews when show info is pressed.
// @author Ethan
// @match https://www.wanikani.com/review/session*
// @grant none
// ==/UserScript==
// TODO if kanji or radical follows vocab, overlay is not removed
var isKanji = function(ch){
return /^[\u4e00-\u9faf]+$/.test(ch);
};
/** Gets the Kanji characters in a given string.
* @param {string} vocabString -
* @return {Array.<string>} An array of the kanji components in the given string
*/
var getComponents = function(vocabString){
return Array.prototype.filter.call(vocabString, function(ch){
return isKanji(ch);
}, this);
};
var addStyleTag = function(){
/* Non-Javascript determined (to be put in style tag)*/
var styleText =
".wkOverlay {\r\n" +
"display: block;\r\n" +
"position: absolute;\r\n" +
"}\r\n" +
".infoSpan {\r\n" +
"position: absolute;\r\n" +
"backgroundColor: black;\r\n" +
"color: #fff;\r\n" +
"textAlign: center;\r\n" +
"padding: 5px 10px;\r\n" +
"borderRadius: 6px;\r\n" +
"display: inline-block;\r\n" +
"fontSize: 10pt;\r\n" +
"}\r\n" +
".infoTop::after{\r\n" +
"content: '';\r\n" +
"position: absolute;\r\n" +
"top: 100%;\r\n" +
"left:20px;\r\n" +
"margin-left: -10px;\r\n" +
"border-width: 10px;\r\n" +
"border-style: solid;\r\n" +
"border-color: black transparent transparent transparent\r\n" +
"}\r\n" +
".infoBottom::after{\r\n" +
"content: '';\r\n" +
"position: absolute;\r\n" +
"bottom: 100%;\r\n" +
"left:20px;\r\n" +
"margin-left: -10px;\r\n" +
"border-width: 10px;\r\n" +
"border-style: solid;\r\n" +
"border-color: transparent transparent black transparent\r\n" +
"} \r\n";
var styleElem = document.createElement('style');
styleElem.appendChild(document.createTextNode(styleText));
document.head.appendChild(styleElem);
};
(function() {
'use strict';
//salt this event so future scripts don't throw multiple events and confuse the script
var hideEvent = "hide"+Math.trunc(Math.random()*1000000);
var showEvent = "show"+Math.trunc(Math.random()*1000000);
//---------------------------
var oldHide = $.fn.hide;
$.fn.hide = function(){this.trigger(new jQuery.Event(hideEvent)); return oldHide.apply(this, arguments);};
var oldShow = $.fn.show;
$.fn.show = function(){this.trigger(new jQuery.Event(showEvent)); return oldShow.apply(this, arguments);};
//--------------------------
addStyleTag();
var parentElement = $("#question");
var overlay = document.createElement('div');
overlay.style.display = 'none';
var descOverlay = document.createElement('div');
var respComps = {};
var prompt;
parentElement[0].appendChild(overlay);
$.jStorage.listenKeyChange('currentItem', function(){
while (overlay.firstChild){
overlay.removeChild(overlay.firstChild);
}
// Runs after span is changed, but is this guaranteed?
prompt = $.jStorage.get('currentItem');
if (prompt.voc){
for (var ch in prompt.voc){
var chSpan = document.createElement('span');
chSpan.innerText = prompt.voc[ch];
chSpan.style.fontSize = document.defaultView.getComputedStyle($("#character")[0], "").fontSize;
}
}
});
// Show overlay when info is being shown.
$("#item-info").on(showEvent, function(){
// Clear array of nodelists
while (overlay.firstChild){
overlay.removeChild(overlay.firstChild);
}
$("#related-items .kanji a").each(function(i, comp){
console.log(comp);
respComps[comp.childNodes[0].textContent] = comp.childNodes[1].textContent;
});
overlay.className = "wkOverlay";
overlay.style.display = 'block';
// while (descOverlay.firstChild){
// descOverlay.removeChild(descOverlay.firstChild);
// }
if (prompt.voc){
var flipTopBottom = false; //true: top, false: bottom
// Position absolute needs negative margins to react to number of characters
var marginLeftPercentage = (-100/prompt.voc.length) + "%";
var marginRightPercentage = "2%";
for (var ch in prompt.voc){
flipTopBottom = !flipTopBottom;
var chSpan = document.createElement('span');
chSpan.className = "wkOverlayChar";
var comp = document.createElement('span');
comp.innerText = prompt.voc[ch];
comp.style.opacity = 0;
chSpan.appendChild(comp);
console.info(respComps, prompt.voc[ch], respComps[prompt.voc[ch]]);
chSpan.style.fontSize = document.defaultView.getComputedStyle($("#character")[0], "").fontSize; // and lineHeight
// Javascript determined values.
overlay.style.height = $("#character span").height() + 'px';
overlay.style.top = $("#character span").position().top + 'px';
overlay.style.left = $("#character span").position().left + 'px';
overlay.setAttribute('lang', "ja");
// overlay.style.position = "absolute";
//overlay.style.display = 'none';
overlay.style.height = $("#character span").height() + 'px';
overlay.appendChild(chSpan);
// Pretty sure it does nothing ----
if (!isKanji(prompt.voc[ch])){
chSpan.style.visibility = 'hidden';
}
else{
// chSpan.style.backgroundColor = "cyan";
}
//---------------------
if (respComps[prompt.voc[ch]]){
var spInf = document.createElement('span');
spInf.innerText = respComps[prompt.voc[ch]];
chSpan.appendChild(spInf);
spInf.style.marginLeft = marginLeftPercentage;
spInf.style.marginRight = marginRightPercentage;
if(flipTopBottom){
spInf.className = "infoSpan infoTop";
spInf.style.bottom = "100%";
}
else{
spInf.className = "infoSpan infoBottom";
spInf.style.top = "100%";
}
spInf.style.position ="absolute";
spInf.style.backgroundColor = "black";
spInf.style.color = "#fff";
spInf.style.textAlign = "center";
spInf.style.padding = "5px 10px";
spInf.style.borderRadius = "6px";
spInf.style.display = "inline-block";
spInf.style.fontSize = "10pt";
}
}
}
// descOverlay.style.display = 'block';
//console.log($("#character span"));
});
$("#item-info").on(hideEvent, function(){
overlay.style.display = 'none';
// descOverlay.style.display = 'none';
});
})();