Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
sp-quiz
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Monitor
Service Desk
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Philip Kaluđerčić
sp-quiz
Commits
7fc0e0f6
Commit
7fc0e0f6
authored
1 year ago
by
Philip Kaluđerčić
Browse files
Options
Downloads
Patches
Plain Diff
Initial revision
parents
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
quiz.js
+238
-0
238 additions, 0 deletions
quiz.js
with
238 additions
and
0 deletions
quiz.js
0 → 100644
+
238
−
0
View file @
7fc0e0f6
// This horrible file is distributed under the CC0 license. Consult
// ./LICENSE for more details.
// $Id$
"
use strict
"
;
const
answers
=
document
.
getElementById
(
"
answers
"
);
const
text
=
document
.
getElementById
(
"
text
"
);
const
media
=
document
.
getElementById
(
"
media
"
);
const
metadata
=
document
.
getElementById
(
"
metadata-data
"
);
const
info
=
document
.
getElementById
(
"
info
"
);
const
info_toggle
=
document
.
getElementById
(
"
info-toggle
"
);
const
action
=
document
.
getElementById
(
"
action
"
);
const
stats
=
document
.
getElementById
(
"
stats
"
);
const
class_list
=
document
.
documentElement
.
classList
;
// toggle information panel
info_toggle
.
onclick
=
_
=>
class_list
.
toggle
(
"
open
"
);
// state variables
var
questions
;
// quiz data
var
current
;
// current question
var
done
=
{};
// question object -> correct answer
var
opts
=
[];
// DOM objects of each answer
var
progress
=
JSON
.
parse
(
window
.
localStorage
.
getItem
(
"
progress
"
))
||
{};
function
shuf
(
arr
)
{
// shuffle option-order using Fisher–Yates shuffle
for
(
let
i
=
0
;
i
<
arr
.
length
-
1
;
i
++
)
{
const
j
=
Math
.
floor
(
Math
.
random
()
*
arr
.
length
);
const
tmp
=
arr
[
j
];
arr
[
j
]
=
arr
[
i
];
arr
[
i
]
=
tmp
;
}
}
function
evaluate
(
q
)
{
const
data
=
progress
[
q
.
id
]
||
{
"
right
"
:
0
,
"
wrong
"
:
0
};
return
2
*
data
[
"
right
"
]
-
data
[
"
wrong
"
]
+
4
*
Math
.
random
()
-
2
;
}
function
get_data
(
q
)
{
return
progress
[
q
.
id
]
||
{
"
right
"
:
0
,
"
wrong
"
:
0
,
"
count
"
:
0
};;
}
function
update_stats
(
q
)
{
const
data
=
get_data
(
q
);
// update stats
stats
.
innerHTML
=
"
ID: <code>
"
+
q
.
id
+
"
</code>
"
+
"
, <abbr title=
\"
Wie oft gesehen
\"
>n</abbr> =
"
+
data
.
count
+
"
, <abbr title=
\"
Wie oft Richtig
\"
>r</abbr> =
"
+
data
.
right
+
"
, <abbr title=
\"
Wie oft Falsch
\"
>w</abbr> =
"
+
data
.
wrong
+
"
; <abbr title=
\"
Anzahl an Fragen insgesammt
\"
>#</abbr> =
"
+
questions
.
length
;
}
function
remember
(
q
,
ok
)
{
const
data
=
get_data
(
q
);
if
(
ok
)
{
data
[
"
right
"
]
++
;
}
else
{
data
[
"
wrong
"
]
++
;
}
data
[
"
count
"
]
++
;
progress
[
q
.
id
]
=
data
;
window
.
sessionStorage
.
setItem
(
"
progress
"
,
progress
);
}
function
pick
()
{
const
idx
=
Math
.
random
()
*
questions
.
length
;
let
choice
=
questions
[
Math
.
floor
(
idx
)];
let
worst
=
evaluate
(
choice
);
// FIXME: Replace this with a proper priority queue
for
(
let
i
=
0
;
i
<
questions
.
length
;
i
++
)
{
const
q
=
questions
[
i
];
let
val
=
evaluate
(
q
);
if
(
val
<=
worst
)
{
choice
=
q
;
worst
=
val
;
}
}
return
choice
;
}
// function to load random questions
function
next
()
{
const
q
=
pick
();
// load question
text
.
innerHTML
=
q
.
question
;
// load metadata
metadata
.
innerHTML
=
q
.
source
;
// load image, if specified
if
(
q
.
media
)
{
media
.
style
.
display
=
(
media
.
src
=
q
.
media
)
?
"
block
"
:
"
none
"
;
}
else
{
media
.
style
.
display
=
"
none
"
;
}
// remove all previous questions
while
(
answers
.
firstChild
)
answers
.
removeChild
(
answers
.
firstChild
);
opts
=
[];
shuf
(
q
.
options
);
// insert questions
for
(
let
i
=
0
;
i
<
q
.
options
.
length
;
i
++
)
{
const
o
=
q
.
options
[
i
];
const
li
=
document
.
createElement
(
"
li
"
);
const
input
=
document
.
createElement
(
"
input
"
);
const
answ
=
document
.
createElement
(
"
p
"
);
const
comm
=
document
.
createElement
(
"
p
"
);
// prepare button
input
.
type
=
q
.
multiple
?
"
checkbox
"
:
"
radio
"
;
input
.
name
=
"
answer
"
;
input
.
onclick
=
_
=>
class_list
.
add
(
"
tried
"
);
action
.
disabled
=
false
;
opts
[
i
]
=
input
;
// prepare answer
answ
.
classList
.
add
(
"
option
"
);
answ
.
innerHTML
=
o
.
option
;
// prepare comment
let
fallback
=
"
Falsch
"
;
comm
.
classList
.
add
(
"
comment
"
);
switch
(
o
.
correct
)
{
case
true
:
comm
.
classList
.
add
(
"
correct
"
);
fallback
=
"
Wahr
"
;
break
;
case
null
:
comm
.
classList
.
add
(
"
maybe
"
);
fallback
=
"
Unsicher
"
;
break
;
}
comm
.
innerHTML
=
o
.
comment
||
fallback
;
li
.
appendChild
(
input
);
li
.
appendChild
(
answ
);
li
.
appendChild
(
comm
);
li
.
onclick
=
_
=>
input
.
click
();
answers
.
appendChild
(
li
);
}
// set current question
current
=
q
;
// unset answer mode
class_list
.
remove
(
"
answer
"
);
class_list
.
remove
(
"
right
"
);
// display question metadata
update_stats
(
q
);
}
function
submit
()
{
let
ok
=
true
;
// check all answers
for
(
let
i
=
0
;
i
<
current
.
options
.
length
;
i
++
)
{
const
checked
=
opts
[
i
].
checked
;
const
correct
=
current
.
options
[
i
].
correct
;
if
(
correct
!=
null
&&
checked
!=
correct
)
{
// wrong answer
ok
=
false
;
}
opts
[
i
].
disabled
=
true
;
}
// respond to result
if
(
ok
)
{
class_list
.
add
(
"
right
"
);
}
remember
(
current
,
ok
);
// set answer mode
class_list
.
add
(
"
answer
"
);
class_list
.
remove
(
"
tried
"
);
action
.
disabled
=
false
;
}
// listen to keys
document
.
onkeyup
=
evt
=>
{
switch
(
evt
.
code
)
{
// shortcuts for first 10 options
case
"
Digit1
"
:
if
(
0
in
opts
)
opts
[
0
].
click
();
break
;
case
"
Digit2
"
:
if
(
1
in
opts
)
opts
[
1
].
click
();
break
;
case
"
Digit3
"
:
if
(
2
in
opts
)
opts
[
2
].
click
();
break
;
case
"
Digit4
"
:
if
(
3
in
opts
)
opts
[
3
].
click
();
break
;
case
"
Digit5
"
:
if
(
4
in
opts
)
opts
[
4
].
click
();
break
;
case
"
Digit6
"
:
if
(
5
in
opts
)
opts
[
5
].
click
();
break
;
case
"
Digit7
"
:
if
(
6
in
opts
)
opts
[
6
].
click
();
break
;
case
"
Digit8
"
:
if
(
7
in
opts
)
opts
[
7
].
click
();
break
;
case
"
Digit9
"
:
if
(
8
in
opts
)
opts
[
8
].
click
();
break
;
case
"
Digit0
"
:
if
(
9
in
opts
)
opts
[
9
].
click
();
break
;
case
"
Space
"
:
case
"
Enter
"
:
// shortcut for action button
action
.
click
();
break
;
case
"
Escape
"
:
// close info section
document
.
documentElement
.
classList
.
remove
(
"
open
"
);
break
;
}
};
// setup action button
action
.
onclick
=
_
=>
{
if
(
class_list
.
contains
(
"
answer
"
))
next
();
else
if
(
class_list
.
contains
(
"
tried
"
))
submit
();
}
// query quiz data (unpleasant hack)
(
async
function
()
{
// query json specification of quiz
questions
=
await
(
await
fetch
(
"
./quiz.json
"
)).
json
();
shuf
(
questions
);
// when done, load first question
next
();
})();
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment