Skip to content
Snippets Groups Projects
Select Git revision
  • c33851bb0d43090dcc7fc3abfed69278ee462d86
  • main default protected
2 results

alquiz_en.js

Blame
  • alquiz_en.js 59.40 KiB
    ///START AL QUIZ SCRIPT///
    class QuestionGroup {
        constructor(id, description, Questions, nextGroup) {
            this.id = id;
            this.description = description;
            this.Questions = {};
            if (!!Questions) {
                Questions.forEach(Question => {
                    this.Questions[Question.id] = Question;
                });
            }
        }
    }
    
    class BubbleInfo {
        constructor(stateStringAssociation) {
            /*this.success = success;
            this.validation = validation;
            this.failure = failure;
            this.redo = redo;
            this.camebackaftersuccess = camebackaftersuccess;
            this.error = error;*/
            for(let i in stateStringAssociation) {
                this[i] = stateStringAssociation[i];
            }
        }
    
        getText(state) {
            if (this[state] != undefined) {
                return this[state];
            }
            return undefined;
        }
    }
    
    class Instruction {
    	constructor(id, description, onsuccess, onfailure, BubbleInfo, questionsOnPage) {
    		this.id = id;
    		/* success means: challenge accepted and go to endboss*/
    		this.onsuccess = onsuccess;
    		/*failure means: give me the first easy question*/
    		this.onfailure = onfailure;
            this.description = description;
            this.BubbleInfo = BubbleInfo;
    
            this.questionsOnPage = questionsOnPage == undefined ? 1 : questionsOnPage;
    	}
    	
    	isSolved() {
    		return false;
    	}
    
        isCurrentlySolved() {
            return false;
        }
    }
    
    class Question extends Instruction {
        constructor(id, description, needs, BubbleInfo, onsuccess, onfailure, askBeforeSkip, questionsOnPage) {
            super(id, description, onsuccess, onfailure, BubbleInfo, questionsOnPage);
            this.needs = needs;
            this.solved = 0;
            /*solved means: solved at least once in this attempt, currentlySolved means: solved actually now in the current scope of js variables*/
            this.currentlySolved = 0;
            this.askBeforeSkip = askBeforeSkip == undefined ? true : askBeforeSkip;
        }
    
        isSolved(onlyOnCurrentlySolved) {
            if(onlyOnCurrentlySolved == undefined) {
                onlyOnCurrentlySolved = false;
            }
            let solvedAtAskedTime = (!onlyOnCurrentlySolved ? this.solved : this.currentlySolved);
            if (solvedAtAskedTime >= this.needs) {
                return true;
            }
            return false;
        }
    
        ifCurrentlySolved() {
            if (this.currentlySolved >= this.needs) {
                return true;
            }
            return false;
        }
    }
    
    class Quiz {
        constructor(QuestionGroups, currentQuestionId) {
            this.QuestionGroups = QuestionGroups;
            this.currentQuestionId = currentQuestionId;
            if (this.currentQuestionId == undefined) {
                this.currentQuestionId = Object.keys(this.QuestionGroups[0].Questions)[0];
            }
    
            //auto assign onsuccess and onfailure for undefined
            let grouplength = this.QuestionGroups.length;
            for (let i = 0; i < grouplength; i++) {
                let questionlength = Object.keys(this.QuestionGroups[i].Questions).length;
                for (let j = 0; j < questionlength; j++) {
                    if (!this.QuestionGroups[i].Questions[Object.keys(this.QuestionGroups[i].Questions)[j]].onsuccess) {
                        //probably next question or next group
                        if (j < questionlength - 1) {
                            //next question
                            this.QuestionGroups[i].Questions[Object.keys(this.QuestionGroups[i].Questions)[j]].onsuccess = Object.keys(this.QuestionGroups[i].Questions)[j + 1];
                        } else if (i < grouplength - 1) {
                            //console.log(Object.keys(this.QuestionGroups[i].Questions)[j] + " leads to next group onsuccess ");
                            //first question of next group
                            this.QuestionGroups[i].Questions[Object.keys(this.QuestionGroups[i].Questions)[j]].onsuccess = Object.keys(this.QuestionGroups[i + 1].Questions)[0];
                        } else {
                            //console.log("no other group");
                            this.QuestionGroups[i].Questions[Object.keys(this.QuestionGroups[i].Questions)[j]].onsuccess = "_finish";
                        }
                    }
    
                    if (!this.QuestionGroups[i].Questions[Object.keys(this.QuestionGroups[i].Questions)[j]].onfailure) {
                        //probably first question of next group
                        if (i < grouplength - 1) {
                            //console.log(Object.keys(this.QuestionGroups[i].Questions)[j] + " leads to next group onfailure ");
                            this.QuestionGroups[i].Questions[Object.keys(this.QuestionGroups[i].Questions)[j]].onfailure = Object.keys(this.QuestionGroups[i + 1].Questions)[0];
                        } else {
                            //console.log("no other group");
                            this.QuestionGroups[i].Questions[Object.keys(this.QuestionGroups[i].Questions)[j]].onfailure = "_finish";
                        }
                    }
                };
            }
        }
    
        getQuestions() {
            let objects = [];
            this.QuestionGroups.forEach(QuestionGroup => {
                for (let k in QuestionGroup.Questions) {
                    objects.push(QuestionGroup.Questions[k]);
                }
            });
            return objects;
        }
    
        getQuestion(id) {
            if (id == undefined) {
                id = this.currentQuestionId;
            }
            for (let i = 0; i < this.QuestionGroups.length; i++) {
                if (this.QuestionGroups[i].Questions[id] != undefined) {
                    return this.QuestionGroups[i].Questions[id];
                }
            }
            return false;
        }
    
        getNextQuestionId(questionId) {
            if (questionId == undefined) {
                questionId = this.currentQuestionId;
            }
            let returnValue = false;
            for (let i = 0; i < this.QuestionGroups.length; i++) {
                if (QuestionGroups[i].Questions[questionId] != undefined) {
                    let nextStep = QuestionGroups[i].Questions[questionId].isSolved() ? QuestionGroups[i].Questions[questionId].onsuccess : QuestionGroups[i].Questions[questionId].onfailure;
                    switch (nextStep) {
                        case "_finish":
                            return -1;
                        default:
                            return nextStep;
                            break;
                    }
                }
            }
            console.log("question id not found");
            return false;
        }
    
        getPageURL(questionId) {
            if (questionId == undefined) {
                questionId = this.currentQuestionId;
            }
    
            let firstQuestionNavElement = document.querySelector("#quiznavbutton1");
            if (!firstQuestionNavElement) {
                return false;
            }
            let plainUrl = "";
            if (!firstQuestionNavElement.href || firstQuestionNavElement.href == "#") {
                plainUrl = window.location.href;
            } else {
                plainUrl = firstQuestionNavElement.href;
            }
    
            //let sanitizedUrl = plainUrl.replace(/(.*?)(?:#|&page=\d*#*|&scrollpos=\d*#*)/, "\1");
            let sanitizedUrl = plainUrl;
            let relPos = plainUrl.indexOf("&scrollpos");
            if (relPos == -1) {
                relPos = plainUrl.indexOf("&page");
                if (relPos == -1) {
                    relPos = plainUrl.indexOf("#");
                }
            }
    
            if (relPos > -1) {
                sanitizedUrl = plainUrl.substr(0, relPos);
            }
    
            return sanitizedUrl + "&page=" + this.getQuestion(questionId).page
        }
    
        getNextPageInfo(questionId, forceURL) {
            if (questionId == undefined) {
                questionId = this.currentQuestionId;
            }
            let Question = this.getQuestion(questionId);
    
            if(forceURL == undefined) {
                forceURL = false;
            }
    
            let nextPageUrl = "";
            let nextPageLinkText = "";
            let nextQuestionId = this.getNextQuestionId();
            let possibleNextPageUrl = this.getPageURL(nextQuestionId);
    
            if (nextQuestionId == -1) {
                //finish
                let finishAttemptElement = document.querySelector(".endtestlink.aalink");
                if (!finishAttemptElement || !finishAttemptElement.href) {
                    possibleNextPageUrl = "summary.php";
                } else {
                    possibleNextPageUrl = finishAttemptElement.href;
                }
                nextPageLinkText = "Finish";
            }
            else {
                nextPageLinkText = "Next question";
            }
    
            //actually means a real skip, no right or wrong
            if(Question.askBeforeSkip == true  && !forceURL && !Question.isSolved() && document.querySelector(".stackprtfeedback") == undefined) {
                //ask before skip
                nextPageUrl = "javascript:showAskBeforeSkipModal();";
                document.querySelector(".skip-yes").href = possibleNextPageUrl;
            }
            else {            
                 nextPageUrl = possibleNextPageUrl;
            }
            return {
                url: nextPageUrl,
                linkText: nextPageLinkText
            };
        }
    
        updateMoodleNavButtons() {
            let buttonDivs = document.querySelectorAll(".submitbtns");
            buttonDivs.forEach(buttonDiv => {
                buttonDiv.childNodes.forEach(buttonDivChild => {
                    buttonDivChild.style.visibility = "hidden";
                    buttonDivChild.style.width = "0";
                });
            });
    
            let cameFrom = sessionStorage.getItem("camefrom");
            if(cameFrom == undefined) {
                let previousPageButton = document.getElementById("mod_quiz-prev-nav");
                if(previousPageButton != undefined) {
                    previousPageButton.value = "Back";
                    previousPageButton.style.visibility = "visible";
                    previousPageButton.style.width = "auto";  
                }
            }
            else {
                let prevButton = document.createElement("a");
                prevButton.classList.add("btn", "btn-primary", "btn-prev-question");
                prevButton.href = this.getPageURL(cameFrom);
                prevButton.innerHTML = "Back";
    
                buttonDivs.forEach(buttonDiv => {
                    buttonDiv.insertBefore(prevButton, buttonDiv.firstChild);
                });
    
                sessionStorage.removeItem("camefrom");
            }
    
            let nextButton = document.createElement("a");
            nextButton.classList.add("btn", "btn-primary", "btn-next-question");
            let nextPageInfos = this.getNextPageInfo();
            nextButton.href = nextPageInfos.url;
            nextButton.innerHTML = nextPageInfos.linkText;
    
            buttonDivs.forEach(buttonDiv => {
                buttonDiv.appendChild(nextButton);
            });
        }
    
        updateSpeechBubbles(id) {
            if (id == undefined) {
                id = this.currentQuestionId;
            }
            let currQuestion = this.getQuestion(id);
            if (!currQuestion || !currQuestion.BubbleInfo) {
                return false;
            }
            let bubbles = document.querySelectorAll(".bubble:not(.in-modal)");
            if (bubbles.length != 1) {
                console.log("bad amount of speech bubbles");
                return false;
            }
            let bubble = bubbles[0];
            let text = "";
    
            let icon = document.querySelector(".dm-icon");
            let iconUrls = {
                grin:"https://marvin.hs-bochum.de/~mneugebauer/dm-avatar-grin.svg",
                think:"https://marvin.hs-bochum.de/~mneugebauer/dm-avatar-think.svg",
                sad:"https://marvin.hs-bochum.de/~mneugebauer/dm-avatar-sad.svg",
                happy:"https://marvin.hs-bochum.de/~mneugebauer/dm-avatar-happy.svg"
            };
            let imgReaction = "";
    
            //on instruction, the revisit property of the bubble info plays a special role, so...
            if(currQuestion instanceof Instruction && !(currQuestion instanceof Question) && currQuestion.visited == true) {
                let revisitText = currQuestion.BubbleInfo.getText("revisit");
                if(revisitText != "" && revisitText != undefined) {
                    text = revisitText;
                }
            }
    
            //get current state of question
            let stackFeedback = document.querySelector(".stackprtfeedback");
            if (stackFeedback != undefined) {
                //solved, false or partially correct
    
                //only move feedback to the speech bubble on one feedback field
                let stackFeedbacks = document.querySelectorAll(".stackprtfeedback");
    
                if (currQuestion.isSolved(true) == true) {
                    imgReaction = "happy";
                    if (currQuestion.BubbleInfo.getText("success") == undefined) {
                        if (stackFeedbacks.length == 1) {
                            //move the stack feedback in the speech bubble by default and add "N&auml;chste Frage/&Uuml;bung beenden"
                            let stackFeedbackInWords = "";//stackFeedback.querySelector("div");
                            let first = true;
                            //console.log(stackFeedback.childNodes);
                            stackFeedback.childNodes.forEach(function(childNode) {
                                //console.log(childNode.innerHTML);
                                if(first == false) { stackFeedbackInWords += " "; } else { first = false; }
                                if(childNode.innerHTML != undefined && childNode.innerHTML != "" && childNode.tagName != "SCRIPT") {
                                    stackFeedbackInWords += childNode.innerHTML;
                                }
                            });
                            if (stackFeedbackInWords == "" /*stackFeedbackInWords == undefined || stackFeedbackInWords.innerHTML == undefined || stackFeedbackInWords.innerHTML == ""*/) {
                                text = "Richtig!";
                                console.log("no feedback found to move");
                            }
                            let nextPageInfos = this.getNextPageInfo();
                            text = stackFeedbackInWords + "If it gives you more confidence, you can <a href=\"javascript:;\" onclick=\"repeatQuestion();\">repeat this task</a>. Otherwise you are ready for the <a href=\"" + nextPageInfos.url + "\">" + nextPageInfos.linkText + "</a>.";
                            stackFeedback.style.display = "none";
                        }
                        else {
                            text = "Richtig!";
                            console.log("using standard speech-bubble-feedback because of undefined feedback text for solved state and too many feedback fields")
                        }
                    }
                    else {
                        text = currQuestion.BubbleInfo.getText("success");
                    }
                }
                else {
                    //false or partially correct
                    imgReaction = "sad";
                    if (currQuestion.BubbleInfo.getText("failure") == undefined) {
                        console.log("no fail text");
                        if (stackFeedbacks.length == 1) {
                            //move the stack feedback in the speech bubble by default and add "Erneut versuchen"
                            let stackFeedbackInWords = "";/*stackFeedback.querySelector("div");*/
                            let first = true;
                            stackFeedback.childNodes.forEach(function(childNode) {
                                //console.log(childNode);//.innerHTML);
                                if(first == false) { stackFeedbackInWords += " "; } else { first = false; }
                                if(childNode.nodeType == 3) { //if text node
                                    stackFeedbackInWords += childNode.data;
                                }
                                else if(childNode.innerHTML != undefined && childNode.innerHTML != "" && childNode.tagName != "SCRIPT") {
                                    stackFeedbackInWords += childNode.innerHTML;
                                }
                            });
                            
                            if (stackFeedbackInWords == ""/* || stackFeedbackInWords.innerHTML == undefined || stackFeedbackInWords.innerHTML == ""*/) {
                                text = "Falsch!";
                                console.log("no feedback found to move");
                            }
                            
                            
                            let nextPageInfos = this.getNextPageInfo();
                            text = stackFeedbackInWords + " Try again? <a href=\"#\" onclick=\"document.querySelector('input[name*=redoslot]').click();\">Yes</a> <a href=\"" + nextPageInfos.url + "\">No (" + nextPageInfos.linkText + ")</a>"
                            stackFeedback.style.display = "none";
                        }
                        else {
                            text = "Falsch.";
                            console.log("using standard speech-bubble-feedback because of undefined feedback text for failure state and too many feedback fields")
                        }
                    }
                    else {
                        text = currQuestion.BubbleInfo.getText("failure");
                    }
                }
            }
            else {
                //verfication, syntax error or came back to main question
                if (document.querySelector(".validationerror") != undefined) {
                    //verification state
                    text = currQuestion.BubbleInfo.getText("validation") == undefined ? "Did the system interpret your input correctly? <a href=\"#\" onclick=\"document.querySelector('input[id*=q][name$=_-submit]').click();\">Yes</a> <a href=\"#\" onclick=\"this.parentNode.innerHTML='&Auml;ndere deine Eingabe und klicke erneut auf &quot;Pr&uuml;fen&quot;'\">No</a>" : currQuestion.BubbleInfo.getText("validation");
                }
                else if(document.querySelector(".alert") != undefined) {
                    //syntax error
                    imgReaction = "think";
                    text = currQuestion.BubbleInfo.getText("error") == undefined ? "Oh! Apparently, there is a problem with your input. Please look at the note below the input field, correct it and click &quot;Check&quot; again." : currQuestion.BubbleInfo.getText("error");
                }
                /*else {
                    //came back to main question after the last of this group is solved
                    console.log("start routine to check for coming back");
                    let i = 0;
                    for (i in this.QuestionGroups) {
                        if (QuestionGroups[i].Questions[this.currentQuestionId] != undefined) {
                            break;
                        }
                    }
                    //console.log(this.currentQuestionId + " is in group " + i);
                    let keys = Object.keys(this.QuestionGroups[i].Questions);
                    if (keys[0] == this.currentQuestionId) {
                        //console.log(this.currentQuestionId + " is the first question of this group");
                        if (this.QuestionGroups[i].Questions[keys[keys.length - 1]] != undefined && this.QuestionGroups[i].Questions[keys[keys.length - 1]].isSolved() == true) {
                            console.log("came back after solving last question of group");
                            if (currQuestion.BubbleInfo.getText("camebackaftersuccess") == undefined) {
                                text = "Willkommen zur&uuml;ck zu dieser Aufgabe. Haben dir die letzten Aufgaben geholfen, diese Aufgabe zu verstehen? Versuche es doch nochmal! Gehe ansonsten weiter zur n&auml;chsten Aufgabe.";
                            } else {
                                text = currQuestion.BubbleInfo.getText("camebackaftersuccess");
                            }
                            currQuestion.onfailure = currQuestion.onsuccess;
                            //this.updateMoodleNavButtons();
                        }
                    }
                }*/
                //if(in verification state)
                //text = Question.BubbleInfo.getText("verify") == undefined ? "Wurde deine Eingabe richtig interpretiert? %check% <a onclick=\"...\">Nein</a>" : Question.BubbleInfo.getText("verify");
                //else if(in false state)
                //else if(in syntax error state)
                //else if(in redo state)
                //else
                //assume initial state
                //text = Question.BubbleInfo.getText("initial")
            }
    
            //bubble.classList.remove("hidden");
    
            if (text != "") {
                //append special links to text, e. g. %nextlink%, %linktoquestionid_id%, %check%
                bubble.innerHTML = text;
            }
            if(imgReaction != "" && icon != undefined) {
                icon.src = iconUrls[imgReaction];
            }
    
            return true;
        }
        
        updateNavigation() {
        	let navPanel = document.querySelector(".qn_buttons");
        	if(!navPanel) {
        		return false;
        	}
        	let buttons = document.querySelectorAll("[id*=quiznavbutton]");
        	if(buttons.length == undefined || buttons.length < 1) {
        		return false;
        	}
        	//group
        	//let groupHeadingNodes = [];
        	this.QuestionGroups.forEach(QuestionGroup => {
        		let wrapper = document.createElement("span");
        		wrapper.dataset.isFor = QuestionGroup.id;
        		//groupHeadingNodes.push(heading);
        		
        		let heading = document.createElement("h2");
        		heading.innerHTML = QuestionGroup.description;
        		heading.style.clear = "left";
        		wrapper.appendChild(heading);
        		
        		let j = 0;
                let k = 1;
        		let questionAmount = Object.keys(QuestionGroup.Questions).length;
        		for(let i in QuestionGroup.Questions) {
                    //console.log("quiznavbutton"+(QuestionGroup.Questions[i].page+1));
        			let questionCard = document.getElementById("quiznavbutton"+(QuestionGroup.Questions[i].page+1));
    
                    questionCard.querySelectorAll(".accesshide").forEach(slotMarker => {
                        if(slotMarker != undefined && slotMarker.nextSibling != undefined) {
                            if(!(QuestionGroup.Questions[i] instanceof Question) && QuestionGroup.Questions[i] instanceof Instruction) {
                                //assume first question to be instructions
                                slotMarker.nextSibling.data = "i";
                            }
                            else if(j < questionAmount-1) {
                                slotMarker.nextSibling.data = k;
                                k++;
                            }
                            else {
                                slotMarker.nextSibling.data = "";
                                let endbossImg = document.createElement("img");
                                endbossImg.src = "https://marvin.hs-bochum.de/~mneugebauer/skull.svg";
                                endbossImg.style.height = "20px";
                                slotMarker.parentNode.insertBefore(endbossImg, slotMarker.nextSibling);
                            }
                        }
                    });
                    if(!questionCard) {
                        console.log("bad question card id for question "+QuestionGroup.Questions[i].id);
                    }
                    else {
                        wrapper.appendChild(questionCard);
                    }
    
                    if(QuestionGroup.Questions[i].questionsOnPage > 1) {
                        for(let l=QuestionGroup.Questions[i].questionsOnPage;l>0;l--) {
                            let questionCardToHide = document.getElementById("quiznavbutton"+(QuestionGroup.Questions[i].page+l+1));
                            if(questionCardToHide != undefined) {
                                questionCardToHide.style.display = "none";
                            }
                        }
                    }
    
        			j++;
        		};
        		
        		navPanel.appendChild(wrapper);
        	});
    
            //put a flag instead of a skull, a number or an "i" in the very last question card
            document.querySelectorAll(".qn_buttons span[data-is-for]:last-child a:last-child img").forEach(function(lastQuestionCard) {
                lastQuestionCard.src = "https://marvin.hs-bochum.de/~mneugebauer/flag.svg";
            });
    
            //show group navigation on instruction and update speech bubble navigation
            let currentQuestion = this.getQuestion();
            if(!(currentQuestion instanceof Question) && currentQuestion instanceof Instruction) {
    
                let CurrentGroup;
                for(let i in this.QuestionGroups) {
                    if(this.QuestionGroups[i].Questions[this.currentQuestionId] != undefined) {
                        CurrentGroup = this.QuestionGroups[i];
                        break;
                    }
                };
    
                let groupNavigation = document.querySelector(".group-navigation");
                if(groupNavigation != undefined) {
                    //find current group
                    
                    if(CurrentGroup != undefined) {
    
                        //show group navigation
                        let cards = document.querySelectorAll("[data-is-for="+CurrentGroup.id+"] a")
                        let cardAmount = cards.length;
                        let keys = Object.keys(CurrentGroup.Questions);
                        for(let i=cardAmount-1;i>=0;i--) {
                            let cardClone = cards[i].cloneNode(true);
                            let stepWrapper = document.createElement("div");
                            stepWrapper.classList.add("wrap_nav_group");
                            let stepHeadingAnchor = document.createElement("a");
                            stepHeadingAnchor.href = cardClone.href;
                            let stepHeading = document.createElement("h2");
                            stepHeading.innerHTML = CurrentGroup.Questions[keys[i]].description;
    
                            stepHeadingAnchor.appendChild(stepHeading);
                            stepWrapper.appendChild(cardClone);
                            stepWrapper.appendChild(stepHeadingAnchor);
                            groupNavigation.appendChild(stepWrapper);
                        };
    
                        let groupNavCss = document.createElement("style");groupNavCss.type="text/css";groupNavCss.innerHTML = ".path-mod-quiz .group-navigation .qnbutton { text-decoration: none; font-size: 14px; line-height: 20px; font-weight: 400; background-color: #fff; background-image: none; height: 40px; width: 30px; border-radius: 3px; border: 0; overflow: visible; margin: 0 6px 6px 0;} .path-mod-quiz .group-navigation .qnbutton { background: none; background-color: rgba(0, 0, 0, 0); background-color: #eee; border: 0; border-radius: 4px; color: #000000 !important; font-size: 14px; font-weight: 700; height: 45px; line-height: 25px !important; margin: 0 5px 5px 0; width: 35px;} .group-navigation .qnbutton .thispageholder { border: 1px solid #999; border-radius: 4px; z-index: 1;}.group-navigation .qnbutton .thispageholder { border: 1px solid; border-radius: 3px; z-index: 1;}.group-navigation .qnbutton .trafficlight, group-navigation .qnbutton .thispageholder { display: block; position: absolute; top: 0; bottom: 0; left: 0; right: 0;} .path-mod-quiz .group-navigation .qnbutton.notyetanswered .trafficlight, .path-mod-quiz .group-navigation .qnbutton.invalidanswer .trafficlight { background-color: #fff;}.path-mod-quiz .group-navigation .qnbutton.notyetanswered .trafficlight, .path-mod-quiz .group-navigation .qnbutton.invalidanswer .trafficlight { background-color: #fff;}.path-mod-quiz .group-navigation .qnbutton .trafficlight { border: 0; background: #fff none center / 10px no-repeat scroll; height: 20px; margin-top: 20px; border-radius: 0 0 3px 3px;} .path-mod-quiz .group-navigation .qnbutton .trafficlight { background: #fff none center 4px / 10px no-repeat scroll; background-color: rgb(255, 255, 255); border: 0; border-radius: 0 0 4px 4px; height: 20px; margin-top: 25px;} .path-mod-quiz .group-navigation .qnbutton.correct .trafficlight {   background-color: #8bc34a;   background-image: url(/theme/image.php/adaptable/theme/1660635117/mod/quiz/checkmark); } .path-mod-quiz .group-navigation .qnbutton.notanswered .trafficlight, .path-mod-quiz .group-navigation .qnbutton.incorrect .trafficlight { background-color: #f44336; } .path-mod-quiz .group-navigation .qnbutton.partiallycorrect .trafficlight { background-color: #ff9800;   background-image: url(/theme/image.php/adaptable/theme/1660635117/mod/quiz/whitecircle); } .path-mod-quiz .group-navigation .qnbutton.thispage .thispageholder {  border: 3px solid #1f536b; } .wrap_nav_group { clear:left; }";
                        document.getElementsByTagName("head")[0].appendChild(groupNavCss);
                    }
                }
    
                let endbossLink = document.querySelector(".endboss-link");
                if(endbossLink != undefined) {
                    endbossLink.href = this.getPageURL(currentQuestion.onsuccess);
                }
    
                if(CurrentGroup != undefined) {
                    let questionKeys = Object.keys(CurrentGroup.Questions);
                    let nextWorldLink = document.querySelector(".link-next-world");
                    let nextWorldURL = this.getPageURL(CurrentGroup.Questions[questionKeys[questionKeys.length-1]].onsuccess);
    
                    if(nextWorldLink != undefined) {
                        nextWorldLink.href = nextWorldURL;
                    }
    
                    let endbossDefeat = CurrentGroup.Questions[questionKeys[questionKeys.length-1]].isSolved();
                    let endbossStatePhrase = document.querySelector(".endboss-state");
                    if(endbossStatePhrase != undefined) {
                        if(endbossDefeat == true) {
                            endbossStatePhrase.innerHTML = "bereits";
                        }
                        /*else {
                            endbossStatePhrase.innerHTML = "noch nicht";
                        }*/
                    }
    
                    let nextQuestionLink = document.querySelector(".link-next-question");
                    if(nextQuestionLink != undefined) {
                        if(endbossDefeat == true) {
                            nextQuestionLink.innerHTML = "der n&auml;chsten Welt";
                            nextQuestionLink.href = nextWorldURL;
                            //overwrite default next question
                            document.querySelector(".btn-next-question").href = nextWorldURL;
                        }
                        else {
                            let i;
                            let page;
                            for(i in CurrentGroup.Questions) {
                                if(!CurrentGroup.Questions[i].isSolved() && CurrentGroup.Questions[i] instanceof Question) {
                                    page = CurrentGroup.Questions[i].page;
                                    break;
                                }
                            }
                            //console.log(page);
                            nextQuestionLink.setAttribute("onclick", 'tutorialFocusElement(document.querySelector(\'.wrap_nav_group [data-quiz-page="'+page+'"]\'));');
                            document.querySelector(".btn-next-question").href = this.getPageURL(i);
                        }
                    }
    
                    let currentLevelPhrase = document.querySelector(".current-level");
                    if(currentLevelPhrase != undefined) {
                        let amount = 0;
                        let solved = 0;
                        for(let i in CurrentGroup.Questions) {
                            if(CurrentGroup.Questions[i] instanceof Question) {
                                amount++;
                                if(CurrentGroup.Questions[i].isSolved()) {
                                    solved++;
                                }
                            }
                        }
                        if(endbossDefeat == true) {
                            currentLevelPhrase.innerHTML = amount+" of "+amount;
                        }
                        else {
                            currentLevelPhrase.innerHTML = solved+" of "+amount;
                        }
                    }
                }
    
                sessionStorage.setItem("camefrom", currentQuestion.id);
            }
        	
        }
    
        setCurrentQuestionId(id) {
            this.currentQuestionId = id;
    
            //save question as visited, so next time on loading the script, question will carry the visited property with true
            let visitedQuestionsAsString = sessionStorage.getItem("visited");
            if (visitedQuestionsAsString != undefined) {
                let visitedQuestions = JSON.parse(visitedQuestionsAsString);
                if (visitedQuestions != undefined && visitedQuestions.indexOf(id) < 0) {
                    visitedQuestions.push(id);
                    sessionStorage.setItem("visited", JSON.stringify(visitedQuestions));
                }
            } else {
                let visited = [];
                sessionStorage.setItem("visited", JSON.stringify(visited));
            }
    
        }
    
        incrementSolved(id) {
            if (id == undefined) {
                id = this.currentQuestionId;
            }
            this.getQuestion(id).solved++;
            this.getQuestion(id).currentlySolved++;
    
            if (this.getQuestion(id).isSolved()) {
                let solvedQuestionsAsString = sessionStorage.getItem("solved");
                if (solvedQuestionsAsString != undefined) {
                    let solvedQuestions = JSON.parse(solvedQuestionsAsString);
                    if (solvedQuestions != undefined) {
                        if (solvedQuestions.indexOf(id) == -1) {
                            solvedQuestions.push(id);
                            sessionStorage.setItem("solved", JSON.stringify(solvedQuestions));
                        }
                    }
                }
            }
    
        }
    }
    
    let DefaultBubble = new BubbleInfo({});
    
    let SynQuestions = [];
    let FraQuestions = [];
    let PQQuestions = [];
    let RulQuestions = [];
    let LogQuestions = [];
    let TriQuestions = [];
    let SurQuestions = [];
    
    let pythagorasPhrase = "The Pythagorean theorem states that the ancathete added to the square with the counter-cathete to the square gives the hypothenuse squared. In mathematical terms: \\(a^2+b^2=c^2\\;\\).";
    
    SynQuestions.push(new Instruction("start_instructions", "Check-In Training Area", "syn_instructions", "syn_instructions"));
    SynQuestions.push(new Instruction("syn_instructions", "Check-In Syntax", "syn_main", "syn_a1", new BubbleInfo({revisit:"You're back in the overview of this math world, which is all about <b>how to enter answers correctly</b>. Here you are in level <b class=\"current-level\">x of y</b>. You have <span class=\"endboss-state\">not yet</span> defeated the <a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.endboss-link'));\">final boss</a> in this world. Check out your progress below and jump to the question of your choice from here. From here you can also jump to the <a class=\"link-next-world\">next math world</a>. I would recommend you to continue with <a class=\"link-next-question\">the first unresolved question in this world</a>. Click on &quot;<a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.submitbtns'));\">Next question</a>&quot; to get there."})));
    SynQuestions.push(new Question("syn_a1", "Enter Equation ", 1, DefaultBubble, "syn_a2", "syn_a2", true));
    SynQuestions.push(new Question("syn_a2", "Enter Fraction &amp; Division", 1, DefaultBubble, "syn_b1", "syn_b1", true));
    SynQuestions.push(new Question("syn_b1", "Powers", 1, DefaultBubble, "syn_b2", "syn_b2", true));
    SynQuestions.push(new Question("syn_b2", "Rational Expressions", 1, DefaultBubble, "syn_c", "syn_c", true));
    SynQuestions.push(new Question("syn_c", "Root Sign", 1, DefaultBubble, "syn_d", "syn_d", true));
    SynQuestions.push(new Question("syn_d", "Multiple Solutions", 1, DefaultBubble, "syn_e", "syn_e", true));
    SynQuestions.push(new Question("syn_e", "Solving equations in several steps", 1, DefaultBubble, "syn_f", "syn_f", true));
    SynQuestions.push(new Question("syn_f", "Greek Letters", 1, DefaultBubble, "syn_main", "syn_main"));
    SynQuestions.push(new Question("syn_main", "Syntax Boss", 1, new BubbleInfo({success:"Very good! You have mastered the first world. You're ready for the next math world!", camebackaftersuccess:"Welcome back to the first task. With the knowledge you have collected along the way, can you now solve this task? Try again! Click on &quot;Next question&quot; to get to the next task."}), "fra_instructions", "syn_instructions"));
    FraQuestions.push(new Instruction("fra_instructions", "Check-In Fractions &amp; Binom. Formulas", "fra_main", "fra_a", new BubbleInfo({revisit:"You're back in the overview of the math world <b>Fractions &amp; Binom. Formulas</b>. Here you are in level <b class=\"current-level\">x of y</b>. You have <span class=\"endboss-state\">not yet</span> defeated the <a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.endboss-link'));\">final boss</a> in this world. Check out your progress below and jump to the question of your choice from here. From here you can also jump to the <a class=\"link-next-world\">next math world</a>. I would recommend you to continue with <a class=\"link-next-question\">the first unresolved question in this world</a>. Click on &quot;<a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.submitbtns'));\">Next question</a>&quot; to get there."})));
    FraQuestions.push(new Question("fra_a", "Reduce Fraction", 1, DefaultBubble, "fra_b", "fra_b"));
    FraQuestions.push(new Question("fra_b", "Add and Expand Fractions", 1, DefaultBubble, "fra_c", "fra_c"));
    FraQuestions.push(new Question("fra_c", "Multiply Fractions", 1, DefaultBubble, "fra_d", "fra_d"));
    FraQuestions.push(new Question("fra_d", "Divide Fractions", 1, DefaultBubble, "fra_e", "fra_e"));
    FraQuestions.push(new Question("fra_e", "Compound Fraction", 1, DefaultBubble, "fra_f", "fra_f"));
    FraQuestions.push(new Question("fra_f", "Fractions Interim Conclusion", 1, DefaultBubble, "bin_a", "bin_a"));
    FraQuestions.push(new Question("bin_a", "First Binomial Formula", 1, DefaultBubble, "bin_b", "bin_b"));
    FraQuestions.push(new Question("bin_b", "Second Binomial Formula", 1, DefaultBubble, "bin_c", "bin_c"));
    FraQuestions.push(new Question("bin_c", "Third Binomial Formula", 1, DefaultBubble, "bin_main", "bin_main"));
    FraQuestions.push(new Question("bin_main", "Application", 1, DefaultBubble, "fra_main", "fra_main"));
    FraQuestions.push(new Question("fra_main", "Expand Fraction With Term", 1, DefaultBubble, "pq_instructions", "fra_instructions"));
    /*FraQuestions.push(new Question("fra_main", "Bruch vereinfachen mithilfe binomischer Formeln ", 1, new BubbleInfo({camebackaftersuccess:"Willkommen zur&uuml;ck zur ersten Aufgabe. Kannst du mit dem Wissen, was du auf dem Weg gesammelt hast, diese Aufgabe jetzt l&ouml;sen? Versuche es nochmal! Mit Klick auf &quot;N&auml;chste Frage&quot; kommst du zur n&auml;chsten Aufgabe."}), "pq_instructions", "fra_instructions"));*/
    PQQuestions.push(new Instruction("pq_instructions", "Check-In p-q-Formel", "pq_main", "pq_a", new BubbleInfo({revisit:"You're back in the overview of the math world <b>Pq Formula</b>. Here you are in level <b class=\"current-level\">x of y</b>. You have <span class=\"endboss-state\">not yet</span> defeated the <a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.endboss-link'));\">final boss</a> in this world. Check out your progress below and jump to the question of your choice from here. From here you can also jump to the <a class=\"link-next-world\">next math world</a>. I would recommend you to continue with <a class=\"link-next-question\">the first unresolved question in this world</a>. Click on &quot;<a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.submitbtns'));\">Next question</a>&quot; to get there."})));
    PQQuestions.push(new Question("pq_a", "Reshap Term", 1, DefaultBubble, "pq_b", "pq_b"));
    PQQuestions.push(new Question("pq_b", "Use Pq Formula", 1, DefaultBubble, "pq_main", "pq_main"));
    PQQuestions.push(new Question("pq_main", "Boss ", 1, new BubbleInfo({camebackaftersuccess:"Welcome back to this task. Now, can you apply term reshaping and pq formula to solve this problem? Good luck!"}), "rul_instructions", "pq_instructions"));
    RulQuestions.push(new Instruction("rul_instructions", "Check-In Power Laws", "rul_main", "rul_a", new BubbleInfo({revisit:"You're back in the overview of the math world <b>Power Laws</b>. Here you are in level <b class=\"current-level\">x of y</b>. You have <span class=\"endboss-state\">not yet</span> defeated the <a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.endboss-link'));\">final boss</a> in this world. Check out your progress below and jump to the question of your choice from here. From here you can also jump to the <a class=\"link-next-world\">next math world</a>. I would recommend you to continue with <a class=\"link-next-question\">the first unresolved question in this world</a>. Click on &quot;<a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.submitbtns'));\">Next question</a>&quot; to get there."})));
    RulQuestions.push(new Question("rul_a", "Add Powers", 1, DefaultBubble, "rul_b", "rul_b"));
    RulQuestions.push(new Question("rul_b", "Subtract Powers", 1, DefaultBubble, "rul_c", "rul_c"));
    RulQuestions.push(new Question("rul_c", "Representing Root As Potency", 1, DefaultBubble, "rul_d", "rul_d"));
    RulQuestions.push(new Question("rul_d", "Multiply Powers", 1, DefaultBubble, "rul_e", "rul_e"));
    RulQuestions.push(new Question("rul_e", "Use Power Laws", 1, DefaultBubble, "rul_main", "rul_main"));
    RulQuestions.push(new Question("rul_main", "Boss", 1, new BubbleInfo({camebackaftersuccess:"Welcome back to the initial task on the power laws. Now you've learned every power calculation rule. Try again to solve this task. Click on &quot;Next question&quot; to get to the next task."}), "tri_instructions", "rul_instructions"));
    /*LogQuestions.push(new Instruction("log_instructions", "Check-In Zinseszins und Logarithmus", "log_main", "log_a"));
    LogQuestions.push(new Question("log_a", "Zinsrechnung ", 1, DefaultBubble, "log_b", "log_b"));
    LogQuestions.push(new Question("log_b", "Zinseszinsrechnung ", 1, DefaultBubble, "log_c", "log_c"));
    LogQuestions.push(new Question("log_c", "Logarithmus ", 1, DefaultBubble, "log_d", "log_d"));
    LogQuestions.push(new Question("log_d", "Mithilfe von Logarithmus gesuchte Potenz bestimmen ", 1, DefaultBubble, "log_main", "log_main"));
    LogQuestions.push(new Question("log_main", "Endboss ", 1, DefaultBubble, "tri_instructions", "log_instructions"));*/
    
    TriQuestions.push(new Instruction("tri_instructions", "Check-In Trigonometry", "tri_main", "tri_a", new BubbleInfo({revisit:"You're back in the overview of the math world <b>Trigonometry</b>. Here you are in level <b class=\"current-level\">x of y</b>. You have <span class=\"endboss-state\">not yet</span> defeated the <a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.endboss-link'));\">final boss</a> in this world. Check out your progress below and jump to the question of your choice from here. From here you can also jump to the <a class=\"link-next-world\">next math world</a>. I would recommend you to continue with <a class=\"link-next-question\">the first unresolved question in this world</a>. Click on &quot;<a href=\"javascript:;\" onclick=\"tutorialFocusElement(document.querySelector('.submitbtns'));\">Next question</a>&quot; to get there."})));
    TriQuestions.push(new Question("tri_a", "Clarification of Triangle Terms", 3, new BubbleInfo({success:"Richtig!", failure:"False. Look at the graph below and repeat the task. Good luck!"}), "tri_b", "tri_b", true));
    TriQuestions.push(new Question("tri_b", "Pythagorean Theorem 1", 2, new BubbleInfo({success:"Correct! "+pythagorasPhrase, failure:"Falsch. "+pythagorasPhrase+" Feel free to try again. Good luck!"}), "tri_c", "tri_c"));
    TriQuestions.push(new Question("tri_c", "Pythagorean Theorem 2 ", 2, new BubbleInfo({success:"Correct!", failure:"False. Feel free to try again. Good luck!"}), "tri_d", "tri_d"));
    TriQuestions.push(new Question("tri_d", "Clarification of Trigonometric Functions", 3, new BubbleInfo({success:"Correct!", failure:"False. Feel free to try again. Good luck!"}), "tri_e", "tri_e"));
    TriQuestions.push(new Question("tri_e", "Trigonometry", 1, DefaultBubble, "tri_f", "tri_f"));
    TriQuestions.push(new Question("tri_f", "Reverse Trigonometric Functions 1", 1, DefaultBubble, "tri_g", "tri_g"));
    TriQuestions.push(new Question("tri_g", "Reverse Trigonometric Functions 2", 1, DefaultBubble, "tri_main", "tri_main"));
    TriQuestions.push(new Question("tri_main", "Endboss ", 1, new BubbleInfo({camebackaftersuccess:"Welcome back to this task. The last tasks were about competencies that you can use to solve this task. Can you solve them now? Good luck!"}), "sur_instructions"/*"_finish"*/, "tri_instructions"));
    
    SurQuestions.push(new Instruction("sur_instructions", "Start Survey", "sur_a", "sur_a", DefaultBubble));
    SurQuestions.push(new Question("sur_a", "Umfrage", 1, new BubbleInfo({beforeskip:"Please press &quot;Check&quot; before proceeding so that your answers to the survey are saved. Or do you want to skip the survey?"}), "_finsih", "_finish", true, 6));
    
    
    let AllQuestions = SynQuestions.concat(FraQuestions, PQQuestions, RulQuestions/*, LogQuestions*/, TriQuestions, SurQuestions);
    
    for (let i = 0; i < AllQuestions.length; i++) {
        AllQuestions[i].page = i;
    }
    
    
    let QuestionGroups = [];
    QuestionGroups.push(new QuestionGroup("syn", "Syntax", SynQuestions));
    QuestionGroups.push(new QuestionGroup("fra", "Fractions &amp; Binom. Formulas", FraQuestions));
    QuestionGroups.push(new QuestionGroup("pq", "pq Formula", PQQuestions));
    QuestionGroups.push(new QuestionGroup("rul", "Power Laws", RulQuestions));
    //QuestionGroups.push(new QuestionGroup("log", "Zinsesinzs &amp; Logarithmus", LogQuestions));
    QuestionGroups.push(new QuestionGroup("tri", "Trigonometry", TriQuestions));
    QuestionGroups.push(new QuestionGroup("sur", "Survey", SurQuestions));
    
    let ALQuiz = new Quiz(QuestionGroups);
    
    let solvedQuestionsAsString = sessionStorage.getItem("solved");
    if (solvedQuestionsAsString != undefined) {
        let solvedQuestions = JSON.parse(solvedQuestionsAsString);
        if (solvedQuestions != undefined) {
            solvedQuestions.forEach(function (solvedQuestion) {
                let Question = ALQuiz.getQuestion(solvedQuestion);
                Question.solved = Question.needs;
            });
        }
    } else {
        let solved = [];
        sessionStorage.setItem("solved", JSON.stringify(solved));
    }
    
    let visitedQuestionsAsString = sessionStorage.getItem("visited");
    if (visitedQuestionsAsString != undefined) {
        let visitedQuestions = JSON.parse(visitedQuestionsAsString);
        if (visitedQuestions != undefined) {
            visitedQuestions.forEach(function (visitedQuestion) {
                let Question = ALQuiz.getQuestion(visitedQuestion);
                Question.visited = true;
            });
        }
    } else {
        let visited = [];
        sessionStorage.setItem("visited", JSON.stringify(visited));
    }
    
    document.addEventListener("DOMContentLoaded", function () {
    
        if (window.location.href.indexOf("review.php") < 0) {
    
               //add ask-before-skip modal
                let modal = document.createElement("div");
                modal.classList.add("dmmodal");
                modal.addEventListener("click", function(event) {
                    if(!event.target.closest(".dmmodal-content")) {
                        this.style.display = "none";
                    }
                });
                let modalContent = document.createElement("div");
                modalContent.classList.add("dmmodal-content", "formulation");
                let closeSpan = document.createElement("span");
                closeSpan.classList.add("dmclose");
                closeSpan.innerHTML = "&times;";
                closeSpan.onclick = function() { this.closest(".dmmodal").style.display="none"; };
                let contentParagraph = document.createElement("p");
                let modalBubble = document.createElement("p");
                modalBubble.classList.add("bubble", "in-modal");
                modalBubble.innerHTML = "Are you sure to skip this question? ";
                if(ALQuiz != undefined && ALQuiz.getQuestion() != undefined && ALQuiz.getQuestion().BubbleInfo != undefined && ALQuiz.getQuestion().BubbleInfo.getText("beforeskip") != undefined) {
                    modalBubble.innerHTML = ALQuiz.getQuestion().BubbleInfo.getText("beforeskip");
                }
                modalBubble.style.marginTop = "50px";
                let dmicon = document.createElement("img");
                dmicon.classList.add("dm-icon");
                dmicon.src="https://marvin.hs-bochum.de/~mneugebauer/dm-avatar-grin.svg";
                let yesButton = document.createElement("a");
                yesButton.classList.add("skip-yes");
                yesButton.href = "javascript:;";
                yesButton.innerHTML = "Yes";
                let noButton = document.createElement("a");
                noButton.classList.add("skip-no");
                noButton.href = "javascript:;";
                noButton.innerHTML = "No";
                noButton.onclick = function() { this.closest(".dmmodal").style.display="none"; };
    
                modalBubble.appendChild(yesButton);
                modalBubble.innerHTML += " ";
                modalBubble.appendChild(noButton);
    
                modalContent.appendChild(closeSpan);
                modalContent.appendChild(modalBubble);
                modalContent.appendChild(dmicon);
                modalContent.appendChild(contentParagraph);
                modal.appendChild(modalContent);
                document.body.appendChild(modal);
    
            //in development state: interrupt button update to give the main page time to recognize the inline scripts like increment solved and set current question id
            /*setTimeout('*/ALQuiz.updateSpeechBubbles(); ALQuiz.updateMoodleNavButtons(); ALQuiz.updateNavigation(); /*', 500)*/;
        }
    
    
        //add styles, e. g. speech bubble
        let style = document.createElement("style");
        style.type = "text/css";
        //.que .outcome background-color is #fcefdc;
        style.innerHTML = ".bubble { /* layout*/ position: relative; max-width: 30em; /* looks*/ background-color: #fcefdc; padding: 1.125em 1.5em; font-size: 1.25em; border-radius: 1rem; box-shadow:	0 0.125rem 0.5rem rgba(0, 0, 0, .3), 0 0.0625rem 0.125rem rgba(0, 0, 0, .2); } .bubble:not(.no-arrow)::before { /* layout*/ content: ''; position: absolute; width: 0; height: 0; top: 100%; left: 1.5em; /* offset should move with padding of parent*/ border: .75rem solid transparent; border-bottom: none; /* looks*/ border-top-color: #fcefdc; filter: drop-shadow(0 0.0625rem 0.0625rem rgba(0, 0, 0, .1)); } .formulation a { text-decoration:underline; } .mathsinput { position:fixed; display:flex; width:100vw; bottom:0px; z-index:1; } .mathsinput button { flex-grow:1; } table.trigonometry_table { border:1px solid black;width:100%; } table.trigonometry_table th, td { border:1px solid black;text-align:center; } .dm-icon { border:2px solid black; border-radius:50%; width: 7.5em; } .user-focus { background-color: #000; width: 100%; height: 100%; position: absolute; opacity: 0.5; overflow: none; display: block; left: 0; } .user-focus.hide-top { top:0; } .user-focus.hide-bottom { bottom:0; } .dmmodal { display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ padding-top: 100px; /* Location of the box */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0,0,0); /* Fallback color */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ } /* Modal Content */ .dmmodal-content { background-color: #fefefe; margin: auto; padding: 20px; border: 1px solid #888; width: 80%; } /* The Close Button */ .dmclose { color: #aaaaaa; float: right; font-size: 28px; font-weight: bold; } .close:hover, .close:focus { color: #000; text-decoration: none; cursor: pointer; } .mathsinput { position:fixed; display:flex; width:100vw; bottom:0px; z-index:1; } .mathsinput button { flex-grow:1; } .show-on-mobile-only { display:inline-block; } .show-on-desktop-only { display:none; } @media (min-width:991px) { .mathsinput { display:none; } .show-on-mobile-only { display:none; } .show-on-desktop-only { display:inline-block; } } .mathsbutton { border:1px solid black; border-radius:50%; height:2em; width:2em; float:right; background-color:#aaaaaa; background-image:url(\"https://marvin.hs-bochum.de/~mneugebauer/operators-white.svg\"); background-repeat:no-repeat; background-size:90%; background-position:50%; } .mathsbutton.active { background-color:#e2001a; }";
        document.getElementsByTagName('head')[0].appendChild(style);
    
        /*let butt = document.createElement("input");
        butt.value = "Try another question like this";
        butt.classList.add("btn");
        butt.classList.add("btn-secondary");
        butt.type = "submit";
        butt.name = "redoslot" + ALQuiz.getQuestion().page;
        document.getElementById("responseform").appendChild(butt);*/
    
        //show additional maths input if neccessary
        document.querySelectorAll("input, textarea").forEach(function(inputElement) {
            inputElement.addEventListener("focus", function() {
                lastFocusedInputElement = this;
            });
        });
    
        let mathsInput = ["+", "-", "*", "/", "(", ")", "^", "="];
        let mathsButtons = [];
        mathsInput.forEach(function(mathsInputSymbol) {
            let button = document.createElement("button");
            button.type = "button";
            button.innerHTML = mathsInputSymbol;
            button.onclick = function() {
                if (!lastFocusedInputElement) {
                    console.log("no focused element to enter maths-symbol");
                    return;
                }
                let caretPos = lastFocusedInputElement.selectionStart;
                let currentContent = lastFocusedInputElement.value;
                lastFocusedInputElement.value = currentContent.substring(0, caretPos) + mathsInputSymbol + currentContent.substring(caretPos);
                lastFocusedInputElement.focus();
                lastFocusedInputElement.setSelectionRange(caretPos + 1, caretPos + 1);
            };
            mathsButtons.push(button);
        });
    
        let mathsInputButtonDiv = document.createElement("div");
        mathsInputButtonDiv.classList.add("mathsinput");
    
        mathsButtons.forEach(function(mathsButton) {
            mathsInputButtonDiv.appendChild(mathsButton);
        });
    
        document.body.appendChild(mathsInputButtonDiv);
    
        //safari hack to show mathsinput at correct position
        addSafariMathsInputAboveKeyboardSupport();
    
    
        addMathsOperatorButton();
    });
    
    document.addEventListener("load", function () {
        //ALQuiz.updateSpeechBubbles();
    });
    
    function tutorialFocusElement(elem) {
        if(!elem) {
            console.log("element to focus not found");
            return;
        }
    
        let userFocusTop = document.createElement("div");
        userFocusTop.classList.add("user-focus", "hide-top");
        userFocusTop.onclick = removeTutorialFocus;
        let userFocusBottom = document.createElement("div");
        userFocusBottom.classList.add("user-focus", "hide-bottom");
        userFocusBottom.onclick = removeTutorialFocus;
        
        let position = elem.getBoundingClientRect(elem);
        userFocusTop.style.height=Math.ceil(position.top+window.pageYOffset-20)+"px";
    
        let pageHeight = document.documentElement.scrollHeight;
        userFocusBottom.style.top = Math.ceil(position.bottom+window.pageYOffset+20)+"px";
        userFocusBottom.style.height=Math.ceil(pageHeight-(position.bottom+window.pageYOffset+20))+"px";
    
        document.body.appendChild(userFocusTop);
        document.body.appendChild(userFocusBottom);
    
        if(supportsSmoothScrolling() == true) {
            elem.scrollIntoView({behavior:"smooth", block:"center", inline:"center"});
        }
        else {
            safariScrollTo(elem);
        }
    }
    
    function removeTutorialFocus() {
        document.querySelectorAll(".user-focus").forEach(function(userFocusElement) {
            userFocusElement.parentNode.removeChild(userFocusElement);
        });
    }
    
    function repeatQuestion() {
        document.querySelector('.mod_quiz-redo_question_button').click();
    }
    
    function showAskBeforeSkipModal() {
        document.querySelector(".dmmodal").style.display = "block";
    }
    
    /*function addMathsOperatorButton() {
        document.querySelectorAll(".formulation.clearfix input[type=text], textarea").forEach(function(inputElement) { let mathsButton = document.createElement("img"); mathsButton.src = "https://marvin.hs-bochum.de/~mneugebauer/operators.svg";
        mathsButton.addEventListener("click", function(event) {
        event.preventDefault();
        //document.querySelector(".mathsinput").classList.toggle("hide");
        let mathsInput = document.querySelector(".mathsinput");
        if(mathsInput.style.display == "none") {
            mathsInput.style.display = "flex";
        }
        else {
            mathsInput.style.display = "none";
        }
        });
        inputElement.parentNode.appendChild(mathsButton); });
    }*/
    
    function addMathsOperatorButton() {
        document.querySelectorAll(".formulation.clearfix").forEach(function(questionElement) {
            let mathsButtonDiv = document.createElement("div");
            mathsButtonDiv.classList.add("mathsbutton");
    
            let mathsInput = document.querySelector(".mathsinput");
            let display = window.getComputedStyle(mathsInput).display;
            if(display == "flex") {
                mathsButtonDiv.classList.add("active");
            }
    
            mathsButtonDiv.addEventListener("click", function() {
                //document.querySelector(".mathsinput").classList.toggle("hide");
                //let mathsInput = document.querySelector(".mathsinput");
                if(!mathsInput.style.display || mathsInput.style.display == "") {
                    display = window.getComputedStyle(mathsInput).display;
                }
                else {
                    display = mathsInput.style.display;
                }
    
                if(display == "none") {
                    mathsInput.style.display = "flex";
                    this.classList.add("active");
                }
                else {
                    mathsInput.style.display = "none";
                    this.classList.remove("active");
                }
            });
            //mathsButtonDiv.appendChild(mathsButton);
            questionElement.appendChild(mathsButtonDiv);
        });
    }
    
    
    //SAFARI HACKS BELOW
    function addSafariMathsInputAboveKeyboardSupport() {
        //alert("checking for safari");
        let isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
        if(isSafari == true) {
    
            //alert("You are using Safari");
    
            //sadly not working solution from stackoverflow
            //style.innerHTML = ".testclass, .mathsinput { display:none; bottom:270px; } @media screen and (min-aspect-ratio:11/16) { .testclass, .mathsinput { display:none; } }";
            document.querySelectorAll("input.algebraic").forEach(function(inputElement) {
                //console.log(inputElement);
                inputElement.onfocus = function() {
                    let mathsInput = document.querySelector(".mathsinput");
                    mathsInput.style.position = "absolute";
                    mathsInput.style.bottom = "auto";
                    let position = this.getBoundingClientRect();
                    mathsInput.style.top = Math.ceil(position.bottom+window.pageYOffset)+"px";
                    //console.log(position);
                }
            });
        }
    }
    
    function supportsSmoothScrolling() {
        let body = document.body;
        let scrollSave = body.style.scrollBehavior;
        body.style.scrollBehavior = 'smooth';
        let hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
        body.style.scrollBehavior = scrollSave;
        return hasSmooth;
    };
    
    //thanks to Jeff Starr from https://perishablepress.com/vanilla-javascript-scroll-anchor/
    function safariScrollTo(elem){
    
        if(elem == undefined) {
            return;
        }
        let position = elem.getBoundingClientRect();
        let to = (position.top+window.pageYOffset)-window.screen.availHeight/2;
        //console.log(to);
    
        var i = parseInt(window.pageYOffset);
        //console.log(i);
        if ( i != to ) {
            to = parseInt(to);
            if (i < to) {
                var int = setInterval(function() {
                    if (i > (to-20)) i += 1;
                    else if (i > (to-40)) i += 3;
                    else if (i > (to-80)) i += 8;
                    else if (i > (to-160)) i += 18;
                    else if (i > (to-200)) i += 24;
                    else if (i > (to-300)) i += 40;
                    else i += 60;
                    window.scroll(0, i);
                    if (i >= to) clearInterval(int);
                }, 15);
            }
            else {
                var int = setInterval(function() {
                    if (i < (to+20)) i -= 1;
                    else if (i < (to+40)) i -= 3;
                    else if (i < (to+80)) i -= 8;
                    else if (i < (to+160)) i -= 18;
                    else if (i < (to+200)) i -= 24;
                    else if (i < (to+300)) i -= 40;
                    else i -= 60;
                    window.scroll(0, i);
                    if (i <= to) clearInterval(int);
                }, 15);
            }
        }
    };
    
    ///END AL QUIZ SCRIPT///