MDL-64573 output: ajax form event
authorDamyon Wiese <damyon@moodle.com>
Wed, 3 Apr 2019 07:10:44 +0000 (15:10 +0800)
committerDamyon Wiese <damyon@moodle.com>
Wed, 24 Apr 2019 08:17:49 +0000 (16:17 +0800)
Add an event that can be fired when an mform is about to be submitted via ajax.
This allows custom field types to perform an action when the form is submitted.

The atto text editor will reset any autosaves when the form is submitted.

16 files changed:
calendar/amd/build/modal_event_form.min.js
calendar/amd/src/modal_event_form.js
lib/amd/build/event.min.js
lib/amd/src/event.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/src/editor/js/autosave-io.js
lib/editor/tinymce/module.js
lib/formslib.php
lib/yui/build/moodle-core-event/moodle-core-event-debug.js
lib/yui/build/moodle-core-event/moodle-core-event-min.js
lib/yui/build/moodle-core-event/moodle-core-event.js
lib/yui/src/event/js/event.js
mod/assign/amd/build/grading_panel.min.js
mod/assign/amd/src/grading_panel.js

index 79035b5..2befc26 100644 (file)
Binary files a/calendar/amd/build/modal_event_form.min.js and b/calendar/amd/build/modal_event_form.min.js differ
index 2401ac5..be7f718 100644 (file)
@@ -407,7 +407,17 @@ define([
      * @return {object} A promise
      */
     ModalEventForm.prototype.save = function() {
-        var loadingContainer = this.saveButton.find(SELECTORS.LOADING_ICON_CONTAINER);
+        var invalid,
+            loadingContainer = this.saveButton.find(SELECTORS.LOADING_ICON_CONTAINER);
+
+        // Now the change events have run, see if there are any "invalid" form fields.
+        invalid = this.getForm().find('[aria-invalid="true"]');
+
+        // If we found invalid fields, focus on the first one and do not submit via ajax.
+        if (invalid.length) {
+            invalid.first().focus();
+            return;
+        }
 
         loadingContainer.removeClass('hidden');
         this.disableButtons();
@@ -472,6 +482,8 @@ define([
         // Catch the submit event before it is actually processed by the browser and
         // prevent the submission. We'll take it from here.
         this.getModal().on('submit', function(e) {
+            Event.notifyFormSubmitAjax(this.getForm()[0]);
+
             this.save();
 
             // Stop the form from actually submitting and prevent it's
index 310efb4..e39e807 100644 (file)
Binary files a/lib/amd/build/event.min.js and b/lib/amd/build/event.min.js differ
index c67b5dd..a5d80e5 100644 (file)
@@ -68,6 +68,35 @@ define(['jquery', 'core/yui'],
                 Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: yuiNodes});
             });
         },
+
+        /**
+         * Trigger an event using both JQuery and YUI
+         *
+         * @method notifyFormSubmittedAjax
+         * @param {DOMElement} form
+         * @param {boolean} skipValidation Submit the form without validation. E.g. "Cancel".
+         */
+        notifyFormSubmitAjax: function(form, skipValidation) {
+
+            // Argument is optional.
+            skipValidation = skipValidation || false;
+
+            Y.use('event', 'moodle-core-event', function(Y) {
+                if (skipValidation) {
+                    window.skipClientValidation = true;
+                }
+                // Trigger it the JQuery way.
+                $(form).trigger(M.core.event.FORM_SUBMIT_AJAX);
+
+                // And again for YUI.
+                Y.one(form).fire(M.core.event.FORM_SUBMIT_AJAX, {currentTarget: Y.one(form)});
+
+                if (skipValidation) {
+                    window.skipClientValidation = false;
+                }
+            });
+        },
+
         /**
          * Trigger an event using both JQuery and YUI
          * This event alerts the world that the editor has restored some content.
index 9fce41e..18d80ba 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js differ
index 0bb1434..2574ec4 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js differ
index cf12f6c..fea3573 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js differ
index a37352e..47e19db 100644 (file)
@@ -198,6 +198,7 @@ Y.extend(EditorAutosaveIoDispatcher, Y.Base, {
         if (typeof this._submitEvents[node.generateID()] === 'undefined') {
             this._submitEvents[node.generateID()] = {
                 event: node.on('submit', this._onSubmit, this),
+                ajaxEvent: node.on(M.core.event.FORM_SUBMIT_AJAX, this._onSubmit, this),
                 ios: []
             };
         }
index 61c56d8..ee8e4d9 100644 (file)
@@ -66,6 +66,12 @@ M.editor_tinymce.init_editor = function(Y, editorid, options) {
         editor.onChange.add(function(ed) {
             ed.save();
         });
+        Y.use('event', 'moodle-core-event', function(Y) {
+            var form = Y.one(document.getElementById(editor.id)).ancestor('form');
+            form.on(M.core.event.FORM_SUBMIT_AJAX, function() {
+                editor.save();
+            }, this)
+        });
     };
 
     tinyMCE.init(options);
index acd0b21..9e2c96f 100644 (file)
@@ -2421,6 +2421,17 @@ require(["core/event", "jquery"], function(Event, $) {
       return ret;
     }
 
+    var form = $(document.getElementById(\'' . $this->_attributes['id'] . '\')).closest(\'form\');
+    form.on(M.core.event.FORM_SUBMIT_AJAX, function() {
+        try {
+            var myValidator = validate_' . $this->_formName . ';
+        } catch(e) {
+            return true;
+        }
+        if (myValidator) {
+            myValidator();
+        }
+    });
 
     document.getElementById(\'' . $this->_attributes['id'] . '\').addEventListener(\'submit\', function(ev) {
         try {
index 1dd7edc..1d72a16 100644 (file)
Binary files a/lib/yui/build/moodle-core-event/moodle-core-event-debug.js and b/lib/yui/build/moodle-core-event/moodle-core-event-debug.js differ
index ae188f2..0a60dbd 100644 (file)
Binary files a/lib/yui/build/moodle-core-event/moodle-core-event-min.js and b/lib/yui/build/moodle-core-event/moodle-core-event-min.js differ
index 847ca8f..8f6ca3b 100644 (file)
Binary files a/lib/yui/build/moodle-core-event/moodle-core-event.js and b/lib/yui/build/moodle-core-event/moodle-core-event.js differ
index 8ceff44..8d4cfaa 100644 (file)
@@ -29,6 +29,7 @@ var LOGNAME = 'moodle-core-event';
 M.core = M.core || {};
 
 M.core.event = M.core.event || {
+
     /**
      * This event is triggered when a page has added dynamic nodes to a page
      * that should be processed by the filter system. An example is loading
@@ -40,6 +41,7 @@ M.core.event = M.core.event || {
      * @param nodes {Y.NodeList} List of nodes added to the DOM.
      */
     FILTER_CONTENT_UPDATED: "filter-content-updated",
+
     /**
      * This event is triggered when an editor has recovered some draft text.
      * It can be used to determine let other sections know that they should reset their
@@ -47,7 +49,15 @@ M.core.event = M.core.event || {
      *
      * @event "editor-content-restored"
      */
-    EDITOR_CONTENT_RESTORED: "editor-content-restored"
+    EDITOR_CONTENT_RESTORED: "editor-content-restored",
+
+    /**
+     * This event is triggered when an mform is about to be submitted via ajax.
+     *
+     * @event "form-submit-ajax"
+     */
+    FORM_SUBMIT_AJAX: "form-submit-ajax"
+
 };
 
 M.core.globalEvents = M.core.globalEvents || {
index ed1ab5c..deb1685 100644 (file)
Binary files a/mod/assign/amd/build/grading_panel.min.js and b/mod/assign/amd/build/grading_panel.min.js differ
index a9abbac..da11d9d 100644 (file)
@@ -25,8 +25,8 @@
  */
 define(['jquery', 'core/yui', 'core/notification', 'core/templates', 'core/fragment',
         'core/ajax', 'core/str', 'mod_assign/grading_form_change_checker',
-        'mod_assign/grading_events'],
-       function($, Y, notification, templates, fragment, ajax, str, checker, GradingEvents) {
+        'mod_assign/grading_events', 'core/event'],
+       function($, Y, notification, templates, fragment, ajax, str, checker, GradingEvents, Event) {
 
     /**
      * GradingPanel class.
@@ -89,11 +89,6 @@ define(['jquery', 'core/yui', 'core/notification', 'core/templates', 'core/fragm
      * @method _saveFormState
      */
     GradingPanel.prototype._saveFormState = function() {
-        // Grrrrr! TinyMCE you know what you did.
-        if (typeof window.tinyMCE !== 'undefined') {
-            window.tinyMCE.triggerSave();
-        }
-
         // Copy data from notify students checkbox which was moved out of the form.
         var checked = $('[data-region="grading-actions-form"] [name="sendstudentnotifications"]').prop("checked");
         $('.gradeform [name="sendstudentnotifications"]').val(checked);
@@ -117,6 +112,9 @@ define(['jquery', 'core/yui', 'core/notification', 'core/templates', 'core/fragm
         // We call this, so other modules can update the form with the latest state.
         form.trigger('save-form-state');
 
+        // Tell all form fields we are about to submit the form.
+        Event.notifyFormSubmitAjax(form[0]);
+
         // Now we get all the current values from the form.
         var data = form.serialize();
         var assignmentid = this._region.attr('data-assignmentid');