Add buttons to go to the next/previous question
This commit is contained in:
parent
965cd99aeb
commit
5519b04a46
@ -1,5 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
from flask import request, render_template, jsonify, Flask, url_for, redirect, flash
|
from flask import request, render_template, jsonify, Flask, url_for, redirect, flash, session
|
||||||
from flask_security import Security, SQLAlchemySessionUserDatastore, login_user, logout_user, current_user
|
from flask_security import Security, SQLAlchemySessionUserDatastore, login_user, logout_user, current_user
|
||||||
from QuizTheWord import database
|
from QuizTheWord import database
|
||||||
from QuizTheWord.admin import admin
|
from QuizTheWord.admin import admin
|
||||||
@ -72,6 +72,36 @@ def check_answer():
|
|||||||
return jsonify(database.check_answer(question_id, answer))
|
return jsonify(database.check_answer(question_id, answer))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/category/hidden_answer/next_question")
|
||||||
|
def next_hidden_answer():
|
||||||
|
if "hidden_answer_ids" not in session:
|
||||||
|
session["hidden_answer_ids"] = []
|
||||||
|
difficulty = request.args.get("difficulty", 1)
|
||||||
|
next_question = database.next_hidden_answer(session["hidden_answer_ids"], difficulty)
|
||||||
|
if next_question:
|
||||||
|
session["hidden_answer_ids"].append(next_question.question_id)
|
||||||
|
session.modified = True
|
||||||
|
return jsonify(next_question.get_dict())
|
||||||
|
else:
|
||||||
|
session.pop("hidden_answer_ids", None)
|
||||||
|
return jsonify(None)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/category/multiple_choice/next_question")
|
||||||
|
def next_multiple_choice():
|
||||||
|
if "multiple_choice_ids" not in session:
|
||||||
|
session["multiple_choice_ids"] = []
|
||||||
|
difficulty = request.args.get("difficulty", 1)
|
||||||
|
next_question = database.next_multiple_choice(session["multiple_choice_ids"], difficulty)
|
||||||
|
if next_question:
|
||||||
|
session["multiple_choice_ids"].append(next_question.question_id)
|
||||||
|
session.modified = True
|
||||||
|
return jsonify(next_question.get_dict_shuffled_choices())
|
||||||
|
else:
|
||||||
|
session.pop("multiple_choice_ids", None)
|
||||||
|
return jsonify(None)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/login", methods=["GET", "POST"])
|
@app.route("/login", methods=["GET", "POST"])
|
||||||
def login():
|
def login():
|
||||||
next_page = request.args.get("next", default=url_for("index"))
|
next_page = request.args.get("next", default=url_for("index"))
|
||||||
|
@ -5,7 +5,7 @@ import sqlalchemy
|
|||||||
from typing import Union, Optional, Literal, Type, List, Tuple
|
from typing import Union, Optional, Literal, Type, List, Tuple
|
||||||
import random
|
import random
|
||||||
from sqlalchemy import Column, JSON, String, Integer, create_engine, ForeignKey, func, Boolean, UnicodeText, DateTime
|
from sqlalchemy import Column, JSON, String, Integer, create_engine, ForeignKey, func, Boolean, UnicodeText, DateTime
|
||||||
from sqlalchemy.sql.expression import or_, and_
|
from sqlalchemy.sql.expression import and_
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.ext.associationproxy import association_proxy
|
from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
from sqlalchemy.orm import sessionmaker, relationship, scoped_session
|
from sqlalchemy.orm import sessionmaker, relationship, scoped_session
|
||||||
@ -410,11 +410,27 @@ def query_users(offset, limit, query: dict = None, sort=None, order=None) -> Tup
|
|||||||
if sort and order:
|
if sort and order:
|
||||||
order_by = getattr(getattr(User, sort), order)()
|
order_by = getattr(getattr(User, sort), order)()
|
||||||
q = session.query(User).filter(*query_params).order_by(order_by)
|
q = session.query(User).filter(*query_params).order_by(order_by)
|
||||||
questions = q.offset(offset).limit(limit).all()
|
users = q.offset(offset).limit(limit).all()
|
||||||
count = q.count()
|
count = q.count()
|
||||||
return questions, count
|
return users, count
|
||||||
|
|
||||||
|
|
||||||
def get_all_roles() -> List[Role]:
|
def get_all_roles() -> List[Role]:
|
||||||
session = get_session()
|
session = get_session()
|
||||||
return session.query(Role).all()
|
return session.query(Role).all()
|
||||||
|
|
||||||
|
|
||||||
|
def next_hidden_answer(previous_questions: List[int], difficulty) -> HiddenAnswer:
|
||||||
|
session = get_session()
|
||||||
|
return session.query(HiddenAnswer)\
|
||||||
|
.filter(HiddenAnswer.hidden_answer_difficulty == difficulty,
|
||||||
|
HiddenAnswer.question_id.notin_(previous_questions))\
|
||||||
|
.order_by(func.random()).first()
|
||||||
|
|
||||||
|
|
||||||
|
def next_multiple_choice(previous_questions: List[int], difficulty) -> MultipleChoice:
|
||||||
|
session = get_session()
|
||||||
|
return session.query(MultipleChoice)\
|
||||||
|
.filter(MultipleChoice.multiple_choice_difficulty == difficulty,
|
||||||
|
MultipleChoice.question_id.notin_(previous_questions))\
|
||||||
|
.order_by(func.random()).first()
|
||||||
|
67
QuizTheWord/static/js/script.js
Normal file
67
QuizTheWord/static/js/script.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
let difficulty_selection = $(".difficulty-selection");
|
||||||
|
let btn_previous_question = $("#btn-previous-question");
|
||||||
|
let btn_next_question = $("#btn-next-question");
|
||||||
|
let control_btns = $(".control-btn");
|
||||||
|
let current_difficulty = 1;
|
||||||
|
|
||||||
|
difficulty_selection.on("click", change_difficulty);
|
||||||
|
btn_next_question.on("click", next_question);
|
||||||
|
btn_previous_question.on("click", previous_question);
|
||||||
|
|
||||||
|
update_question();
|
||||||
|
|
||||||
|
function get_new_question(difficulty) {
|
||||||
|
control_btns.attr("disabled", true);
|
||||||
|
$.ajax(next_question_url, {
|
||||||
|
method: "GET",
|
||||||
|
cache: false,
|
||||||
|
data: {difficulty: difficulty},
|
||||||
|
dataType: "json",
|
||||||
|
success: (data, textStatus, jqXHR) => {
|
||||||
|
control_btns.attr("disabled", false);
|
||||||
|
question_received(data);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function change_difficulty(event) {
|
||||||
|
difficulty_selection.removeClass("active");
|
||||||
|
let target = $(event.target);
|
||||||
|
target.addClass("active");
|
||||||
|
if (target.prop("innerText") === "Easy") {
|
||||||
|
current_difficulty = 1;
|
||||||
|
} else if (target.prop("innerText") === "Medium") {
|
||||||
|
current_difficulty = 2;
|
||||||
|
} else {
|
||||||
|
current_difficulty = 3;
|
||||||
|
}
|
||||||
|
update_question();
|
||||||
|
}
|
||||||
|
|
||||||
|
function next_question() {
|
||||||
|
let difficulty = questions[current_difficulty-1]
|
||||||
|
let question_index = difficulty["current_question"]+1;
|
||||||
|
if (difficulty["questions"].length === question_index) {
|
||||||
|
get_new_question(current_difficulty);
|
||||||
|
} else {
|
||||||
|
difficulty["current_question"] += 1;
|
||||||
|
update_question();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function previous_question() {
|
||||||
|
questions[current_difficulty-1]["current_question"] -= 1;
|
||||||
|
update_question();
|
||||||
|
}
|
||||||
|
|
||||||
|
function question_received(data) {
|
||||||
|
let difficulty = questions[current_difficulty-1];
|
||||||
|
if (data) {
|
||||||
|
difficulty["questions"].push(data);
|
||||||
|
difficulty["current_question"] += 1;
|
||||||
|
update_question();
|
||||||
|
} else {
|
||||||
|
difficulty["last_index"] = difficulty["current_question"];
|
||||||
|
update_question();
|
||||||
|
}
|
||||||
|
}
|
@ -11,20 +11,22 @@
|
|||||||
<p id="question-answer" class="d-none answer"></p>
|
<p id="question-answer" class="d-none answer"></p>
|
||||||
<div id="bible-verses"></div>
|
<div id="bible-verses"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<button id="btn-previous-question" class="btn btn-primary mt-2 float-start control-btn">Previous</button>
|
||||||
|
<button id="btn-next-question" class="btn btn-primary mt-2 float-end">Next</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="nav nav-pills justify-content-center mt-2">
|
<ul class="nav nav-pills justify-content-center mt-2">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link active difficulty-selection" id="btn-show-easy" type="button" aria-controls="easy" aria-selected="true">Easy
|
<button class="nav-link active difficulty-selection control-btn" id="btn-show-easy" type="button" aria-controls="easy" aria-selected="true">Easy
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link difficulty-selection" id="btn-show-medium" type="button" aria-controls="medium" aria-selected="false">Medium
|
<button class="nav-link difficulty-selection control-btn" id="btn-show-medium" type="button" aria-controls="medium" aria-selected="false">Medium
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link difficulty-selection" id="btn-show-hard" type="button" aria-controls="hard" aria-selected="false">Hard
|
<button class="nav-link difficulty-selection control-btn" id="btn-show-hard" type="button" aria-controls="hard" aria-selected="false">Hard
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -34,36 +36,41 @@
|
|||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script>
|
<script>
|
||||||
|
next_question_url = "{{ url_for("next_hidden_answer") }}";
|
||||||
let questions = [
|
let questions = [
|
||||||
{{ easy.get_dict()|tojson }},
|
{
|
||||||
{{ medium.get_dict()|tojson }},
|
"current_question": 0,
|
||||||
{{ hard.get_dict()|tojson }},
|
"questions": [{{ easy.get_dict()|tojson }}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"current_question": 0,
|
||||||
|
"questions": [{{ medium.get_dict()|tojson }}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"current_question": 0,
|
||||||
|
"questions": [{{ hard.get_dict()|tojson }}],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
let difficulty_selection = $(".difficulty-selection");
|
|
||||||
let btn_show_answer = $("#btn-show-answer");
|
let btn_show_answer = $("#btn-show-answer");
|
||||||
let question_answer = $("#question-answer");
|
let question_answer = $("#question-answer");
|
||||||
let current_difficulty = 1;
|
|
||||||
|
|
||||||
change_difficulty(current_difficulty);
|
|
||||||
|
|
||||||
difficulty_selection.on("click", (event) => {
|
|
||||||
difficulty_selection.removeClass("active");
|
|
||||||
let target = $(event.target);
|
|
||||||
target.addClass("active");
|
|
||||||
if (target.prop("innerText") === "Easy") {
|
|
||||||
current_difficulty = 1;
|
|
||||||
} else if (target.prop("innerText") === "Medium") {
|
|
||||||
current_difficulty = 2;
|
|
||||||
} else {
|
|
||||||
current_difficulty = 3;
|
|
||||||
}
|
|
||||||
change_difficulty(current_difficulty);
|
|
||||||
})
|
|
||||||
|
|
||||||
btn_show_answer.on("click", showAnswer);
|
btn_show_answer.on("click", showAnswer);
|
||||||
|
|
||||||
function change_difficulty(difficulty) {
|
function update_question() {
|
||||||
let question = questions[difficulty-1];
|
let difficulty = questions[current_difficulty-1];
|
||||||
|
let question_index = difficulty["current_question"];
|
||||||
|
let question = difficulty["questions"][question_index];
|
||||||
|
if (question_index === 0) {
|
||||||
|
btn_previous_question.attr("disabled", true);
|
||||||
|
} else {
|
||||||
|
btn_previous_question.attr("disabled", false);
|
||||||
|
}
|
||||||
|
if (question_index === difficulty["last_index"]) {
|
||||||
|
btn_next_question.attr("disabled", true);
|
||||||
|
} else {
|
||||||
|
btn_next_question.attr("disabled", false);
|
||||||
|
}
|
||||||
|
|
||||||
if (question["answer_visible"]) {
|
if (question["answer_visible"]) {
|
||||||
btn_show_answer.css("display", "none");
|
btn_show_answer.css("display", "none");
|
||||||
question_answer.removeClass("d-none");
|
question_answer.removeClass("d-none");
|
||||||
@ -77,9 +84,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showAnswer() {
|
function showAnswer() {
|
||||||
questions[current_difficulty-1]["answer_visible"] = true;
|
let question_index = questions[current_difficulty-1]["current_question"];
|
||||||
|
let question = questions[current_difficulty-1]["questions"][question_index];
|
||||||
|
question["answer_visible"] = true;
|
||||||
question_answer.removeClass("d-none");
|
question_answer.removeClass("d-none");
|
||||||
btn_show_answer.css("display", "none");
|
btn_show_answer.css("display", "none");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -9,20 +9,22 @@
|
|||||||
<h5 id="question-text"></h5>
|
<h5 id="question-text"></h5>
|
||||||
<div id="question-choices" class="list-group"></div>
|
<div id="question-choices" class="list-group"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<button id="btn-previous-question" class="btn btn-primary mt-2 float-start control-btn">Previous</button>
|
||||||
|
<button id="btn-next-question" class="btn btn-primary mt-2 float-end control-btn">Next</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="nav nav-pills justify-content-center mt-2">
|
<ul class="nav nav-pills justify-content-center mt-2">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link active difficulty-selection" id="btn-show-easy" type="button" aria-controls="easy" aria-selected="true">Easy
|
<button class="nav-link active difficulty-selection control-btn" id="btn-show-easy" type="button" aria-controls="easy" aria-selected="true">Easy
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link difficulty-selection" id="btn-show-medium" type="button" aria-controls="medium" aria-selected="false">Medium
|
<button class="nav-link difficulty-selection control-btn" id="btn-show-medium" type="button" aria-controls="medium" aria-selected="false">Medium
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link difficulty-selection" id="btn-show-hard" type="button" aria-controls="hard" aria-selected="false">Hard
|
<button class="nav-link difficulty-selection control-btn" id="btn-show-hard" type="button" aria-controls="hard" aria-selected="false">Hard
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -32,32 +34,37 @@
|
|||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script>
|
<script>
|
||||||
|
next_question_url = "{{ url_for("next_multiple_choice") }}";
|
||||||
let questions = [
|
let questions = [
|
||||||
{{ easy.get_dict_shuffled_choices()|tojson }},
|
{
|
||||||
{{ medium.get_dict_shuffled_choices()|tojson }},
|
"current_question": 0,
|
||||||
{{ hard.get_dict_shuffled_choices()|tojson }},
|
"questions": [{{ easy.get_dict_shuffled_choices()|tojson }}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"current_question": 0,
|
||||||
|
"questions": [{{ medium.get_dict_shuffled_choices()|tojson }}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"current_question": 0,
|
||||||
|
"questions": [{{ hard.get_dict_shuffled_choices()|tojson }}],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
let difficulty_selection = $(".difficulty-selection");
|
|
||||||
let current_difficulty = 1;
|
|
||||||
|
|
||||||
change_difficulty(current_difficulty);
|
function update_question() {
|
||||||
|
let difficulty = questions[current_difficulty-1];
|
||||||
difficulty_selection.on("click", (event) => {
|
let question_index = difficulty["current_question"];
|
||||||
difficulty_selection.removeClass("active");
|
let question = difficulty["questions"][question_index];
|
||||||
let target = $(event.target);
|
if (question_index === 0) {
|
||||||
target.addClass("active");
|
btn_previous_question.attr("disabled", true);
|
||||||
if (target.prop("innerText") === "Easy") {
|
|
||||||
current_difficulty = 1;
|
|
||||||
} else if (target.prop("innerText") === "Medium") {
|
|
||||||
current_difficulty = 2;
|
|
||||||
} else {
|
} else {
|
||||||
current_difficulty = 3;
|
btn_previous_question.attr("disabled", false);
|
||||||
|
}
|
||||||
|
if (question_index === difficulty["last_index"]) {
|
||||||
|
btn_next_question.attr("disabled", true);
|
||||||
|
} else {
|
||||||
|
btn_next_question.attr("disabled", false);
|
||||||
}
|
}
|
||||||
change_difficulty(current_difficulty);
|
|
||||||
})
|
|
||||||
|
|
||||||
function change_difficulty(difficulty) {
|
|
||||||
let question = questions[difficulty-1];
|
|
||||||
$("#question-text").text(question["question_text"]);
|
$("#question-text").text(question["question_text"]);
|
||||||
$("#bible-verses").text(question["addresses"]);
|
$("#bible-verses").text(question["addresses"]);
|
||||||
$("#question-choices").empty();
|
$("#question-choices").empty();
|
||||||
@ -83,7 +90,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkAnswer(question_id, button_index, answer) {
|
function checkAnswer(question_id, button_index, answer) {
|
||||||
let question = questions[current_difficulty-1];
|
let difficulty = questions[current_difficulty-1];
|
||||||
|
let question_index = difficulty["current_question"];
|
||||||
|
let question = difficulty["questions"][question_index];
|
||||||
question["chosen_answer"] = button_index;
|
question["chosen_answer"] = button_index;
|
||||||
let loading_spinner = $("<div>")
|
let loading_spinner = $("<div>")
|
||||||
.attr("id", "check-answer")
|
.attr("id", "check-answer")
|
||||||
@ -116,4 +125,5 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
Reference in New Issue
Block a user