Skip to content

Instantly share code, notes, and snippets.

@motsu0
Last active July 7, 2022 03:50
Show Gist options
  • Save motsu0/729b5141c3dd4323160abb8c41a7eddf to your computer and use it in GitHub Desktop.
Save motsu0/729b5141c3dd4323160abb8c41a7eddf to your computer and use it in GitHub Desktop.
@charset "utf-8";
:root{
--main-color: #0288D1;
--sub-color: #B3E5FC;
--attention-color: #D32F2F;
--correct-color: #D32F2F;
--wrong-color: #303F9F;
}
#quiz{
width: 100%;
max-width: 600px;
height: 100%;
max-height: 95vh;
position: fixed;
top: 50%;
left: 50%;
z-index: 500;
transform: translate(-50%,-50%);
border-radius: 8px;
background-color: #fff;
box-shadow: 0 0 5px 5px rgba(60,60,60,.2);
}
/* */
#quiz__area-n{
display: flex;
justify-content: center;
align-items: center;
height: 10%;
}
/* */
#quiz__area-q{
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
height: 35%;
padding: 16px;
overflow-y: auto;
color: var(--main-color);
font-size: 30px;
line-height: 1.5em;
}
/* */
#quiz__area-a{
height: 45%;
overflow-y: auto;
background-color: var(--sub-color);
user-select: none;
}
.unit-a__answer{
margin: 16px;
}
.answer__radio{
display: none;
}
.answer__label{
display: block;
box-sizing: border-box;
padding: 4px;
background-color: #fff;
text-align: center;
cursor: pointer;
}
.answer__radio:checked+.answer__label{
background-color: var(--main-color);
color: #fff;
}
.bt-end{
display: block;
box-sizing: border-box;
width: 100%;
padding: 4px;
border: none;
background-color: #fff;
text-align: center;
cursor: pointer;
}
/* */
.quiz__area-c{
display: flex;
justify-content: space-between;
align-items: center;
height: 10%;
user-select: none;
}
.bt-control{
padding: 2px 8px;
margin: 0 16px;
border: 1px solid var(--main-color);
background-color: #fff;
cursor: pointer;
}
#bt-confirm{
border: none;
background-color: var(--attention-color);
color: #fff;
}
/* */
.quiz-res__table{
margin: 0 auto;
border-collapse: collapse;
}
.quiz-res__head__td{
box-sizing: border-box;
padding: 8px 16px;
border: 1px solid var(--main-color);
background-color: var(--sub-color);
text-align: center;
color: var(--main-color);
}
.quiz-res__td{
box-sizing: border-box;
padding: 8px 16px;
border: 1px solid var(--main-color);
}
.quiz-res__td-a__inner{
display: flex;
align-items: center;
}
.quiz-res__mark{
display: inline-flex;
justify-content: center;
align-items: center;
width: 20px;
margin-right: 16px;
}
.quiz-res__maru{
color: var(--correct-color);
}
.quiz-res__correct{
color: var(--correct-color);
}
.quiz-res__batsu{
color: var(--wrong-color);
}
.quiz-res__wrong{
text-decoration: line-through;
color: var(--wrong-color);
}
.quiz-res__td-sum{
text-align: right;
}
/* */
.s-hide{
display: none;
}
.s-invisible{
visibility: hidden;
}
/*!
* quiz-maker.js v1.0
*
* Copyright (c) 2022 motsu
*
* Released under the MIT license.
* see https://opensource.org/licenses/MIT
*/
class quizMaker{
#json;
#num_quiz = 0;
#len_quiz;
#body = document.getElementById('quiz');
constructor(src){
this.url_json = src;
this.#loadJson();
}
#loadJson(){
fetch(this.url_json,{
method: 'GET'
}).then(response=>{
if(response.ok){
//通信成功
return response.json();
}else{
//通信失敗
this.#dispError();
}
}).then(json=>{
this.#json = json;
this.#len_quiz = this.#json.length;
this.#makeQuiz();
this.#body.classList.remove('hide');
})
.catch(error=>{
this.#dispError();
});
}
#dispError(){
document.getElementById('quiz-res').textContent = 'クイズデータの取得に失敗しました。';
}
#makeQuiz(){
const el_area_q = document.getElementById('quiz__area-q');
const el_area_a = document.getElementById('quiz__area-a');
this.#json.forEach((data,i)=>{
//問題欄
const el_unit_q = document.createElement('div');
el_unit_q.classList.add('area-q__unit-q');
if(i!=0) el_unit_q.classList.add('s-hide');
el_unit_q.innerHTML = escHtml(data['question']).replace(/\n/g,'<br>');
el_area_q.appendChild(el_unit_q);
//回答欄
const el_unit_a = document.createElement('div');
el_unit_a.classList.add('area-a__unit-a');
if(i!=0) el_unit_a.classList.add('s-hide');
el_area_a.appendChild(el_unit_a);
data['answers'].forEach((a,j)=>{
const el_answer = document.createElement('div');
el_answer.classList.add('unit-a__answer');
el_unit_a.appendChild(el_answer);
const el_radio_answer = document.createElement('input');
el_radio_answer.type = 'radio';
el_radio_answer.name = 'radio'+i;
el_radio_answer.id = `radio${i}-${j}`;
el_radio_answer.value = j;
el_radio_answer.classList.add('answer__radio');
el_answer.appendChild(el_radio_answer);
const el_label_answer = document.createElement('label');
el_label_answer.htmlFor = el_radio_answer.id;
el_label_answer.classList.add('answer__label')
el_label_answer.textContent = a;
el_answer.appendChild(el_label_answer);
});
});
//confirm最後尾へ
const el_confirm_q = document.getElementById('confirm-q');
const el_confirm_a = document.getElementById('confirm-a');
el_area_q.appendChild(el_confirm_q);
el_area_a.appendChild(el_confirm_a);
//リスナ設定
const el_area_n = document.getElementById('quiz__area-n');
const els_unit_q = document.getElementsByClassName('area-q__unit-q');
const els_unit_a = document.getElementsByClassName('area-a__unit-a');
const bt_prev = document.getElementById('bt-prev');
const bt_confirm = document.getElementById('bt-confirm');
const bt_next = document.getElementById('bt-next');
const bt_end_no = document.getElementById('bt-end-no');
const bt_end_yes = document.getElementById('bt-end-yes');
bt_prev.addEventListener('click',()=>{
changeQuestion(this,-1);
});
bt_next.addEventListener('click',()=>{
changeQuestion(this,1);
});
bt_confirm.addEventListener('click',()=>{
confirm(this);
});
bt_end_no.addEventListener('click',e=>{
e.preventDefault();
confirmNo(this);
})
bt_end_yes.addEventListener('click',e=>{
e.preventDefault();
confirmYes(this);
})
writeNumber(this);
function changeQuestion(QM,diff){
QM.#num_quiz += diff;
if(QM.#num_quiz<0) QM.#num_quiz = 0;
if(QM.#num_quiz>QM.#len_quiz-1) QM.#num_quiz = QM.#len_quiz - 1;
if(QM.#num_quiz==0){
bt_prev.classList.add('s-invisible');
}else{
bt_prev.classList.remove('s-invisible');
}
if(QM.#num_quiz==QM.#len_quiz-1){
bt_next.classList.add('s-invisible');
}else{
bt_next.classList.remove('s-invisible');
}
for(let i=0;i<QM.#len_quiz;i++){
if(i==QM.#num_quiz){
els_unit_q[i].classList.remove('s-hide');
els_unit_a[i].classList.remove('s-hide');
}else{
els_unit_q[i].classList.add('s-hide');
els_unit_a[i].classList.add('s-hide');
}
}
writeNumber(QM);
}
function writeNumber(QM) {
el_area_n.textContent = `問 ${QM.#num_quiz+1}/${QM.#len_quiz}`;
}
function confirm(QM){
els_unit_q[QM.#num_quiz].classList.add('s-hide');
els_unit_a[QM.#num_quiz].classList.add('s-hide');
bt_prev.classList.add('s-invisible');
bt_next.classList.add('s-invisible');
bt_confirm.classList.add('s-invisible');
el_confirm_q.classList.remove('s-hide');
el_confirm_a.classList.remove('s-hide');
}
function confirmNo(QM){
el_confirm_q.classList.add('s-hide');
el_confirm_a.classList.add('s-hide');
bt_confirm.classList.remove('s-invisible');
changeQuestion(QM,0);
}
function confirmYes(QM){
//採点中表示
bt_end_yes.classList.add('s-invisible')
bt_end_no.classList.add('s-invisible');
//要素準備
const el_res = document.getElementById('quiz-res');
el_res.textContent = '';
const el_table_res = document.createElement('table');
el_table_res.classList.add('quiz-res__table');
const el_form = el_area_a;
//見出し
const el_table__head = document.createElement('tr');
const el_table__head__td_q = document.createElement('td');
el_table__head__td_q.classList.add('quiz-res__head__td');
el_table__head__td_q.textContent = '問題';
const el_table__head__td_a = document.createElement('td');
el_table__head__td_a.classList.add('quiz-res__head__td');
el_table__head__td_a.textContent = '解答';
el_table__head.appendChild(el_table__head__td_q);
el_table__head.appendChild(el_table__head__td_a);
el_table_res.appendChild(el_table__head);
//問題&解答行
let count_correct = 0;
for(let i=0;i<QM.#len_quiz;i++){
const i_answer = el_form.elements['radio'+i].value;
const el_tr_res = document.createElement('tr');
//問題列
const el_td_q = document.createElement('td');
el_td_q.classList.add('quiz-res__td');
el_td_q.innerHTML = escHtml(QM.#json[i]['question']).replace(/\n/g,'<br>');
el_tr_res.appendChild(el_td_q);
//回答列
const el_td_a = document.createElement('td');
el_td_a.classList.add('quiz-res__td');
const el_td_a__inner = document.createElement('div');
el_td_a__inner.classList.add('quiz-res__td-a__inner');
const el_td_a__mark = document.createElement('div');
el_td_a__mark.classList.add('quiz-res__mark');
const el_td_a__text = document.createElement('div');
el_td_a__text.classList.add('quiz-res__correct');
el_td_a__text.textContent = QM.#json[i]['answers'][QM.#json[i]['index-answer']];
if(i_answer!=''&&i_answer==QM.#json[i]['index-answer']){
//正解
el_td_a__mark.classList.add('quiz-res__maru');
el_td_a__mark.textContent = '◯';
count_correct++;
}else{
//不正解
el_td_a__mark.classList.add('quiz-res__batsu');
el_td_a__mark.textContent = '✕';
const el_wrong = document.createElement('div');
el_wrong.classList.add('quiz-res__wrong');
if(i_answer==''){
el_wrong.textContent = '無回答';
}else{
el_wrong.textContent = QM.#json[i]['answers'][i_answer];
}
el_td_a__text.prepend(el_wrong);
}
el_td_a.appendChild(el_td_a__inner);
el_td_a__inner.appendChild(el_td_a__mark);
el_td_a__inner.appendChild(el_td_a__text);
el_tr_res.appendChild(el_td_a);
//
el_table_res.appendChild(el_tr_res);
}
//結果まとめ行
const el_tr_sum = document.createElement('tr');
const el_td_sum = document.createElement('td');
el_td_sum.classList.add('quiz-res__td');
el_td_sum.classList.add('quiz-res__td-sum');
el_td_sum.colSpan = '2';
el_td_sum.textContent = `${QM.#len_quiz}問中${count_correct}問正解!`;
el_tr_sum.appendChild(el_td_sum);
el_table_res.appendChild(el_tr_sum);
//表示
el_res.appendChild(el_table_res);
QM.#body.classList.add('hide');
//スクロール
const pos_res = window.pageYOffset + el_res.getBoundingClientRect().top;
window.scrollTo({
top: pos_res,
left: 0,
behavior: 'smooth'
});
}
function escHtml(str){
str = str.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
return str;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment