MDL-69608 core_form: frozen forms do not have form tag
[moodle.git] / theme / boost / amd / src / form-display-errors.js
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16 /**
17  * Custom form error event handler to manipulate the bootstrap markup and show
18  * nicely styled errors in an mform.
19  *
20  * @module     theme_boost/form-display-errors
21  * @copyright  2016 Damyon Wiese <damyon@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
24 define(['jquery', 'core/event'], function($, Event) {
25     return {
26         enhance: function(elementid) {
27             var element = document.getElementById(elementid);
28             if (!element) {
29                 // Some elements (e.g. static) don't have a form field.
30                 // Hence there is no validation. So, no setup required here.
31                 return;
32             }
34             $(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
35                 event.preventDefault();
36                 var parent = $(element).closest('.form-group');
37                 var feedback = parent.find('.form-control-feedback');
39                 // Sometimes (atto) we have a hidden textarea backed by a real contenteditable div.
40                 if (($(element).prop("tagName") == 'TEXTAREA') && parent.find('[contenteditable]')) {
41                     element = parent.find('[contenteditable]');
42                 }
43                 if (msg !== '') {
44                     parent.addClass('has-danger');
45                     parent.data('client-validation-error', true);
46                     $(element).addClass('is-invalid');
47                     $(element).attr('aria-describedby', feedback.attr('id'));
48                     $(element).attr('aria-invalid', true);
49                     feedback.attr('tabindex', 0);
50                     feedback.html(msg);
52                     // Only display and focus when the error was not already visible.
53                     // This is so that, when tabbing around the form, you don't get stuck.
54                     if (!feedback.is(':visible')) {
55                         feedback.show();
56                         feedback.focus();
57                     }
59                 } else {
60                     if (parent.data('client-validation-error') === true) {
61                         parent.removeClass('has-danger');
62                         parent.data('client-validation-error', false);
63                         $(element).removeClass('is-invalid');
64                         $(element).removeAttr('aria-describedby');
65                         $(element).attr('aria-invalid', false);
66                         feedback.hide();
67                     }
68                 }
69             });
71             var form = element.closest('form');
72             if (form && !('boostFormErrorsEnhanced' in form.dataset)) {
73                 form.addEventListener('submit', function() {
74                     var visibleError = $('.form-control-feedback:visible');
75                     if (visibleError.length) {
76                         visibleError[0].focus();
77                     }
78                 });
79                 form.dataset.boostFormErrorsEnhanced = 1;
80             }
81         }
82     };
83 });