Refactor this shit

This commit is contained in:
Oskar Winkels 2021-01-05 18:32:02 +01:00
parent c39284729d
commit 83544a28be
5 changed files with 277 additions and 270 deletions

View File

@ -17,7 +17,7 @@
<header>
<h1>FS Czech Quiz Tool</h1>
<h1>FS Quiz Tool</h1>
<noscript><span class="warning">Please enable JavaScript</span></noscript>
@ -75,7 +75,10 @@
&middot; <span id="meme"></span>
</footer>
<script src="main.js"></script>
<script src="util.js"></script>
<script src="ssparser.js"></script>
<script src="share.js"></script>
<script src="quiz.js"></script>
</body>

View File

@ -1,98 +1,3 @@
const defaultState = {
style: 'FSCzech',
id: null,
title: null,
questions: [],
success: 0,
submitTimer: 0,
submitInterval: null,
totalTimer: 0,
totalInterval: null,
}
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 = location.origin + '/?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 = location.origin + '/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 updateTotalTimer() {
var timerEls = document.querySelectorAll('.totaltimer')
@ -157,104 +62,6 @@ function startSubmitTimer(time) {
}
function parseLine(line) {
// replace newline markers with html newlines
var els = line.replace(/⎊/g, '<br>').split('\t')
var q = {}
if (els[0] != '') {
if ( els[0] == 'ChooseOne' ||
els[0] == 'ChooseAny' ||
els[0] == 'Text') {
q.type = els[0]
} else {
alert('Invalid type given on one line')
return null
}
} else {
alert('No type given on one line')
return null
}
if (els[1]) {
q.question = els[1]
} else {
alert('No question given on one line')
return null
}
// Split choices into array
// Choices for text questions are labels
// No choices (empty string) are okay for text questions
// Also filter out empty lines because some people can't use spreadsheets
if (els[2] || (q.type == 'Text' && els[2] == '')) {
q.choices = els[2].split('<br>').filter(el => el != "")
} else {
alert('No choices given at question "'
+ q.question + '"')
return null
}
// If multiple answers are allowed, they are newline-separated
// Also filter out empty lines because some people can't use spreadsheets
if (els[3] && els[3] != '') {
q.answers = els[3].split('<br>').filter(el => el != "")
} else {
alert('No answers given at question "'
+ q.question + '"')
return null
}
// Optional parameters
q.explanation = els[4] || '[No explanation provided]'
q.author = els[5] || '[No author provided]'
q.picture = els[6] || null
return q
}
function parseSpreadsheet() {
console.log('Parsing spreadsheet data')
var textEl = document.getElementById('questions')
/* MAGIC:
* 1. Find quoted multiline cells (<tab>"a<newline>b"<tab>)
* 2. Replace all newlines inside with a special char so the cell won't be
* split later (<tab>"a<specialchar>b"<tab>)
* 3. Replace escaped quotes ("a ""b"" c") with single ones ("a "b" c")
* 4. Remove the outer quotes and tabs (a<specialchar>b)
* 5. Replace all tabs inside with spaces
* 6. Re-add outer tabs (<tab>a<specialchar>b<tab>)
*/
var text = textEl.value.replace(/\t"([^"\n]|"")+\n([^"]|"")*"/g,
m => m.replace(/\n/g, '⎊')
.replace(/""/g, '"')
.replace(/^\t"(.*)"$/, '$1')
.replace(/\t/g, ' ')
.replace(/^(.*)$/g, '\t$1')
)
state.questions = text.split('\n').map(parseLine)
if (state.questions.some(el => el == null)) {
alert('Erroneous data. Please check and re-enter.')
return {success: false}
}
localStorage.setItem('state', JSON.stringify(state))
return {success: true}
}
function renderQuiz() {
var quizForm = document.querySelector('#quiz form')
@ -332,11 +139,6 @@ function reStartQuiz() {
}
function updateTitles() {
document.querySelector('#prescreen h1').innerHTML = state.title || ''
document.querySelector('#quiz h1').innerHTML = state.title || ''
}
function createQuiz() {
console.log('Creating new quiz')
@ -471,75 +273,6 @@ function abortQuiz() {
}
function idFromUrl() {
var s = window.location.search.split('id=')
if (s.length <= 1)
return null
return s[1].split('&')[0]
}
async function fetchQuiz(id) {
console.log('Fetching quiz')
var url = location.origin + '/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',
'#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 noch gepasst',
'¯\\_(ツ)_/¯',
'AMK Brudi',
'Mmmhh cones',
]
window.onload = async function() {
@ -547,6 +280,7 @@ window.onload = async function() {
var browserWarning = document.getElementById('browserwarning')
// If arrow functions are supported, it's modern enough :P
browserWarning.style.display = (() => 'none')()
var stateString = localStorage.getItem('state')
@ -577,7 +311,8 @@ window.onload = async function() {
}
updateTitles()
document.getElementById('meme').innerHTML = memes[Math.floor(Math.random()*memes.length)]
var meme = memes[Math.floor(Math.random()*memes.length)]
document.getElementById('meme').innerHTML = meme
if (stateString && !useUrl)
startQuiz()

96
web/share.js Normal file
View File

@ -0,0 +1,96 @@
function showLink() {
var link = location.origin + '/?id=' + state.id
history.pushState(state.id, '', link)
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 = location.origin + '/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 idFromUrl() {
var s = window.location.search.split('id=')
if (s.length <= 1)
return null
return s[1].split('&')[0]
}
async function fetchQuiz(id) {
console.log('Fetching quiz')
var url = location.origin + '/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
}

96
web/ssparser.js Normal file
View File

@ -0,0 +1,96 @@
function parseLine(line) {
// replace newline markers with html newlines
var els = line.replace(/⎊/g, '<br>').split('\t')
var q = {}
if (els[0] != '') {
if ( els[0] == 'ChooseOne' ||
els[0] == 'ChooseAny' ||
els[0] == 'Text') {
q.type = els[0]
} else {
alert('Invalid type given on one line')
return null
}
} else {
alert('No type given on one line')
return null
}
if (els[1]) {
q.question = els[1]
} else {
alert('No question given on one line')
return null
}
// Split choices into array
// Choices for text questions are labels
// No choices (empty string) are okay for text questions
// Also filter out empty lines because some people can't use spreadsheets
if (els[2] || (q.type == 'Text' && els[2] == '')) {
q.choices = els[2].split('<br>').filter(el => el != "")
} else {
alert('No choices given at question "'
+ q.question + '"')
return null
}
// If multiple answers are allowed, they are newline-separated
// Also filter out empty lines because some people can't use spreadsheets
if (els[3] && els[3] != '') {
q.answers = els[3].split('<br>').filter(el => el != "")
} else {
alert('No answers given at question "'
+ q.question + '"')
return null
}
// Optional parameters
q.explanation = els[4] || '[No explanation provided]'
q.author = els[5] || '[No author provided]'
q.picture = els[6] || null
return q
}
function parseSpreadsheet() {
console.log('Parsing spreadsheet data')
var textEl = document.getElementById('questions')
/* MAGIC:
* 1. Find quoted multiline cells (<tab>"a<newline>b"<tab>)
* 2. Replace all newlines inside with a special char so the cell won't be
* split later (<tab>"a<specialchar>b"<tab>)
* 3. Replace escaped quotes ("a ""b"" c") with single ones ("a "b" c")
* 4. Remove the outer quotes and tabs (a<specialchar>b)
* 5. Replace all tabs inside with spaces
* 6. Re-add outer tabs (<tab>a<specialchar>b<tab>)
*/
var text = textEl.value.replace(/\t"([^"\n]|"")+\n([^"]|"")*"/g,
m => m.replace(/\n/g, '⎊')
.replace(/""/g, '"')
.replace(/^\t"(.*)"$/, '$1')
.replace(/\t/g, ' ')
.replace(/^(.*)$/g, '\t$1')
)
state.questions = text.split('\n').map(parseLine)
if (state.questions.some(el => el == null)) {
alert('Erroneous data. Please check and re-enter.')
return {success: false}
}
localStorage.setItem('state', JSON.stringify(state))
return {success: true}
}

77
web/util.js Normal file
View File

@ -0,0 +1,77 @@
const defaultState = {
style: 'FSCzech', // enum of { FSG, FSA, FSN, FSEast, FSCzech, FSSpain, FSSwitzerland }
id: null,
title: null,
questions: [],
success: 0,
submitTimer: 0,
submitInterval: null,
totalTimer: 0,
totalInterval: null,
}
var state
function clearState() {
state = JSON.parse(JSON.stringify(defaultState))
}
clearState()
function updateTitles() {
document.querySelector('#prescreen h1').innerHTML = state.title || ''
document.querySelector('#quiz h1').innerHTML = state.title || ''
}
function changeView(view) {
for (el of document.querySelectorAll('.view'))
el.style.display = 'none'
document.getElementById(view).style.display = 'block'
}
const memes = [
"GE-SUND-BRUN-NEN-CENTER!",
"Deine Mudda! Berlin!",
"Eine Runde Kicker?",
"Hulkdrian!",
"Jetz' bin i' wieda doa",
"Mmmmh Carbonstaub",
"#würthshausfranz",
"#berlinerluft",
"FaST<b>TUBe</b>, not Fast<b>COQUE</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 noch gepasst",
"¯\\_(ツ)_/¯",
"AMK Brudi",
"Mmmhh cones",
"Best viewed in Netscape Navigator 1.22",
]