-
This commit is contained in:
		
							parent
							
								
									2c9a744667
								
							
						
					
					
						commit
						319b3410ba
					
				@ -15,15 +15,24 @@ if (!get_autologin_state()) {
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <title>SpreadQuiz</title>
 | 
			
		||||
    <script src="js/spreadquiz.js"></script>
 | 
			
		||||
    <script src="js/req.js"></script>
 | 
			
		||||
    <script src="js/o.js"></script>
 | 
			
		||||
    <script src="js/common.js"></script>
 | 
			
		||||
    <script src="js/spreadquiz.js"></script>
 | 
			
		||||
    <script src="js/default_frame.js"></script>
 | 
			
		||||
    <link rel="stylesheet" href="style/spreadquiz.css">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<section id="game_list_panel">
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
<section class="window" shown="false" id="results_window">
 | 
			
		||||
    <section class="window-inner">
 | 
			
		||||
        <section id="results_overview_display">
 | 
			
		||||
 | 
			
		||||
        </section>
 | 
			
		||||
        <input type="button" value="Bezárás" onclick="hide('results_window')">
 | 
			
		||||
    </section>
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								gamemgr.php
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								gamemgr.php
									
									
									
									
									
								
							@ -13,7 +13,7 @@ const DEFAULT_GAME_PROPERTIES = [
 | 
			
		||||
 | 
			
		||||
function create_game(string $name, string $owner, string $description = "", array $properties = DEFAULT_GAME_PROPERTIES, array $contributors = [], array $challenges = []): bool
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    global $gamedb;
 | 
			
		||||
    $game_data = [
 | 
			
		||||
        "name" => $name,
 | 
			
		||||
        "owner" => $owner,
 | 
			
		||||
@ -23,7 +23,7 @@ function create_game(string $name, string $owner, string $description = "", arra
 | 
			
		||||
        "properties" => $properties,
 | 
			
		||||
        "groups" => [],
 | 
			
		||||
    ];
 | 
			
		||||
    $game_data = $testdb->insert($game_data);
 | 
			
		||||
    $game_data = $gamedb->insert($game_data);
 | 
			
		||||
 | 
			
		||||
    // prepare game context
 | 
			
		||||
    $id = $game_data["_id"];
 | 
			
		||||
@ -35,25 +35,25 @@ function create_game(string $name, string $owner, string $description = "", arra
 | 
			
		||||
 | 
			
		||||
function get_game(string $gameid): array
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    return $testdb->findById($gameid);
 | 
			
		||||
    global $gamedb;
 | 
			
		||||
    return $gamedb->findById($gameid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function update_game(array $game_data)
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    $testdb->update($game_data);
 | 
			
		||||
    global $gamedb;
 | 
			
		||||
    $gamedb->update($game_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function delete_game(string $gameid)
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    global $gamedb;
 | 
			
		||||
    $game_data = get_game($gameid);
 | 
			
		||||
    if (count($game_data) != 0) {
 | 
			
		||||
        foreach ($game_data["groups"] as $groupid) {
 | 
			
		||||
            change_group_game_assignments($groupid, null, $gameid);
 | 
			
		||||
        }
 | 
			
		||||
        $testdb->deleteById($gameid);
 | 
			
		||||
        $gamedb->deleteById($gameid);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -68,18 +68,18 @@ function change_game_group_assignments(string $gid, $groupname_add, $groupname_r
 | 
			
		||||
 | 
			
		||||
function get_all_games()
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    return $testdb->findAll();
 | 
			
		||||
    global $gamedb;
 | 
			
		||||
    return $gamedb->findAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function get_all_game_data_by_contributor_nickname(string $nickname): array
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    global $gamedb;
 | 
			
		||||
    $game_headers = [];
 | 
			
		||||
    if ($nickname !== "*") {
 | 
			
		||||
        $game_data_array = $testdb->findBy([["owner", "=", $nickname], "OR", ["contributors", "CONTAINS", $nickname]]);
 | 
			
		||||
        $game_data_array = $gamedb->findBy([["owner", "=", $nickname], "OR", ["contributors", "CONTAINS", $nickname]]);
 | 
			
		||||
    } else {
 | 
			
		||||
        $game_data_array = $testdb->findAll();
 | 
			
		||||
        $game_data_array = $gamedb->findAll();
 | 
			
		||||
    }
 | 
			
		||||
    foreach ($game_data_array as $game_data) {
 | 
			
		||||
        $game_headers[] = $game_data;
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@ require_once "common_func.php";
 | 
			
		||||
require_once "usermgr.php";
 | 
			
		||||
require_once "groupmgr.php";
 | 
			
		||||
require_once "gamemgr.php";
 | 
			
		||||
require_once "testmgr.php";
 | 
			
		||||
 | 
			
		||||
$action = $_REQUEST["action"];
 | 
			
		||||
 | 
			
		||||
@ -83,6 +84,61 @@ switch ($action) {
 | 
			
		||||
            $result = json_encode($games_by_groups);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case "start_or_continue_test":
 | 
			
		||||
        {
 | 
			
		||||
            $gameid = trim($_REQUEST["gameid"] ?: "");
 | 
			
		||||
            $testid = create_or_continue_test($gameid, $nickname);
 | 
			
		||||
            $result = $testid;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_results_overview":
 | 
			
		||||
        {
 | 
			
		||||
            $gameid = trim($_REQUEST["gameid"] ?: "");
 | 
			
		||||
            $concluded_tests = get_concluded_tests($gameid, $nickname);
 | 
			
		||||
            $overviews = [];
 | 
			
		||||
            foreach ($concluded_tests as $ct) {
 | 
			
		||||
                $overview = [
 | 
			
		||||
                    "testid" => $ct["_id"],
 | 
			
		||||
                    "start_time" => $ct["start_time"],
 | 
			
		||||
                    "end_time" => $ct["end_time"],
 | 
			
		||||
                    ...$ct["summary"]
 | 
			
		||||
                ];
 | 
			
		||||
                $overviews[] = $overview;
 | 
			
		||||
            }
 | 
			
		||||
            $result = json_encode($overviews);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// test-related queries
 | 
			
		||||
if ((($testid = trim($_REQUEST["testid"] ?: "")) !== "") &&
 | 
			
		||||
    ((count($test_data = get_test($testid))) > 0) &&
 | 
			
		||||
    ($test_data["nickname"] === $nickname)) {
 | 
			
		||||
 | 
			
		||||
    // update the test if timed
 | 
			
		||||
    update_timed_tests([ $test_data ]);
 | 
			
		||||
 | 
			
		||||
    switch ($action) {
 | 
			
		||||
        case "get_test":
 | 
			
		||||
            {
 | 
			
		||||
                $test_data_with_current_time = $test_data;
 | 
			
		||||
                $test_data_with_current_time["current_time"] = time();
 | 
			
		||||
                $result = json_encode($test_data_with_current_time);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case "save_answer":
 | 
			
		||||
            {
 | 
			
		||||
                $chidx = $_REQUEST["challenge_index"];
 | 
			
		||||
                $answeridx = $_REQUEST["answer_index"];
 | 
			
		||||
                save_answer($testid, $chidx, $answeridx);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case "submit_test":
 | 
			
		||||
            {
 | 
			
		||||
                conclude_test($testid);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// creator or quizmaster actions
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								js/common.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								js/common.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
function unix_time_to_human_readable(tunix) {
 | 
			
		||||
    const date = new Date(Number(tunix) * 1000);
 | 
			
		||||
    return date.getFullYear() + ". " + String(date.getMonth() + 1).padStart(2, "0") + ". " + String(date.getDate()).padStart(2, "0") + ". "
 | 
			
		||||
        + String(date.getHours()).padStart(2, "0") + ":" + String(date.getMinutes()).padStart(2, "0") + ":" + String(date.getSeconds()).padStart(2, "0");
 | 
			
		||||
}
 | 
			
		||||
@ -9,21 +9,103 @@ function list_available_games() {
 | 
			
		||||
        games_by_groups.forEach((game_collection) => {
 | 
			
		||||
            let group_box = document.createElement("section");
 | 
			
		||||
            group_box.classList.add("group-box");
 | 
			
		||||
            let group_box_caption_container = document.createElement("span");
 | 
			
		||||
            group_box_caption_container.classList.add("group-box-caption-container");
 | 
			
		||||
            let group_box_caption = document.createElement("span");
 | 
			
		||||
            group_box_caption.classList.add("group-box-caption");
 | 
			
		||||
            group_box_caption.innerHTML = game_collection["groupname"];
 | 
			
		||||
            group_box_caption_container.append(group_box_caption);
 | 
			
		||||
            let group_box_inner = document.createElement("section");
 | 
			
		||||
            group_box_inner.classList.add("group-box-inner");
 | 
			
		||||
            group_box.append(group_box_caption, group_box_inner);
 | 
			
		||||
            group_box.append(group_box_caption_container, group_box_inner);
 | 
			
		||||
 | 
			
		||||
            game_collection["games"].forEach((game) => {
 | 
			
		||||
               let game_box = document.createElement("section");
 | 
			
		||||
               game_box.classList.add("game-box");
 | 
			
		||||
               game_box.innerHTML = game["name"];
 | 
			
		||||
               group_box_inner.appendChild(game_box);
 | 
			
		||||
                let game_box = document.createElement("section");
 | 
			
		||||
                game_box.classList.add("game-box");
 | 
			
		||||
                game_box.addEventListener("click", () => {
 | 
			
		||||
                    start_or_continue_test(game["_id"]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                let game_box_caption = document.createElement("section");
 | 
			
		||||
                game_box_caption.classList.add("game-box-caption");
 | 
			
		||||
                game_box_caption.innerHTML = game["name"];
 | 
			
		||||
 | 
			
		||||
                let list_results_btn = document.createElement("section");
 | 
			
		||||
                list_results_btn.classList.add("list-results-btn", "material", "btn");
 | 
			
		||||
                list_results_btn.addEventListener("click", (event) => {
 | 
			
		||||
                    event.stopPropagation();
 | 
			
		||||
                    list_corresponding_results(game["_id"]);
 | 
			
		||||
                });
 | 
			
		||||
                list_results_btn.innerHTML = "";
 | 
			
		||||
 | 
			
		||||
                game_box.append(game_box_caption, list_results_btn);
 | 
			
		||||
 | 
			
		||||
                group_box_inner.append(game_box);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            game_list_panel.appendChild(group_box);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function start_or_continue_test(gameid) {
 | 
			
		||||
    let req = {
 | 
			
		||||
        action: "start_or_continue_test",
 | 
			
		||||
        gameid: gameid
 | 
			
		||||
    }
 | 
			
		||||
    request(req).then(resp => {
 | 
			
		||||
        if (resp.length > 0) // response is non-zero
 | 
			
		||||
        {
 | 
			
		||||
            open_test(resp);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function open_test(testid) {
 | 
			
		||||
    window.open("testground.php?testid=" + testid, "_new");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function list_corresponding_results(gameid) {
 | 
			
		||||
    let results_overview_display = document.getElementById("results_overview_display");
 | 
			
		||||
    results_overview_display.innerHTML = "";
 | 
			
		||||
 | 
			
		||||
    let req = {
 | 
			
		||||
        action: "get_results_overview",
 | 
			
		||||
        gameid: gameid
 | 
			
		||||
    };
 | 
			
		||||
    request(req).then(resp => {
 | 
			
		||||
        let results = JSON.parse(resp);
 | 
			
		||||
        let n = results.length;
 | 
			
		||||
        if (n === 0) { // don't continue with processing an empty array
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        results.sort((a,b) => {return Number(b["testid"]) - Number(a["testid"])}); // sort records by ID
 | 
			
		||||
        results.forEach((record) => {
 | 
			
		||||
           let test_summary_record = document.createElement("section");
 | 
			
		||||
           test_summary_record.classList.add("test-summary-record");
 | 
			
		||||
           test_summary_record.addEventListener("click", () => {
 | 
			
		||||
              open_test(record["testid"]);
 | 
			
		||||
           });
 | 
			
		||||
 | 
			
		||||
           let sequence_number_sec = document.createElement("section");
 | 
			
		||||
           sequence_number_sec.classList.add("summary-sequence-number");
 | 
			
		||||
           sequence_number_sec.innerText = "#" + n;
 | 
			
		||||
           let duration_sec = document.createElement("section");
 | 
			
		||||
           duration_sec.classList.add("summary-duration");
 | 
			
		||||
           let start_time = unix_time_to_human_readable(record["start_time"]);
 | 
			
		||||
           let end_time = unix_time_to_human_readable(record["end_time"]);
 | 
			
		||||
           duration_sec.innerHTML = `${start_time}-<br>${end_time}<br>${record["correct_answer_n"]}/${record["challenge_n"]}`;
 | 
			
		||||
 | 
			
		||||
           let percentage = document.createElement("section");
 | 
			
		||||
           percentage.classList.add("summary-percentage");
 | 
			
		||||
           let r = Math.floor((record["correct_answer_n"] / record["challenge_n"]) * 100);
 | 
			
		||||
           percentage.innerHTML = `${r}%`;
 | 
			
		||||
 | 
			
		||||
           test_summary_record.append(sequence_number_sec, duration_sec, percentage);
 | 
			
		||||
           results_overview_display.appendChild(test_summary_record);
 | 
			
		||||
 | 
			
		||||
           n--;
 | 
			
		||||
        });
 | 
			
		||||
        show("results_window")
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								js/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								js/main.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
function logout() {
 | 
			
		||||
    let req = {
 | 
			
		||||
        action: "logout"
 | 
			
		||||
    };
 | 
			
		||||
    request(req).then(resp => {
 | 
			
		||||
        location.href = "login.php";
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										176
									
								
								js/testground.js
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								js/testground.js
									
									
									
									
									
								
							@ -1,30 +1,164 @@
 | 
			
		||||
function populate_test(test_id) {
 | 
			
		||||
    let test_display = document.getElementById("test_display");
 | 
			
		||||
let TEST_DATA = {}
 | 
			
		||||
let INTERVAL_HANDLE = null;
 | 
			
		||||
 | 
			
		||||
function print_time_left(t) {
 | 
			
		||||
    let timerS = document.getElementById("timer");
 | 
			
		||||
    let hours = Math.floor(t / 3600);
 | 
			
		||||
    t -= hours * 3600;
 | 
			
		||||
    let minutes = Math.floor(t / 60);
 | 
			
		||||
    t -= minutes * 60;
 | 
			
		||||
    let seconds = t;
 | 
			
		||||
    timerS.innerHTML = String(hours).padStart(2, "0") + ":"
 | 
			
		||||
        + String(minutes).padStart(2, "0") + ":"
 | 
			
		||||
        + String(seconds).padStart(2, "0");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function populate_infobox(test_data) {
 | 
			
		||||
    if (INTERVAL_HANDLE !== null) {
 | 
			
		||||
        clearInterval(INTERVAL_HANDLE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let test_concluded = TEST_DATA["state"] === "concluded";
 | 
			
		||||
 | 
			
		||||
    let game_nameS = document.getElementById("game_name");
 | 
			
		||||
    let durationS = document.getElementById("duration");
 | 
			
		||||
    let percentageS = document.getElementById("percentage");
 | 
			
		||||
 | 
			
		||||
    game_nameS.innerHTML = test_data["gamename"];
 | 
			
		||||
 | 
			
		||||
    if (test_concluded) {
 | 
			
		||||
        let summary = test_data["summary"];
 | 
			
		||||
        let correct_answer_n = summary["correct_answer_n"];
 | 
			
		||||
        let challenge_n = summary["challenge_n"];
 | 
			
		||||
        let r = Math.ceil((correct_answer_n / challenge_n) * 100);
 | 
			
		||||
        percentageS.innerHTML = `${r}% (${correct_answer_n}/${challenge_n})`;
 | 
			
		||||
 | 
			
		||||
        let start_time = unix_time_to_human_readable(test_data["start_time"]);
 | 
			
		||||
        let end_time = unix_time_to_human_readable(test_data["end_time"]);
 | 
			
		||||
        durationS.value = `${start_time} - ${end_time}`;
 | 
			
		||||
 | 
			
		||||
        hide("ongoing-info");
 | 
			
		||||
        show("concluded-info");
 | 
			
		||||
    } else {
 | 
			
		||||
        if (test_data["time_limited"]) {
 | 
			
		||||
            let time_left_s = Number(test_data["end_limit_time"]) - Number(test_data["current_time"]);
 | 
			
		||||
            print_time_left(time_left_s);
 | 
			
		||||
            INTERVAL_HANDLE = setInterval(() => {
 | 
			
		||||
                time_left_s--;
 | 
			
		||||
                print_time_left(time_left_s);
 | 
			
		||||
                if (time_left_s <= 0) {
 | 
			
		||||
                    populate_all(test_data["_id"]);
 | 
			
		||||
                    clearInterval(INTERVAL_HANDLE);
 | 
			
		||||
                    INTERVAL_HANDLE = null;
 | 
			
		||||
                }
 | 
			
		||||
            }, 1000);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        show("ongoing-info");
 | 
			
		||||
        hide("concluded-info");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function populate_challenges(test_data) {
 | 
			
		||||
    let test_display = document.getElementById("test_display");
 | 
			
		||||
    test_display.innerHTML = "";
 | 
			
		||||
 | 
			
		||||
    let test_concluded = TEST_DATA["state"] === "concluded";
 | 
			
		||||
 | 
			
		||||
    let challenge_N = 0;
 | 
			
		||||
    test_data["challenges"].forEach((challenge) => {
 | 
			
		||||
        let challenge_N_snapshot = challenge_N;
 | 
			
		||||
        let challenge_box = document.createElement("section");
 | 
			
		||||
        challenge_box.classList.add("challenge");
 | 
			
		||||
        let question = document.createElement("span");
 | 
			
		||||
        question.classList.add("question");
 | 
			
		||||
        question.innerHTML = preprocess_inserts(challenge["question"]);
 | 
			
		||||
        let answer_container = document.createElement("section");
 | 
			
		||||
        answer_container.classList.add("answer-container");
 | 
			
		||||
        challenge_box.append(question, answer_container);
 | 
			
		||||
 | 
			
		||||
        let answer_N = 0;
 | 
			
		||||
        let player_answer = challenge["player_answer"];
 | 
			
		||||
        player_answer = (player_answer !== "") ? Number(player_answer) : -1;
 | 
			
		||||
        challenge["answers"].forEach((answer) => {
 | 
			
		||||
            let answer_section = document.createElement("section");
 | 
			
		||||
            answer_section.classList.add("answer");
 | 
			
		||||
            let answer_radio = document.createElement("input");
 | 
			
		||||
            answer_radio.type = "radio";
 | 
			
		||||
            answer_radio.id = `${challenge_N}_${answer_N}`;
 | 
			
		||||
            answer_radio.name = `challenge_${challenge_N}`;
 | 
			
		||||
            answer_radio.disabled = test_concluded;
 | 
			
		||||
            let answer_N_snapshot = answer_N;
 | 
			
		||||
            answer_radio.addEventListener("input", () => {
 | 
			
		||||
                save_answer(challenge_N_snapshot, answer_N_snapshot);
 | 
			
		||||
            });
 | 
			
		||||
            if (player_answer === answer_N) {
 | 
			
		||||
                answer_radio.checked = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let answer_text = document.createElement("label");
 | 
			
		||||
            answer_text.innerHTML = preprocess_inserts(answer);
 | 
			
		||||
            answer_text.setAttribute("for", answer_radio.id);
 | 
			
		||||
            if (test_concluded && (challenge["correct_answer"] === answer_N)) {
 | 
			
		||||
                answer_text.classList.add("correct-answer")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            answer_section.append(answer_radio, answer_text);
 | 
			
		||||
            answer_container.appendChild(answer_section);
 | 
			
		||||
 | 
			
		||||
            answer_N++;
 | 
			
		||||
        });
 | 
			
		||||
        challenge_N++;
 | 
			
		||||
 | 
			
		||||
        test_display.appendChild(challenge_box);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    MathJax.typeset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function populate_all(test_id) {
 | 
			
		||||
    let req = {
 | 
			
		||||
        action: "get_test",
 | 
			
		||||
        id: test_id
 | 
			
		||||
        testid: test_id
 | 
			
		||||
    }
 | 
			
		||||
    request(req).then(resp => {
 | 
			
		||||
        let test_data = JSON.parse(resp);
 | 
			
		||||
        test_data["challenges"].forEach((challenge) => {
 | 
			
		||||
            let challenge_box = document.createElement("section");
 | 
			
		||||
            challenge_box.classList.add("challenge");
 | 
			
		||||
            let question = document.createElement("span");
 | 
			
		||||
            question.classList.add("question");
 | 
			
		||||
            question.innerHTML = challenge["question"];
 | 
			
		||||
            let answer_container = document.createElement("section");
 | 
			
		||||
            answer_container.classList.add("answer-container");
 | 
			
		||||
            challenge_box.append(question, answer_container);
 | 
			
		||||
        TEST_DATA = JSON.parse(resp);
 | 
			
		||||
        populate_challenges(TEST_DATA);
 | 
			
		||||
        populate_infobox(TEST_DATA);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            challenge["answers"].forEach((answer) => {
 | 
			
		||||
                let answer_section = document.createElement("section");
 | 
			
		||||
                answer_section.classList.add("answer");
 | 
			
		||||
                answer_section.innerHTML = answer;
 | 
			
		||||
                answer_container.appendChild(answer_section);
 | 
			
		||||
            });
 | 
			
		||||
function save_answer(chidx, aidx) {
 | 
			
		||||
    let req = {
 | 
			
		||||
        action: "save_answer",
 | 
			
		||||
        testid: TEST_DATA["_id"],
 | 
			
		||||
        challenge_index: chidx,
 | 
			
		||||
        answer_index: aidx,
 | 
			
		||||
    };
 | 
			
		||||
    request(req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            test_display.appendChild(challenge_box);
 | 
			
		||||
        });
 | 
			
		||||
function preprocess_inserts(str) {
 | 
			
		||||
    let code_delim = '`';
 | 
			
		||||
    let parts = str.split(code_delim);
 | 
			
		||||
    let res = "";
 | 
			
		||||
    for (let i = 0; i < parts.length; i++) {
 | 
			
		||||
        res += parts[i];
 | 
			
		||||
        if (i % 2 === 0) {
 | 
			
		||||
            res += "<code>";
 | 
			
		||||
        } else {
 | 
			
		||||
            res += "</code>";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function submit_test() {
 | 
			
		||||
    let req = {
 | 
			
		||||
        action: "submit_test",
 | 
			
		||||
        testid: TEST_DATA["_id"]
 | 
			
		||||
    }
 | 
			
		||||
    request(req).then(resp => {
 | 
			
		||||
        populate_all(TEST_DATA["_id"]);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								main.php
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								main.php
									
									
									
									
									
								
							@ -22,6 +22,7 @@ $privilege = $user_data["privilege"];
 | 
			
		||||
        <meta charset="UTF-8">
 | 
			
		||||
        <title>SpreadQuiz</title>
 | 
			
		||||
        <script src="js/req.js"></script>
 | 
			
		||||
        <script src="js/main.js"></script>
 | 
			
		||||
        <script src="js/spreadquiz.js"></script>
 | 
			
		||||
        <link rel="stylesheet" href="style/spreadquiz.css"/>
 | 
			
		||||
    </head>
 | 
			
		||||
@ -31,7 +32,13 @@ $privilege = $user_data["privilege"];
 | 
			
		||||
            <iframe id="content_frame" src="default_frame.php"></iframe>
 | 
			
		||||
        </section>
 | 
			
		||||
        <section id="info_pane">
 | 
			
		||||
            <section id="user_info" class="info-pane-element"><?= $user_data["nickname"]; ?></section>
 | 
			
		||||
            <section id="user_info" class="info-pane-element">
 | 
			
		||||
                <?= $user_data["nickname"]; ?>
 | 
			
		||||
                <section style="margin-top: 1em">
 | 
			
		||||
                    <input type="button" value="Beállítások"><br>
 | 
			
		||||
                    <input type="button" value="Kijelentkezés" onclick="logout()">
 | 
			
		||||
                </section>
 | 
			
		||||
            </section>
 | 
			
		||||
            <?php if ($privilege != PRIVILEGE_PLAYER) { ?>
 | 
			
		||||
                <section id="action_panel" class="info-pane-element">
 | 
			
		||||
                    <?php if (($privilege === PRIVILEGE_CREATOR) || ($privilege === PRIVILEGE_QUIZMASTER)) { ?>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										45
									
								
								style/quizmaster_area.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								style/quizmaster_area.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
section#table_section {
 | 
			
		||||
    position: sticky;
 | 
			
		||||
    height: calc(100vh - 4em);
 | 
			
		||||
    overflow-y: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    border-collapse: collapse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management thead th {
 | 
			
		||||
    padding: 0.5em 0;
 | 
			
		||||
    position: sticky;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    background-color: darkgray;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management tbody td {
 | 
			
		||||
    border: 1pt lightgrey solid;
 | 
			
		||||
    padding: 0.3em 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management tbody tr[highlight="true"] {
 | 
			
		||||
    background-color: antiquewhite;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management tbody tr[highlight="false"] td input {
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#user_manager_action_bar {
 | 
			
		||||
    margin-top: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td.checkbox {
 | 
			
		||||
    width: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hintbox-window {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    display: block;
 | 
			
		||||
    width: 15em;
 | 
			
		||||
    height: 8em;
 | 
			
		||||
}
 | 
			
		||||
@ -1,3 +1,10 @@
 | 
			
		||||
@import url('https://fonts.googleapis.com/css2?family=Autour+One&family=Kanit:wght@500&display=swap');
 | 
			
		||||
@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0");
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
    font-family: 'Autour One', sans-serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
*[shown="false"] {
 | 
			
		||||
    visibility: hidden;
 | 
			
		||||
    display: none;
 | 
			
		||||
@ -10,6 +17,10 @@
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.material {
 | 
			
		||||
    font-family: 'Material Symbols Outlined', sans-serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------- */
 | 
			
		||||
 | 
			
		||||
section#screen_panel {
 | 
			
		||||
@ -31,13 +42,15 @@ section#content_pane, section#info_pane {
 | 
			
		||||
section#content_pane {
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 80vw;
 | 
			
		||||
    background-color: lightcyan;
 | 
			
		||||
    /*background-color: lightcyan;*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#info_pane {
 | 
			
		||||
    right: 0;
 | 
			
		||||
    width: 20vw;
 | 
			
		||||
    background-color: beige;
 | 
			
		||||
    background-color: whitesmoke;
 | 
			
		||||
    border-left: 5px solid #176767;
 | 
			
		||||
    box-shadow: -5px 0 #d3e5e5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-pane-element {
 | 
			
		||||
@ -50,9 +63,19 @@ section#info_pane {
 | 
			
		||||
section#user_info {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    background-color: aquamarine;
 | 
			
		||||
    background-color: #176767;
 | 
			
		||||
    color: whitesmoke;
 | 
			
		||||
    font-size: 18pt;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    height: 1.2em;
 | 
			
		||||
    overflow: clip;
 | 
			
		||||
    transition: 0.3s ease;
 | 
			
		||||
    border-bottom: 0 dashed whitesmoke;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#user_info:hover {
 | 
			
		||||
    height: 5em;
 | 
			
		||||
    border-width: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#action_panel {
 | 
			
		||||
@ -61,46 +84,11 @@ section#action_panel {
 | 
			
		||||
 | 
			
		||||
iframe#content_frame {
 | 
			
		||||
    display: block;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    width: calc(100% - 1em);
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    border: 0 transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#table_section {
 | 
			
		||||
    position: sticky;
 | 
			
		||||
    height: calc(100vh - 4em);
 | 
			
		||||
    overflow-y: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    border-collapse: collapse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management thead th {
 | 
			
		||||
    padding: 0.5em 0;
 | 
			
		||||
    position: sticky;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    background-color: darkgray;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management tbody td {
 | 
			
		||||
    border: 1pt lightgrey solid;
 | 
			
		||||
    padding: 0.3em 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management tbody tr[highlight="true"] {
 | 
			
		||||
    background-color: antiquewhite;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.management tbody tr[highlight="false"] td input {
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#user_manager_action_bar {
 | 
			
		||||
    margin-top: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.window {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    display: block;
 | 
			
		||||
@ -115,23 +103,12 @@ section.window {
 | 
			
		||||
section.window-inner {
 | 
			
		||||
    margin: 0 auto;
 | 
			
		||||
    display: block;
 | 
			
		||||
    border: 2pt solid darkslategray;
 | 
			
		||||
    border: 2pt solid #176767;
 | 
			
		||||
    background-color: whitesmoke;
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
    width: fit-content;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td.checkbox {
 | 
			
		||||
    width: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hintbox-window {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    display: block;
 | 
			
		||||
    width: 15em;
 | 
			
		||||
    height: 8em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----- */
 | 
			
		||||
 | 
			
		||||
section#game_list_panel {
 | 
			
		||||
@ -145,15 +122,30 @@ section.group-box {
 | 
			
		||||
    margin: 1em;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    background-color: beige;
 | 
			
		||||
    background-color: #f8fbfb;
 | 
			
		||||
    border: 0.5px solid #176767;
 | 
			
		||||
    /*border-radius:  0 0 0.2em 0.2em;*/
 | 
			
		||||
    box-shadow: 5px 5px #d3e5e5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.group-box-caption {
 | 
			
		||||
span.group-box-caption-container {
 | 
			
		||||
    display: block;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    background-color: #176767;
 | 
			
		||||
    box-shadow: 0 5px #d3e5e5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.group-box-caption {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    /*position: relative;*/
 | 
			
		||||
    /*top: -0.5em;*/
 | 
			
		||||
    color: #176767;
 | 
			
		||||
    background-color: #d3e5e5;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    font-size: 1.2em;
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
    background-color: chartreuse;
 | 
			
		||||
    margin-left: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.group-box-inner {
 | 
			
		||||
@ -164,13 +156,45 @@ section.group-box-inner {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.game-box {
 | 
			
		||||
    display: table-cell;
 | 
			
		||||
    width: 8em;
 | 
			
		||||
    height: 8em;
 | 
			
		||||
    border: 2pt dashed gray;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    width: 12em;
 | 
			
		||||
    height: 12em;
 | 
			
		||||
    border: 2pt solid #176767;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    margin-right: 1em;
 | 
			
		||||
    overflow: clip;
 | 
			
		||||
    box-shadow: 5px 5px #d3e5e5;
 | 
			
		||||
    transform: scale(100%) rotate(0);
 | 
			
		||||
    background-color: whitesmoke;
 | 
			
		||||
    transition: ease 0.3s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.game-box:hover {
 | 
			
		||||
    transform: scale(105%) rotate(3deg);
 | 
			
		||||
    z-index: 1000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.game-box-caption {
 | 
			
		||||
    margin-top: 2em;
 | 
			
		||||
    font-size: 1.3em;
 | 
			
		||||
    rotate: -10deg;
 | 
			
		||||
    background-color: #176767;
 | 
			
		||||
    width: 13em;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    left: -3em;
 | 
			
		||||
    padding: 0.6em;
 | 
			
		||||
    color: whitesmoke;
 | 
			
		||||
    box-shadow: 0 5px #d3e5e5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.list-results-btn {
 | 
			
		||||
    display: block;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    right: 0.2em;
 | 
			
		||||
    bottom: 0.2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#test_area {
 | 
			
		||||
@ -181,11 +205,20 @@ section#test_area {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.challenge {
 | 
			
		||||
 | 
			
		||||
    display: block;
 | 
			
		||||
    margin: 0 auto;
 | 
			
		||||
    width: 40em;
 | 
			
		||||
    /*border: 1px solid black;*/
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
    background-color: #d3e5e5;
 | 
			
		||||
    margin-bottom: 0.5em;
 | 
			
		||||
    border-radius: 0.3em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.question {
 | 
			
		||||
 | 
			
		||||
    font-size: 1.3em;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    color: #176767;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.answer-container {
 | 
			
		||||
@ -193,5 +226,112 @@ section.answer-container {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.answer {
 | 
			
		||||
    margin: 0.3em 0.8em;
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.answer label {
 | 
			
		||||
    margin-left: 0.5em;
 | 
			
		||||
    padding: 0.3em 0.5em;
 | 
			
		||||
    border-radius: 0.3em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.answer label.correct-answer {
 | 
			
		||||
    border: 2px solid #176767 !important;
 | 
			
		||||
    padding: 0.1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.answer input[type="radio"]:checked+label:not(.correct-answer) {
 | 
			
		||||
    background-color: #176767;
 | 
			
		||||
    color: whitesmoke;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#infobox {
 | 
			
		||||
    display: block;
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    margin: 1em;
 | 
			
		||||
    /*padding: 1em;*/
 | 
			
		||||
    background: #f8fbfb;
 | 
			
		||||
    border: 0.5px solid #176767;
 | 
			
		||||
    min-width: 15em;
 | 
			
		||||
    min-height: 5em;
 | 
			
		||||
    box-shadow: 5px 5px #d3e5e5;
 | 
			
		||||
    overflow: clip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#infobox > section {
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span#game_name {
 | 
			
		||||
    display: block;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
    background-color: #176767;
 | 
			
		||||
    box-shadow: 0px 5px #d3e5e5;
 | 
			
		||||
    color: whitesmoke;
 | 
			
		||||
    font-size: 1.2em;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#timer {
 | 
			
		||||
    color: #176767;
 | 
			
		||||
    margin-bottom: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section#percentage {
 | 
			
		||||
    color: #176767;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.infobox-description {
 | 
			
		||||
    font-size: 0.8em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.btn {
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
    padding: 0.3em;
 | 
			
		||||
    border-radius: 0.2em;
 | 
			
		||||
    font-size: 1.3em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.btn:hover {
 | 
			
		||||
    background-color: rgba(128, 128, 128, 0.30);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section.test-summary-record {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    border: 0.5px solid #176767;
 | 
			
		||||
    margin-bottom: 0.3em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.summary-sequence-number {
 | 
			
		||||
    font-size: 2em;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    background-color: #176767;
 | 
			
		||||
    color: whitesmoke;
 | 
			
		||||
    padding: 0.5em;
 | 
			
		||||
    width: 1.5em;
 | 
			
		||||
    box-shadow: 5px 0 #d3e5e5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.summary-duration {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    margin-left: 1em;
 | 
			
		||||
    color: #176767;
 | 
			
		||||
    font-size: 0.7em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.summary-percentage {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    margin-left: 1em;
 | 
			
		||||
    background-color: #176767;
 | 
			
		||||
    padding: 0 1em;
 | 
			
		||||
    box-shadow: -5px 0 #d3e5e5;
 | 
			
		||||
    color: whitesmoke;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
@ -8,7 +8,10 @@ if (!get_autologin_state() || !isset($_REQUEST["testid"])) {
 | 
			
		||||
    exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$testid = $_REQUEST["testid"];
 | 
			
		||||
$testid = trim($_REQUEST["testid"] ?: "");
 | 
			
		||||
if ($testid === "") {
 | 
			
		||||
    exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
?>
 | 
			
		||||
 | 
			
		||||
@ -17,15 +20,35 @@ $testid = $_REQUEST["testid"];
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <title>SpreadQuiz</title>
 | 
			
		||||
    <script src="js/spreadquiz.js"></script>
 | 
			
		||||
    <script src="js/req.js"></script>
 | 
			
		||||
    <script src="js/spreadquiz.js"></script>
 | 
			
		||||
    <script src="js/o.js"></script>
 | 
			
		||||
    <script src="js/common.js"></script>
 | 
			
		||||
    <script src="js/testground.js"></script>
 | 
			
		||||
    <link rel="stylesheet" href="style/spreadquiz.css">
 | 
			
		||||
    <script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <section id="test_display">
 | 
			
		||||
<section id="test_display">
 | 
			
		||||
 | 
			
		||||
</section>
 | 
			
		||||
<section id="infobox">
 | 
			
		||||
    <span id="game_name"></span>
 | 
			
		||||
    <section>
 | 
			
		||||
        <section id="ongoing-info">
 | 
			
		||||
            <span class="infobox-description">Hátralevő idő:</span>
 | 
			
		||||
            <section id="timer">10:00:00</section>
 | 
			
		||||
            <input type="button" value="Beküld" onclick="submit_test()">
 | 
			
		||||
        </section>
 | 
			
		||||
        <section id="concluded-info">
 | 
			
		||||
            <section id="duration"></section>
 | 
			
		||||
            <span class="infobox-description">Eredmény:</span>
 | 
			
		||||
            <section id="percentage">95% (19/20)</section>
 | 
			
		||||
        </section>
 | 
			
		||||
    </section>
 | 
			
		||||
</section>
 | 
			
		||||
<script>
 | 
			
		||||
    populate_all("<?=$testid ?>");
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										103
									
								
								testmgr.php
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								testmgr.php
									
									
									
									
									
								
							@ -29,7 +29,7 @@ function create_or_continue_test(string $gameid, string $nickname): string
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // check if the user had taken this test before
 | 
			
		||||
    $fetch_criteria = [["gameid", "=", $gameid], "AND", ["nickname", "=", $nickname]];
 | 
			
		||||
    $fetch_criteria = [["gameid", "=", (int)$gameid], "AND", ["nickname", "=", $nickname]];
 | 
			
		||||
    $previous_tests = $testdb->findBy($fetch_criteria);
 | 
			
		||||
    if (count($previous_tests) > 0) { // if there are previous attempts, then...
 | 
			
		||||
        // update timed tests to see if they had expired
 | 
			
		||||
@ -53,12 +53,15 @@ function create_or_continue_test(string $gameid, string $nickname): string
 | 
			
		||||
 | 
			
		||||
function create_test(array $game_data, array $user_data) : string
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    $gameid = $game_data["_id"];
 | 
			
		||||
    $game_properties = $game_data["properties"];
 | 
			
		||||
 | 
			
		||||
    // fill basic data
 | 
			
		||||
    $game_data = [
 | 
			
		||||
    $test_data = [
 | 
			
		||||
        "gameid" => $gameid,
 | 
			
		||||
        "nickname" => $user_data["nickname"],
 | 
			
		||||
        "gamename" => $game_data["name"]
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // fill challenges
 | 
			
		||||
@ -67,11 +70,33 @@ function create_test(array $game_data, array $user_data) : string
 | 
			
		||||
    // shuffle answers
 | 
			
		||||
    foreach ($challenges as &$ch) {
 | 
			
		||||
        shuffle($ch["answers"]);
 | 
			
		||||
        $ch["correct_answer"] = "";
 | 
			
		||||
        $ch["player_answer"] = "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $game_data["challenges"] = $challenges;
 | 
			
		||||
 | 
			
		||||
    // involve properties
 | 
			
		||||
    $now = time();
 | 
			
		||||
    $properties = [
 | 
			
		||||
        "state" => TEST_ONGOING,
 | 
			
		||||
        "time_limited" => (($game_properties["time_limit"] ?: -1) > -1),
 | 
			
		||||
        "start_time" => $now,
 | 
			
		||||
        "repeatable" => $game_properties["repeatable"] ?: false
 | 
			
		||||
    ];
 | 
			
		||||
    if ($properties["time_limited"]) {
 | 
			
		||||
        $properties["end_limit_time"] = $now + $game_properties["time_limit"];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // merge properties and test data
 | 
			
		||||
    $test_data = array_merge($test_data, $properties);
 | 
			
		||||
 | 
			
		||||
    // add challenges
 | 
			
		||||
    $test_data["challenges"] = $challenges;
 | 
			
		||||
 | 
			
		||||
    // store game
 | 
			
		||||
    $test_data = $testdb->insert($test_data);
 | 
			
		||||
 | 
			
		||||
    $testid = $test_data["_id"];
 | 
			
		||||
    return $testid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function update_timed_tests(array $test_data_array)
 | 
			
		||||
@ -79,9 +104,8 @@ function update_timed_tests(array $test_data_array)
 | 
			
		||||
    $now = time();
 | 
			
		||||
    foreach ($test_data_array as $test_data) {
 | 
			
		||||
        // look for unprocessed expired tests
 | 
			
		||||
        if (($test_data["state"] === TEST_ONGOING) && ($test_data["end_limit_time"] < $now)) {
 | 
			
		||||
            $test_data["state"] = TEST_CONCLUDED;
 | 
			
		||||
            update_test($test_data);
 | 
			
		||||
        if (($test_data["state"] === TEST_ONGOING) && ($test_data["time_limited"]) && ($test_data["end_limit_time"] < $now)) {
 | 
			
		||||
            conclude_test($test_data["_id"]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -90,4 +114,69 @@ function update_test(array $test_data)
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    $testdb->update($test_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function get_test(string $testid): array
 | 
			
		||||
{
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    return $testdb->findById($testid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function save_answer(string $testid, $chidx, $ansidx)
 | 
			
		||||
{
 | 
			
		||||
    $test_data = get_test($testid);
 | 
			
		||||
    $chidx = (int)$chidx;
 | 
			
		||||
    if ((count($test_data) > 0) && ($test_data["state"] === TEST_ONGOING)) {
 | 
			
		||||
        if ($chidx < count($test_data["challenges"])) {
 | 
			
		||||
            $test_data["challenges"][$chidx]["player_answer"] = $ansidx;
 | 
			
		||||
            update_test($test_data);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function get_concluded_tests(string $gameid, string $nickname) {
 | 
			
		||||
    global $testdb;
 | 
			
		||||
    $fetch_criteria = [["gameid", "=", (int)$gameid], "AND", ["nickname", "=", $nickname], "AND", ["state", "=", TEST_CONCLUDED]];
 | 
			
		||||
    $test_data_array = $testdb->findBy($fetch_criteria);
 | 
			
		||||
    return $test_data_array;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function conclude_test(string $testid) {
 | 
			
		||||
    $test_data = get_test($testid);
 | 
			
		||||
    if (count($test_data) === 0) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // load game data
 | 
			
		||||
    //$game_data = get_game($test_data["gameid"]);
 | 
			
		||||
    $game_challenges = load_challenges($test_data["gameid"]);
 | 
			
		||||
 | 
			
		||||
    // check the answers
 | 
			
		||||
    $challenge_n = count($test_data["challenges"]); // number of challenges
 | 
			
		||||
    $cans_n = 0; // number of correct answers
 | 
			
		||||
    for ($chidx = 0; $chidx < $challenge_n; $chidx++) {
 | 
			
		||||
        // get challenge
 | 
			
		||||
        $tch = &$test_data["challenges"][$chidx];
 | 
			
		||||
        $gch = $game_challenges[$chidx];
 | 
			
		||||
 | 
			
		||||
        // translate correct answer into an index by the shuffled answer order
 | 
			
		||||
        $cans_idx = array_search($gch["correct_answer"], $tch["answers"]);
 | 
			
		||||
        $tch["correct_answer"] = $cans_idx;
 | 
			
		||||
 | 
			
		||||
        // check the player's answer
 | 
			
		||||
        $player_answer = trim($tch["player_answer"]);
 | 
			
		||||
        if (($player_answer !== "") && ($cans_idx === (int)$player_answer)) {
 | 
			
		||||
            $cans_n++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // set state and fill summary
 | 
			
		||||
    $test_data["state"] = TEST_CONCLUDED;
 | 
			
		||||
    $test_data["end_time"] = time();
 | 
			
		||||
    $test_data["summary"] = [
 | 
			
		||||
        "challenge_n" => $challenge_n,
 | 
			
		||||
        "correct_answer_n" => $cans_n
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    update_test($test_data);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user