From 5db319a86e65e8039879fc720eea48ab8eec7a4b Mon Sep 17 00:00:00 2001 From: Geoffrey Wu Date: Sun, 27 Oct 2024 23:01:32 -0400 Subject: [PATCH] fix #304: add % option to multiplayer --- client/multiplayer/room.jsx | 19 ++-- client/multiplayer/room.min.js | 8 +- client/scripts/components/CategoryModal.jsx | 45 +++++---- .../scripts/components/CategoryModal.min.js | 2 +- client/singleplayer/ClientTossupRoom.js | 2 +- client/singleplayer/tossups/index.jsx | 9 +- client/singleplayer/tossups/index.min.js | 5 +- quizbowl/TossupRoom.js | 37 +++++--- quizbowl/category-manager.js | 92 ++++++++++--------- server/multiplayer/ServerTossupRoom.js | 6 +- 10 files changed, 133 insertions(+), 92 deletions(-) diff --git a/client/multiplayer/room.jsx b/client/multiplayer/room.jsx index 8b095f04..a53a1c07 100644 --- a/client/multiplayer/room.jsx +++ b/client/multiplayer/room.jsx @@ -11,6 +11,7 @@ import DifficultyDropdown from '../scripts/components/DifficultyDropdown.min.js' const categoryManager = new CategoryManager(); let oldCategories = JSON.stringify(categoryManager.export()); +let startingDifficulties = []; let maxPacketNumber = 24; @@ -232,10 +233,11 @@ async function connectionAcknowledgedQuery ({ standardOnly, alternateSubcategories, categories, - subcategories + subcategories, + percentView, + categoryPercents }) { setDifficulties({ difficulties }); - $('#slider').slider('values', 0, minYear); $('#slider').slider('values', 1, maxYear); document.getElementById('year-range-a').textContent = minYear; @@ -259,7 +261,7 @@ async function connectionAcknowledgedQuery ({ document.getElementById('toggle-standard-only').checked = standardOnly; - categoryManager.import(categories, subcategories, alternateSubcategories); + categoryManager.import({ categories, subcategories, alternateSubcategories, percentView, categoryPercents }); categoryManager.loadCategoryModal(); } @@ -543,15 +545,20 @@ function sortPlayerListGroup (descending = true) { }); } -function setCategories ({ alternateSubcategories, categories, subcategories, username }) { +function setCategories ({ alternateSubcategories, categories, subcategories, percentView, categoryPercents, username }) { logEvent(username, 'updated the categories'); - categoryManager.import(categories, subcategories, alternateSubcategories); + categoryManager.import({ categories, subcategories, alternateSubcategories, percentView, categoryPercents }); categoryManager.loadCategoryModal(); } function setDifficulties ({ difficulties, username = undefined }) { if (username) { logEvent(username, difficulties.length > 0 ? `set the difficulties to ${difficulties}` : 'cleared the difficulties'); } + if (!document.getElementById('difficulties')) { + startingDifficulties = difficulties; + return; + } + Array.from(document.getElementById('difficulties').children).forEach(li => { const input = li.querySelector('input'); if (difficulties.includes(parseInt(input.value))) { @@ -997,7 +1004,6 @@ document.getElementById('username').value = username; ReactDOM.createRoot(document.getElementById('category-modal-root')).render( { if (oldCategories !== JSON.stringify(categoryManager.export())) { socket.send(JSON.stringify({ type: 'set-categories', ...categoryManager.export() })); @@ -1009,6 +1015,7 @@ ReactDOM.createRoot(document.getElementById('category-modal-root')).render( ReactDOM.createRoot(document.getElementById('difficulty-dropdown-root')).render( socket.send(JSON.stringify({ type: 'set-difficulties', difficulties: getDropdownValues('difficulties') }))} /> ); diff --git a/client/multiplayer/room.min.js b/client/multiplayer/room.min.js index 9d2fcb18..b9474497 100644 --- a/client/multiplayer/room.min.js +++ b/client/multiplayer/room.min.js @@ -1,8 +1,8 @@ -import account from"../scripts/accounts.js";import questionStats from"../scripts/auth/question-stats.js";import api from"../scripts/api/index.js";import audio from"../audio/index.js";import CategoryManager from"../../quizbowl/category-manager.js";import{getDropdownValues}from"../scripts/utilities/dropdown-checklist.js";import{arrayToRange,createTossupCard,rangeToArray}from"../scripts/utilities/index.js";import{escapeHTML}from"../scripts/utilities/strings.js";import CategoryModal from"../scripts/components/CategoryModal.min.js";import DifficultyDropdown from"../scripts/components/DifficultyDropdown.min.js";const categoryManager=new CategoryManager;let oldCategories=JSON.stringify(categoryManager.export()),maxPacketNumber=24;/** +import account from"../scripts/accounts.js";import questionStats from"../scripts/auth/question-stats.js";import api from"../scripts/api/index.js";import audio from"../audio/index.js";import CategoryManager from"../../quizbowl/category-manager.js";import{getDropdownValues}from"../scripts/utilities/dropdown-checklist.js";import{arrayToRange,createTossupCard,rangeToArray}from"../scripts/utilities/index.js";import{escapeHTML}from"../scripts/utilities/strings.js";import CategoryModal from"../scripts/components/CategoryModal.min.js";import DifficultyDropdown from"../scripts/components/DifficultyDropdown.min.js";const categoryManager=new CategoryManager;let oldCategories=JSON.stringify(categoryManager.export()),startingDifficulties=[],maxPacketNumber=24;/** * userId to player object */const players={},ROOM_NAME=decodeURIComponent(window.location.pathname.substring(13));let tossup={},USER_ID=window.localStorage.getItem("USER_ID")||"unknown",username=window.localStorage.getItem("multiplayer-username")||api.getRandomName();const socket=new window.WebSocket(window.location.href.replace("http","ws")+(window.location.href.endsWith("?private=true")?"&":"?")+new URLSearchParams({roomName:ROOM_NAME,userId:USER_ID,username}).toString()),PING_INTERVAL_ID=setInterval(()=>socket.send(JSON.stringify({type:"ping"})),45e3);// Ping server every 45 seconds to prevent socket disconnection -socket.onclose=function(a){const{code:b}=a;3e3!==b&&window.alert("Disconnected from server"),clearInterval(PING_INTERVAL_ID)},socket.onmessage=function(a){const b=JSON.parse(a.data);switch(b.type){case"buzz":return buzz(b);case"force-username":return forceUsername(b);case"chat":return chat(b,!1);case"chat-live-update":return chat(b,!0);case"clear-stats":return clearStats(b);case"connection-acknowledged":return connectionAcknowledged(b);case"connection-acknowledged-query":return connectionAcknowledgedQuery(b);case"connection-acknowledged-tossup":return connectionAcknowledgedTossup(b);case"end-of-set":return endOfSet(b);case"error":return handleError(b);case"give-answer":return giveAnswer(b);case"give-answer-live-update":return logGiveAnswer(b,!0);case"join":return join(b);case"leave":return leave(b);case"lost-buzzer-race":return lostBuzzerRace(b);case"next":return next(b);case"no-questions-found":return noQuestionsFound(b);case"pause":return pause(b);case"reveal-answer":return revealAnswer(b);case"set-categories":return setCategories(b);case"set-difficulties":return setDifficulties(b);case"set-reading-speed":return setReadingSpeed(b);case"set-packet-numbers":return setPacketNumbers(b);case"set-strictness":return setStrictness(b);case"set-set-name":return setSetName(b);case"set-username":return setUsername(b);case"set-year-range":return setYearRange(b);case"skip":return next(b);case"start":return next(b);case"timer-update":return updateTimerDisplay(b.timeRemaining);case"toggle-lock":return toggleLock(b);case"toggle-login-required":return toggleLoginRequired(b);case"toggle-powermark-only":return togglePowermarkOnly(b);case"toggle-public":return togglePublic(b);case"toggle-rebuzz":return toggleRebuzz(b);case"toggle-select-by-set-name":return toggleSelectBySetName(b);case"toggle-skip":return toggleSkip(b);case"toggle-standard-only":return toggleStandardOnly(b);case"toggle-timer":return toggleTimer(b);case"update-question":return updateQuestion(b)}};function buzz({userId:a,username:b}){logEvent(b,"buzzed"),document.getElementById("buzz").disabled=!0,document.getElementById("pause").disabled=!0,document.getElementById("next").disabled=!0,document.getElementById("skip").disabled=!0,a===USER_ID&&(document.getElementById("answer-input-group").classList.remove("d-none"),document.getElementById("answer-input").focus())}function chat({message:a,userId:c,username:d},e=!1){if(!e&&""===a)return void document.getElementById("live-chat-"+c).parentElement.remove();if(!e&&a)return document.getElementById("live-chat-"+c).className="",void(document.getElementById("live-chat-"+c).id="");if(document.getElementById("live-chat-"+c))return void(document.getElementById("live-chat-"+c).textContent=a);const f=document.createElement("b");f.textContent=d;const b=document.createElement("span");b.classList.add("text-muted"),b.id="live-chat-"+c,b.textContent=a;const g=document.createElement("li");g.appendChild(f),g.appendChild(document.createTextNode(" ")),g.appendChild(b),document.getElementById("room-history").prepend(g)}function clearStats({userId:a}){for(const b of["celerity","negs","points","powers","tens","tuh","zeroes"])players[a][b]=0;upsertPlayerItem(players[a]),sortPlayerListGroup()}function connectionAcknowledged({buzzedIn:a,canBuzz:b,isPermanent:c,players:d,questionProgress:e,settings:f,userId:g}){document.getElementById("buzz").disabled=!b,c&&(document.getElementById("category-select-button").disabled=!0,document.getElementById("strictness").disabled=!0,document.getElementById("toggle-public").disabled=!0,document.getElementById("toggle-select-by-set-name").disabled=!0,document.getElementById("private-chat-warning").innerHTML="This is a permanent room. Some settings have been restricted."),Object.keys(d).forEach(a=>{d[a].celerity=d[a].celerity.correct.average,players[a]=d[a],upsertPlayerItem(players[a])}),sortPlayerListGroup();0===e?(document.getElementById("next").textContent="Start",document.getElementById("next").classList.remove("btn-primary"),document.getElementById("next").classList.add("btn-success")):1===e?(showSkipButton(),document.getElementById("settings").classList.add("d-none"),a?(document.getElementById("buzz").disabled=!0,document.getElementById("next").disabled=!0,document.getElementById("pause").disabled=!0):(document.getElementById("buzz").disabled=!1,document.getElementById("pause").disabled=!1)):2===e?(showNextButton(),document.getElementById("settings").classList.add("d-none")):void 0;document.getElementById("toggle-lock").checked=f.lock,document.getElementById("toggle-login-required").checked=f.loginRequired,document.getElementById("chat").disabled=f.public,document.getElementById("toggle-lock").disabled=f.public,document.getElementById("toggle-login-required").disabled=f.public,document.getElementById("toggle-timer").disabled=f.public,document.getElementById("toggle-public").checked=f.public,document.getElementById("reading-speed").value=f.readingSpeed,document.getElementById("reading-speed-display").textContent=f.readingSpeed,document.getElementById("strictness").value=f.strictness,document.getElementById("strictness-display").textContent=f.strictness,document.getElementById("toggle-rebuzz").checked=f.rebuzz,document.getElementById("toggle-skip").checked=f.skip,document.getElementById("timer").classList.toggle("d-none",!f.timer),document.getElementById("toggle-timer").checked=f.timer,USER_ID=g,window.localStorage.setItem("USER_ID",USER_ID)}async function connectionAcknowledgedQuery({difficulties:i=[],minYear:a,maxYear:b,packetNumbers:j=[],powermarkOnly:c,selectBySetName:d,setName:k="",standardOnly:e,alternateSubcategories:f,categories:g,subcategories:h}){setDifficulties({difficulties:i}),$("#slider").slider("values",0,a),$("#slider").slider("values",1,b),document.getElementById("year-range-a").textContent=a,document.getElementById("year-range-b").textContent=b,document.getElementById("packet-number").value=arrayToRange(j),document.getElementById("toggle-powermark-only").checked=c,document.getElementById("difficulty-settings").classList.toggle("d-none",d),document.getElementById("set-settings").classList.toggle("d-none",!d),document.getElementById("toggle-select-by-set-name").checked=d,document.getElementById("toggle-powermark-only").disabled=d,document.getElementById("toggle-standard-only").disabled=d,document.getElementById("set-name").value=k,maxPacketNumber=await api.getNumPackets(k),""!==k&&0===maxPacketNumber&&document.getElementById("set-name").classList.add("is-invalid"),document.getElementById("toggle-standard-only").checked=e,categoryManager.import(g,h,f),categoryManager.loadCategoryModal()}function connectionAcknowledgedTossup({tossup:a}){tossup=a,document.getElementById("set-name-info").textContent=tossup?.set?.name??"",document.getElementById("packet-number-info").textContent=tossup?.packet?.number??"-",document.getElementById("question-number-info").textContent=tossup?.number??"-"}function endOfSet(){window.alert("You have reached the end of the set")}function forceUsername({message:a,username:b}){window.alert(a),window.localStorage.setItem("multiplayer-username",b),document.querySelector("#username").value=b}async function giveAnswer({celerity:a,directive:b,directedPrompt:c,givenAnswer:d,perQuestionCelerity:e,score:f,tossup:g,userId:h,username:i}){document.getElementById("answer-input").value="",document.getElementById("answer-input-group").classList.add("d-none"),document.getElementById("answer-input").blur(),logGiveAnswer({directive:b,message:d,username:i}),"prompt"===b&&c?logEvent(i,`was prompted with "${c}"`):"prompt"===b?logEvent(i,"was prompted"):logEvent(i,`${0{a.textContent=parseInt(a.innerHTML)+1})),"reject"===b&&(document.getElementById("buzz").disabled=!document.getElementById("toggle-rebuzz").checked&&h===USER_ID),10f&&players[h].negs++,players[h].points+=f,players[h].tuh++,players[h].celerity=a,upsertPlayerItem(players[h]),sortPlayerListGroup()),"prompt"!==b&&h===USER_ID&&(await account.getUsername())&&questionStats.recordTossup(g,0{const b=parseInt(document.getElementById("points-"+d.id.substring(f)).innerHTML),e=parseInt(document.getElementById("points-"+a.id.substring(f)).innerHTML);// if points are equal, sort alphabetically by username -if(b===e){const b=document.getElementById("username-"+d.id.substring(f)).innerHTML,e=document.getElementById("username-"+a.id.substring(f)).innerHTML;return c?b.localeCompare(e):e.localeCompare(b)}return c?e-b:b-e}).forEach(a=>{d.appendChild(a)})}function setCategories({alternateSubcategories:a,categories:b,subcategories:c,username:d}){logEvent(d,"updated the categories"),categoryManager.import(b,c,a),categoryManager.loadCategoryModal()}function setDifficulties({difficulties:a,username:b=void 0}){b&&logEvent(b,0{const c=b.querySelector("input");a.includes(parseInt(c.value))?(c.checked=!0,b.classList.add("active")):(c.checked=!1,b.classList.remove("active"))})}function setPacketNumbers({username:a,packetNumbers:b}){b=arrayToRange(b),logEvent(a,0{d[a].celerity=d[a].celerity.correct.average,players[a]=d[a],upsertPlayerItem(players[a])}),sortPlayerListGroup();0===e?(document.getElementById("next").textContent="Start",document.getElementById("next").classList.remove("btn-primary"),document.getElementById("next").classList.add("btn-success")):1===e?(showSkipButton(),document.getElementById("settings").classList.add("d-none"),a?(document.getElementById("buzz").disabled=!0,document.getElementById("next").disabled=!0,document.getElementById("pause").disabled=!0):(document.getElementById("buzz").disabled=!1,document.getElementById("pause").disabled=!1)):2===e?(showNextButton(),document.getElementById("settings").classList.add("d-none")):void 0;document.getElementById("toggle-lock").checked=f.lock,document.getElementById("toggle-login-required").checked=f.loginRequired,document.getElementById("chat").disabled=f.public,document.getElementById("toggle-lock").disabled=f.public,document.getElementById("toggle-login-required").disabled=f.public,document.getElementById("toggle-timer").disabled=f.public,document.getElementById("toggle-public").checked=f.public,document.getElementById("reading-speed").value=f.readingSpeed,document.getElementById("reading-speed-display").textContent=f.readingSpeed,document.getElementById("strictness").value=f.strictness,document.getElementById("strictness-display").textContent=f.strictness,document.getElementById("toggle-rebuzz").checked=f.rebuzz,document.getElementById("toggle-skip").checked=f.skip,document.getElementById("timer").classList.toggle("d-none",!f.timer),document.getElementById("toggle-timer").checked=f.timer,USER_ID=g,window.localStorage.setItem("USER_ID",USER_ID)}async function connectionAcknowledgedQuery({difficulties:k=[],minYear:a,maxYear:b,packetNumbers:l=[],powermarkOnly:c,selectBySetName:d,setName:m="",standardOnly:e,alternateSubcategories:f,categories:g,subcategories:h,percentView:i,categoryPercents:j}){setDifficulties({difficulties:k}),$("#slider").slider("values",0,a),$("#slider").slider("values",1,b),document.getElementById("year-range-a").textContent=a,document.getElementById("year-range-b").textContent=b,document.getElementById("packet-number").value=arrayToRange(l),document.getElementById("toggle-powermark-only").checked=c,document.getElementById("difficulty-settings").classList.toggle("d-none",d),document.getElementById("set-settings").classList.toggle("d-none",!d),document.getElementById("toggle-select-by-set-name").checked=d,document.getElementById("toggle-powermark-only").disabled=d,document.getElementById("toggle-standard-only").disabled=d,document.getElementById("set-name").value=m,maxPacketNumber=await api.getNumPackets(m),""!==m&&0===maxPacketNumber&&document.getElementById("set-name").classList.add("is-invalid"),document.getElementById("toggle-standard-only").checked=e,categoryManager.import({categories:g,subcategories:h,alternateSubcategories:f,percentView:i,categoryPercents:j}),categoryManager.loadCategoryModal()}function connectionAcknowledgedTossup({tossup:a}){tossup=a,document.getElementById("set-name-info").textContent=tossup?.set?.name??"",document.getElementById("packet-number-info").textContent=tossup?.packet?.number??"-",document.getElementById("question-number-info").textContent=tossup?.number??"-"}function endOfSet(){window.alert("You have reached the end of the set")}function forceUsername({message:a,username:b}){window.alert(a),window.localStorage.setItem("multiplayer-username",b),document.querySelector("#username").value=b}async function giveAnswer({celerity:a,directive:b,directedPrompt:c,givenAnswer:d,perQuestionCelerity:e,score:f,tossup:g,userId:h,username:i}){document.getElementById("answer-input").value="",document.getElementById("answer-input-group").classList.add("d-none"),document.getElementById("answer-input").blur(),logGiveAnswer({directive:b,message:d,username:i}),"prompt"===b&&c?logEvent(i,`was prompted with "${c}"`):"prompt"===b?logEvent(i,"was prompted"):logEvent(i,`${0{a.textContent=parseInt(a.innerHTML)+1})),"reject"===b&&(document.getElementById("buzz").disabled=!document.getElementById("toggle-rebuzz").checked&&h===USER_ID),10f&&players[h].negs++,players[h].points+=f,players[h].tuh++,players[h].celerity=a,upsertPlayerItem(players[h]),sortPlayerListGroup()),"prompt"!==b&&h===USER_ID&&(await account.getUsername())&&questionStats.recordTossup(g,0{const b=parseInt(document.getElementById("points-"+d.id.substring(f)).innerHTML),e=parseInt(document.getElementById("points-"+a.id.substring(f)).innerHTML);// if points are equal, sort alphabetically by username +if(b===e){const b=document.getElementById("username-"+d.id.substring(f)).innerHTML,e=document.getElementById("username-"+a.id.substring(f)).innerHTML;return c?b.localeCompare(e):e.localeCompare(b)}return c?e-b:b-e}).forEach(a=>{d.appendChild(a)})}function setCategories({alternateSubcategories:a,categories:b,subcategories:c,percentView:d,categoryPercents:e,username:f}){logEvent(f,"updated the categories"),categoryManager.import({categories:b,subcategories:c,alternateSubcategories:a,percentView:d,categoryPercents:e}),categoryManager.loadCategoryModal()}function setDifficulties({difficulties:a,username:b=void 0}){return b&&logEvent(b,0{const c=b.querySelector("input");a.includes(parseInt(c.value))?(c.checked=!0,b.classList.add("active")):(c.checked=!1,b.classList.remove("active"))}):void(startingDifficulties=a)}function setPacketNumbers({username:a,packetNumbers:b}){b=arrayToRange(b),logEvent(a,0 @@ -32,4 +32,4 @@ k.className=`list-group-item ${b===USER_ID?"user-score":""} clickable`,k.id=`lis ${j.toFixed(3)} - `),document.getElementById("player-list-group").appendChild(k),new bootstrap.Popover(k)}function setYearRange({minYear:a,maxYear:b,username:c}){c&&logEvent(c,`changed the year range to ${a}-${b}`),$("#slider").slider("values",0,a),$("#slider").slider("values",1,b),document.getElementById("year-range-a").textContent=a,document.getElementById("year-range-b").textContent=b}document.getElementById("answer-form").addEventListener("submit",function(a){a.preventDefault(),a.stopPropagation();const b=document.getElementById("answer-input").value;socket.send(JSON.stringify({type:"give-answer",givenAnswer:b}))}),document.getElementById("answer-input").addEventListener("input",function(){socket.send(JSON.stringify({type:"give-answer-live-update",message:this.value}))}),document.getElementById("buzz").addEventListener("click",function(){this.blur(),audio.soundEffects&&audio.buzz.play(),socket.send(JSON.stringify({type:"buzz"})),socket.send(JSON.stringify({type:"give-answer-live-update",message:""}))}),document.getElementById("chat").addEventListener("click",function(){this.blur(),document.getElementById("chat-input-group").classList.remove("d-none"),document.getElementById("chat-input").focus(),socket.send(JSON.stringify({type:"chat-live-update",message:""}))}),document.getElementById("chat-form").addEventListener("submit",function(a){a.preventDefault(),a.stopPropagation();const b=document.getElementById("chat-input").value;document.getElementById("chat-input").value="",document.getElementById("chat-input-group").classList.add("d-none"),document.getElementById("chat-input").blur(),socket.send(JSON.stringify({type:"chat",message:b}))}),document.getElementById("chat-input").addEventListener("input",function(){socket.send(JSON.stringify({type:"chat-live-update",message:this.value}))}),document.getElementById("clear-stats").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"clear-stats"}))}),document.getElementById("next").addEventListener("click",function(){switch(this.blur(),this.innerHTML){case"Start":socket.send(JSON.stringify({type:"start"}));break;case"Next":socket.send(JSON.stringify({type:"next"}))}}),document.getElementById("skip").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"skip"}))}),document.getElementById("packet-number").addEventListener("change",function(){const a=rangeToArray(this.value,maxPacketNumber);return a.some(a=>1>a||a>maxPacketNumber)?void document.getElementById("packet-number").classList.add("is-invalid"):void(document.getElementById("packet-number").classList.remove("is-invalid"),socket.send(JSON.stringify({type:"set-packet-numbers",packetNumbers:a})))}),document.getElementById("pause").addEventListener("click",function(){this.blur();const a=parseFloat(document.querySelector(".timer .face").innerText),b=parseFloat(document.querySelector(".timer .fraction").innerText);socket.send(JSON.stringify({type:"pause",pausedTime:10*(a+b)}))}),document.getElementById("reading-speed").addEventListener("change",function(){socket.send(JSON.stringify({type:"set-reading-speed",readingSpeed:this.value}))}),document.getElementById("reading-speed").addEventListener("input",function(){document.getElementById("reading-speed-display").textContent=this.value}),document.getElementById("report-question-submit").addEventListener("click",function(){api.reportQuestion(document.getElementById("report-question-id").value,document.getElementById("report-question-reason").value,document.getElementById("report-question-description").value)}),document.getElementById("set-name").addEventListener("change",async function(){api.getSetList().includes(this.value)||0===this.value.length?this.classList.remove("is-invalid"):this.classList.add("is-invalid"),maxPacketNumber=await api.getNumPackets(this.value),document.getElementById("packet-number").value=""===this.value||0===maxPacketNumber?"":`1-${maxPacketNumber}`,socket.send(JSON.stringify({type:"set-set-name",setName:this.value,packetNumbers:rangeToArray(document.getElementById("packet-number").value)}))}),document.getElementById("strictness").addEventListener("change",function(){this.blur(),socket.send(JSON.stringify({type:"set-strictness",strictness:this.value}))}),document.getElementById("strictness").addEventListener("input",function(){document.getElementById("strictness-display").textContent=this.value}),document.getElementById("toggle-lock").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-lock",lock:this.checked}))}),document.getElementById("toggle-login-required").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-login-required",loginRequired:this.checked}))}),document.getElementById("toggle-powermark-only").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-powermark-only",powermarkOnly:this.checked}))}),document.getElementById("toggle-rebuzz").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-rebuzz",rebuzz:this.checked}))}),document.getElementById("toggle-skip").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-skip",skip:this.checked}))}),document.getElementById("toggle-select-by-set-name").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-select-by-set-name",setName:document.getElementById("set-name").value,selectBySetName:this.checked}))}),document.getElementById("toggle-settings").addEventListener("click",function(){this.blur(),document.getElementById("buttons").classList.toggle("col-lg-9"),document.getElementById("buttons").classList.toggle("col-lg-12"),document.getElementById("content").classList.toggle("col-lg-9"),document.getElementById("content").classList.toggle("col-lg-12"),document.getElementById("settings").classList.toggle("d-none"),document.getElementById("settings").classList.toggle("d-lg-none")}),document.getElementById("toggle-standard-only").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-standard-only",standardOnly:this.checked}))}),document.getElementById("toggle-timer").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-timer",timer:this.checked}))}),document.getElementById("toggle-public").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-public",public:this.checked}))}),document.getElementById("username").addEventListener("change",function(){socket.send(JSON.stringify({type:"set-username",userId:USER_ID,username:this.value})),username=this.value,window.localStorage.setItem("multiplayer-username",username)}),document.getElementById("year-range-a").onchange=function(){const[a,b]=$("#slider").slider("values");if(b{if("Escape"===a.key&&"chat-input"===document.activeElement.id&&(document.getElementById("chat-input").value="",document.getElementById("chat-input-group").classList.add("d-none"),document.getElementById("chat-input").blur(),socket.send(JSON.stringify({type:"chat",message:""}))),!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement.tagName))switch(a.key?.toLowerCase()){case" ":document.getElementById("buzz").click(),a.target===document.body&&a.preventDefault();break;case"e":return document.getElementById("toggle-settings").click();case"k":return document.getElementsByClassName("card-header-clickable")[0].click();case"p":return document.getElementById("pause").click();case"t":return document.getElementsByClassName("star-tossup")[0].click();case"y":return navigator.clipboard.writeText(tossup._id??"");case"n":case"s":document.getElementById("next").click(),document.getElementById("skip").click()}}),document.addEventListener("keypress",function(a){"Enter"===a.key&&a.target===document.body&&document.getElementById("chat").click()}),document.getElementById("username").value=username,ReactDOM.createRoot(document.getElementById("category-modal-root")).render(/*#__PURE__*/React.createElement(CategoryModal,{categoryManager:categoryManager,disablePercentView:!0,onClose:()=>{oldCategories!==JSON.stringify(categoryManager.export())&&socket.send(JSON.stringify({type:"set-categories",...categoryManager.export()})),oldCategories=JSON.stringify(categoryManager.export())}})),ReactDOM.createRoot(document.getElementById("difficulty-dropdown-root")).render(/*#__PURE__*/React.createElement(DifficultyDropdown,{onChange:()=>socket.send(JSON.stringify({type:"set-difficulties",difficulties:getDropdownValues("difficulties")}))})); \ No newline at end of file + `),document.getElementById("player-list-group").appendChild(k),new bootstrap.Popover(k)}function setYearRange({minYear:a,maxYear:b,username:c}){c&&logEvent(c,`changed the year range to ${a}-${b}`),$("#slider").slider("values",0,a),$("#slider").slider("values",1,b),document.getElementById("year-range-a").textContent=a,document.getElementById("year-range-b").textContent=b}document.getElementById("answer-form").addEventListener("submit",function(a){a.preventDefault(),a.stopPropagation();const b=document.getElementById("answer-input").value;socket.send(JSON.stringify({type:"give-answer",givenAnswer:b}))}),document.getElementById("answer-input").addEventListener("input",function(){socket.send(JSON.stringify({type:"give-answer-live-update",message:this.value}))}),document.getElementById("buzz").addEventListener("click",function(){this.blur(),audio.soundEffects&&audio.buzz.play(),socket.send(JSON.stringify({type:"buzz"})),socket.send(JSON.stringify({type:"give-answer-live-update",message:""}))}),document.getElementById("chat").addEventListener("click",function(){this.blur(),document.getElementById("chat-input-group").classList.remove("d-none"),document.getElementById("chat-input").focus(),socket.send(JSON.stringify({type:"chat-live-update",message:""}))}),document.getElementById("chat-form").addEventListener("submit",function(a){a.preventDefault(),a.stopPropagation();const b=document.getElementById("chat-input").value;document.getElementById("chat-input").value="",document.getElementById("chat-input-group").classList.add("d-none"),document.getElementById("chat-input").blur(),socket.send(JSON.stringify({type:"chat",message:b}))}),document.getElementById("chat-input").addEventListener("input",function(){socket.send(JSON.stringify({type:"chat-live-update",message:this.value}))}),document.getElementById("clear-stats").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"clear-stats"}))}),document.getElementById("next").addEventListener("click",function(){switch(this.blur(),this.innerHTML){case"Start":socket.send(JSON.stringify({type:"start"}));break;case"Next":socket.send(JSON.stringify({type:"next"}))}}),document.getElementById("skip").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"skip"}))}),document.getElementById("packet-number").addEventListener("change",function(){const a=rangeToArray(this.value,maxPacketNumber);return a.some(a=>1>a||a>maxPacketNumber)?void document.getElementById("packet-number").classList.add("is-invalid"):void(document.getElementById("packet-number").classList.remove("is-invalid"),socket.send(JSON.stringify({type:"set-packet-numbers",packetNumbers:a})))}),document.getElementById("pause").addEventListener("click",function(){this.blur();const a=parseFloat(document.querySelector(".timer .face").innerText),b=parseFloat(document.querySelector(".timer .fraction").innerText);socket.send(JSON.stringify({type:"pause",pausedTime:10*(a+b)}))}),document.getElementById("reading-speed").addEventListener("change",function(){socket.send(JSON.stringify({type:"set-reading-speed",readingSpeed:this.value}))}),document.getElementById("reading-speed").addEventListener("input",function(){document.getElementById("reading-speed-display").textContent=this.value}),document.getElementById("report-question-submit").addEventListener("click",function(){api.reportQuestion(document.getElementById("report-question-id").value,document.getElementById("report-question-reason").value,document.getElementById("report-question-description").value)}),document.getElementById("set-name").addEventListener("change",async function(){api.getSetList().includes(this.value)||0===this.value.length?this.classList.remove("is-invalid"):this.classList.add("is-invalid"),maxPacketNumber=await api.getNumPackets(this.value),document.getElementById("packet-number").value=""===this.value||0===maxPacketNumber?"":`1-${maxPacketNumber}`,socket.send(JSON.stringify({type:"set-set-name",setName:this.value,packetNumbers:rangeToArray(document.getElementById("packet-number").value)}))}),document.getElementById("strictness").addEventListener("change",function(){this.blur(),socket.send(JSON.stringify({type:"set-strictness",strictness:this.value}))}),document.getElementById("strictness").addEventListener("input",function(){document.getElementById("strictness-display").textContent=this.value}),document.getElementById("toggle-lock").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-lock",lock:this.checked}))}),document.getElementById("toggle-login-required").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-login-required",loginRequired:this.checked}))}),document.getElementById("toggle-powermark-only").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-powermark-only",powermarkOnly:this.checked}))}),document.getElementById("toggle-rebuzz").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-rebuzz",rebuzz:this.checked}))}),document.getElementById("toggle-skip").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-skip",skip:this.checked}))}),document.getElementById("toggle-select-by-set-name").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-select-by-set-name",setName:document.getElementById("set-name").value,selectBySetName:this.checked}))}),document.getElementById("toggle-settings").addEventListener("click",function(){this.blur(),document.getElementById("buttons").classList.toggle("col-lg-9"),document.getElementById("buttons").classList.toggle("col-lg-12"),document.getElementById("content").classList.toggle("col-lg-9"),document.getElementById("content").classList.toggle("col-lg-12"),document.getElementById("settings").classList.toggle("d-none"),document.getElementById("settings").classList.toggle("d-lg-none")}),document.getElementById("toggle-standard-only").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-standard-only",standardOnly:this.checked}))}),document.getElementById("toggle-timer").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-timer",timer:this.checked}))}),document.getElementById("toggle-public").addEventListener("click",function(){this.blur(),socket.send(JSON.stringify({type:"toggle-public",public:this.checked}))}),document.getElementById("username").addEventListener("change",function(){socket.send(JSON.stringify({type:"set-username",userId:USER_ID,username:this.value})),username=this.value,window.localStorage.setItem("multiplayer-username",username)}),document.getElementById("year-range-a").onchange=function(){const[a,b]=$("#slider").slider("values");if(b{if("Escape"===a.key&&"chat-input"===document.activeElement.id&&(document.getElementById("chat-input").value="",document.getElementById("chat-input-group").classList.add("d-none"),document.getElementById("chat-input").blur(),socket.send(JSON.stringify({type:"chat",message:""}))),!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement.tagName))switch(a.key?.toLowerCase()){case" ":document.getElementById("buzz").click(),a.target===document.body&&a.preventDefault();break;case"e":return document.getElementById("toggle-settings").click();case"k":return document.getElementsByClassName("card-header-clickable")[0].click();case"p":return document.getElementById("pause").click();case"t":return document.getElementsByClassName("star-tossup")[0].click();case"y":return navigator.clipboard.writeText(tossup._id??"");case"n":case"s":document.getElementById("next").click(),document.getElementById("skip").click()}}),document.addEventListener("keypress",function(a){"Enter"===a.key&&a.target===document.body&&document.getElementById("chat").click()}),document.getElementById("username").value=username,ReactDOM.createRoot(document.getElementById("category-modal-root")).render(/*#__PURE__*/React.createElement(CategoryModal,{categoryManager:categoryManager,onClose:()=>{oldCategories!==JSON.stringify(categoryManager.export())&&socket.send(JSON.stringify({type:"set-categories",...categoryManager.export()})),oldCategories=JSON.stringify(categoryManager.export())}})),ReactDOM.createRoot(document.getElementById("difficulty-dropdown-root")).render(/*#__PURE__*/React.createElement(DifficultyDropdown,{startingDifficulties:startingDifficulties,onChange:()=>socket.send(JSON.stringify({type:"set-difficulties",difficulties:getDropdownValues("difficulties")}))})); \ No newline at end of file diff --git a/client/scripts/components/CategoryModal.jsx b/client/scripts/components/CategoryModal.jsx index a6c03c04..65555623 100644 --- a/client/scripts/components/CategoryModal.jsx +++ b/client/scripts/components/CategoryModal.jsx @@ -62,9 +62,6 @@ const ALTERNATE_SUBCATEGORY_BUTTONS = [ ]; function CategoryModal ({ categoryManager, disablePercentView = false, onClose = () => {} }) { - const [percents, setPercents] = React.useState(CATEGORY_BUTTONS.map(element => 0)); - const [percentView, setPercentView] = React.useState(false); - React.useEffect(() => { categoryManager.loadCategoryModal(); document.getElementById('category-modal').addEventListener('hidden.bs.modal', onClose); @@ -74,24 +71,26 @@ function CategoryModal ({ categoryManager, disablePercentView = false, onClose = function handleClick () { if (categoryManager.categories.length === 0) { categoryManager.import( - CATEGORY_BUTTONS.map(element => element[0]), - SUBCATEGORY_BUTTONS.map(element => element[0]), - ALTERNATE_SUBCATEGORY_BUTTONS.map(element => element[0]) + { + categories: CATEGORY_BUTTONS.map(element => element[0]), + subcategories: SUBCATEGORY_BUTTONS.map(element => element[0]), + alternateSubcategories: ALTERNATE_SUBCATEGORY_BUTTONS.map(element => element[0]) + } ); } else { - categoryManager.import([], [], []); + categoryManager.import(); } categoryManager.loadCategoryModal(); } return ( - + ); } function TogglePercentView () { function handleClick () { - categoryManager.percentView = !percentView; - setPercentView(!percentView); + categoryManager.percentView = !categoryManager.percentView; + categoryManager.loadCategoryModal(); } return ( @@ -101,27 +100,29 @@ function CategoryModal ({ categoryManager, disablePercentView = false, onClose = function PercentButtonRow ({ category, index }) { function adjustPercent (amount) { // clamp the percent between 0 and 100 - const percent = Math.min(100, Math.max(0, percents[index] + amount)); - setPercents([...percents.slice(0, index), percent, ...percents.slice(index + 1)]); + const percent = Math.min(100, Math.max(0, categoryManager.categoryPercents[index] + amount)); categoryManager.categoryPercents[index] = percent; + categoryManager.loadCategoryModal(); } return ( {category} - {String(percents[index]).padStart(3, '\u00A0')}% + + {/* set by categoryManager.loadCategoryModal */} +
- + @@ -184,7 +185,7 @@ function CategoryModal ({ categoryManager, disablePercentView = false, onClose =
-
+
Category
{CATEGORY_BUTTONS.map((element) => )} @@ -201,7 +202,7 @@ function CategoryModal ({ categoryManager, disablePercentView = false, onClose = {ALTERNATE_SUBCATEGORY_BUTTONS.map((element) =>
-
+
{CATEGORY_BUTTONS.map((element, index) => )} @@ -209,8 +210,14 @@ function CategoryModal ({ categoryManager, disablePercentView = false, onClose = diff --git a/client/scripts/components/CategoryModal.min.js b/client/scripts/components/CategoryModal.min.js index d328e2ce..a902127b 100644 --- a/client/scripts/components/CategoryModal.min.js +++ b/client/scripts/components/CategoryModal.min.js @@ -1,2 +1,2 @@ const CATEGORY_BUTTONS=[["Literature","primary"],["History","success"],["Science","danger"],["Fine Arts","warning"],["Religion","secondary"],["Mythology","secondary"],["Philosophy","secondary"],["Social Science","secondary"],["Current Events","secondary"],["Geography","secondary"],["Other Academic","secondary"],["Trash","secondary"]],SUBCATEGORY_BUTTONS=[["American Literature","primary"],["British Literature","primary"],["Classical Literature","primary"],["European Literature","primary"],["World Literature","primary"],["Other Literature","primary"],["American History","success"],["Ancient History","success"],["European History","success"],["World History","success"],["Other History","success"],["Biology","danger"],["Chemistry","danger"],["Physics","danger"],["Other Science","danger"],["Visual Fine Arts","warning"],["Auditory Fine Arts","warning"],["Other Fine Arts","warning"]],ALTERNATE_SUBCATEGORY_BUTTONS=[["Drama","primary"],["Long Fiction","primary"],["Poetry","primary"],["Short Fiction","primary"],["Misc Literature","primary"],["Math","danger"],["Astronomy","danger"],["Computer Science","danger"],["Earth Science","danger"],["Engineering","danger"],["Misc Science","danger"],["Architecture","warning"],["Dance","warning"],["Film","warning"],["Jazz","warning"],["Opera","warning"],["Photography","warning"],["Misc Arts","warning"],["Anthropology","secondary"],["Economics","secondary"],["Linguistics","secondary"],["Psychology","secondary"],["Sociology","secondary"],["Other Social Science","secondary"]];function CategoryModal({categoryManager:a,disablePercentView:b=!1,onClose:c=()=>{}}){function d({category:b,index:c}){function d(b){// clamp the percent between 0 and 100 -const d=Math.min(100,Math.max(0,h[c]+b));i([...h.slice(0,c),d,...h.slice(c+1)]),a.categoryPercents[c]=d}return/*#__PURE__*/React.createElement("tr",null,/*#__PURE__*/React.createElement("th",{style:{width:"50%"}},b),/*#__PURE__*/React.createElement("td",{style:{width:"50%"}},/*#__PURE__*/React.createElement("span",{className:"font-monospace me-1"},(h[c]+"").padStart(3,"\xA0"),"%"),/*#__PURE__*/React.createElement("div",{class:"btn-group btn-group-sm me-1",role:"group"},/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(-5)},"-"),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(5)},"+")),/*#__PURE__*/React.createElement("div",{class:"btn-group btn-group-sm",role:"group"},/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(-100)},"Min"),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(50-h[c])},"50%"),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(100-h.reduce((c,a)=>c+a))},"Max"))))}function e({category:b,color:c}){return/*#__PURE__*/React.createElement("div",null,/*#__PURE__*/React.createElement("input",{type:"checkbox",className:"btn-check",autoComplete:"off",id:b,onClick:function(){a.updateCategory(b),a.loadCategoryModal()}}),/*#__PURE__*/React.createElement("label",{className:`btn btn-outline-${c} w-100 rounded-0 my-1`,htmlFor:b},b,/*#__PURE__*/React.createElement("br",null)))}function f({subcategory:b,color:c,hidden:d=!1}){return/*#__PURE__*/React.createElement("div",null,/*#__PURE__*/React.createElement("input",{type:"checkbox",className:"btn-check",autoComplete:"off",id:b,onClick:function(){a.updateSubcategory(b),a.loadCategoryModal()}}),/*#__PURE__*/React.createElement("label",{className:`btn btn-outline-${c} w-100 rounded-0 my-1 ${d&&"d-none"}`,htmlFor:b},b,/*#__PURE__*/React.createElement("br",null)))}function g({subcategory:b,color:c,hidden:d=!1}){return/*#__PURE__*/React.createElement("div",null,/*#__PURE__*/React.createElement("input",{type:"checkbox",className:"btn-check",autoComplete:"off",id:b,onClick:function(){a.updateAlternateSubcategory(b),a.loadCategoryModal()}}),/*#__PURE__*/React.createElement("label",{className:`btn btn-outline-${c} w-100 rounded-0 my-1 ${d&&"d-none"}`,htmlFor:b},b,/*#__PURE__*/React.createElement("br",null)))}const[h,i]=React.useState(CATEGORY_BUTTONS.map(()=>0)),[j,k]=React.useState(!1);return React.useEffect(()=>{a.loadCategoryModal(),document.getElementById("category-modal").addEventListener("hidden.bs.modal",c)},[c]),/*#__PURE__*/React.createElement("div",{className:"modal modal-lg",id:"category-modal",tabIndex:"-1"},/*#__PURE__*/React.createElement("div",{className:"modal-dialog modal-dialog-scrollable"},/*#__PURE__*/React.createElement("div",{className:"modal-content"},/*#__PURE__*/React.createElement("div",{className:"modal-header"},/*#__PURE__*/React.createElement("h5",{className:"modal-title me-2"},"Select Categories"),/*#__PURE__*/React.createElement(function(){return/*#__PURE__*/React.createElement("button",{className:"btn btn-primary me-1",onClick:function(){0===a.categories.length?a.import(CATEGORY_BUTTONS.map(a=>a[0]),SUBCATEGORY_BUTTONS.map(a=>a[0]),ALTERNATE_SUBCATEGORY_BUTTONS.map(a=>a[0])):a.import([],[],[]),a.loadCategoryModal()},disabled:j},"Toggle all")},null),b||/*#__PURE__*/React.createElement(function(){return/*#__PURE__*/React.createElement("button",{className:"btn btn-primary",onClick:function(){a.percentView=!j,k(!j)}},"% view")},null),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn-close","data-bs-dismiss":"modal","aria-label":"Close"})),/*#__PURE__*/React.createElement("div",{className:"modal-body"},/*#__PURE__*/React.createElement("div",{className:j?"d-none":"row",id:"non-percent-view"},/*#__PURE__*/React.createElement("div",{className:"col-4",id:"categories"},/*#__PURE__*/React.createElement("h5",{className:"text-center"},"Category"),CATEGORY_BUTTONS.map(a=>/*#__PURE__*/React.createElement(e,{key:a[0],category:a[0],color:a[1]}))),/*#__PURE__*/React.createElement("div",{className:"col-4",id:"subcategories"},/*#__PURE__*/React.createElement("h5",{className:"text-center"},"Subcategory"),/*#__PURE__*/React.createElement("div",{className:"text-muted text-center",id:"subcategory-info-text"},"You must select categories before you can select subcategories."),SUBCATEGORY_BUTTONS.map(a=>/*#__PURE__*/React.createElement(f,{key:a[0],subcategory:a[0],color:a[1],hidden:!0}))),/*#__PURE__*/React.createElement("div",{className:"col-4",id:"alternate-subcategories"},/*#__PURE__*/React.createElement("h5",{className:"text-center"},"Alternate ",/*#__PURE__*/React.createElement("span",{className:"d-none d-lg-inline"},"Subcategory")),ALTERNATE_SUBCATEGORY_BUTTONS.map(a=>/*#__PURE__*/React.createElement(g,{key:a[0],subcategory:a[0],color:a[1],hidden:!0})))),/*#__PURE__*/React.createElement("div",{className:!j&&"d-none",id:"percent-view"},/*#__PURE__*/React.createElement("table",{className:"table"},/*#__PURE__*/React.createElement("tbody",null,CATEGORY_BUTTONS.map((a,b)=>/*#__PURE__*/React.createElement(d,{key:a[0],category:a[0],index:b})),/*#__PURE__*/React.createElement("tr",null,/*#__PURE__*/React.createElement("th",null,"Total Percent:"),/*#__PURE__*/React.createElement("td",{className:"font-monospace"},/*#__PURE__*/React.createElement("span",{className:"me-1"},(h.reduce((c,a)=>c+a,0)+"").padStart(3,"\xA0"),"%"),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-sm btn-outline-secondary",onClick:()=>i(h.map(()=>0))},"Reset"))))))))))}export default CategoryModal; \ No newline at end of file +const d=Math.min(100,Math.max(0,a.categoryPercents[c]+b));a.categoryPercents[c]=d,a.loadCategoryModal()}return/*#__PURE__*/React.createElement("tr",null,/*#__PURE__*/React.createElement("th",{style:{width:"50%"}},b),/*#__PURE__*/React.createElement("td",{style:{width:"50%"}},/*#__PURE__*/React.createElement("span",{className:"font-monospace me-1 category-percent"}),/*#__PURE__*/React.createElement("div",{class:"btn-group btn-group-sm me-1",role:"group"},/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(-5)},"-"),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(5)},"+")),/*#__PURE__*/React.createElement("div",{class:"btn-group btn-group-sm",role:"group"},/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(-100)},"Min"),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(50-a.categoryPercents[c])},"50%"),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-outline-secondary",onClick:()=>d(100-a.categoryPercents.reduce((c,a)=>c+a))},"Max"))))}function e({category:b,color:c}){return/*#__PURE__*/React.createElement("div",null,/*#__PURE__*/React.createElement("input",{type:"checkbox",className:"btn-check",autoComplete:"off",id:b,onClick:function(){a.updateCategory(b),a.loadCategoryModal()}}),/*#__PURE__*/React.createElement("label",{className:`btn btn-outline-${c} w-100 rounded-0 my-1`,htmlFor:b},b,/*#__PURE__*/React.createElement("br",null)))}function f({subcategory:b,color:c,hidden:d=!1}){return/*#__PURE__*/React.createElement("div",null,/*#__PURE__*/React.createElement("input",{type:"checkbox",className:"btn-check",autoComplete:"off",id:b,onClick:function(){a.updateSubcategory(b),a.loadCategoryModal()}}),/*#__PURE__*/React.createElement("label",{className:`btn btn-outline-${c} w-100 rounded-0 my-1 ${d&&"d-none"}`,htmlFor:b},b,/*#__PURE__*/React.createElement("br",null)))}function g({subcategory:b,color:c,hidden:d=!1}){return/*#__PURE__*/React.createElement("div",null,/*#__PURE__*/React.createElement("input",{type:"checkbox",className:"btn-check",autoComplete:"off",id:b,onClick:function(){a.updateAlternateSubcategory(b),a.loadCategoryModal()}}),/*#__PURE__*/React.createElement("label",{className:`btn btn-outline-${c} w-100 rounded-0 my-1 ${d&&"d-none"}`,htmlFor:b},b,/*#__PURE__*/React.createElement("br",null)))}return React.useEffect(()=>{a.loadCategoryModal(),document.getElementById("category-modal").addEventListener("hidden.bs.modal",c)},[c]),/*#__PURE__*/React.createElement("div",{className:"modal modal-lg",id:"category-modal",tabIndex:"-1"},/*#__PURE__*/React.createElement("div",{className:"modal-dialog modal-dialog-scrollable"},/*#__PURE__*/React.createElement("div",{className:"modal-content"},/*#__PURE__*/React.createElement("div",{className:"modal-header"},/*#__PURE__*/React.createElement("h5",{className:"modal-title me-2"},"Select Categories"),/*#__PURE__*/React.createElement(function(){return/*#__PURE__*/React.createElement("button",{className:"btn btn-primary me-1",id:"toggle-all",onClick:function(){0===a.categories.length?a.import({categories:CATEGORY_BUTTONS.map(a=>a[0]),subcategories:SUBCATEGORY_BUTTONS.map(a=>a[0]),alternateSubcategories:ALTERNATE_SUBCATEGORY_BUTTONS.map(a=>a[0])}):a.import(),a.loadCategoryModal()}},"Toggle all")},null),b||/*#__PURE__*/React.createElement(function(){return/*#__PURE__*/React.createElement("button",{className:"btn btn-primary",onClick:function(){a.percentView=!a.percentView,a.loadCategoryModal()}},"% view")},null),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn-close","data-bs-dismiss":"modal","aria-label":"Close"})),/*#__PURE__*/React.createElement("div",{className:"modal-body"},/*#__PURE__*/React.createElement("div",{className:"row",id:"non-percent-view"},/*#__PURE__*/React.createElement("div",{className:"col-4",id:"categories"},/*#__PURE__*/React.createElement("h5",{className:"text-center"},"Category"),CATEGORY_BUTTONS.map(a=>/*#__PURE__*/React.createElement(e,{key:a[0],category:a[0],color:a[1]}))),/*#__PURE__*/React.createElement("div",{className:"col-4",id:"subcategories"},/*#__PURE__*/React.createElement("h5",{className:"text-center"},"Subcategory"),/*#__PURE__*/React.createElement("div",{className:"text-muted text-center",id:"subcategory-info-text"},"You must select categories before you can select subcategories."),SUBCATEGORY_BUTTONS.map(a=>/*#__PURE__*/React.createElement(f,{key:a[0],subcategory:a[0],color:a[1],hidden:!0}))),/*#__PURE__*/React.createElement("div",{className:"col-4",id:"alternate-subcategories"},/*#__PURE__*/React.createElement("h5",{className:"text-center"},"Alternate ",/*#__PURE__*/React.createElement("span",{className:"d-none d-lg-inline"},"Subcategory")),ALTERNATE_SUBCATEGORY_BUTTONS.map(a=>/*#__PURE__*/React.createElement(g,{key:a[0],subcategory:a[0],color:a[1],hidden:!0})))),/*#__PURE__*/React.createElement("div",{className:"d-none",id:"percent-view"},/*#__PURE__*/React.createElement("table",{className:"table"},/*#__PURE__*/React.createElement("tbody",null,CATEGORY_BUTTONS.map((a,b)=>/*#__PURE__*/React.createElement(d,{key:a[0],category:a[0],index:b})),/*#__PURE__*/React.createElement("tr",null,/*#__PURE__*/React.createElement("th",null,"Total Percent:"),/*#__PURE__*/React.createElement("td",{className:"font-monospace"},/*#__PURE__*/React.createElement("span",{className:"me-1"},(a.categoryPercents.reduce((c,a)=>c+a,0)+"").padStart(3,"\xA0"),"%"),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-sm btn-outline-secondary",onClick:()=>{a.categoryPercents=a.categoryPercents.map(()=>0),a.loadCategoryModal()}},"Reset"))))))))))}export default CategoryModal; \ No newline at end of file diff --git a/client/singleplayer/ClientTossupRoom.js b/client/singleplayer/ClientTossupRoom.js index b1877c27..b7ade161 100644 --- a/client/singleplayer/ClientTossupRoom.js +++ b/client/singleplayer/ClientTossupRoom.js @@ -22,7 +22,7 @@ export default class ClientTossupRoom extends TossupRoom { }; this.checkAnswer = api.checkAnswer; - this.getRandomTossups = async (args) => await api.getRandomTossup({ number: 20, ...args }); + this.getRandomTossups = async (args) => await api.getRandomTossup({ ...args }); this.getSet = async ({ setName, packetNumbers }) => setName ? await api.getPacketTossups(setName, packetNumbers[0] ?? 1) : []; this.getSetList = api.getSetList; this.getNumPackets = api.getNumPackets; diff --git a/client/singleplayer/tossups/index.jsx b/client/singleplayer/tossups/index.jsx index 1380ccc2..28029473 100644 --- a/client/singleplayer/tossups/index.jsx +++ b/client/singleplayer/tossups/index.jsx @@ -173,8 +173,8 @@ function revealAnswer ({ answer, question }) { document.getElementById('toggle-correct').textContent = room.previous.isCorrect ? 'I was wrong' : 'I was right'; } -function setCategories ({ alternateSubcategories, categories, subcategories }) { - categoryManager.import(categories, subcategories, alternateSubcategories); +function setCategories ({ alternateSubcategories, categories, subcategories, percentView, categoryPercents }) { + categoryManager.import({ categories, subcategories, alternateSubcategories, percentView, categoryPercents }); categoryManager.loadCategoryModal(); window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...room.query, version: queryVersion })); } @@ -455,8 +455,9 @@ let startingDifficulties = []; if (window.localStorage.getItem('singleplayer-tossup-query')) { try { const savedQuery = JSON.parse(window.localStorage.getItem('singleplayer-tossup-query')); - if (savedQuery.version !== queryVersion) { throw new Error(); } - categoryManager.import(savedQuery.categories, savedQuery.subcategories, savedQuery.alternateSubcategories); + // if (savedQuery.version !== queryVersion) { throw new Error(); } + categoryManager.import(savedQuery); + room.categoryManager.import(savedQuery); room.query = savedQuery; socket.sendToServer({ type: 'set-packet-numbers', ...savedQuery }); socket.sendToServer({ type: 'set-set-name', ...savedQuery }); diff --git a/client/singleplayer/tossups/index.min.js b/client/singleplayer/tossups/index.min.js index 64fdf773..e204069c 100644 --- a/client/singleplayer/tossups/index.min.js +++ b/client/singleplayer/tossups/index.min.js @@ -1,5 +1,6 @@ -import account from"../../scripts/accounts.js";import api from"../../scripts/api/index.js";import questionStats from"../../scripts/auth/question-stats.js";import audio from"../../audio/index.js";import Player from"../../../quizbowl/Player.js";import ClientTossupRoom from"../ClientTossupRoom.js";import CategoryManager from"../../../quizbowl/category-manager.js";import{arrayToRange,createTossupCard,rangeToArray}from"../../scripts/utilities/index.js";import{getDropdownValues}from"../../scripts/utilities/dropdown-checklist.js";import CategoryModal from"../../scripts/components/CategoryModal.min.js";import DifficultyDropdown from"../../scripts/components/DifficultyDropdown.min.js";let maxPacketNumber=24;const categoryManager=new CategoryManager,queryVersion="2024-10-11",settingsVersion="2024-10-16",USER_ID="user",room=new ClientTossupRoom;room.players[USER_ID]=new Player(USER_ID);const socket={send:onmessage,sendToServer:a=>room.message(USER_ID,a)};room.sockets[USER_ID]=socket;function onmessage(a){const b=JSON.parse(a);switch(b.type){case"buzz":return buzz(b);case"clear-stats":return clearStats(b);case"end-of-set":return endOfSet(b);case"give-answer":return giveAnswer(b);case"next":return next(b);case"no-questions-found":return noQuestionsFound(b);case"pause":return pause(b);case"reveal-answer":return revealAnswer(b);case"set-categories":return setCategories(b);case"set-difficulties":return setDifficulties(b);case"set-strictness":return setStrictness(b);case"set-reading-speed":return setReadingSpeed(b);case"set-packet-numbers":return setPacketNumbers(b);case"set-set-name":return setSetName(b);case"set-year-range":return setYearRange(b);case"skip":return next(b);case"start":return next(b);case"timer-update":return updateTimerDisplay(b.timeRemaining);case"toggle-correct":return toggleCorrect(b);case"toggle-powermark-only":return togglePowermarkOnly(b);case"toggle-rebuzz":return toggleRebuzz(b);case"toggle-select-by-set-name":return toggleSelectBySetName(b);case"toggle-show-history":return toggleShowHistory(b);case"toggle-standard-only":return toggleStandardOnly(b);case"toggle-timer":return toggleTimer(b);case"toggle-type-to-answer":return toggleTypeToAnswer(b);case"update-question":return updateQuestion(b)}}function buzz({timer:a,userId:b,username:c}){audio.soundEffects&&audio.buzz.play();const d=document.getElementById("type-to-answer").checked;d&&(document.getElementById("answer-input-group").classList.remove("d-none"),document.getElementById("answer-input").focus(),document.getElementById("buzz").disabled=!0)}function clearStats({userId:a}){updateStatDisplay(room.players[a])}function endOfSet(){window.alert("No more questions left"),document.getElementById("buzz").disabled=!0,document.getElementById("pause").disabled=!0,document.getElementById("next").disabled=!0}async function giveAnswer({directive:a,directedPrompt:b,perQuestionCelerity:c,score:d,tossup:e,userId:f}){return"prompt"===a?(document.getElementById("answer-input-group").classList.remove("d-none"),document.getElementById("answer-input").focus(),void(document.getElementById("answer-input").placeholder=b?`Prompt: "${b}"`:"Prompt")):void(document.getElementById("answer-input").value="",document.getElementById("answer-input").blur(),document.getElementById("answer-input").placeholder="Enter answer",document.getElementById("answer-input-group").classList.add("d-none"),document.getElementById("next").disabled=!1,document.getElementById("pause").disabled=!1,room.settings.rebuzz&&(document.getElementById("buzz").disabled=!1,document.getElementById("buzz").textContent="Buzz"),updateStatDisplay(room.players[USER_ID]),audio.soundEffects&&f===USER_ID&&("accept"===a&&10room.message(USER_ID,a)};room.sockets[USER_ID]=socket;function onmessage(a){const b=JSON.parse(a);switch(b.type){case"buzz":return buzz(b);case"clear-stats":return clearStats(b);case"end-of-set":return endOfSet(b);case"give-answer":return giveAnswer(b);case"next":return next(b);case"no-questions-found":return noQuestionsFound(b);case"pause":return pause(b);case"reveal-answer":return revealAnswer(b);case"set-categories":return setCategories(b);case"set-difficulties":return setDifficulties(b);case"set-strictness":return setStrictness(b);case"set-reading-speed":return setReadingSpeed(b);case"set-packet-numbers":return setPacketNumbers(b);case"set-set-name":return setSetName(b);case"set-year-range":return setYearRange(b);case"skip":return next(b);case"start":return next(b);case"timer-update":return updateTimerDisplay(b.timeRemaining);case"toggle-correct":return toggleCorrect(b);case"toggle-powermark-only":return togglePowermarkOnly(b);case"toggle-rebuzz":return toggleRebuzz(b);case"toggle-select-by-set-name":return toggleSelectBySetName(b);case"toggle-show-history":return toggleShowHistory(b);case"toggle-standard-only":return toggleStandardOnly(b);case"toggle-timer":return toggleTimer(b);case"toggle-type-to-answer":return toggleTypeToAnswer(b);case"update-question":return updateQuestion(b)}}function buzz({timer:a,userId:b,username:c}){audio.soundEffects&&audio.buzz.play();const d=document.getElementById("type-to-answer").checked;d&&(document.getElementById("answer-input-group").classList.remove("d-none"),document.getElementById("answer-input").focus(),document.getElementById("buzz").disabled=!0)}function clearStats({userId:a}){updateStatDisplay(room.players[a])}function endOfSet(){window.alert("No more questions left"),document.getElementById("buzz").disabled=!0,document.getElementById("pause").disabled=!0,document.getElementById("next").disabled=!0}async function giveAnswer({directive:a,directedPrompt:b,perQuestionCelerity:c,score:d,tossup:e,userId:f}){return"prompt"===a?(document.getElementById("answer-input-group").classList.remove("d-none"),document.getElementById("answer-input").focus(),void(document.getElementById("answer-input").placeholder=b?`Prompt: "${b}"`:"Prompt")):void(document.getElementById("answer-input").value="",document.getElementById("answer-input").blur(),document.getElementById("answer-input").placeholder="Enter answer",document.getElementById("answer-input-group").classList.add("d-none"),document.getElementById("next").disabled=!1,document.getElementById("pause").disabled=!1,room.settings.rebuzz&&(document.getElementById("buzz").disabled=!1,document.getElementById("buzz").textContent="Buzz"),updateStatDisplay(room.players[USER_ID]),audio.soundEffects&&f===USER_ID&&("accept"===a&&101>a||a>maxPacketNumber);return b?void document.getElementById("packet-number").classList.add("is-invalid"):void(document.getElementById("packet-number").classList.remove("is-invalid"),socket.sendToServer({type:"set-packet-numbers",packetNumbers:a}))}),document.getElementById("pause").addEventListener("click",function(){this.blur();const a=parseFloat(document.querySelector(".timer .face").innerText),b=parseFloat(document.querySelector(".timer .fraction").innerText);socket.sendToServer({type:"pause",pausedTime:10*(a+b)})}),document.getElementById("reading-speed").addEventListener("change",function(){socket.sendToServer({type:"set-reading-speed",readingSpeed:this.value})}),document.getElementById("report-question-submit").addEventListener("click",function(){api.reportQuestion(document.getElementById("report-question-id").value,document.getElementById("report-question-reason").value,document.getElementById("report-question-description").value)}),document.getElementById("set-name").addEventListener("change",async function(){socket.sendToServer({type:"set-set-name",setName:this.value.trim(),packetNumbers:rangeToArray(document.getElementById("packet-number").value)})}),document.getElementById("start").addEventListener("click",function(){socket.sendToServer({type:"start"})}),document.getElementById("strictness").addEventListener("change",function(){this.blur(),socket.sendToServer({type:"set-strictness",strictness:this.value})}),document.getElementById("strictness").addEventListener("input",function(){document.getElementById("strictness-display").textContent=this.value}),document.getElementById("toggle-correct").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-correct",correct:"I was right"===this.textContent})}),document.getElementById("toggle-powermark-only").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-powermark-only",powermarkOnly:this.checked})}),document.getElementById("toggle-rebuzz").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-rebuzz",rebuzz:this.checked})}),document.getElementById("toggle-select-by-set-name").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-select-by-set-name",selectBySetName:this.checked})}),document.getElementById("toggle-settings").addEventListener("click",function(){this.blur(),document.getElementById("buttons").classList.toggle("col-lg-9"),document.getElementById("buttons").classList.toggle("col-lg-12"),document.getElementById("content").classList.toggle("col-lg-9"),document.getElementById("content").classList.toggle("col-lg-12"),document.getElementById("settings").classList.toggle("d-none"),document.getElementById("settings").classList.toggle("d-lg-none")}),document.getElementById("toggle-show-history").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-show-history",showHistory:this.checked})}),document.getElementById("toggle-standard-only").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-standard-only",standardOnly:this.checked})}),document.getElementById("toggle-timer").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-timer",timer:this.checked})}),document.getElementById("type-to-answer").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-type-to-answer",typeToAnswer:this.checked})}),document.getElementById("year-range-a").onchange=function(){const a=$("#slider").slider("values",0),b=$("#slider").slider("values",1);socket.sendToServer({type:"set-year-range",minYear:a,maxYear:b})},document.getElementById("year-range-b").onchange=function(){const a=$("#slider").slider("values",0),b=$("#slider").slider("values",1);socket.sendToServer({type:"set-year-range",minYear:a,maxYear:b})},document.addEventListener("keydown",a=>{if(!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement.tagName))switch(a.key?.toLowerCase()){case" ":document.getElementById("buzz").click(),a.target===document.body&&a.preventDefault();break;case"e":return document.getElementById("toggle-settings").click();case"k":return document.getElementsByClassName("card-header-clickable")[0].click();case"n":return document.getElementById("next").click();case"p":return document.getElementById("pause").click();case"s":return document.getElementById("start").click();case"t":return document.getElementsByClassName("star-tossup")[0].click();case"y":return navigator.clipboard.writeText(room.tossup._id??"")}});let startingDifficulties=[];if(window.localStorage.getItem("singleplayer-tossup-query"))try{const a=JSON.parse(window.localStorage.getItem("singleplayer-tossup-query"));if(a.version!==queryVersion)throw new Error;categoryManager.import(a.categories,a.subcategories,a.alternateSubcategories),room.query=a,socket.sendToServer({type:"set-packet-numbers",...a}),socket.sendToServer({type:"set-set-name",...a}),socket.sendToServer({type:"set-year-range",...a}),socket.sendToServer({type:"toggle-powermark-only",...a}),socket.sendToServer({type:"toggle-select-by-set-name",...a}),socket.sendToServer({type:"toggle-standard-only",...a}),startingDifficulties=a.difficulties}catch{window.localStorage.removeItem("singleplayer-tossup-query")}if(window.localStorage.getItem("singleplayer-tossup-settings"))try{const a=JSON.parse(window.localStorage.getItem("singleplayer-tossup-settings"));if(a.version!==settingsVersion)throw new Error;socket.sendToServer({type:"set-strictness",...a}),socket.sendToServer({type:"set-reading-speed",...a}),socket.sendToServer({type:"toggle-rebuzz",...a}),socket.sendToServer({type:"toggle-show-history",...a}),socket.sendToServer({type:"toggle-timer",...a}),socket.sendToServer({type:"toggle-type-to-answer",...a})}catch{window.localStorage.removeItem("singleplayer-tossup-settings")}ReactDOM.createRoot(document.getElementById("category-modal-root")).render(/*#__PURE__*/React.createElement(CategoryModal,{categoryManager:categoryManager,onClose:()=>socket.sendToServer({type:"set-categories",...categoryManager.export()})})),ReactDOM.createRoot(document.getElementById("difficulty-dropdown-root")).render(/*#__PURE__*/React.createElement(DifficultyDropdown,{startingDifficulties:startingDifficulties??[],onChange:()=>socket.sendToServer({type:"set-difficulties",difficulties:getDropdownValues("difficulties")})})); \ No newline at end of file +document.getElementById("statline").innerHTML=`${a}/${b}/${c} with ${d} tossup${h} seen (${e} pts, celerity: ${g})`,document.getElementById("clear-stats").disabled=0===d}function updateTimerDisplay(a){const b=Math.floor(a/10);document.querySelector(".timer .face").innerText=b,document.querySelector(".timer .fraction").innerText="."+a%10}document.getElementById("answer-form").addEventListener("submit",function(a){a.preventDefault(),a.stopPropagation();const b=document.getElementById("answer-input").value;socket.sendToServer({type:"give-answer",givenAnswer:b})}),document.getElementById("buzz").addEventListener("click",function(){this.blur(),audio.soundEffects&&audio.buzz.play(),socket.sendToServer({type:"buzz"})}),document.getElementById("clear-stats").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"clear-stats"})}),document.getElementById("next").addEventListener("click",function(){this.blur(),"Skip"===this.innerHTML?socket.sendToServer({type:"skip"}):socket.sendToServer({type:"next"})}),document.getElementById("packet-number").addEventListener("change",function(){const a=rangeToArray(this.value.trim(),maxPacketNumber),b=a.some(a=>1>a||a>maxPacketNumber);return b?void document.getElementById("packet-number").classList.add("is-invalid"):void(document.getElementById("packet-number").classList.remove("is-invalid"),socket.sendToServer({type:"set-packet-numbers",packetNumbers:a}))}),document.getElementById("pause").addEventListener("click",function(){this.blur();const a=parseFloat(document.querySelector(".timer .face").innerText),b=parseFloat(document.querySelector(".timer .fraction").innerText);socket.sendToServer({type:"pause",pausedTime:10*(a+b)})}),document.getElementById("reading-speed").addEventListener("change",function(){socket.sendToServer({type:"set-reading-speed",readingSpeed:this.value})}),document.getElementById("report-question-submit").addEventListener("click",function(){api.reportQuestion(document.getElementById("report-question-id").value,document.getElementById("report-question-reason").value,document.getElementById("report-question-description").value)}),document.getElementById("set-name").addEventListener("change",async function(){socket.sendToServer({type:"set-set-name",setName:this.value.trim(),packetNumbers:rangeToArray(document.getElementById("packet-number").value)})}),document.getElementById("start").addEventListener("click",function(){socket.sendToServer({type:"start"})}),document.getElementById("strictness").addEventListener("change",function(){this.blur(),socket.sendToServer({type:"set-strictness",strictness:this.value})}),document.getElementById("strictness").addEventListener("input",function(){document.getElementById("strictness-display").textContent=this.value}),document.getElementById("toggle-correct").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-correct",correct:"I was right"===this.textContent})}),document.getElementById("toggle-powermark-only").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-powermark-only",powermarkOnly:this.checked})}),document.getElementById("toggle-rebuzz").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-rebuzz",rebuzz:this.checked})}),document.getElementById("toggle-select-by-set-name").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-select-by-set-name",selectBySetName:this.checked})}),document.getElementById("toggle-settings").addEventListener("click",function(){this.blur(),document.getElementById("buttons").classList.toggle("col-lg-9"),document.getElementById("buttons").classList.toggle("col-lg-12"),document.getElementById("content").classList.toggle("col-lg-9"),document.getElementById("content").classList.toggle("col-lg-12"),document.getElementById("settings").classList.toggle("d-none"),document.getElementById("settings").classList.toggle("d-lg-none")}),document.getElementById("toggle-show-history").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-show-history",showHistory:this.checked})}),document.getElementById("toggle-standard-only").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-standard-only",standardOnly:this.checked})}),document.getElementById("toggle-timer").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-timer",timer:this.checked})}),document.getElementById("type-to-answer").addEventListener("click",function(){this.blur(),socket.sendToServer({type:"toggle-type-to-answer",typeToAnswer:this.checked})}),document.getElementById("year-range-a").onchange=function(){const a=$("#slider").slider("values",0),b=$("#slider").slider("values",1);socket.sendToServer({type:"set-year-range",minYear:a,maxYear:b})},document.getElementById("year-range-b").onchange=function(){const a=$("#slider").slider("values",0),b=$("#slider").slider("values",1);socket.sendToServer({type:"set-year-range",minYear:a,maxYear:b})},document.addEventListener("keydown",a=>{if(!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement.tagName))switch(a.key?.toLowerCase()){case" ":document.getElementById("buzz").click(),a.target===document.body&&a.preventDefault();break;case"e":return document.getElementById("toggle-settings").click();case"k":return document.getElementsByClassName("card-header-clickable")[0].click();case"n":return document.getElementById("next").click();case"p":return document.getElementById("pause").click();case"s":return document.getElementById("start").click();case"t":return document.getElementsByClassName("star-tossup")[0].click();case"y":return navigator.clipboard.writeText(room.tossup._id??"")}});let startingDifficulties=[];if(window.localStorage.getItem("singleplayer-tossup-query"))try{const a=JSON.parse(window.localStorage.getItem("singleplayer-tossup-query"));// if (savedQuery.version !== queryVersion) { throw new Error(); } +categoryManager.import(a),room.categoryManager.import(a),room.query=a,socket.sendToServer({type:"set-packet-numbers",...a}),socket.sendToServer({type:"set-set-name",...a}),socket.sendToServer({type:"set-year-range",...a}),socket.sendToServer({type:"toggle-powermark-only",...a}),socket.sendToServer({type:"toggle-select-by-set-name",...a}),socket.sendToServer({type:"toggle-standard-only",...a}),startingDifficulties=a.difficulties}catch{window.localStorage.removeItem("singleplayer-tossup-query")}if(window.localStorage.getItem("singleplayer-tossup-settings"))try{const a=JSON.parse(window.localStorage.getItem("singleplayer-tossup-settings"));if(a.version!==settingsVersion)throw new Error;socket.sendToServer({type:"set-strictness",...a}),socket.sendToServer({type:"set-reading-speed",...a}),socket.sendToServer({type:"toggle-rebuzz",...a}),socket.sendToServer({type:"toggle-show-history",...a}),socket.sendToServer({type:"toggle-timer",...a}),socket.sendToServer({type:"toggle-type-to-answer",...a})}catch{window.localStorage.removeItem("singleplayer-tossup-settings")}ReactDOM.createRoot(document.getElementById("category-modal-root")).render(/*#__PURE__*/React.createElement(CategoryModal,{categoryManager:categoryManager,onClose:()=>socket.sendToServer({type:"set-categories",...categoryManager.export()})})),ReactDOM.createRoot(document.getElementById("difficulty-dropdown-root")).render(/*#__PURE__*/React.createElement(DifficultyDropdown,{startingDifficulties:startingDifficulties??[],onChange:()=>socket.sendToServer({type:"set-difficulties",difficulties:getDropdownValues("difficulties")})})); \ No newline at end of file diff --git a/quizbowl/TossupRoom.js b/quizbowl/TossupRoom.js index 38a1e970..2eef847a 100644 --- a/quizbowl/TossupRoom.js +++ b/quizbowl/TossupRoom.js @@ -50,6 +50,8 @@ export default class TossupRoom extends Room { this.randomQuestionCache = []; this.setCache = []; + this.categoryManager = new CategoryManager(categories, subcategories, alternateSubcategories); + this.query = { difficulties: [4, 5], minYear: DEFAULT_MIN_YEAR, @@ -59,6 +61,8 @@ export default class TossupRoom extends Room { alternateSubcategories, categories, subcategories, + percentView: false, + categoryPercents: CATEGORIES.map(() => 0), reverse: true, // used for `database.getSet` powermarkOnly: false, selectBySetName: false, @@ -118,6 +122,8 @@ export default class TossupRoom extends Room { if (this.query.selectBySetName) { this.setCache = await this.getSet({ setName: this.query.setName, packetNumbers: [this.query.packetNumbers[0]] }); this.packetLength = this.setCache.length; + } else if (this.categoryManager.percentView) { + this.randomQuestionCache = []; } else { this.randomQuestionCache = await this.getRandomTossups({ ...this.query, number: 1 }); } @@ -127,7 +133,6 @@ export default class TossupRoom extends Room { this.queryingQuestion = true; if (this.query.selectBySetName) { - const categoryManager = new CategoryManager(this.query.categories, this.query.subcategories, this.query.alternateSubcategories); do { if (this.setCache.length === 0) { const packetNumber = this.query.packetNumbers.shift(); @@ -141,15 +146,19 @@ export default class TossupRoom extends Room { this.tossup = this.setCache.shift(); this.query.packetNumbers = this.query.packetNumbers.filter(packetNumber => packetNumber >= this.tossup.packet.number); - } while (!categoryManager.isValidCategory(this.tossup)); + } while (!this.categoryManager.isValidCategory(this.tossup)); } else { - if (this.randomQuestionCache.length === 0) { + if (this.categoryManager.percentView) { + const randomCategory = this.categoryManager.getRandomCategory(); + this.randomQuestionCache = await this.getRandomTossups({ ...this.query, number: 1, categories: [randomCategory], subcategories: [], alternateSubcategories: [] }); + } else if (this.randomQuestionCache.length === 0) { this.randomQuestionCache = await this.getRandomTossups({ ...this.query, number: 20 }); - if (this.randomQuestionCache?.length === 0) { - this.tossup = {}; - this.emitMessage({ type: 'no-questions-found' }); - return false; - } + } + + if (this.randomQuestionCache?.length === 0) { + this.tossup = {}; + this.emitMessage({ type: 'no-questions-found' }); + return false; } this.tossup = this.randomQuestionCache.pop(); } @@ -449,10 +458,11 @@ export default class TossupRoom extends Room { this.emitMessage({ type: 'toggle-timer', timer, username }); } - setCategories (userId, { categories, subcategories, alternateSubcategories }) { + setCategories (userId, { categories, subcategories, alternateSubcategories, percentView, categoryPercents }) { if (!Array.isArray(categories)) { return; } if (!Array.isArray(subcategories)) { return; } if (!Array.isArray(alternateSubcategories)) { return; } + if (categoryPercents?.length !== CATEGORIES.length) { return; } categories = categories.filter(category => CATEGORIES.includes(category)); subcategories = subcategories.filter(subcategory => SUBCATEGORIES.includes(subcategory)); @@ -461,9 +471,14 @@ export default class TossupRoom extends Room { if (subcategories.some(sub => !categories.includes(SUBCATEGORY_TO_CATEGORY[sub]))) { return; } if (alternateSubcategories.some(sub => !categories.includes(ALTERNATE_SUBCATEGORY_TO_CATEGORY[sub]))) { return; } + this.categoryManager.import({ categories, subcategories, alternateSubcategories, percentView, categoryPercents }); + const username = this.players[userId].username; - this.adjustQuery(['categories', 'subcategories', 'alternateSubcategories'], [categories, subcategories, alternateSubcategories]); - this.emitMessage({ type: 'set-categories', categories, subcategories, alternateSubcategories, username }); + this.adjustQuery( + ['categories', 'subcategories', 'alternateSubcategories', 'percentView', 'categoryPercents'], + [categories, subcategories, alternateSubcategories, percentView, categoryPercents] + ); + this.emitMessage({ type: 'set-categories', ...this.categoryManager.export(), username }); } setYearRange (userId, { minYear, maxYear }) { diff --git a/quizbowl/category-manager.js b/quizbowl/category-manager.js index ee2ca7b0..533bec18 100644 --- a/quizbowl/category-manager.js +++ b/quizbowl/category-manager.js @@ -8,12 +8,7 @@ export default class CategoryManager { */ constructor (categories = [], subcategories = [], alternateSubcategories = []) { // Should sum to 100 - this.categoryPercents = []; - for (let i = 0; i < CATEGORIES.length; i++) { - this.categoryPercents.push(0); - } - this.percentView = false; - this.import(categories, subcategories, alternateSubcategories); + this.import({ categories, subcategories, alternateSubcategories }); } export () { @@ -26,7 +21,14 @@ export default class CategoryManager { }; } - import (categories = [], subcategories = [], alternateSubcategories = [], percentView = false, categoryPercents = []) { + import ({ categories = [], subcategories = [], alternateSubcategories = [], percentView = false, categoryPercents = undefined } = {}) { + if (!categoryPercents) { + categoryPercents = []; + for (let i = 0; i < CATEGORIES.length; i++) { + categoryPercents.push(0); + } + } + if (categories.length > 0 && subcategories.length === 0) { categories.forEach(category => { CATEGORY_TO_SUBCATEGORY[category].forEach(subcategory => { @@ -38,6 +40,8 @@ export default class CategoryManager { this.categories = categories; this.subcategories = subcategories; this.alternateSubcategories = alternateSubcategories; + this.percentView = percentView; + this.categoryPercents = categoryPercents; } getRandomCategory () { @@ -45,19 +49,19 @@ export default class CategoryManager { if (total === 0) { // uniformly return a random category return CATEGORIES[Math.floor(Math.random() * CATEGORIES.length)]; - } else { - let random = Math.random() * total; - for (let i = 0; i < this.categoryPercents.length; i++) { - random -= this.categoryPercents[i]; - if (random <= 0) { return CATEGORIES[i]; } - } + } + + let random = Math.random() * total; + for (let i = 0; i < this.categoryPercents.length; i++) { + random -= this.categoryPercents[i]; + if (random <= 0) { return CATEGORIES[i]; } } } /** - * @param {JSON} question - * @returns {boolean} Whether or not the question is part of the valid category and subcategory combination. - */ + * @param {JSON} question + * @returns {boolean} Whether or not the question is part of the valid category and subcategory combination. + */ isValidCategory (question) { if (this.categories.length === 0 && this.subcategories.length === 0) { return true; @@ -67,9 +71,9 @@ export default class CategoryManager { } /** - * Updates the category modal to show the given categories and subcategories. - * @returns {void} - */ + * Updates the category modal to show the given categories and subcategories. + * @returns {void} + */ loadCategoryModal () { document.querySelectorAll('#categories input').forEach(element => { element.checked = false; }); document.querySelectorAll('#subcategories input').forEach(element => { element.checked = false; }); @@ -77,21 +81,18 @@ export default class CategoryManager { document.querySelectorAll('#alternate-subcategories input').forEach(element => { element.checked = false; }); document.querySelectorAll('#alternate-subcategories label').forEach(element => { element.classList.add('d-none'); }); - if (this.categories.length === 0 && this.subcategories.length === 0) { - document.getElementById('subcategory-info-text').classList.remove('d-none'); - } else { - document.getElementById('subcategory-info-text').classList.add('d-none'); - } + document.getElementById('subcategory-info-text').classList.toggle('d-none', this.categories.length || this.subcategories.length); for (const category of this.categories) { document.getElementById(category).checked = true; - CATEGORY_TO_SUBCATEGORY[category].forEach(subcategory => { + + for (const subcategory of CATEGORY_TO_SUBCATEGORY[category]) { document.querySelector(`[for="${subcategory}"]`).classList.remove('d-none'); - }); + } - CATEGORY_TO_ALTERNATE_SUBCATEGORIES[category].forEach(subcategory => { + for (const subcategory of CATEGORY_TO_ALTERNATE_SUBCATEGORIES[category]) { document.querySelector(`[for="${subcategory}"]`).classList.remove('d-none'); - }); + } } for (const subcategory of this.subcategories) { @@ -101,14 +102,23 @@ export default class CategoryManager { for (const alternateSubcategory of this.alternateSubcategories) { document.getElementById(alternateSubcategory).checked = true; } + + document.getElementById('non-percent-view').className = this.percentView ? 'd-none' : 'row'; + document.getElementById('percent-view').className = this.percentView ? '' : 'd-none'; + document.getElementById('toggle-all').disabled = this.percentView; + + const categoryPercentElements = document.querySelectorAll('.category-percent'); + for (let i = 0; i < this.categoryPercents.length; i++) { + categoryPercentElements.item(i).textContent = String(this.categoryPercents[i]).padStart(3, '\u00A0') + '%'; + } } /** - * Adds the given category if it is not in the list of valid categories. - * Otherwise, the category is removed. - * @param {string} category - * @returns {boolean} true if the category was added, false if the category was removed - */ + * Adds the given category if it is not in the list of valid categories. + * Otherwise, the category is removed. + * @param {string} category + * @returns {boolean} true if the category was added, false if the category was removed + */ updateCategory (category) { if (this.categories.includes(category)) { this.categories = this.categories.filter(a => a !== category); @@ -124,10 +134,10 @@ export default class CategoryManager { } /** - * Adds the given subcategory if it is not in the list of valid subcategories. - * Otherwise, the subcategory is removed. - * @param {String} subcategory - */ + * Adds the given subcategory if it is not in the list of valid subcategories. + * Otherwise, the subcategory is removed. + * @param {String} subcategory + */ updateSubcategory (subcategory) { if (this.subcategories.includes(subcategory)) { this.subcategories = this.subcategories.filter(a => a !== subcategory); @@ -139,10 +149,10 @@ export default class CategoryManager { } /** - * Adds the given subcategory if it is not in the list of valid subcategories. - * Otherwise, the subcategory is removed. - * @param {String} alternateSubcategory - */ + * Adds the given subcategory if it is not in the list of valid subcategories. + * Otherwise, the subcategory is removed. + * @param {String} alternateSubcategory + */ updateAlternateSubcategory (alternateSubcategory) { if (this.alternateSubcategories.includes(alternateSubcategory)) { this.alternateSubcategories = this.alternateSubcategories.filter(a => a !== alternateSubcategory); diff --git a/server/multiplayer/ServerTossupRoom.js b/server/multiplayer/ServerTossupRoom.js index d70008b2..1f7b769c 100644 --- a/server/multiplayer/ServerTossupRoom.js +++ b/server/multiplayer/ServerTossupRoom.js @@ -87,7 +87,7 @@ export default class ServerTossupRoom extends TossupRoom { settings: this.settings })); - socket.send(JSON.stringify({ type: 'connection-acknowledged-query', ...this.query })); + socket.send(JSON.stringify({ type: 'connection-acknowledged-query', ...this.query, ...this.categoryManager.export() })); socket.send(JSON.stringify({ type: 'connection-acknowledged-tossup', tossup: this.tossup })); if (this.questionProgress === this.QuestionProgressEnum.READING) { @@ -142,9 +142,9 @@ export default class ServerTossupRoom extends TossupRoom { super.next(userId, { type }); } - setCategories (userId, { categories, subcategories, alternateSubcategories }) { + setCategories (userId, { categories, subcategories, alternateSubcategories, percentView, categoryPercents }) { if (this.isPermanent) { return; } - super.setCategories(userId, { categories, subcategories, alternateSubcategories }); + super.setCategories(userId, { categories, subcategories, alternateSubcategories, percentView, categoryPercents }); } async setSetName (userId, { packetNumbers, setName }) {
Total Percent: {/* '\u00A0' ===   */} - {String(percents.reduce((a, b) => a + b, 0)).padStart(3, '\u00A0')}% - + {String(categoryManager.categoryPercents.reduce((a, b) => a + b, 0)).padStart(3, '\u00A0')}% +