const cssVars = (document.body.getAttribute('data-css-vars') ?? 'x6,x8,xc').split(',');
const cssA = cssVars[0]; // 答案欄位
const cssN = cssVars[1]; // 題號欄位
const cssQ = cssVars[2]; // 選項欄位
// 等待 DOM 載入完成後再執行
document.addEventListener('DOMContentLoaded', function () {
// 動態加入 CSS style 區塊
const style = document.createElement('style');
style.innerHTML = `
:root {
--font-size-title: 10pt;
--font-size-button: 8pt;
--font-size-timer: 14pt;
--font-size-control: 9pt;
--font-size-stats: 9.5pt;
}
.control-panel {
position: fixed;
top: 4px;
left: 4px;
background-color: rgba(0, 0, 0, 0.6);
padding: 4px;
border-radius: 8px;
color: white;
font-family: Arial, sans-serif;
z-index: 9999;
width: 100px;
height: 100vh;
display: flex;
flex-direction: column;
text-align: center;
}
.control-panel .title {
margin: 0 6px;
font-size: var(--font-size-title);
width: 80px;
button {
font-size: var(--font-size-button);
padding: 0px 4px;
}
#timer {
font-family: 'Digital7', monospace;
font-size: 28px;
color: #00ff00;
background-color: rgba(0, 0, 0, 0.8);
padding: 4px 8px;
border-radius: 4px;
}
.control {
margin-top: 6px;
font-size: var(--font-size-control);
}
}
.control-panel #stats {
flex: 1;
display: flex;
flex-direction: row;
flex-wrap: wrap;
font-size: var(--font-size-stats);
gap: 6px;
margin-top: 12px;
padding-right: 4px;
align-content: flex-start;
margin-left: 4px;
.no {
cursor: pointer;
width: calc(25% - 6px);
text-align: center;
&.empty {
color: #bbb;
}
&.filled {
color: yellow;
}
}
}
.wrong {
position: relative;
.should {
color: red;
position: absolute;
left: 0.9em;
}
}
.slash {
position: relative;
display: inline-block;
color: gray;
}
.slash::after {
content: '';
position: absolute;
top: -0.3em;
left: -0.2em;
width: 1em;
height: 1.2em;
border-left: 4px solid red;
transform: rotate(45deg);
transform-origin: left bottom;
}
#result {
color: white;
}
.q-option{
cursor: pointer;
&:hover {
text-decoration: underline;
color: blue;
}
}
[cloak] .x6 { display: none; }
@font-face {
font-family: 'Digital7';
src: url('../digital_7mono.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap; /* 改善載入效能 */
}
`;
document.head.appendChild(style);
// 使用 innerHTML 定義 DOM
const controlPanel = document.createElement('div');
controlPanel.className = 'control-panel';
controlPanel.innerHTML = `
`;
// 將控制區插入到頁面
document.body.appendChild(controlPanel);
scanQuestions();
controlPanel.addEventListener('click', function (event) {
if (event.target.classList.contains('no')) {
const qNo = event.target.textContent;
const qBody = document.querySelector(`.q-body[data-no='${qNo}']`);
if (qBody) {
const page = qBody.closest('.pf');
if (page) {
page.scrollIntoView({ behavior: 'smooth' });
}
qBody.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
if (event.target.tagName === 'BUTTON') {
CheckAnswers();
}
});
updateTimer();
});
function CheckAnswers() {
document.querySelectorAll('.q-option').forEach(el => {
el.classList.remove('q-option');
});
event.target.disabled = true;
clearInterval(timerHandle);
const ansFields = document.querySelectorAll(`.q-ans`);
let correctCount = 0;
ansFields.forEach(el => {
const no = el.getAttribute('data-no');
const ans = el.getAttribute('data-ans');
const userAns = el.textContent.trim();
if (userAns === ans) {
el.style.color = 'green';
document.querySelector('#stats .no[data-no="' + no + '"]').style.color = 'lightgreen';
correctCount++;
} else {
el.style.color = 'red';
el.style.fontWeight = 'bold';
el.style.webkitTextStroke = '0px transparent';
el.innerHTML = `${userAns}${ans}`;
document.querySelector('#stats .no[data-no="' + no + '"]').style.color = 'orange';
}
});
const score = ((correctCount / ansFields.length) * 100).toFixed(0);
document.getElementById('result').innerHTML = `得分:${score} 分`;
}
const storageKey = 'stats-' + window.location.pathname;
class SessionState {
constructor() {
this.answers = [];
this.seconds = 0;
}
}
function saveSessionState() {
localStorage.setItem(storageKey, JSON.stringify(stat));
}
let stat = JSON.parse(localStorage.getItem(storageKey)) || new SessionState();
function updateTimer() {
const mins = Math.floor(stat.seconds / 60);
const secs = stat.seconds % 60;
document.getElementById('timer').textContent = `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
stat.seconds++;
saveSessionState();
}
const timerHandle = setInterval(updateTimer, 1000);
const emptyChar = '?';
function updateStats() {
const ansFields = document.querySelectorAll(`.q-ans`);
let filledCount = 0;
stat.answers = [];
const html = [...ansFields].map(el => {
const no = el.getAttribute('data-no');
const ans = el.getAttribute('data-ans');
const userAns = el.textContent.trim();
const filled = (userAns !== emptyChar);
if (filled) filledCount++;
const flag = filled ? 'filled' : 'empty';
stat.answers.push({ no, ans: filled ? userAns : '' });
return `${no}
`;
});
saveSessionState();
document.getElementById('stats').innerHTML = html.join('');
}
function scanQuestions() {
// 最後一頁的 .h0 會覆蓋在最上方,移除之
[...document.querySelectorAll('.pc .h0')].pop().remove();
// 尋找題號欄
let i = 0;
[...document.querySelectorAll(`.${cssN}`)]
.map(el => {
// 偵測是否以題號開頭(例如 "1."、"2." 等)
const m = el.textContent.trim().match(/^\d+\.?$/);
i++;
if (m) {
// 前一欄 td 為答案欄位
const qAns = el.previousElementSibling;
el.classList.add('q-no');
// 下一欄為題目內容
const qBody = el.nextElementSibling;
if (qBody) {
qBody.classList.add(`q-body`);
const qNo = m[0].replace('.', '');
qBody.setAttribute('data-no', qNo);
const ans = qAns ? qAns.textContent.trim() : 'N/A';
qBody.setAttribute('data-ans', ans);
qAns.setAttribute('data-no', qNo);
const ansField = qAns.querySelector('div');
if (ansField) {
ansField.classList.add('q-ans');
ansField.textContent = stat.answers.find(a => a.no === qNo)?.ans || emptyChar;
ansField.setAttribute('data-ans', ans);
ansField.setAttribute('data-no', qNo);
}
}
}
});
document.body.removeAttribute('cloak');
// 處理跨頁題目
[...document.querySelectorAll(`.${cssQ}`)]
.filter(el => !el.classList.contains('q-body'))
.map(el => {
let prev = el.previousElementSibling;
while (prev && !prev?.classList?.contains('q-body')) {
prev = prev.previousElementSibling;
}
if (prev == null) {
let prevPage = el.closest('.pf');
var qBodys = prevPage.previousElementSibling?.querySelectorAll('.q-body');
prev = qBodys ? qBodys[qBodys.length - 1] : null;
}
if (prev?.classList?.contains('q-body')) {
el.classList.add('q-body');
el.setAttribute('data-no', prev.getAttribute('data-no'));
el.setAttribute('data-ans', prev.getAttribute('data-ans'));
}
});
document.querySelectorAll('.q-body div').forEach(el => {
// el.style.border = '1px dashed blue';
const text = el.textContent.trim();
const m = text.match(/^\([A-D]\)/);
if (m) {
el.classList.add('q-option');
el.setAttribute('data-option', m[0].replace(/[()]/g, ''));
const qNo = el.closest('.q-body').getAttribute('data-no');
el.setAttribute('data-no', qNo);
}
});
updateStats();
}
document.addEventListener('click', function (event) {
const target = event.target;
const option = target.closest('.q-option');
if (option) {
const qNo = option.getAttribute('data-no');
const qAns = document.querySelector(`.q-ans[data-no='${qNo}']`);
if (qAns) {
qAns.textContent = option.getAttribute('data-option');
updateStats();
}
}
});