harness/app-assets/templates/assets/js/modules/quiz.js (398 lines of code) (raw):

/*global window,define */ define([ 'smoothScroll', 'modules/ads' ], function ( smoothScroll, Ads ) { 'use strict'; var initialised = false, numAnswered, questionCount, isPersonalityQuiz, moveMPU, score, scoreMessages, personalityQuizBuckets; function init(quiz) { numAnswered = 0; questionCount = 0; isPersonalityQuiz = document.getElementsByClassName('quiz__buckets')[0]; moveMPU = isAdBelowQuiz(quiz); if (isPersonalityQuiz) { quiz.classList.add('personality-quiz'); setupPersonalityQuizBuckets(); setupPersonalityQuizQuestions(); removePersonalityQuizAnswers(); buildResultsPanel(quiz); } else { quiz.classList.add('news-quiz'); score = 0; scoreMessages = getScoreMessages(); setupNewsQuizQuestions(); removeNewsQuizAnswers(); buildScoresPanel(quiz); } quiz.classList.add('loaded'); } function setupNewsQuizQuestions() { var i, questionsAndAnswers = getQuestionsAndAnswers(), question, questions = document.getElementsByClassName('quiz__question'), questionObj; for (i = 0; i < questions.length; i++) { question = questions[i]; questionObj = questionsAndAnswers[i+1]; questionObj.elem = question; wrapQuestion(question); setupNewsQuizAnswers(questionObj); questionCount++; } } function setupNewsQuizAnswers(questionObj) { var i, answerCode, answers = questionObj.elem.getElementsByClassName('question__answer'); for (i = 0; i < answers.length; i++) { answerCode = GU.util.getStringFromUnicodeVal(65 + i); if (answerCode === questionObj.correctAnswer) { if (questionObj.revealText) { answers[i].dataset.correctAnswerExplanation = questionObj.revealText; } answers[i].dataset.correct = 'true'; } styleAnswer(answers[i]); answers[i].addEventListener('click', onNewsAnswerClick.bind(null, answers[i], questionObj.elem, answers[i].getElementsByTagName('img')[0])); } } function removeNewsQuizAnswers() { var i, answers = document.querySelectorAll('.quiz__correct-answers-title, .quiz__correct-answers'); for (i = 0; i < answers.length; i++) { answers[i].parentNode.removeChild(answers[i]); } } function setupPersonalityQuizBuckets() { var i, bucketCode, buckets = document.getElementsByClassName('quiz__bucket'), quizBuckets = {}; for (i = 0; i < buckets.length; i++) { bucketCode = GU.util.getStringFromUnicodeVal(65 + i); quizBuckets[bucketCode] = { count: 0, title: buckets[i].dataset.title, description: buckets[i].dataset.description }; } personalityQuizBuckets = quizBuckets; } function setupPersonalityQuizQuestions() { var i, question, questions = document.getElementsByClassName('quiz__question'), questionObj; for (i = 0; i < questions.length; i++) { question = questions[i]; questionObj = {}; questionObj.elem = question; wrapQuestion(question); setupPersonalityQuizAnswers(questionObj); questionCount++; } } function setupPersonalityQuizAnswers(questionObj) { var i, answers = questionObj.elem.getElementsByClassName('question__answer'); for (i = 0; i < answers.length; i++) { styleAnswer(answers[i]); answers[i].addEventListener('click', onPersonalityAnswerClick.bind(null, answers[i], questionObj.elem)); } } function removePersonalityQuizAnswers() { var i, answers = document.querySelectorAll('.quiz__buckets-title, .quiz__buckets'); for (i = 0; i < answers.length; i++) { answers[i].parentNode.removeChild(answers[i]); } } function getQuestionsAndAnswers() { var i, key, answerMatch, question, answer, answers = {}, correctAnswerWordList = document.getElementsByClassName('quiz__correct-answers')[0].innerHTML.split(' '); for (i = 0; i < correctAnswerWordList.length; i++) { // Check if word in this format: 1:A answerMatch = correctAnswerWordList[i].match(/(\d+):([A-Z])/g); if (answerMatch && answerMatch.length) { answer = answerMatch[0]; question = answer.split(':')[0]; answers[question] = { correctAnswer: answer.split(':')[1] }; } else { if (!answers[question].revealText || answers[question].revealText === '- ') { answers[question].revealText = ''; } answers[question].revealText += correctAnswerWordList[i] + ' '; } } for (key in answers) { if (answers.hasOwnProperty(key) && answers[key].revealText) { // Remove trailing comma in revealText answers[key].revealText = answers[key].revealText.replace(/,\s*$/, ''); } } return answers; } function getScoreMessages() { var i, message, minScore, scoreElems = document.querySelectorAll('.quiz__scores > li'), messages = {}; for (i = 0; i < scoreElems.length; i++) { message = scoreElems[i].dataset.title; minScore = scoreElems[i].dataset.minScore; messages[Math.max(minScore, 0)] = message; } return messages; } function buildScoresPanel(quiz) { var scoresPanel = document.createElement('div'); scoresPanel.classList.add('quiz-scores'); scoresPanel.id = 'quiz-scores'; scoresPanel.innerHTML = '<p class="quiz-scores__score">' + '<span class="quiz-scores__correct"></span> / <span class="quiz-scores__questions">' + questionCount + '</span></p><p class="quiz-scores__message"></p>'; quiz.appendChild(scoresPanel); } function buildResultsPanel(quiz) { var resultPanel = document.createElement('div'); resultPanel.classList.add('quiz-results'); resultPanel.id = 'quiz-results'; resultPanel.innerHTML = '<h1 class="quiz-results__title"></h1><p class="quiz-results__description"></p>'; quiz.appendChild(resultPanel); } function wrapQuestion(question) { var i, questionWrapper = document.createElement('div'), questionAnswerList = question.getElementsByClassName('question__answers'), questionImages = question.querySelectorAll(':scope > img'), questionText = question.getElementsByClassName('question__text'); questionWrapper.classList.add('question__wrapper'); question.insertBefore(questionWrapper, questionAnswerList[0]); // Does this question have text for (i = 0; i < questionText.length; i++) { adjustText(questionWrapper, questionText[i]); } // Does this question have an image for (i = 0; i < questionImages.length; i++) { adjustImage(question, questionWrapper, questionImages[i], true); } } function styleAnswer(answer) { var answerImages = answer.querySelectorAll(':scope > img'), answerMarker = document.createElement('div'), answerMessage = document.createElement('div'), answerWrapper = document.createElement('div'), answerText = answer.getElementsByClassName('answer__text'), i; // Wrap answer in a div for styling answerWrapper.classList.add('answer__wrapper'); answer.appendChild(answerWrapper); // Add an answer message div to wrap text answer, correct/wrong message and explanation response answerMessage.classList.add('answer__message'); answerWrapper.appendChild(answerMessage); // Add a marker icon span answerMarker.classList.add('answer__marker'); if (isPersonalityQuiz) { answerMarker.innerHTML = '<div class="answer__marker__inner"></div>'; } answerWrapper.appendChild(answerMarker); // Does this answer have text for (i = 0; i < answerText.length; i++) { adjustText(answerMessage, answerText[i]); } // Does this answer have an image for (i = 0; i < answerImages.length; i++) { adjustImage(answer, answerWrapper, answerImages[i], false); } } function adjustImage(parent, wrapper, image, isQuestion) { var src = image.getAttribute('src'); if (src !== '') { parent.classList.add('has-image'); if (isQuestion) { wrapper.parentNode.classList.add('question__img'); // if the text height is greater than the image height resize the wrapper checkWrapperHeight(src, image, wrapper); } else { image.classList.add('answer__img'); } wrapper.appendChild(image); } else { image.parentNode.removeChild(image); } } function checkWrapperHeight(src, image, wrapper) { var dummyImage, text = wrapper.getElementsByClassName('question__text')[0]; if (!text) { return; } dummyImage = document.createElement('img'); dummyImage.addEventListener('load', adjustWrapperHeight.bind(null, image, text, wrapper)); dummyImage.src = src; } function adjustWrapperHeight(image, text, wrapper) { if (image.offsetHeight < text.offsetHeight) { wrapper.style.height = text.offsetHeight + 'px'; } } function adjustText(parent, text) { parent.appendChild(text); } function isAdBelowQuiz(quiz) { var adBelowQuiz = false, mpu = document.getElementsByClassName('advert-slot__wrapper')[0], mpuOffset, quizOffset; if (mpu) { mpuOffset = GU.util.getElementOffset(mpu).top; quizOffset = GU.util.getElementOffset(quiz).top; if (mpuOffset > quizOffset) { adBelowQuiz = true; } } return adBelowQuiz; } function adjustAdPosition(yPos, startTime, timeStamp) { var newYPos, progress; if (!startTime) { startTime = timeStamp; } progress = timeStamp - startTime; newYPos = Ads.updateMPUPosition(yPos); if (progress < 2000) { window.requestAnimationFrame(adjustAdPosition.bind(null, newYPos, startTime)); } } function onNewsAnswerClick(answer, question, isImage) { var answerPara, correctAnswerWrapper, startTime = null, yPos = null; if (question.classList.contains('answered')) { return; } if (answer.dataset.correct === 'true') { question.classList.add('is-correct'); score++; } else { answer.classList.add('wrong-answer'); question.classList.add('is-wrong'); answer = question.querySelector('[data-correct="true"]'); } answer.classList.add('correct-answer'); if (answer.dataset.correctAnswerExplanation) { answerPara = document.createElement('p'); answerPara.classList.add('answer__explanation'); answerPara.innerHTML = answer.dataset.correctAnswerExplanation.trim(); correctAnswerWrapper = answer.getElementsByClassName('answer__message')[0]; correctAnswerWrapper.appendChild(answerPara); } question.classList.add('answered'); numAnswered++; // If necessary set up a call to check mpu position if (moveMPU) { window.requestAnimationFrame(adjustAdPosition.bind(null, yPos, startTime)); } // When we have an image answer we need to move the positioning of the explanation and marker if (isImage) { showMarkedAnswer(question); } // If all questions have been answered display the score if (questionCount === numAnswered) { showScore(); } } function onPersonalityAnswerClick(answer, question) { var hightedAnswer; if (question.classList.contains('answered')) { if (answer.classList.contains('highlight-answer') || questionCount === numAnswered) { return; } else { hightedAnswer = question.getElementsByClassName('highlight-answer')[0]; hightedAnswer.classList.remove('highlight-answer'); personalityQuizBuckets[hightedAnswer.dataset.buckets].count--; numAnswered--; } } if (personalityQuizBuckets[answer.dataset.buckets]) { question.classList.add('answered'); answer.classList.add('highlight-answer'); numAnswered++; personalityQuizBuckets[answer.dataset.buckets].count++; // If all questions have been answered display the score if (questionCount === numAnswered) { showResult(); } } } function showMarkedAnswer(question) { var i, markedAnswer, markedAnswers = question.querySelectorAll('.correct-answer, .wrong-answer'), thisMessage, thisHeight, thisMarker; for (i = 0; i < markedAnswers.length; i++) { markedAnswer = markedAnswers[i]; thisMessage = markedAnswer.getElementsByClassName('answer__message')[0]; thisHeight = thisMessage.offsetHeight; thisMarker = markedAnswer.getElementsByClassName('answer__marker')[0]; // position explanation to the bottom of wrapper thisMessage.style.top = 'calc(100% - ' + thisHeight + 'px)'; thisMarker.style.top = 'calc(100% - ' + (thisHeight - 7) + 'px)'; } } function showScore() { var i, scoreDisplayMessage = ''; for (i = 0; i < score; i++) { if (scoreMessages[i]) { scoreDisplayMessage = scoreMessages[i]; } } document.getElementsByClassName('quiz-scores__correct')[0].innerHTML = score.toString(); document.getElementsByClassName('quiz-scores__message')[0].innerHTML = scoreDisplayMessage; document.getElementsByClassName('quiz-scores')[0].classList.add('open'); // Scroll score panel into view smoothScroll.animateScroll('#quiz-scores', null, {speed: 1500, offset: 40}); } function showResult() { var key, bucket, result, resultTitle, resultDescription; for (key in personalityQuizBuckets) { if (personalityQuizBuckets.hasOwnProperty(key)) { bucket = personalityQuizBuckets[key]; if (!result || (bucket.count > result.count)) { result = bucket; resultDescription = result.description; resultTitle = result.title; } } } document.getElementsByClassName('quiz-results__description')[0].innerHTML = resultDescription; document.getElementsByClassName('quiz-results__title')[0].innerHTML = resultTitle; document.getElementsByClassName('quiz-results')[0].classList.add('open'); // Scroll result panel into view smoothScroll.animateScroll('#quiz-results', null, {speed: 1500, offset: 40}); } function ready() { var quiz; if (!initialised) { initialised = true; quiz = document.querySelector('.element-atom .quiz'); if (quiz) { init(quiz); } } } return { init: ready }; });