[Userscript] Self-Study Quiz

[Userscript] Wanikani JLPT Items (for Self-Study Quiz)

Here’s the sample script I mentioned.

I modified the script a little so it now fetches the item data from an external file only when needed, so it’s pretty light-weight when not in use.

The external item data file needs to be on a server that grants CORS access to wanikani (or "*").
I’ve set up a sample with about 20 items on [https://www.wkstats.com/cors/wanikani/jlpt_items_v0.0.1.js]

Here’s the script source:

Source code
// ==UserScript==
// @name        Wanikani JLPT Items (for Self-Study Quiz)
// @namespace   rfindley
// @description Source for JLPT items in Self-Study Quiz
// @version     1.0.0
// @include     https://www.wanikani.com/*
// @copyright   2018+, Robin Findley
// @license     MIT; http://opensource.org/licenses/MIT
// @run-at      document-end
// @grant       none
// ==/UserScript==

window.jlpt_items = {};

(function(gobj) {

    /* global $, wkof */
    /* eslint no-multi-spaces: "off" */

    var jlpt_items_file = 'https://www.wkstats.com/cors/wanikani/jlpt_items_v0.0.1.js';

    //===================================================================
    // Initialization of the Wanikani Open Framework.
    //-------------------------------------------------------------------
    var script_name = 'JLPT Items (for Self-Study Quiz)';
    var wkof_version_needed = '1.0.45';
    if (!window.wkof) {
        if (confirm(script_name+' requires Wanikani Open Framework.\nDo you want to be forwarded to the installation instructions?')) {
            window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';
        }
        return;
    }
    if (wkof.version.compare_to(wkof_version_needed) === 'older') {
        if (confirm(script_name+' requires Wanikani Open Framework version '+wkof_version_needed+'.\nDo you want to be forwarded to the update page?')) {
            window.location.href = 'https://greasyfork.org/en/scripts/38582-wanikani-open-framework';
        }
        return;
    }

    wkof.include('ItemData');
    wkof.ready('ItemData').then(startup);

    //===================================================================
    function jlpt_fetcher() {
        if (gobj.jlpt_items !== undefined) return Promise.resolve(gobj.jlpt_items);
        return wkof.load_script(jlpt_items_file, true /* use_cache */)
            .then(parse_items);
    }

    //===================================================================
    function parse_items() {
        var jlpt_items = {};
        var jlpt_level, items, item, idx;
        var id_cnt = 0;

        //------------------
        for (jlpt_level in gobj.kanji) {
            items = gobj.kanji[jlpt_level];
            for (idx in items) {
                item = items[idx];
                jlpt_items['jlpt_' + id_cnt++] = {
                    object: 'kanji',
                    data: {
                        jlpt_level: jlpt_level,
                        characters: item[0],
                        meanings: to_meanings(item[1]),
                        readings: to_yomi(item[2], item[3])
                    }
                };
            }
        }

        //------------------
        for (jlpt_level in gobj.vocabulary) {
            items = gobj.vocabulary[jlpt_level];
            for (idx in items) {
                item = items[idx];
                jlpt_items['jlpt_' + id_cnt++] = {
                    object: 'vocabulary',
                    data: {
                        jlpt_level: jlpt_level,
                        characters: item[0],
                        meanings: to_meanings(item[1]),
                        readings: to_readings(item[2], item[3])
                    }
                };
            }
        }

        //-------------------------------------------------------------------
        function to_meanings(text) {
            return split_list(text).map(function(meaning){return {meaning:meaning, primary:true, accepted_answer:true};});
        }
        //-------------------------------------------------------------------
        function to_yomi(kunyomi, onyomi) {
            return split_list(kunyomi).map(function(reading){return {type:'kunyomi', reading:reading, primary:true, accepted_answer:true};}).concat(
                split_list(onyomi).map(function(reading){return {type:'onyomi', reading:reading, primary:true, accepted_answer:true};})
            );
        }
        //-------------------------------------------------------------------
        function to_readings(text) {
            return split_list(text).map(function(reading){return {reading:reading, primary:true, accepted_answer:true};});
        }
        //-------------------------------------------------------------------

        return jlpt_items;
    }

    //-------------------------------------------------------------------
    function split_list(str) {return str.replace(/^\s+|\s*(,)\s*|\s+$/g, '$1').split(',').filter(function(name) {return (name.length > 0);});}

    //===================================================================
    var item_type_filter = {
        type: 'multi',
        label: 'Item type',
        default: [],
        content: {kanji:'Kanji',vocabulary:'Vocabulary'},
        filter_func: function(filter_value, item){return filter_value[item.object] === true;},
        hover_tip: 'Filter by item type (kanji, vocabulary)'
	};

    //===================================================================
    var jlpt_level_filter = {
        type: 'multi',
        label: 'JLPT Level',
        default: [],
        content: {N5:'N5',N4:'N4',N3:'N3',N2:'N2',N1:'N1'},
        filter_func: function(filter_value, item){return filter_value[item.data.jlpt_level] === true;},
        hover_tip: 'Filter by JLPT Level (N5, N4, N3, N2, N1)'
	};

    //===================================================================
    function startup() {
        wkof.ItemData.registry.sources.jlpt_items = {
            description:"JLPT",
            fetcher:jlpt_fetcher,
            filters:{
                item_type:item_type_filter,
                jlpt_level:jlpt_level_filter,
            },
            options:{}
        };
    }

})(window.jlpt_items);

(ping: @seanblue)

1 Like