Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mng 11 html quiz template #19

Merged
merged 13 commits into from
Jan 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist
.cache
node_modules
coverage
.vscode
46 changes: 35 additions & 11 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="pl">

<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
Expand All @@ -14,16 +15,39 @@

<body>

<div id="pokequiz-app">
Łukasz Dutka
daria305
memeraki / Gosia Dziewit
Aleksandra Cypko / AleksandraCyp
mariusz-sm / Mariusz Smarz
Agata Ludwiczyńska/ AgataLudwiczynska
arendarczyk / Kamil Arendarczyk
</div>
<div id="pokequiz-app">
Łukasz Dutka
daria305
memeraki / Gosia Dziewit
Aleksandra Cypko / AleksandraCyp
mariusz-sm / Mariusz Smarz
Agata Ludwiczyńska/ AgataLudwiczynska
arendarczyk / Kamil Arendarczyk
</div>

<template id="quiz-template">
<div class="quiz-top-bar progress-bar">
<div id="timer"></div>
<div class="mode-title">
<h2></h2>
</div>
<div id="question-counter"></div>
</div>
<div id="quiz-body">
<div class="quiz-question"></div>
<div class="quiz-answers">
<ul class="quiz-answers-list"></ul>
</div>
</div>
</template>

<script src="src/index.js"></script>
<template id="quiz-li">
<li class="quiz-answer">
<div class="unchecked"></div>
</li>
</template>

<script src="src/index.js"></script>
</body>
</html>

</html>
11 changes: 9 additions & 2 deletions src/app/App.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { doc } from "prettier";
import { showStartingPage } from './showStartingPage.js';
import { showAPopUpScreen } from './showAPopUpScreen';
import { addHelpScreenTemplate } from "./addHelpScreenTemplate.js";
import { renderQuizPage } from './quizPage.js'
import { WHO_IS_THAT_POKEMON, WHAT_DOES_THIS_POKEMON_LOOK_LIKE } from "../service/modes.js"

export const App = ({options}) => {

let SELECTED_MODE = WHO_IS_THAT_POKEMON;

showStartingPage();
addHelpScreenTemplate();

Expand All @@ -18,10 +21,12 @@ export const App = ({options}) => {
document.querySelector('#whoIsThatPokemonOption').addEventListener('click',()=>{
if(style.display=='none'||help.style.display == 'none')
console.log("Who's that Pokemon?");
SELECTED_MODE = WHO_IS_THAT_POKEMON;
});
document.querySelector('#whatItLooksLikeOption').addEventListener('click',()=>{
if(style.display=='none'||help.style.display == 'none')
console.log("What it looks like?");
SELECTED_MODE = WHAT_DOES_THIS_POKEMON_LOOK_LIKE;
});
document.querySelector('#guessTheTypeOption').addEventListener('click',()=>{
if(style.display=='none'||help.style.display == 'none')
Expand All @@ -32,6 +37,8 @@ export const App = ({options}) => {
if(style.display=='none'||help.style.display == 'none')
console.log("Hall of Fame");
});
}

// start the game
document.querySelector("#startGameButton").addEventListener("click", () => renderQuizPage(SELECTED_MODE));
}

18 changes: 18 additions & 0 deletions src/app/appSettings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// css styles dictionary changed during app runtime
export const START_PAGE_STYLES = {
startPageClass: "start-page"
}

export const QUIZ_PAGE_STYLES = {
quizPageClass: "quiz-page",
quizAnswerTextClass: "answer-text",
quizAnswerImageClass: "answer-image",
quizQuestionTextClass: "question-text",
quizQuestionImageClass: "question-image",
wrongAnswerClass: "wrong-answer",
correctAnswerClass: "correct-answer",
uncheckedClass: "unchecked"
}

export const TIMEOUT_AFTER_ANSWER_SELECTION = 1; //miliseconds

223 changes: 223 additions & 0 deletions src/app/quizPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import {
QuestionService
} from "../service/QuestionService.js"

import {
QUIZ_PAGE_STYLES,
START_PAGE_STYLES,
TIMEOUT_AFTER_ANSWER_SELECTION
} from "./appSettings.js"

// will be filledi with mode object during page rendering
let CURRENT_MODE = null;
let GENERATOR = null;

// use to render the page for the first time, after the game start
export function renderQuizPage(mode) {
CURRENT_MODE = mode;

const appScreen = document.querySelector('#pokequiz-app');
appScreen.classList.add(QUIZ_PAGE_STYLES.quizPageClass)
appScreen.classList.remove(START_PAGE_STYLES.startPageClass)
const quizTemplate = document.getElementById('quiz-template');
appScreen.innerHTML = quizTemplate.innerHTML;
// TODO later - generate question using questionService - below are temporary dummy variables
const generatedQuestion = {
question: "quizQuestion",
questionNum: 1,
}
setupPageTitle(CURRENT_MODE);
//GENERATOR = new QuestionService.Generator()
//TODO setupTimer() -- here or directly in App
renderNextQuestion(CURRENT_MODE);
}


// use to update quizPage and change only the question, new answers and question counter
// not changing the timer and bar
// gent question generator and use generates next question if there is any left to answer
// otherwise finishes the game and redirect user to the summary page
export function renderNextQuestion(mode) {
//genQuestion nie powinno być przekazywane do funkcji tylko powinno być tu wywoływana
const genQuestion = getNextQuestion(mode); // TODO later pass generator and use generator.genQuestion(), and replace dummy function with real one, once it's implemented. Gonna be async
if (genQuestion) { // some questions still left to answer
const quizBody = document.querySelector("#quiz-body");
// Update question
const quizQuestionElem = quizBody.querySelector(".quiz-question");
updateQuestion(quizQuestionElem, genQuestion.question, mode);
// Update answers list
const quizUl = quizBody.querySelector(".quiz-answers-list");
updateAnswersList(quizUl, genQuestion.question, mode);
// Update question counter
const questionCounter = document.querySelector("#question-counter");
updateQuestionCounter(questionCounter, genQuestion.questionNum);
// listen for an answer selection
const answersOptions = [...quizBody.querySelector(".quiz-answers-list").children]
for (let option of answersOptions) {
option.addEventListener("mouseup", function selectEventFunc() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mouseup? czemu nie click?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a, dobra, bo może ktoś by się w ostatniej chwili cofnął i jednak chciał ściągnąć myszkę z odpowiedzi. Make sense 😌

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, that was the idea behind

selectAnswer(genQuestion.question, option.querySelector("div"));
})
}
} else { // no more questions left
console.log("You WON!, but sorry, we still don't have any summary page"); // TODO create summary page redirection
}
}

//TODO dummy function to be removed after generator is added
const getNextQuestion = (mode) => {
Copy link
Owner

@lukaszdutka lukaszdutka Jan 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

be aware of that this function is going to be async

let q;
if (mode.name == "WHO_IS_THAT_POKEMON") {
q = {
question: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png',
answers: ['bulbasaur', 'ivysaur', 'venusaur', 'charmander', 'dummy1', 'dummy2'],
correctAnswer: {
name: 'bulbasaur',
index: 1
}
}
} else if (mode.name == "WHAT_DOES_THIS_POKEMON_LOOK_LIKE") {
q = {
question: 'bulbasaur',
answers: ['https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png',
'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/4.png',
'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/3.png',
'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/2.png'
],
correctAnswer: {
name: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png',
index: 1
}
}
}
return {
question: q,
questionNum: 1,
}
}

// Changes the title corresponding to the chosen game mode
const setupPageTitle = (mode) => {
const modeHeader = document.querySelector(".mode-title h2")
modeHeader.innerText = mode.title // Setup mode title
}

// Updates the question div with styling and content depending on a type of a question
const updateQuestion = (questionElement, questionSet, mode) => {
if (mode.questionType === "image") {
questionElement.classList.add(QUIZ_PAGE_STYLES.quizQuestionImageClass);
const imgElem = createImgElement(questionSet.question); // add img from url
questionElement.appendChild(imgElem);

} else if (mode.questionType === "text") {
questionElement.classList.add(QUIZ_PAGE_STYLES.quizQuestionTextClass);
questionElement.innerText = questionSet.question; // add question as an inner text
}
}

// Creates img element with a selected image url
const createImgElement = (url) => {
const img = document.createElement("img");
img.setAttribute("src", url);
return img;
}

// Updates styles for question list based on mode type
// creates question items sor provided question set
const updateAnswersList = (answersElement, questionSet, mode) => {
for (let answer of questionSet.answers) {
const answerElement = createAnswerElement(answer, mode);
answersElement.appendChild(answerElement);
}
}

// returns children elements from the template
// for template.content replacement, which is not fully supported yet
const getTemplateContent = (template) => {
const dummyDiv = document.createElement("div"); //
dummyDiv.innerHTML = template.innerHTML;
return dummyDiv.children
}

const createAnswerElement = (answer, mode) => {
const liTemplate = document.querySelector("#quiz-li");
const li = getTemplateContent(liTemplate)[0];
const liFirstElem = li.children[0]

if (mode.answerType === "image") {
// first child of li receives an image
liFirstElem.classList.add(QUIZ_PAGE_STYLES.quizAnswerImageClass)
const imgElem = createImgElement(answer) // get img url
liFirstElem.appendChild(imgElem)

} else if (mode.answerType === "text") {
// first child of li receives text
liFirstElem.classList.add(QUIZ_PAGE_STYLES.quizAnswerTextClass)
liFirstElem.innerText = answer // add question as an inner text
}
return li
}

// Updates the question number ona quiz page
const updateQuestionCounter = (counterElem, questionNum) => {
counterElem.innerText = String(questionNum).padStart(2, '0'); //TODO maybe - total num of question in a game mode
}

// fires up on mouse up event on answers list li, additionally accepts questionSet
// check which answer was selected
// eventHandler is element to which eventListener was attached to
function selectAnswer(questionSet, eventHandler) {
const answer = getAnswerFromElement(eventHandler);
if (answer) {
questionSet.correctAnswer.name === answer ? correctAnswerSelected(eventHandler) : wrongAnswerSelected(eventHandler);
} else {
throw new Error('Answer was not found')
}
}


// Read selected answer value from clicked list item
const getAnswerFromElement = (target) => {
const targetClasses = [...target.classList];
let answer;
if (targetClasses.includes(QUIZ_PAGE_STYLES.uncheckedClass)) {
if (targetClasses.includes(QUIZ_PAGE_STYLES.quizAnswerTextClass)) {
answer = target.innerText
} else if (targetClasses.includes(QUIZ_PAGE_STYLES.quizAnswerImageClass)) {
answer = target.children[0].getAttribute("src")
}
return answer
}
}

const correctAnswerSelected = (selectedElem) => {
console.log("yes")
//TODO add correct-answer class and remove unchecked
selectedElem.classList.remove(QUIZ_PAGE_STYLES.uncheckedClass)
selectedElem.classList.add(QUIZ_PAGE_STYLES.correctAnswerClass)
//TODO store results
setTimeout(()=> {
resetQuizAfterQuestion();
renderNextQuestion(CURRENT_MODE);
}, TIMEOUT_AFTER_ANSWER_SELECTION)
}

const wrongAnswerSelected = (selectedElem) => {
console.log("no")
// add wrong-answer class and remove unchecked
selectedElem.classList.remove(QUIZ_PAGE_STYLES.uncheckedClass)
selectedElem.classList.add(QUIZ_PAGE_STYLES.wrongAnswerClass)
//TODO store results
setTimeout(()=> {
resetQuizAfterQuestion();
renderNextQuestion(CURRENT_MODE);
}, TIMEOUT_AFTER_ANSWER_SELECTION)
}

// removes question list items
const resetQuizAfterQuestion = () => {
const quizBody = document.getElementById('quiz-body');
const quizTemplate = document.getElementById('quiz-template');
quizBody.innerHTML = getTemplateContent(quizTemplate)[1].innerHTML // get the quiz body inner HTML from the template
}
// TODO check if any css class should be reset too

4 changes: 4 additions & 0 deletions src/app/showStartingPage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { START_PAGE_STYLES } from "./appSettings.js"

export const showStartingPage = () => {
const appScreen = document.querySelector('#pokequiz-app');
appScreen.classList.add(START_PAGE_STYLES.startPageClass)
const startingPageTemplate =
`<div id="headerWithLogo" class="firstColumn spanInPortrait disableWithPopUpScreen">
<img src="./static/assets/ui/logo.png" alt='Pokemon' id='pokemonLogo'/>
Expand Down Expand Up @@ -32,4 +35,5 @@ export const showStartingPage = () => {
<img src='./static/assets/ui/pikach1.png' alt='Pikachu' id='pikachuImg' class="secondColumn disableWithPopUpScreen"/>
`
appScreen.innerHTML = startingPageTemplate;

}
Loading