Merge branch 'MDL-69918-master' of git://github.com/andrewnicols/moodle

This commit is contained in:
Víctor Déniz
2021-08-10 19:15:22 +01:00
70 changed files with 1060 additions and 1057 deletions
+2 -4
View File
@@ -158,9 +158,7 @@ echo $outputhtml;
echo html_writer::end_tag('fieldset');
echo html_writer::end_tag('form');
$PAGE->requires->yui_module('moodle-core-formchangechecker', 'M.core_formchangechecker.init', [[
'formid' => 'adminsettings'
]]);
$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
// Add the form change checker.
$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['adminsettings']);
echo $OUTPUT->footer();
+2 -7
View File
@@ -148,13 +148,8 @@ if (empty($SITE->fullname)) {
echo $OUTPUT->render_from_template('core_admin/settings', $context);
}
$PAGE->requires->yui_module('moodle-core-formchangechecker',
'M.core_formchangechecker.init',
array(array(
'formid' => 'adminsettings'
))
);
$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
// Add the form change checker.
$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['adminsettings']);
if ($settingspage->has_dependencies()) {
$opts = [
+1 -1
View File
@@ -1,2 +1,2 @@
define ("tool_dataprivacy/add_category",["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment"],function(a,b,c,d,e,f,g){var h={CATEGORY_LINK:"[data-add-element=\"category\"]"},i=function(a){this.contextId=a;this.strings=b.get_strings([{key:"addcategory",component:"tool_dataprivacy"},{key:"save",component:"admin"}]);this.registerEventListeners()};i.prototype.contextId=0;i.prototype.strings=0;i.prototype.registerEventListeners=function(){var b=a(h.CATEGORY_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))};i.prototype.getBody=function(a){var b=null;if("undefined"!=typeof a){b={jsonformdata:JSON.stringify(a)}}return g.loadFragment("tool_dataprivacy","addcategory_form",this.contextId,b)};i.prototype.setupFormModal=function(a,b){a.setLarge();a.setSaveButtonText(b);a.getRoot().on(f.hidden,this.destroy.bind(this));a.setBody(this.getBody());a.getRoot().on(f.save,this.submitForm.bind(this));a.getRoot().on("submit","form",this.submitFormAjax.bind(this));this.modal=a;a.show()};i.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};i.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_category_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this),fail:d.exception}])};i.prototype.close=function(){this.destroy();document.location.reload()};i.prototype.destroy=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});this.modal.destroy()};i.prototype.removeListeners=function(){a(h.CATEGORY_LINK).off("click")};return{getInstance:function getInstance(a){return new i(a)}}});
define ("tool_dataprivacy/add_category",["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment","core_form/changechecker"],function(a,b,c,d,e,f,g,h){var i={CATEGORY_LINK:"[data-add-element=\"category\"]"},j=function(a){this.contextId=a;this.strings=b.get_strings([{key:"addcategory",component:"tool_dataprivacy"},{key:"save",component:"admin"}]);this.registerEventListeners()};j.prototype.contextId=0;j.prototype.strings=0;j.prototype.registerEventListeners=function(){var b=a(i.CATEGORY_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))};j.prototype.getBody=function(a){var b=null;if("undefined"!=typeof a){b={jsonformdata:JSON.stringify(a)}}return g.loadFragment("tool_dataprivacy","addcategory_form",this.contextId,b)};j.prototype.setupFormModal=function(a,b){a.setLarge();a.setSaveButtonText(b);a.getRoot().on(f.hidden,this.destroy.bind(this));a.setBody(this.getBody());a.getRoot().on(f.save,this.submitForm.bind(this));a.getRoot().on("submit","form",this.submitFormAjax.bind(this));this.modal=a;a.show()};j.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};j.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_category_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this),fail:d.exception}])};j.prototype.close=function(){this.destroy();document.location.reload()};j.prototype.destroy=function(){h.resetAllFormDirtyStates();this.modal.destroy()};j.prototype.removeListeners=function(){a(i.CATEGORY_LINK).off("click")};return{getInstance:function getInstance(a){return new j(a)}}});
//# sourceMappingURL=add_category.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("tool_dataprivacy/add_purpose",["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment"],function(a,b,c,d,e,f,g){var h={PURPOSE_LINK:"[data-add-element=\"purpose\"]"},i=function(a){this.contextId=a;this.strings=b.get_strings([{key:"addpurpose",component:"tool_dataprivacy"},{key:"save",component:"admin"}]);this.registerEventListeners()};i.prototype.contextId=0;i.prototype.strings=0;i.prototype.registerEventListeners=function(){var b=a(h.PURPOSE_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))};i.prototype.getBody=function(a){var b=null;if("undefined"!=typeof a){b={jsonformdata:JSON.stringify(a)}}return g.loadFragment("tool_dataprivacy","addpurpose_form",this.contextId,b)};i.prototype.setupFormModal=function(a,b){a.setLarge();a.setSaveButtonText(b);a.getRoot().on(f.hidden,this.destroy.bind(this));a.setBody(this.getBody());a.getRoot().on(f.save,this.submitForm.bind(this));a.getRoot().on("submit","form",this.submitFormAjax.bind(this));this.modal=a;a.show()};i.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};i.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_purpose_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this),fail:d.exception}])};i.prototype.close=function(){this.destroy();document.location.reload()};i.prototype.destroy=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});this.modal.destroy()};i.prototype.removeListeners=function(){a(h.PURPOSE_LINK).off("click")};return{getInstance:function getInstance(a){return new i(a)}}});
define ("tool_dataprivacy/add_purpose",["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment","core_form/changechecker"],function(a,b,c,d,e,f,g,h){var i={PURPOSE_LINK:"[data-add-element=\"purpose\"]"},j=function(a){this.contextId=a;this.strings=b.get_strings([{key:"addpurpose",component:"tool_dataprivacy"},{key:"save",component:"admin"}]);this.registerEventListeners()};j.prototype.contextId=0;j.prototype.strings=0;j.prototype.registerEventListeners=function(){var b=a(i.PURPOSE_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))};j.prototype.getBody=function(a){var b=null;if("undefined"!=typeof a){b={jsonformdata:JSON.stringify(a)}}return g.loadFragment("tool_dataprivacy","addpurpose_form",this.contextId,b)};j.prototype.setupFormModal=function(a,b){a.setLarge();a.setSaveButtonText(b);a.getRoot().on(f.hidden,this.destroy.bind(this));a.setBody(this.getBody());a.getRoot().on(f.save,this.submitForm.bind(this));a.getRoot().on("submit","form",this.submitFormAjax.bind(this));this.modal=a;a.show()};j.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};j.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_purpose_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this),fail:d.exception}])};j.prototype.close=function(){this.destroy();document.location.reload()};j.prototype.destroy=function(){h.resetAllFormDirtyStates();this.modal.destroy()};j.prototype.removeListeners=function(){a(i.PURPOSE_LINK).off("click")};return{getInstance:function getInstance(a){return new j(a)}}});
//# sourceMappingURL=add_purpose.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("tool_dataprivacy/data_registry",["jquery","core/str","core/ajax","core/notification","core/templates","core/modal_factory","core/modal_events","core/fragment","tool_dataprivacy/add_purpose","tool_dataprivacy/add_category"],function(a,b,c,d,e,f,g,h,i,j){var k={TREE_NODES:"[data-context-tree-node=1]",FORM_CONTAINER:"#context-form-container"},l=function(a,b,c){this.systemContextId=a;this.currentContextLevel=b;this.currentContextId=c;this.init()};l.prototype.systemContextId=0;l.prototype.currentContextLevel=0;l.prototype.currentContextId=0;l.prototype.addpurpose=null;l.prototype.addcategory=null;l.prototype.init=function(){this.addpurpose=i.getInstance(this.systemContextId);this.addcategory=j.getInstance(this.systemContextId);this.strings=b.get_strings([{key:"changessaved",component:"moodle"},{key:"contextpurposecategorysaved",component:"tool_dataprivacy"},{key:"noblockstoload",component:"tool_dataprivacy"},{key:"noactivitiestoload",component:"tool_dataprivacy"},{key:"nocoursestoload",component:"tool_dataprivacy"}]);this.registerEventListeners();if(this.currentContextId){this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this))}else{this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))}};l.prototype.registerEventListeners=function(){a(k.TREE_NODES).on("click",function(b){b.preventDefault();var c=a(b.currentTarget);a(k.TREE_NODES).removeClass("active");c.addClass("active");var d=c.data("contextlevel"),e=c.data("contextid");if(d){window.history.pushState({},null,"?contextlevel="+d);this.addpurpose.removeListeners();this.addcategory.removeListeners();this.currentContextLevel=d;this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))}else if(e){window.history.pushState({},null,"?contextid="+e);this.addpurpose.removeListeners();this.addcategory.removeListeners();this.currentContextId=e;this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this))}else{var f=c.data("expandcontextid"),g=c.data("expandelement"),h=c.data("expanded");if(g){if(!h){if(c.data("loaded")||!f||!g){this.expand(c)}else{c.find("> i").removeClass("fa-plus");c.find("> i").addClass("fa-circle-o-notch fa-spin");this.loadExtra(c,f,g)}}else{this.collapse(c)}}}}.bind(this))};l.prototype.removeListeners=function(){a(k.TREE_NODES).off("click")};l.prototype.loadForm=function(b,c,f){this.clearForm();var g=h.loadFragment("tool_dataprivacy",b,this.systemContextId,c);g.done(function(b,c){a(k.FORM_CONTAINER).html(b);e.runTemplateJS(c);this.addpurpose.registerEventListeners();this.addcategory.registerEventListeners();a(k.FORM_CONTAINER).on("submit","form",f)}.bind(this)).fail(d.exception)};l.prototype.clearForm=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});a(k.FORM_CONTAINER).off("submit","form")};l.prototype.submitForm=function(b){b.preventDefault();a(k.FORM_CONTAINER).find("form").submit()};l.prototype.submitContextLevelFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_contextlevel_form")};l.prototype.submitContextFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_context_form")};l.prototype.submitFormAjax=function(b,e){b.preventDefault();var f=a(k.FORM_CONTAINER).find("form").serialize();return this.strings.then(function(a){c.call([{methodname:e,args:{jsonformdata:JSON.stringify(f)},done:function done(){d.alert(a[0],a[1])},fail:d.exception}])}).catch(d.exception)};l.prototype.loadExtra=function(a,b,f){c.call([{methodname:"tool_dataprivacy_tree_extra_branches",args:{contextid:b,element:f},done:function(b){if(0==b.branches.length){this.noElements(a,f);return}e.render("tool_dataprivacy/context_tree_branches",b).then(function(b){a.after(b);this.removeListeners();this.registerEventListeners();this.expand(a);a.data("loaded",1)}.bind(this)).fail(d.exception)}.bind(this),fail:d.exception}])};l.prototype.noElements=function(a,b){a.data("expandcontextid","");a.data("expandelement","");this.strings.then(function(c){var d=2;if("module"==b){d=3}else if("course"==b){d=4}a.text(c[d])}).fail(d.exception)};l.prototype.collapse=function(a){a.data("expanded",0);a.siblings("nav").addClass("hidden");a.find("> i").removeClass("fa-minus");a.find("> i").addClass("fa-plus")};l.prototype.expand=function(a){a.data("expanded",1);a.siblings("nav").removeClass("hidden");a.find("> i").removeClass("fa-plus");a.find("> i").removeClass("fa-circle-o-notch fa-spin");a.find("> i").addClass("fa-minus")};return{init:function init(a,b,c){return new l(a,b,c)}}});
define ("tool_dataprivacy/data_registry",["jquery","core/str","core/ajax","core/notification","core/templates","core/modal_factory","core/modal_events","core/fragment","tool_dataprivacy/add_purpose","tool_dataprivacy/add_category"],function(a,b,c,d,e,f,g,h,i,j){var k={TREE_NODES:"[data-context-tree-node=1]",FORM_CONTAINER:"#context-form-container"},l=function(a,b,c){this.systemContextId=a;this.currentContextLevel=b;this.currentContextId=c;this.init()};l.prototype.systemContextId=0;l.prototype.currentContextLevel=0;l.prototype.currentContextId=0;l.prototype.addpurpose=null;l.prototype.addcategory=null;l.prototype.init=function(){this.addpurpose=i.getInstance(this.systemContextId);this.addcategory=j.getInstance(this.systemContextId);this.strings=b.get_strings([{key:"changessaved",component:"moodle"},{key:"contextpurposecategorysaved",component:"tool_dataprivacy"},{key:"noblockstoload",component:"tool_dataprivacy"},{key:"noactivitiestoload",component:"tool_dataprivacy"},{key:"nocoursestoload",component:"tool_dataprivacy"}]);this.registerEventListeners();if(this.currentContextId){this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this))}else{this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))}};l.prototype.registerEventListeners=function(){a(k.TREE_NODES).on("click",function(b){b.preventDefault();var c=a(b.currentTarget);a(k.TREE_NODES).removeClass("active");c.addClass("active");var d=c.data("contextlevel"),e=c.data("contextid");if(d){window.history.pushState({},null,"?contextlevel="+d);this.addpurpose.removeListeners();this.addcategory.removeListeners();this.currentContextLevel=d;this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))}else if(e){window.history.pushState({},null,"?contextid="+e);this.addpurpose.removeListeners();this.addcategory.removeListeners();this.currentContextId=e;this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this))}else{var f=c.data("expandcontextid"),g=c.data("expandelement"),h=c.data("expanded");if(g){if(!h){if(c.data("loaded")||!f||!g){this.expand(c)}else{c.find("> i").removeClass("fa-plus");c.find("> i").addClass("fa-circle-o-notch fa-spin");this.loadExtra(c,f,g)}}else{this.collapse(c)}}}}.bind(this))};l.prototype.removeListeners=function(){a(k.TREE_NODES).off("click")};l.prototype.loadForm=function(b,c,f){this.clearForm();var g=h.loadFragment("tool_dataprivacy",b,this.systemContextId,c);g.done(function(b,c){a(k.FORM_CONTAINER).html(b);e.runTemplateJS(c);this.addpurpose.registerEventListeners();this.addcategory.registerEventListeners();a(k.FORM_CONTAINER).on("submit","form",f)}.bind(this)).fail(d.exception)};l.prototype.clearForm=function(){a(k.FORM_CONTAINER).off("submit","form")};l.prototype.submitForm=function(b){b.preventDefault();a(k.FORM_CONTAINER).find("form").submit()};l.prototype.submitContextLevelFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_contextlevel_form")};l.prototype.submitContextFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_context_form")};l.prototype.submitFormAjax=function(b,e){b.preventDefault();var f=a(k.FORM_CONTAINER).find("form").serialize();return this.strings.then(function(a){c.call([{methodname:e,args:{jsonformdata:JSON.stringify(f)},done:function done(){d.alert(a[0],a[1])},fail:d.exception}])}).catch(d.exception)};l.prototype.loadExtra=function(a,b,f){c.call([{methodname:"tool_dataprivacy_tree_extra_branches",args:{contextid:b,element:f},done:function(b){if(0==b.branches.length){this.noElements(a,f);return}e.render("tool_dataprivacy/context_tree_branches",b).then(function(b){a.after(b);this.removeListeners();this.registerEventListeners();this.expand(a);a.data("loaded",1)}.bind(this)).fail(d.exception)}.bind(this),fail:d.exception}])};l.prototype.noElements=function(a,b){a.data("expandcontextid","");a.data("expandelement","");this.strings.then(function(c){var d=2;if("module"==b){d=3}else if("course"==b){d=4}a.text(c[d])}).fail(d.exception)};l.prototype.collapse=function(a){a.data("expanded",0);a.siblings("nav").addClass("hidden");a.find("> i").removeClass("fa-minus");a.find("> i").addClass("fa-plus")};l.prototype.expand=function(a){a.data("expanded",1);a.siblings("nav").removeClass("hidden");a.find("> i").removeClass("fa-plus");a.find("> i").removeClass("fa-circle-o-notch fa-spin");a.find("> i").addClass("fa-minus")};return{init:function init(a,b,c){return new l(a,b,c)}}});
//# sourceMappingURL=data_registry.min.js.map
File diff suppressed because one or more lines are too long
+20 -5
View File
@@ -20,8 +20,25 @@
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/fragment'],
function($, Str, Ajax, Notification, ModalFactory, ModalEvents, Fragment) {
define([
'jquery',
'core/str',
'core/ajax',
'core/notification',
'core/modal_factory',
'core/modal_events',
'core/fragment',
'core_form/changechecker',
], function(
$,
Str,
Ajax,
Notification,
ModalFactory,
ModalEvents,
Fragment,
FormChangeChecker
) {
var SELECTORS = {
CATEGORY_LINK: '[data-add-element="category"]',
@@ -151,9 +168,7 @@ define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_fact
};
AddCategory.prototype.destroy = function() {
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
FormChangeChecker.resetAllFormDirtyStates();
this.modal.destroy();
};
+20 -5
View File
@@ -20,8 +20,25 @@
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/fragment'],
function($, Str, Ajax, Notification, ModalFactory, ModalEvents, Fragment) {
define([
'jquery',
'core/str',
'core/ajax',
'core/notification',
'core/modal_factory',
'core/modal_events',
'core/fragment',
'core_form/changechecker',
], function(
$,
Str,
Ajax,
Notification,
ModalFactory,
ModalEvents,
Fragment,
FormChangeChecker
) {
var SELECTORS = {
PURPOSE_LINK: '[data-add-element="purpose"]',
@@ -152,9 +169,7 @@ define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_fact
};
AddPurpose.prototype.destroy = function() {
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
FormChangeChecker.resetAllFormDirtyStates();
this.modal.destroy();
};
@@ -189,11 +189,6 @@ define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/templates'
};
DataRegistry.prototype.clearForm = function() {
// For the previously loaded form.
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
// Remove previous listeners.
$(SELECTORS.FORM_CONTAINER).off('submit', 'form');
};
+1 -1
View File
@@ -1,2 +1,2 @@
define ("tool_policy/acceptmodal",["jquery","core/str","core/modal_factory","core/modal_events","core/notification","core/fragment","core/ajax","core/yui"],function(a,b,c,d,f,g,h,i){"use strict";var e=function(a){this.contextid=a;this.init()};e.prototype.modal=null;e.prototype.contextid=-1;e.prototype.currentTrigger=null;e.prototype.triggers={SINGLE:"a[data-action=acceptmodal]",BULK:"input[data-action=acceptmodal]"};e.prototype.init=function(){a(this.triggers.SINGLE).on("click",function(b){b.preventDefault();this.currentTrigger=a(b.currentTarget);var c=a(b.currentTarget).attr("href"),d=c.slice(c.indexOf("?")+1);this.showFormModal(d)}.bind(this));a(this.triggers.BULK).on("click",function(c){c.preventDefault();this.currentTrigger=a(c.currentTarget);var d=a(c.currentTarget).closest("form");if(d.find("input[type=checkbox][name=\"userids[]\"]:checked").length){var e=d.serialize();this.showFormModal(e)}else{b.get_strings([{key:"notice"},{key:"selectusersforconsent",component:"tool_policy"},{key:"ok"}]).then(function(a){f.alert(a[0],a[1],a[2])}).fail(f.exception)}}.bind(this))};e.prototype.showFormModal=function(a){for(var d,e=a.split("&"),g=0,h;g<e.length;g++){h=e[g].split("=");if("action"==h[0]){d=h[1]}}b.get_strings([{key:"statusformtitleaccept",component:"tool_policy"},{key:"iagreetothepolicy",component:"tool_policy"},{key:"statusformtitlerevoke",component:"tool_policy"},{key:"irevokethepolicy",component:"tool_policy"},{key:"statusformtitledecline",component:"tool_policy"},{key:"declinethepolicy",component:"tool_policy"}]).then(function(b){var e,f;if("accept"==d){e=b[0];f=b[1]}else if("revoke"==d){e=b[2];f=b[3]}else if("decline"==d){e=b[4];f=b[5]}return c.create({type:c.types.SAVE_CANCEL,title:e,body:""}).done(function(b){this.modal=b;this.setupFormModal(a,f)}.bind(this))}.bind(this)).catch(f.exception)};e.prototype.setupFormModal=function(a,b){var c=this.modal;c.setLarge();c.setSaveButtonText(b);c.getRoot().on(d.hidden,this.destroy.bind(this));c.setBody(this.getBody(a));c.getRoot().on(d.save,this.submitForm.bind(this));c.getRoot().on("submit","form",this.submitFormAjax.bind(this));c.show()};e.prototype.getBody=function(a){if("undefined"==typeof a){a={}}var b={jsonformdata:JSON.stringify(a)};return g.loadFragment("tool_policy","accept_on_behalf",this.contextid,b)};e.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize(),c=h.call([{methodname:"tool_policy_submit_accept_on_behalf",args:{jsonformdata:JSON.stringify(b)}}]);c[0].done(function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this)).fail(f.exception)};e.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};e.prototype.close=function(){this.destroy();document.location.reload()};e.prototype.destroy=function(){i.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});this.modal.destroy();this.currentTrigger.focus()};return{getInstance:function getInstance(a){return new e(a)}}});
define ("tool_policy/acceptmodal",["jquery","core/str","core/modal_factory","core/modal_events","core/notification","core/fragment","core/ajax","core_form/changechecker"],function(a,b,c,d,f,g,h,i){"use strict";var j=function(a){this.contextid=a;this.init()};j.prototype.modal=null;j.prototype.contextid=-1;j.prototype.currentTrigger=null;j.prototype.triggers={SINGLE:"a[data-action=acceptmodal]",BULK:"input[data-action=acceptmodal]"};j.prototype.init=function(){a(this.triggers.SINGLE).on("click",function(b){b.preventDefault();this.currentTrigger=a(b.currentTarget);var c=a(b.currentTarget).attr("href"),d=c.slice(c.indexOf("?")+1);this.showFormModal(d)}.bind(this));a(this.triggers.BULK).on("click",function(c){c.preventDefault();this.currentTrigger=a(c.currentTarget);var d=a(c.currentTarget).closest("form");if(d.find("input[type=checkbox][name=\"userids[]\"]:checked").length){var e=d.serialize();this.showFormModal(e)}else{b.get_strings([{key:"notice"},{key:"selectusersforconsent",component:"tool_policy"},{key:"ok"}]).then(function(a){f.alert(a[0],a[1],a[2])}).fail(f.exception)}}.bind(this))};j.prototype.showFormModal=function(a){for(var d,e=a.split("&"),g=0,h;g<e.length;g++){h=e[g].split("=");if("action"==h[0]){d=h[1]}}b.get_strings([{key:"statusformtitleaccept",component:"tool_policy"},{key:"iagreetothepolicy",component:"tool_policy"},{key:"statusformtitlerevoke",component:"tool_policy"},{key:"irevokethepolicy",component:"tool_policy"},{key:"statusformtitledecline",component:"tool_policy"},{key:"declinethepolicy",component:"tool_policy"}]).then(function(b){var e,f;if("accept"==d){e=b[0];f=b[1]}else if("revoke"==d){e=b[2];f=b[3]}else if("decline"==d){e=b[4];f=b[5]}return c.create({type:c.types.SAVE_CANCEL,title:e,body:""}).done(function(b){this.modal=b;this.setupFormModal(a,f)}.bind(this))}.bind(this)).catch(f.exception)};j.prototype.setupFormModal=function(a,b){var c=this.modal;c.setLarge();c.setSaveButtonText(b);c.getRoot().on(d.hidden,this.destroy.bind(this));c.setBody(this.getBody(a));c.getRoot().on(d.save,this.submitForm.bind(this));c.getRoot().on("submit","form",this.submitFormAjax.bind(this));c.show()};j.prototype.getBody=function(a){if("undefined"==typeof a){a={}}var b={jsonformdata:JSON.stringify(a)};return g.loadFragment("tool_policy","accept_on_behalf",this.contextid,b)};j.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize(),c=h.call([{methodname:"tool_policy_submit_accept_on_behalf",args:{jsonformdata:JSON.stringify(b)}}]);c[0].done(function(a){if(a.validationerrors){this.modal.setBody(this.getBody(b))}else{this.close()}}.bind(this)).fail(f.exception)};j.prototype.submitForm=function(a){a.preventDefault();this.modal.getRoot().find("form").submit()};j.prototype.close=function(){this.destroy();document.location.reload()};j.prototype.destroy=function(){i.resetAllFormDirtyStates();this.modal.destroy();this.currentTrigger.focus()};return{getInstance:function getInstance(a){return new j(a)}}});
//# sourceMappingURL=acceptmodal.min.js.map
File diff suppressed because one or more lines are too long
+20 -6
View File
@@ -20,9 +20,25 @@
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/notification', 'core/fragment',
'core/ajax', 'core/yui'],
function($, Str, ModalFactory, ModalEvents, Notification, Fragment, Ajax, Y) {
define([
'jquery',
'core/str',
'core/modal_factory',
'core/modal_events',
'core/notification',
'core/fragment',
'core/ajax',
'core_form/changechecker',
], function(
$,
Str,
ModalFactory,
ModalEvents,
Notification,
Fragment,
Ajax,
FormChangeChecker
) {
"use strict";
@@ -244,9 +260,7 @@ define(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/n
* Destroy the modal
*/
AcceptOnBehalf.prototype.destroy = function() {
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
FormChangeChecker.resetAllFormDirtyStates();
this.modal.destroy();
this.currentTrigger.focus();
};
+1 -8
View File
@@ -73,14 +73,7 @@ echo $OUTPUT->heading(get_string('bulkactivitycompletion', 'completion'));
echo $renderer->navigation($course, 'bulkcompletion');
$PAGE->requires->yui_module('moodle-core-formchangechecker',
'M.core_formchangechecker.init',
array(array(
'formid' => 'theform'
))
);
$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['theform']);
echo $renderer->bulkcompletion($bulkcompletiondata);
+1 -7
View File
@@ -68,13 +68,7 @@ echo $OUTPUT->heading(get_string('defaultcompletion', 'completion'));
echo $renderer->navigation($course, 'defaultcompletion');
$PAGE->requires->yui_module('moodle-core-formchangechecker',
'M.core_formchangechecker.init',
array(array(
'formid' => 'theform'
))
);
$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['theform']);
echo $renderer->defaultcompletion($activityresourcedata);
+1 -7
View File
@@ -299,13 +299,7 @@ if ($moving) {
echo $OUTPUT->container_end();
$PAGE->requires->yui_module('moodle-core-formchangechecker',
'M.core_formchangechecker.init',
array(array(
'formid' => 'gradetreeform'
))
);
$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['gradetreeform']);
echo $OUTPUT->footer();
die;
+1 -7
View File
@@ -1254,13 +1254,7 @@ class grade_report_grader extends grade_report {
$PAGE->requires->strings_for_js(array('addfeedback', 'feedback', 'grade'), 'grades');
$PAGE->requires->strings_for_js(array('ajaxchoosescale', 'ajaxclicktoclose', 'ajaxerror', 'ajaxfailedupdate', 'ajaxfieldchanged'), 'gradereport_grader');
if (!$enableajax && $USER->gradeediting[$this->courseid]) {
$PAGE->requires->yui_module('moodle-core-formchangechecker',
'M.core_formchangechecker.init',
array(array(
'formid' => 'gradereport_grader'
))
);
$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['gradereport_grader']);
}
$rows = $this->get_right_range_row($rows);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+20 -7
View File
@@ -21,10 +21,25 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 3.0
*/
define(
['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],
function($, log, str, templates, notification, LoadingIcon, Aria) {
define([
'jquery',
'core/log',
'core/str',
'core/templates',
'core/notification',
'core/loadingicon',
'core/aria',
'core_form/changechecker',
], function(
$,
log,
str,
templates,
notification,
LoadingIcon,
Aria,
FormChangeChecker
) {
// Private functions and variables.
/** @var {Object} KEYS - List of keycode constants. */
var KEYS = {
@@ -202,9 +217,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
* @param {jQuery} originalSelect The jQuery object matching the hidden select list.
*/
var notifyChange = function(originalSelect) {
if (typeof M.core_formchangechecker !== 'undefined') {
M.core_formchangechecker.set_form_changed();
}
FormChangeChecker.markFormChangedFromNode(originalSelect[0]);
// Note, jQuery .change() was not working here. Better to
// use plain JavaScript anyway.
+2
View File
@@ -0,0 +1,2 @@
define ("core_form/changechecker",["exports","core_editor/events","core/str"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.markFormAsDirtyById=a.resetFormDirtyStateById=a.watchFormById=a.startWatching=a.markAllFormsSubmitted=a.markFormSubmitted=a.markFormChangedFromNode=a.disableAllChecks=a.markFormAsDirty=a.markAllFormsAsDirty=a.resetFormDirtyState=a.resetAllFormDirtyStates=a.unWatchForm=a.watchForm=void 0;var d,e=[],f=!1,g=function(a){return a.closest("form")},h=function(a){a=g(a);if(!a){return}if(q(a)){return}e.push(a)};a.watchForm=h;var i=function(a){e=e.filter(function(b){return!!b.contains(a)})};a.unWatchForm=i;var j=function(){e.forEach(function(a){a.dataset.formSubmitted="false";a.dataset.formDirty="false"})};a.resetAllFormDirtyStates=j;var k=function(a){a=g(a);if(!a){return}a.dataset.formSubmitted="false";a.dataset.formDirty="false"};a.resetFormDirtyState=k;var l=function(){e.forEach(function(a){a.dataset.formDirty="true"})};a.markAllFormsAsDirty=l;var m=function(a){a=g(a);if(!a){return}a.dataset.formDirty="true"};a.markFormAsDirty=m;var n=function(){f=!0};a.disableAllChecks=n;var o=function(){if(f){return!1}var a=e.some(function(a){return"true"===a.dataset.formSubmitted});if(a){return!1}var b=e.some(function(a){if(!a.isConnected){return!1}if("true"===a.dataset.formDirty){return!0}if(document.activeElement&&document.activeElement.dataset.propertyIsEnumerable("initialValue")){var b=q(document.activeElement),c=document.activeElement.dataset.initialValue!==document.activeElement.value;if(b&&c){return!0}}return!1});if(b){return!0}if("undefined"!=typeof window.tinyMCE){if(window.tinyMCE.editors.some(function(a){return a.isDirty()})){return!0}}return!1},p=function(a){return e.find(function(b){return b.contains(a)})},q=function(a){return e.some(function(b){return b.contains(a)})},r=function(a){return!!a.closest(".ignoredirty")},s=function(a){if(a.dataset.formChangeCheckerOverride){n();return}if(!q(a)){return}if(r(a)){return}var b=p(a);b.dataset.formDirty="true"};a.markFormChangedFromNode=s;var t=function(a){a=g(a);if(!a){return}a.dataset.formSubmitted="true"};a.markFormSubmitted=t;var u=function(){e.forEach(function(a){return t(a)})};a.markAllFormsSubmitted=u;var v=function(a){var b=o()&&!M.cfg.behatsiterunning;if(b){a.preventDefault();a.returnValue=d;return a.returnValue}window.removeEventListener("beforeunload",v);return null},w=function(){x();document.addEventListener("change",function(a){if(!q(a.target)){return}s(a.target)});document.addEventListener("click",function(a){var b=a.target.closest("[data-formchangechecker-ignore-submit]");if(!b){return}var c=g(a.target);if(c){c.dataset.ignoreSubmission="true"}});document.addEventListener("focusin",function(a){if(a.target.matches("input, textarea, select")){if(a.target.dataset.propertyIsEnumerable("initialValue")){return}a.target.dataset.initialValue=a.target.value}});document.addEventListener("submit",function(a){var b=g(a.target);if(!b){return}if(b.dataset.ignoreSubmission){b.dataset.ignoreSubmission="false";return}t(b)});document.addEventListener(b.eventTypes.editorContentRestored,function(a){if(a.target!=document){k(a.target)}else{j()}});(0,c.get_string)("changesmadereallygoaway","moodle").then(function(a){d=a}).catch();window.addEventListener("beforeunload",v)};a.startWatching=w;var x=function(){var a=function(a,b,c){return function(){window.console.warn("The moodle-core-formchangechecker has been deprecated and replaced with core_form/changechecker. "+"The ".concat(a," function has been replaced with ").concat(b,"."));c.apply(void 0,arguments)}};window.M.core_formchangechecker={init:a("init","watchFormById",y),reset_form_dirty_state:a("reset_form_dirty_state","resetFormDirtyState",j),set_form_changed:a("set_form_changed","markFormAsDirty",l),set_form_submitted:a("set_form_submitted","markFormSubmitted",u)}},y=function(a){h(document.getElementById(a))};a.watchFormById=y;a.resetFormDirtyStateById=function resetFormDirtyStateById(a){k(document.getElementById(a))};a.markFormAsDirtyById=function markFormAsDirtyById(a){m(document.getElementById(a))};w()});
//# sourceMappingURL=changechecker.min.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+546
View File
@@ -0,0 +1,546 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This module provides change detection to forms, allowing a browser to warn the user before navigating away if changes
* have been made.
*
* Two flags are stored for each form:
* * a 'dirty' flag; and
* * a 'submitted' flag.
*
* When the page is unloaded each watched form is checked. If the 'dirty' flag is set for any form, and the 'submitted'
* flag is not set for any form, then a warning is shown.
*
* The 'dirty' flag is set when any form element is modified within a watched form.
* The flag can also be set programatically. This may be required for custom form elements.
*
* It is not possible to customise the warning message in any modern browser.
*
* Please note that some browsers have controls on when these alerts may or may not be shown.
* See {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload} for browser-specific
* notes and references.
*
* @module core_form/changechecker
* @copyright 2021 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @example <caption>Usage where the FormElement is already held</caption>
*
* import {watchForm} from 'core_form/changechecker';
*
* // Fetch the form element somehow.
* watchForm(formElement);
*
* @example <caption>Usage from the child of a form - i.e. an input, button, div, etc.</caption>
*
* import {watchForm} from 'core_form/changechecker';
*
* // Watch the form by using a child of it.
* watchForm(document.querySelector('input[data-foo="bar"]'););
*
* @example <caption>Usage from within a template</caption>
* <form id="mod_example-entry-{{uniqid}}" ...>
* <!--
*
* -->
* </form>
* {{#js}}
* require(['core_form/changechecker'], function(changeChecker) {
* watchFormById('mod_example-entry-{{uniqid}}');
* });
* {{/js}}
*/
import {eventTypes} from 'core_editor/events';
import {get_string as getString} from 'core/str';
/**
* @property {Bool} initialised Whether the change checker has been initialised
* @private
*/
let initialised = false;
/**
* @property {String} warningString The warning string to show on form change failure
* @private
*/
let warningString;
/**
* @property {Array} watchedForms The list of watched forms
* @private
*/
let watchedForms = [];
/**
* @property {Bool} formChangeCheckerDisabled Whether the form change checker has been actively disabled
* @private
*/
let formChangeCheckerDisabled = false;
/**
* Get the nearest form element from a child element.
*
* @param {HTMLElement} formChild
* @returns {HTMLFormElement|null}
* @private
*/
const getFormFromChild = formChild => formChild.closest('form');
/**
* Watch the specified form for changes.
*
* @method
* @param {HTMLElement} formNode
*/
export const watchForm = formNode => {
// Normalise the formNode.
formNode = getFormFromChild(formNode);
if (!formNode) {
// No form found.
return;
}
if (isWatchingForm(formNode)) {
// This form is already watched.
return;
}
watchedForms.push(formNode);
};
/**
* Stop watching the specified form for changes.
*
* If the form was not watched, then no change is made.
*
* A child of the form may be passed instead.
*
* @method
* @param {HTMLElement} formNode
* @example <caption>Stop watching a form for changes</caption>
* import {unWatchForm} from 'core_form/changechecker';
*
* // ...
* document.addEventListener('click', e => {
* if (e.target.closest('[data-action="changePage"]')) {
* unWatchForm(e.target);
* }
* });
*/
export const unWatchForm = formNode => {
watchedForms = watchedForms.filter(watchedForm => !!watchedForm.contains(formNode));
};
/**
* Reset the 'dirty' flag for all watched forms.
*
* If a form was previously marked as 'dirty', then this flag will be cleared and when the page is unloaded no warning
* will be shown.
*
* @method
*/
export const resetAllFormDirtyStates = () => {
watchedForms.forEach(watchedForm => {
watchedForm.dataset.formSubmitted = "false";
watchedForm.dataset.formDirty = "false";
});
};
/**
* Reset the 'dirty' flag of the specified form.
*
* @method
* @param {HTMLElement} formNode
*/
export const resetFormDirtyState = formNode => {
formNode = getFormFromChild(formNode);
if (!formNode) {
return;
}
formNode.dataset.formSubmitted = "false";
formNode.dataset.formDirty = "false";
};
/**
* Mark all forms as dirty.
*
* This function is only for backwards-compliance with the old YUI module and should not be used in any other situation.
* It will be removed in Moodle 4.4.
*
* @method
*/
export const markAllFormsAsDirty = () => {
watchedForms.forEach(watchedForm => {
watchedForm.dataset.formDirty = "true";
});
};
/**
* Mark a specific form as dirty.
*
* This behaviour may be required for custom form elements which are not caught by the standard change listeners.
*
* @method
* @param {HTMLElement} formNode
*/
export const markFormAsDirty = formNode => {
formNode = getFormFromChild(formNode);
if (!formNode) {
return;
}
// Mark it as dirty.
formNode.dataset.formDirty = "true";
};
/**
* Actively disable the form change checker.
*
* Please note that it cannot be re-enabled once disabled.
*
* @method
*/
export const disableAllChecks = () => {
formChangeCheckerDisabled = true;
};
/**
* Check whether any watched from is dirty.
*
* @method
* @returns {Bool}
* @private
*/
const isAnyWatchedFormDirty = () => {
if (formChangeCheckerDisabled) {
// The form change checker is disabled.
return false;
}
const hasSubmittedForm = watchedForms.some(watchedForm => watchedForm.dataset.formSubmitted === "true");
if (hasSubmittedForm) {
// Do not warn about submitted forms, ever.
return false;
}
const hasDirtyForm = watchedForms.some(watchedForm => {
if (!watchedForm.isConnected) {
// The watched form is not connected to the DOM.
return false;
}
if (watchedForm.dataset.formDirty === "true") {
// The form has been marked as dirty.
return true;
}
// Elements currently holding focus will not have triggered change detection.
// Check whether the value matches the original value upon form load.
if (document.activeElement && document.activeElement.dataset.propertyIsEnumerable('initialValue')) {
const isActiveElementWatched = isWatchingForm(document.activeElement);
const hasValueChanged = document.activeElement.dataset.initialValue !== document.activeElement.value;
if (isActiveElementWatched && hasValueChanged) {
return true;
}
}
return false;
});
if (hasDirtyForm) {
// At least one form is dirty.
return true;
}
// Handle TinyMCE editor instances.
// TinyMCE forms may not have been initialised at the time that startWatching is called.
// Check whether any tinyMCE editor is dirty.
if (typeof window.tinyMCE !== 'undefined') {
if (window.tinyMCE.editors.some(editor => editor.isDirty())) {
return true;
}
}
// No dirty forms detected.
return false;
};
/**
* Get the watched form for the specified target.
*
* @method
* @param {HTMLNode} target
* @returns {HTMLFormElement}
* @private
*/
const getFormForNode = target => watchedForms.find(watchedForm => watchedForm.contains(target));
/**
* Whether the specified target is a watched form.
*
* @method
* @param {HTMLNode} target
* @returns {Bool}
* @private
*/
const isWatchingForm = target => watchedForms.some(watchedForm => watchedForm.contains(target));
/**
* Whether the specified target should ignore changes or not.
*
* @method
* @param {HTMLNode} target
* @returns {Bool}
* @private
*/
const shouldIgnoreChangesForNode = target => !!target.closest('.ignoredirty');
/**
* Mark a form as changed.
*
* @method
* @param {HTMLElement} changedNode An element in the form which was changed
*/
export const markFormChangedFromNode = changedNode => {
if (changedNode.dataset.formChangeCheckerOverride) {
// Changes to this form node disable the form change checker entirely.
// This is intended for select fields which cause an immediate redirect.
disableAllChecks();
return;
}
if (!isWatchingForm(changedNode)) {
return;
}
if (shouldIgnoreChangesForNode(changedNode)) {
return;
}
// Mark the form as dirty.
const formNode = getFormForNode(changedNode);
formNode.dataset.formDirty = "true";
};
/**
* Mark a form as submitted.
*
* @method
* @param {HTMLElement} formNode An element in the form to mark as submitted
*/
export const markFormSubmitted = formNode => {
formNode = getFormFromChild(formNode);
if (!formNode) {
return;
}
formNode.dataset.formSubmitted = "true";
};
/**
* Mark all forms as submitted.
*
* This function is only for backwards-compliance with the old YUI module and should not be used in any other situation.
* It will be removed in Moodle 4.4.
*
* @method
*/
export const markAllFormsSubmitted = () => {
watchedForms.forEach(watchedForm => markFormSubmitted(watchedForm));
};
/**
* Handle the beforeunload event.
*
* @method
* @param {Event} e
* @returns {string|null}
* @private
*/
const beforeUnloadHandler = e => {
// Please note: The use of Promises in this function is forbidden.
// This is an event handler and _cannot_ be asynchronous.
let warnBeforeUnload = isAnyWatchedFormDirty() && !M.cfg.behatsiterunning;
if (warnBeforeUnload) {
// According to the specification, to show the confirmation dialog an event handler should call preventDefault()
// on the event.
e.preventDefault();
// However note that not all browsers support this method, and some instead require the event handler to
// implement one of two legacy methods:
// * assigning a string to the event's returnValue property; and
// * returning a string from the event handler.
// Assigning a string to the event's returnValue property.
e.returnValue = warningString;
// Returning a string from the event handler.
return e.returnValue;
}
// Attaching an event handler/listener to window or document's beforeunload event prevents browsers from using
// in-memory page navigation caches, like Firefox's Back-Forward cache or WebKit's Page Cache.
// Remove the handler.
window.removeEventListener('beforeunload', beforeUnloadHandler);
return null;
};
/**
* Start watching for form changes.
*
* This function is called on module load, and should not normally be called.
*
* @method
* @protected
*/
export const startWatching = () => {
if (initialised) {
return;
}
// Add legacy support to provide b/c for the old YUI version.
addLegacyFunctions();
document.addEventListener('change', e => {
if (!isWatchingForm(e.target)) {
return;
}
markFormChangedFromNode(e.target);
});
document.addEventListener('click', e => {
const ignoredButton = e.target.closest('[data-formchangechecker-ignore-submit]');
if (!ignoredButton) {
return;
}
const ownerForm = getFormFromChild(e.target);
if (ownerForm) {
ownerForm.dataset.ignoreSubmission = "true";
}
});
document.addEventListener('focusin', e => {
if (e.target.matches('input, textarea, select')) {
if (e.target.dataset.propertyIsEnumerable('initialValue')) {
// The initial value has already been set.
return;
}
e.target.dataset.initialValue = e.target.value;
}
});
document.addEventListener('submit', e => {
const formNode = getFormFromChild(e.target);
if (!formNode) {
// Weird, but watch for this anyway.
return;
}
if (formNode.dataset.ignoreSubmission) {
// This form was submitted by a button which requested that the form checked should not mark it as submitted.
formNode.dataset.ignoreSubmission = "false";
return;
}
markFormSubmitted(formNode);
});
document.addEventListener(eventTypes.editorContentRestored, e => {
if (e.target != document) {
resetFormDirtyState(e.target);
} else {
resetAllFormDirtyStates();
}
});
getString('changesmadereallygoaway', 'moodle')
.then(changesMadeString => {
warningString = changesMadeString;
return;
})
.catch();
window.addEventListener('beforeunload', beforeUnloadHandler);
};
/**
* Add legacy functions for backwards compatability.
*
* @method
* @private
*/
const addLegacyFunctions = () => {
// Create a curried function to log use of the old function and provide detail on its replacement.
const getLoggedLegacyFallback = (oldFunctionName, newFunctionName, newFunction) => (...args) => {
window.console.warn(
`The moodle-core-formchangechecker has been deprecated ` +
`and replaced with core_form/changechecker. ` +
`The ${oldFunctionName} function has been replaced with ${newFunctionName}.`
);
newFunction(...args);
};
/* eslint-disable */
window.M.core_formchangechecker = {
init: getLoggedLegacyFallback('init', 'watchFormById', watchFormById),
reset_form_dirty_state: getLoggedLegacyFallback('reset_form_dirty_state', 'resetFormDirtyState', resetAllFormDirtyStates),
set_form_changed: getLoggedLegacyFallback('set_form_changed', 'markFormAsDirty', markAllFormsAsDirty),
set_form_submitted: getLoggedLegacyFallback('set_form_submitted', 'markFormSubmitted', markAllFormsSubmitted),
};
/* eslint-enable */
};
/**
* Watch the form matching the specified ID for changes.
*
* @method
* @param {String} formId
*/
export const watchFormById = formId => {
watchForm(document.getElementById(formId));
};
/**
* Reset the dirty state of the form matching the specified ID..
*
* @method
* @param {String} formId
*/
export const resetFormDirtyStateById = formId => {
resetFormDirtyState(document.getElementById(formId));
};
/**
* Mark the form matching the specified ID as dirty.
*
* @method
* @param {String} formId
*/
export const markFormAsDirtyById = formId => {
markFormAsDirty(document.getElementById(formId));
};
// Configure all event listeners.
startWatching();
+12 -23
View File
@@ -34,13 +34,13 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import Ajax from 'core/ajax';
import * as FormChangeChecker from 'core_form/changechecker';
import * as FormEvents from 'core_form/events';
import Ajax from 'core/ajax';
import Fragment from 'core/fragment';
import Notification from 'core/notification';
import Pending from 'core/pending';
import Templates from 'core/templates';
import Y from 'core/yui';
import {get_strings as getStrings} from 'core/str';
/**
@@ -261,18 +261,11 @@ export default class DynamicForm {
/**
* Notifies listeners that form dirty state should be reset.
*
* @return {Promise<unknown>}
* @fires event:formSubmittedByJavascript
*/
notifyResetFormChanges() {
FormEvents.notifyFormSubmittedByJavascript(this.getFormNode(), true);
return new Promise(resolve => {
Y.use('event', 'moodle-core-event', 'moodle-core-formchangechecker', () => {
M.core_formchangechecker.reset_form_dirty_state();
resolve();
});
});
FormChangeChecker.resetFormDirtyState(this.getFormNode());
}
/**
@@ -280,16 +273,13 @@ export default class DynamicForm {
*/
processCancelButton() {
// Notify listeners that the form is about to be submitted (this will reset atto autosave).
this.notifyResetFormChanges()
.then(() => {
const event = this.trigger(this.events.FORM_CANCELLED);
if (!event.defaultPrevented) {
// By default removes the form from the DOM.
this.container.innerHTML = '';
}
return null;
})
.catch(null);
this.notifyResetFormChanges();
const event = this.trigger(this.events.FORM_CANCELLED);
if (!event.defaultPrevented) {
// By default removes the form from the DOM.
this.container.innerHTML = '';
}
}
/**
@@ -373,9 +363,8 @@ export default class DynamicForm {
// Form was submitted properly.
const data = JSON.parse(response.data);
this.enableButtons();
this.notifyResetFormChanges()
.then(() => this.onSubmitSuccess(data))
.catch();
this.notifyResetFormChanges();
this.onSubmitSuccess(data);
}
return null;
})
+14 -29
View File
@@ -36,13 +36,13 @@
*/
import Ajax from 'core/ajax';
import * as FormChangeChecker from 'core_form/changechecker';
import * as FormEvents from 'core_form/events';
import Fragment from 'core/fragment';
import ModalEvents from 'core/modal_events';
import ModalFactory from 'core/modal_factory';
import Notification from 'core/notification';
import Pending from 'core/pending';
import Y from 'core/yui';
export default class ModalForm {
@@ -129,16 +129,12 @@ export default class ModalForm {
// After successfull submit, when we press "Cancel" or close the dialogue by clicking on X in the top right corner.
this.modal.getRoot().on(ModalEvents.hidden, () => {
this.notifyResetFormChanges()
.then(() => {
this.modal.destroy();
// Focus on the element that actually launched the modal.
if (this.config.returnFocus) {
this.config.returnFocus.focus();
}
return null;
})
.catch(() => null);
this.notifyResetFormChanges();
this.modal.destroy();
// Focus on the element that actually launched the modal.
if (this.config.returnFocus) {
this.config.returnFocus.focus();
}
});
// Add the class to the modal dialogue.
@@ -266,7 +262,6 @@ export default class ModalForm {
/**
* Notifies listeners that form dirty state should be reset.
*
* @return {Promise<unknown>}
* @fires event:formSubmittedByJavascript
*/
notifyResetFormChanges() {
@@ -274,17 +269,10 @@ export default class ModalForm {
FormEvents.notifyFormSubmittedByJavascript(this.getFormNode(), true);
if (!form) {
return Promise.resolve();
return;
}
return new Promise(resolve => {
Y.use('event', 'moodle-core-event', 'moodle-core-formchangechecker', () => {
// Ensure that modal contains a form element (it may not if the form class threw an early exception).
M.core_formchangechecker.reset_form_dirty_state();
resolve();
});
});
FormChangeChecker.resetFormDirtyState(this.getFormNode());
}
/**
@@ -388,14 +376,11 @@ export default class ModalForm {
} else {
// Form was submitted properly. Hide the modal and execute callback.
const data = JSON.parse(response.data);
return this.notifyResetFormChanges()
.then(() => {
const event = this.trigger(this.events.FORM_SUBMITTED, data);
if (!event.defaultPrevented) {
this.modal.hide();
}
return null;
});
this.notifyResetFormChanges();
const event = this.trigger(this.events.FORM_SUBMITTED, data);
if (!event.defaultPrevented) {
this.modal.hide();
}
}
return null;
})
+16 -17
View File
@@ -38,12 +38,21 @@
* this.options.itemid
*/
/* eslint camelcase: off */
M.form_filemanager = {templates:{}};
M.form_filemanager = {
templates: {},
formChangeChecker: null,
};
require(['core_form/changechecker'], function(FormChangeChecker) {
// This is a nasty, hacky, way of doing it but it's the smallest evil.
M.form_filemanager.formChangeChecker = FormChangeChecker;
});
M.form_filemanager.set_templates = function(Y, templates) {
M.form_filemanager.templates = templates;
}
};
/**
* This fucntion is called for each file picker on page.
@@ -199,9 +208,7 @@ M.form_filemanager.init = function(Y, options) {
this.filecount++;
this.check_buttons();
this.refresh(this.currentpath);
if (typeof M.core_formchangechecker != 'undefined') {
M.core_formchangechecker.set_form_changed();
}
M.form_filemanager.formChangeChecker.markFormChangedFromNode(this.filemanager.getDOMNode());
},
check_buttons: function() {
if (this.filecount>0) {
@@ -328,9 +335,7 @@ M.form_filemanager.init = function(Y, options) {
scope.mkdir_dialog.hide();
scope.refresh(filepath);
Y.one('#fm-newname-'+scope.client_id).set('value', '');
if (typeof M.core_formchangechecker != 'undefined') {
M.core_formchangechecker.set_form_changed();
}
M.form_filemanager.formChangeChecker.markFormChangedFromNode(scope.filemanager.getDOMNode());
}
});
};
@@ -460,9 +465,7 @@ M.form_filemanager.init = function(Y, options) {
if (obj && obj.length) {
args.scope.refresh(obj[0]);
}
if (typeof M.core_formchangechecker != 'undefined') {
M.core_formchangechecker.set_form_changed();
}
M.form_filemanager.formChangeChecker.markFormChangedFromNode(this.scope.filemanager.getDOMNode());
}
});
};
@@ -853,9 +856,7 @@ M.form_filemanager.init = function(Y, options) {
} else {
args.scope.selectui.hide();
args.scope.refresh((obj && obj.filepath) ? obj.filepath : '/');
if (typeof M.core_formchangechecker != 'undefined') {
M.core_formchangechecker.set_form_changed();
}
M.form_filemanager.formChangeChecker.markFormChangedFromNode(this.scope.filemanager.getDOMNode());
}
}
});
@@ -970,9 +971,7 @@ M.form_filemanager.init = function(Y, options) {
//args.scope.selectui.hide();
args.scope.filecount--;
args.scope.refresh(obj.filepath);
if (typeof M.core_formchangechecker != 'undefined') {
M.core_formchangechecker.set_form_changed();
}
M.form_filemanager.formChangeChecker.markFormChangedFromNode(this.scope.filemanager.getDOMNode());
}
});
};
+5 -9
View File
@@ -1615,7 +1615,7 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
*/
var $_disableShortforms = false;
/** @var bool whether to automatically initialise M.formchangechecker for this form. */
/** @var bool whether to automatically initialise the form change detector this form. */
protected $_use_form_change_checker = true;
/**
@@ -3135,14 +3135,10 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
}
if ($form->is_form_change_checker_enabled()) {
$PAGE->requires->yui_module('moodle-core-formchangechecker',
'M.core_formchangechecker.init',
array(array(
'formid' => $formid,
'initialdirtystate' => $form->is_dirty(),
))
);
$PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', [$formid]);
if ($form->is_dirty()) {
$PAGE->requires->js_call_amd('core_form/changechecker', 'markFormAsDirtyById', [$formid]);
}
}
if (!empty($this->_collapsibleElements)) {
if (count($this->_collapsibleElements) > 1) {
+71 -71
View File
@@ -242,84 +242,84 @@ M.util.show_confirm_dialog = function(e, args) {
e.preventDefault();
}
YUI().use('moodle-core-notification-confirm', function(Y) {
var confirmationDialogue = new M.core.confirm({
width: '300px',
center: true,
modal: true,
visible: false,
draggable: false,
title: M.util.get_string('confirmation', 'admin'),
noLabel: M.util.get_string('cancel', 'moodle'),
question: args.message
});
require(['core_form/changechecker'], function(FormChangeChecker) {
// eslint-disable-next-line no-undef, new-cap
YUI().use('moodle-core-notification-confirm', function(Y) {
var confirmationDialogue = new M.core.confirm({
width: '300px',
center: true,
modal: true,
visible: false,
draggable: false,
title: M.util.get_string('confirmation', 'admin'),
noLabel: M.util.get_string('cancel', 'moodle'),
question: args.message
});
// The dialogue was submitted with a positive value indication.
confirmationDialogue.on('complete-yes', function(e) {
// Handle any callbacks.
if (args.callback) {
if (!Y.Lang.isFunction(args.callback)) {
Y.log('Callbacks to show_confirm_dialog must now be functions. Please update your code to pass in a function instead.',
'warn', 'M.util.show_confirm_dialog');
return;
}
var scope = e.target;
if (Y.Lang.isObject(args.scope)) {
scope = args.scope;
}
var callbackargs = args.callbackargs || [];
args.callback.apply(scope, callbackargs);
return;
}
var targetancestor = null,
targetform = null;
if (target.test('a')) {
window.location = target.get('href');
} else if ((targetancestor = target.ancestor('a')) !== null) {
window.location = targetancestor.get('href');
} else if (target.test('input') || target.test('button')) {
targetform = target.ancestor('form', true);
if (!targetform) {
return;
}
if (target.get('name') && target.get('value')) {
targetform.append('<input type="hidden" name="' + target.get('name') +
'" value="' + target.get('value') + '">');
if (typeof M.core_formchangechecker !== 'undefined') {
M.core_formchangechecker.set_form_submitted();
// The dialogue was submitted with a positive value indication.
confirmationDialogue.on('complete-yes', function(e) {
// Handle any callbacks.
if (args.callback) {
if (!Y.Lang.isFunction(args.callback)) {
Y.log('Callbacks to show_confirm_dialog must now be functions. ' +
'Please update your code to pass in a function instead.',
'warn', 'M.util.show_confirm_dialog');
return;
}
}
targetform.submit();
} else if (target.test('form')) {
if (typeof M.core_formchangechecker !== 'undefined') {
M.core_formchangechecker.set_form_submitted();
}
target.submit();
var scope = e.target;
if (Y.Lang.isObject(args.scope)) {
scope = args.scope;
}
} else {
Y.log("Element of type " + target.get('tagName') +
" is not supported by the M.util.show_confirm_dialog function. Use A, INPUT, BUTTON or FORM",
'warn', 'javascript-static');
var callbackargs = args.callbackargs || [];
args.callback.apply(scope, callbackargs);
return;
}
var targetancestor = null,
targetform = null;
if (target.test('a')) {
window.location = target.get('href');
} else if ((targetancestor = target.ancestor('a')) !== null) {
window.location = targetancestor.get('href');
} else if (target.test('input') || target.test('button')) {
targetform = target.ancestor('form', true);
if (!targetform) {
return;
}
if (target.get('name') && target.get('value')) {
targetform.append('<input type="hidden" name="' + target.get('name') +
'" value="' + target.get('value') + '">');
FormChangeChecker.markFormAsDirty(targetform);
}
targetform.submit();
} else if (target.test('form')) {
FormChangeChecker.markFormAsDirty(target);
target.submit();
} else {
Y.log("Element of type " + target.get('tagName') +
" is not supported by the M.util.show_confirm_dialog function. Use A, INPUT, BUTTON or FORM",
'warn', 'javascript-static');
}
}, this);
if (args.cancellabel) {
confirmationDialogue.set('noLabel', args.cancellabel);
}
}, this);
if (args.cancellabel) {
confirmationDialogue.set('noLabel', args.cancellabel);
}
if (args.continuelabel) {
confirmationDialogue.set('yesLabel', args.continuelabel);
}
if (args.continuelabel) {
confirmationDialogue.set('yesLabel', args.continuelabel);
}
confirmationDialogue.render()
.show();
confirmationDialogue.render()
.show();
});
});
};
-2
View File
@@ -4220,8 +4220,6 @@ EOD;
'page' => $this->page
);
}
$this->page->requires->string_for_js('changesmadereallygoaway', 'moodle');
}
} else {
$heading = null;
+2
View File
@@ -58,6 +58,8 @@ information provided here is intended especially for developers.
completion_info::internal_set_data() to reaggregate completions that have been marked for instant course completion.
* The following functions have been finally deprecated and can not be used anymore:
- generate_uuid
* The YUI moodle-core-formchangechecker module has been deprecated and replaced with a new AMD module
core_form/changechecker.
=== 3.11.2 ===
* For security reasons, filelib has been updated so all requests now use emulated redirects.
@@ -9,247 +9,64 @@ YUI.add('moodle-core-formchangechecker', function (Y, NAME) {
/**
* A utility to check for form changes before navigating away from a page.
*
* To initialise, call M.core_formchangechecker.init({formid: 'myform'}); or perhaps
*
* Y.use('moodle-core-formchangechecker', function() {
* M.core_formchangechecker.init({formid: 'myform'});
* });
*
* If you have some fields in your form that you don't want to have tracked, then add
* a data-formchangechecker-ignore-dirty to the field, or any parent element, and it
* will be ignored.
*
* If you have a submit button in your form that does not actually save the data,
* then add a data-formchangechecker-ignore-submit attribute to it.
* Please note that this YUI module has been deprecated in favour of the core_form/changechecker AMD module.
*
* @class M.core.formchangechecker
* @constructor
* @deprecated
*/
var FORMCHANGECHECKERNAME = 'core-formchangechecker',
FORMCHANGECHECKER = function() {
FORMCHANGECHECKER.superclass.constructor.apply(this, arguments);
};
Y.extend(FORMCHANGECHECKER, Y.Base, {
// The delegated listeners we need to detach after the initial value has been stored once
initialvaluelisteners: [],
/**
* Initialize the module
*
* @method initializer
*/
initializer: function() {
var formid = 'form#' + this.get('formid'),
currentform = Y.one(formid);
if (!currentform) {
// If the form was not found, then we can't check for changes.
return;
}
if (!M.core_formchangechecker.stateinformation.formchanged) {
M.core_formchangechecker.stateinformation.formchanged = this.get('initialdirtystate');
}
// Add a listener here for an editor restore event.
Y.on(M.core.event.EDITOR_CONTENT_RESTORED, M.core_formchangechecker.reset_form_dirty_state, this);
// Add change events to the form elements
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'input', this);
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'textarea', this);
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'select', this);
// Add a focus event to check for changes which are made without triggering a change event
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'input', this));
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'textarea', this));
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'select', this));
currentform.delegate('click', function() {
currentform.setData('ignoreSubmission', true);
}, '[data-formchangechecker-ignore-submit]');
// We need any submit buttons on the form to set the submitted flag.
Y.one(formid).on('submit', function() {
if (currentform.getData('ignoreSubmission')) {
// But not if we have been told to ignore this button.
currentform.clearData('ignoreSubmission');
return;
}
M.core_formchangechecker.set_form_submitted();
}, this);
// YUI doesn't support onbeforeunload properly so we must use the DOM to set the onbeforeunload. As
// a result, the has_changed must stay in the DOM too
window.onbeforeunload = M.core_formchangechecker.report_form_dirty_state;
},
/**
* Store the initial value of the currently focussed element
*
* If an element has been focussed and changed but not yet blurred, the on change
* event won't be fired. We need to store it's initial value to compare it in the
* get_form_dirty_state function later.
*
* @method store_initial_value
* @param {EventFacade} e
*/
store_initial_value: function(e) {
var thisevent;
// Don't warn on elements we have been told to ignore.
if (e.target.ancestor('.ignoredirty', true) ||
e.target.ancestor('[data-formchangechecker-ignore-dirty]', true)) {
return;
}
if (M.core_formchangechecker.get_form_dirty_state()) {
// Detach all listen events to prevent duplicate initial value setting
while (this.initialvaluelisteners.length) {
thisevent = this.initialvaluelisteners.shift();
thisevent.detach();
}
return;
}
// Make a note of the current element so that it can be interrogated and
// compared in the get_form_dirty_state function
M.core_formchangechecker.stateinformation.focused_element = {
element: e.target,
initial_value: e.target.get('value')
};
}
},
{
NAME: FORMCHANGECHECKERNAME,
ATTRS: {
formid: {
'value': ''
},
initialdirtystate: {
'value': false
}
}
}
window.console.warn(
'The moodle-core-formchangechecker has been deprecated ' +
'and replaced with core_form/changechecker. ' +
'Please update your code to make use of the new module.'
);
M.core_formchangechecker = M.core_formchangechecker || {};
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.startWatching();
});
// We might have multiple instances of the form change protector
M.core_formchangechecker.instances = M.core_formchangechecker.instances || [];
M.core_formchangechecker.init = function(config) {
var formchangechecker = new FORMCHANGECHECKER(config);
M.core_formchangechecker.instances.push(formchangechecker);
return formchangechecker;
};
// The following are provided to prevent race conditions.
// Because the AMD module is loaded asynchronously after the YUI module is loaded, there is a possibility that the
// calling code may call the YUI function calls before the AMD module has finished loading.
// These will be removed in future and are automatically overwritten by the legacy helper provided as part of the new
// changechecker AMD module.
// eslint-disable-next-line camelcase
M.core_formchangechecker = M.core_formchangechecker || {
init: function(config) {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.watchFormById(config.formid);
});
},
// Store state information
M.core_formchangechecker.stateinformation = [];
/**
* Set the form changed state to true
*/
// eslint-disable-next-line camelcase
set_form_changed: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.markAllFormsAsDirty();
});
},
/*
* Set the form changed state to true
*/
M.core_formchangechecker.set_form_changed = function(e) {
// Don't warn on elements we have been told to ignore.
if (e && e.target && (e.target.ancestor('.ignoredirty', true) ||
e.target.ancestor('[data-formchangechecker-ignore-dirty]', true))) {
return;
}
/**
* Set the form submitted state to true
*/
// eslint-disable-next-line camelcase
set_form_submitted: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.markAllFormsSubmitted();
});
},
M.core_formchangechecker.stateinformation.formchanged = 1;
// Once the form has been marked as dirty, we no longer need to keep track of form elements
// which haven't yet blurred
delete M.core_formchangechecker.stateinformation.focused_element;
};
/*
* Set the form submitted state to true
*/
M.core_formchangechecker.set_form_submitted = function() {
M.core_formchangechecker.stateinformation.formsubmitted = 1;
};
/*
* Attempt to determine whether the form has been modified in any way and
* is thus 'dirty'
*
* @return Integer 1 is the form is dirty; 0 if not
*/
M.core_formchangechecker.get_form_dirty_state = function() {
var state = M.core_formchangechecker.stateinformation,
editor;
// If the form was submitted, then return a non-dirty state
if (state.formsubmitted) {
return 0;
}
// If any fields have been marked dirty, return a dirty state
if (state.formchanged) {
return 1;
}
// If a field has been focused and changed, but still has focus then the browser won't fire the
// onChange event. We check for this eventuality here
if (state.focused_element) {
if (state.focused_element.element.get('value') !== state.focused_element.initial_value) {
return 1;
}
}
// Handle TinyMCE editor instances
// We can't add a listener in the initializer as the editors may not have been created by that point
// so we do so here instead
if (typeof window.tinyMCE !== 'undefined') {
for (editor in window.tinyMCE.editors) {
if (window.tinyMCE.editors[editor].isDirty()) {
return 1;
}
}
}
// If we reached here, then the form hasn't met any of the dirty conditions
return 0;
};
/*
* Reset the form state
*/
M.core_formchangechecker.reset_form_dirty_state = function() {
M.core_formchangechecker.stateinformation.formsubmitted = false;
M.core_formchangechecker.stateinformation.formchanged = false;
};
/*
* Return a suitable message if changes have been made to a form
*/
M.core_formchangechecker.report_form_dirty_state = function(e) {
if (!M.core_formchangechecker.get_form_dirty_state()) {
// the form is not dirty, so don't display any message
return;
}
// This is the error message that we'll show to browsers which support it
var warningmessage = M.util.get_string('changesmadereallygoaway', 'moodle');
if (M.cfg.behatsiterunning) {
// If the behat site is running we don't want browser alerts.
return;
}
// Most browsers are happy with the returnValue being set on the event
// But some browsers do not consistently pass the event
if (e) {
e.returnValue = warningmessage;
}
// But some require it to be returned instead
return warningmessage;
/**
* Reset the form state
*/
// eslint-disable-next-line camelcase
reset_form_dirty_state: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.resetAllFormDirtyStates();
});
},
};
@@ -1 +1 @@
YUI.add("moodle-core-formchangechecker",function(r,e){var c=function(){c.superclass.constructor.apply(this,arguments)};r.extend(c,r.Base,{initialvaluelisteners:[],initializer:function(){var e="form#"+this.get("formid"),t=r.one(e);t&&(M.core_formchangechecker.stateinformation.formchanged||(M.core_formchangechecker.stateinformation.formchanged=this.get("initialdirtystate")),r.on(M.core.event.EDITOR_CONTENT_RESTORED,M.core_formchangechecker.reset_form_dirty_state,this),t.delegate("change",M.core_formchangechecker.set_form_changed,"input",this),t.delegate("change",M.core_formchangechecker.set_form_changed,"textarea",this),t.delegate("change",M.core_formchangechecker.set_form_changed,"select",this),this.initialvaluelisteners.push(t.delegate("focus",this.store_initial_value,"input",this)),this.initialvaluelisteners.push(t.delegate("focus",this.store_initial_value,"textarea",this)),this.initialvaluelisteners.push(t.delegate("focus",this.store_initial_value,"select",this)),t.delegate("click",function(){t.setData("ignoreSubmission",!0)},"[data-formchangechecker-ignore-submit]"),r.one(e).on("submit",function(){t.getData("ignoreSubmission")?t.clearData("ignoreSubmission"):M.core_formchangechecker.set_form_submitted()},this),window.onbeforeunload=M.core_formchangechecker.report_form_dirty_state)},store_initial_value:function(e){if(!e.target.ancestor(".ignoredirty",!0)&&!e.target.ancestor("[data-formchangechecker-ignore-dirty]",!0))if(M.core_formchangechecker.get_form_dirty_state())for(;this.initialvaluelisteners.length;)this.initialvaluelisteners.shift().detach();else M.core_formchangechecker.stateinformation.focused_element={element:e.target,initial_value:e.target.get("value")}}},{NAME:"core-formchangechecker",ATTRS:{formid:{value:""},initialdirtystate:{value:!1}}}),M.core_formchangechecker=M.core_formchangechecker||{},M.core_formchangechecker.instances=M.core_formchangechecker.instances||[],M.core_formchangechecker.init=function(e){var t=new c(e);return M.core_formchangechecker.instances.push(t),t},M.core_formchangechecker.stateinformation=[],M.core_formchangechecker.set_form_changed=function(e){e&&e.target&&(e.target.ancestor(".ignoredirty",!0)||e.target.ancestor("[data-formchangechecker-ignore-dirty]",!0))||(M.core_formchangechecker.stateinformation.formchanged=1,delete M.core_formchangechecker.stateinformation.focused_element)},M.core_formchangechecker.set_form_submitted=function(){M.core_formchangechecker.stateinformation.formsubmitted=1},M.core_formchangechecker.get_form_dirty_state=function(){var e,t=M.core_formchangechecker.stateinformation;if(t.formsubmitted)return 0;if(t.formchanged)return 1;if(t.focused_element&&t.focused_element.element.get("value")!==t.focused_element.initial_value)return 1;if("undefined"!=typeof window.tinyMCE)for(e in window.tinyMCE.editors)if(window.tinyMCE.editors[e].isDirty())return 1;return 0},M.core_formchangechecker.reset_form_dirty_state=function(){M.core_formchangechecker.stateinformation.formsubmitted=!1,M.core_formchangechecker.stateinformation.formchanged=!1},M.core_formchangechecker.report_form_dirty_state=function(e){if(M.core_formchangechecker.get_form_dirty_state()){var t=M.util.get_string("changesmadereallygoaway","moodle");if(!M.cfg.behatsiterunning)return e&&(e.returnValue=t),t}}},"@VERSION@",{requires:["base","event-focus","moodle-core-event"]});
YUI.add("moodle-core-formchangechecker",function(e,r){window.console.warn("The moodle-core-formchangechecker has been deprecated and replaced with core_form/changechecker. Please update your code to make use of the new module."),require(["core_form/changechecker"],function(e){e.startWatching()}),M.core_formchangechecker=M.core_formchangechecker||{init:function(r){require(["core_form/changechecker"],function(e){e.watchFormById(r.formid)})},set_form_changed:function(){require(["core_form/changechecker"],function(e){e.markAllFormsAsDirty()})},set_form_submitted:function(){require(["core_form/changechecker"],function(e){e.markAllFormsSubmitted()})},reset_form_dirty_state:function(){require(["core_form/changechecker"],function(e){e.resetAllFormDirtyStates()})}}},"@VERSION@",{requires:["base","event-focus","moodle-core-event"]});
@@ -9,247 +9,64 @@ YUI.add('moodle-core-formchangechecker', function (Y, NAME) {
/**
* A utility to check for form changes before navigating away from a page.
*
* To initialise, call M.core_formchangechecker.init({formid: 'myform'}); or perhaps
*
* Y.use('moodle-core-formchangechecker', function() {
* M.core_formchangechecker.init({formid: 'myform'});
* });
*
* If you have some fields in your form that you don't want to have tracked, then add
* a data-formchangechecker-ignore-dirty to the field, or any parent element, and it
* will be ignored.
*
* If you have a submit button in your form that does not actually save the data,
* then add a data-formchangechecker-ignore-submit attribute to it.
* Please note that this YUI module has been deprecated in favour of the core_form/changechecker AMD module.
*
* @class M.core.formchangechecker
* @constructor
* @deprecated
*/
var FORMCHANGECHECKERNAME = 'core-formchangechecker',
FORMCHANGECHECKER = function() {
FORMCHANGECHECKER.superclass.constructor.apply(this, arguments);
};
Y.extend(FORMCHANGECHECKER, Y.Base, {
// The delegated listeners we need to detach after the initial value has been stored once
initialvaluelisteners: [],
/**
* Initialize the module
*
* @method initializer
*/
initializer: function() {
var formid = 'form#' + this.get('formid'),
currentform = Y.one(formid);
if (!currentform) {
// If the form was not found, then we can't check for changes.
return;
}
if (!M.core_formchangechecker.stateinformation.formchanged) {
M.core_formchangechecker.stateinformation.formchanged = this.get('initialdirtystate');
}
// Add a listener here for an editor restore event.
Y.on(M.core.event.EDITOR_CONTENT_RESTORED, M.core_formchangechecker.reset_form_dirty_state, this);
// Add change events to the form elements
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'input', this);
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'textarea', this);
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'select', this);
// Add a focus event to check for changes which are made without triggering a change event
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'input', this));
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'textarea', this));
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'select', this));
currentform.delegate('click', function() {
currentform.setData('ignoreSubmission', true);
}, '[data-formchangechecker-ignore-submit]');
// We need any submit buttons on the form to set the submitted flag.
Y.one(formid).on('submit', function() {
if (currentform.getData('ignoreSubmission')) {
// But not if we have been told to ignore this button.
currentform.clearData('ignoreSubmission');
return;
}
M.core_formchangechecker.set_form_submitted();
}, this);
// YUI doesn't support onbeforeunload properly so we must use the DOM to set the onbeforeunload. As
// a result, the has_changed must stay in the DOM too
window.onbeforeunload = M.core_formchangechecker.report_form_dirty_state;
},
/**
* Store the initial value of the currently focussed element
*
* If an element has been focussed and changed but not yet blurred, the on change
* event won't be fired. We need to store it's initial value to compare it in the
* get_form_dirty_state function later.
*
* @method store_initial_value
* @param {EventFacade} e
*/
store_initial_value: function(e) {
var thisevent;
// Don't warn on elements we have been told to ignore.
if (e.target.ancestor('.ignoredirty', true) ||
e.target.ancestor('[data-formchangechecker-ignore-dirty]', true)) {
return;
}
if (M.core_formchangechecker.get_form_dirty_state()) {
// Detach all listen events to prevent duplicate initial value setting
while (this.initialvaluelisteners.length) {
thisevent = this.initialvaluelisteners.shift();
thisevent.detach();
}
return;
}
// Make a note of the current element so that it can be interrogated and
// compared in the get_form_dirty_state function
M.core_formchangechecker.stateinformation.focused_element = {
element: e.target,
initial_value: e.target.get('value')
};
}
},
{
NAME: FORMCHANGECHECKERNAME,
ATTRS: {
formid: {
'value': ''
},
initialdirtystate: {
'value': false
}
}
}
window.console.warn(
'The moodle-core-formchangechecker has been deprecated ' +
'and replaced with core_form/changechecker. ' +
'Please update your code to make use of the new module.'
);
M.core_formchangechecker = M.core_formchangechecker || {};
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.startWatching();
});
// We might have multiple instances of the form change protector
M.core_formchangechecker.instances = M.core_formchangechecker.instances || [];
M.core_formchangechecker.init = function(config) {
var formchangechecker = new FORMCHANGECHECKER(config);
M.core_formchangechecker.instances.push(formchangechecker);
return formchangechecker;
};
// The following are provided to prevent race conditions.
// Because the AMD module is loaded asynchronously after the YUI module is loaded, there is a possibility that the
// calling code may call the YUI function calls before the AMD module has finished loading.
// These will be removed in future and are automatically overwritten by the legacy helper provided as part of the new
// changechecker AMD module.
// eslint-disable-next-line camelcase
M.core_formchangechecker = M.core_formchangechecker || {
init: function(config) {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.watchFormById(config.formid);
});
},
// Store state information
M.core_formchangechecker.stateinformation = [];
/**
* Set the form changed state to true
*/
// eslint-disable-next-line camelcase
set_form_changed: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.markAllFormsAsDirty();
});
},
/*
* Set the form changed state to true
*/
M.core_formchangechecker.set_form_changed = function(e) {
// Don't warn on elements we have been told to ignore.
if (e && e.target && (e.target.ancestor('.ignoredirty', true) ||
e.target.ancestor('[data-formchangechecker-ignore-dirty]', true))) {
return;
}
/**
* Set the form submitted state to true
*/
// eslint-disable-next-line camelcase
set_form_submitted: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.markAllFormsSubmitted();
});
},
M.core_formchangechecker.stateinformation.formchanged = 1;
// Once the form has been marked as dirty, we no longer need to keep track of form elements
// which haven't yet blurred
delete M.core_formchangechecker.stateinformation.focused_element;
};
/*
* Set the form submitted state to true
*/
M.core_formchangechecker.set_form_submitted = function() {
M.core_formchangechecker.stateinformation.formsubmitted = 1;
};
/*
* Attempt to determine whether the form has been modified in any way and
* is thus 'dirty'
*
* @return Integer 1 is the form is dirty; 0 if not
*/
M.core_formchangechecker.get_form_dirty_state = function() {
var state = M.core_formchangechecker.stateinformation,
editor;
// If the form was submitted, then return a non-dirty state
if (state.formsubmitted) {
return 0;
}
// If any fields have been marked dirty, return a dirty state
if (state.formchanged) {
return 1;
}
// If a field has been focused and changed, but still has focus then the browser won't fire the
// onChange event. We check for this eventuality here
if (state.focused_element) {
if (state.focused_element.element.get('value') !== state.focused_element.initial_value) {
return 1;
}
}
// Handle TinyMCE editor instances
// We can't add a listener in the initializer as the editors may not have been created by that point
// so we do so here instead
if (typeof window.tinyMCE !== 'undefined') {
for (editor in window.tinyMCE.editors) {
if (window.tinyMCE.editors[editor].isDirty()) {
return 1;
}
}
}
// If we reached here, then the form hasn't met any of the dirty conditions
return 0;
};
/*
* Reset the form state
*/
M.core_formchangechecker.reset_form_dirty_state = function() {
M.core_formchangechecker.stateinformation.formsubmitted = false;
M.core_formchangechecker.stateinformation.formchanged = false;
};
/*
* Return a suitable message if changes have been made to a form
*/
M.core_formchangechecker.report_form_dirty_state = function(e) {
if (!M.core_formchangechecker.get_form_dirty_state()) {
// the form is not dirty, so don't display any message
return;
}
// This is the error message that we'll show to browsers which support it
var warningmessage = M.util.get_string('changesmadereallygoaway', 'moodle');
if (M.cfg.behatsiterunning) {
// If the behat site is running we don't want browser alerts.
return;
}
// Most browsers are happy with the returnValue being set on the event
// But some browsers do not consistently pass the event
if (e) {
e.returnValue = warningmessage;
}
// But some require it to be returned instead
return warningmessage;
/**
* Reset the form state
*/
// eslint-disable-next-line camelcase
reset_form_dirty_state: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.resetAllFormDirtyStates();
});
},
};
+51 -234
View File
@@ -7,245 +7,62 @@
/**
* A utility to check for form changes before navigating away from a page.
*
* To initialise, call M.core_formchangechecker.init({formid: 'myform'}); or perhaps
*
* Y.use('moodle-core-formchangechecker', function() {
* M.core_formchangechecker.init({formid: 'myform'});
* });
*
* If you have some fields in your form that you don't want to have tracked, then add
* a data-formchangechecker-ignore-dirty to the field, or any parent element, and it
* will be ignored.
*
* If you have a submit button in your form that does not actually save the data,
* then add a data-formchangechecker-ignore-submit attribute to it.
* Please note that this YUI module has been deprecated in favour of the core_form/changechecker AMD module.
*
* @class M.core.formchangechecker
* @constructor
* @deprecated
*/
var FORMCHANGECHECKERNAME = 'core-formchangechecker',
FORMCHANGECHECKER = function() {
FORMCHANGECHECKER.superclass.constructor.apply(this, arguments);
};
Y.extend(FORMCHANGECHECKER, Y.Base, {
// The delegated listeners we need to detach after the initial value has been stored once
initialvaluelisteners: [],
/**
* Initialize the module
*
* @method initializer
*/
initializer: function() {
var formid = 'form#' + this.get('formid'),
currentform = Y.one(formid);
if (!currentform) {
// If the form was not found, then we can't check for changes.
return;
}
if (!M.core_formchangechecker.stateinformation.formchanged) {
M.core_formchangechecker.stateinformation.formchanged = this.get('initialdirtystate');
}
// Add a listener here for an editor restore event.
Y.on(M.core.event.EDITOR_CONTENT_RESTORED, M.core_formchangechecker.reset_form_dirty_state, this);
// Add change events to the form elements
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'input', this);
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'textarea', this);
currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'select', this);
// Add a focus event to check for changes which are made without triggering a change event
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'input', this));
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'textarea', this));
this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'select', this));
currentform.delegate('click', function() {
currentform.setData('ignoreSubmission', true);
}, '[data-formchangechecker-ignore-submit]');
// We need any submit buttons on the form to set the submitted flag.
Y.one(formid).on('submit', function() {
if (currentform.getData('ignoreSubmission')) {
// But not if we have been told to ignore this button.
currentform.clearData('ignoreSubmission');
return;
}
M.core_formchangechecker.set_form_submitted();
}, this);
// YUI doesn't support onbeforeunload properly so we must use the DOM to set the onbeforeunload. As
// a result, the has_changed must stay in the DOM too
window.onbeforeunload = M.core_formchangechecker.report_form_dirty_state;
},
/**
* Store the initial value of the currently focussed element
*
* If an element has been focussed and changed but not yet blurred, the on change
* event won't be fired. We need to store it's initial value to compare it in the
* get_form_dirty_state function later.
*
* @method store_initial_value
* @param {EventFacade} e
*/
store_initial_value: function(e) {
var thisevent;
// Don't warn on elements we have been told to ignore.
if (e.target.ancestor('.ignoredirty', true) ||
e.target.ancestor('[data-formchangechecker-ignore-dirty]', true)) {
return;
}
if (M.core_formchangechecker.get_form_dirty_state()) {
// Detach all listen events to prevent duplicate initial value setting
while (this.initialvaluelisteners.length) {
thisevent = this.initialvaluelisteners.shift();
thisevent.detach();
}
return;
}
// Make a note of the current element so that it can be interrogated and
// compared in the get_form_dirty_state function
M.core_formchangechecker.stateinformation.focused_element = {
element: e.target,
initial_value: e.target.get('value')
};
}
},
{
NAME: FORMCHANGECHECKERNAME,
ATTRS: {
formid: {
'value': ''
},
initialdirtystate: {
'value': false
}
}
}
window.console.warn(
'The moodle-core-formchangechecker has been deprecated ' +
'and replaced with core_form/changechecker. ' +
'Please update your code to make use of the new module.'
);
M.core_formchangechecker = M.core_formchangechecker || {};
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.startWatching();
});
// We might have multiple instances of the form change protector
M.core_formchangechecker.instances = M.core_formchangechecker.instances || [];
M.core_formchangechecker.init = function(config) {
var formchangechecker = new FORMCHANGECHECKER(config);
M.core_formchangechecker.instances.push(formchangechecker);
return formchangechecker;
};
// Store state information
M.core_formchangechecker.stateinformation = [];
/*
* Set the form changed state to true
*/
M.core_formchangechecker.set_form_changed = function(e) {
// Don't warn on elements we have been told to ignore.
if (e && e.target && (e.target.ancestor('.ignoredirty', true) ||
e.target.ancestor('[data-formchangechecker-ignore-dirty]', true))) {
return;
}
M.core_formchangechecker.stateinformation.formchanged = 1;
// Once the form has been marked as dirty, we no longer need to keep track of form elements
// which haven't yet blurred
delete M.core_formchangechecker.stateinformation.focused_element;
};
/*
* Set the form submitted state to true
*/
M.core_formchangechecker.set_form_submitted = function() {
M.core_formchangechecker.stateinformation.formsubmitted = 1;
};
/*
* Attempt to determine whether the form has been modified in any way and
* is thus 'dirty'
*
* @return Integer 1 is the form is dirty; 0 if not
*/
M.core_formchangechecker.get_form_dirty_state = function() {
var state = M.core_formchangechecker.stateinformation,
editor;
// If the form was submitted, then return a non-dirty state
if (state.formsubmitted) {
return 0;
}
// If any fields have been marked dirty, return a dirty state
if (state.formchanged) {
return 1;
}
// If a field has been focused and changed, but still has focus then the browser won't fire the
// onChange event. We check for this eventuality here
if (state.focused_element) {
if (state.focused_element.element.get('value') !== state.focused_element.initial_value) {
return 1;
}
}
// Handle TinyMCE editor instances
// We can't add a listener in the initializer as the editors may not have been created by that point
// so we do so here instead
if (typeof window.tinyMCE !== 'undefined') {
for (editor in window.tinyMCE.editors) {
if (window.tinyMCE.editors[editor].isDirty()) {
return 1;
}
}
}
// If we reached here, then the form hasn't met any of the dirty conditions
return 0;
};
/*
* Reset the form state
*/
M.core_formchangechecker.reset_form_dirty_state = function() {
M.core_formchangechecker.stateinformation.formsubmitted = false;
M.core_formchangechecker.stateinformation.formchanged = false;
};
/*
* Return a suitable message if changes have been made to a form
*/
M.core_formchangechecker.report_form_dirty_state = function(e) {
if (!M.core_formchangechecker.get_form_dirty_state()) {
// the form is not dirty, so don't display any message
return;
}
// This is the error message that we'll show to browsers which support it
var warningmessage = M.util.get_string('changesmadereallygoaway', 'moodle');
if (M.cfg.behatsiterunning) {
// If the behat site is running we don't want browser alerts.
return;
}
// Most browsers are happy with the returnValue being set on the event
// But some browsers do not consistently pass the event
if (e) {
e.returnValue = warningmessage;
}
// But some require it to be returned instead
return warningmessage;
// The following are provided to prevent race conditions.
// Because the AMD module is loaded asynchronously after the YUI module is loaded, there is a possibility that the
// calling code may call the YUI function calls before the AMD module has finished loading.
// These will be removed in future and are automatically overwritten by the legacy helper provided as part of the new
// changechecker AMD module.
// eslint-disable-next-line camelcase
M.core_formchangechecker = M.core_formchangechecker || {
init: function(config) {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.watchFormById(config.formid);
});
},
/**
* Set the form changed state to true
*/
// eslint-disable-next-line camelcase
set_form_changed: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.markAllFormsAsDirty();
});
},
/**
* Set the form submitted state to true
*/
// eslint-disable-next-line camelcase
set_form_submitted: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.markAllFormsSubmitted();
});
},
/**
* Reset the form state
*/
// eslint-disable-next-line camelcase
reset_form_dirty_state: function() {
require(['core_form/changechecker'], function(ChangeChecker) {
ChangeChecker.resetAllFormDirtyStates();
});
},
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("mod_assign/override_form",["exports","jquery"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(a,c){var d=document.getElementById(a),e=d.querySelector("[name=\"".concat(c,"\"]"));(0,b.default)(e).on("change",function(){var a=document.createElement("input");a.setAttribute("type","hidden");a.setAttribute("name","userchange");a.setAttribute("value",!0);d.appendChild(a);if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.reset_form_dirty_state()}d.submit()})};a.init=c});
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("mod_assign/override_form",["exports","jquery","core_form/changechecker"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);c=e(c);function d(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;d=function(){return a};return a}function e(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=d();if(b&&b.has(a)){return b.get(a)}var c={},e=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in a){if(Object.prototype.hasOwnProperty.call(a,f)){var g=e?Object.getOwnPropertyDescriptor(a,f):null;if(g&&(g.get||g.set)){Object.defineProperty(c,f,g)}else{c[f]=a[f]}}}c.default=a;if(b){b.set(a,c)}return c}var f=function(a,d){var e=document.getElementById(a),f=e.querySelector("[name=\"".concat(d,"\"]"));(0,b.default)(f).on("change",function(){var a=document.createElement("input");a.setAttribute("type","hidden");a.setAttribute("name","userchange");a.setAttribute("value",!0);e.appendChild(a);c.markFormSubmitted(a);e.submit()})};a.init=f});
//# sourceMappingURL=override_form.min.js.map
@@ -1 +1 @@
{"version":3,"sources":["../src/override_form.js"],"names":["init","formId","selectElementName","form","document","getElementById","selectElement","querySelector","on","inputElement","createElement","setAttribute","appendChild","M","core_formchangechecker","reset_form_dirty_state","submit"],"mappings":"kJAsBA,uDAEO,GAAMA,CAAAA,CAAI,CAAG,SAACC,CAAD,CAASC,CAAT,CAA+B,IACzCC,CAAAA,CAAI,CAAGC,QAAQ,CAACC,cAAT,CAAwBJ,CAAxB,CADkC,CAEzCK,CAAa,CAAGH,CAAI,CAACI,aAAL,mBAA6BL,CAA7B,QAFyB,CAI/C,cAAEI,CAAF,EAAiBE,EAAjB,CAAoB,QAApB,CAA8B,UAAM,CAChC,GAAMC,CAAAA,CAAY,CAAGL,QAAQ,CAACM,aAAT,CAAuB,OAAvB,CAArB,CACAD,CAAY,CAACE,YAAb,CAA0B,MAA1B,CAAkC,QAAlC,EACAF,CAAY,CAACE,YAAb,CAA0B,MAA1B,CAAkC,YAAlC,EACAF,CAAY,CAACE,YAAb,CAA0B,OAA1B,KAEAR,CAAI,CAACS,WAAL,CAAiBH,CAAjB,EAEA,GAAwC,WAApC,QAAOI,CAAAA,CAAC,CAACC,sBAAb,CAAqD,CACjDD,CAAC,CAACC,sBAAF,CAAyBC,sBAAzB,EACH,CAEDZ,CAAI,CAACa,MAAL,EACH,CAbD,CAcH,CAlBM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to enhance the override form.\n *\n * @copyright 2019 Ryan Wyllie <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\n\nexport const init = (formId, selectElementName) => {\n const form = document.getElementById(formId);\n const selectElement = form.querySelector(`[name=\"${selectElementName}\"]`);\n\n $(selectElement).on('change', () => {\n const inputElement = document.createElement('input');\n inputElement.setAttribute('type', 'hidden');\n inputElement.setAttribute('name', 'userchange');\n inputElement.setAttribute('value', true);\n\n form.appendChild(inputElement);\n\n if (typeof M.core_formchangechecker !== 'undefined') {\n M.core_formchangechecker.reset_form_dirty_state();\n }\n\n form.submit();\n });\n};"],"file":"override_form.min.js"}
{"version":3,"sources":["../src/override_form.js"],"names":["init","formId","selectElementName","form","document","getElementById","selectElement","querySelector","on","inputElement","createElement","setAttribute","appendChild","FormChangeChecker","markFormSubmitted","submit"],"mappings":"idAsBA,uDACA,O,siBAEO,GAAMA,CAAAA,CAAI,CAAG,SAACC,CAAD,CAASC,CAAT,CAA+B,IACzCC,CAAAA,CAAI,CAAGC,QAAQ,CAACC,cAAT,CAAwBJ,CAAxB,CADkC,CAEzCK,CAAa,CAAGH,CAAI,CAACI,aAAL,mBAA6BL,CAA7B,QAFyB,CAI/C,cAAEI,CAAF,EAAiBE,EAAjB,CAAoB,QAApB,CAA8B,UAAM,CAChC,GAAMC,CAAAA,CAAY,CAAGL,QAAQ,CAACM,aAAT,CAAuB,OAAvB,CAArB,CACAD,CAAY,CAACE,YAAb,CAA0B,MAA1B,CAAkC,QAAlC,EACAF,CAAY,CAACE,YAAb,CAA0B,MAA1B,CAAkC,YAAlC,EACAF,CAAY,CAACE,YAAb,CAA0B,OAA1B,KAEAR,CAAI,CAACS,WAAL,CAAiBH,CAAjB,EAEAI,CAAiB,CAACC,iBAAlB,CAAoCL,CAApC,EAEAN,CAAI,CAACY,MAAL,EACH,CAXD,CAYH,CAhBM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to enhance the override form.\n *\n * @copyright 2019 Ryan Wyllie <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport * as FormChangeChecker from 'core_form/changechecker';\n\nexport const init = (formId, selectElementName) => {\n const form = document.getElementById(formId);\n const selectElement = form.querySelector(`[name=\"${selectElementName}\"]`);\n\n $(selectElement).on('change', () => {\n const inputElement = document.createElement('input');\n inputElement.setAttribute('type', 'hidden');\n inputElement.setAttribute('name', 'userchange');\n inputElement.setAttribute('value', true);\n\n form.appendChild(inputElement);\n\n FormChangeChecker.markFormSubmitted(inputElement);\n\n form.submit();\n });\n};\n"],"file":"override_form.min.js"}
+42 -15
View File
@@ -22,11 +22,32 @@
* @since 3.1
*/
define([
'jquery', 'core/yui', 'core/notification', 'core/templates', 'core/fragment',
'core/ajax', 'core/str', 'mod_assign/grading_form_change_checker',
'mod_assign/grading_events', 'core_form/events', 'core/toast'
],
function($, Y, notification, templates, fragment, ajax, str, checker, GradingEvents, FormEvents, Toast) {
'jquery',
'core/yui',
'core/notification',
'core/templates',
'core/fragment',
'core/ajax',
'core/str',
'mod_assign/grading_form_change_checker',
'mod_assign/grading_events',
'core_form/events',
'core/toast',
'core_form/changechecker',
], function(
$,
Y,
notification,
templates,
fragment,
ajax,
str,
checker,
GradingEvents,
FormEvents,
Toast,
FormChangeChecker
) {
/**
* GradingPanel class.
@@ -120,6 +141,9 @@ function($, Y, notification, templates, fragment, ajax, str, checker, GradingEve
$('[data-region="overlay"]').show();
// Mark the form as submitted in the change checker.
FormChangeChecker.markFormSubmitted(form[0]);
// We call this, so other modules can update the form with the latest state.
form.trigger('save-form-state');
@@ -145,9 +169,9 @@ function($, Y, notification, templates, fragment, ajax, str, checker, GradingEve
* @private
* @method _handleFormSubmissionResponse
* @param {Array} formdata - submitted values
* @param {Integer} nextUserId - optional. The id of the user to load after the form is saved.
* @param {Number} [nextUserId] The id of the user to load after the form is saved
* @param {Boolean} [nextUser] - Whether to switch to next user in the grading list.
* @param {Array} response List of errors.
* @param {Boolean} nextUser - optional. If true, switch to next user in the grading list.
*/
GradingPanel.prototype._handleFormSubmissionResponse = function(formdata, nextUserId, nextUser, response) {
if (typeof nextUserId === "undefined") {
@@ -158,14 +182,17 @@ function($, Y, notification, templates, fragment, ajax, str, checker, GradingEve
// validation errors.
$(document).trigger('reset', [this._lastUserId, formdata]);
} else {
str.get_strings([
{key: 'gradechangessaveddetail', component: 'mod_assign'},
]).done(function(strs) {
Toast.add(strs[0]);
}).fail(notification.exception);
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
str.get_string('gradechangessaveddetail', 'mod_assign')
.then(function(str) {
Toast.add(str);
return str;
})
.catch(notification.exception);
// Reset the form state.
var form = $(this._region.find('form.gradeform'));
FormChangeChecker.resetFormDirtyState(form[0]);
if (nextUserId == this._lastUserId) {
$(document).trigger('reset', nextUserId);
} else if (nextUser) {
+3 -4
View File
@@ -21,6 +21,7 @@
*/
import $ from 'jquery';
import * as FormChangeChecker from 'core_form/changechecker';
export const init = (formId, selectElementName) => {
const form = document.getElementById(formId);
@@ -34,10 +35,8 @@ export const init = (formId, selectElementName) => {
form.appendChild(inputElement);
if (typeof M.core_formchangechecker !== 'undefined') {
M.core_formchangechecker.reset_form_dirty_state();
}
FormChangeChecker.markFormSubmitted(inputElement);
form.submit();
});
};
};
+11 -6
View File
@@ -71,12 +71,17 @@ class feedback_edit_use_template_form extends moodleform {
$options[get_string('public', 'feedback')] = $publicoptions;
}
$attributes = 'onChange="M.core_formchangechecker.set_form_submitted(); this.form.submit()"';
$elementgroup[] = $mform->createElement('selectgroups',
'templateid',
get_string('using_templates', 'feedback'),
$options,
$attributes);
$attributes = [
'onChange="this.form.submit()"',
'data-form-change-checker-override="1"',
];
$elementgroup[] = $mform->createElement(
'selectgroups',
'templateid',
get_string('using_templates', 'feedback'),
$options,
implode(' ', $attributes)
);
$elementgroup[] = $mform->createElement('submit',
'use_template',
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("mod_forum/inpage_reply",["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,f){var g={NESTED_V2:4,THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},h={POST_CREATED:"mod_forum-post-created"},i={MOODLE:0},j=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer),d=a.outerWidth();a.css("width",d);b.addClass("hidden");c.removeClass("hidden")},k=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer);a.css("width","");b.removeClass("hidden");c.addClass("hidden")},l=function(l){l.on("click",f.post.inpageSubmitBtn,function(m){m.preventDefault();var e=a(m.currentTarget),n=e.parent().find(f.post.inpageReplyButton),o=e.parents(f.post.inpageReplyForm).get(0),p=o.elements.post.value.trim(),q=i.MOODLE,r=o.elements.reply.value,s=o.elements.subject.value,t=e.closest(f.post.post),u=o.elements.privatereply!=void 0?o.elements.privatereply.checked:!1,v=l.find(f.post.modeSelect),w=v.length?parseInt(v.get(0).value):null,x;if(p.length){j(e);n.prop("disabled",!0);d.addDiscussionPost(r,s,p,q,u,!0).then(function(a){var b=a.messages.reduce(function(a,b){if("success"==b.type){a+="<p>"+b.message+"</p>"}return a},"");c.addNotification({message:b,type:"success"});return a}).then(function(a){o.reset();var c=a.post;x=c.id;switch(w){case g.NESTED_V2:var d=c.capabilities,e=t.children().not(f.post.repliesContainer).find(f.post.authorName).text();c.parentauthorname=e;c.showactionmenu=d.view||d.controlreadstatus||d.edit||d.split||d.delete||d.export||c.urls.viewparent;return b.render("mod_forum/forum_discussion_nested_v2_post_reply",c);case g.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case g.NESTED:return b.render("mod_forum/forum_discussion_nested_post",c);default:return b.render("mod_forum/forum_discussion_post",c);}}).then(function(a,c){var d=t.find(f.post.repliesContainer).first();if(w==g.FLAT_NEWEST_FIRST){return b.prependNodeContents(d,a,c)}else{return b.appendNodeContents(d,a,c)}}).then(function(){e.trigger(h.POST_CREATED,x);k(e);n.prop("disabled",!1);if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.reset_form_dirty_state()}return t.find(f.post.inpageReplyContent).hide()}).then(function(){location.href="#p"+x}).catch(function(a){k(e);n.prop("disabled",!1);return c.exception(a)})}})};return{init:function init(a){l(a)},CONTENT_FORMATS:i,EVENTS:h}});
define ("mod_forum/inpage_reply",["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors","core_form/changechecker"],function(a,b,c,d,f,g){var h={NESTED_V2:4,THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},i={POST_CREATED:"mod_forum-post-created"},j={MOODLE:0},k=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer),d=a.outerWidth();a.css("width",d);b.addClass("hidden");c.removeClass("hidden")},l=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer);a.css("width","");b.removeClass("hidden");c.addClass("hidden")},m=function(m){m.on("click",f.post.inpageSubmitBtn,function(n){n.preventDefault();var e=a(n.currentTarget),o=e.parent().find(f.post.inpageReplyButton),p=e.parents(f.post.inpageReplyForm).get(0),q=p.elements.post.value.trim(),r=j.MOODLE,s=p.elements.reply.value,t=p.elements.subject.value,u=e.closest(f.post.post),v=p.elements.privatereply!=void 0?p.elements.privatereply.checked:!1,w=m.find(f.post.modeSelect),x=w.length?parseInt(w.get(0).value):null,y;if(q.length){k(e);o.prop("disabled",!0);d.addDiscussionPost(s,t,q,r,v,!0).then(function(a){var b=a.messages.reduce(function(a,b){if("success"==b.type){a+="<p>"+b.message+"</p>"}return a},"");c.addNotification({message:b,type:"success"});return a}).then(function(a){p.reset();var c=a.post;y=c.id;switch(x){case h.NESTED_V2:var d=c.capabilities,e=u.children().not(f.post.repliesContainer).find(f.post.authorName).text();c.parentauthorname=e;c.showactionmenu=d.view||d.controlreadstatus||d.edit||d.split||d.delete||d.export||c.urls.viewparent;return b.render("mod_forum/forum_discussion_nested_v2_post_reply",c);case h.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case h.NESTED:return b.render("mod_forum/forum_discussion_nested_post",c);default:return b.render("mod_forum/forum_discussion_post",c);}}).then(function(a,c){var d=u.find(f.post.repliesContainer).first();if(x==h.FLAT_NEWEST_FIRST){return b.prependNodeContents(d,a,c)}else{return b.appendNodeContents(d,a,c)}}).then(function(){e.trigger(i.POST_CREATED,y);l(e);o.prop("disabled",!1);g.resetFormDirtyState(e[0]);return u.find(f.post.inpageReplyContent).hide()}).then(function(){location.href="#p"+y}).catch(function(a){l(e);o.prop("disabled",!1);return c.exception(a)})}})};return{init:function init(a){m(a)},CONTENT_FORMATS:j,EVENTS:i}});
//# sourceMappingURL=inpage_reply.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("mod_forum/posts_list",["jquery","core/templates","core/notification","core/pending","core/yui","mod_forum/selectors","mod_forum/inpage_reply"],function(a,b,c,d,e,f,g){var h=function(h){h.on("click",f.post.inpageReplyLink,function(h){h.preventDefault();if(window.location.hash){var i=window.location.href.split("#")[0];history.pushState({},document.title,i)}var j=new d("inpage-reply"),k=a(h.currentTarget).parents(f.post.forumCoreContent),l=k.find(f.post.forumSubject),m=a(h.currentTarget).parents(f.post.forumContent),n={postid:a(m).data("post-id"),reply_url:a(h.currentTarget).attr("href"),sesskey:M.cfg.sesskey,parentsubject:l.data("replySubject"),canreplyprivately:a(h.currentTarget).data("can-reply-privately"),postformat:g.CONTENT_FORMATS.MOODLE};if(!m.find(f.post.inpageReplyContent).length){b.render("mod_forum/inpage_reply",n).then(function(a,c){return b.appendNodeContents(k,a,c)}).then(function(){return m.find(f.post.inpageReplyContent).slideToggle(300,j.resolve).find("textarea").focus()}).then(function(){e.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.init({formid:"inpage-reply-".concat(n.postid)})})}).fail(c.exception)}else{var o=m.find(f.post.inpageReplyContent);o.slideToggle(300,j.resolve);if(o.is(":visible")){o.find("textarea").focus()}}})};return{init:function init(a){h(a);g.init(a)}}});
define ("mod_forum/posts_list",["jquery","core/templates","core/notification","core/pending","mod_forum/selectors","mod_forum/inpage_reply","core_form/changechecker"],function(a,b,c,d,f,g,h){var i=function(e){e.on("click",f.post.inpageReplyLink,function(i){i.preventDefault();if(window.location.hash){var e=window.location.href.split("#")[0];history.pushState({},document.title,e)}var j=new d("inpage-reply"),k=a(i.currentTarget).parents(f.post.forumCoreContent),l=k.find(f.post.forumSubject),m=a(i.currentTarget).parents(f.post.forumContent),n={postid:a(m).data("post-id"),reply_url:a(i.currentTarget).attr("href"),sesskey:M.cfg.sesskey,parentsubject:l.data("replySubject"),canreplyprivately:a(i.currentTarget).data("can-reply-privately"),postformat:g.CONTENT_FORMATS.MOODLE};if(!m.find(f.post.inpageReplyContent).length){b.render("mod_forum/inpage_reply",n).then(function(a,c){return b.appendNodeContents(k,a,c)}).then(function(){return m.find(f.post.inpageReplyContent).slideToggle(300,j.resolve).find("textarea").focus()}).then(function(){h.watchFormById("inpage-reply-".concat(n.postid))}).catch(c.exception)}else{var o=m.find(f.post.inpageReplyContent);o.slideToggle(300,j.resolve);if(o.is(":visible")){o.find("textarea").focus()}}})};return{init:function init(a){i(a);g.init(a)}}});
//# sourceMappingURL=posts_list.min.js.map
File diff suppressed because one or more lines are too long
+2 -14
View File
@@ -23,6 +23,7 @@
import $ from 'jquery';
import AutoRows from 'core/auto_rows';
import CustomEvents from 'core/custom_interaction_events';
import * as FormChangeChecker from 'core_form/changechecker';
import Notification from 'core/notification';
import Templates from 'core/templates';
import Discussion from 'mod_forum/discussion';
@@ -247,20 +248,7 @@ const buildShowInPageReplyFormFunction = (additionalTemplateContext) => {
Notification.exception(e);
}
// Load formchangechecker module.
import('core/yui')
.then(Y => {
return new Promise(resolve => {
Y.use('moodle-core-formchangechecker', Y => {
resolve(Y);
});
});
})
.then(Y => {
M.core_formchangechecker.init({formid: Y.one(postContainer[0].querySelector('form')).generateID()});
return Y;
})
.catch();
FormChangeChecker.watchForm(postContainer[0].querySelector('form'));
}
inPageReplyCreateButton.fadeOut(ANIMATION_DURATION, () => {
+15 -15
View File
@@ -21,18 +21,20 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/templates',
'core/notification',
'mod_forum/repository',
'mod_forum/selectors',
], function(
$,
Templates,
Notification,
Repository,
Selectors
) {
'jquery',
'core/templates',
'core/notification',
'mod_forum/repository',
'mod_forum/selectors',
'core_form/changechecker',
], function(
$,
Templates,
Notification,
Repository,
Selectors,
FormChangeChecker
) {
var DISPLAYCONSTANTS = {
NESTED_V2: 4,
@@ -170,9 +172,7 @@ define([
allButtons.prop('disabled', false);
// Tell formchangechecker we submitted the form.
if (typeof M.core_formchangechecker !== 'undefined') {
M.core_formchangechecker.reset_form_dirty_state();
}
FormChangeChecker.resetFormDirtyState(submitButton[0]);
return currentRoot.find(Selectors.post.inpageReplyContent).hide();
})
+18 -21
View File
@@ -25,22 +25,22 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/templates',
'core/notification',
'core/pending',
'core/yui',
'mod_forum/selectors',
'mod_forum/inpage_reply',
], function(
$,
Templates,
Notification,
Pending,
Y,
Selectors,
InPageReply
) {
'jquery',
'core/templates',
'core/notification',
'core/pending',
'mod_forum/selectors',
'mod_forum/inpage_reply',
'core_form/changechecker',
], function(
$,
Templates,
Notification,
Pending,
Selectors,
InPageReply,
FormChangeChecker
) {
var registerEventListeners = function(root) {
root.on('click', Selectors.post.inpageReplyLink, function(e) {
@@ -78,13 +78,10 @@ define([
.slideToggle(300, pending.resolve).find('textarea').focus();
})
.then(function() {
// Load formchangechecker module.
Y.use('moodle-core-formchangechecker', () => {
M.core_formchangechecker.init({formid: `inpage-reply-${context.postid}`});
});
FormChangeChecker.watchFormById(`inpage-reply-${context.postid}`);
return;
})
.fail(Notification.exception);
.catch(Notification.exception);
} else {
var form = currentRoot.find(Selectors.post.inpageReplyContent);
form.slideToggle(300, pending.resolve);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3 -5
View File
@@ -25,9 +25,9 @@ import $ from 'jquery';
import Popper from 'core/popper';
import CustomEvents from 'core/custom_interaction_events';
import Selectors from 'forumreport_summary/selectors';
import Y from 'core/yui';
import Ajax from 'core/ajax';
import KeyCodes from 'core/key_codes';
import * as FormChangeChecker from 'core_form/changechecker';
export const init = (root) => {
let jqRoot = $(root);
@@ -131,9 +131,7 @@ export const init = (root) => {
// Submit report via filter
const submitWithFilter = (containerelement) => {
// Disable the dates filter mform checker to prevent any changes triggering a warning to the user.
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
FormChangeChecker.unWatchForm(document.forms.filtersform);
// Close the container (eg popover).
$(containerelement).addClass('hidden');
@@ -349,7 +347,7 @@ export const init = (root) => {
let fromTimestamp = 0,
toTimestamp = 0;
result['timestamps'].forEach(function(data){
result.timestamps.forEach(function(data) {
if (data.key === 'from') {
fromTimestamp = data.timestamp;
} else if (data.key === 'to') {
+1 -1
View File
@@ -1,2 +1,2 @@
define ("mod_quiz/modal_add_random_question",["jquery","core/yui","core/notification","core/modal","core/modal_events","core/modal_registry","core/fragment","core/templates"],function(a,b,c,d,e,f,g,h){var i=!1,j={EXISTING_CATEGORY_CONTAINER:"[data-region=\"existing-category-container\"]",EXISTING_CATEGORY_FORM_ELEMENT:"#id_existingcategoryheader",NEW_CATEGORY_CONTAINER:"[data-region=\"new-category-container\"]",NEW_CATEGORY_FORM_ELEMENT:"#id_newcategoryheader",TAB_CONTENT:"[data-region=\"tab-content\"]",ADD_ON_PAGE_FORM_ELEMENT:"[name=\"addonpage\"]",SUBMIT_BUTTON_ELEMENT:"input[type=\"submit\"]",CANCEL_BUTTON_ELEMENT:"input[type=\"submit\"][name=\"cancel\"]",FORM_HEADER:"legend",BUTTON_CONTAINER:".fitem"},k=function(a){d.call(this,a);this.contextId=null;this.addOnPageId=null;this.category=null;this.returnUrl=null;this.cmid=null;this.loadedForm=!1};k.TYPE="mod_quiz-quiz-add-random-question";k.prototype=Object.create(d.prototype);k.prototype.constructor=k;k.prototype.setContextId=function(a){this.contextId=a};k.prototype.getContextId=function(){return this.contextId};k.prototype.setAddOnPageId=function(a){this.addOnPageId=a;this.getBody().find(j.ADD_ON_PAGE_FORM_ELEMENT).val(a)};k.prototype.getAddOnPageId=function(){return this.addOnPageId};k.prototype.setCategory=function(a){this.category=a};k.prototype.getCategory=function(){return this.category};k.prototype.setReturnUrl=function(a){this.returnUrl=a};k.prototype.getReturnUrl=function(){return this.returnUrl};k.prototype.setCMID=function(a){this.cmid=a};k.prototype.getCMID=function(){return this.cmid};k.prototype.moveFormElementIntoTab=function(b,c){var d=b.find(j.SUBMIT_BUTTON_ELEMENT),e=a("<div class=\"modal-footer mt-1\" data-region=\"footer\"></div>");b.find(j.FORM_HEADER).addClass("hidden");b.wrap(c);d.closest(j.BUTTON_CONTAINER).remove();d.appendTo(e);e.appendTo(b)};k.prototype.moveTabsIntoTabContent=function(a){var b=this.getBody().find(j.TAB_CONTENT).empty();a.find("[role=\"tabpanel\"]").wrapAll(b)};k.prototype.moveCancelButtonToTabs=function(a){var b=a.find(j.CANCEL_BUTTON_ELEMENT).addClass("ml-1"),c=a.find("[data-region=\"footer\"]");b.closest(j.BUTTON_CONTAINER).remove();b.clone().appendTo(c)};k.prototype.loadForm=function(){return g.loadFragment("mod_quiz","add_random_question_form",this.getContextId(),{addonpage:this.getAddOnPageId(),cat:this.getCategory(),returnurl:this.getReturnUrl(),cmid:this.getCMID()}).then(function(b,c){var d=a(b),e=d.find(j.EXISTING_CATEGORY_FORM_ELEMENT),f=this.getBody().find(j.EXISTING_CATEGORY_CONTAINER),g=d.find(j.NEW_CATEGORY_FORM_ELEMENT),i=this.getBody().find(j.NEW_CATEGORY_CONTAINER);this.moveFormElementIntoTab(e,f);this.moveFormElementIntoTab(g,i);this.moveTabsIntoTabContent(d);this.moveCancelButtonToTabs(d);h.replaceNode(this.getBody().find(j.TAB_CONTENT),d,c)}.bind(this)).then(function(){b.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()})}).fail(c.exception)};k.prototype.show=function(){d.prototype.show.call(this);if(!this.loadedForm){this.loadForm();this.loadedForm=!0}};if(!i){f.register(k.TYPE,k,"mod_quiz/modal_add_random_question");i=!0}return k});
define ("mod_quiz/modal_add_random_question",["jquery","core/notification","core/modal","core/modal_events","core/modal_registry","core/fragment","core/templates","core_form/changechecker"],function(a,b,c,d,e,f,g,h){var i=!1,j={EXISTING_CATEGORY_CONTAINER:"[data-region=\"existing-category-container\"]",EXISTING_CATEGORY_FORM_ELEMENT:"#id_existingcategoryheader",NEW_CATEGORY_CONTAINER:"[data-region=\"new-category-container\"]",NEW_CATEGORY_FORM_ELEMENT:"#id_newcategoryheader",TAB_CONTENT:"[data-region=\"tab-content\"]",ADD_ON_PAGE_FORM_ELEMENT:"[name=\"addonpage\"]",SUBMIT_BUTTON_ELEMENT:"input[type=\"submit\"]",CANCEL_BUTTON_ELEMENT:"input[type=\"submit\"][name=\"cancel\"]",FORM_HEADER:"legend",BUTTON_CONTAINER:".fitem"},k=function(a){c.call(this,a);this.contextId=null;this.addOnPageId=null;this.category=null;this.returnUrl=null;this.cmid=null;this.loadedForm=!1};k.TYPE="mod_quiz-quiz-add-random-question";k.prototype=Object.create(c.prototype);k.prototype.constructor=k;k.prototype.setContextId=function(a){this.contextId=a};k.prototype.getContextId=function(){return this.contextId};k.prototype.setAddOnPageId=function(a){this.addOnPageId=a;this.getBody().find(j.ADD_ON_PAGE_FORM_ELEMENT).val(a)};k.prototype.getAddOnPageId=function(){return this.addOnPageId};k.prototype.setCategory=function(a){this.category=a};k.prototype.getCategory=function(){return this.category};k.prototype.setReturnUrl=function(a){this.returnUrl=a};k.prototype.getReturnUrl=function(){return this.returnUrl};k.prototype.setCMID=function(a){this.cmid=a};k.prototype.getCMID=function(){return this.cmid};k.prototype.moveFormElementIntoTab=function(b,c){var d=b.find(j.SUBMIT_BUTTON_ELEMENT),e=a("<div class=\"modal-footer mt-1\" data-region=\"footer\"></div>");b.find(j.FORM_HEADER).addClass("hidden");b.wrap(c);d.closest(j.BUTTON_CONTAINER).remove();d.appendTo(e);e.appendTo(b)};k.prototype.moveTabsIntoTabContent=function(a){var b=this.getBody().find(j.TAB_CONTENT).empty();a.find("[role=\"tabpanel\"]").wrapAll(b)};k.prototype.moveCancelButtonToTabs=function(a){var b=a.find(j.CANCEL_BUTTON_ELEMENT).addClass("ml-1"),c=a.find("[data-region=\"footer\"]");b.closest(j.BUTTON_CONTAINER).remove();b.clone().appendTo(c)};k.prototype.loadForm=function(){return f.loadFragment("mod_quiz","add_random_question_form",this.getContextId(),{addonpage:this.getAddOnPageId(),cat:this.getCategory(),returnurl:this.getReturnUrl(),cmid:this.getCMID()}).then(function(b,c){var d=a(b),e=d.find(j.EXISTING_CATEGORY_FORM_ELEMENT),f=this.getBody().find(j.EXISTING_CATEGORY_CONTAINER),h=d.find(j.NEW_CATEGORY_FORM_ELEMENT),i=this.getBody().find(j.NEW_CATEGORY_CONTAINER);this.moveFormElementIntoTab(e,f);this.moveFormElementIntoTab(h,i);this.moveTabsIntoTabContent(d);this.moveCancelButtonToTabs(d);g.replaceNode(this.getBody().find(j.TAB_CONTENT),d,c)}.bind(this)).then(function(){h.disableAllChecks()}).fail(b.exception)};k.prototype.show=function(){c.prototype.show.call(this);if(!this.loadedForm){this.loadForm();this.loadedForm=!0}};if(!i){e.register(k.TYPE,k,"mod_quiz/modal_add_random_question");i=!0}return k});
//# sourceMappingURL=modal_add_random_question.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("mod_quiz/modal_quiz_question_bank",["jquery","core/yui","core/notification","core/modal","core/modal_events","core/modal_registry","core/fragment"],function(a,b,c,d,e,f,g){var h=!1,i={ADD_TO_QUIZ_CONTAINER:"td.addtoquizaction",ANCHOR:"a[href]",PREVIEW_CONTAINER:"td.previewaction",SEARCH_OPTIONS:"#advancedsearch",DISPLAY_OPTIONS:"#displayoptions",ADD_QUESTIONS_FORM:"form[action=\"edit.php\"]"},j=function(a){d.call(this,a);this.contextId=null;this.addOnPageId=null};j.TYPE="mod_quiz-quiz-question-bank";j.prototype=Object.create(d.prototype);j.prototype.constructor=j;j.prototype.setContextId=function(a){this.contextId=a};j.prototype.getContextId=function(){return this.contextId};j.prototype.setAddOnPageId=function(a){this.addOnPageId=a};j.prototype.getAddOnPageId=function(){return this.addOnPageId};j.prototype.show=function(){this.reloadBodyContent(window.location.search);return d.prototype.show.call(this)};j.prototype.reloadBodyContent=function(a){var b=g.loadFragment("mod_quiz","quiz_question_bank",this.getContextId(),{querystring:a}).fail(c.exception);this.setBody(b)};j.prototype.handleAddToQuizEvent=function(a,b){var c=b.attr("href")+"&addonpage="+this.getAddOnPageId();b.attr("href",c)};j.prototype.handlePreviewContainerEvent=function(a,b){window.openpopup(a,{url:b.attr("href"),name:"questionpreview",options:["height=600","width=800","top=0","left=0","menubar=0","location=0","scrollbars","resizable","toolbar","status","directories=0","fullscreen=0","dependent"].join(",")})};j.prototype.handleDisplayOptionFormEvent=function(b){b.stopPropagation();b.preventDefault();var c=a(b.target).closest(i.DISPLAY_OPTIONS),d="?"+c.serialize();this.reloadBodyContent(d)};j.prototype.registerDisplayOptionListeners=function(){this.getModal().on("change",i.DISPLAY_OPTIONS,function(b){var c=a(b.target);if(c.attr("aria-autocomplete")){return}this.handleDisplayOptionFormEvent(b)}.bind(this));this.getModal().on("submit",i.DISPLAY_OPTIONS,function(a){this.handleDisplayOptionFormEvent(a)}.bind(this))};j.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this);this.registerDisplayOptionListeners();this.getModal().on("submit",i.ADD_QUESTIONS_FORM,function(b){var c=a(b.currentTarget);a("<input />").attr("type","hidden").attr("name","addonpage").attr("value",this.getAddOnPageId()).appendTo(c)}.bind(this));this.getModal().on("click",i.ANCHOR,function(b){var c=a(b.currentTarget);if(c.closest(i.ADD_TO_QUIZ_CONTAINER).length){this.handleAddToQuizEvent(b,c);return}if(c.closest(i.PREVIEW_CONTAINER).length){this.handlePreviewContainerEvent(b,c);return}if(c.closest(i.SEARCH_OPTIONS).length){return}b.preventDefault();this.reloadBodyContent(c.prop("search"))}.bind(this));this.getRoot().on(e.bodyRendered,function(){b.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()})})};if(!h){f.register(j.TYPE,j,"core/modal");h=!0}return j});
define ("mod_quiz/modal_quiz_question_bank",["jquery","core/notification","core/modal","core/modal_events","core/modal_registry","core/fragment","core_form/changechecker"],function(a,b,c,d,e,f,g){var h=!1,i={ADD_TO_QUIZ_CONTAINER:"td.addtoquizaction",ANCHOR:"a[href]",PREVIEW_CONTAINER:"td.previewaction",SEARCH_OPTIONS:"#advancedsearch",DISPLAY_OPTIONS:"#displayoptions",ADD_QUESTIONS_FORM:"form[action=\"edit.php\"]"},j=function(a){c.call(this,a);this.contextId=null;this.addOnPageId=null};j.TYPE="mod_quiz-quiz-question-bank";j.prototype=Object.create(c.prototype);j.prototype.constructor=j;j.prototype.setContextId=function(a){this.contextId=a};j.prototype.getContextId=function(){return this.contextId};j.prototype.setAddOnPageId=function(a){this.addOnPageId=a};j.prototype.getAddOnPageId=function(){return this.addOnPageId};j.prototype.show=function(){this.reloadBodyContent(window.location.search);return c.prototype.show.call(this)};j.prototype.reloadBodyContent=function(a){var c=f.loadFragment("mod_quiz","quiz_question_bank",this.getContextId(),{querystring:a}).fail(b.exception);this.setBody(c)};j.prototype.handleAddToQuizEvent=function(a,b){var c=b.attr("href")+"&addonpage="+this.getAddOnPageId();b.attr("href",c)};j.prototype.handlePreviewContainerEvent=function(a,b){window.openpopup(a,{url:b.attr("href"),name:"questionpreview",options:["height=600","width=800","top=0","left=0","menubar=0","location=0","scrollbars","resizable","toolbar","status","directories=0","fullscreen=0","dependent"].join(",")})};j.prototype.handleDisplayOptionFormEvent=function(b){b.stopPropagation();b.preventDefault();var c=a(b.target).closest(i.DISPLAY_OPTIONS),d="?"+c.serialize();this.reloadBodyContent(d)};j.prototype.registerDisplayOptionListeners=function(){this.getModal().on("change",i.DISPLAY_OPTIONS,function(b){var c=a(b.target);if(c.attr("aria-autocomplete")){return}this.handleDisplayOptionFormEvent(b)}.bind(this));this.getModal().on("submit",i.DISPLAY_OPTIONS,function(a){this.handleDisplayOptionFormEvent(a)}.bind(this))};j.prototype.registerEventListeners=function(){c.prototype.registerEventListeners.call(this);this.registerDisplayOptionListeners();this.getModal().on("submit",i.ADD_QUESTIONS_FORM,function(b){var c=a(b.currentTarget);a("<input />").attr("type","hidden").attr("name","addonpage").attr("value",this.getAddOnPageId()).appendTo(c)}.bind(this));this.getModal().on("click",i.ANCHOR,function(b){var c=a(b.currentTarget);if(c.closest(i.ADD_TO_QUIZ_CONTAINER).length){this.handleAddToQuizEvent(b,c);return}if(c.closest(i.PREVIEW_CONTAINER).length){this.handlePreviewContainerEvent(b,c);return}if(c.closest(i.SEARCH_OPTIONS).length){return}b.preventDefault();this.reloadBodyContent(c.prop("search"))}.bind(this));this.getRoot().on(d.bodyRendered,function(){g.disableAllChecks()})};if(!h){e.register(j.TYPE,j,"core/modal");h=!0}return j});
//# sourceMappingURL=modal_quiz_question_bank.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("mod_quiz/preflightcheck",["jquery","core/yui"],function(a,b){var c={confirmDialogue:null,init:function init(a,d,e,f){var g=a;b.use("moodle-core-notification",function(){if(b.one(e)){c.confirmDialogue=new M.core.dialogue({headerContent:d,bodyContent:b.one(e),draggable:!0,visible:!1,center:!0,modal:!0,width:null,extraClasses:["mod_quiz_preflight_popup"]});b.one(a).on("click",c.displayDialogue);b.one("#id_cancel").on("click",c.hideDialogue);g=c.confirmDialogue.get("boundingBox").one("[name=\"submitbutton\"]")}if(f){b.one(g).on("click",c.launchQuizPopup,c,f)}})},displayDialogue:function displayDialogue(a){if(a){a.halt()}c.confirmDialogue.show()},hideDialogue:function hideDialogue(a){if(a){a.halt()}c.confirmDialogue.hide(a)},launchQuizPopup:function launchQuizPopup(a,c){a.halt();b.use("moodle-core-formchangechecker","io-form",function(){M.core_formchangechecker.reset_form_dirty_state();var d=a.target.ancestor("form");window.openpopup(a,{url:d.get("action")+"?"+b.IO.stringify(d).replace(/\bcancel=/,"x="),windowname:"quizpopup",options:c,fullscreen:!0})})}};return c});
define ("mod_quiz/preflightcheck",["jquery","core/yui","core_form/changechecker"],function(a,b,c){var d={confirmDialogue:null,init:function init(a,c,e,f){var g=a;b.use("moodle-core-notification",function(){if(b.one(e)){d.confirmDialogue=new M.core.dialogue({headerContent:c,bodyContent:b.one(e),draggable:!0,visible:!1,center:!0,modal:!0,width:null,extraClasses:["mod_quiz_preflight_popup"]});b.one(a).on("click",d.displayDialogue);b.one("#id_cancel").on("click",d.hideDialogue);g=d.confirmDialogue.get("boundingBox").one("[name=\"submitbutton\"]")}if(f){b.one(g).on("click",d.launchQuizPopup,d,f)}})},displayDialogue:function displayDialogue(a){if(a){a.halt()}d.confirmDialogue.show()},hideDialogue:function hideDialogue(a){if(a){a.halt()}d.confirmDialogue.hide(a)},launchQuizPopup:function launchQuizPopup(a,d){a.halt();b.use("io-form",function(){var e=a.target.ancestor("form");c.resetFormDirtyState(e.getDOMNode());window.openpopup(a,{url:e.get("action")+"?"+b.IO.stringify(e).replace(/\bcancel=/,"x="),windowname:"quizpopup",options:d,fullscreen:!0})})}};return d});
//# sourceMappingURL=preflightcheck.min.js.map
File diff suppressed because one or more lines are too long
@@ -22,23 +22,23 @@
*/
define([
'jquery',
'core/yui',
'core/notification',
'core/modal',
'core/modal_events',
'core/modal_registry',
'core/fragment',
'core/templates',
'core_form/changechecker',
],
function(
$,
Y,
Notification,
Modal,
ModalEvents,
ModalRegistry,
Fragment,
Templates
Templates,
FormChangeChecker,
) {
var registered = false;
@@ -272,12 +272,9 @@ function(
return;
}.bind(this))
.then(function() {
// Make sure the form change checker is disabled otherwise it'll
// stop the user from navigating away from the page once the modal
// is hidden.
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
// Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the
// page once the modal is hidden.
FormChangeChecker.disableAllChecks();
return;
})
.fail(Notification.exception);
+7 -10
View File
@@ -22,21 +22,21 @@
*/
define([
'jquery',
'core/yui',
'core/notification',
'core/modal',
'core/modal_events',
'core/modal_registry',
'core/fragment'
'core/fragment',
'core_form/changechecker',
],
function(
$,
Y,
Notification,
Modal,
ModalEvents,
ModalRegistry,
Fragment
Fragment,
FormChangeChecker,
) {
var registered = false;
@@ -298,12 +298,9 @@ function(
// Disable the form change checker when the body is rendered.
this.getRoot().on(ModalEvents.bodyRendered, function() {
// Make sure the form change checker is disabled otherwise it'll
// stop the user from navigating away from the page once the modal
// is hidden.
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
// Make sure the form change checker is disabled otherwise it'll stop the user from navigating away from the
// page once the modal is hidden.
FormChangeChecker.disableAllChecks();
});
};
+4 -3
View File
@@ -24,7 +24,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 3.1
*/
define(['jquery', 'core/yui'], function($, Y) {
define(['jquery', 'core/yui', 'core_form/changechecker'], function($, Y, FormChangeChecker) {
/**
* @alias module:mod_quiz/preflightcheck
@@ -97,9 +97,10 @@ define(['jquery', 'core/yui'], function($, Y) {
*/
launchQuizPopup: function(e, popupoptions) {
e.halt();
Y.use('moodle-core-formchangechecker', 'io-form', function() {
M.core_formchangechecker.reset_form_dirty_state();
Y.use('io-form', function() {
var form = e.target.ancestor('form');
FormChangeChecker.resetFormDirtyState(form.getDOMNode());
window.openpopup(e, {
url: form.get('action') + '?' + Y.IO.stringify(form).replace(/\bcancel=/, 'x='),
windowname: 'quizpopup',
+1 -2
View File
@@ -1970,14 +1970,13 @@ function quiz_get_js_module() {
'name' => 'mod_quiz',
'fullpath' => '/mod/quiz/module.js',
'requires' => array('base', 'dom', 'event-delegate', 'event-key',
'core_question_engine', 'moodle-core-formchangechecker'),
'core_question_engine'),
'strings' => array(
array('cancel', 'moodle'),
array('flagged', 'question'),
array('functiondisabledbysecuremode', 'quiz'),
array('startattempt', 'quiz'),
array('timesup', 'quiz'),
array('changesmadereallygoaway', 'moodle'),
),
);
}
+8 -2
View File
@@ -12,6 +12,7 @@
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/* eslint camelcase: off */
/**
* JavaScript library for the quiz module.
@@ -27,7 +28,9 @@ M.mod_quiz = M.mod_quiz || {};
M.mod_quiz.init_attempt_form = function(Y) {
M.core_question_engine.init_form(Y, '#responseform');
Y.on('submit', M.mod_quiz.timer.stop, '#responseform');
M.core_formchangechecker.init({formid: 'responseform'});
require(['core_form/changechecker'], function(FormChangeChecker) {
FormChangeChecker.watchFormById('responseform');
});
};
M.mod_quiz.init_review_form = function(Y) {
@@ -72,6 +75,9 @@ M.mod_quiz.timer = {
M.mod_quiz.timer.preview = preview;
M.mod_quiz.timer.update();
Y.one('#quiz-timer-wrapper').setStyle('display', 'flex');
require(['core_form/changechecker'], function(FormChangeChecker) {
M.mod_quiz.timer.FormChangeChecker = FormChangeChecker;
});
},
/**
@@ -109,7 +115,7 @@ M.mod_quiz.timer = {
if (form.one('input[name=finishattempt]')) {
form.one('input[name=finishattempt]').set('value', 0);
}
M.core_formchangechecker.set_form_submitted();
M.mod_quiz.timer.FormChangeChecker.markFormSubmitted(input.getDOMNode());
form.submit();
return;
}
+3 -3
View File
@@ -170,9 +170,9 @@ class quiz_grading_renderer extends plugin_renderer_base {
]), ['class' => 'mdl-align']);
$output .= html_writer::end_tag('div') . html_writer::end_tag('form');
$this->page->requires->string_for_js('changesmadereallygoaway', 'moodle');
$this->page->requires->yui_module('moodle-core-formchangechecker',
'M.core_formchangechecker.init', [['formid' => 'manualgradingform']]);
// Add the form change checker.
$this->page->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['manualgradingform']);
return $output;
}