Time limit per question - implementation guide

Time limit per question - implementation guide

by Dawid Bartkowiak -
Number of replies: 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.
Average of ratings: -
In reply to Dawid Bartkowiak

Re: Time limit per question - implementation guide

by Rick Jerz -
Picture of Particularly helpful Moodlers Picture of Testers
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.
In reply to Rick Jerz

Odp: Re: Time limit per question - implementation guide

by 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? 
In reply to Dawid Bartkowiak

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

by Rick Jerz -
Picture of Particularly helpful Moodlers Picture of Testers
I am not a programmer, Dawid.

See MDL-33654 in Tracker. Vote. Or even contribute some of your code.
In reply to Dawid Bartkowiak

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

by Daniel Thies -
Picture of Core developers Picture of Plugin developers Picture of Testers

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.

In reply to Dawid Bartkowiak

Re: Time limit per question - implementation guide

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
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.
Average of ratings: Useful (1)
In reply to Tim Hunt

Odp: Re: Time limit per question - implementation guide

by 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
In reply to Dawid Bartkowiak

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

by Dominique Bauer -
Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Plugin developers

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

Average of ratings: Useful (3)
In reply to Dominique Bauer

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

by Dawid Bartkowiak -
Thank you, I will take a look at it.
In reply to Dawid Bartkowiak

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

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
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.
Average of ratings: Useful (2)
In reply to Tim Hunt

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

by Dominique Bauer -
Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Plugin developers
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.) black eye

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). black eye

smile

Average of ratings: Useful (1)
In reply to Dominique Bauer

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

by Marcus Green -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
In reply to Marcus Green

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

by Dominique Bauer -
Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Plugin developers

Marcus

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

In reply to Dominique Bauer

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

by 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
Average of ratings: Useful (1)
In reply to Tim Hunt

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

by 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?
In reply to Dawid Bartkowiak

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

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

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

}
In reply to Tim Hunt

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

by 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
In reply to Tim Hunt

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

by 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."');");
}
Average of ratings: Useful (1)
In reply to Tim Hunt

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

by 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. 
Average of ratings: Useful (2)
In reply to shiva k

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

by Luiggi Sansonetti -
Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
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 wink
In reply to Luiggi Sansonetti

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

by 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>

Average of ratings: Useful (1)
In reply to shiva k

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

by Luiggi Sansonetti -
Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers

Hi Shiva

Thanks for your feedback and new code

It's better for the review and refresh


But some mistakes again smile

  • 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:


In reply to Luiggi Sansonetti

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

by 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
Average of ratings: Useful (1)
In reply to shiva k

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

by Luiggi Sansonetti -
Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
Ok thanks

It's almost perfect now wink

I'll be back soon with some other tests
In reply to shiva k

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

by Luiggi Sansonetti -
Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers

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...

In reply to Luiggi Sansonetti

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

by Luiggi Sansonetti -
Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
Sorry

atto_templates4u and filter_filtercodes
In reply to Luiggi Sansonetti

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

by 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>



In reply to shiva k

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

by 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();
});
};
Average of ratings: Useful (1)
In reply to shiva k

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

by 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

In reply to shiva k

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

by 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.
In reply to shiva k

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

by 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.
In reply to Dawid Bartkowiak

Re: Time limit per question - implementation guide

by P H -
Is there any hope of bringing this to fruition in the form of a plugin?
Average of ratings: Useful (1)