Wanikani Multiple Answer Input (revamped)

Input multiple readings/meanings into Wanikani (revamped)

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Wanikani Multiple Answer Input (revamped)
// @namespace    buschwichtel
// @version      1.2.2
// @description  Input multiple readings/meanings into Wanikani (revamped)
// @author       Buschwichtel (original by Mempo)
// @match        https://www.wanikani.com/review/session
// @match        https://www.wanikani.com/lesson/session
// @match        https://www.wanikani.com/extra_study/session*
// @match        https://preview.wanikani.com/review/session
// @match        https://preview.wanikani.com/lesson/session
// @match        https://preview.wanikani.com/extra_study/session*
// @grant        none
// ==/UserScript==
/*jshint esversion: 6 */

const CONSOLE_PREFIX = "/// WKMAIR: ";
const SCRIPT_ID = "multiple_answer_input_rev";
const SCRIPT_NAME = "Multiple Answer Input (rev)";


(function() {
    'use strict';

    console.debug(CONSOLE_PREFIX + "INIT");

    setup();

    $('input#user-response').on('keydown',function(event){

        if (event.keyCode === 13){
            var isLesson = /^http.*:\/\/www\.wanikani\.com\/lesson/.test(location.href);
            var currentItem = $.jStorage.get(isLesson ? "l/currentQuizItem" : "currentItem");
            var questionType = $.jStorage.get(isLesson ? "l/questionType" : "questionType");

            if(!questionType){
                console.error(CONSOLE_PREFIX + "Invalid question, can't process.");
                return;
            }
            if(!currentItem){
                console.error(CONSOLE_PREFIX + "Invalid quiz item, can't process.");
                return;
            }

            // stops the event from bubbling up to the original wanikani script
            event.preventDefault();
            event.stopPropagation();

            var input = $('input#user-response')[0].value;
            var inputElements = input ? input.split(/[;]|[ ]{2,}/) : null;
            var wrongAnswers = [];
            var correctAnswers = [];

            if(inputElements){
                inputElements.forEach((element) => {
                    if(element !== "") {
                        var cleanedElement = cleanInput(element);

                        // this is wanikani's own result evaluation, so it should be identical to entering each input one at a time
                        var answer = answerChecker.evaluate(questionType, cleanedElement, currentItem);

                        console.debug(CONSOLE_PREFIX + "answerChecker evaluated: " + answer.passed + " for answer: " + cleanedElement);

                        if(answer.passed||answer.accurate){
                            correctAnswers.push(cleanedElement);
                        }
                        else {
                            wrongAnswers.push(cleanedElement);
                        }
                    }
                });

                var wrongAnswersString = "";
                var correctAnswersString = "";

                var anyWrongAnswers = wrongAnswers.length > 0;
                var anyCorrectAnswers = correctAnswers.length > 0;

                if(anyWrongAnswers) {
                    wrongAnswersString = wrongAnswers.join("; ");
                }
                if(anyCorrectAnswers) {
                    correctAnswersString = correctAnswers.join("; ");
                }

                console.info(CONSOLE_PREFIX + "Right answers given: " + (0 === correctAnswersString.length ? "none" : correctAnswersString) +
                             ", Wrong answers given: " + (0 === wrongAnswersString.length ? "none" : wrongAnswersString));

                if(wkof.settings.multiple_answer_input_rev.force_all_correct) {
                    if(anyWrongAnswers) {
                        // It doesn't matter how we send the answers, since they're wrong anyway.
                        // Note that any correct answers in the original input aren't part of the result here.
                        sendAnswer(wrongAnswersString);
                    }
                    else if(anyCorrectAnswers) {
                        // Since there were no wrong answer and at least one correct answer, all answers are correct.
                        // WaniKani only expects a single response, so we send only the first correct answer to wanikani, so it accepts it,
                        // then replace the result string with all of the answers again (since they are all correct)
                        sendAnswer(correctAnswers[0]);
                        $('input#user-response')[0].value = input;
                    }
                }
                else {
                    // If everything is wrong...
                    if(!anyCorrectAnswers) {
                        sendAnswer(wrongAnswersString);
                    }
                    // ...or everything is correct, we can just pass it off to the default
                    else if(!anyWrongAnswers && anyCorrectAnswers) {
                        sendAnswer(correctAnswers[0]);
                        $('input#user-response')[0].value = input;
                    }
                    else {
                        // put the input back into what the user actually entered
                        $('input#user-response')[0].value = input;

                        var msg = 'Not all of your answers were correct! Wrong: "' + wrongAnswersString + '"';

                        // show a message describing which answers were wrong & do the shaky thingy
                        if(!$("#answer-form form").is(":animated") && $('#user-response').val() !== '') {
                            $("#answer-form form").effect("shake", {}, 300, function() {
                                $("#additional-content").append($('<div id="answer-exception"><span>'+msg+'</span></div>').addClass("animated fadeInUp"));
                            });
                            $("#answer-form form").find("input").focus();
                        }
                    }
                }
            }
            else
            {
                // if we can't split it, just hand it off to the default script.
                // input is probably empty in this case, anyway.
                sendAnswer(input);
                console.log(CONSOLE_PREFIX + "No readable answers given.");
            }
        }
    });
})();

function setup() {
    if (!window.wkof) {
        alert(SCRIPT_NAME + ' requires Wanikani Open Framework.\nYou will now be forwarded to installation instructions.');
        window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';
        return;
    }

    wkof.include('Menu,Settings');
    wkof.ready('Menu,Settings').then(loadSettings);

    function loadSettings() {

        wkof.Menu.insert_script_link({name:SCRIPT_ID,submenu:'Settings',title:SCRIPT_NAME,on_click:openSettingsMenu});

        var defaults = {
            force_all_correct: true
        };
        wkof.Settings.load(SCRIPT_ID, defaults);
    }
}

function openSettingsMenu() {
    var dialog = new wkof.Settings({
        script_id: SCRIPT_ID,
        title: SCRIPT_NAME,
        content: {
            tabSettings: {type:'page', label:'Settings', content: {
                force_all_correct: {type:'checkbox', label:'Force all correct', default: true, hover_tip: 'When enabled, will fail you if a single answer given is incorrect.'}
            }}
        }
    });
    dialog.open();
}

function sendAnswer(answer) {
    $('input#user-response')[0].value = answer;
    $("#answer-form form button").click();
}

// Carbon copy of the first few lines of answerChecker.evaluate, sadly doesn't exist standalone :(
function cleanInput(input, questionType) {
    var normalizedResponse = normalizeResponse(input);
    if (questionType === "reading") {
        // normalizeReadingResponse DOES get exported, for some reason.
        normalizedResponse = answerChecker.normalizeReadingResponse(normalizedResponse);
    }
    return normalizedResponse;
}

// Carbon copy of answerChecker.normalizeResponse, but that doesn't get exported :(
function normalizeResponse(response) {
    return response
        .trim()
        .toLowerCase()
        .replace(/-/g, " ") // replace hyphen with space
        .replace(/\.|,|'|’|\/|:/g, ""); // replace periods, comma, colons, and apostrophe with blanks
}