// 例 function quiz() { const QTAG = "quiz2023"; var name = document.getElementById("name"), login = document.getElementById("login"), commit = document.getElementById("commit"), button = document.getElementById("push"), info = document.getElementById("info"), qbox = document.getElementById("question"), stage = document.getElementById("stage"); var conn, PORT=9124, server = location.hostname||"localhost"; server = 'www.koeki-prj.org'; server = 'tmp.iekei.org' var quiz; // クイズ全体を保持 var myquiz; // クライアントモードで受け取ったクイズ情報 var counthash; // 現在の問題のクライアント選択状況保持 var currentQ; // 現在の問題番号(添字) var clientchoice; // 解答者の選択一覧を保持 var servermode; // サーバのとき true function replID(id, content) { let elm = document.getElementById(id); if (elm) elm.textContent = content; } function disableRadio() { for (let r of document.querySelectorAll('input[name="answer"]')) r.disabled = true; } function resetChecked() { // すべての選択肢のcheckを外す for (let radio of document.querySelectorAll('input[name="answer"]')) { radio.checked = radio.disabled = false; // disabledも解除 radio.addEventListener("change", sendChoice, false); } for (let e of document.querySelectorAll(".bright")) { console.log(e); e.classList.remove("bright"); } } function setChoices(quiz) { for (let [k, v] of Object.entries(quiz)) { replID(k, v); } } function settoStorage(key, val) { let ls = localStorage.getItem(QTAG); ls = ls ? JSON.parse(ls) : {} ls[key] = val; localStorage.setItem(QTAG, JSON.stringify(ls)); console.log(`localStorage[${key}] <- ${val}`); } function showStorage(e) { let ls = localStorage.getItem(QTAG); console.log(`showstorage:ls=${ls}`); ls = ls ? JSON.parse(ls) : {} let lsc = ls.cleared; console.log(`lsc=${JSON.stringify(lsc)}`); info.textContent = lsc ? `${Object.keys(lsc).length}問正解` : "not found"; } function resetStorage(e) { localStorage.removeItem(QTAG); info.textContent = "Reset storage"; } function registerBingo() { // クライアントモードのみ let ls = localStorage.getItem(QTAG); ls = ls ? JSON.parse(ls) : {}; console.log(`ls=${ls}`); ls.cleared = ls.cleared||{}; let q = qbox.textContent; console.log(`qbox=${q}, lsq=${ls.cleared}`); ls.cleared[q.trim()] = 1; localStorage.setItem(QTAG, JSON.stringify(ls)); } function resetParentValues() { counthash = {}; clientchoice = {}; console.log(`cQ=${currentQ}, qz=${quiz}`); //setChoices(quiz[currentQ]); sendto({"setquiz": currentQ}); setChoices(quiz[currentQ]); for (let e of document.getElementsByTagName("meter")) e.value = 0; // 解答数メーターを0にする } function parentSetupStage() { let e; e = qbox.querySelector("select"); if (e) e.remove(); // select要素を新規作成して問題文を入れていく let select = document.createElement("select"), n = 0; while (e = document.querySelector('input[type="radio"]')) { // クイズサーバ画面からはradioボタンを消す e.remove(); } for (let q of quiz) { let opt = document.createElement("option"); opt.textContent = q.question; delete q.question; // 親から不要なので消す opt.value = n++; select.appendChild(opt); } qbox.appendChild(select); select.addEventListener("change", (ev) => { currentQ = ev.target.value; resetParentValues(); }); console.log(`cQ=${currentQ}, so=${select.options}`); select.options[currentQ].selected = true; } function handleMessage(ev) { console.log(`data=${ev.data}`); try { var json = JSON.parse(ev.data) } catch (err) { // Do nothing... console.log("ERROR!"); return; } if (json.info) { info.textContent = json.info; } else if (json.q) { // サーバから問題集が送られて来た場合 quiz = json.q; currentQ = 0; parentSetupStage() resetParentValues(); } else if (json.setquiz) { // {setquiz: JSON...} myquiz = json.setquiz; console.log(`Got setquiz #${myquiz}`); qbox.textContent = myquiz.question; info.textContent = "問題!"; setChoices(myquiz); resetChecked(); } else if (json.select) { // クライアントからの選択報告 // {select: {name: クライアント名, choice: 選択番号}} let n = json.select.name, c = "choice"+json.select.choice; console.log(`cq=${currentQ}, CHOI: ${JSON.stringify(quiz[currentQ])}`); q = quiz[currentQ][c]; clientchoice[n] = c console.log(`quiz=${JSON.stringify(quiz)}`) info.textContent = `${n}さんが${q}を選びました。`; console.log(`clichoi=${JSON.stringify(clientchoice)}`); counthash = {}; for (let [name, choice] of Object.entries(clientchoice)) { counthash[choice] = counthash[choice]||0; counthash[choice]++; // 各選択肢を選んだ個数を得る } console.log(`counthash=${JSON.stringify(counthash)}`); for (let [key, val] of Object.entries(quiz[currentQ])) { // 各選択肢ごとに集計 let n = counthash[key]||0, meter = document.getElementById(`N-${key}`); if (meter) { meter.value = n; meter.textContent = `${n}人`; // 非グラフィック端末用 } } } else if (json.check) { // サーバからの正解発表 let myanswer, rans=json.check.rightanswer; for (let btn of document.getElementsByName("answer")) { if (btn.checked) { myanswer = btn.value; break; } } let rchoice = document.getElementById(`choice${rans}`) if (rchoice) rchoice.parentNode.parentNode.classList.add("bright"); if (myanswer) { disableRadio(); let ra = myquiz[`choice${rans}`] info.textContent = `残念...正解は「${ra}」`; if (myanswer == rans) { info.textContent = ("正解!"); registerBingo(); } else { } } else { info.innerText = "(時間切れ)"; } info.innerText += `\n${json.check.comment}`; } else if (json.result) { // 結果発表! showStorage(); } } function LRbtn(e) { let dir = parseInt(e.target.value); let sel = document.querySelector("select"); if (!sel) return; let last = currentQ; currentQ += dir; currentQ = Math.max(0, Math.min(sel.options.length-1, currentQ)); sel.options[currentQ].selected = true; if (currentQ != last) resetParentValues(); } function hideLogin() { stage.style.display = "block"; login.style.display = "none"; } function showLogin() { stage.style.display = "none"; login.style.display = "block"; } function initConn(afterinit) { try { if (location.hostname) { console.log(`Connecting to wss://${server}`); conn = new WebSocket('wss://' + server + ':' + '/quiz2023'); } else { conn = new WebSocket('ws://' + server + ':' + PORT + '/'); } conn.onopen = function() { let suffix = document.URL.match(/\?(.*)/); console.log(`suffix=${suffix}`); if (suffix) { servermode = true; sendto({"mode": RegExp.$1}); if (!document.getElementById("reset")) { let reset = document.createElement("button"); stage.appendChild(reset); reset.textContent = reset.id = "reset"; reset.addEventListener("click", (e) => { localStorage.removeItem(QTAG); }); let result = document.createElement("button"); stage.appendChild(result); result.textContent = result.id = "RESULT"; result.addEventListener("click", (e) => { sendto({"result": true}); }); document.body.classList.add("server"); } } else { // Remove <meter>s on clientmode let m; while (m=document.querySelector("meter")) m.remove(); button.style.display = "none"; document.getElementById("right").style.display = document.getElementById("left").style.display = "none"; } button.classList.remove("warn"); button.textContent = "正解発表"; if (afterinit) (afterinit)(); }; // Nothing special conn.onerror = function(err) { alert('WebSocket failure: ' + err) }; conn.onmessage = handleMessage; conn.onclose = function(ev) { info.textContent = "接続断: 少し待って再接続ボタンを押してください。"; button.style.display = null; button.textContent = "サーバへ再接続"; button.classList.add("warn"); conn = null; }; info.textContent = "..."; } catch (err) { alert("Socket Creation Error\n\ Firefoxですか? URLウィンドウに about:config と入れて\n\ Search: 窓に websocket と入れて、\n\ network..websocket.allowInsecureFromHTTP\n\ の行をダブルクリックして true に変えてください。\n" + err); } } function sendto(json) { let str = JSON.stringify(json); console.log(`sending: ${str}`) conn.send(str); } function setName(e) { if (!name.value || name.value=="") { alert("何か名前を入れてください!"); } else { sendto({name: name.value}); if (!servermode) sendto({"getquiz": null}); hideLogin(); } } function sendChoice(e) { let ans = e.target.value; console.log(`answer = ${ans}`); sendto({"select": ans}); } function check(ev) { if (!conn) initConn(setName); if (servermode) { sendto({"check": { "rightanswer": quiz[currentQ].answer, "comment": quiz[currentQ].comment}}); settoStorage(currentQ, counthash); } } commit.addEventListener("mousedown", setName, false); button.addEventListener("mousedown", check, false); let cr = document.getElementById("copyright"); cr.addEventListener("mouseover", showStorage, false); cr.addEventListener("click", resetStorage, false); for (let i of ["left", "right"]) document.getElementById(i).addEventListener("click", LRbtn, false); resetChecked(); initConn(); } document.addEventListener("DOMContentLoaded", quiz, false);