| 1 | efrain | 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/>.
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 | /**
 | 
        
           |  |  | 17 |  * Validation for configtext_maxlength.
 | 
        
           |  |  | 18 |  *
 | 
        
           |  |  | 19 |  * @module     core_form/configtext-maxlength
 | 
        
           |  |  | 20 |  * @copyright  2021 The Open University
 | 
        
           |  |  | 21 |  */
 | 
        
           |  |  | 22 | import {get_string as getString} from 'core/str';
 | 
        
           |  |  | 23 | import Templates from 'core/templates';
 | 
        
           |  |  | 24 | import Notification from 'core/notification';
 | 
        
           |  |  | 25 | import {prefetchStrings, prefetchTemplates} from 'core/prefetch';
 | 
        
           |  |  | 26 |   | 
        
           |  |  | 27 | let registered = false;
 | 
        
           |  |  | 28 |   | 
        
           |  |  | 29 | /**
 | 
        
           |  |  | 30 |  * Initialisation function.
 | 
        
           |  |  | 31 |  */
 | 
        
           |  |  | 32 | export const init = () => {
 | 
        
           |  |  | 33 |     if (registered) {
 | 
        
           |  |  | 34 |         return;
 | 
        
           |  |  | 35 |     }
 | 
        
           |  |  | 36 |     prefetchStrings('core', [
 | 
        
           |  |  | 37 |         'maximumchars',
 | 
        
           |  |  | 38 |     ]);
 | 
        
           |  |  | 39 |   | 
        
           |  |  | 40 |     prefetchTemplates([
 | 
        
           |  |  | 41 |         'core_form/setting_validation_failure',
 | 
        
           |  |  | 42 |     ]);
 | 
        
           |  |  | 43 |   | 
        
           |  |  | 44 |     registered = true;
 | 
        
           |  |  | 45 |   | 
        
           |  |  | 46 |     document.addEventListener('input', e => {
 | 
        
           |  |  | 47 |         const maxLengthField = e.target.closest('[data-validation-max-length]');
 | 
        
           |  |  | 48 |         if (!maxLengthField) {
 | 
        
           |  |  | 49 |             return;
 | 
        
           |  |  | 50 |         }
 | 
        
           |  |  | 51 |   | 
        
           |  |  | 52 |         if (maxLengthField.value.length > maxLengthField.dataset.validationMaxLength) {
 | 
        
           |  |  | 53 |             // Disable the form for this field.
 | 
        
           |  |  | 54 |             maxLengthField.form.addEventListener('submit', submissionCheck);
 | 
        
           |  |  | 55 |             // Display an error.
 | 
        
           |  |  | 56 |             getString('maximumchars', 'core', maxLengthField.dataset.validationMaxLength)
 | 
        
           |  |  | 57 |                 .then(errorMessage => {
 | 
        
           |  |  | 58 |                     return Templates.renderForPromise('core_form/setting_validation_failure', {
 | 
        
           |  |  | 59 |                         fieldid: maxLengthField.id,
 | 
        
           |  |  | 60 |                         message: errorMessage,
 | 
        
           |  |  | 61 |                     });
 | 
        
           |  |  | 62 |                 })
 | 
        
           |  |  | 63 |                 .then(errorTemplate => {
 | 
        
           |  |  | 64 |                     if (!maxLengthField.dataset.validationFailureId) {
 | 
        
           |  |  | 65 |                         const formWrapper = maxLengthField.closest('.form-text');
 | 
        
           |  |  | 66 |                         Templates.prependNodeContents(formWrapper, errorTemplate.html, errorTemplate.js);
 | 
        
           |  |  | 67 |                         maxLengthField.dataset.validationFailureId = `maxlength_error_${maxLengthField.id}`;
 | 
        
           |  |  | 68 |                         // Disable submit button when the message is displayed.
 | 
        
           |  |  | 69 |                         updateSubmitButton();
 | 
        
           |  |  | 70 |                     }
 | 
        
           |  |  | 71 |                     return;
 | 
        
           |  |  | 72 |                 })
 | 
        
           |  |  | 73 |                 .then(() => {
 | 
        
           |  |  | 74 |                     maxLengthField.setAttribute('aria-invalid', true);
 | 
        
           |  |  | 75 |                     const errorField = document.getElementById(maxLengthField.dataset.validationFailureId);
 | 
        
           |  |  | 76 |                     if (errorField) {
 | 
        
           |  |  | 77 |                         errorField.setAttribute('aria-describedby', maxLengthField.id);
 | 
        
           |  |  | 78 |                     }
 | 
        
           |  |  | 79 |                     return;
 | 
        
           |  |  | 80 |                 })
 | 
        
           |  |  | 81 |                 .catch(Notification.exception);
 | 
        
           |  |  | 82 |         } else {
 | 
        
           |  |  | 83 |             // Remove the old message.
 | 
        
           |  |  | 84 |             const validationMessage = document.getElementById(maxLengthField.dataset.validationFailureId);
 | 
        
           |  |  | 85 |             if (validationMessage) {
 | 
        
           |  |  | 86 |                 validationMessage.parentElement.remove();
 | 
        
           |  |  | 87 |                 delete maxLengthField.dataset.validationFailureId;
 | 
        
           |  |  | 88 |                 maxLengthField.removeAttribute('aria-invalid');
 | 
        
           |  |  | 89 |                 // Enable submit button when the message was removed.
 | 
        
           |  |  | 90 |                 updateSubmitButton();
 | 
        
           |  |  | 91 |             }
 | 
        
           |  |  | 92 |         }
 | 
        
           |  |  | 93 |     });
 | 
        
           |  |  | 94 | };
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 | /**
 | 
        
           |  |  | 97 |  * Handle form submission.
 | 
        
           |  |  | 98 |  *
 | 
        
           |  |  | 99 |  * @param {Event} e The event.
 | 
        
           |  |  | 100 |  */
 | 
        
           |  |  | 101 | const submissionCheck = e => {
 | 
        
           |  |  | 102 |     const maxLengthFields = e.target.querySelectorAll('[data-validation-max-length]');
 | 
        
           |  |  | 103 |     const maxLengthFieldsArray = Array.from(maxLengthFields);
 | 
        
           |  |  | 104 |     maxLengthFieldsArray.some(maxLengthField => {
 | 
        
           |  |  | 105 |         // Focus on the first validation failure.
 | 
        
           |  |  | 106 |         if (maxLengthField.value.length > maxLengthField.dataset.validationMaxLength) {
 | 
        
           |  |  | 107 |             e.preventDefault();
 | 
        
           |  |  | 108 |             maxLengthField.focus();
 | 
        
           |  |  | 109 |             return true;
 | 
        
           |  |  | 110 |         }
 | 
        
           |  |  | 111 |         return false;
 | 
        
           |  |  | 112 |     });
 | 
        
           |  |  | 113 | };
 | 
        
           |  |  | 114 |   | 
        
           |  |  | 115 | /**
 | 
        
           |  |  | 116 |  * Update submit button.
 | 
        
           |  |  | 117 |  */
 | 
        
           |  |  | 118 | const updateSubmitButton = () => {
 | 
        
           |  |  | 119 |     const shouldDisable = document.querySelector('form#adminsettings .error');
 | 
        
           |  |  | 120 |     document.querySelector('form#adminsettings button[type="submit"]').disabled = !!shouldDisable;
 | 
        
           |  |  | 121 | };
 |