From c214508ee71fcdcc5144e907dca131c18deb4029 Mon Sep 17 00:00:00 2001 From: Lukas Winkler Date: Wed, 28 Mar 2018 15:01:16 +0200 Subject: [PATCH] implement quiz --- server.py | 17 ++++++- templates/quiz.html | 34 ++++++++++++-- web/static/js/app.js | 94 ++++++++++++++++++++++++++++++++++++-- web/static/sass/style.scss | 62 ++++++++++++++++++++++++- 4 files changed, 198 insertions(+), 9 deletions(-) diff --git a/server.py b/server.py index 163c468..1952799 100644 --- a/server.py +++ b/server.py @@ -87,10 +87,25 @@ def quiz(): print('{} ms'.format((time2 - time1) * 1000.0)) return render_template( "quiz.html", - question=question + question=question, + stats=session["quiz"] if "quiz" in session else {"total": 0, "correct": 0} ) +@app.route("/api/quiz//", methods=["POST"]) +def quiz_api(id, guess): + if "quiz" not in session: + session["quiz"] = {"total": 0, "correct": 0} + session["quiz"]["total"] += 1 + query = Question.select(Site).join(Site).where(Question.id == id).get() + if guess == query.site.url: + correct = True + session["quiz"]["correct"] += 1 + else: + correct = False + return jsonify({"site": model_to_dict(query)["site"], "correct": correct}) + + @app.route('/api/sites') def sites(): sites = Site.select().where(Site.last_download.is_null(False)) diff --git a/templates/quiz.html b/templates/quiz.html index cbca7dc..fcb2dae 100644 --- a/templates/quiz.html +++ b/templates/quiz.html @@ -1,12 +1,40 @@ {% extends "base.html" %} {% block body %} - - +
+

Stackexchange-Quiz

+
+ + + +
+ + +
+
+
+ Correct! +
+
+ Incorrect! +
+
+
+
Total
{{ stats.total }}
+
Correct
{{ stats.correct }}
+
Ratio
{{ '%d' | format((stats.correct / stats.total * 100) if stats.correct > 0 else 0) }}%
+ +
+ + +

{{ question.title.text }}

-
+
{{ question.upvotes - question.downvotes }}
diff --git a/web/static/js/app.js b/web/static/js/app.js index 44943fe..5781134 100644 --- a/web/static/js/app.js +++ b/web/static/js/app.js @@ -27,6 +27,45 @@ document.addEventListener("DOMContentLoaded", function (event) { }); }); var input = document.getElementById("siteselector"); + var check = document.getElementById("check"); + var header = document.getElementsByClassName("siteheader")[0]; + var retry = document.getElementById("retry"); + var selectedSite, headerimg, headertitle, entered; + + function toast(type, message) { + console.warn(type, message) + } + + function checkQuiz(selection, id) { + console.info(selection, id); + input.disabled = true; + check.disabled = true; + var request = new XMLHttpRequest(); + request.open("POST", "/api/quiz/" + id + "/" + selection.url, true); + + request.onload = function () { + if (this.status >= 200 && this.status < 400) { + var resp = JSON.parse(this.response); + console.log(resp.correct); + headertitle.innerText = resp.site.name; + headerimg.src = resp.site.icon_url; + header.style.backgroundColor = resp.site.tag_background_color; + header.style.color = resp.site.link_color; + var result = document.getElementById(resp.correct ? "correct" : "incorrect"); + result.style.display = "block"; + retry.focus() + } else { + // We reached our target server, but it returned an error + + } + }; + request.onerror = function () { + // There was a connection error of some sort + }; + request.send(); + + } + if (input) { var mode = input.dataset.mode; var request = new XMLHttpRequest(); @@ -52,18 +91,37 @@ document.addEventListener("DOMContentLoaded", function (event) { minChars: 0, autoFirst: true }); + if (mode === "quiz") { + console.log(input); + input.focus() + } input.addEventListener("awesomplete-select", function (event) { if (!(event.text.value in resp)) { // shouldn't happen return false } - var selectedSite = resp[event.text.value]; + selectedSite = resp[event.text.value]; if (mode === "filter") { window.location.href = "/s/" + selectedSite.url } else if (mode === "quiz") { - console.log(selectedSite); - } + input.focus(); + entered = true; + console.log(selectedSite); + check.style.backgroundColor = selectedSite.tag_background_color; + header.style.backgroundColor = selectedSite.tag_background_color; + check.style.color = selectedSite.link_color; + header.style.color = selectedSite.link_color; + while (header.firstChild) { + header.removeChild(header.firstChild); + } + headerimg = new Image(30, 30); + headerimg.src = selectedSite.icon_url; + headertitle = document.createElement('span'); + headertitle.innerText = selectedSite.name + "?"; + header.appendChild(headerimg); + header.appendChild(headertitle); + } }); } else { // We reached our target server, but it returned an error @@ -74,6 +132,36 @@ document.addEventListener("DOMContentLoaded", function (event) { // There was a connection error of some sort }; request.send(); + if (mode === "quiz") { + var handler = function (event) { + // event.preventDefault(); + if (event.keyCode === 13 && entered) { + checkQuiz(selectedSite, input.dataset.id); + input.removeEventListener("keydown", handler, false) + } + }; + input.addEventListener("keydown", handler); + input.addEventListener("input", function () { + entered = false + }); + check.addEventListener("click", function () { + if (entered) { + checkQuiz(selectedSite, input.dataset.id); + + } else { + toast("warning", "please select a site") + } + }); + retry.addEventListener("click", function () { + window.location.reload(true); + }); + retry.addEventListener("click", function (event) { + if (event.keyCode === 13) { + window.location.reload(true); + } + }); + + } } diff --git a/web/static/sass/style.scss b/web/static/sass/style.scss index f78b4bf..68842ac 100644 --- a/web/static/sass/style.scss +++ b/web/static/sass/style.scss @@ -20,7 +20,7 @@ pre > code { display: flex; flex-direction: row; padding: 15px 5px 15px; - &:not(.question){ + &:not(.question) { border-bottom: solid lightgray 1px; } border-right: solid 10px transparent; @@ -104,10 +104,14 @@ h1, h2 { margin-top: 10px; color: inherit; } -h2 {font-size: 18px} + +h2 { + font-size: 18px +} .siteheader { background: #ebf2f5; + transition: background-color .3s, color .3s; display: flex; height: 50px; align-items: center; @@ -116,3 +120,57 @@ h2 {font-size: 18px} color: inherit; } } + +.quizselector { + margin: 15px; + display: flex; + flex-direction: row; + justify-content: center; + > .awesomplete { + margin-right: 5px; + width: 70%; + input { + font-size: 20px; + width: 100%; + } + } +} + +button { + height: 32px; + background-color: lightgray; + color: #606c76; + border: none; + transition: opacity .3s; + &:hover, &:focus { + opacity: .6; + background-color: lightgray; + color: #606c76; + } +} + +#result { + > div { + width: 100%; + padding: 20px 0; + font-size: 25px; + text-align: center; + display: none; + } +} + +#correct { + background-color: $success; +} + +#incorrect { + background-color: $warning; +} + +#stats { + display: flex; + flex-direction: row; + justify-content: space-around; + text-align: center; + padding: 20px 0; +}