fs-quiz-tool/src/main.js

470 lines
8.5 KiB
JavaScript
Raw Normal View History

2020-01-13 00:24:53 +01:00
const defaultState = {
2020-01-12 15:25:31 +01:00
style: 'FSCzech',
id: null,
title: null,
questions: [],
timer: 0,
interval: null,
success: 0
}
2020-01-13 00:24:53 +01:00
var state = defaultState
2020-01-13 00:52:30 +01:00
function clearState() {
state = JSON.parse(JSON.stringify(defaultState))
}
2020-01-12 15:25:31 +01:00
function changeView(view) {
for (el of document.querySelectorAll('.view'))
el.style.display = 'none'
document.getElementById(view).style.display = 'block'
2020-01-12 15:25:31 +01:00
}
function showLink() {
var link = 'https://quiz.fasttube.de/?id=' + state.id
var linkEl = document.getElementById('shareLink')
linkEl.href = link
linkEl.innerHTML = link
document.querySelector('#sharing input').style.display = 'none'
}
function removeLink() {
var linkEl = document.getElementById('shareLink')
linkEl.href = ''
linkEl.innerHTML = ''
document.querySelector('#sharing input').style.display = 'inline-block'
}
2020-01-12 15:25:31 +01:00
async function shareQuiz() {
if (state.id) {
console.log('Showing saved local link')
showLink()
return
}
console.log('Saving quiz to server. QuizData:')
var quizData = {
title: state.title,
questions: state.questions
}
console.log(quizData)
console.log('Waiting for id')
var db = 'https://quiz.fasttube.de/db/'
var response = await fetch(db, {
method: 'POST',
headers: {'Content-Type': 'text/plain'},
2020-01-12 15:25:31 +01:00
body: JSON.stringify(quizData)
})
if (response.ok == false) {
alert('Something went wrong while sharing')
return
}
var responseBody = await response.text()
console.log('Received id: ' + responseBody)
state.id = responseBody
showLink()
}
function updateTimer() {
var button = document.getElementById('quizSubmitButton')
if (state.timer > 0) {
button.value = 'Wait ' + state.timer + 's'
button.disabled = true
state.timer -= 1
} else {
button.value = 'Submit Answers'
button.disabled = false
clearInterval(state.interval)
}
localStorage.setItem('state', JSON.stringify(state))
}
function startTimer(time) {
state.timer = time || 30
console.log('Setting timer to ' + state.timer + ' seconds.')
updateTimer()
state.interval = setInterval(updateTimer, 1000)
}
function parseLine(line) {
// replace newline markers with newlines
var els = line.replace(/⎊/g, '<br>').split('\t')
if (els.length < 4) {
alert('Information missing. At least 4 columns needed.')
return null
}
var type = els[0]
// For multiple-choice, split lines into array
var choices = els[2].split('<br>')
// If multiple answers are allowed, they are ampersand-separated
var answers = (els[3]) ? els[3].split('<br>') : null
return {
question: els[1] || '[No question provided]',
type: type,
choices: choices,
answers: answers,
explanation: els[4] || '[No explanation provided]',
author: els[5] || '[No author provided]',
picture: els[6] || null,
}
}
function parseSpreadsheet() {
console.log('Parsing spreadsheet data')
var textEl = document.getElementById('questions')
var text = textEl.value.replace(/"([^"]|"")+"/g, m => m.replace(/\n/g, '⎊').replace(/""/g, '"').replace(/^"(.*)"$/, '$1'))
state.questions = text.split('\n').map(parseLine)
if (state.questions[0] == null)
return {success: false}
localStorage.setItem('state', JSON.stringify(state))
return {success: true}
}
function startQuiz() {
state.success = false
console.log('Starting/Resuming quiz. State:')
console.log(state)
var quizForm = document.querySelector('#quiz form')
for (const [i, q] of state.questions.entries()) {
var html = ''
html += `<h3>Question #${i+1}</h3>`
html += `<h4>${q.question}</h4>`
if (q.picture)
html += `<img src="${q.picture}">`
if (q.type == 'ChooseOne' || q.type == 'ChooseAny') {
var choices = Array.from(q.choices.entries())
var shuffled = choices.sort(() => Math.random() - 0.5)
for ([ci, c] of shuffled)
html += (q.type == 'ChooseOne')
? `<label><input type="radio" name="q${i}" value="${ci+1}"> <p>${c}</p></label><br>`
: `<label><input type="checkbox" name="q${i}" value="${ci+1}"> <p>${c}</p></label><br>`
} else {
for (c of q.choices)
html += `<label>${c}<input type="text" name="q${i}"></label>`
}
quizForm.innerHTML += html
}
changeView('quiz')
if (state.timer > 0)
startTimer(state.timer)
else
updateTimer()
console.log('Quiz started/resumed')
}
function updateTitles() {
document.querySelector('#prescreen h1').innerHTML = state.title || ''
document.querySelector('#quiz h1').innerHTML = state.title || ''
}
function createQuiz() {
console.log('Creating new quiz')
2020-01-13 00:52:30 +01:00
clearState()
removeLink()
2020-01-12 15:25:31 +01:00
if (parseSpreadsheet().success == false)
return
console.log('Spreadsheet parsing successful')
state.title = document.getElementById('titleField').value
updateTitles()
changeView('prescreen')
console.log('Quiz created')
}
function endQuiz() {
console.log('Ending quiz')
localStorage.removeItem('state')
document.querySelector('#quiz form').innerHTML = ''
changeView('postscreen')
if (state.interval)
clearInterval(state.interval)
console.log('Quiz ended')
}
function mergeKeyReducer(acc, entry) {
if (!acc[entry[0]])
acc[entry[0]] = []
acc[entry[0]].push(entry[1])
return acc
}
function submitQuiz() {
console.log('Submitting quiz. State:')
console.log(state)
var quizForm = document.querySelector('#quiz form')
var data = new FormData(quizForm)
var responses = Array.from(data.entries()).reduce(mergeKeyReducer, {})
console.log(responses)
var correct = 0
for (var [key, value] of Object.entries(responses)) {
console.log(key + ": " + value)
// "q3" -> 3
var idx = key[1]
if (state.questions[idx].type == 'ChooseOne' || state.questions[idx].type == 'ChooseAny') {
state.questions[idx].answers.sort()
value.sort()
}
if (JSON.stringify(state.questions[idx].answers) == JSON.stringify(value))
correct++
}
var text = '' + correct + '/' + state.questions.length + ' questions answered correctly.\n'
state.success = (correct == state.questions.length)
text += state.success ? 'Yay you did it!' : 'Try again!'
if (!state.success) {
startTimer()
alert(text)
}
if (state.success) {
document.querySelector('#postscreen h1').innerHTML = `Yay, we're done!<br>Everything is correct :)`
endQuiz()
}
console.log('Quiz submitted')
}
function abortQuiz() {
console.log('Aborting quiz')
if (!confirm('You sure you want to abort this quiz? Your progress will be lost.'))
return
document.querySelector('#postscreen h1').innerHTML = `Quiz cancelled.`
endQuiz()
console.log('Quiz cancelled')
}
function idFromUrl() {
var s = window.location.href.split('id=')
if (s.length <= 1)
return null
return s[1].split('&')[0]
}
async function fetchQuiz(id) {
console.log('Fetching quiz')
var url = 'https://quiz.fasttube.de/db/' + id
var response = await fetch(url)
if (response.ok == false) {
alert('Something went wrong while loading this quiz')
return
}
var json = await response.json()
console.log('Quiz fetched. Response:')
console.log(json)
return json
}
const memes = [
'GE-SUND-BRUN-NEN-CENTER!',
'Deine Mudda! Berlin!',
'Eine Runde Kicker?',
'Hulkdrian!',
'Jetz\' bin i\' wieda doa',
'Mmmmh Carbonstaub :P',
'#würthshausfranz',
'#berlinerluft',
'FaST<b>TUBe</b>, not Fast<b>COCUE</b>',
'Yes, we CAN',
'Ist in der Cloud.',
'Ist im Wiki.',
'Ich liiebe Teamcenter <3',
'Podio kann alles!',
'Let\'s build 3 fucking racecars!',
'Der Fahrstuhl ist kaputt',
'Frau Ipta reißt euch den Kopf ab!',
'Max, Max, Max, Max, Max, Max, MaxMax!',
'Julian, Anwärter, Firewall',
'Diese Webseite ist geerdet.',
'Wer AMS sagt muss auch BMS sagen',
'Ist der Kabelbinder in der BOM?',
'*Fistbump*',
'Nividia',
'Ihr schafft das! :)',
'Klotzen, nicht kleckern!',
'*revving noises*',
'Resistance is futile',
'Jan schweißt das noch',
'Would Claude approve of this?',
'Im CAD hat\'s gepasst',
'¯\\_(ツ)_/¯',
'AMK Brudi',
'Mmmhh cones',
]
2020-01-12 15:25:31 +01:00
window.onload = async function() {
console.log('onload')
var stateString = localStorage.getItem('state')
var urlId = idFromUrl()
console.log('URL ID:' + urlId)
if (stateString) {
console.log('Loading local state')
state = JSON.parse(stateString)
}
// only fetch if it's a different one
var useUrl = (urlId && urlId != state.id)
if (useUrl) {
console.log('Using remote quiz from url')
quiz = await fetchQuiz(urlId)
state.title = quiz.title
state.questions = quiz.questions
state.id = urlId
changeView('prescreen')
}
updateTitles()
document.getElementById('meme').innerHTML = memes[Math.floor(Math.random()*memes.length)]
2020-01-12 15:25:31 +01:00
if (stateString && !useUrl)
startQuiz()
if (!stateString && !useUrl)
changeView('spreadsheet')
console.log('onload complete')
}