From c079bde10d66e50db02dc50ebe13292931fe90c0 Mon Sep 17 00:00:00 2001 From: Geoffrey Wu Date: Fri, 11 Oct 2024 23:36:18 -0400 Subject: [PATCH] implement loading of saved preferences --- client/database/index.jsx | 4 +- client/database/index.min.js | 2 +- client/multiplayer/room.jsx | 2 +- client/multiplayer/room.min.js | 6 +- client/scripts/Timer.js | 40 - client/singleplayer/ClientTossupRoom.js | 33 +- client/singleplayer/bonuses/index.jsx | 2 +- client/singleplayer/bonuses/index.min.js | 2 +- client/singleplayer/tossups/index.jsx | 180 ++-- client/singleplayer/tossups/index.min.js | 8 +- client/singleplayer/tossups/old-index.jsx | 809 ------------------ client/singleplayer/tossups/old-index.min.js | 36 - quizbowl/TossupRoom.js | 62 +- .../category-manager.js | 0 quizbowl/insert-tokens-into-html.js | 4 +- routes/index.js | 3 +- server/multiplayer/ServerTossupRoom.js | 13 +- 17 files changed, 199 insertions(+), 1007 deletions(-) delete mode 100644 client/scripts/Timer.js delete mode 100644 client/singleplayer/tossups/old-index.jsx delete mode 100644 client/singleplayer/tossups/old-index.min.js rename {client/scripts/utilities => quizbowl}/category-manager.js (100%) diff --git a/client/database/index.jsx b/client/database/index.jsx index 586e4385..1f9a89fe 100644 --- a/client/database/index.jsx +++ b/client/database/index.jsx @@ -7,9 +7,9 @@ import BonusCard from '../scripts/components/BonusCard.min.js'; import CategoryModal from '../scripts/components/CategoryModal.min.js'; import DifficultyDropdown from '../scripts/components/DifficultyDropdown.min.js'; import Star from '../scripts/components/Star.min.js'; -import CategoryManager from '../scripts/utilities/category-manager.js'; +import CategoryManager from '../../quizbowl/category-manager.js'; import { getDropdownValues } from '../scripts/utilities/dropdown-checklist.js'; -import { insertTokensIntoHTML } from '../insert-tokens-into-html.js'; +import insertTokensIntoHTML from '../../quizbowl/insert-tokens-into-html.js'; const starredTossupIds = new Set(await star.getStarredTossupIds()); const starredBonusIds = new Set(await star.getStarredBonusIds()); diff --git a/client/database/index.min.js b/client/database/index.min.js index c1a603c7..ee82c922 100644 --- a/client/database/index.min.js +++ b/client/database/index.min.js @@ -1,4 +1,4 @@ -import{downloadQuestionsAsText,downloadBonusesAsCSV,downloadTossupsAsCSV,downloadQuestionsAsJSON}from"./download.js";import api from"../scripts/api/index.js";import star from"../scripts/auth/star.js";import TossupCard from"../scripts/components/TossupCard.min.js";import BonusCard from"../scripts/components/BonusCard.min.js";import CategoryModal from"../scripts/components/CategoryModal.min.js";import DifficultyDropdown from"../scripts/components/DifficultyDropdown.min.js";import Star from"../scripts/components/Star.min.js";import CategoryManager from"../scripts/utilities/category-manager.js";import{getDropdownValues}from"../scripts/utilities/dropdown-checklist.js";import{insertTokensIntoHTML}from"../insert-tokens-into-html.js";const starredTossupIds=new Set(await star.getStarredTossupIds()),starredBonusIds=new Set(await star.getStarredBonusIds()),paginationShiftLength=992""!==a).map(a=>new RegExp(a,"ig")):[b];for(const g of f){if("question"===e||"all"===e){const{starts:b,ends:c}=getMatchIndices(a.question_sanitized,g);a.question=insertTokensIntoHTML(a.question,a.question_sanitized,[b,c])}if("answer"===e||"all"===e){const{starts:b,ends:c}=getMatchIndices(a.answer_sanitized,g);a.answer=insertTokensIntoHTML(a.answer,a.answer_sanitized,[b,c])}}return a}function highlightBonusQuery({bonus:a,regExp:b,searchType:e="all",ignoreWordOrder:c,queryString:d}){const f=c?d.split(" ").filter(a=>""!==a).map(a=>new RegExp(a,"ig")):[b];for(const g of f){if("question"===e||"all"===e){{const{starts:b,ends:c}=getMatchIndices(a.leadin_sanitized,g);a.leadin=insertTokensIntoHTML(a.leadin,a.leadin_sanitized,[b,c])}for(let b=0;ba+c)}function b(){return Math.floor(1e4/(r||25))}function c(a,c){switch(a.preventDefault(),c){case"first":R=1;break;case"previous":R=Math.max(1,R-1);break;case"next":R=Math.min(V,R+1,b());break;case"last":R=Math.min(V,b());break;default:R=c}S(R),$(paginationShiftLength*Math.floor((R-1)/paginationShiftLength)),e(a,!1,!0),window.scrollTo({top:document.getElementById("tossups").offsetTop-100,behavior:"smooth"})}function d(a,c){switch(a.preventDefault(),c){case"first":T=1;break;case"previous":T=Math.max(1,T-1);break;case"next":T=Math.min(X,T+1,b());break;case"last":T=Math.min(X,b());break;default:T=c}U(T),aa(paginationShiftLength*Math.floor((T-1)/paginationShiftLength)),e(a,!1,!0),window.scrollTo({top:document.getElementById("bonuses").offsetTop-100,behavior:"smooth"})}function e(a,b=!1,c=!1){const d=performance.now();a.preventDefault(),Q(!0),(b||!c)&&(R=1,T=1,S(R),U(T));const e=new URLSearchParams({queryString:t,...categoryManager.export(),difficulties:getDropdownValues("difficulties"),maxReturnLength:r,questionType:v,randomize:b,exactPhrase:H,powermarkOnly:J,regex:D,ignoreWordOrder:F,searchType:x,setName:document.getElementById("set-name").value,tossupPagination:R,bonusPagination:T,minYear:z,maxYear:B}).toString();fetch(`/api/query?${e}`).then(a=>{if(400===a.status)throw new Error("Invalid query");return a}).then(a=>a.json()).then(a=>{const{tossups:c,bonuses:f,queryString:h}=a,j=RegExp(h,"ig"),l=Math.max(1,r||25),{count:n,questionArray:p}=c,{count:s,questionArray:u}=f,v=JSON.parse(JSON.stringify(p)),w=JSON.parse(JSON.stringify(u));// create deep copy to highlight +import{downloadQuestionsAsText,downloadBonusesAsCSV,downloadTossupsAsCSV,downloadQuestionsAsJSON}from"./download.js";import api from"../scripts/api/index.js";import star from"../scripts/auth/star.js";import TossupCard from"../scripts/components/TossupCard.min.js";import BonusCard from"../scripts/components/BonusCard.min.js";import CategoryModal from"../scripts/components/CategoryModal.min.js";import DifficultyDropdown from"../scripts/components/DifficultyDropdown.min.js";import Star from"../scripts/components/Star.min.js";import CategoryManager from"../../quizbowl/category-manager.js";import{getDropdownValues}from"../scripts/utilities/dropdown-checklist.js";import insertTokensIntoHTML from"../../quizbowl/insert-tokens-into-html.js";const starredTossupIds=new Set(await star.getStarredTossupIds()),starredBonusIds=new Set(await star.getStarredBonusIds()),paginationShiftLength=992""!==a).map(a=>new RegExp(a,"ig")):[b];for(const g of f){if("question"===e||"all"===e){const{starts:b,ends:c}=getMatchIndices(a.question_sanitized,g);a.question=insertTokensIntoHTML(a.question,a.question_sanitized,[b,c])}if("answer"===e||"all"===e){const{starts:b,ends:c}=getMatchIndices(a.answer_sanitized,g);a.answer=insertTokensIntoHTML(a.answer,a.answer_sanitized,[b,c])}}return a}function highlightBonusQuery({bonus:a,regExp:b,searchType:e="all",ignoreWordOrder:c,queryString:d}){const f=c?d.split(" ").filter(a=>""!==a).map(a=>new RegExp(a,"ig")):[b];for(const g of f){if("question"===e||"all"===e){{const{starts:b,ends:c}=getMatchIndices(a.leadin_sanitized,g);a.leadin=insertTokensIntoHTML(a.leadin,a.leadin_sanitized,[b,c])}for(let b=0;ba+c)}function b(){return Math.floor(1e4/(r||25))}function c(a,c){switch(a.preventDefault(),c){case"first":R=1;break;case"previous":R=Math.max(1,R-1);break;case"next":R=Math.min(V,R+1,b());break;case"last":R=Math.min(V,b());break;default:R=c}S(R),$(paginationShiftLength*Math.floor((R-1)/paginationShiftLength)),e(a,!1,!0),window.scrollTo({top:document.getElementById("tossups").offsetTop-100,behavior:"smooth"})}function d(a,c){switch(a.preventDefault(),c){case"first":T=1;break;case"previous":T=Math.max(1,T-1);break;case"next":T=Math.min(X,T+1,b());break;case"last":T=Math.min(X,b());break;default:T=c}U(T),aa(paginationShiftLength*Math.floor((T-1)/paginationShiftLength)),e(a,!1,!0),window.scrollTo({top:document.getElementById("bonuses").offsetTop-100,behavior:"smooth"})}function e(a,b=!1,c=!1){const d=performance.now();a.preventDefault(),Q(!0),(b||!c)&&(R=1,T=1,S(R),U(T));const e=new URLSearchParams({queryString:t,...categoryManager.export(),difficulties:getDropdownValues("difficulties"),maxReturnLength:r,questionType:v,randomize:b,exactPhrase:H,powermarkOnly:J,regex:D,ignoreWordOrder:F,searchType:x,setName:document.getElementById("set-name").value,tossupPagination:R,bonusPagination:T,minYear:z,maxYear:B}).toString();fetch(`/api/query?${e}`).then(a=>{if(400===a.status)throw new Error("Invalid query");return a}).then(a=>a.json()).then(a=>{const{tossups:c,bonuses:f,queryString:h}=a,j=RegExp(h,"ig"),l=Math.max(1,r||25),{count:n,questionArray:p}=c,{count:s,questionArray:u}=f,v=JSON.parse(JSON.stringify(p)),w=JSON.parse(JSON.stringify(u));// create deep copy to highlight if(""!==t){for(let a=0;a{console.error("Error:",a),window.alert("Invalid query. Please check your search parameters and try again.")}).finally(()=>{document.querySelectorAll("b.collapsed[data-bs-toggle=\"collapse\"]").forEach(a=>a.classList.remove("collapsed")),document.querySelectorAll("div.card-container.collapse:not(.show)").forEach(a=>a.classList.add("show")),Q(!1)})}const[f,g]=React.useState([]),[h,i]=React.useState([]),[j,k]=React.useState([]),[l,m]=React.useState([]),[n,o]=React.useState(0),[p,q]=React.useState(0),[r,s]=React.useState(""),[t,u]=React.useState(""),[v,w]=React.useState("all"),[x,y]=React.useState("all"),[z,A]=React.useState(""),[B,C]=React.useState(""),[D,E]=React.useState(!1),[F,G]=React.useState(!1),[H,I]=React.useState(!1),[J,K]=React.useState(!1),[L,M]=React.useState(!1),[N,O]=React.useState(!0),[P,Q]=React.useState(!1);let[R,S]=React.useState(1),[T,U]=React.useState(1);const[V,W]=React.useState(1),[X,Y]=React.useState(1),[Z,$]=React.useState(0),[_,aa]=React.useState(0),[ba,ca]=React.useState(0),da="true"===window.localStorage.getItem("database-font-size")?window.localStorage.getItem("font-size")??16:16,ea=[];for(let a=0;a{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)}),window.addEventListener("popstate",a=>{if(null===a.state)return o(0),g([]),k([]),q(0),i([]),m([]),W(1),Y(1),$(0),void aa(0);const{tossups:b,highlightedTossupArray:c,bonuses:d,highlightedBonusArray:e,timeElapsed:f,workingMaxReturnLength:h,randomize:j}=a.state,{count:l,questionArray:n}=b,{count:p,questionArray:r}=d;o(l),g(n),k(c),q(p),i(r),m(e),j?(W(1),Y(1)):(W(Math.ceil(l/h)),Y(Math.ceil(p/h))),$(paginationShiftLength*Math.floor((R-1)/paginationShiftLength)),aa(paginationShiftLength*Math.floor((T-1)/paginationShiftLength)),ca(f)}),document.getElementById("set-list").innerHTML=api.getSetList().map(a=>``).join("")},[]),/*#__PURE__*/React.createElement("div",null,/*#__PURE__*/React.createElement(CategoryModal,{categoryManager:categoryManager,disablePercentView:!0}),/*#__PURE__*/React.createElement("form",{className:"mt-3",onSubmit:a=>{e(a)}},/*#__PURE__*/React.createElement("div",{className:"input-group mb-2"},/*#__PURE__*/React.createElement("input",{type:"text",className:"form-control",id:"query",placeholder:"Query",value:t,onChange:a=>{u(a.target.value)}}),/*#__PURE__*/React.createElement("button",{type:"submit",className:"btn btn-info"},"Search"),/*#__PURE__*/React.createElement("button",{id:"randomize",className:"btn btn-success",onClick:a=>{e(a,!0)}},"Random")),/*#__PURE__*/React.createElement("div",{className:"row"},/*#__PURE__*/React.createElement("div",{className:"col-6 col-xl-3 mb-2"},/*#__PURE__*/React.createElement(DifficultyDropdown,null)),/*#__PURE__*/React.createElement("div",{className:"col-6 col-xl-3 mb-2"},/*#__PURE__*/React.createElement("input",{type:"number",className:"form-control",id:"max-return-length",placeholder:"# to Display",value:r,onChange:a=>{s(a.target.value)}})),/*#__PURE__*/React.createElement("div",{className:"input-group col-12 col-xl-6 mb-2"},/*#__PURE__*/React.createElement("input",{type:"text",className:"form-control",id:"set-name",placeholder:"Set Name",list:"set-list"}),/*#__PURE__*/React.createElement("datalist",{id:"set-list"}),/*#__PURE__*/React.createElement("button",{type:"button",className:"btn btn-danger",id:"category-select-button","data-bs-toggle":"modal","data-bs-target":"#category-modal"},"Categories"))),/*#__PURE__*/React.createElement("div",{className:"row"},/*#__PURE__*/React.createElement("div",{className:"col-6 col-md-3 mb-2"},/*#__PURE__*/React.createElement("select",{className:"form-select",id:"search-type",value:x,onChange:a=>{y(a.target.value)}},/*#__PURE__*/React.createElement("option",{value:"all"},"All text"),/*#__PURE__*/React.createElement("option",{value:"question"},"Question"),/*#__PURE__*/React.createElement("option",{value:"answer"},"Answer"))),/*#__PURE__*/React.createElement("div",{className:"col-6 col-md-3 mb-2"},/*#__PURE__*/React.createElement("select",{className:"form-select",id:"question-type",value:v,onChange:a=>{w(a.target.value)}},/*#__PURE__*/React.createElement("option",{value:"all"},"All questions"),/*#__PURE__*/React.createElement("option",{value:"tossup"},"Tossups"),/*#__PURE__*/React.createElement("option",{value:"bonus"},"Bonuses"))),/*#__PURE__*/React.createElement("div",{className:"col-6 col-md-3 mb-2"},/*#__PURE__*/React.createElement("input",{type:"number",className:"form-control",id:"min-year",placeholder:"Min Year",value:z,onChange:a=>{A(a.target.value)}})),/*#__PURE__*/React.createElement("div",{className:"col-6 col-md-3 mb-2"},/*#__PURE__*/React.createElement("input",{type:"number",className:"form-control",id:"max-year",placeholder:"Max Year",value:B,onChange:a=>{C(a.target.value)}}))),/*#__PURE__*/React.createElement("div",{className:"row"},/*#__PURE__*/React.createElement("div",{className:"col-12"},/*#__PURE__*/React.createElement("div",{className:"form-check form-switch"},/*#__PURE__*/React.createElement("input",{className:"form-check-input",type:"checkbox",role:"switch",id:"toggle-regex",checked:D,onChange:()=>{E(!D)}}),/*#__PURE__*/React.createElement("label",{className:"form-check-label",htmlFor:"toggle-regex"},"Search using regular expression"),/*#__PURE__*/React.createElement("a",{href:"https://www.sitepoint.com/learn-regex/"}," What's this?")),/*#__PURE__*/React.createElement("div",{className:"form-check form-switch"},/*#__PURE__*/React.createElement("input",{className:"form-check-input",type:"checkbox",role:"switch",id:"toggle-ignore-word-order",checked:!D&&F,disabled:D,onChange:()=>{G(!F)}}),/*#__PURE__*/React.createElement("label",{className:"form-check-label",htmlFor:"toggle-ignore-word-order"},"Ignore word order")),/*#__PURE__*/React.createElement("div",{className:"form-check form-switch"},/*#__PURE__*/React.createElement("input",{className:"form-check-input",type:"checkbox",role:"switch",id:"toggle-exact-phrase",checked:!D&&H,disabled:D,onChange:()=>{I(!H)}}),/*#__PURE__*/React.createElement("label",{className:"form-check-label",htmlFor:"toggle-exact-phrase"},"Search for exact phrase")),/*#__PURE__*/React.createElement("div",{className:"form-check form-switch"},/*#__PURE__*/React.createElement("input",{className:"form-check-input",type:"checkbox",role:"switch",id:"toggle-powermark-only",checked:J,onChange:()=>{K(!J)}}),/*#__PURE__*/React.createElement("label",{className:"form-check-label",htmlFor:"toggle-powermark-only"},"Powermarked tossups only")),/*#__PURE__*/React.createElement("div",{className:"form-check form-switch"},/*#__PURE__*/React.createElement("input",{className:"form-check-input",type:"checkbox",role:"switch",id:"toggle-hide-answerlines",checked:L,onChange:()=>{M(!L)}}),/*#__PURE__*/React.createElement("label",{className:"form-check-label",htmlFor:"toggle-hide-answerlines"},"Hide answerlines")),/*#__PURE__*/React.createElement("div",{className:"form-check form-switch"},/*#__PURE__*/React.createElement("input",{className:"form-check-input",type:"checkbox",role:"switch",id:"toggle-show-card-footers",checked:N,onChange:()=>{O(!N)}}),/*#__PURE__*/React.createElement("label",{className:"form-check-label",htmlFor:"toggle-show-card-footers"},"Show card footers")),/*#__PURE__*/React.createElement("div",{className:"float-end"},/*#__PURE__*/React.createElement("b",null,"Download this page:"),/*#__PURE__*/React.createElement("a",{className:"ms-2 clickable",onClick:()=>{downloadQuestionsAsText(f,h)}},"TXT"),/*#__PURE__*/React.createElement("a",{className:"ms-2 clickable",onClick:()=>{downloadTossupsAsCSV(f),downloadBonusesAsCSV(h)}},"CSV"),/*#__PURE__*/React.createElement("a",{className:"ms-2 clickable",onClick:()=>{downloadQuestionsAsJSON(f,h)}},"JSON"))))),P&&/*#__PURE__*/React.createElement("div",{className:"d-block mx-auto mt-3 spinner-border",role:"status"},/*#__PURE__*/React.createElement("span",{className:"d-none"},"Loading...")),/*#__PURE__*/React.createElement("div",{className:"row text-center mt-2 mt-sm-0"},/*#__PURE__*/React.createElement("h3",{id:"tossups"},"Tossups")),0window.scrollTo({top:document.getElementById("bonuses").offsetTop,behavior:"smooth"})},"Jump to bonuses")))// eslint-disable-line :/*#__PURE__*/React.createElement("div",{className:"text-muted"},"No tossups found"),/*#__PURE__*/React.createElement("div",null,ea),1{c(a,"first")}},"\xAB")),/*#__PURE__*/React.createElement("li",{className:"page-item"},/*#__PURE__*/React.createElement("a",{className:"page-link",href:"#","aria-label":"Previous",onClick:a=>{c(a,"previous")}},"\u2039")),a(Math.min(Z),Math.min(Z+paginationShiftLength,V)).map(a=>{const b=R===a+1;return/*#__PURE__*/React.createElement("li",{key:`tossup-pagination-${a+1}`,className:"page-item"},/*#__PURE__*/React.createElement("a",{className:`page-link ${b&&"active"}`,href:"#",onClick:b=>{c(b,a+1)}},a+1))}),/*#__PURE__*/React.createElement("li",{className:"page-item"},/*#__PURE__*/React.createElement("a",{className:"page-link",href:"#","aria-label":"Next",onClick:a=>{c(a,"next")}},"\u203A")),/*#__PURE__*/React.createElement("li",{className:"page-item"},/*#__PURE__*/React.createElement("a",{className:"page-link",href:"#","aria-label":"Last",onClick:a=>{c(a,"last")}},/*#__PURE__*/React.createElement("span",{"aria-hidden":"true"},"\xBB"))))),/*#__PURE__*/React.createElement("div",{className:"mb-5"}),/*#__PURE__*/React.createElement("div",{className:"row text-center"},/*#__PURE__*/React.createElement("h3",{id:"bonuses"},"Bonuses")),0window.scrollTo({top:document.getElementById("tossups").offsetTop,behavior:"smooth"})},"Jump to tossups")))// eslint-disable-line :/*#__PURE__*/React.createElement("div",{className:"text-muted"},"No bonuses found"),/*#__PURE__*/React.createElement("div",null,fa),1{d(a,"first")}},"\xAB")),/*#__PURE__*/React.createElement("li",{className:"page-item"},/*#__PURE__*/React.createElement("a",{className:"page-link",href:"#","aria-label":"Previous",onClick:a=>{d(a,"previous")}},"\u2039")),a(Math.min(_),Math.min(_+paginationShiftLength,X)).map(a=>{const b=T===a+1;return/*#__PURE__*/React.createElement("li",{key:`bonus-pagination-${a+1}`,className:"page-item"},/*#__PURE__*/React.createElement("a",{className:`page-link ${b&&"active"}`,href:"#",onClick:b=>{d(b,a+1)}},a+1))}),/*#__PURE__*/React.createElement("li",{className:"page-item"},/*#__PURE__*/React.createElement("a",{className:"page-link",href:"#","aria-label":"Next",onClick:a=>{d(a,"next")}},"\u203A")),/*#__PURE__*/React.createElement("li",{className:"page-item"},/*#__PURE__*/React.createElement("a",{className:"page-link",href:"#","aria-label":"Last",onClick:a=>{d(a,"last")}},/*#__PURE__*/React.createElement("span",{"aria-hidden":"true"},"\xBB"))))),/*#__PURE__*/React.createElement("div",{className:"mb-5"}))}const root=ReactDOM.createRoot(document.getElementById("root"));root.render(/*#__PURE__*/React.createElement(QueryForm,null)); \ No newline at end of file diff --git a/client/multiplayer/room.jsx b/client/multiplayer/room.jsx index 99c9f393..0b306070 100644 --- a/client/multiplayer/room.jsx +++ b/client/multiplayer/room.jsx @@ -4,7 +4,7 @@ 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 '../scripts/utilities/category-manager.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'; diff --git a/client/multiplayer/room.min.js b/client/multiplayer/room.min.js index d242a263..d5efb60d 100644 --- a/client/multiplayer/room.min.js +++ b/client/multiplayer/room.min.js @@ -1,8 +1,8 @@ -/* globals WebSocket */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"../scripts/utilities/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;/** +/* globals WebSocket */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;/** * 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")||(await api.getRandomName());const socket=new 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-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("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("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,validAlternateSubcategories:f,validCategories:g,validSubcategories: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.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 @@ -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",value: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",value: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",value:this.value,packetNumbers:rangeToArray(document.getElementById("packet-number").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{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",value: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("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{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 diff --git a/client/scripts/Timer.js b/client/scripts/Timer.js deleted file mode 100644 index 69b2bfb7..00000000 --- a/client/scripts/Timer.js +++ /dev/null @@ -1,40 +0,0 @@ -export default class Timer { - constructor () { - this.tenthsRemaining = 0; - } - - get seconds () { - return Math.floor(this.tenthsRemaining / 10); - } - - get tenths () { - return this.tenthsRemaining % 10; - } - - stopTimer () { - clearInterval(this.timerInterval); - } - - /** - * - * @param {number} duration - duration of the timer, in seconds - * @param {Function} callback - */ - startTimer (duration, callback) { - clearInterval(this.timerInterval); - this.tenthsRemaining = Math.floor(duration * 10); - this.timerInterval = setInterval(() => { - if (this.tenthsRemaining <= 0) { - clearInterval(this.timerInterval); - callback(); - } - this.updateDisplay(); - this.tenthsRemaining--; - }, 100); - } - - updateDisplay () { - document.querySelector('.timer .face').innerText = this.seconds; - document.querySelector('.timer .fraction').innerText = '.' + this.tenths; - } -} diff --git a/client/singleplayer/ClientTossupRoom.js b/client/singleplayer/ClientTossupRoom.js index 5ea1c5e8..b1877c27 100644 --- a/client/singleplayer/ClientTossupRoom.js +++ b/client/singleplayer/ClientTossupRoom.js @@ -1,6 +1,5 @@ import api from '../scripts/api/index.js'; -// import TossupRoom from '../../quizbowl/TossupRoom.js'; -import TossupRoom from '../TossupRoom.js'; +import TossupRoom from '../../quizbowl/TossupRoom.js'; export default class ClientTossupRoom extends TossupRoom { constructor (name, categories = [], subcategories = [], alternateSubcategories = []) { @@ -15,7 +14,12 @@ export default class ClientTossupRoom extends TossupRoom { powerValue: 15, tossup: {} }; - this.settings.skip = true; + this.settings = { + ...this.settings, + skip: true, + showHistory: true, + typeToAnswer: true + }; this.checkAnswer = api.checkAnswer; this.getRandomTossups = async (args) => await api.getRandomTossup({ number: 20, ...args }); @@ -23,16 +27,27 @@ export default class ClientTossupRoom extends TossupRoom { this.getSetList = api.getSetList; this.getNumPackets = api.getNumPackets; - this.setList = this.getSetList().concat(''); + this.setList = this.getSetList(); } async message (userId, message) { switch (message.type) { case 'toggle-correct': return this.toggleCorrect(userId, message); + case 'toggle-show-history': return this.toggleShowHistory(userId, message); + case 'toggle-type-to-answer': return this.toggleTypeToAnswer(userId, message); default: super.message(userId, message); } } + buzz (userId) { + if (!this.settings.typeToAnswer && this.buzzes.includes(userId)) { + this.giveAnswer(userId, { givenAnswer: this.tossup.answer_sanitized }); + return; + } + + super.buzz(userId); + } + get liveAnswer () { return document.getElementById('answer-input').value; } @@ -74,4 +89,14 @@ export default class ClientTossupRoom extends TossupRoom { this.emitMessage({ type: 'toggle-correct', correct, userId }); } + + toggleShowHistory (userId, { showHistory }) { + this.settings.showHistory = showHistory; + this.emitMessage({ type: 'toggle-show-history', showHistory, userId }); + } + + toggleTypeToAnswer (userId, { typeToAnswer }) { + this.settings.typeToAnswer = typeToAnswer; + this.emitMessage({ type: 'toggle-type-to-answer', typeToAnswer, userId }); + } } diff --git a/client/singleplayer/bonuses/index.jsx b/client/singleplayer/bonuses/index.jsx index 51934483..579ab090 100644 --- a/client/singleplayer/bonuses/index.jsx +++ b/client/singleplayer/bonuses/index.jsx @@ -3,7 +3,7 @@ import questionStats from '../../scripts/auth/question-stats.js'; import api from '../../scripts/api/index.js'; import audio from '../../audio/index.js'; import { arrayToRange, createBonusCard, rangeToArray } from '../../scripts/utilities/index.js'; -import CategoryManager from '../../scripts/utilities/category-manager.js'; +import CategoryManager from '../../../quizbowl/category-manager.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'; diff --git a/client/singleplayer/bonuses/index.min.js b/client/singleplayer/bonuses/index.min.js index 3293d67c..9a05b923 100644 --- a/client/singleplayer/bonuses/index.min.js +++ b/client/singleplayer/bonuses/index.min.js @@ -1,4 +1,4 @@ -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{arrayToRange,createBonusCard,rangeToArray}from"../../scripts/utilities/index.js";import CategoryManager from"../../scripts/utilities/category-manager.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";// Functions and variables specific to the bonuses page. +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{arrayToRange,createBonusCard,rangeToArray}from"../../scripts/utilities/index.js";import CategoryManager from"../../../quizbowl/category-manager.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";// Functions and variables specific to the bonuses page. // Status variables let currentBonusPart=-1,maxPacketNumber=24,questionNumber=0,randomBonuses=[],bonuses=[{}];// WARNING: 1-indexed /** diff --git a/client/singleplayer/tossups/index.jsx b/client/singleplayer/tossups/index.jsx index 44e6461e..aa965308 100644 --- a/client/singleplayer/tossups/index.jsx +++ b/client/singleplayer/tossups/index.jsx @@ -3,10 +3,10 @@ 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 Player from '../../Player.js'; +import Player from '../../../quizbowl/Player.js'; import ClientTossupRoom from '../ClientTossupRoom.js'; -import CategoryManager from '../../scripts/utilities/category-manager.js'; -import { createTossupCard, rangeToArray } from '../../scripts/utilities/index.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'; @@ -14,7 +14,8 @@ import DifficultyDropdown from '../../scripts/components/DifficultyDropdown.min. let maxPacketNumber = 24; const categoryManager = new CategoryManager(); - +const queryVersion = '2024-10-11'; +const settingsVersion = '2024-10-11'; const USER_ID = 'user'; const room = new ClientTossupRoom(); @@ -28,7 +29,6 @@ room.sockets[USER_ID] = socket; function onmessage (message) { const data = JSON.parse(message); - console.log(data); switch (data.type) { case 'buzz': return buzz(data); case 'clear-stats': return clearStats(data); @@ -51,8 +51,10 @@ function onmessage (message) { case 'toggle-powermark-only': return togglePowermarkOnly(data); case 'toggle-rebuzz': return toggleRebuzz(data); case 'toggle-select-by-set-name': return toggleSelectBySetName(data); + case 'toggle-show-history': return toggleShowHistory(data); case 'toggle-standard-only': return toggleStandardOnly(data); case 'toggle-timer': return toggleTimer(data); + case 'toggle-type-to-answer': return toggleTypeToAnswer(data); case 'update-question': return updateQuestion(data); } } @@ -69,8 +71,7 @@ function buzz ({ timer, userId, username }) { } function clearStats ({ userId }) { - if (userId !== USER_ID) { return; } - updateStatDisplay(room.players[USER_ID]); + updateStatDisplay(room.players[userId]); } function endOfSet () { @@ -116,7 +117,7 @@ async function giveAnswer ({ directive, directedPrompt, perQuestionCelerity, sco // } } -async function next ({ oldTossup, tossup: nextTossup, type }) { +async function next ({ packetLength, oldTossup, tossup: nextTossup, type }) { if (type === 'start') { document.getElementById('next').disabled = false; document.getElementById('next').textContent = 'Skip'; @@ -136,10 +137,10 @@ async function next ({ oldTossup, tossup: nextTossup, type }) { document.getElementById('buzz').disabled = false; document.getElementById('next').textContent = 'Skip'; document.getElementById('packet-number-info').textContent = nextTossup.packet.number; - console.log(room); - document.getElementById('packet-length-info').textContent = room.query.selectBySetName ? room.tossup.length : '-'; + document.getElementById('packet-length-info').textContent = room.query.selectBySetName ? packetLength : '-'; document.getElementById('pause').textContent = 'Pause'; document.getElementById('pause').disabled = false; + document.getElementById('question-number-info').textContent = nextTossup.number; document.getElementById('set-name-info').textContent = nextTossup.set.name; if (type === 'next' && await account.getUsername() && document.getElementById('answer').innerHTML) { @@ -175,41 +176,84 @@ function revealAnswer ({ answer, question }) { function setCategories ({ alternateSubcategories, categories, subcategories }) { categoryManager.import(categories, subcategories, alternateSubcategories); categoryManager.loadCategoryModal(); + window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...room.query, version: queryVersion })); } -function setDifficulties ({ difficulties }) {} +function setDifficulties ({ difficulties }) { + window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...room.query, version: queryVersion })); +} -function setPacketNumbers ({ packetNumbers }) {} +function setPacketNumbers ({ packetNumbers }) { + document.getElementById('packet-number').value = arrayToRange(packetNumbers); + window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...room.query, version: queryVersion })); +} function setReadingSpeed ({ readingSpeed }) { document.getElementById('reading-speed').value = readingSpeed; document.getElementById('reading-speed-display').textContent = readingSpeed; + window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...room.settings, version: settingsVersion })); } -function setSetName ({ value }) {} +async function setSetName ({ setName }) { + document.getElementById('set-name').value = setName; + // make border red if set name is not in set list + const valid = !setName || api.getSetList().includes(setName); + document.getElementById('set-name').classList.toggle('is-invalid', !valid); + maxPacketNumber = valid ? await api.getNumPackets(setName) : 0; + document.getElementById('packet-number').placeholder = 'Packet Numbers' + (maxPacketNumber ? ` (1-${maxPacketNumber})` : ''); + window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...room.query, version: queryVersion })); +} -function setYearRange ({ minYear, maxYear }) {} +function setYearRange ({ minYear, maxYear }) { + $('#slider').slider('values', [minYear, maxYear]); + document.getElementById('year-range-a').textContent = minYear; + document.getElementById('year-range-b').textContent = maxYear; + window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...room.query, version: queryVersion })); +} function toggleCorrect ({ correct, userId }) { updateStatDisplay(room.players[USER_ID]); document.getElementById('toggle-correct').textContent = correct ? 'I was wrong' : 'I was right'; } -function togglePowermarkOnly ({ powermarkOnly }) {} +function togglePowermarkOnly ({ powermarkOnly }) { + document.getElementById('toggle-powermark-only').checked = powermarkOnly; + window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...room.query, version: queryVersion })); +} -function toggleRebuzz ({ rebuzz }) {} +function toggleRebuzz ({ rebuzz }) { + document.getElementById('toggle-rebuzz').checked = rebuzz; + window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...room.settings, version: settingsVersion })); +} -function toggleSelectBySetName ({ selectBySetName, setName }) { +function toggleSelectBySetName ({ selectBySetName }) { document.getElementById('difficulty-settings').classList.toggle('d-none', selectBySetName); - document.getElementById('set-settings').classList.toggle('d-none', !selectBySetName); document.getElementById('toggle-powermark-only').disabled = selectBySetName; + document.getElementById('toggle-select-by-set-name').checked = selectBySetName; document.getElementById('toggle-standard-only').disabled = selectBySetName; + document.getElementById('set-settings').classList.toggle('d-none', !selectBySetName); + window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...room.query, version: queryVersion })); } -function toggleStandardOnly ({ standardOnly }) {} +function toggleShowHistory ({ showHistory }) { + document.getElementById('room-history').classList.toggle('d-none', !showHistory); + document.getElementById('toggle-show-history').checked = showHistory; + window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...room.settings, version: settingsVersion })); +} + +function toggleStandardOnly ({ standardOnly }) { + document.getElementById('toggle-standard-only').checked = standardOnly; +} function toggleTimer ({ timer }) { document.getElementById('timer').classList.toggle('d-none', !timer); + document.getElementById('toggle-timer').checked = timer; + window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...room.settings, version: settingsVersion })); +} + +function toggleTypeToAnswer ({ typeToAnswer }) { + document.getElementById('type-to-answer').checked = typeToAnswer; + window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...room.settings, version: settingsVersion })); } function updateQuestion ({ word }) { @@ -265,8 +309,8 @@ document.getElementById('next').addEventListener('click', function () { document.getElementById('packet-number').addEventListener('change', function () { const range = rangeToArray(this.value.trim(), maxPacketNumber); - - if (range.some((num) => num < 1 || num > maxPacketNumber)) { + const invalid = range.some(num => num < 1 || num > maxPacketNumber); + if (invalid) { document.getElementById('packet-number').classList.add('is-invalid'); return; } @@ -296,21 +340,9 @@ document.getElementById('report-question-submit').addEventListener('click', func }); document.getElementById('set-name').addEventListener('change', async function () { - // make border red if set name is not in set list - const valid = api.getSetList().includes(this.value) || this.value.length === 0; - this.classList.toggle('is-invalid', !valid); - - maxPacketNumber = await api.getNumPackets(this.value); - - if (this.value === '' || maxPacketNumber === 0) { - document.getElementById('packet-number').placeholder = 'Packet Numbers'; - } else { - document.getElementById('packet-number').placeholder = `Packet Numbers (1-${maxPacketNumber})`; - } - socket.sendToServer({ type: 'set-set-name', - value: this.value.trim(), + setName: this.value.trim(), packetNumbers: rangeToArray(document.getElementById('packet-number').value) }); }); @@ -338,7 +370,6 @@ document.getElementById('toggle-select-by-set-name').addEventListener('click', f this.blur(); socket.sendToServer({ type: 'toggle-select-by-set-name', - setName: document.getElementById('set-name').value, selectBySetName: this.checked }); }); @@ -355,7 +386,7 @@ document.getElementById('toggle-settings').addEventListener('click', function () document.getElementById('toggle-show-history').addEventListener('click', function () { this.blur(); - document.getElementById('room-history').classList.toggle('d-none', !this.checked); + socket.sendToServer({ type: 'toggle-show-history', showHistory: this.checked }); }); document.getElementById('toggle-standard-only').addEventListener('click', function () { @@ -368,6 +399,11 @@ document.getElementById('toggle-timer').addEventListener('click', function () { 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 minYear = $('#slider').slider('values', 0); const maxYear = $('#slider').slider('values', 1); @@ -386,39 +422,52 @@ document.addEventListener('keydown', (event) => { switch (event.key) { case ' ': document.getElementById('buzz').click(); - // Prevent spacebar from scrolling the page: - if (event.target === document.body) event.preventDefault(); - break; - case 'e': - document.getElementById('toggle-settings').click(); - break; - case 'k': - document.getElementsByClassName('card-header-clickable')[0].click(); - break; - case 't': - document.getElementsByClassName('star-tossup')[0].click(); - break; - case 'y': - navigator.clipboard.writeText(room.tossup._id ?? ''); - break; - case 'n': - document.getElementById('next').click(); - break; - case 'p': - document.getElementById('pause').click(); - break; - case 's': - document.getElementById('start').click(); + if (event.target === document.body) { + // Prevent spacebar from scrolling the page: + event.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 ?? ''); } }); -// $(document).ready(function () { -// $('#slider').slider('values', 0, query.minYear); -// $('#slider').slider('values', 1, query.maxYear); -// }); -// document.getElementById('year-range-a').textContent = query.minYear; -// document.getElementById('year-range-b').textContent = query.maxYear; +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); + socket.sendToServer({ type: 'set-packet-numbers', ...savedQuery }); + socket.sendToServer({ type: 'set-set-name', ...savedQuery }); + socket.sendToServer({ type: 'set-year-range', ...savedQuery }); + socket.sendToServer({ type: 'toggle-powermark-only', ...savedQuery }); + socket.sendToServer({ type: 'toggle-select-by-set-name', ...savedQuery }); + socket.sendToServer({ type: 'toggle-standard-only', ...savedQuery }); + startingDifficulties = savedQuery.difficulties; + } catch { + window.localStorage.removeItem('singleplayer-tossup-query'); + } +} + +if (window.localStorage.getItem('singleplayer-tossup-settings')) { + try { + const savedSettings = JSON.parse(window.localStorage.getItem('singleplayer-tossup-settings')); + if (savedSettings.version !== settingsVersion) { throw new Error(); } + socket.sendToServer({ type: 'set-reading-speed', ...savedSettings }); + socket.sendToServer({ type: 'toggle-rebuzz', ...savedSettings }); + socket.sendToServer({ type: 'toggle-show-history', ...savedSettings }); + socket.sendToServer({ type: 'toggle-timer', ...savedSettings }); + socket.sendToServer({ type: 'toggle-type-to-answer', ...savedSettings }); + } catch { + window.localStorage.removeItem('singleplayer-tossup-settings'); + } +} ReactDOM.createRoot(document.getElementById('category-modal-root')).render( socket.sendToServer({ type: 'set-difficulties', difficulties: getDropdownValues('difficulties') })} /> ); diff --git a/client/singleplayer/tossups/index.min.js b/client/singleplayer/tossups/index.min.js index 911715a7..4f8f001f 100644 --- a/client/singleplayer/tossups/index.min.js +++ b/client/singleplayer/tossups/index.min.js @@ -1,8 +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 Player from"../../Player.js";import ClientTossupRoom from"../ClientTossupRoom.js";import CategoryManager from"../../scripts/utilities/category-manager.js";import{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,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(console.log(b),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-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-standard-only":return toggleStandardOnly(b);case"toggle-timer":return toggleTimer(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}){a!==USER_ID||updateStatDisplay(room.players[USER_ID])}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-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)?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",value: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(){// make border red if set name is not in set list -const a=api.getSetList().includes(this.value)||0===this.value.length;this.classList.toggle("is-invalid",!a),maxPacketNumber=await api.getNumPackets(this.value),document.getElementById("packet-number").placeholder=""===this.value||0===maxPacketNumber?"Packet Numbers":`Packet Numbers (1-${maxPacketNumber})`,socket.sendToServer({type:"set-set-name",value:this.value.trim(),packetNumbers:rangeToArray(document.getElementById("packet-number").value)})}),document.getElementById("start").addEventListener("click",function(){socket.sendToServer({type:"start"})}),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",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-show-history").addEventListener("click",function(){this.blur(),document.getElementById("room-history").classList.toggle("d-none",!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("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){case" ":document.getElementById("buzz").click(),a.target===document.body&&a.preventDefault();break;case"e":document.getElementById("toggle-settings").click();break;case"k":document.getElementsByClassName("card-header-clickable")[0].click();break;case"t":document.getElementsByClassName("star-tossup")[0].click();break;case"y":navigator.clipboard.writeText(room.tossup._id??"");break;case"n":document.getElementById("next").click();break;case"p":document.getElementById("pause").click();break;case"s":document.getElementById("start").click()}}),window.localStorage.getItem("singleplayer-tossup-query"))try{const a=JSON.parse(window.localStorage.getItem("singleplayer-tossup-query"));if("01-06-2024"!==a.version)throw new Error;// socket.sendToServer({ type: 'set-categories', ...savedQuery }); -// socket.sendToServer({ type: 'set-difficulties', ...savedQuery }); -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-standard-only",...a})}catch{window.localStorage.removeItem("singleplayer-tossup-query")}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,{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("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){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),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-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/client/singleplayer/tossups/old-index.jsx b/client/singleplayer/tossups/old-index.jsx deleted file mode 100644 index 22f442b4..00000000 --- a/client/singleplayer/tossups/old-index.jsx +++ /dev/null @@ -1,809 +0,0 @@ -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 Timer from '../../scripts/Timer.js'; -import { arrayToRange, createTossupCard, rangeToArray } from '../../scripts/utilities/index.js'; -import CategoryManager from '../../scripts/utilities/category-manager.js'; -import { getDropdownValues } from '../../scripts/utilities/dropdown-checklist.js'; -import { insertTokensIntoHTML } from '../../insert-tokens-into-html.js'; -import CategoryModal from '../../scripts/components/CategoryModal.min.js'; -import DifficultyDropdown from '../../scripts/components/DifficultyDropdown.min.js'; - -// Functions and variables specific to the tossups page. - -const ANSWER_TIME_LIMIT = 10; -const DEAD_TIME_LIMIT = 5; - -// Status variables -let buzzpointIndex = -1; -let currentlyBuzzing = false; -let maxPacketNumber = 24; -let paused = false; -let questionNumber = 0; // WARNING: 1-indexed -const timer = new Timer(); - -/** - * An array of random questions. - * We get 20 random questions at a time so we don't have to make an HTTP request between every question. - */ -let randomTossups = []; -let timeoutID = -1; - -let tossups = [{}]; -let tossupText = ''; -let tossupTextSplit = []; - -const previous = { - isCorrect: true, - inPower: false, - negValue: -5, - powerValue: 15, - endOfQuestion: false, - celerity: 0 -}; - -const stats = window.sessionStorage.getItem('tossup-stats') - ? JSON.parse(window.sessionStorage.getItem('tossup-stats')) - : { - powers: 0, - tens: 0, - negs: 0, - dead: 0, - points: 0, - totalCorrectCelerity: 0 - }; - -const defaults = { - alternateSubcategories: [], - categories: [], - difficulties: [], - minYear: 2010, - maxYear: 2024, - packetNumbers: [], - powermarkOnly: false, - setName: '', - standardOnly: false, - subcategories: [], - version: '01-06-2024' -}; - -let query; -if (!window.localStorage.getItem('singleplayer-tossup-query')) { - query = defaults; -} else { - query = JSON.parse(window.localStorage.getItem('singleplayer-tossup-query')); - if (query.version !== defaults.version) { - query = defaults; - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); - } -} - -const categoryManager = new CategoryManager(query.categories, query.subcategories, query.alternateSubcategories); - -const settings = window.localStorage.getItem('singleplayer-tossup-settings') - ? JSON.parse(window.localStorage.getItem('singleplayer-tossup-settings')) - : { - readingSpeed: 50, - rebuzz: false, - selectBySetName: false, - showHistory: true, - timer: true, - typeToAnswer: true - }; - -// Load query and settings first so user doesn't see the default settings -if (settings.readingSpeed) { - document.getElementById('reading-speed-display').textContent = settings.readingSpeed; - document.getElementById('reading-speed').value = settings.readingSpeed; -} - -if (settings.rebuzz) { - document.getElementById('toggle-rebuzz').checked = true; -} - -if (settings.selectBySetName) { - document.getElementById('difficulty-settings').classList.add('d-none'); - document.getElementById('set-settings').classList.remove('d-none'); - document.getElementById('toggle-select-by-set-name').checked = true; - document.getElementById('toggle-powermark-only').disabled = true; - document.getElementById('toggle-standard-only').disabled = true; -} - -if (!settings.showHistory) { - document.getElementById('toggle-show-history').checked = false; - document.getElementById('room-history').classList.add('d-none'); -} - -if (!settings.timer) { - document.getElementById('toggle-timer').checked = false; - document.getElementById('timer').classList.add('d-none'); -} - -if (!settings.typeToAnswer) { - document.getElementById('type-to-answer').checked = false; - document.getElementById('toggle-rebuzz').disabled = true; -} - -if (query.packetNumbers) { - document.getElementById('packet-number').value = arrayToRange(query.packetNumbers); -} - -if (query.powermarkOnly) { - document.getElementById('toggle-powermark-only').checked = true; -} - -if (query.setName) { - document.getElementById('set-name').value = query.setName; - api.getNumPackets(query.setName).then(numPackets => { - maxPacketNumber = numPackets; - if (maxPacketNumber === 0) { - document.getElementById('set-name').classList.add('is-invalid'); - } else { - document.getElementById('packet-number').placeholder = `Packet Numbers (1-${maxPacketNumber})`; - } - }); -} - -updateStatDisplay(); - -function queryLock () { - document.getElementById('question').textContent = 'Fetching questions...'; - document.getElementById('start').disabled = true; - document.getElementById('next').disabled = true; - document.getElementById('pause').disabled = true; - document.getElementById('buzz').disabled = true; -} - -function queryUnlock () { - document.getElementById('question').textContent = ''; - document.getElementById('start').disabled = false; - document.getElementById('next').disabled = false; - document.getElementById('pause').disabled = false; - document.getElementById('buzz').disabled = false; -} - -/** - * @returns {Promise} Whether or not there is a next question - */ -async function advanceQuestion () { - if (settings.selectBySetName) { - // Get the next question if the current one is in the wrong category and subcategory - do { - questionNumber++; - - // Go to the next packet if you reach the end of this packet - if (questionNumber > tossups.length) { - query.packetNumbers.shift(); - if (query.packetNumbers.length === 0) { - window.alert('No more questions left'); - document.getElementById('buzz').disabled = true; - document.getElementById('pause').disabled = true; - document.getElementById('next').disabled = true; - return false; // alert the user if there are no more packets - } - - queryLock(); - try { - tossups = await api.getPacketTossups(query.setName, query.packetNumbers[0]); - } finally { - queryUnlock(); - } - - questionNumber = 1; - } - } while (!categoryManager.isValidCategory(tossups[questionNumber - 1])); - - if (Object.keys(tossups[0]).length > 0) { - tossupText = tossups[questionNumber - 1].question_sanitized; - tossupTextSplit = tossupText.split(' ').filter(word => word !== ''); - document.getElementById('question-number-info').textContent = questionNumber; - } - } else { - queryLock(); - try { - tossups = await getRandomTossup(query, categoryManager); - tossups = [tossups]; - } finally { - queryUnlock(); - } - - if (!tossups[0]) { - window.alert('No questions found'); - return false; - } - - query.setName = tossups[0].set.name; - query.packetNumbers = [tossups[0].packet.number]; - - tossupText = tossups[0].question_sanitized; - tossupTextSplit = tossupText.split(' ').filter(word => word !== ''); - document.getElementById('question-number-info').textContent = tossups[0].number; - questionNumber = 1; - } - - return true; -} - -/** - * Called when the users buzzes. - * The first "buzz" pauses the question, and the second "buzz" reveals the rest of the question - * and updates the score. - */ -function buzz () { - // Stop the question reading - clearTimeout(timeoutID); - currentlyBuzzing = true; - if (audio.soundEffects) audio.buzz.play(); - - buzzpointIndex = document.getElementById('question').textContent.length; - if (!tossupTextSplit.includes('(*)') && tossupText.includes('(*)')) { - buzzpointIndex += 3; - } - - // Include buzzpoint - document.getElementById('question').textContent += '(#) '; - - document.getElementById('buzz').textContent = 'Reveal'; - document.getElementById('next').disabled = true; - document.getElementById('start').disabled = true; - document.getElementById('pause').disabled = true; - - if (settings.timer) { - timer.stopTimer(); - timer.startTimer(ANSWER_TIME_LIMIT, () => document.getElementById('answer-submit').click()); - } -} - -/** - * Clears user stats. - */ -function clearStats () { - stats.powers = 0; - stats.tens = 0; - stats.negs = 0; - stats.dead = 0; - stats.points = 0; - stats.totalCorrectCelerity = 0; - - updateStatDisplay(); - window.sessionStorage.removeItem('tossup-stats'); -} - -async function giveAnswer (givenAnswer) { - currentlyBuzzing = false; - - const { directive, directedPrompt } = await api.checkAnswer(tossups[questionNumber - 1].answer, givenAnswer); - - switch (directive) { - case 'accept': { - const points = updateScore(true); - if (audio.soundEffects) { - if (points > 10) { - audio.power.play(); - } else { - audio.correct.play(); - } - } - revealQuestion(); - break; - } - case 'reject': - updateScore(false); - if (audio.soundEffects) audio.incorrect.play(); - if (settings.rebuzz) { - document.getElementById('buzz').disabled = false; - document.getElementById('buzz').textContent = 'Buzz'; - document.getElementById('next').disabled = false; - document.getElementById('pause').disabled = false; - document.getElementById('start').disabled = false; - readQuestion(Date.now()); - } else { - revealQuestion(); - } - break; - case 'prompt': - document.getElementById('answer-input-group').classList.remove('d-none'); - document.getElementById('answer-input').focus(); - document.getElementById('answer-input').placeholder = directedPrompt ? `Prompt: "${directedPrompt}"` : 'Prompt'; - break; - } -} - -function isPace (setName) { - if (!setName) { return false; } - - return setName.includes('PACE'); -} - -async function loadRandomTossups ({ alternateSubcategories, categories, difficulties, maxYear, minYear, number = 1, powermarkOnly, standardOnly, subcategories } = {}) { - randomTossups = []; - randomTossups = await api.getRandomTossup({ alternateSubcategories, categories, difficulties, maxYear, minYear, number, powermarkOnly, standardOnly, subcategories }); -} - -/** - * Get a random tossup. - * @returns - */ -async function getRandomTossup ({ alternateSubcategories, categories, difficulties, minYear, maxYear, powermarkOnly, subcategories, standardOnly } = {}, categoryManager = null) { - if (categoryManager?.percentView) { - categories = [categoryManager.getRandomCategory()]; - subcategories = []; - alternateSubcategories = []; - await loadRandomTossups({ alternateSubcategories, categories, difficulties, maxYear, minYear, powermarkOnly, subcategories, standardOnly }); - return randomTossups.pop(); - } - - if (randomTossups.length === 0) { - await loadRandomTossups({ alternateSubcategories, categories, difficulties, maxYear, minYear, number: 20, powermarkOnly, subcategories, standardOnly }); - } - - const randomQuestion = randomTossups.pop(); - - // Begin loading the next batch of questions (asynchronously) - if (randomTossups.length === 0) { - loadRandomTossups({ alternateSubcategories, categories, difficulties, maxYear, minYear, number: 20, powermarkOnly, subcategories, standardOnly }); - } - - return randomQuestion; -} - -async function next () { - // Stop reading the current question: - clearTimeout(timeoutID); - currentlyBuzzing = false; - if (settings.timer) { - timer.stopTimer(); - timer.tenthsRemaining = 0; - timer.updateDisplay(); - } - - if (await account.getUsername() && document.getElementById('answer').innerHTML) { - const pointValue = previous.isCorrect ? (previous.inPower ? previous.powerValue : 10) : (previous.endOfQuestion ? 0 : previous.negValue); - questionStats.recordTossup(tossups[questionNumber - 1], previous.isCorrect, pointValue, previous.celerity, false); - } - - document.getElementById('answer').textContent = ''; - document.getElementById('question').textContent = ''; - document.getElementById('toggle-correct').textContent = 'I was wrong'; - document.getElementById('toggle-correct').classList.add('d-none'); - - const hasNextQuestion = await advanceQuestion(); - - if (!hasNextQuestion) { - return; - } - - document.getElementById('buzz').textContent = 'Buzz'; - document.getElementById('buzz').disabled = false; - document.getElementById('next').textContent = 'Skip'; - document.getElementById('packet-number-info').textContent = query.packetNumbers[0]; - document.getElementById('packet-length-info').textContent = settings.selectBySetName ? tossups.length : '-'; - document.getElementById('pause').textContent = 'Pause'; - document.getElementById('pause').disabled = false; - document.getElementById('question').textContent = ''; - document.getElementById('set-name-info').textContent = query.setName; - - paused = false; - readQuestion(Date.now()); -} - -/** - * Toggles pausing or resuming the tossup. - */ -function pause () { - if (paused) { - document.getElementById('buzz').removeAttribute('disabled'); - document.getElementById('pause').textContent = 'Pause'; - readQuestion(Date.now()); - } else { - document.getElementById('buzz').setAttribute('disabled', 'disabled'); - document.getElementById('pause').textContent = 'Resume'; - clearTimeout(timeoutID); - } - paused = !paused; -} - -/** - * Recursively reads the question based on the reading speed. - */ -function readQuestion (expectedReadTime) { - if (!currentlyBuzzing && tossupTextSplit.length > 0) { - const word = tossupTextSplit.shift(); - if (word !== '(*)') { - document.getElementById('question').textContent += word + ' '; - } - - // calculate time needed before reading next word - let time = Math.log(word.length) + 1; - if ((word.endsWith('.') && word.charCodeAt(word.length - 2) > 96 && word.charCodeAt(word.length - 2) < 123) || - word.slice(-2) === '.\u201d' || word.slice(-2) === '!\u201d' || word.slice(-2) === '?\u201d') { time += 2; } else if (word.endsWith(',') || word.slice(-2) === ',\u201d') { time += 0.75; } else if (word === '(*)') { time = 0; } - - time = time * 0.9 * (125 - settings.readingSpeed); - const delay = time - Date.now() + expectedReadTime; - - timeoutID = window.setTimeout(() => { - readQuestion(time + expectedReadTime); - }, delay); - } else { - document.getElementById('pause').disabled = true; - if (settings.timer) { - timer.startTimer(DEAD_TIME_LIMIT, revealQuestion); - } - } -} - -function revealQuestion () { - document.getElementById('question').innerHTML = insertTokensIntoHTML(tossups[questionNumber - 1].question, tossups[questionNumber - 1].question_sanitized, [[buzzpointIndex]], [' (#) ']); - document.getElementById('answer').innerHTML = 'ANSWER: ' + tossups[questionNumber - 1].answer; - - document.getElementById('buzz').disabled = true; - document.getElementById('buzz').textContent = 'Buzz'; - document.getElementById('next').disabled = false; - document.getElementById('next').textContent = 'Next'; - document.getElementById('start').disabled = false; - - document.getElementById('toggle-correct').classList.remove('d-none'); - document.getElementById('toggle-correct').textContent = previous.isCorrect ? 'I was wrong' : 'I was right'; -} - -function toggleCorrect () { - const multiplier = previous.isCorrect ? -1 : 1; - - if (previous.inPower) { - stats.powers += multiplier * 1; - stats.points += multiplier * previous.powerValue; - } else { - stats.tens += multiplier * 1; - stats.points += multiplier * 10; - } - - if (previous.endOfQuestion) { - stats.dead += multiplier * -1; - } else { - stats.negs += multiplier * -1; - stats.points += multiplier * -previous.negValue; - } - - stats.totalCorrectCelerity += multiplier * previous.celerity; - - previous.isCorrect = !previous.isCorrect; - document.getElementById('toggle-correct').textContent = previous.isCorrect ? 'I was wrong' : 'I was right'; - - updateStatDisplay(); - window.sessionStorage.setItem('tossup-stats', JSON.stringify(stats)); -} - -function updateScore (isCorrect) { - const endOfQuestion = (tossupTextSplit.length === 0); - const inPower = tossupTextSplit.includes('(*)') && tossupText.includes('(*)'); - const powerValue = isPace(query.setName) ? 20 : 15; - const negValue = isPace(query.setName) ? 0 : -5; - const points = isCorrect ? (inPower ? powerValue : 10) : (endOfQuestion ? 0 : negValue); - - const characterCount = tossupTextSplit.join(' ').length; - const celerity = characterCount / tossupText.length; - - let result; - - if (isCorrect) { - result = inPower ? 'powers' : 'tens'; - stats.totalCorrectCelerity += celerity; - } else { - result = endOfQuestion ? 'dead' : 'negs'; - } - - stats[result] += 1; - stats.points += points; - - previous.celerity = celerity; - previous.endOfQuestion = endOfQuestion; - previous.inPower = inPower; - previous.negValue = negValue; - previous.powerValue = powerValue; - previous.isCorrect = isCorrect; - - updateStatDisplay(); - window.sessionStorage.setItem('tossup-stats', JSON.stringify(stats)); - - return points; -} - -/** - * Updates the displayed stat line. - */ -function updateStatDisplay () { - const { powers, tens, negs, dead, points, totalCorrectCelerity } = stats; - const numTossups = powers + tens + negs + dead; - const numCorrectTossups = powers + tens; - let celerity = numCorrectTossups === 0 ? 0 : parseFloat(totalCorrectCelerity) / numCorrectTossups; - celerity = Math.round(1000 * celerity) / 1000; - const includePlural = (numTossups === 1) ? '' : 's'; - document.getElementById('statline').innerHTML = - `${powers}/${tens}/${negs} with ${numTossups} tossup${includePlural} seen (${points} pts, celerity: ${celerity})`; - - // disable clear stats button if no stats - document.getElementById('clear-stats').disabled = (numTossups === 0); -} - -document.getElementById('answer-form').addEventListener('submit', function (event) { - event.preventDefault(); - event.stopPropagation(); - - if (settings.timer) { - timer.stopTimer(); - timer.tenthsRemaining = 0; - timer.updateDisplay(); - } - - const answer = document.getElementById('answer-input').value; - - 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'); - - giveAnswer(answer); -}); - -document.getElementById('buzz').addEventListener('click', function () { - this.blur(); - - // reveal answer on second click - // when NOT using type to answer - if (currentlyBuzzing) { - currentlyBuzzing = false; - updateScore(true); - revealQuestion(); - return; - } - - buzz(); - - if (settings.typeToAnswer) { - document.getElementById('answer-input-group').classList.remove('d-none'); - document.getElementById('answer-input').focus(); - this.disabled = true; - } -}); - -document.getElementById('clear-stats').addEventListener('click', function () { - this.blur(); - clearStats(); -}); - -document.getElementById('next').addEventListener('click', function () { - this.blur(); - createTossupCard(tossups[questionNumber - 1]); - next(); -}); - -document.getElementById('packet-number').addEventListener('change', function () { - // if field is blank, store blank result in `query` - query.packetNumbers = rangeToArray(this.value.trim(), 0); - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); - query.packetNumbers = rangeToArray(this.value.trim(), maxPacketNumber); -}); - -document.getElementById('pause').addEventListener('click', function () { - this.blur(); - pause(); -}); - -document.getElementById('reading-speed').addEventListener('input', function () { - settings.readingSpeed = this.value; - document.getElementById('reading-speed-display').textContent = this.value; - window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify(settings)); -}); - -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 () { - query.setName = this.value.trim(); - - // make border red if set name is not in set list - if (api.getSetList().includes(this.value) || this.value.length === 0) { - this.classList.remove('is-invalid'); - } else { - this.classList.add('is-invalid'); - } - - maxPacketNumber = await api.getNumPackets(this.value); - - if (this.value === '' || maxPacketNumber === 0) { - document.getElementById('packet-number').placeholder = 'Packet Numbers'; - } else { - document.getElementById('packet-number').placeholder = `Packet Numbers (1-${maxPacketNumber})`; - } - - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); -}); - -document.getElementById('start').addEventListener('click', async function () { - this.blur(); - if (query.setName.length === 0 && settings.selectBySetName) { - window.alert('Please enter a set name.'); - return false; - } - - if (query.packetNumbers.length === 0 && settings.selectBySetName) { - query.packetNumbers = rangeToArray(document.getElementById('packet-number').value.trim(), maxPacketNumber); - } - - document.getElementById('next').disabled = false; - document.getElementById('next').textContent = 'Skip'; - document.getElementById('settings').classList.add('d-none'); - - if (settings.selectBySetName) { - queryLock(); - questionNumber = 0; - try { - tossups = await api.getPacketTossups(query.setName, query.packetNumbers[0]); - } finally { - queryUnlock(); - } - } - - next(); -}); - -document.getElementById('toggle-correct').addEventListener('click', function () { - this.blur(); - toggleCorrect(); -}); - -document.getElementById('toggle-powermark-only').addEventListener('click', function () { - this.blur(); - query.powermarkOnly = this.checked; - loadRandomTossups(query); - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); -}); - -document.getElementById('toggle-select-by-set-name').addEventListener('click', function () { - this.blur(); - settings.selectBySetName = this.checked; - document.getElementById('toggle-powermark-only').disabled = this.checked; - document.getElementById('toggle-standard-only').disabled = this.checked; - - if (this.checked) { - document.getElementById('difficulty-settings').classList.add('d-none'); - document.getElementById('set-settings').classList.remove('d-none'); - } else { - document.getElementById('difficulty-settings').classList.remove('d-none'); - document.getElementById('set-settings').classList.add('d-none'); - } - - window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify(settings)); -}); - -document.getElementById('toggle-show-history').addEventListener('click', function () { - this.blur(); - settings.showHistory = this.checked; - - if (this.checked) { - document.getElementById('room-history').classList.remove('d-none'); - } else { - document.getElementById('room-history').classList.add('d-none'); - } - - window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify(settings)); -}); - -document.getElementById('toggle-standard-only').addEventListener('click', function () { - this.blur(); - query.standardOnly = this.checked; - loadRandomTossups(query); - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); -}); - -document.getElementById('toggle-timer').addEventListener('click', function () { - this.blur(); - settings.timer = this.checked; - document.getElementById('timer').classList.toggle('d-none'); - window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify(settings)); -}); - -document.getElementById('type-to-answer').addEventListener('click', function () { - this.blur(); - settings.typeToAnswer = this.checked; - document.getElementById('toggle-rebuzz').disabled = !this.checked; - window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify(settings)); -}); - -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-rebuzz').addEventListener('click', function () { - this.blur(); - settings.rebuzz = this.checked; - window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify(settings)); -}); - -document.getElementById('year-range-a').onchange = function () { - query.minYear = $('#slider').slider('values', 0); - query.maxYear = $('#slider').slider('values', 1); - loadRandomTossups(query); - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); -}; - -document.getElementById('year-range-b').onchange = function () { - query.minYear = $('#slider').slider('values', 0); - query.maxYear = $('#slider').slider('values', 1); - loadRandomTossups(query); - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); -}; - -document.addEventListener('keydown', (event) => { - if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName)) return; - - switch (event.key) { - case ' ': - document.getElementById('buzz').click(); - // Prevent spacebar from scrolling the page: - if (event.target === document.body) event.preventDefault(); - break; - case 'e': - document.getElementById('toggle-settings').click(); - break; - case 'k': - document.getElementsByClassName('card-header-clickable')[0].click(); - break; - case 't': - document.getElementsByClassName('star-tossup')[0].click(); - break; - case 'y': - navigator.clipboard.writeText(tossups[0]?._id ?? ''); - break; - case 'n': - document.getElementById('next').click(); - break; - case 'p': - document.getElementById('pause').click(); - break; - case 's': - document.getElementById('start').click(); - break; - } -}); - -$(document).ready(function () { - $('#slider').slider('values', 0, query.minYear); - $('#slider').slider('values', 1, query.maxYear); -}); -document.getElementById('year-range-a').textContent = query.minYear; -document.getElementById('year-range-b').textContent = query.maxYear; - -ReactDOM.createRoot(document.getElementById('category-modal-root')).render( - { - ({ categories: query.categories, subcategories: query.subcategories, alternateSubcategories: query.alternateSubcategories } = categoryManager.export()); - loadRandomTossups(query); - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); - }} - /> -); - -ReactDOM.createRoot(document.getElementById('difficulty-dropdown-root')).render( - { - query.difficulties = getDropdownValues('difficulties'); - loadRandomTossups(query); - window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query)); - }} - /> -); diff --git a/client/singleplayer/tossups/old-index.min.js b/client/singleplayer/tossups/old-index.min.js deleted file mode 100644 index 09471d56..00000000 --- a/client/singleplayer/tossups/old-index.min.js +++ /dev/null @@ -1,36 +0,0 @@ -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 Timer from"../../scripts/Timer.js";import{arrayToRange,createTossupCard,rangeToArray}from"../../scripts/utilities/index.js";import CategoryManager from"../../scripts/utilities/category-manager.js";import{getDropdownValues}from"../../scripts/utilities/dropdown-checklist.js";import{insertTokensIntoHTML}from"../../insert-tokens-into-html.js";import CategoryModal from"../../scripts/components/CategoryModal.min.js";import DifficultyDropdown from"../../scripts/components/DifficultyDropdown.min.js";// Functions and variables specific to the tossups page. -const ANSWER_TIME_LIMIT=10,DEAD_TIME_LIMIT=5;// Status variables -let buzzpointIndex=-1,currentlyBuzzing=!1,maxPacketNumber=24,paused=!1,questionNumber=0;// WARNING: 1-indexed -const timer=new Timer;/** - * An array of random questions. - * We get 20 random questions at a time so we don't have to make an HTTP request between every question. - */let randomTossups=[],timeoutID=-1,tossups=[{}],tossupText="",tossupTextSplit=[];const previous={isCorrect:!0,inPower:!1,negValue:-5,powerValue:15,endOfQuestion:!1,celerity:0},stats=window.sessionStorage.getItem("tossup-stats")?JSON.parse(window.sessionStorage.getItem("tossup-stats")):{powers:0,tens:0,negs:0,dead:0,points:0,totalCorrectCelerity:0},defaults={alternateSubcategories:[],categories:[],difficulties:[],minYear:2010,maxYear:2024,packetNumbers:[],powermarkOnly:!1,setName:"",standardOnly:!1,subcategories:[],version:"01-06-2024"};let query;window.localStorage.getItem("singleplayer-tossup-query")?(query=JSON.parse(window.localStorage.getItem("singleplayer-tossup-query")),query.version!==defaults.version&&(query=defaults,window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query)))):query=defaults;const categoryManager=new CategoryManager(query.categories,query.subcategories,query.alternateSubcategories),settings=window.localStorage.getItem("singleplayer-tossup-settings")?JSON.parse(window.localStorage.getItem("singleplayer-tossup-settings")):{readingSpeed:50,rebuzz:!1,selectBySetName:!1,showHistory:!0,timer:!0,typeToAnswer:!0};// Load query and settings first so user doesn't see the default settings -settings.readingSpeed&&(document.getElementById("reading-speed-display").textContent=settings.readingSpeed,document.getElementById("reading-speed").value=settings.readingSpeed),settings.rebuzz&&(document.getElementById("toggle-rebuzz").checked=!0),settings.selectBySetName&&(document.getElementById("difficulty-settings").classList.add("d-none"),document.getElementById("set-settings").classList.remove("d-none"),document.getElementById("toggle-select-by-set-name").checked=!0,document.getElementById("toggle-powermark-only").disabled=!0,document.getElementById("toggle-standard-only").disabled=!0),settings.showHistory||(document.getElementById("toggle-show-history").checked=!1,document.getElementById("room-history").classList.add("d-none")),settings.timer||(document.getElementById("toggle-timer").checked=!1,document.getElementById("timer").classList.add("d-none")),settings.typeToAnswer||(document.getElementById("type-to-answer").checked=!1,document.getElementById("toggle-rebuzz").disabled=!0),query.packetNumbers&&(document.getElementById("packet-number").value=arrayToRange(query.packetNumbers)),query.powermarkOnly&&(document.getElementById("toggle-powermark-only").checked=!0),query.setName&&(document.getElementById("set-name").value=query.setName,api.getNumPackets(query.setName).then(a=>{maxPacketNumber=a,0===maxPacketNumber?document.getElementById("set-name").classList.add("is-invalid"):document.getElementById("packet-number").placeholder=`Packet Numbers (1-${maxPacketNumber})`})),updateStatDisplay();function queryLock(){document.getElementById("question").textContent="Fetching questions...",document.getElementById("start").disabled=!0,document.getElementById("next").disabled=!0,document.getElementById("pause").disabled=!0,document.getElementById("buzz").disabled=!0}function queryUnlock(){document.getElementById("question").textContent="",document.getElementById("start").disabled=!1,document.getElementById("next").disabled=!1,document.getElementById("pause").disabled=!1,document.getElementById("buzz").disabled=!1}/** - * @returns {Promise} Whether or not there is a next question - */async function advanceQuestion(){if(settings.selectBySetName){// Get the next question if the current one is in the wrong category and subcategory -do// Go to the next packet if you reach the end of this packet -if(questionNumber++,questionNumber>tossups.length){if(query.packetNumbers.shift(),0===query.packetNumbers.length)return window.alert("No more questions left"),document.getElementById("buzz").disabled=!0,document.getElementById("pause").disabled=!0,document.getElementById("next").disabled=!0,!1;// alert the user if there are no more packets -queryLock();try{tossups=await api.getPacketTossups(query.setName,query.packetNumbers[0])}finally{queryUnlock()}questionNumber=1}while(!categoryManager.isValidCategory(tossups[questionNumber-1]));0""!==a),document.getElementById("question-number-info").textContent=questionNumber)}else{queryLock();try{tossups=await getRandomTossup(query,categoryManager),tossups=[tossups]}finally{queryUnlock()}if(!tossups[0])return window.alert("No questions found"),!1;query.setName=tossups[0].set.name,query.packetNumbers=[tossups[0].packet.number],tossupText=tossups[0].question_sanitized,tossupTextSplit=tossupText.split(" ").filter(a=>""!==a),document.getElementById("question-number-info").textContent=tossups[0].number,questionNumber=1}return!0}/** - * Called when the users buzzes. - * The first "buzz" pauses the question, and the second "buzz" reveals the rest of the question - * and updates the score. - */function buzz(){// Stop the question reading -// Include buzzpoint -clearTimeout(timeoutID),currentlyBuzzing=!0,audio.soundEffects&&audio.buzz.play(),buzzpointIndex=document.getElementById("question").textContent.length,!tossupTextSplit.includes("(*)")&&tossupText.includes("(*)")&&(buzzpointIndex+=3),document.getElementById("question").textContent+="(#) ",document.getElementById("buzz").textContent="Reveal",document.getElementById("next").disabled=!0,document.getElementById("start").disabled=!0,document.getElementById("pause").disabled=!0,settings.timer&&(timer.stopTimer(),timer.startTimer(ANSWER_TIME_LIMIT,()=>document.getElementById("answer-submit").click()))}/** - * Clears user stats. - */function clearStats(){stats.powers=0,stats.tens=0,stats.negs=0,stats.dead=0,stats.points=0,stats.totalCorrectCelerity=0,updateStatDisplay(),window.sessionStorage.removeItem("tossup-stats")}async function giveAnswer(a){currentlyBuzzing=!1;const{directive:b,directedPrompt:c}=await api.checkAnswer(tossups[questionNumber-1].answer,a);switch(b){case"accept":{const a=updateScore(!0);audio.soundEffects&&(10b.charCodeAt(b.length-2)||".\u201D"===b.slice(-2)||"!\u201D"===b.slice(-2)||"?\u201D"===b.slice(-2)?c+=2:b.endsWith(",")||",\u201D"===b.slice(-2)?c+=.75:"(*)"===b&&(c=0),c=.9*c*(125-settings.readingSpeed);const d=c-Date.now()+a;timeoutID=window.setTimeout(()=>{readQuestion(c+a)},d)}else document.getElementById("pause").disabled=!0,settings.timer&&timer.startTimer(DEAD_TIME_LIMIT,revealQuestion)}function revealQuestion(){document.getElementById("question").innerHTML=insertTokensIntoHTML(tossups[questionNumber-1].question,tossups[questionNumber-1].question_sanitized,[[buzzpointIndex]],[" (#) "]),document.getElementById("answer").innerHTML="ANSWER: "+tossups[questionNumber-1].answer,document.getElementById("buzz").disabled=!0,document.getElementById("buzz").textContent="Buzz",document.getElementById("next").disabled=!1,document.getElementById("next").textContent="Next",document.getElementById("start").disabled=!1,document.getElementById("toggle-correct").classList.remove("d-none"),document.getElementById("toggle-correct").textContent=previous.isCorrect?"I was wrong":"I was right"}function toggleCorrect(){const a=previous.isCorrect?-1:1;previous.inPower?(stats.powers+=1*a,stats.points+=a*previous.powerValue):(stats.tens+=1*a,stats.points+=10*a),previous.endOfQuestion?stats.dead+=-1*a:(stats.negs+=-1*a,stats.points+=a*-previous.negValue),stats.totalCorrectCelerity+=a*previous.celerity,previous.isCorrect=!previous.isCorrect,document.getElementById("toggle-correct").textContent=previous.isCorrect?"I was wrong":"I was right",updateStatDisplay(),window.sessionStorage.setItem("tossup-stats",JSON.stringify(stats))}function updateScore(a){const b=0===tossupTextSplit.length,c=tossupTextSplit.includes("(*)")&&tossupText.includes("(*)"),d=isPace(query.setName)?20:15,e=isPace(query.setName)?0:-5,f=a?c?d:10:b?0:e,g=tossupTextSplit.join(" ").length,h=g/tossupText.length;let i;return a?(i=c?"powers":"tens",stats.totalCorrectCelerity+=h):i=b?"dead":"negs",stats[i]+=1,stats.points+=f,previous.celerity=h,previous.endOfQuestion=b,previous.inPower=c,previous.negValue=e,previous.powerValue=d,previous.isCorrect=a,updateStatDisplay(),window.sessionStorage.setItem("tossup-stats",JSON.stringify(stats)),f}/** - * Updates the displayed stat line. - */function updateStatDisplay(){const{powers:a,tens:b,negs:c,dead:d,points:e,totalCorrectCelerity:f}=stats,g=a+b+c+d,h=a+b;let i=0===h?0:parseFloat(f)/h;i=Math.round(1e3*i)/1e3;const j=1===g?"":"s";// disable clear stats button if no stats -document.getElementById("statline").innerHTML=`${a}/${b}/${c} with ${g} tossup${j} seen (${e} pts, celerity: ${i})`,document.getElementById("clear-stats").disabled=0===g}document.getElementById("answer-form").addEventListener("submit",function(a){a.preventDefault(),a.stopPropagation(),settings.timer&&(timer.stopTimer(),timer.tenthsRemaining=0,timer.updateDisplay());const b=document.getElementById("answer-input").value;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"),giveAnswer(b)}),document.getElementById("buzz").addEventListener("click",function(){// reveal answer on second click -// when NOT using type to answer -return this.blur(),currentlyBuzzing?(currentlyBuzzing=!1,updateScore(!0),void revealQuestion()):void(buzz(),settings.typeToAnswer&&(document.getElementById("answer-input-group").classList.remove("d-none"),document.getElementById("answer-input").focus(),this.disabled=!0))}),document.getElementById("clear-stats").addEventListener("click",function(){this.blur(),clearStats()}),document.getElementById("next").addEventListener("click",function(){this.blur(),createTossupCard(tossups[questionNumber-1]),next()}),document.getElementById("packet-number").addEventListener("change",function(){// if field is blank, store blank result in `query` -query.packetNumbers=rangeToArray(this.value.trim(),0),window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query)),query.packetNumbers=rangeToArray(this.value.trim(),maxPacketNumber)}),document.getElementById("pause").addEventListener("click",function(){this.blur(),pause()}),document.getElementById("reading-speed").addEventListener("input",function(){settings.readingSpeed=this.value,document.getElementById("reading-speed-display").textContent=this.value,window.localStorage.setItem("singleplayer-tossup-settings",JSON.stringify(settings))}),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(){query.setName=this.value.trim(),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").placeholder=""===this.value||0===maxPacketNumber?"Packet Numbers":`Packet Numbers (1-${maxPacketNumber})`,window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query))}),document.getElementById("start").addEventListener("click",async function(){if(this.blur(),0===query.setName.length&&settings.selectBySetName)return window.alert("Please enter a set name."),!1;if(0===query.packetNumbers.length&&settings.selectBySetName&&(query.packetNumbers=rangeToArray(document.getElementById("packet-number").value.trim(),maxPacketNumber)),document.getElementById("next").disabled=!1,document.getElementById("next").textContent="Skip",document.getElementById("settings").classList.add("d-none"),settings.selectBySetName){queryLock(),questionNumber=0;try{tossups=await api.getPacketTossups(query.setName,query.packetNumbers[0])}finally{queryUnlock()}}next()}),document.getElementById("toggle-correct").addEventListener("click",function(){this.blur(),toggleCorrect()}),document.getElementById("toggle-powermark-only").addEventListener("click",function(){this.blur(),query.powermarkOnly=this.checked,loadRandomTossups(query),window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query))}),document.getElementById("toggle-select-by-set-name").addEventListener("click",function(){this.blur(),settings.selectBySetName=this.checked,document.getElementById("toggle-powermark-only").disabled=this.checked,document.getElementById("toggle-standard-only").disabled=this.checked,this.checked?(document.getElementById("difficulty-settings").classList.add("d-none"),document.getElementById("set-settings").classList.remove("d-none")):(document.getElementById("difficulty-settings").classList.remove("d-none"),document.getElementById("set-settings").classList.add("d-none")),window.localStorage.setItem("singleplayer-tossup-settings",JSON.stringify(settings))}),document.getElementById("toggle-show-history").addEventListener("click",function(){this.blur(),settings.showHistory=this.checked,this.checked?document.getElementById("room-history").classList.remove("d-none"):document.getElementById("room-history").classList.add("d-none"),window.localStorage.setItem("singleplayer-tossup-settings",JSON.stringify(settings))}),document.getElementById("toggle-standard-only").addEventListener("click",function(){this.blur(),query.standardOnly=this.checked,loadRandomTossups(query),window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query))}),document.getElementById("toggle-timer").addEventListener("click",function(){this.blur(),settings.timer=this.checked,document.getElementById("timer").classList.toggle("d-none"),window.localStorage.setItem("singleplayer-tossup-settings",JSON.stringify(settings))}),document.getElementById("type-to-answer").addEventListener("click",function(){this.blur(),settings.typeToAnswer=this.checked,document.getElementById("toggle-rebuzz").disabled=!this.checked,window.localStorage.setItem("singleplayer-tossup-settings",JSON.stringify(settings))}),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-rebuzz").addEventListener("click",function(){this.blur(),settings.rebuzz=this.checked,window.localStorage.setItem("singleplayer-tossup-settings",JSON.stringify(settings))}),document.getElementById("year-range-a").onchange=function(){query.minYear=$("#slider").slider("values",0),query.maxYear=$("#slider").slider("values",1),loadRandomTossups(query),window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query))},document.getElementById("year-range-b").onchange=function(){query.minYear=$("#slider").slider("values",0),query.maxYear=$("#slider").slider("values",1),loadRandomTossups(query),window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query))},document.addEventListener("keydown",a=>{if(!["INPUT","TEXTAREA","SELECT"].includes(document.activeElement.tagName))switch(a.key){case" ":document.getElementById("buzz").click(),a.target===document.body&&a.preventDefault();break;case"e":document.getElementById("toggle-settings").click();break;case"k":document.getElementsByClassName("card-header-clickable")[0].click();break;case"t":document.getElementsByClassName("star-tossup")[0].click();break;case"y":navigator.clipboard.writeText(tossups[0]?._id??"");break;case"n":document.getElementById("next").click();break;case"p":document.getElementById("pause").click();break;case"s":document.getElementById("start").click()}}),$(document).ready(function(){$("#slider").slider("values",0,query.minYear),$("#slider").slider("values",1,query.maxYear)}),document.getElementById("year-range-a").textContent=query.minYear,document.getElementById("year-range-b").textContent=query.maxYear,ReactDOM.createRoot(document.getElementById("category-modal-root")).render(/*#__PURE__*/React.createElement(CategoryModal,{categoryManager:categoryManager,onClose:()=>{({categories:query.categories,subcategories:query.subcategories,alternateSubcategories:query.alternateSubcategories}=categoryManager.export()),loadRandomTossups(query),window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query))}})),ReactDOM.createRoot(document.getElementById("difficulty-dropdown-root")).render(/*#__PURE__*/React.createElement(DifficultyDropdown,{startingDifficulties:query.difficulties,onChange:()=>{query.difficulties=getDropdownValues("difficulties"),loadRandomTossups(query),window.localStorage.setItem("singleplayer-tossup-query",JSON.stringify(query))}})); \ No newline at end of file diff --git a/quizbowl/TossupRoom.js b/quizbowl/TossupRoom.js index 321ce350..5e25aaca 100644 --- a/quizbowl/TossupRoom.js +++ b/quizbowl/TossupRoom.js @@ -1,5 +1,6 @@ import { DEFAULT_MIN_YEAR, DEFAULT_MAX_YEAR, CATEGORIES, SUBCATEGORIES_FLATTENED, ALTERNATE_SUBCATEGORIES_FLATTENED, SUBCATEGORY_TO_CATEGORY, ALTERNATE_SUBCATEGORY_TO_CATEGORY } from './constants.js'; -import { insertTokensIntoHTML } from './insert-tokens-into-html.js'; +import CategoryManager from './category-manager.js'; +import insertTokensIntoHTML from './insert-tokens-into-html.js'; import Room from './Room.js'; /** @@ -37,9 +38,9 @@ export default class TossupRoom extends Room { this.buzzes = []; this.buzzpointIndices = []; this.liveAnswer = ''; + this.packetLength = undefined; this.paused = false; this.queryingQuestion = false; - this.questionNumber = 0; this.questionProgress = this.QuestionProgressEnum.NOT_STARTED; this.questionSplit = []; this.tossup = {}; @@ -103,7 +104,7 @@ export default class TossupRoom extends Room { } } - adjustQuery (settings, values) { + async adjustQuery (settings, values) { if (settings.length !== values.length) { return; } for (let i = 0; i < settings.length; i++) { @@ -115,14 +116,10 @@ export default class TossupRoom extends Room { } if (this.query.selectBySetName) { - this.questionNumber = 0; - this.getSet(this.query).then(set => { - this.setCache = set; - }); + this.setCache = await this.getSet({ setName: this.query.setName, packetNumbers: [this.query.packetNumbers[0]] }); + this.packetLength = this.setCache.length; } else { - this.getRandomTossups(this.query).then(tossups => { - this.randomQuestionCache = tossups; - }); + this.randomQuestionCache = await this.getRandomTossups({ ...this.query, number: 1 }); } } @@ -130,24 +127,30 @@ export default class TossupRoom extends Room { this.queryingQuestion = true; if (this.query.selectBySetName) { - if (this.setCache.length === 0) { - this.emitMessage({ type: 'end-of-set' }); - return false; - } else { - this.tossup = this.setCache.pop(); - this.questionNumber = this.tossup.number; + 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(); + if (packetNumber === undefined) { + this.emitMessage({ type: 'end-of-set' }); + return false; + } + this.setCache = await this.getSet({ setName: this.query.setName, packetNumbers: [packetNumber] }); + this.packetLength = this.setCache.length; + } + + this.tossup = this.setCache.shift(); this.query.packetNumbers = this.query.packetNumbers.filter(packetNumber => packetNumber >= this.tossup.packet.number); - } + } while (!categoryManager.isValidCategory(this.tossup)); } else { if (this.randomQuestionCache.length === 0) { - this.randomQuestionCache = await this.getRandomTossups(this.query); - 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; } } - this.tossup = this.randomQuestionCache.pop(); } @@ -279,7 +282,7 @@ export default class TossupRoom extends Room { if (!hasNextQuestion) { return; } const username = this.players[userId].username; - this.emitMessage({ type, userId, username, oldTossup, tossup: this.tossup }); + this.emitMessage({ type, packetLength: this.packetLength, userId, username, oldTossup, tossup: this.tossup }); this.wordIndex = 0; this.questionProgress = this.QuestionProgressEnum.READING; @@ -320,8 +323,8 @@ export default class TossupRoom extends Room { if (packetNumbers.some((value) => typeof value !== 'number' || value < 1 || value > allowedPacketNumbers)) { return false; } const username = this.players[userId].username; - this.emitMessage({ type: 'set-packet-numbers', username, packetNumbers }); this.adjustQuery(['packetNumbers'], [packetNumbers]); + this.emitMessage({ type: 'set-packet-numbers', username, packetNumbers }); } setReadingSpeed (userId, { readingSpeed }) { @@ -336,11 +339,6 @@ export default class TossupRoom extends Room { async setSetName (userId, { packetNumbers, setName }) { if (typeof setName !== 'string') { return; } - if (!this.setList) { return; } - if (!this.setList.includes(setName)) { return; } - const maxPacketNumber = await this.getNumPackets(setName); - if (packetNumbers.some((num) => num > maxPacketNumber || num < 1)) { return; } - const username = this.players[userId].username; this.emitMessage({ type: 'set-set-name', username, setName }); this.adjustQuery(['setName', 'packetNumbers'], [setName, packetNumbers]); @@ -406,8 +404,8 @@ export default class TossupRoom extends Room { togglePowermarkOnly (userId, { powermarkOnly }) { this.query.powermarkOnly = powermarkOnly; const username = this.players[userId].username; - this.emitMessage({ type: 'toggle-powermark-only', powermarkOnly, username }); this.adjustQuery(['powermarkOnly'], [powermarkOnly]); + this.emitMessage({ type: 'toggle-powermark-only', powermarkOnly, username }); } toggleRebuzz (userId, { rebuzz }) { @@ -417,13 +415,9 @@ export default class TossupRoom extends Room { } toggleSelectBySetName (userId, { selectBySetName, setName }) { - if (!this.setList) { return; } - if (!this.setList.includes(setName)) { return; } - this.query.selectBySetName = selectBySetName; const username = this.players[userId].username; this.emitMessage({ type: 'toggle-select-by-set-name', selectBySetName, setName, username }); - this.adjustQuery(['setName'], [setName]); } toggleSkip (userId, { skip }) { @@ -435,8 +429,8 @@ export default class TossupRoom extends Room { toggleStandardOnly (userId, { standardOnly }) { this.query.standardOnly = standardOnly; const username = this.players[userId].username; - this.emitMessage({ type: 'toggle-standard-only', standardOnly, username }); this.adjustQuery(['standardOnly'], [standardOnly]); + this.emitMessage({ type: 'toggle-standard-only', standardOnly, username }); } toggleTimer (userId, { timer }) { @@ -458,8 +452,8 @@ export default class TossupRoom extends Room { if (alternateSubcategories.some(sub => !categories.includes(ALTERNATE_SUBCATEGORY_TO_CATEGORY[sub]))) { return; } const username = this.players[userId].username; - this.emitMessage({ type: 'set-categories', categories, subcategories, alternateSubcategories, username }); this.adjustQuery(['categories', 'subcategories', 'alternateSubcategories'], [categories, subcategories, alternateSubcategories]); + this.emitMessage({ type: 'set-categories', categories, subcategories, alternateSubcategories, username }); } setYearRange (userId, { minYear, maxYear }) { diff --git a/client/scripts/utilities/category-manager.js b/quizbowl/category-manager.js similarity index 100% rename from client/scripts/utilities/category-manager.js rename to quizbowl/category-manager.js diff --git a/quizbowl/insert-tokens-into-html.js b/quizbowl/insert-tokens-into-html.js index aff4f32d..a657d4c2 100644 --- a/quizbowl/insert-tokens-into-html.js +++ b/quizbowl/insert-tokens-into-html.js @@ -7,7 +7,7 @@ * @param {string[]} arrayOfTokens - an array of tokens to insert into the HTML string. Default is `['', '']` * @returns {string} the dirty string with tokens inserted at the specified positions in the clean string */ -function insertTokensIntoHTML (dirty, clean, arrayOfIndices, arrayOfTokens = ['', '']) { +export default function insertTokensIntoHTML (dirty, clean, arrayOfIndices, arrayOfTokens = ['', '']) { dirty = dirty.replace(/…/g, '...'); const result = []; @@ -76,5 +76,3 @@ function insertTokensIntoHTML (dirty, clean, arrayOfIndices, arrayOfTokens = ['< return result.join('').replace(/〈/g, '<').replace(/〉/g, '>').replace(/\u0267/g, '&'); } - -export { insertTokensIntoHTML }; diff --git a/routes/index.js b/routes/index.js index 46dce545..0eb815f2 100644 --- a/routes/index.js +++ b/routes/index.js @@ -33,8 +33,9 @@ router.use('/multiplayer', multiplayerRouter); router.use('/user', userRouter); router.use('/webhook', webhookRouter); +router.use('/quizbowl', express.static('quizbowl')); + router.use(express.static('client', { extensions: ['html'] })); -router.use(express.static('quizbowl')); router.use(express.static('node_modules')); /** diff --git a/server/multiplayer/ServerTossupRoom.js b/server/multiplayer/ServerTossupRoom.js index 091966fc..482a74ba 100644 --- a/server/multiplayer/ServerTossupRoom.js +++ b/server/multiplayer/ServerTossupRoom.js @@ -1,7 +1,7 @@ import ServerPlayer from './ServerPlayer.js'; import { HEADER, ENDC, OKBLUE, OKGREEN } from '../bcolors.js'; import isAppropriateString from '../moderation/is-appropriate-string.js'; -import { insertTokensIntoHTML } from '../../quizbowl/insert-tokens-into-html.js'; +import insertTokensIntoHTML from '../../quizbowl/insert-tokens-into-html.js'; import TossupRoom from '../../quizbowl/TossupRoom.js'; import RateLimit from '../RateLimit.js'; @@ -147,6 +147,14 @@ export default class ServerTossupRoom extends TossupRoom { super.setCategories(userId, { categories, subcategories, alternateSubcategories }); } + async setSetName (userId, { packetNumbers, setName }) { + if (!this.setList) { return; } + if (!this.setList.includes(setName)) { return; } + const maxPacketNumber = await this.getNumPackets(setName); + if (packetNumbers.some((num) => num > maxPacketNumber || num < 1)) { return; } + super.setSetName(userId, { packetNumbers, setName }); + } + setUsername (userId, { username }) { if (typeof username !== 'string') { return false; } @@ -192,7 +200,10 @@ export default class ServerTossupRoom extends TossupRoom { toggleSelectBySetName (userId, { selectBySetName, setName }) { if (this.isPermanent) { return; } + if (!this.setList) { return; } + if (!this.setList.includes(setName)) { return; } super.toggleSelectBySetName(userId, { selectBySetName, setName }); + this.adjustQuery(['setName'], [setName]); } toggleTimer (userId, { timer }) {