Merge branch 'MDL-58926-ajax-timer' of https://github.com/rboyatt/moodle

This commit is contained in:
Jake Dallimore 2020-07-02 09:37:00 +08:00
commit c39dc16da4
6 changed files with 48 additions and 5 deletions

View File

@ -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);

View File

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

View File

@ -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;

View File

@ -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))):0<t&&i.later(this.TINYMCE_DETECTION_DELAY,this,this.init_tinymce,[t-1])},init_tinymce_editor:function(t,e){e.onChange.add(this.editor_change_handler),e.onRedo.add(this.editor_change_handler),e.onUndo.add(this.editor_change_handler),e.onKeyDown.add(this.editor_change_handler)},value_changed:function(t){var e=t.target.getAttribute("name");"thispage"===e||"scrollpos"===e||e&&e.match(/_:flagged$/)||(e=e||"#"+t.target.getAttribute("id"),this.start_save_timer_if_necessary())},editor_changed:function(t){this.start_save_timer_if_necessary()},start_save_timer_if_necessary:function(){this.dirty=!0,this.delay_timer||this.save_transaction||this.start_save_timer()},start_save_timer:function(){this.cancel_delay(),this.delay_timer=i.later(this.delay,this,this.save_changes)},cancel_delay:function(){this.delay_timer&&!0!==this.delay_timer&&this.delay_timer.cancel(),this.delay_timer=null},save_changes:function(){if(this.cancel_delay(),this.dirty=!1,this.is_time_nearly_over())this.stop_autosaving();else{"undefined"!=typeof window.tinyMCE&&window.tinyMCE.triggerSave();var t=this.form.all("input[type=submit], button[type=submit]");t.setAttribute("type","button"),this.save_transaction=i.io(this.AUTOSAVE_HANDLER,{method:"POST",form:{id:this.form},on:{success:this.save_done,failure:this.save_failed},context:this}),t.setAttribute("type","submit")}},save_done:function(t,e){"OK"===e.responseText?(this.save_transaction=null,this.dirty&&this.start_save_timer(),0<this.savefailures?(i.one(this.SELECTORS.CONNECTION_ERROR).hide(),i.one(this.SELECTORS.CONNECTION_OK).show(),this.savefailures=this.FIRST_SUCCESSFUL_SAVE):this.savefailures===this.FIRST_SUCCESSFUL_SAVE&&(i.one(this.SELECTORS.CONNECTION_OK).hide(),this.savefailures=0)):this.save_failed(t,e)},save_failed:function(){this.save_transaction=null,this.start_save_timer(),this.savefailures=Math.max(1,this.savefailures+1),this.savefailures===this.FAILURES_BEFORE_NOTIFY&&(i.one(this.SELECTORS.CONNECTION_ERROR).show(),i.one(this.SELECTORS.CONNECTION_OK).hide())},is_time_nearly_over:function(){return M.mod_quiz.timer&&M.mod_quiz.timer.endtime&&(new Date).getTime()+2*this.delay>M.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"]});
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))):0<e&&s.later(this.TINYMCE_DETECTION_DELAY,this,this.init_tinymce,[e-1])},init_tinymce_editor:function(e,t){t.onChange.add(this.editor_change_handler),t.onRedo.add(this.editor_change_handler),t.onUndo.add(this.editor_change_handler),t.onKeyDown.add(this.editor_change_handler)},value_changed:function(e){var t=e.target.getAttribute("name");"thispage"===t||"scrollpos"===t||t&&t.match(/_:flagged$/)||(t=t||"#"+e.target.getAttribute("id"),this.start_save_timer_if_necessary())},editor_changed:function(e){this.start_save_timer_if_necessary()},start_save_timer_if_necessary:function(){this.dirty=!0,this.delay_timer||this.save_transaction||this.start_save_timer()},start_save_timer:function(){this.cancel_delay(),this.delay_timer=s.later(this.delay,this,this.save_changes)},cancel_delay:function(){this.delay_timer&&!0!==this.delay_timer&&this.delay_timer.cancel(),this.delay_timer=null},save_changes:function(){if(this.cancel_delay(),this.dirty=!1,this.is_time_nearly_over())this.stop_autosaving();else{"undefined"!=typeof window.tinyMCE&&window.tinyMCE.triggerSave();var e=this.form.all("input[type=submit], button[type=submit]");e.setAttribute("type","button"),this.save_transaction=s.io(this.AUTOSAVE_HANDLER,{method:"POST",form:{id:this.form},on:{success:this.save_done,failure:this.save_failed},context:this}),e.setAttribute("type","submit")}},save_done:function(e,t){var i=JSON.parse(t.responseText);"OK"===i.status?("undefined"!=typeof i.timeleft&&M.mod_quiz.timer.updateEndTime(i.timeleft),this.save_transaction=null,this.dirty&&this.start_save_timer(),0<this.savefailures?(s.one(this.SELECTORS.CONNECTION_ERROR).hide(),s.one(this.SELECTORS.CONNECTION_OK).show(),this.savefailures=this.FIRST_SUCCESSFUL_SAVE):this.savefailures===this.FIRST_SUCCESSFUL_SAVE&&(s.one(this.SELECTORS.CONNECTION_OK).hide(),this.savefailures=0)):this.save_failed(e,t)},save_failed:function(){this.save_transaction=null,this.start_save_timer(),this.savefailures=Math.max(1,this.savefailures+1),this.savefailures===this.FAILURES_BEFORE_NOTIFY&&(s.one(this.SELECTORS.CONNECTION_ERROR).show(),s.one(this.SELECTORS.CONNECTION_OK).hide())},is_time_nearly_over:function(){return M.mod_quiz.timer&&M.mod_quiz.timer.endtime&&(new Date).getTime()+2*this.delay>M.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"]});

View File

@ -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) {

View File

@ -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;