Add buttons to go to the next/previous question

This commit is contained in:
Matthew Welch 2021-08-29 22:04:15 -07:00
parent 965cd99aeb
commit 5519b04a46
5 changed files with 188 additions and 55 deletions

View File

@ -1,5 +1,5 @@
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 QuizTheWord import database
from QuizTheWord.admin import admin
@ -72,6 +72,36 @@ def check_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"])
def login():
next_page = request.args.get("next", default=url_for("index"))

View File

@ -5,7 +5,7 @@ import sqlalchemy
from typing import Union, Optional, Literal, Type, List, Tuple
import random
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.associationproxy import association_proxy
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:
order_by = getattr(getattr(User, sort), order)()
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()
return questions, count
return users, count
def get_all_roles() -> List[Role]:
session = get_session()
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()

View 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();
}
}

View File

@ -11,20 +11,22 @@
<p id="question-answer" class="d-none answer"></p>
<div id="bible-verses"></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>
<ul class="nav nav-pills justify-content-center mt-2">
<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>
</li>
<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>
</li>
<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>
</li>
</ul>
@ -34,36 +36,41 @@
{% block scripts %}
<script>
next_question_url = "{{ url_for("next_hidden_answer") }}";
let questions = [
{{ easy.get_dict()|tojson }},
{{ medium.get_dict()|tojson }},
{{ hard.get_dict()|tojson }},
{
"current_question": 0,
"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 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);
function change_difficulty(difficulty) {
let question = questions[difficulty-1];
function update_question() {
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"]) {
btn_show_answer.css("display", "none");
question_answer.removeClass("d-none");
@ -77,9 +84,12 @@
}
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");
btn_show_answer.css("display", "none");
}
</script>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
{% endblock %}

View File

@ -9,20 +9,22 @@
<h5 id="question-text"></h5>
<div id="question-choices" class="list-group"></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>
<ul class="nav nav-pills justify-content-center mt-2">
<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>
</li>
<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>
</li>
<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>
</li>
</ul>
@ -32,32 +34,37 @@
{% block scripts %}
<script>
next_question_url = "{{ url_for("next_multiple_choice") }}";
let questions = [
{{ easy.get_dict_shuffled_choices()|tojson }},
{{ medium.get_dict_shuffled_choices()|tojson }},
{{ hard.get_dict_shuffled_choices()|tojson }},
{
"current_question": 0,
"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);
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;
function update_question() {
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 {
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"]);
$("#bible-verses").text(question["addresses"]);
$("#question-choices").empty();
@ -83,7 +90,9 @@
}
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;
let loading_spinner = $("<div>")
.attr("id", "check-answer")
@ -116,4 +125,5 @@
});
}
</script>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
{% endblock %}