New version of KunOn script: WK Custom Review Question (KunOn+)

I didn’t post it originally because the kind of patch I would post if a maintainer is considering up streaming would try to minimize the number of lines changed to make their life easier. I’ve posted the version I use below, which does not attempt to do that. (No diff because the indentation level changed on ~half the code.)

// ==UserScript==
// @name        WK Custom Review Question (KunOn+)
// @namespace   WK_CustomQuestion
// @description Changes the text of the Review or Lesson Quiz question. Specifies ON or KUN reading for Kanji. Options to have the text in English or Japanese.
// @author      hoovard
// @include     https://www.wanikani.com/review/session*
// @include     http://www.wanikani.com/review/session*
// @include     https://www.wanikani.com/lesson/session*
// @include     http://www.wanikani.com/lesson/session*
// @version     0.4.3
// @license     Do what you want with it (Preferably improve it).
// @grant       none
// ==/UserScript==
// Version 0.4.3 applies to Reviews and Lesson Quizzes.

// Language options
// English "en", Japanese "ja"
var strLang = "en";


// Tested on the following:
// Firefox 35.0.1 and Chrome 39.0.2171.95 (64-bit), Linux Mint 17.1 Cinnamon 64-bit
// Firefox 35.0.1 and Chrome 40.0.2214.115 m, Windows 8.1 64-bit

// Thanks to Rui Pinheiro (LordGravewish) for the original script 
// and to Ethan for the idea to use MutationObserver to detect changes in the DOM.

// Vars to compose the replacement question string
var strKanji;
var strRadical;
var strVocab;
var strMeaning;
var strReading;
var strVocabReading;
var strOn;
var strKun;
var strNan;
var strName;

// Translations
switch (strLang)
{
	case "en":
		strKanji = "kanji";
		strRadical = "radical";
		strVocab = "vocabulary";
		strMeaning = "meaning";
		//strReading = "yomi";
		strVocabReading = "reading";
		strOn = "on'yomi";
		strKun = "kun'yomi";
        strNan = "nanori";
		strName = "name";
		break;
	case "ja":
		strKanji = "漢字";
		strRadical = "部首";
		strVocab = "単語";
		strMeaning = "意味";
		//strReading = "読み";
		strVocabReading = "読み";
		strOn = "音読み";
		strKun = "訓読み";
        strNan = "名乗り";
		strName = "名前";
		break;
}

// Variable to save and check against the previous contents of the jStorage item
var objSavedCurrentItem;

// Review or Lesson Quiz. jStorage objects are different.
bIsReview = ($(location).attr('href').indexOf("review") != -1);

// Code based on Stack Overflow to detect changes in the DOM.
// (http://stackoverflow.com/questions/3219758/detect-changes-in-the-dom/14570614#14570614)
var observeDOM = (function(){
    var MutationObserver = window.MutationObserver;

    return function(obj, callback){
        if( MutationObserver ){
            // define a new observer
            var obs = new MutationObserver(function(mutations, observer){
                    callback();
            });
            // have the observer observe for changes in children
            // need to observe attributes because after we alter the question, wanikani will
            // not update the question text in certain circumstances and instead only changes the class
            // because WK uses regex to do a replacement on the text which results in no change if the
            // text does not have the string WK is searching for (this behavior occurs in lesson quiz)
            obs.observe( obj, { childList: true, attributes: true, subtree:true });
        }
    }
})();

// Callback function observing the 'question-type' div 'h1' element
var selector = '#question-type h1';
var observeMe = $(selector); // on review page
if (observeMe.length == 0) {
    // on lesson quiz page
    selector = '#question-type'
    observeMe = $(document); // on lessons page, selector isn't in dom on page load
}
observeMe = observeMe[0];
let in_call = false;
observeDOM( observeMe ,function(){
    let el = $(selector);
    if (el.length==0)
        return;


    var objCurItem;
    if (bIsReview) {
        objCurItem = $.jStorage.get("currentItem");
    } else {
        objCurItem = $.jStorage.get("l/currentQuizItem");
    }



    var strQuestionType;
    if (bIsReview) {
        strQuestionType = $.jStorage.get("questionType");
    } else {
        strQuestionType = $.jStorage.get("l/questionType");
    }

    var strItemType = "";
    var strReadingType = "Reading";

    // Compose the string elements to be sent into the h1 element
    if ("kan" in objCurItem)
    {
        // Kanji
        strItemType = strKanji;
        if (strQuestionType == "reading") {
            if(objCurItem.emph == "onyomi")
                strReadingType = strOn;
            else if(objCurItem.emph == "kunyomi")
                strReadingType = strKun;
            else if(objCurItem.emph == "nanori")
                strReadingType = strNan;
        } else {
            strReadingType = strMeaning;
        }
    }
    else if ("voc" in objCurItem)
    {
        // Vocabulary
        strItemType = strVocab;
        if (strQuestionType == "reading") {
            strReadingType = strVocabReading;
        } else {
            strReadingType = strMeaning;
        }
    }
    else if ("rad" in objCurItem)
    {
        // Radical
        strItemType = strRadical;
        strReadingType = strName;
    }

    // replace the contents of #question-type h1
    let newContents;
    switch (strLang)
    {
        case "en":
            newContents = strItemType + ' <strong>' + strReadingType + '</strong>';
            break;
        case "ja":
            newContents = strReadingType;
            break;
    }

    // Prevent responding to own DOM changes
    // triggers fewer mutationobservers compared to
    // previous way of doing this
    if (newContents != el.html()) {
        $(selector).html(newContents);
    }
});
1 Like