first commit
This commit is contained in:
commit
36040d9744
29
cookie.js
Normal file
29
cookie.js
Normal file
@ -0,0 +1,29 @@
|
||||
function createCookie(name,value,days) {
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 *1000));
|
||||
var expires = "; expires=" + date.toGMTString();
|
||||
} else {
|
||||
var expires = "";
|
||||
}
|
||||
document.cookie = name + "=" + value + expires + "; path=/";
|
||||
}
|
||||
|
||||
function readCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==' ') {
|
||||
c = c.substring(1,c.length);
|
||||
}
|
||||
if (c.indexOf(nameEQ) == 0) {
|
||||
return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function eraseCookie(name) {
|
||||
createCookie(name,"",-1);
|
||||
}
|
53
example.txt
Normal file
53
example.txt
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Jeopardy File Format
|
||||
* Questions and answers go below categories as seen below
|
||||
* # is the character to start a category
|
||||
* ? is the character to start a question
|
||||
* & is the character to provide an answer
|
||||
* Lines starting with any other character are ignored
|
||||
*
|
||||
* If 5 questions aren't provided for a category
|
||||
* The rest of the 5 buttons will be autofilled as blank/used questions
|
||||
*
|
||||
* If more than 5 questions/answers are provided, the site uses the first five
|
||||
*
|
||||
* Keybinds are as follows
|
||||
* c : Reset the page / delete any stored games
|
||||
* esc/q : Return back to the main board
|
||||
* space : Reveal the answer for the selected question
|
||||
* p : Play / Stop the jeopardy theme song
|
||||
* - : Add another team score box
|
||||
* + : Remove the last team score box
|
||||
* h : Reveal this help file
|
||||
*
|
||||
* Note: if you refresh the page, it will reset the board (What has been answered)
|
||||
* Team scores will not be saved on page refresh!
|
||||
*/
|
||||
|
||||
#This is Example Category 1
|
||||
?Question
|
||||
&Answer
|
||||
?Question
|
||||
&Answer
|
||||
?Question
|
||||
&Answer
|
||||
?Question
|
||||
&Answer
|
||||
?Question
|
||||
&Answer
|
||||
|
||||
#This is Example Category 2
|
||||
?Question that is worth 100
|
||||
&Answer that is worth 100
|
||||
|
||||
?Question that is worth 200
|
||||
&Answer that is worth 200
|
||||
|
||||
?Question that is worth 300
|
||||
&Answer that is worth 300
|
||||
|
||||
?Question that is worth 400
|
||||
&Answer that is worth 400
|
||||
|
||||
?Question that is worth 500
|
||||
&Answer that is worth 500
|
169
game.js
Normal file
169
game.js
Normal file
@ -0,0 +1,169 @@
|
||||
function packButtonEvents(){
|
||||
document.querySelectorAll("td").forEach(td => {
|
||||
td.addEventListener('mouseup', function () {
|
||||
this.classList.add("selected");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function displayGame(game){
|
||||
// Ensure file upload is hidden
|
||||
document.getElementById("file").style.display = "none";
|
||||
document.getElementById("game").style.display = "table";
|
||||
|
||||
// This will build the board
|
||||
game = JSON.parse(game);
|
||||
let table = document.querySelector('#game');
|
||||
let tableHeaders = document.querySelector('#game tr');
|
||||
let tableRows = document.querySelectorAll('#game tr:not(:first-child)');
|
||||
|
||||
game.forEach(category => {
|
||||
//console.log(category.title);
|
||||
//console.log(category.questions);
|
||||
|
||||
// Add category as a header
|
||||
let title = document.createTextNode(category.title);
|
||||
let th = document.createElement('th');
|
||||
th.appendChild(title);
|
||||
tableHeaders.appendChild(th);
|
||||
|
||||
//Now Pack Each Question
|
||||
for(let i = 0;i < category.questions.length || i < 5;i++){
|
||||
let td = document.createElement('td');
|
||||
|
||||
let valueText = document.createTextNode((i+1)*100);
|
||||
let valueNode = document.createElement('div');
|
||||
valueNode.classList.add('value');
|
||||
valueNode.appendChild(valueText);
|
||||
|
||||
//Ensure we actually have a question / placeholder if not
|
||||
let quesText = category.questions[i];
|
||||
if(quesText === undefined || quesText.question === undefined) {
|
||||
quesText = "";
|
||||
td.classList.add("revealed");
|
||||
} else {
|
||||
quesText = category.questions[i].question;
|
||||
}
|
||||
let quesTextNode = document.createTextNode(quesText);
|
||||
let quesNode = document.createElement('div');
|
||||
quesNode.classList.add('question');
|
||||
quesNode.appendChild(quesTextNode);
|
||||
|
||||
//Ensure we actually have an answer / placeholder if not
|
||||
let ansText = category.questions[i];
|
||||
if(ansText === undefined || ansText.answer === undefined) {
|
||||
ansText = "";
|
||||
td.classList.add("revealed");
|
||||
} else {
|
||||
ansText = category.questions[i].answer;
|
||||
}
|
||||
let ansTextNode = document.createTextNode(ansText);
|
||||
let ansNode = document.createElement('div');
|
||||
ansNode.classList.add('answer');
|
||||
ansNode.appendChild(ansTextNode);
|
||||
|
||||
td.appendChild(valueNode);
|
||||
td.appendChild(quesNode);
|
||||
td.appendChild(ansNode);
|
||||
|
||||
tableRows[i].appendChild(td);
|
||||
}
|
||||
});
|
||||
packButtonEvents();
|
||||
}
|
||||
|
||||
function fileParse(){
|
||||
//This runs to build the data to be saved as a cookie
|
||||
|
||||
var tis = document.querySelector("#file input[type=file]");
|
||||
console.log("Recieved file to parse!");
|
||||
|
||||
var file = tis.files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(progressEvent){
|
||||
let tempLines = this.result.split(/\r\n|\n/);
|
||||
var lines = (function(){
|
||||
let finalLines = [];
|
||||
|
||||
// Remove Blank Pages
|
||||
for(var line = 0; line < tempLines.length; line++){
|
||||
if(tempLines[line] != "") {
|
||||
//normal line to keep
|
||||
finalLines.push(tempLines[line]);
|
||||
}
|
||||
}
|
||||
|
||||
return finalLines;
|
||||
})();
|
||||
|
||||
let game = [];
|
||||
let qOverflow = false;
|
||||
for(var line = 0; line < lines.length; line++){
|
||||
// Make the sub-div for the line of the current slide
|
||||
switch(lines[line][0]){
|
||||
case '#':
|
||||
// Category Title
|
||||
|
||||
//Reset question overflow detection
|
||||
qOverflow = false;
|
||||
|
||||
let title = lines[line].substring(1);
|
||||
game.push({title: title, questions: []});
|
||||
break;
|
||||
case '?':
|
||||
// Question
|
||||
let que = lines[line].substring(1);
|
||||
let qlen = game[game.length-1].questions.length;
|
||||
|
||||
//Check if last question has been set already
|
||||
if(game[game.length-1].questions[qlen-1] != undefined && game[game.length-1].questions[qlen-1].answer == undefined){
|
||||
game[game.length-1].questions[qlen-1].question += " " + que;
|
||||
} else if(game[game.length-1].questions.length >= 5){
|
||||
console.log("Error: too many questions provided for category");
|
||||
qOverflow = true;
|
||||
} else {
|
||||
game[game.length-1].questions.push({question: que});
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
// Answer
|
||||
let ans = lines[line].substring(1);
|
||||
let qlen2 = game[game.length-1].questions.length;
|
||||
|
||||
//Check if no questions have been made, last answer has been set already
|
||||
if(game[game.length-1].questions[qlen2-1] === undefined){
|
||||
console.log("Error: Answer provided but no question");
|
||||
} else if(qOverflow == true){
|
||||
console.log("Error: Answer Overflow")
|
||||
} else if(game[game.length-1].questions[qlen2-1].answer != undefined){
|
||||
game[game.length-1].questions[qlen2-1].answer += " " + ans;
|
||||
} else {
|
||||
game[game.length-1].questions[qlen2-1].answer = ans;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Save Cookie here(game)
|
||||
let strGame = JSON.stringify(game);
|
||||
// document.cookie = "game="+strGame;
|
||||
// Save the game for 2 days
|
||||
createCookie("game",strGame,2);
|
||||
displayGame(strGame);
|
||||
}
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
function rememberGame() {
|
||||
//let game = (document.cookie.match(/^(?:.*;)?\s*game\s*=\s*([^;]+)(?:.*)?$/)||[,null])[1]
|
||||
let game = readCookie("game")
|
||||
if(game){
|
||||
console.log("Resuming Old Game!");
|
||||
displayGame(game);
|
||||
} else {
|
||||
console.log("Waiting for Game Data!");
|
||||
var tis = document.querySelector("#file input[type=file]");
|
||||
document.getElementById("file").style.display = "flex";
|
||||
tis.addEventListener('change', fileParse);
|
||||
}
|
||||
}
|
||||
window.onload = rememberGame();
|
31
index.html
Normal file
31
index.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="icon" href="./media/favicon.png" media="(prefers-color-scheme: no-preference)" type="image/png">
|
||||
<link rel="icon" href="./media/favicon-dark.png" media="(prefers-color-scheme: dark)" type="image/png">
|
||||
<link rel="icon" href="./media/favicon.png" media="(prefers-color-scheme: light)" type="image/png">
|
||||
<script src="keybinds.js"></script>
|
||||
<script src="cookie.js"></script>
|
||||
</head>
|
||||
<audio id="audio">
|
||||
<source src="media/Jeopardy-theme-song.mp3" type="audio/mpeg">
|
||||
</audio>
|
||||
<body>
|
||||
<div id="file">
|
||||
<input type="file">
|
||||
<h1>Upload Jeopardy Game File<br>For Formatting Help, press 'H'</h1>
|
||||
</div>
|
||||
<table id="game">
|
||||
<tr id="categories"></tr>
|
||||
<tr></tr>
|
||||
<tr></tr>
|
||||
<tr></tr>
|
||||
<tr></tr>
|
||||
<tr></tr>
|
||||
</table>
|
||||
<div id="scores">
|
||||
</div>
|
||||
</body>
|
||||
<script src="game.js"></script>
|
||||
</html>
|
134
keybinds.js
Normal file
134
keybinds.js
Normal file
@ -0,0 +1,134 @@
|
||||
var playstate = 0;
|
||||
|
||||
function decTeam(){
|
||||
let input = this.parentNode.querySelector("input[type=text]");
|
||||
// Check if there is an active page
|
||||
let selected = document.querySelector(".selected");
|
||||
if(selected != undefined && selected.querySelector(".value") != undefined){
|
||||
|
||||
// Use the correct innerText method for whatever browser
|
||||
let textMethod = ('innerText' in selected.querySelector(".value"))? 'innerText' : 'textContent';
|
||||
let selectedValue = selected.querySelector(".value")[textMethod];
|
||||
input.value = parseInt(input.value) - parseInt(selectedValue);
|
||||
|
||||
} else {
|
||||
input.value = parseInt(input.value) - 100;
|
||||
}
|
||||
}
|
||||
function incTeam(){
|
||||
let input = this.parentNode.querySelector("input[type=text]");
|
||||
|
||||
// Check if there is an active page
|
||||
let selected = document.querySelector(".selected");
|
||||
if(selected != undefined && selected.querySelector(".value") != undefined){
|
||||
|
||||
// Use the correct innerText method for whatever browser
|
||||
let textMethod = ('innerText' in selected.querySelector(".value"))? 'innerText' : 'textContent';
|
||||
let selectedValue = selected.querySelector(".value")[textMethod];
|
||||
input.value = parseInt(input.value) + parseInt(selectedValue);
|
||||
|
||||
} else {
|
||||
input.value = parseInt(input.value) + 100;
|
||||
}
|
||||
}
|
||||
|
||||
document.onkeydown = function(e) {
|
||||
switch (e.keyCode) {
|
||||
case 27:
|
||||
case 81:
|
||||
// ESC/Q Key pressed
|
||||
// Set active question to inactive (Return to board)
|
||||
//console.log("Returning to board view");
|
||||
document.querySelector(".selected").classList.remove("selected");
|
||||
break;
|
||||
case 32:
|
||||
// Space Key pressed
|
||||
// Reveal answer
|
||||
// Mark active question as used
|
||||
//console.log("Toggling the answer");
|
||||
|
||||
// Prevent button incrementing/decrementing team score
|
||||
e.preventDefault();
|
||||
document.querySelector(".selected").classList.toggle("revealed");
|
||||
break;
|
||||
case 67:
|
||||
// C Key pressed
|
||||
// Reset/clear the game board
|
||||
createCookie("game","",-1);
|
||||
window.location.reload();
|
||||
break;
|
||||
case 72:
|
||||
// H Key pressed
|
||||
// Show the example file
|
||||
let url = 'https://pingforagoodtime.com/jeopardy/example.txt';
|
||||
window.open(url, '_blank');
|
||||
break;
|
||||
case 80:
|
||||
// P Key pressed
|
||||
// Toggle playing audio
|
||||
var audio = document.getElementById('audio');
|
||||
|
||||
if(playstate == 0){
|
||||
playstate = 1;
|
||||
audio.play();
|
||||
}else if(playstate == 1 && audio.duration == audio.currentTime){
|
||||
audio.pause();
|
||||
audio.currentTime = 0;
|
||||
audio.play();
|
||||
}else{
|
||||
playstate = 0;
|
||||
audio.pause();
|
||||
audio.currentTime = 0;
|
||||
}
|
||||
break;
|
||||
case 61: //Firefox
|
||||
case 187:
|
||||
// + Key pressed
|
||||
// Add a team
|
||||
let scores = document.querySelector('#scores');
|
||||
let teamCount = document.querySelectorAll('#scores div').length+1;
|
||||
|
||||
// Limit the teams to 12
|
||||
if(teamCount > 12){
|
||||
break;
|
||||
}
|
||||
|
||||
let teamNode = document.createElement('div');
|
||||
let nameNode = document.createElement('h3');
|
||||
let teamName = document.createTextNode("Team " + teamCount);
|
||||
|
||||
let minusNode = document.createElement('input');
|
||||
minusNode.type = "button";
|
||||
minusNode.value = "-";
|
||||
minusNode.addEventListener('click', decTeam);
|
||||
|
||||
let textNode = document.createElement('input');
|
||||
textNode.type = "text";
|
||||
//textNode.disabled = "true";
|
||||
textNode.value = "0";
|
||||
|
||||
let plusNode = document.createElement('input');
|
||||
plusNode.type = "button";
|
||||
plusNode.value = "+";
|
||||
plusNode.addEventListener('click', incTeam);
|
||||
|
||||
nameNode.appendChild(teamName);
|
||||
teamNode.appendChild(nameNode);
|
||||
|
||||
teamNode.appendChild(minusNode);
|
||||
teamNode.appendChild(textNode);
|
||||
teamNode.appendChild(plusNode);
|
||||
|
||||
scores.appendChild(teamNode);
|
||||
break;
|
||||
case 173: //Firefox
|
||||
case 189:
|
||||
// - Key pressed
|
||||
// Remove last team
|
||||
let lastTeam = document.querySelector('#scores div:last-child');
|
||||
if(lastTeam != undefined){
|
||||
lastTeam.parentNode.removeChild(lastTeam);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
BIN
media/Jeopardy-theme-song.mp3
Normal file
BIN
media/Jeopardy-theme-song.mp3
Normal file
Binary file not shown.
BIN
media/favicon-dark.png
Normal file
BIN
media/favicon-dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
media/favicon.png
Normal file
BIN
media/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
164
style.css
Normal file
164
style.css
Normal file
@ -0,0 +1,164 @@
|
||||
:root {
|
||||
--fg-default:#C5C6C7;
|
||||
--bg-default:#0B0C10;
|
||||
|
||||
--header-font: ;
|
||||
--fg-header:#ffffff;
|
||||
--bg-header:linear-gradient(to top, #1d2675 0%,#2a3698 100%);
|
||||
|
||||
--cell-font: "impact, sans-serif";
|
||||
--fg-cell:#d49f4b;
|
||||
--bg-cell:linear-gradient(to top, #1d2675 0%,#2a3698 100%);
|
||||
}
|
||||
|
||||
* {
|
||||
padding:0;
|
||||
margin:0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
html {
|
||||
color-scheme: light dark;
|
||||
background: var(--bg-default);
|
||||
height:95vh;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
|
||||
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
line-height: 1.22;
|
||||
height:100vh;
|
||||
white-space: nowrap;
|
||||
background: var(--bg-default);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color:var(--fg-default);
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#file {
|
||||
width:100%;
|
||||
height:100%;
|
||||
display:none;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
background:
|
||||
linear-gradient(to right, var(--fg-default) 8px, transparent 8px) 0 0,
|
||||
linear-gradient(to right, var(--fg-default) 8px, transparent 8px) 0 100%,
|
||||
linear-gradient(to left, var(--fg-default) 8px, transparent 8px) 100% 0,
|
||||
linear-gradient(to left, var(--fg-default) 8px, transparent 8px) 100% 100%,
|
||||
linear-gradient(to bottom, var(--fg-default) 8px, transparent 8px) 0 0,
|
||||
linear-gradient(to bottom, var(--fg-default) 8px, transparent 8px) 100% 0,
|
||||
linear-gradient(to top, var(--fg-default) 8px, transparent 8px) 0 100%,
|
||||
linear-gradient(to top, var(--fg-default) 8px, transparent 8px) 100% 100%;
|
||||
|
||||
background-repeat: no-repeat;
|
||||
background-size: 20px 20px;
|
||||
}
|
||||
#file input[type=file]{
|
||||
height:100%;
|
||||
width:100%;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
opacity:0;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#game {
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align:center;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
#game th {
|
||||
font-family: var(--header-font);
|
||||
font-size: 2vw;
|
||||
color: var(--fg-header);
|
||||
background: var(--bg-header);
|
||||
white-space: pre-line;
|
||||
height:0;
|
||||
}
|
||||
|
||||
#game td {
|
||||
font-family: var(--cell-font);
|
||||
font-size: 3.5vw;
|
||||
color: var(--fg-cell);
|
||||
background: var(--bg-cell);
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.value {
|
||||
text-shadow: 5px 5px black;
|
||||
font-weight:bold;
|
||||
}
|
||||
td:not(.selected):hover {
|
||||
cursor:pointer;
|
||||
}
|
||||
.question,
|
||||
.answer {
|
||||
display: none;
|
||||
color: var(--fg-header);
|
||||
}
|
||||
|
||||
td.selected {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 99.9vw;
|
||||
height: 100%;
|
||||
z-index:100;
|
||||
}
|
||||
|
||||
td.selected .value {
|
||||
width: 100%;
|
||||
}
|
||||
td.selected .question {
|
||||
margin: 10% 0 0 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
td.revealed:not(.selected) .value{
|
||||
font-style:italic;
|
||||
opacity: 5%;
|
||||
}
|
||||
td.selected.revealed .answer {
|
||||
display: block;
|
||||
margin: 5% 0 0 0;
|
||||
padding: 5% 0 0 0;
|
||||
border-top:1px solid var(--fg-header);
|
||||
}
|
||||
|
||||
#scores {
|
||||
z-index: 200;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#scores div {
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
color: #000000;
|
||||
background: #fff;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#scores div input {
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#scores div input[type=text] {
|
||||
width: 80px;
|
||||
}
|
||||
#scores div input[type=button] {
|
||||
width: 30px;
|
||||
}
|
Loading…
Reference in New Issue
Block a user