Skip to content

Commit 2f2988e

Browse files
Fix and rewrite quiz in native JS (#257)
Fix quiz loading error caused by late jQuery loading. Issue was introduced in 1e50d58
1 parent 28f8607 commit 2f2988e

File tree

1 file changed

+102
-57
lines changed

1 file changed

+102
-57
lines changed

js/quiz.js

Lines changed: 102 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,134 @@
1-
$(document).ready(function () {
2-
var questions = {};
3-
if ($('p.quiz').length == 0) {
1+
"use strict";
2+
3+
addEventListener("load", () => {
4+
let questions = {};
5+
const paragraphs = document.querySelectorAll('p.quiz');
6+
7+
if (paragraphs.length == 0) {
48
return;
59
}
6-
$('.post-content').append('<div id="quiz" class="carousel slide" data-interval="0" data-ride="carousel"><ol class="carousel-indicators"></ol><div class="carousel-inner" role="listbox"></div><a class="left carousel-control" href="#quiz" role="button" data-slide="prev"><span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span><span class="sr-only">Previous</span></a><a class="right carousel-control" href="#quiz" role="button" data-slide="next"><span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span><span class="sr-only">Next</span></a></div>');
7-
var items = $('.carousel-inner');
810

9-
$('p.quiz').each(function(index) {
10-
var $this = $(this);
11-
var options = $this.next();
11+
const carouselHTML = `
12+
<div id="quiz" class="carousel slide" data-interval="0" data-ride="carousel">
13+
<ol class="carousel-indicators"></ol>
14+
<div class="carousel-inner" role="listbox"></div>
15+
<a class="left carousel-control" href="#quiz" role="button" data-slide="prev">
16+
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
17+
<span class="sr-only">Previous</span>
18+
</a>
19+
<a class="right carousel-control" href="#quiz" role="button" data-slide="next">
20+
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
21+
<span class="sr-only">Next</span>
22+
</a>
23+
</div>
24+
`;
25+
26+
document.querySelector('.post-content').insertAdjacentHTML('beforeend', carouselHTML);
27+
28+
paragraphs.forEach((paragraph, index) => {
29+
const options = paragraph.nextElementSibling;
1230

13-
if (!options.is('ul')) {
31+
if (!options || options.tagName !== 'UL') {
1432
return;
1533
}
1634

17-
var question = $(this).text();
18-
$this.wrap('<div class="item"><div class="container"><div class="carousel-caption"><h1>' + question + '</h1><div class="form-group" id="question' + index + '"></div></div></div></div>');
19-
var formGroup = $('#question' + index);
35+
const question = paragraph.textContent;
36+
paragraph.outerHTML = `
37+
<div class="item">
38+
<div class="container">
39+
<div class="carousel-caption">
40+
<h1>${question}</h1>
41+
<div class="form-group" id="question${index}"></div>
42+
</div>
43+
</div>
44+
</div>
45+
`;
46+
const formGroup = document.getElementById(`question${index}`);
2047

21-
$this.remove();
48+
options.querySelectorAll('li').forEach(option => {
49+
const text = option.textContent.trim();
50+
option.textContent = '';
2251

23-
var question = {expected: 0, correct: 0, wrong: 0};
24-
25-
questions['question'+index] = question;
26-
options.find('li').each(function() {
27-
$this = $(this);
28-
var text = $this.text().trim();
29-
$this.text = '';
3052
if (text.startsWith('[ ]')) {
31-
formGroup.append('<div class="checkbox"><label class="control-label"><input type="checkbox" class="form-control-sm possible-answer" data-question="question' + index + '" data-answer="false" name="question-' + index + '">' + text.replace(/^\[ \]/, '') + '</label></div>');
32-
}
33-
if (text.startsWith('[x]')) {
34-
question.expected++;
35-
formGroup.append('<div class="checkbox"><label class="control-label"><input type="checkbox" class="form-control-sm possible-answer" data-question="question' + index + '" data-answer="true" name="question-' + index + '"> ' + text.replace(/^\[x\]/, '') + '</label></div>');
36-
}
37-
if (text.startsWith('( )')) {
38-
formGroup.append('<div class="radio"><label class="control-label"><input type="radio" class="form-control-sm possible-answer" data-question="question' + index + '" data-answer="false" name="question-' + index + '">' + text.replace(/^\( \)/, '') + '</label></div>');
39-
}
40-
if (text.startsWith('(x)')) {
41-
question.expected++;
42-
formGroup.append('<div class="radio"><label class="control-label"><input type="radio" class="form-control-sm possible-answer" data-question="question' + index + '" data-answer="true" name="question-' + index + '"> ' + text.replace(/^\(x\)/, '') + '</label></div>');
53+
formGroup.insertAdjacentHTML('beforeend', `<div class="checkbox"><label class="control-label"><input type="checkbox" class="form-control-sm possible-answer" data-question="question${index}" data-answer="false" name="question-${index}">${text.replace(/^\[ \]/, '')}</label></div>`);
54+
} else if (text.startsWith('[x]')) {
55+
formGroup.insertAdjacentHTML('beforeend', `<div class="checkbox"><label class="control-label"><input type="checkbox" class="form-control-sm possible-answer" data-question="question${index}" data-answer="true" name="question-${index}"> ${text.replace(/^\[x\]/, '')}</label></div>`);
56+
questions[`question${index}`] = { expected: 1, correct: 0, wrong: 0 };
57+
} else if (text.startsWith('( )')) {
58+
formGroup.insertAdjacentHTML('beforeend', `<div class="radio"><label class="control-label"><input type="radio" class="form-control-sm possible-answer" data-question="question${index}" data-answer="false" name="question-${index}">${text.replace(/^\( \)/, '')}</label></div>`);
59+
} else if (text.startsWith('(x)')) {
60+
formGroup.insertAdjacentHTML('beforeend', `<div class="radio"><label class="control-label"><input type="radio" class="form-control-sm possible-answer" data-question="question${index}" data-answer="true" name="question-${index}"> ${text.replace(/^\(x\)/, '')}</label></div>`);
61+
questions[`question${index}`] = { expected: 1, correct: 0, wrong: 0 };
4362
}
4463
});
64+
4565
options.remove();
46-
$('.carousel-indicators').append('<li data-target="#quiz" data-slide-to="' + index + '"></li>');
66+
document.querySelector('.carousel-indicators').insertAdjacentHTML('beforeend', `<li data-target="#quiz" data-slide-to="${index}"></li>`);
4767
});
48-
$('.item').appendTo('.carousel-inner');
49-
$('.item').first().addClass('active');
50-
$('.item .carousel-caption').last().append('<p><br/><a class="btn btn-lg btn-primary submit-quiz" href="#" role="button">Submit your answers</p>');
51-
$('ol.carousel-indicators li').first().addClass('active');
5268

53-
$('a.submit-quiz').click(validateQuiz);
69+
document.querySelectorAll('.item').forEach(item => {
70+
item.parentNode.querySelector('.carousel-inner').appendChild(item);
71+
});
5472

73+
document.querySelector('.item').classList.add('active');
74+
document.querySelector('.item:last-child .carousel-caption').insertAdjacentHTML('beforeend', '<p><br/><a class="btn btn-lg btn-primary submit-quiz" href="#" role="button">Submit your answers</p>');
75+
document.querySelector('ol.carousel-indicators li').classList.add('active');
76+
document.querySelector('a.submit-quiz').addEventListener('click', validateQuiz);
5577

5678
function validateQuiz() {
57-
$('input.possible-answer').each(function(i, o) {
58-
var self = $(this);
59-
if (o.checked && self.attr('data-answer') == 'false') {
60-
self.parent().parent().addClass('quiz-error');
61-
questions[self.attr('data-question')].wrong++;
62-
} else if (o.checked && self.attr('data-answer') == 'true') {
63-
questions[self.attr('data-question')].correct++;
79+
document.querySelectorAll('input.possible-answer').forEach(input => {
80+
const self = input;
81+
const parent = self.parentElement.parentElement;
82+
const dataQuestion = self.getAttribute('data-question');
83+
const dataAnswer = self.getAttribute('data-answer');
84+
85+
if (self.checked && dataAnswer === 'false') {
86+
parent.classList.add('quiz-error');
87+
questions[dataQuestion].wrong++;
88+
} else if (self.checked && dataAnswer === 'true') {
89+
questions[dataQuestion].correct++;
6490
}
65-
if (self.attr('data-answer') == 'true') {
66-
self.parent().parent().addClass('quiz-success');
91+
if (dataAnswer === 'true') {
92+
parent.classList.add('quiz-success');
6793
}
68-
self.prop('disabled', true);
94+
self.disabled = true;
6995
});
7096

71-
var result = {correct: 0, total: 0};
97+
const result = { correct: 0, total: 0 };
7298

73-
for (var i in questions) {
74-
var q = questions[i];
99+
for (const key in questions) {
100+
const q = questions[key];
75101

76102
result.total++;
77-
if (q.wrong == 0 && q.correct == q.expected) {
103+
if (q.wrong === 0 && q.correct === q.expected) {
78104
result.correct++;
79105
}
80106
}
81107

82-
var title = $('.post-title').text();
83-
var hashtags = 'dockerbday';
84-
var text = encodeURIComponent('I\'ve just completed the docker birthday tutorial ' + title + ' and got ' + result.correct + ' out of ' + result.total);
108+
const title = document.querySelector('.post-title').textContent;
109+
const hashtags = 'dockerbday';
110+
const text = encodeURIComponent(`I've just completed the docker birthday tutorial ${title} and got ${result.correct} out of ${result.total}`);
111+
112+
const submitQuizLink = document.querySelector('a.submit-quiz');
113+
submitQuizLink.outerHTML = `<h3>You've got ${result.correct} out of ${result.total}</h3>
114+
<a class="twitter-share-button" href="https://twitter.com/intent/tweet?hashtags=${hashtags}&text=${text}" data-size="large">Tweet</a>`;
115+
116+
fetch('https://platform.twitter.com/widgets.js')
117+
.then(response => {
118+
if (!response.ok) {
119+
throw new Error('Failed to load script');
120+
}
121+
return response.text();
122+
})
123+
.then(scriptText => {
124+
const scriptElement = document.createElement('script');
125+
scriptElement.textContent = scriptText;
126+
document.body.appendChild(scriptElement);
127+
})
128+
.catch(error => {
129+
console.error('Error loading script:', error);
130+
});
85131

86-
$('a.submit-quiz').replaceWith('<h3>You\'ve got ' + result.correct + ' out of ' + result.total + '</h3><a class="twitter-share-button" href="https://twitter.com/intent/tweet?hashtags=' + hashtags + '&text=' + text + '" data-size="large">Tweet</a>');
87-
$.getScript('//platform.twitter.com/widgets.js');
88132
}
133+
89134
});

0 commit comments

Comments
 (0)