Time limit per question - implementation guide

Time limit per question - implementation guide

Dawid Bartkowiak -
Atsakymų skaičius: 34

I need to add time limit per question to the quiz activity. After searching this forum I can see that this is not easy to implement. Some people argue why would one need this option. The reason I need it is I am trying to make a platform where people can prepare for a real government exam which has this limit. 

I would like to write a plugin that adds this functionality.

  • should I copy the whole quiz module, add the functionality and install it as a new module?
  • can I add this functionality to the quiz module by writing a local plugin? 
  • should I take another approach?
I would appreciate if someone could guide me in the right direction as I am new to Moodle.

I am using moodle_37_stable.
Pažymių vidurkis: -
Atsakymas į Dawid Bartkowiak

Re: Time limit per question - implementation guide

Rick Jerz -
Particularly helpful Moodlers paveikslėlis Testers paveikslėlis
Does the government exam impose a time limit "per question" or "per exam?"

Tim Hunt is the person who probably knows the most about Moodle's quiz engine, and I am sure that he has seen others wanting a time-limit per question. Maybe he will see your question, jump in, and let you know about how difficult your need is to program.

You might want to search the Tracker system and see if this is already a feature request. Then, vote on it. If not, create a feature request yourself.
Atsakymas į Rick Jerz

Odp: Re: Time limit per question - implementation guide

Dawid Bartkowiak -
The government exam impose 3 time limits: "per question review", "per question answer" and "per exam".

I have good c#, javascript (node.js) and some php experience. It would be nice to hear from Mr. Tim Hunt. I can of course read all the code but any advice/pointing me in the right direction would make my life much easier.

A simple solution would be the best, maybe a javascript showing the timer on the page and changing the question to the next one when the time passed? Is this something we can simply add to the activity? 
Atsakymas į Dawid Bartkowiak

Re: Odp: Re: Time limit per question - implementation guide

Rick Jerz -
Particularly helpful Moodlers paveikslėlis Testers paveikslėlis
I am not a programmer, Dawid.

See MDL-33654 in Tracker. Vote. Or even contribute some of your code.
Atsakymas į Dawid Bartkowiak

Re: Odp: Re: Time limit per question - implementation guide

Daniel Thies -
Core developers paveikslėlis Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis Testers paveikslėlis

Dawid,

If they need to see feedback to review after each question, that sounds like you would be using the question behaviour Imediate feedback. I would look at configuring that first and seeing if it meets your other needs. You may be able to add timing changes there.

Atsakymas į Dawid Bartkowiak

Re: Time limit per question - implementation guide

Tim Hunt -
Core developers paveikslėlis Documentation writers paveikslėlis Particularly helpful Moodlers paveikslėlis Peer reviewers paveikslėlis Plugin developers paveikslėlis
Definitely don't copy the whole quiz module. That would be impossible to maintain.

The client-side of the implementation will involve JavaScript in the browser, and a local plugin, using the Output callbacks (https://docs.moodle.org/dev/Output_callbacks) will be able to inject the JavaScript into quiz pages.

That won't really be secure unless you also check the timings server-side, but there is not easy way to do that in a plugin. If Quiz access rule plugins were a bit more powerful, then it might be possible (https://docs.moodle.org/dev/Quiz_access_rules) to do the necessary server-side code in a plugin.

To understand what you are dealing with, you are going to have to look at mod/quiz/attempt.php, .../processattempt.php and .../attemptlib.php to understand how the quiz works. If you can read C# and JS then you can probably understand what PHP code is doing. These docs may help https://docs.moodle.org/dev/Quiz_user_interface_overview.

You have to realise that as well as being an application, Moodle is also its own framework, and you should expect it to take some time to understand how Moodle code works.
Atsakymas į Tim Hunt

Odp: Re: Time limit per question - implementation guide

Dawid Bartkowiak -
Thank you a lot for your answer. It helps a lot! The code is well written and commented so it is like reading a book uśmiech

My first thought after reading the docs was I should start with the YUI module for the JavaScript part. Is it better to use a local plugin with the output callbacks for injecting the js code?
In my case I don't worry about the cheating so much (if this is what you meant by security). People should use this course to prepare for the government exam. If they cheat they will make it worse for themself uśmiech
Atsakymas į Dawid Bartkowiak

Re: Odp: Re: Time limit per question - implementation guide

Dominique Bauer -
Documentation writers paveikslėlis Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis

Here↗ you'll find a simple client-side approach, consisting of Java scripts inserted directly into the questions, which could meet your needs.

Atsakymas į Dawid Bartkowiak

Re: Odp: Re: Time limit per question - implementation guide

Tim Hunt -
Core developers paveikslėlis Documentation writers paveikslėlis Particularly helpful Moodlers paveikslėlis Peer reviewers paveikslėlis Plugin developers paveikslėlis
Good point that this is only preparation, so security is not a big issue.

The world of JavaScript, (including JavaScript in Moodle) keeps changing. Don't use YUI any more. (I know that quiz contains a lot of UI that will one day need to be updated.) If possible, use AMD modules (https://docs.moodle.org/dev/Javascript_Modules).

Whatever method you use, you will need to inject the JS into the page. I think that a local plugin and the output callbacks is probably the cleanest way to achieve that, but I am not sure. The main think is to write the JavaScript and get it working. How you inject it is not important.
Atsakymas į Tim Hunt

Re: Odp: Re: Time limit per question - implementation guide

Dominique Bauer -
Documentation writers paveikslėlis Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis
If possible, use AMD modules...

I looked at https://docs.moodle.org/dev/Javascript_Modules. Hmm, I am not a software developer, I am a structural engineer, I build bridges and buildings. Therefore, at the moment , I do not understand the meaning of the following terms: AMD, API, ECMAScript, aka ES6, Babel JS, Grunt, cachejs, build tools, wrap processes, nodejs environnement, npm, node, module, minified Javascript, source map file, first.js, network request, lint feature, RequireJS, inline javascript, Mustache, built file, git commit, JSDoc, define name, pollute page size, pass css selectors for DOM elements that contain data-attributes for any required data or fetch data via ajax in the background...

I may be able to understand all these terms one day. But for the moment, I manage with the little that I learned recently on javascript. It's still better than waiting years for a given functionality to possibly be implemented. (Because of the lack of human resources, we are all overworked and sometimes tend to deal with details that take little time because we do not have time to tackle larger issues.) mėlynė

When I propose java scripts on this forum, I hope they have some value and that software developers do not consider them as garbage (well, at least, thank you for not saying it). mėlynė

besišypsantis

Atsakymas į Dominique Bauer

Re: Odp: Re: Time limit per question - implementation guide

Marcus Green -
Core developers paveikslėlis Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis Testers paveikslėlis
Atsakymas į Marcus Green

Re: Odp: Re: Time limit per question - implementation guide

Dominique Bauer -
Documentation writers paveikslėlis Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis

Marcus

I will take your post as kind words. Thank you very much for lightening the mood.

Atsakymas į Dominique Bauer

Odp: Re: Odp: Re: Time limit per question - implementation guide

Dawid Bartkowiak -
I don't think there is a software developer that knows every possible term and every language/technology/framework. Same with construction - you can't be good in everything.

The code you proposed is interesting but in my case I have too many questions to inject javascript into every single one and it would be difficult to get the functionality I want. When writing code you also want to separate data from script logic as much as possible. It would be good for a simple quiz. So I am going to use the AMD module or local plugin and the output callbacks as Tim suggested.

As long long as you get the functionality you want and it works for you then it is good uśmiech In the end it's not like building bridges - nobody will die if we make a small mistake here and there or the code is not super efficient :p
Atsakymas į Tim Hunt

Odp: Re: Odp: Re: Time limit per question - implementation guide

Dawid Bartkowiak -
Just a quick question. I started writing a local plugin. I can see the Output callbacks are meant to affect all the pages. Can I limit the JS injection just to mod_quiz pages with Output callbacks?
Atsakymas į Dawid Bartkowiak

Re: Odp: Re: Odp: Re: Time limit per question - implementation guide

Tim Hunt -
Core developers paveikslėlis Documentation writers paveikslėlis Particularly helpful Moodlers paveikslėlis Peer reviewers paveikslėlis Plugin developers paveikslėlis
You should be able to. The basic idea is:

global $PAGE;
if ($PAGE-> == 'mod-quiz-attempt') {

}
Atsakymas į Tim Hunt

Odp: Re: Odp: Re: Odp: Re: Time limit per question - implementation guide

Dawid Bartkowiak -
Perfect, thank you for your time. I think I need to read the Page API. I wish some paid services had this good support uśmiech
Atsakymas į Tim Hunt

Odp: Re: Odp: Re: Odp: Re: Time limit per question - implementation guide

Dawid Bartkowiak -
For anybody interested, this is how I injected JavaScript to quiz attempt page using a local plugin. I want to add the JS only to one quiz category so change the category name to one you want or remove this line. You can also use category->id. Change the xxx to your local plugin name. Content of the lib.php:

<?php
function local_xxx_before_footer() {
global $PAGE;
if ($PAGE->category->name == 'Your Category Name' && $PAGE->bodyid == 'page-mod-quiz-attempt'){
$PAGE->requires->js_init_code("alert('".$PAGE->bodyid."');");
}
Atsakymas į Tim Hunt

Re: Odp: Re: Time limit per question - implementation guide

shiva k -
Because Moodle is awesome and Javascript is awesome even for a non-programmer, I have implemented time limit for each question using front-end javascript ( I am a pure teacher who does not know spelling for program(me)). We do have exams called OSCE in medical and dental schools where time for each question does matter. My requirement was limiting time for each question and not to allow students to revisit the question after the time limit and force to next question once time limit is over.
I have used the following steps to achieve this:
  1. Create a quiz with sequential navigation method.
  2. Arrange page layout so that each question is in one page.
  3. If you want to restrict first question with say, 2 minutes (120s) time limit, add the following code (under question text>show/hide advanced button >HTML (<>)):
    <h4>The time allocated for this question is 2 minutes.</h4>
    <h3><span id="displayDiv " class="label label-danger"></span></h3>
<script>
    var timer;
    function countDown(i, callback) {
        //callback = callback || function(){};
        timer = setInterval(function() {
            minutes = parseInt(i / 60, 10);
            seconds = parseInt(i % 60, 10);
            minutes = minutes < 10 ? "0" + minutes : minutes;
            seconds = seconds < 10 ? "0" + seconds : seconds;
            document.getElementById("displayDiv ").innerHTML = "Time left " + minutes + " Min : " + seconds + " Sec ";

            i-- || (clearInterval(timer), callback());
        }, 1000);
    }

    window.onload = function() {
        countDown(120, function() {
            $('#myModal').modal('show');
        });
    };
</script>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title" id="myModalLabel"></h4>
            </div>
            <div class="modal-body">
                <h4>The time allocated for this question is over. Please go to the next page: </h4>
            </div>
            <div class="modal-footer">
                <input type="submit" name="next" value="Next page" class="mod_quiz-next-nav btn btn-primary">
            </div>
        </div>
        <!-- /.modal-content -->
    </div>
    <!-- /.modal-dialog -->
</div>
<!-- /.modal -->

Hope this helps for someone. 
Atsakymas į shiva k

Re: Odp: Re: Time limit per question - implementation guide

Luiggi Sansonetti -
Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis Testers paveikslėlis
Hi

Just tested but not a really good solution...

Student can be locked on the review attemp page...

During the quiz it's not bad, but time can be different between question time ans quiz time (because I spended time to close the modal...)


But for training why not.

And yes, we need this feature mirkt
Atsakymas į Luiggi Sansonetti

Re: Odp: Re: Time limit per question - implementation guide

shiva k -

Dear Luggi

Thanks for testing and getting me the feedback.

I have rectified and implemented following:

  1. Refreshing the page will not reset the counter. Using cookies timer will continue despite refresh or reloading page.
  2. Removed modal and automatically takes to next question.
  3. During review the counter does not show up.

Here is the amended code:

<h3>  <p style="text-align: right;"><b>Time left for the entire exam is </b><span id="quiz-time-left">0:00:00</span></p></h3>

<h2>  <p style="text-align: center;"><b>Question No: 1</b></p></h2>

<div style="text-align:center" class="sticky">    <h4>The time allocated for this question is 6 minutes. Please answer all questions.</h>

<h3><span id="displayDiv" class="label label-danger"></span></h3>

</div>

<script>

    const COUNTER_KEY = 'my-counter';

    function countDown(i, callback) {

        //callback = callback || function(){};

        timer = setInterval(function() {

            minutes = parseInt(i / 60, 10);

            seconds = parseInt(i % 60, 10);

            minutes = minutes < 10 ? "0" + minutes : minutes;

            seconds = seconds < 10 ? "0" + seconds : seconds;

            document.getElementById("displayDiv").innerHTML = "Time left for this question is  (h:min:sec)  " + "0:" + minutes + ":" + seconds;

            if ((i--) > 0) {

                window.sessionStorage.setItem(COUNTER_KEY, i);

            } else {

                window.sessionStorage.removeItem(COUNTER_KEY);

                clearInterval(timer);

                callback();

            }

        }, 1000);

    }

    if (document.location.href.indexOf('review') === -1) {

        window.onload = function() {

            var countDownTime = window.sessionStorage.getItem(COUNTER_KEY) || 360;

            countDown(countDownTime, function() {

                document.getElementsByClassName("mod_quiz-next-nav btn btn-primary")[0].click();

            });

        };

    }

</script>

Atsakymas į shiva k

Re: Odp: Re: Time limit per question - implementation guide

Luiggi Sansonetti -
Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis Testers paveikslėlis

Hi Shiva

Thanks for your feedback and new code

It's better for the review and refresh


But some mistakes again besišypsantis

  • there is no more the time in the navigation block
so we have to put the exam time in all question text

  • time by question is not only for THE question if we clic on next before end of time
when I'm doint the question 1 and if I clic on next before end of time, the time left is less for the question 2

I explain :
Test 2min
Q1 30s
Q2 30s
Q3 30s
Q4 30s

If I do the Q1 during 10s, the time for Q2 is 20s left and not 30s...

Screencast:


Atsakymas į Luiggi Sansonetti

Re: Odp: Re: Time limit per question - implementation guide

shiva k -
Dear Luiggi
Thanks again.
The reason why time left is not appearing on navigation panel because I have stolen: 0:00:00 The current code fill only in one place. So if we want timer on navigation panel, we need to remove this span id.

Regarding restarting time, I forgot to tell you the constant should be renamed for each page: const COUNTER_KEY1 = 'my-counter1'; and using with such numbered make sure each question have their unique timing.
with regards
Atsakymas į shiva k

Re: Odp: Re: Time limit per question - implementation guide

Luiggi Sansonetti -
Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis Testers paveikslėlis

The best would then be to increment a counter number based on the question_name or question_id

And then, with the templates for 4 plugin and the filter code filter plugin we can help the question timer creation

But it's not yet a success for me...




Also with {} it doesn't work

Maybe...

Atsakymas į Luiggi Sansonetti

Re: Odp: Re: Time limit per question - implementation guide

Luiggi Sansonetti -
Particularly helpful Moodlers paveikslėlis Plugin developers paveikslėlis Testers paveikslėlis
Sorry

atto_templates4u and filter_filtercodes
Atsakymas į Luiggi Sansonetti

Ri: Re: Odp: Re: Time limit per question - implementation guide

Emanuele Signoretta -

Dear Mr. Sansonetti,


I to use the code and it worked fine. When I tried to do a single counter per question using atto_templates and filter_filtercodes it stopped working. 


Here is the code. Can you please tell me where it is wrong? Thank you in advance

<center>

    <!--   <h3>  <p style="text-align: right;"><b>Time left for the entire exam is </b><span id="quiz-time-left">0:00:00</span></p></h3>


<h2>  <p style="text-align: center;"><b>Question No: 1</b></p></h2>

-->

    <div style="text-align:center" class="sticky">

        <h4>Il tempo dedicato a questa domanda è 30 secondi, cortesemente rispondi a tutte le domande.


        </h4>

        <h3><span id="displayDiv" class="label label-danger"></span></h3>


    </div>


    <script>

        <!-- const COUNTER_KEY%7Bquestion_id%7D = 'my-counter'; -->

        const COUNTER_KEY % 7 B {

            question_id

        } % 7 D = 'my-counter%7D{question_id}%7D';


        function countDown(i, callback) {


            //callback = callback || function(){};


            timer = setInterval(function() {


                minutes = parseInt(i / 60, 10);


                seconds = parseInt(i % 60, 10);


                minutes = minutes < 10 ? "0" + minutes : minutes;


                seconds = seconds < 10 ? "0" + seconds : seconds;


                document.getElementById("displayDiv").innerHTML = "Tempo rimasto: " + "0:" + minutes + ":" + seconds;


                if ((i--) > 0) {


                    window.sessionStorage.setItem(COUNTER_KEY % 7 B {

                        question_id

                    } % 7 D, i);


                } else {


                    window.sessionStorage.removeItem(COUNTER_KEY % 7 B {

                        question_id

                    } % 7 D);


                    clearInterval(timer);


                    callback();


                }


            }, 1000);


        }


        if (document.location.href.indexOf('review') === -1) {


            window.onload = function() {


                var countDownTime = window.sessionStorage.getItem(COUNTER_KEY % 7 B {

                    question_id

                } % 7 D) || 30; <!-- originalmente 360 Indica i secondi -->


                countDown(countDownTime, function() {


                    document.getElementsByClassName("mod_quiz-next-nav btn btn-primary")[0].click();


                });


            };


        }

    </script>

</center>



Atsakymas į shiva k

Re: Odp: Re: Time limit per question - implementation guide

Lasantha Adikaram -
Thank you.
This is working .........
Also I disable the "Next" button to disable the free navigation and implemented in a quiz with "Sequence" access and it will bock backward navigation as well.

if (document.location.href.indexOf('review') === -1) {
window.onload = function() {
var countDownTime = window.sessionStorage.getItem(COUNTER_KEY) || 15;
var button = document.getElementsByName("next")[0];
button.style.visibility = "hidden";
countDown(countDownTime, function() {
document.getElementsByClassName("mod_quiz-next-nav btn btn-primary")[0].click();
});
};
Atsakymas į shiva k

Re: Odp: Re: Time limit per question - implementation guide

Lukman Zhang -
Thank's for the code. I change a little for each answer duration (Const duration=20). And count down don't affect when we were in review page.

Alokasi waktu untuk soal ini adalah 20 detik

Atsakymas į shiva k

Re: Odp: Re: Time limit per question - implementation guide

Lukman Zhang -
I try this, but there is a problem. when the timer still count and i go to Next page, the timer display continous from the question before.
Atsakymas į shiva k

Re: Odp: Re: Time limit per question - implementation guide

aziz vefa -
Hi Shiva.
I see your code is working well. My need is like that:
I set the navigation method free and question behavior immediate feedback. Also, I locked the question between them. So a student can't proceed unless he/she answer the current question. Also, I want to keep the student for a time (e.g. 90sec) in each question, prevent the student click on the submit button until the allotted time finishes for the question.
How can we do that, please?
Thank you.