Hack for no red ink

shows the answer to the questions in noredink. When you get a question wrong it will be saved to the database, so the more people who use this script, the more accurate it will be. currently supports multiple choice, highlighting, multi-highlighting, playground, outlinedraggable and punctuation question types and more will be added later

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

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que 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.

Tendrás que instalar una extensión como Tampermonkey antes de poder 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)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

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

// ==UserScript==
// @name         Hack for no red ink
// @namespace    
// @version      2.0
// @description  shows the answer to the questions in noredink.  When you get a question wrong it will be saved to the database, so the more people who use this script, the more accurate it will be.  currently supports multiple choice, highlighting, multi-highlighting, playground, outlinedraggable and punctuation question types and more will be added later
// @author       You
// @match        *://www.noredink.com/learn/quiz/*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js
// @require      https://code.jquery.com/ui/1.12.1/jquery-ui.js
// @resource     jqUI_CSS  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css
// @resource     IconSet1  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/images/ui-icons_222222_256x240.png
// @resource     IconSet2  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/images/ui-icons_454545_256x240.png
// @grant        GM_addStyle
// @grant        GM_getResourceURL
// @grant        GM_getResourceText
// @grant        GM.xmlHttpRequest
//// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    var $ = window.jQuery;

    //https://stackoverflow.com/a/11532646
    var iconSet1 = GM_getResourceURL ("IconSet1");
    var iconSet2 = GM_getResourceURL ("IconSet2");
    var jqUI_CssSrc = GM_getResourceText ("jqUI_CSS");
    jqUI_CssSrc = jqUI_CssSrc.replace (/url\(images\/ui\-bg_.*00\.png\)/g, "");
    jqUI_CssSrc = jqUI_CssSrc.replace (/images\/ui-icons_222222_256x240\.png/g, iconSet1);
    jqUI_CssSrc = jqUI_CssSrc.replace (/images\/ui-icons_454545_256x240\.png/g, iconSet2);

    GM_addStyle (jqUI_CssSrc);
    //https://stackoverflow.com/a/25468928
    //--- For this to work well, we must also add-in the jQuery-UI CSS.
    //We add the CSS this way so that the embedded, relatively linked images load correctly.
    //(Use //ajax... so that https or http is selected as appropriate to avoid "mixed content".)

    $("head").append (
        '<link '
        //+ 'href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/le-frog/jquery-ui.min.css" '
        +'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css'
        + 'rel="stylesheet" type="text/css">'
    );
    //--- Add our custom dialog using jQuery.
    $("body").append (
        `<div id="gmOverlayDialog">
         <button type="button" id="hidedialogue" onclick="$(this).parent().hide();$('.ui-dialog').on('click','.ui-dialog-titlebar', ()=>{$(this).parent().show();$(this).parent().parent().width(300);$('span.ui-dialog-title').text('options');});$('span.ui-dialog-title').text('🇳🔧'); $(this).parent().parent().width(100);$('.ui-resizable-handle').hide();">hide window</button>
         <fieldset>
         <legend>get all wrong: </legend>
         <label for="radio-1">on</label>
         <input type="radio" name="radio-1" id="radio-1" value="on">
         <label for="radio-2">off</label>
         <input type="radio" name="radio-1" id="radio-2" value="off">
         </fieldset>
         <fieldset>
         <legend>on wrong question proceed: </legend>
         <label for="radio-1">instantly</label>
         <input type="radio" name="radio-2" id="radio-3" value="on">
         <label for="radio-2">delay</label>
         <input type="radio" name="radio-2" id="radio-4" value="off">
         </fieldset>
         <span id="questionInfo"></span>
         </div>`
    );

    //--- Activate the dialog.
    $("#gmOverlayDialog").dialog ( {
        closeOnEscape:false,
        modal:      false,
        title:      "options",
        //position:"relative",
        position:   {
            my: "left top",
            at: "left top",
            of: document
            , collision: "none"
        },
        //width:      "auto",
        width:300,
        minWidth:   300,
        minHeight:  200,
        zIndex:     3666,
        open: function(event, ui) {
            //$(this).hide();//hide it for now i guess
            //https://stackoverflow.com/a/897393
            $(".ui-dialog-titlebar-close", $(this).parent()).hide();
          //document.getElementById("hidedialogue").click();
        }
    } )
        .dialog ("widget").draggable ("option", "containment", "none");

    ////////////////////////////////////////////////////
    var settings_getAllWrong,settings_instantContinue;
    var url=window.location.href;
    var practiceID=url.indexOf("try_similar")==-1?url.split("/learn/quiz/")[1].split("/")[0]:url.split("/learn/quiz/")[1].split("/try_similar")[0];
    var userID;
    //var REST="https://rest-api-for-nri-userscript.herokuapp.com/api/";
    var REST="https://rest-api-for-userscript-1.lukec1.repl.co/api/";
    var question;
    var choice=[];
    var $keyElements=["html>body>div:eq(2)>div>div>div:eq(0)>header>h2"];//,"html>body>div:eq(2)>div>div:eq(0)>div:eq(0)>header>h2"];
    var $trySimilar="html>body>div:eq(3)>div:eq(1)>div>div>div>button";
    var numOfChoices=0;
    //var trysimilartype;
    ///////////////
    function addQuestion(id,question,answer,callback){
        $.get(REST+"addanswer/"+id+"/"+encodeURIComponent(question)+"/"+encodeURIComponent(answer), function(result){
            console.log(result);
            callback(result);
        });
    }
    function getQuestions(id,question){
        //$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section:eq(1)>article>span:eq(0)>button>span>div>div>img").attr("src","https://www.streamscheme.com/wp-content/uploads/2020/04/poggers.png");
        //$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section:eq(1)>article>span:eq(0)>button>span>div>div>img").hide();
        //$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section:eq(1)>article>span:eq(0)>button>span>div>span").text("loading question info...");
        document.body.getElementsByTagName("h2")[0].innerText="loading question info...";
        //for some reason normal jquery ajax doesnt work here
        GM.xmlHttpRequest({//https://wiki.greasespot.net/GM.xmlHttpRequest#GET_request
            method: "GET",
            url: REST+"search/"+id+"/"+question,
            headers: {
                "User-Agent": "Mozilla/5.0",
                "Accept": "text/xml"
            },
            onload: function(response) {
                var responseXML = null;
                console.log([
                    response.status,
                    response.statusText,
                    response.readyState,
                    response.responseHeaders,
                    response.responseText,
                    response.finalUrl,
                    responseXML
                ].join("\n"));
                if(response.responseText!=="no match"){
                    var question=JSON.parse(response.responseText).question;
                    var answer=JSON.parse(response.responseText).answer;
                    var confidence=JSON.parse(response.responseText).confidence;
                    console.log("answer: "+answer+"\nconfidence"+confidence);
                    //$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section:eq(1)>article>span:eq(0)>button>span>div>span").attr("style", "white-space: pre;");
                    document.body.getElementsByTagName("h2")[0].setAttribute("style","white-space: pre;");
                    //$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section:eq(1)>article>span:eq(0)>button>span>div>span").text("question: "+question+"\r\nanswer: "+answer+"\r\nconfidence: "+confidence);
                    document.body.getElementsByTagName("h2")[0].innerText="question: "+question+"\r\nanswer: "+answer+"\r\nconfidence: "+confidence;

                }else{
                    console.log(response.responseText);
                    //alert(encodeURIComponent(document.getElementsByClassName("Nri-Quiz-Layout-Question")[0].getElementsByTagName("p")[0].innerHtml));
                    //$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section:eq(1)>article>span:eq(0)>button>span>div>span").text(response.responseText);
                    document.body.getElementsByTagName("h2")[0].innerText=response.responseText;

                }

            }


        });
    }
  function getNumOfQuestion(id,callback){
        GM.xmlHttpRequest({//https://wiki.greasespot.net/GM.xmlHttpRequest#GET_request
            method: "GET",
            url: REST+"search/"+id+"/",
            headers: {
                "User-Agent": "Mozilla/5.0",
                "Accept": "text/xml"
            },
            onload: function(response) {
                var responseXML = null;
                console.log([
                    response.status,
                    response.statusText,
                    response.readyState,
                    response.responseHeaders,
                    response.responseText,
                    response.finalUrl,
                    responseXML
                ].join("\n"));
              callback((Object.keys(JSON.parse(response.responseText)).length>=1)?(Object.keys(JSON.parse(response.responseText)).length-1):0);

            }


        });
    }
    /*function findClosestStringInArray(array,_string){

        var a = FuzzySet();
        array.forEach((i)=>{a.add(i)});
        return a.get(_string);
    }*/
    function setUserSettings(userid,setting,value,callback){
        $.get(REST+"addanswer/"+userid+"/"+encodeURIComponent(setting)+"/"+encodeURIComponent(value), function(result){
            console.log(result);
            callback(result);
        });
    }
    function getUserSettings(userid,callback){
        GM.xmlHttpRequest({//https://wiki.greasespot.net/GM.xmlHttpRequest#GET_request
            method: "GET",
            url: REST+"search/user"+userid,
            headers: {
                "User-Agent": "Mozilla/5.0",
                "Accept": "text/xml"
            },
            onload: function(response) {
                var responseXML = null;
                console.log([
                    response.status,
                    response.statusText,
                    response.readyState,
                    response.responseHeaders,
                    response.responseText,
                    response.finalUrl,
                    responseXML
                ].join("\n"));

                callback(JSON.parse(response.responseText).getAllWrong,JSON.parse(response.responseText).instantContinue);//callback(get all wrong?, continue instantly on incorrect?)
            }
        });
    }
  
    function getTrySimilarQuestionType(callback){
        GM.xmlHttpRequest({//https://wiki.greasespot.net/GM.xmlHttpRequest#GET_request
            method: "GET",
            url: REST+"search/"+practiceID,
            headers: {
                "User-Agent": "Mozilla/5.0",
                "Accept": "text/xml"
            },
            onload: function(response) {
                var responseXML = null;
                console.log([
                    response.status,
                    response.statusText,
                    response.readyState,
                    response.responseHeaders,
                    response.responseText,
                    response.finalUrl,
                    responseXML
                ].join("\n"));

                callback(JSON.parse(response.responseText).type);
            }
        });
    }
  function getServerStatus(callback){
        GM.xmlHttpRequest({//https://wiki.greasespot.net/GM.xmlHttpRequest#GET_request
            method: "GET",
            url: REST+"test/",
            headers: {
                "User-Agent": "Mozilla/5.0",
                "Accept": "text/xml"
            },
            onload: function(response) {
                var responseXML = null;
                console.log([
                    response.status,
                    response.statusText,
                    response.readyState,
                    response.responseHeaders,
                    response.responseText,
                    response.finalUrl,
                    responseXML
                ].join("\n"));
                callback(response.responseText=="hello world!");
            }
        });
    }
    function getQuestionType(){
        var qType="error";
        /*if(document.getElementById("nri-yellow").length>-1){
            qType="highlighter"
        }
        else if($("html>body>div:eq(3)>div>div>div:eq(1)>div>section>div:eq(1)>section>section>button:eq(0)>span").length>-1){
            qType="multiplechoice";
        }*/
        if(url.indexOf("try_similar")==-1){//not trysimilar
            qType=JSON.parse(document.getElementById("quiz-question").getElementsByTagName("div")[0].getAttribute("data-data")).questionType;
            addQuestion(practiceID,"type",qType,(result)=>{console.log(result)});
        }else{
            //
        }
        return qType;
    }
    /*class jqWindow{
        constructor(_title,_id){
            this.title=_title;
            this.id=_id;
        }
        create(){
            var div=document.createElement("DIV");
            div.title=this.setAttribute("title",this.title);
            div.id=this.setAttribute("id",this.id);
            document.body.appendChild(div);
            $(div).dialog();
        }
    }*/
    function getRndInteger(min, max) {
        return Math.floor(Math.random() * (max - min + 1) ) + min;
    }
    var waitForItToLoad=setInterval(()=>{
        $keyElements.forEach(i=>{if($(i).length>-1){//checks if one of the key elements have loaded aka the page finished loaded
            userID=document.head.getElementsByTagName("script")[2].innerHTML.split("id: ")[1].split(",")[0];
          
            //https://stackoverflow.com/a/13152970
            $('input[type=radio][name=radio-1]').change(function() {//getAllWrong
                if (this.value == 'on') {
                    //alert("on");
                    setUserSettings("user"+userID,"getAllWrong","on",(result)=>{console.log(result)});
                    setTimeout(()=>{$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section>article>div>button").click()},getRndInteger(100,500));//automatically click next button to get all wrong and collect data fast
                }
                else if (this.value == 'off') {
                    //alert("off");
                    setUserSettings("user"+userID,"getAllWrong","off",(result)=>{console.log(result)});
                }
            });
          $('input[type=radio][name=radio-2]').change(function() {//instantContinue
                if (this.value == 'on') {
                    //alert("on");
                    setUserSettings("user"+userID,"instantContinue","on",(result)=>{console.log(result)});
                    setTimeout(()=>{$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section>article>div>button").click()},getRndInteger(100,500));//automatically click next button to get all wrong and collect data fast
                }
                else if (this.value == 'off') {
                    //alert("off");
                    setUserSettings("user"+userID,"instantContinue","off",(result)=>{console.log(result)});
                }
            });
          //document.getElementById("hidedialogue").click();
            getUserSettings(userID,(gotAllWrong,instontContinue)=>{//get the users settings if saved
                //alert(gotAllWrong);
                $('input[type=radio][name=radio-1][value=on]').prop("checked",(gotAllWrong=="on"));
                $('input[type=radio][name=radio-1][value=off]').prop("checked",(gotAllWrong=="off"));
                settings_getAllWrong=gotAllWrong=="on";//true:false
                $('input[type=radio][name=radio-2][value=on]').prop("checked",(instontContinue=="on"));
                $('input[type=radio][name=radio-2][value=off]').prop("checked",(instontContinue=="off"));
                settings_instantContinue=instontContinue=="on";
                if(settings_getAllWrong)setTimeout(()=>{$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section>article>div>button").click();document.getElementsByClassName("Nri-Quiz-Layout-Question")[0].getElementsByTagName("button")[getRndInteger(0,3)].click();},getRndInteger(100,500));
            });
            if(url.indexOf("try_similar")==-1){//not on try_similar page aka in a practice question
                //alert(getQuestionType());
                //var window=new jqWindow(10,10,"test","windowid");
                //window.create();
              getServerStatus((status)=>{getNumOfQuestion(practiceID,(numofquestions)=>{document.getElementById("questionInfo").innerText+="type: "+getQuestionType()+"\nquestion id: "+practiceID+"\nuser id: "+userID+"\nserver status: "+((status)?"up":"down");document.getElementById("questionInfo").innerText+="\n"+numofquestions+" answers are available for this practice so far.  ";})});
              
                if(getQuestionType()=="MultipleChoice"){
                    question=document.getElementsByClassName("Nri-Quiz-Layout-Question")[0].getElementsByTagName("p")[0].innerText;
                    /*numOfChoices=document.getElementsByClassName("Nri-Quiz-Layout-Question")[0].getElementsByTagName("button").length;
                    for(var x=0;x<numOfChoices;x++){
                        choice[x]=document.getElementsByClassName("Nri-Quiz-Layout-Question")[0].getElementsByTagName("button")[x].innerText;
                    };*/
                    //alert("q:"+question+"\nchoice:"+choice);
                    getQuestions(practiceID,question);

                }else if(getQuestionType()=="Highlighting"){
                    question="";
                    for(var x=0;x<document.getElementById("nri-yellow").getElementsByTagName("span").length-2;x++){
                        question+=document.getElementById("nri-yellow").getElementsByTagName("span")[x].innerText;
                    }
                    //alert(question);
                    getQuestions(practiceID,question);
                }
                else if(getQuestionType()=="OutlineDraggable"){
                  question=document.getElementsByClassName("Nri-Quiz-Layout-Question")[0].getElementsByTagName("p")[0].innerText;
                  getQuestions(practiceID,question);
                }
              else if(getQuestionType()=="Playground"){
                  question=JSON.parse(document.getElementById("quiz-question").getElementsByTagName("div")[0].getAttribute("data-data")).the_question.paragraphs[0].structures[0].sections[0].text;
                  getQuestions(practiceID,question);
                }
              else if(getQuestionType()=="Punctuation"){
                  var temmmmmmp=JSON.parse(document.getElementById("quiz-question").getElementsByTagName("div")[0].getAttribute("data-data")).the_question;
                var numberofthethings=(JSON.stringify(temmmmmmp.sentence)).match(/text/g).length;
                question="";
                  for(var x=0; x<numberofthethings;x++){
                    question+=temmmmmmp.sentence[x].text;
                  }
                //alert(temmmmmmp.the_question.sentence[0].text);
                //alert(question);
                getQuestions(practiceID,question);
                }
            }else if(url.indexOf("try_similar")>-1){//if on try_similar page aka they just got one wrong
                //alert(getQuestionType());
                getTrySimilarQuestionType((result)=>{
                  document.getElementById("questionInfo").innerText+="type: "+result+"\nquestion id: "+practiceID+"\nuser id: "+userID;
                    if(result=="MultipleChoice"){
                        document.getElementById("try-similar-problem").innerText="question data saved";
                        var Question,Answer;
                        var questionjsondata=JSON.parse(document.getElementsByClassName("try-similar-container")[0].getElementsByTagName("div")[1].getAttribute("data-data"));
                        Question=questionjsondata.sentence;
                        Answer=questionjsondata.correct_option;
                        //alert("q: "+Question+"\na: "+Answer);
                        addQuestion(practiceID,Question,Answer,(result)=>{console.log(result)});
                    }else if(result=="Highlighting"){
                        document.getElementById("try-similar-problem").innerText="question data saved";
                        var _Question="";
                        var _Answer;
                        for(var y=0;y<document.getElementsByClassName("remediation-answer-sentence")[0].getElementsByTagName("span").length/2;y++){
                            _Question+=document.getElementsByClassName("remediation-answer-sentence")[0].getElementsByTagName("span")[y].innerText;
                        }
                        _Answer=document.getElementsByClassName("answer-correct")[0].innerText;
                        //alert(_Answer);
                        //alert(_Question);
                        addQuestion(practiceID,_Question,_Answer,(result)=>{console.log(result)});
                    }else if(result=="OutlineDraggable"){
                        document.getElementById("try-similar-problem").innerText="question data saved";
                        var _answer="";
                      var __question=JSON.parse(document.getElementsByClassName("try-similar-container")[0].getElementsByTagName("div")[1].getAttribute("data-data")).outline[0].text;
                        var __answer;
                        //_Answer=$("[data-answer='correct']")[0].getElementsByTagName("p")[0].innerText;
                        __answer=JSON.parse(document.getElementsByClassName("try-similar-container")[0].getElementsByTagName("div")[1].getAttribute("data-data")).correctsByDropzone;
                      for(var corr in __answer){
                        _answer+= __answer[corr];
                      }
                      //alert(__question);
                        //alert(_Answer);
                        //alert(_Question);
                        addQuestion(practiceID,__question,_answer,(result)=>{console.log(result)});
                    }else if(result=="MultiHighlighter"){//WIP
                      /*var datadata=JSON.parse(document.getElementsByClassName("try-similar-container")[0].getElementsByTagName("div")[0].getAttribute("data-data")).correctAnswer;
                      var tmp="";
                      for(var x=0;x<datadata.length;x++){
                        if(datadata[x].highlighted=="Reasoning")tmp+=datadata[x].text
                      }
                    */
                  }else if(result=="Playground"){
                      //var datadata=JSON.parse(document.getElementsByClassName("try-similar-container")[0].getElementsByTagName("div")[0].getAttribute("data-data")).correctAnswer;
                  var aaaaanswer=JSON.parse(document.getElementsByClassName("comparison-paragraphs")[0].getElementsByTagName("div")[0].getAttribute("data-data")).comparison_paragraphs[1].playground.paragraphs[1].structures[0].sections[0].text;
                    var qqqqqquestion=JSON.parse(document.getElementsByClassName("comparison-paragraphs")[0].getElementsByTagName("div")[0].getAttribute("data-data")).comparison_paragraphs[1].playground.paragraphs[1].structures[0].sections[0].text;
                    addQuestion(practiceID,encodeURIComponent(qqqqqquestion),encodeURIComponent(aaaaanswer),(result)=>{console.log(result)});
                  }else if(result=="Punctuation"){
                      //var datadata=JSON.parse(document.getElementsByClassName("try-similar-container")[0].getElementsByTagName("div")[0].getAttribute("data-data")).correctAnswer;
                  var aaaaaanswer=document.getElementsByClassName("markdownified-quiz-engine-text markdownified")[1].innerText;
                    var qqqqqqquestion=document.getElementsByClassName("markdownified-quiz-engine-text markdownified")[1].innerText;
                    addQuestion(practiceID,encodeURIComponent(qqqqqqquestion),encodeURIComponent(aaaaaanswer),(result)=>{console.log(result)});
                }
                  
                });
            }else{
                alert("wtf");
            }
            //alert(JSON.Stringify(getQuestions()));

            //alert(question+"\n"+choice);
            clearInterval(waitForItToLoad);
        }});
        var timer=settings_instantContinue==false?3:0;var countdown=setInterval(()=>{if(!(typeof document.getElementById("try-similar-problem") == "undefined"||document.getElementById("try-similar-problem")==null)){document.getElementById("try-similar-problem").innerText="automatically continuing in "+timer+"...";timer--;}if(timer<=0){clearInterval(countdown);$($trySimilar).click();}},1000);
        //$($trySimilar).click();//click the continue button (if it is there)
        //if(settings_getAllWrong)setTimeout(()=>{$("html>body>div:eq(3)>div>div>div:eq(1)>div>section>section>article>div>button").click()},getRndInteger(100,500));//automatically click next button to get all wrong and collect data fast
    },500);
})();