137 lines
4.8 KiB
JavaScript
137 lines
4.8 KiB
JavaScript
class TestPage extends HTMLElement {
|
|
connectedCallback() {
|
|
this.className = 'screen';
|
|
this.renderQuestion();
|
|
}
|
|
|
|
renderHeader(step) {
|
|
const wrapper = document.createElement('div');
|
|
const counter = document.createElement('span');
|
|
counter.className = 'muted';
|
|
counter.textContent = `${step} / ${state.questions.length}`;
|
|
|
|
const topbar = createTopbar([counter]);
|
|
topbar.querySelector('.brand').onclick = () => {
|
|
if (confirm('처음 화면으로 돌아갈까요? 지금까지의 응답은 사라집니다.')) {
|
|
showStartScreen();
|
|
}
|
|
};
|
|
|
|
const track = document.createElement('div');
|
|
track.className = 'progress-track';
|
|
const fill = document.createElement('div');
|
|
fill.className = 'progress-fill';
|
|
fill.style.width = `${(step / state.questions.length) * 100}%`;
|
|
track.appendChild(fill);
|
|
|
|
wrapper.append(topbar, track);
|
|
return wrapper;
|
|
}
|
|
|
|
renderQuestion() {
|
|
const index = state.current;
|
|
const question = state.questions[index];
|
|
let selected = state.answers[index] ?? null;
|
|
let confidence = state.confidences[index] ?? null;
|
|
|
|
this.replaceChildren(this.renderHeader(index + 1));
|
|
|
|
const card = document.createElement('div');
|
|
card.className = 'card';
|
|
|
|
const title = document.createElement('p');
|
|
title.className = 'question-text';
|
|
title.textContent = `${index + 1}. ${question.question}`;
|
|
card.appendChild(title);
|
|
|
|
const list = document.createElement('ul');
|
|
list.className = 'options';
|
|
const optionButtons = question.options.map((option, i) => {
|
|
const item = document.createElement('li');
|
|
const button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.className = 'option';
|
|
button.setAttribute('aria-pressed', String(option === selected));
|
|
|
|
const key = document.createElement('span');
|
|
key.className = 'key';
|
|
key.textContent = String.fromCharCode(65 + i);
|
|
const text = document.createElement('span');
|
|
text.textContent = option;
|
|
|
|
button.append(key, text);
|
|
button.onclick = () => {
|
|
selected = option;
|
|
optionButtons.forEach((b) => b.setAttribute('aria-pressed', 'false'));
|
|
button.setAttribute('aria-pressed', 'true');
|
|
updateSubmitState();
|
|
};
|
|
|
|
item.appendChild(button);
|
|
list.appendChild(item);
|
|
return button;
|
|
});
|
|
card.appendChild(list);
|
|
|
|
const confidenceBox = document.createElement('div');
|
|
confidenceBox.className = 'confidence';
|
|
const confidenceLabel = document.createElement('label');
|
|
confidenceLabel.textContent = '이 답에 얼마나 확신하나요?';
|
|
confidenceBox.append(
|
|
confidenceLabel,
|
|
createChipGroup(CONFIDENCE, {
|
|
selected: confidence,
|
|
onSelect: (value) => {
|
|
confidence = value;
|
|
updateSubmitState();
|
|
},
|
|
})
|
|
);
|
|
card.appendChild(confidenceBox);
|
|
|
|
const actions = document.createElement('div');
|
|
actions.className = 'actions';
|
|
if (index > 0) {
|
|
actions.appendChild(createButton('이전 문제', () => history.back(), 'ghost'));
|
|
}
|
|
|
|
const isLast = index === state.questions.length - 1;
|
|
const submitButton = document.createElement('button');
|
|
submitButton.className = 'primary';
|
|
submitButton.textContent = isLast ? '결과 보기' : '다음 문제';
|
|
submitButton.onclick = () => {
|
|
state.answers[index] = selected;
|
|
state.confidences[index] = confidence;
|
|
if (isLast) {
|
|
finishQuiz();
|
|
} else {
|
|
goToQuestion(index + 1);
|
|
}
|
|
};
|
|
actions.appendChild(submitButton);
|
|
card.appendChild(actions);
|
|
|
|
const updateSubmitState = () => {
|
|
submitButton.disabled = !(selected && confidence);
|
|
};
|
|
updateSubmitState();
|
|
|
|
this.appendChild(card);
|
|
|
|
this.onkeydown = (event) => {
|
|
if (event.target.tagName === 'INPUT') return;
|
|
const fromLetter = event.key.toUpperCase().charCodeAt(0) - 65;
|
|
const fromNumber = Number(event.key) - 1;
|
|
const at = optionButtons[fromLetter] ?? optionButtons[fromNumber];
|
|
if (event.key.length === 1 && at) {
|
|
at.click();
|
|
at.focus();
|
|
}
|
|
};
|
|
this.tabIndex = -1;
|
|
this.focus({ preventScroll: true });
|
|
}
|
|
}
|
|
|
|
customElements.define('test-page', TestPage);
|