diff --git a/mod/quiz/autosave.ajax.php b/mod/quiz/autosave.ajax.php index ebf34994ff8..c2f38179f48 100644 --- a/mod/quiz/autosave.ajax.php +++ b/mod/quiz/autosave.ajax.php @@ -61,4 +61,15 @@ if ($attemptobj->is_finished()) { $attemptobj->process_auto_save($timenow); $transaction->allow_commit(); -echo 'OK'; + +// Calculate time remaining. +$timeleft = $attemptobj->get_time_left_display($timenow); + +// Build response, only returning timeleft if quiz in-progress +// has a time limit. +$r = new stdClass(); +$r->status = "OK"; +if ($timeleft !== false) { + $r->timeleft = $timeleft; +} +echo json_encode($r); diff --git a/mod/quiz/module.js b/mod/quiz/module.js index 46f5ab8b98f..9ede9214fb2 100644 --- a/mod/quiz/module.js +++ b/mod/quiz/module.js @@ -58,6 +58,9 @@ M.mod_quiz.timer = { // so we can cancel. timeoutid: null, + // Threshold for updating time remaining, in milliseconds. + threshold: 3000, + /** * @param Y the YUI object * @param start, the timer starting time, in seconds. @@ -130,6 +133,18 @@ M.mod_quiz.timer = { // Arrange for this method to be called again soon. M.mod_quiz.timer.timeoutid = setTimeout(M.mod_quiz.timer.update, 100); + }, + + // Allow the end time of the quiz to be updated. + updateEndTime: function(timeleft) { + var newtimeleft = new Date().getTime() + timeleft * 1000; + + // Only update if change is greater than the threshold, so the + // time doesn't bounce around unnecessarily. + if (Math.abs(newtimeleft - M.mod_quiz.timer.endtime) > M.mod_quiz.timer.threshold) { + M.mod_quiz.timer.endtime = newtimeleft; + M.mod_quiz.timer.update(); + } } }; diff --git a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-debug.js b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-debug.js index 99e5e2de975..403fb96fd5d 100644 --- a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-debug.js +++ b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-debug.js @@ -358,13 +358,19 @@ M.mod_quiz.autosave = { }, save_done: function(transactionid, response) { - if (response.responseText !== 'OK') { + var autosavedata = JSON.parse(response.responseText); + if (autosavedata.status !== 'OK') { // Because IIS is useless, Moodle can't send proper HTTP response // codes, so we have to detect failures manually. this.save_failed(transactionid, response); return; } + if (typeof autosavedata.timeleft !== 'undefined') { + Y.log('Updating timer: ' + autosavedata.timeleft + ' seconds remain.', 'debug', 'moodle-mod_quiz-timer'); + M.mod_quiz.timer.updateEndTime(autosavedata.timeleft); + } + Y.log('Save completed.', 'debug', 'moodle-mod_quiz-autosave'); this.save_transaction = null; diff --git a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-min.js b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-min.js index 6d79032bbbc..393c2d90ea0 100644 --- a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-min.js +++ b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-min.js @@ -1 +1 @@ -YUI.add("moodle-mod_quiz-autosave",function(i,t){M.mod_quiz=M.mod_quiz||{},M.mod_quiz.autosave={TINYMCE_DETECTION_DELAY:500,TINYMCE_DETECTION_REPEATS:20,WATCH_HIDDEN_DELAY:1e3,FAILURES_BEFORE_NOTIFY:1,FIRST_SUCCESSFUL_SAVE:-1,SELECTORS:{QUIZ_FORM:"#responseform",VALUE_CHANGE_ELEMENTS:'input, textarea, [contenteditable="true"]',CHANGE_ELEMENTS:"input, select",HIDDEN_INPUTS:"input[type=hidden]",CONNECTION_ERROR:"#connection-error",CONNECTION_OK:"#connection-ok"},AUTOSAVE_HANDLER:M.cfg.wwwroot+"/mod/quiz/autosave.ajax.php",delay:12e4,form:null,dirty:!1,delay_timer:null,save_transaction:null,savefailures:0,editor_change_handler:null,hidden_field_values:{},init:function(t){this.form=i.one(this.SELECTORS.QUIZ_FORM),this.form&&(this.delay=1e3*t,this.form.delegate("valuechange",this.value_changed,this.SELECTORS.VALUE_CHANGE_ELEMENTS,this),this.form.delegate("change",this.value_changed,this.SELECTORS.CHANGE_ELEMENTS,this),this.form.on("submit",this.stop_autosaving,this),this.init_tinymce(this.TINYMCE_DETECTION_REPEATS),this.save_hidden_field_values(),this.watch_hidden_fields())},save_hidden_field_values:function(){this.form.all(this.SELECTORS.HIDDEN_INPUTS).each(function(t){var e=t.get("name");e&&(this.hidden_field_values[e]=t.get("value"))},this)},watch_hidden_fields:function(){this.detect_hidden_field_changes(),i.later(this.WATCH_HIDDEN_DELAY,this,this.watch_hidden_fields)},detect_hidden_field_changes:function(){this.form.all(this.SELECTORS.HIDDEN_INPUTS).each(function(t){var e=t.get("name"),i=t.get("value");e&&(e in this.hidden_field_values&&i===this.hidden_field_values[e]||(this.hidden_field_values[e]=i,this.value_changed({target:t})))},this)},init_tinymce:function(t){"undefined"!=typeof window.tinyMCE?(this.editor_change_handler=i.bind(this.editor_changed,this),window.tinyMCE.onAddEditor.add(i.bind(this.init_tinymce_editor,this))):0M.mod_quiz.timer.endtime},stop_autosaving:function(){this.cancel_delay(),this.delay_timer=!0,this.save_transaction&&this.save_transaction.abort()}}},"@VERSION@",{requires:["base","node","event","event-valuechange","node-event-delegate","io-form"]}); \ No newline at end of file +YUI.add("moodle-mod_quiz-autosave",function(s,e){M.mod_quiz=M.mod_quiz||{},M.mod_quiz.autosave={TINYMCE_DETECTION_DELAY:500,TINYMCE_DETECTION_REPEATS:20,WATCH_HIDDEN_DELAY:1e3,FAILURES_BEFORE_NOTIFY:1,FIRST_SUCCESSFUL_SAVE:-1,SELECTORS:{QUIZ_FORM:"#responseform",VALUE_CHANGE_ELEMENTS:'input, textarea, [contenteditable="true"]',CHANGE_ELEMENTS:"input, select",HIDDEN_INPUTS:"input[type=hidden]",CONNECTION_ERROR:"#connection-error",CONNECTION_OK:"#connection-ok"},AUTOSAVE_HANDLER:M.cfg.wwwroot+"/mod/quiz/autosave.ajax.php",delay:12e4,form:null,dirty:!1,delay_timer:null,save_transaction:null,savefailures:0,editor_change_handler:null,hidden_field_values:{},init:function(e){this.form=s.one(this.SELECTORS.QUIZ_FORM),this.form&&(this.delay=1e3*e,this.form.delegate("valuechange",this.value_changed,this.SELECTORS.VALUE_CHANGE_ELEMENTS,this),this.form.delegate("change",this.value_changed,this.SELECTORS.CHANGE_ELEMENTS,this),this.form.on("submit",this.stop_autosaving,this),this.init_tinymce(this.TINYMCE_DETECTION_REPEATS),this.save_hidden_field_values(),this.watch_hidden_fields())},save_hidden_field_values:function(){this.form.all(this.SELECTORS.HIDDEN_INPUTS).each(function(e){var t=e.get("name");t&&(this.hidden_field_values[t]=e.get("value"))},this)},watch_hidden_fields:function(){this.detect_hidden_field_changes(),s.later(this.WATCH_HIDDEN_DELAY,this,this.watch_hidden_fields)},detect_hidden_field_changes:function(){this.form.all(this.SELECTORS.HIDDEN_INPUTS).each(function(e){var t=e.get("name"),i=e.get("value");t&&(t in this.hidden_field_values&&i===this.hidden_field_values[t]||(this.hidden_field_values[t]=i,this.value_changed({target:e})))},this)},init_tinymce:function(e){"undefined"!=typeof window.tinyMCE?(this.editor_change_handler=s.bind(this.editor_changed,this),window.tinyMCE.onAddEditor.add(s.bind(this.init_tinymce_editor,this))):0M.mod_quiz.timer.endtime},stop_autosaving:function(){this.cancel_delay(),this.delay_timer=!0,this.save_transaction&&this.save_transaction.abort()}}},"@VERSION@",{requires:["base","node","event","event-valuechange","node-event-delegate","io-form"]}); \ No newline at end of file diff --git a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave.js b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave.js index 21abfc50409..674d946a173 100644 --- a/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave.js +++ b/mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave.js @@ -350,13 +350,18 @@ M.mod_quiz.autosave = { }, save_done: function(transactionid, response) { - if (response.responseText !== 'OK') { + var autosavedata = JSON.parse(response.responseText); + if (autosavedata.status !== 'OK') { // Because IIS is useless, Moodle can't send proper HTTP response // codes, so we have to detect failures manually. this.save_failed(transactionid, response); return; } + if (typeof autosavedata.timeleft !== 'undefined') { + M.mod_quiz.timer.updateEndTime(autosavedata.timeleft); + } + this.save_transaction = null; if (this.dirty) { diff --git a/mod/quiz/yui/src/autosave/js/autosave.js b/mod/quiz/yui/src/autosave/js/autosave.js index cce5017374b..9633f7310e5 100644 --- a/mod/quiz/yui/src/autosave/js/autosave.js +++ b/mod/quiz/yui/src/autosave/js/autosave.js @@ -356,13 +356,19 @@ M.mod_quiz.autosave = { }, save_done: function(transactionid, response) { - if (response.responseText !== 'OK') { + var autosavedata = JSON.parse(response.responseText); + if (autosavedata.status !== 'OK') { // Because IIS is useless, Moodle can't send proper HTTP response // codes, so we have to detect failures manually. this.save_failed(transactionid, response); return; } + if (typeof autosavedata.timeleft !== 'undefined') { + Y.log('Updating timer: ' + autosavedata.timeleft + ' seconds remain.', 'debug', 'moodle-mod_quiz-timer'); + M.mod_quiz.timer.updateEndTime(autosavedata.timeleft); + } + Y.log('Save completed.', 'debug', 'moodle-mod_quiz-autosave'); this.save_transaction = null;