const defaultState = { style: 'FSCzech', id: null, title: null, questions: [], timer: 0, interval: null, success: 0 } var state = defaultState function clearState() { state = JSON.parse(JSON.stringify(defaultState)) } function changeView(view) { for (el of document.querySelectorAll('.view')) el.style.display = 'none' document.getElementById(view).style.display = 'block' } 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' } 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'}, 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, '
').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('
') // If multiple answers are allowed, they are ampersand-separated var answers = (els[3]) ? els[3].split('
') : 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 += `

Question #${i+1}

` html += `

${q.question}

` if (q.picture) html += `` 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') ? `
` : `
` } else { for (c of q.choices) html += `` } 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') clearState() removeLink() 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!
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', 'FaSTTUBe, not FastCOCUE', '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', ] 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)] if (stateString && !useUrl) startQuiz() if (!stateString && !useUrl) changeView('spreadsheet') console.log('onload complete') }