diff --git a/index.html b/index.html index 534cd886..218e4005 100644 --- a/index.html +++ b/index.html @@ -9,6 +9,7 @@

JavaScript Quiz

+
00:00
@@ -28,7 +29,7 @@

JavaScript Quiz

- + - - - \ No newline at end of file + diff --git a/src/index.js b/src/index.js index 03737ba3..e4bcc116 100644 --- a/src/index.js +++ b/src/index.js @@ -14,39 +14,53 @@ document.addEventListener("DOMContentLoaded", () => { // End view elements const resultContainer = document.querySelector("#result"); - /************ SET VISIBILITY OF VIEWS ************/ // Show the quiz view (div#quizView) and hide the end view (div#endView) quizView.style.display = "block"; endView.style.display = "none"; - /************ QUIZ DATA ************/ - + // Array with the quiz questions const questions = [ new Question("What is 2 + 2?", ["3", "4", "5", "6"], "4", 1), - new Question("What is the capital of France?", ["Miami", "Paris", "Oslo", "Rome"], "Paris", 1), - new Question("Who created JavaScript?", ["Plato", "Brendan Eich", "Lea Verou", "Bill Gates"], "Brendan Eich", 2), - new Question("What is the mass–energy equivalence equation?", ["E = mc^2", "E = m*c^2", "E = m*c^3", "E = m*c"], "E = mc^2", 3), + new Question( + "What is the capital of France?", + ["Miami", "Paris", "Oslo", "Rome"], + "Paris", + 1 + ), + new Question( + "Who created JavaScript?", + ["Plato", "Brendan Eich", "Lea Verou", "Bill Gates"], + "Brendan Eich", + 2 + ), + new Question( + "What is the mass–energy equivalence equation?", + ["E = mc^2", "E = m*c^2", "E = m*c^3", "E = m*c"], + "E = mc^2", + 3 + ), // Add more questions here ]; const quizDuration = 120; // 120 seconds (2 minutes) - /************ QUIZ INSTANCE ************/ - + // Create a new Quiz instance object const quiz = new Quiz(questions, quizDuration, quizDuration); // Shuffle the quiz questions quiz.shuffleQuestions(); - - /************ SHOW INITIAL CONTENT ************/ // Convert the time remaining in seconds to minutes and seconds, and pad the numbers with zeros if needed - const minutes = Math.floor(quiz.timeRemaining / 60).toString().padStart(2, "0"); + //const timeRemainingContainer = document.getElementById("timeRemaining"); + //! for exemple 2.3 => 2 => "2" => "02" + const minutes = Math.floor(quiz.timeRemaining / 60) + .toString() + .padStart(2, "0"); const seconds = (quiz.timeRemaining % 60).toString().padStart(2, "0"); // Display the time remaining in the time remaining container @@ -55,27 +69,35 @@ document.addEventListener("DOMContentLoaded", () => { // Show first question showQuestion(); - + // Show Timer for the first time /************ TIMER ************/ + const timer = document.getElementById("timer"); + + showTimer(); - let timer; + function showTimer() { + //! for exemple 2.3 => 2 => "2" => "02" + const minutes = Math.floor(quiz.timeRemaining / 60) + .toString() + .padStart(2, "0"); + const seconds = (quiz.timeRemaining % 60).toString().padStart(2, "0"); + // Display the time remaining in the time remaining container + const timer = document.getElementById("timer"); + timer.innerText = `${minutes}:${seconds}`; + } /************ EVENT LISTENERS ************/ nextButton.addEventListener("click", nextButtonHandler); - - /************ FUNCTIONS ************/ // showQuestion() - Displays the current question and its choices // nextButtonHandler() - Handles the click on the next button // showResults() - Displays the end view and the quiz results - - function showQuestion() { // If the quiz has ended, show the results if (quiz.hasEnded()) { @@ -91,84 +113,157 @@ document.addEventListener("DOMContentLoaded", () => { const question = quiz.getQuestion(); // Shuffle the choices of the current question by calling the method 'shuffleChoices()' on the question object question.shuffleChoices(); - - // YOUR CODE HERE: // // 1. Show the question // Update the inner text of the question container element and show the question text - - + questionContainer.innerText = question.text; // 2. Update the green progress bar // Update the green progress bar (div#progressBar) width so that it shows the percentage of questions answered - - progressBar.style.width = `65%`; // This value is hardcoded as a placeholder - + // console.log(quiz.questions.indexOf(question), quiz.questions); + //! ((index + 1) / question.length) * 100 + let currentPercentage = + ((quiz.questions.indexOf(question) + 1) / quiz.questions.length) * 100; + progressBar.style.width = `${currentPercentage}%`; // This value is hardcoded as a placeholder - - // 3. Update the question count text + // 3. Update the question count text // Update the question count (div#questionCount) show the current question out of total questions - - questionCount.innerText = `Question 1 of 10`; // This value is hardcoded as a placeholder + questionCount.innerText = `Question ${ + quiz.questions.indexOf(question) + 1 + } of ${quiz.questions.length}`; // This value is hardcoded as a placeholder - // 4. Create and display new radio input element with a label for each choice. // Loop through the current question `choices`. - // For each choice create a new radio input with a label, and append it to the choice container. - // Each choice should be displayed as a radio input element with a label: - /* + // For each choice create a new radio input with a label, and append it to the choice container. + // Each choice should be displayed as a radio input element with a label: + /*
*/ - // Hint 1: You can use the `document.createElement()` method to create a new element. - // Hint 2: You can use the `element.type`, `element.name`, and `element.value` properties to set the type, name, and value of an element. - // Hint 3: You can use the `element.appendChild()` method to append an element to the choices container. - // Hint 4: You can use the `element.innerText` property to set the inner text of an element. - + question.choices.forEach((choice) => { + // choiceContainer.innerHTML += ` + // + //
`; + const inputRadio = document.createElement("input"); + inputRadio.type = "radio"; + inputRadio.name = "choice"; + inputRadio.value = choice; + const labelRadio = document.createElement("label"); + labelRadio.innerText = choice; + choiceContainer.appendChild(inputRadio); + choiceContainer.appendChild(labelRadio); + choiceContainer.appendChild(document.createElement("br")); + }); + // Hint 1: You can use the `document.createElement()` method to create a new element. + // Hint 2: You can use the `element.type`, `element.name`, and `element.value` properties to set the type, name, and value of an element. + // Hint 3: You can use the `element.appendChild()` method to append an element to the choices container. + // Hint 4: You can use the `element.innerText` property to set the inner text of an element. } - - - function nextButtonHandler () { + function nextButtonHandler() { let selectedAnswer; // A variable to store the selected answer value - - // YOUR CODE HERE: // // 1. Get all the choice elements. You can use the `document.querySelectorAll()` method. - - + const allChoicesElement = document.querySelectorAll("input"); // 2. Loop through all the choice elements and check which one is selected - // Hint: Radio input elements have a property `.checked` (e.g., `element.checked`). - // When a radio input gets selected the `.checked` property will be set to true. - // You can use check which choice was selected by checking if the `.checked` property is true. - - + // Hint: Radio input elements have a property `.checked` (e.g., `element.checked`). + // When a radio input gets selected the `.checked` property will be set to true. + // You can use check which choice was selected by checking if the `.checked` property is true. + // console.log(allChoicesElement); + allChoicesElement.forEach((choice) => { + if (choice.checked === true) { + selectedAnswer = choice.value; + } + }); + // console.log(selectedAnswer); // 3. If an answer is selected (`selectedAnswer`), check if it is correct and move to the next question - // Check if selected answer is correct by calling the quiz method `checkAnswer()` with the selected answer. - // Move to the next question by calling the quiz method `moveToNextQuestion()`. - // Show the next question by calling the function `showQuestion()`. - } - - - - + // Check if selected answer is correct by calling the quiz method `checkAnswer()` with the selected answer. + // Move to the next question by calling the quiz method `moveToNextQuestion()`. + // Show the next question by calling the function `showQuestion()`. + if (selectedAnswer !== undefined) { + quiz.checkAnswer(selectedAnswer); + quiz.moveToNextQuestion(); + showQuestion(); + } + } + // nextButtonHandler(); function showResults() { - // YOUR CODE HERE: - // + // ! Stop The Timer interval + clearInterval(timerInterval); // 1. Hide the quiz view (div#quizView) quizView.style.display = "none"; // 2. Show the end view (div#endView) endView.style.display = "flex"; - + // 3. Update the result container (div#result) inner text to show the number of correct answers out of total questions - resultContainer.innerText = `You scored 1 out of 1 correct answers!`; // This value is hardcoded as a placeholder + resultContainer.innerText = `You scored ${quiz.correctAnswers} out of ${quiz.questions.length} correct answers!`; // This value is hardcoded as a placeholder + } + + // ! add listener + + nextButton.addEventListener("click", nextButtonHandler()); + + const restartButton = document.querySelector("#restartButton"); + + //! restart button + restartButton.addEventListener("click", () => { + //!Hide the endview + endView.style.display = "none"; + + //! show the quizView + quizView.style.display = "flex"; + + //!restart the current Question + quiz.currentQuestionIndex = 0; + + //! restart The result + quiz.correctAnswers = 0; + + //! restart Timer with quizDuration + quiz.timeRemaining = quiz.timeLimit; + + //! shuffle all question + quiz.shuffleQuestions(); + + //! Show the Question + showQuestion(); + + //! Show the Timer Start + showTimer(); + + //! Set The timer Intervalle + startTimer(); + }); + // ! let timer; + + // Interval TIMER start + startTimer(); + + // function start timer interval + function startTimer() { + timerInterval = setInterval(() => { + quiz.timeRemaining--; + showTimer(); + if (quiz.timeRemaining === 60) { + timer.style.backgroundColor = "orange"; + } + if (quiz.timeRemaining === 10) { + timer.style.backgroundColor = "red"; + } + if (quiz.timeRemaining === 0) { + clearInterval(timerInterval); + showResults(); + } + }, 1000); } - -}); \ No newline at end of file + + //!DONT WRITE AFTER THIS +}); +//! THIS IS THE END diff --git a/src/question.js b/src/question.js index 68f6631a..5e10c736 100644 --- a/src/question.js +++ b/src/question.js @@ -1,7 +1,30 @@ class Question { - // YOUR CODE HERE: - // - // 1. constructor (text, choices, answer, difficulty) + // YOUR CODE HERE: + // + // 1. constructor (text, choices, answer, difficulty) + constructor(text, choices, answer, difficulty) { + this.text = text; + this.choices = choices; + this.answer = answer; + this.difficulty = difficulty; + } + // 2. shuffleChoices() + // ['1', '2' ,'4'] - // 2. shuffleChoices() -} \ No newline at end of file + //['3',] + shuffleChoices() { + let shuffleChoices = []; + + for (let i = 0; i < this.choices.length; i++) { + let index = Math.round(Math.random() * (this.choices.length - 1)); + + while (shuffleChoices.includes(this.choices[index])) { + index = Math.round(Math.random() * (this.choices.length - 1)); + } + + shuffleChoices.push(this.choices[index]); + // console.log(this.choices, shuffleChoices); + } + this.choices = shuffleChoices; + } +} diff --git a/src/quiz.js b/src/quiz.js index d94cfd14..25bd6bad 100644 --- a/src/quiz.js +++ b/src/quiz.js @@ -1,15 +1,79 @@ class Quiz { - // YOUR CODE HERE: - // - // 1. constructor (questions, timeLimit, timeRemaining) + // YOUR CODE HERE: + // + // 1. constructor (questions, timeLimit, timeRemaining) + constructor(questions, timeLimit, timeRemaining) { + this.questions = questions; + this.timeLimit = timeLimit; + this.timeRemaining = timeRemaining; - // 2. getQuestion() - - // 3. moveToNextQuestion() + this.correctAnswers = 0; + this.currentQuestionIndex = 0; + } - // 4. shuffleQuestions() + // 2. getQuestion() + getQuestion() { + return this.questions[this.currentQuestionIndex]; + } + // 3. moveToNextQuestion() + moveToNextQuestion() { + this.currentQuestionIndex++; + } + // 4. shuffleQuestions() + shuffleQuestions() { + // this.questions.forEach((question) => { + // //! question is instance of Question (class) so i can use the method of this class. here i use the metho shuffleChoices inside this object. + // question.shuffleChoices(); + // }); + let shuffleQuestions = []; + for (let i = 0; i < this.questions.length; i++) { + let index = Math.round(Math.random() * (this.questions.length - 1)); - // 5. checkAnswer(answer) + while (shuffleQuestions.includes(this.questions[index])) { + index = Math.round(Math.random() * (this.questions.length - 1)); + } - // 6. hasEnded() -} \ No newline at end of file + shuffleQuestions.push(this.questions[index]); + // console.log(this.choices, shuffleChoices); + } + this.questions = shuffleQuestions; + } + + // 5. checkAnswer(answer) + checkAnswer(answer) { + //!this.question = array of all questions + //! this.currenQuestionIndex = the index of the current question + //! this.questions[this.currentQuestionIndex] = the current Object question + //! because this.questions[this.currentQuestionIndex] its a object i can select all this property with .property : here .answer + //! this.questions[this.currentQuestionIndex].answer = the current correct answer + if (answer === this.questions[this.currentQuestionIndex].answer) { + this.correctAnswers++; + } + } + + // 6. hasEnded() + hasEnded() { + //! this return all the time false except when currentQuestionIndex is equal to the questions array length + return this.currentQuestionIndex === this.questions.length; + } + //7. filterQuestionByDifficulty + filterQuestionsByDifficulty(difficulty) { + //! this.questions type = Array //// this.questions = [{text: text1, choices: [], }, {text: text2, choices = [], answer: }] + //! question type = object + + if (difficulty >= 1 && difficulty <= 3) { + this.questions = this.questions.filter( + (question) => question.difficulty === difficulty + ); + return this.questions; + } + } + //8. Average difficulty + averageDifficulty() { + const totalDifficulty = this.questions.reduce( + (sum, question) => sum + question.difficulty, + 0 + ); + return totalDifficulty / this.questions.length; + } +} diff --git a/styles/style.css b/styles/style.css index 8de97e38..564811aa 100644 --- a/styles/style.css +++ b/styles/style.css @@ -1,172 +1,189 @@ /* CSS Reset */ * { - margin: 0; - padding: 0; - box-sizing: border-box; + margin: 0; + padding: 0; + box-sizing: border-box; } body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - background-color: #f4f4f4; - color: #333; - line-height: 1.6; - padding: 20px; + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + background-color: #f4f4f4; + color: #333; + line-height: 1.6; + padding: 20px; } header { - padding: 0 20px; + padding: 0 20px; + display: flex; + justify-content: space-between; + align-items: center; + +} +#timer{ + background-color: #46a049; + color: white; + width: 6rem; + height: 3rem; + border-radius: 5px; + text-align: center; + line-height: 3rem; + } - .container { - height: 540px; - max-width: 600px; - margin: auto; - padding: 20px; - background: #fff; - box-shadow: 0 5px 15px rgba(0,0,0,0.1); + height: 540px; + max-width: 600px; + margin: auto; + padding: 20px; + background: #fff; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); } -#quizView, #endView { - overflow-y: auto; - padding: 20px; - box-sizing: border-box; - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; +#quizView, +#endView { + overflow-y: auto; + padding: 20px; + box-sizing: border-box; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; } .view { - text-align: center; - margin-top: 20px; + text-align: center; + margin-top: 20px; } button { - color: white; - border: none; - border-radius: 5px; - padding: 10px 20px; - cursor: pointer; - font-size: 16px; - width: 160px; + color: white; + border: none; + border-radius: 5px; + padding: 10px 20px; + cursor: pointer; + font-size: 16px; + width: 160px; } .button-primary { - background-color: #4caf50; + background-color: #4caf50; } .button-primary:hover { - background-color: #46a049; + background-color: #46a049; } .button-secondary { - background-color: #333; + background-color: #333; } .button-secondary:hover { - background-color: #1e1e1e; + background-color: #1e1e1e; } .title { - margin-top: 20px; - margin-bottom: -12px; + margin-top: 20px; + margin-bottom: -12px; } - button:hover { - background-color: #4cae4c; + background-color: #4cae4c; } ul { - list-style-type: none; - padding: 0; + list-style-type: none; + padding: 0; } li { - margin: 10px 0; + margin: 10px 0; } input[type="radio"] { - margin-right: 10px; + margin-right: 10px; } -.emphasis, #startQuestionsCount, #questionCount, #resultQuestionsCount { - font-size: 16px; - font-weight: bold; - margin: 0 auto; - margin-bottom: 10px; +.emphasis, +#startQuestionsCount, +#questionCount, +#resultQuestionsCount { + font-size: 16px; + font-weight: bold; + margin: 0 auto; + margin-bottom: 10px; } .content { - min-height: 300px; - display: flex; - flex-direction: column; + min-height: 300px; + display: flex; + flex-direction: column; } #choices { - min-width: 25px; - margin: 0 auto; - text-align: left; + min-width: 25px; + margin: 0 auto; + text-align: left; } -#quizDescription, #question, #result { - font-size: 18px; - font-style: italic; - color: #333; - margin: 0 auto; - margin-top: 20px; - margin-bottom: 12px; +#quizDescription, +#question, +#result { + font-size: 18px; + font-style: italic; + color: #333; + margin: 0 auto; + margin-top: 20px; + margin-bottom: 12px; } #quizDescription { - margin-bottom: 20px; + margin-bottom: 20px; } - #progress { - width: 100%; - background-color: #ddd; - border-radius: 8px; - overflow: hidden; - margin-bottom: 5px; + width: 100%; + background-color: #ddd; + border-radius: 8px; + overflow: hidden; + margin-bottom: 5px; } #progressBar { - height: 20px; - background-color: #4caf50; - width: 0%; - border-radius: 8px; + height: 20px; + background-color: #4caf50; + width: 0%; + border-radius: 8px; } #result-progress { - width: 100%; - background-color: #ddd; - border-radius: 8px; - overflow: hidden; - margin-bottom: 5px; + width: 100%; + background-color: #ddd; + border-radius: 8px; + overflow: hidden; + margin-bottom: 5px; } .divider { - width: 100%; - height: 20px; - background-color: #ddd; - border-radius: 8px; - overflow: hidden; - margin-bottom: 5px; + width: 100%; + height: 20px; + background-color: #ddd; + border-radius: 8px; + overflow: hidden; + margin-bottom: 5px; } #resultProgressBar { - width: 100%; - height: 20px; - background-color: #4caf50; - width: 100%; - border-radius: 8px; + width: 100%; + height: 20px; + background-color: #4caf50; + width: 100%; + border-radius: 8px; } #timeRemaining { - font-size: 14px; - font-style: italic; - color: #333; - margin: 0 auto; - margin-top: -35px; - margin-bottom: 12px; -} \ No newline at end of file + font-size: 14px; + font-style: italic; + color: #333; + margin: 0 auto; + margin-top: -35px; + margin-bottom: 12px; +}