Responsive Quiz Game built with HTML5 , CSS3 and Javascript.
Last active
August 10, 2021 19:33
-
-
Save batazo/eb12d03b0978e9d00aa3edf933c6e4da to your computer and use it in GitHub Desktop.
Webdeveloper Quiz v14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <div id="container"> | |
| <header> | |
| <h1>Webdeveloper Quiz</h1><span id="verSpan"></span> | |
| </header> | |
| <div id="result" class="hidden"></div> | |
| <div id="questionDIV"> | |
| <div class="load"> | |
| <img src=" | |
| https://c.tenor.com/I6kN-6X7nhAAAAAj/loading-buffering.gif" /> | |
| </div> | |
| </div><!-- questionDIV end --> | |
| <div id="actions"> | |
| <button id="evaluate" onclick="runEvaluation()">KIÉRTÉKEL</button> | |
| </div> | |
| </div><!-- Conmtainer end--> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //Globals | |
| const version = "v14"; | |
| let answerareas; | |
| let questionlimit = 10; | |
| let qinputs; | |
| //Inits | |
| renerAllQuestions(); | |
| verSpan.innerHTML = `(${version})`; | |
| //Renders | |
| //Evaluation renders | |
| async function renderEvaluation(answerareasN) { | |
| answerareasN.nextElementSibling.innerHTML = ""; | |
| let renderString = await evaluationTemplate( | |
| await evaluationTempleteVars(answerareasN) | |
| ); | |
| answerareasN.nextElementSibling.innerHTML += renderString; | |
| answerareasN.nextElementSibling.classList.remove("hidden"); | |
| } | |
| async function renderAllEvaluation() { | |
| for (let answerarea of answerareas) { | |
| await renderEvaluation(answerarea); | |
| } | |
| } | |
| //Score renders | |
| async function renderScore() { | |
| let renderString = await scoreTemplate(await scoreTemplateVars()); | |
| result.innerHTML = await renderString; | |
| } | |
| //Question renders | |
| async function renerAllQuestions() { | |
| questionDIV.innerHTML = ""; | |
| let renderString = ""; | |
| let questions = await getQuestionList(); | |
| if (!questions) { | |
| renderString += `<p>SERVER ERROR <button onclick="renerAllQuestions()">REFRESH</button></p>`; | |
| questionDIV.innerHTML += renderString; | |
| } else { | |
| for (let question of questions) { | |
| renderString = await questionTemplate(await questionTemplateVars(question)); | |
| questionDIV.innerHTML += await renderString; | |
| } | |
| } | |
| refreshSelectors(); | |
| } | |
| //Templates amd TemplateVars | |
| //Questions Templs | |
| async function questionTemplateVars(injectedVars) { | |
| return { | |
| questionId: injectedVars.id, | |
| questionNumber: injectedVars.qnumber, | |
| question: injectedVars.question, | |
| answerAreaHTML: allAnswerBoxTemplate( | |
| allAnswerBoxTemplateVars(injectedVars.answers, injectedVars.qnumber) | |
| ), | |
| default: "OK" | |
| }; | |
| } | |
| async function questionTemplate(templateVars) { | |
| return ` | |
| <div id="question-${templateVars.questionNumber}" class="questioninput"> | |
| <h3 id="Q${templateVars.questionNumber}"> ${templateVars.questionNumber}. Kérdés: ${templateVars.question}</h3> | |
| <div class="answerarea" id="answerarea-${templateVars.questionNumber}" data-qid="${templateVars.questionId}"> | |
| ${templateVars.answerAreaHTML} | |
| </div><!-- end of answerarea --> | |
| <div id="explanOf${templateVars.questionNumber}_${templateVars.questionId}" class="explanation hidden"></div> | |
| <hr> | |
| </div><!-- questioninput end -->`; | |
| } | |
| //Answers Templs | |
| function allAnswerBoxTemplateVars(injectedVarsAnswers, injectedVarsQNumber) { | |
| let allansverboxHTML = ""; | |
| for (let injectedVarsAnswer of injectedVarsAnswers) { | |
| allansverboxHTML += answerboxTemplate( | |
| answerboxTemplateVars(injectedVarsAnswer, injectedVarsQNumber) | |
| ); | |
| } | |
| return { | |
| answerboxes: allansverboxHTML | |
| }; | |
| } | |
| function allAnswerBoxTemplate(templateVars) { | |
| return ` | |
| ${templateVars.answerboxes} | |
| `; | |
| } | |
| function answerboxTemplateVars(injectedVarsAnswer, injectedVarsQNumber) { | |
| return { | |
| questionNumber: injectedVarsQNumber, | |
| answerNumber: injectedVarsAnswer.anumber, | |
| answerId: injectedVarsAnswer.id, | |
| answerString: injectedVarsAnswer.answer | |
| }; | |
| } | |
| function answerboxTemplate(templateVars) { | |
| return ` | |
| <input type="radio" name="Q${templateVars.questionNumber}" id="Q${templateVars.questionNumber}A${templateVars.answerNumber}" data-aid="${templateVars.answerId}" /> | |
| <label for="Q${templateVars.questionNumber}A${templateVars.answerNumber}">${templateVars.answerString}</label>`; | |
| } | |
| //Evalution Templs | |
| async function evaluationTempleteVars(answerareasN) { | |
| let data = await checkAnswerByAnswerarea(answerareasN); | |
| let explan = | |
| data.explanation == undefined ? "Nem jelöltél ki választ" : data.explanation; | |
| let correct = data.correct | |
| ? "A válaszod helyes!" | |
| : "A válaszod sajnos helytelen!"; | |
| let correctColor = data.correct ? "green" : "red"; | |
| let success = data.correct ? true : false; | |
| let whatCorrects = data.correctAnswers == undefined ? "" : data.correctAnswers; | |
| let whatCorrectString = whatCorrects ? getGoodAnswersStringFromData(data) : ""; | |
| return { | |
| explan: explan, | |
| correct: correct, | |
| success: success, | |
| correctColor: correctColor, | |
| whatCorrectString: whatCorrectString | |
| }; | |
| } | |
| function evaluationTemplate(templateVar) { | |
| return ` | |
| <p data-chksuccess="${templateVar.success}"><b style="color: ${templateVar.correctColor}">${templateVar.correct}</b> | |
| ${templateVar.whatCorrectString} | |
| </p> | |
| <p>${templateVar.explan}</p> | |
| `; | |
| } | |
| //Score Templs | |
| async function scoreTemplateVars(injectedvars) { | |
| let goodAnswers = document.querySelectorAll( | |
| `.explanation p[data-chksuccess="true"] ` | |
| ).length; | |
| return { | |
| score: goodAnswers, | |
| scorePercent: goodAnswers / (questionlimit / 100) | |
| }; | |
| } | |
| async function scoreTemplate(templateVars) { | |
| return `A pontjaid száma: ${templateVars.score} (${templateVars.scorePercent} %)`; | |
| } | |
| //Controllers | |
| async function getQuestionList() { | |
| try { | |
| const questions = await getQuestion(); | |
| let questionNumber = 1; | |
| let answerNumber = 0; | |
| for (let question of questions) { | |
| question.qnumber = questionNumber++; | |
| for (let answer of question.answers) { | |
| answer.anumber = answerNumber++; | |
| } | |
| } | |
| return questions; | |
| } catch (e) { | |
| console.log(e); | |
| return false; | |
| } | |
| } | |
| function getAnswerareaDatasetQid(answerareasN) { | |
| return answerareasN.dataset.qid; | |
| } | |
| function getAnswerareaSelectedDatasetAids(answerareasN) { | |
| let checkedAnswers = document.querySelectorAll( | |
| `#${answerareasN.id} input:checked` | |
| ); | |
| let selected = []; | |
| for (let checkedAnswer of checkedAnswers) { | |
| selected.push(checkedAnswer.dataset.aid); | |
| } | |
| return selected; | |
| } | |
| function getAnswerareaAllDatasetAids(answerareasN) { | |
| let answersInArea = document.querySelectorAll(`#${answerareasN.id} input`); | |
| let answerareaAids = []; | |
| for (let answerInArea of answersInArea) { | |
| answerareaAids.push(answerInArea.dataset.aid); | |
| } | |
| return answerareaAids; | |
| } | |
| function getGoodAnswersFromData(fromdata) { | |
| let goodAnswers = []; | |
| for (let data of fromdata.correctAnswers) { | |
| goodAnswers.push(data.id); | |
| } | |
| return goodAnswers; | |
| } | |
| function getGoodAnswersStringFromData(fromdata) { | |
| let goodAnswers = "A helyes válasz(ok): "; | |
| for (let data of fromdata.correctAnswers) { | |
| goodAnswers += data.answer; | |
| } | |
| return goodAnswers; | |
| } | |
| async function checkAnswerByAnswerarea(answerareasN) { | |
| let qid = getAnswerareaDatasetQid(answerareasN); | |
| let aids = getAnswerareaSelectedDatasetAids(answerareasN); | |
| return await checkAnswer(qid, aids); | |
| } | |
| //Data Queries | |
| async function getQuestion() { | |
| const endpoint = | |
| "https://webdevquiz.mysqhost.ml:8090/api/questionlist/" + questionlimit; | |
| const response = await fetch(endpoint); | |
| const data = await response.json(); | |
| return data; | |
| } | |
| async function checkAnswer(qid, aids) { | |
| const endpoint = "https://webdevquiz.mysqhost.ml:8090/api/check/"; | |
| const bodyData = { | |
| questionId: qid, | |
| selectedAnswerIds: aids | |
| }; | |
| const options = { | |
| method: "POST", | |
| mode: "cors", | |
| headers: { | |
| "Content-Type": "application/json" | |
| }, | |
| body: JSON.stringify(bodyData) | |
| }; | |
| const response = await fetch(endpoint, options); | |
| const data = await response.json(); | |
| return data; | |
| } | |
| //Helpers | |
| function refreshSelectors() { | |
| answerareas = document.querySelectorAll("[data-qid]"); | |
| qinputs = document.querySelectorAll(".questioninput"); | |
| } | |
| //Evnent handlers | |
| async function runEvaluation() { | |
| result.innerHTML = "Scores loading...."; | |
| result.classList.remove("hidden"); | |
| window.scrollTo(0, 0); | |
| await renderAllEvaluation(); | |
| renderScore(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap'); | |
| * { box-sizing: border-box; | |
| } | |
| body { | |
| background-image: url("https://i.imgur.com/qzpVNy0.jpg"); | |
| font-family: 'Roboto', sans-serif; | |
| margin: 40px; | |
| display: flex; | |
| flex-wrap: wrap; | |
| } | |
| #container { | |
| background-color:#2992bf; | |
| border-radius: 10px; | |
| display: block; | |
| flex-wrap: wrap; | |
| box-shadow: 3px 5px 7px 3px #8395a7; | |
| align-items: center; | |
| justify-content: center; | |
| color: #fff; | |
| padding: 15px; | |
| } | |
| header { | |
| border-bottom:1px dotted white; | |
| text-align:center; | |
| } | |
| header h1 { margin:0; padding:0;} | |
| .hidden { | |
| display: none; | |
| } | |
| .explanation { | |
| color: gray; | |
| padding: 10px; | |
| border: 1px solid gray; | |
| background-color: lightgray; | |
| } | |
| #result { | |
| margin: 10px;padding: 10px;background-color: lightgray;border: 3px solid blue;color: darkblue; | |
| } | |
| .success { | |
| color: lightgreen; | |
| } | |
| .unsuccessful { | |
| color: red; | |
| } | |
| #container, | |
| form { min-width:100%;} | |
| .questioninput { margin-bottom:30px;} | |
| .load { | |
| text-align: center; padding-top:60px;padding-bottom:60px; | |
| } | |
| .questioninput input{ | |
| display: none; | |
| padding: 15px; | |
| } | |
| .questioninput label{ | |
| color: black; | |
| padding: 15px; | |
| margin: 15px; | |
| width: 300px; | |
| display:inline-block; | |
| text-align: center; | |
| border-radius: 10px; | |
| background-color: lightgray; | |
| box-shadow: 3px 3px 9px 3px #075c77; | |
| font-size: larger; | |
| } | |
| .questioninput label:hover{ | |
| background-color: gray; | |
| } | |
| .questioninput input[type="radio"]:checked + label { | |
| border: 2px solid blue; | |
| background-color: gray; | |
| } | |
| .questioninput hr{ | |
| height: 10px; | |
| border: 0; | |
| box-shadow: 0 10px 10px -10px #1f246c8a inset; | |
| } | |
| #actions { | |
| text-align: center; | |
| } | |
| #actions button { | |
| text-align: center; | |
| padding: 20px; | |
| border-radius: 15px; | |
| color: white; | |
| background-color: #2d8ae7; | |
| } | |
| .answerarea{ | |
| text-align: center; | |
| } | |
| @media screen and (max-width: 795px){ | |
| .questioninput label{ | |
| width: 90%; | |
| } | |
| body{ | |
| margin: 0px; | |
| } | |
| } | |
| @media screen and (max-width: 600px) { | |
| form { | |
| margin:initial; | |
| text-align:initial; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment