Skip to content

Commit

Permalink
MDL-70760 admin: Limited length config setting validate client-side
Browse files Browse the repository at this point in the history
  • Loading branch information
viettruongq committed Nov 1, 2023
1 parent 859df15 commit 2375b00
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 3 deletions.
13 changes: 11 additions & 2 deletions admin/templates/setting_configtext.mustache
Expand Up @@ -27,6 +27,8 @@
* forceltr - always display as ltr
* attributes - list of additional attributes containing name, value
* readonly - bool
* data - list of arbitrary data attributes
* maxcharacter - maximum character
Example context (json):
{
Expand All @@ -36,12 +38,19 @@
"size": "21",
"forceltr": false,
"readonly": false,
"attributes": [ { "name": "readonly", "value": "readonly" } ]
"attributes": [ { "name": "readonly", "value": "readonly" } ],
"data": [ { "key": "validation_max_length", "value": "10" } ],
"maxcharacter": false
}
}}
{{!
Setting configtext.
}}
<div class="form-text defaultsnext">
<input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}" {{#readonly}}disabled{{/readonly}}>
<input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}" {{#readonly}}disabled{{/readonly}} {{#data}} data-{{key}}={{#quote}}{{{value}}}{{/quote}}{{/data}}>
{{#data}}
{{#maxcharacter}}
<div class="form-defaultinfo text-muted d-block">{{#str}} maxcharacter, admin, {{value}} {{/str}}</div>
{{/maxcharacter}}
{{/data}}
</div>
10 changes: 10 additions & 0 deletions admin/tool/messageinbound/tests/behat/incoming_mail.feature
Expand Up @@ -23,3 +23,13 @@ Feature: Incoming mail configuration
When I navigate to "Server > Email > Incoming mail configuration" in site administration
Then "OAuth 2 service" "select" should exist
And I should see "Testing service" in the "OAuth 2 service" "select"

@javascript
Scenario: Check character limitations of mailbox name
When I navigate to "Server > Email > Incoming mail configuration" in site administration
And I set the field "Mailbox name" to "frogfrogfrogfrog"
Then I should see "Maximum of 15 characters"
And the "disabled" attribute of "form#adminsettings button[type='submit']" "css_element" should contain "true"
And I set the field "Mailbox name" to "frogfrogfrogfro"
And I should not see "Maximum of 15 characters"
And the "disabled" attribute of "form#adminsettings button[type='submit']" "css_element" should not be set
1 change: 1 addition & 0 deletions lang/en/admin.php
Expand Up @@ -871,6 +871,7 @@
from a STABLE branch of the Moodle code. See Moodle Docs for more details.';
$string['maxbytes'] = 'Maximum uploaded file size';
$string['maxconsecutiveidentchars'] = 'Consecutive identical characters';
$string['maxcharacter'] = '{$a} character maximum';
$string['maxsizeperdownloadcoursefile'] = 'Maximum size per file';
$string['maxsizeperdownloadcoursefile_desc'] = 'The maximum size of each file when downloading course content. Files exceeding this size will be omitted from the download.';
$string['maxeditingtime'] = 'Maximum time to edit posts';
Expand Down
34 changes: 33 additions & 1 deletion lib/adminlib.php
Expand Up @@ -2447,6 +2447,8 @@ class admin_setting_configtext extends admin_setting {

/** @var int default field size */
public $size;
/** @var array List of arbitrary data attributes */
protected $datavalues = [];

/**
* Config text constructor
Expand Down Expand Up @@ -2530,11 +2532,24 @@ public function validate($data) {
}
}

/**
* Set arbitrary data attributes for template.
*
* @param string $key Attribute key for template.
* @param string $value Attribute value for template.
*/
public function set_data_attribute(string $key, string $value): void {
$this->datavalues[] = [
'key' => $key,
'value' => $value,
];
}

/**
* Return an XHTML string for the setting
* @return string Returns an XHTML string
*/
public function output_html($data, $query='') {
public function output_html($data, $query = '') {
global $OUTPUT;

$default = $this->get_defaultsetting();
Expand All @@ -2545,6 +2560,8 @@ public function output_html($data, $query='') {
'value' => $data,
'forceltr' => $this->get_force_ltr(),
'readonly' => $this->is_readonly(),
'data' => $this->datavalues,
'maxcharacter' => array_key_exists('validation-max-length', $this->datavalues),
];
$element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context);

Expand Down Expand Up @@ -2578,6 +2595,7 @@ class admin_setting_configtext_with_maxlength extends admin_setting_configtext {
public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW,
$size=null, $maxlength = 0) {
$this->maxlength = $maxlength;
$this->set_data_attribute('validation-max-length', $maxlength);
parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
}

Expand All @@ -2604,6 +2622,20 @@ public function validate($data) {
return $parentvalidation;
}
}

/**
* Return an XHTML string for the setting.
*
* @param string $data data.
* @param string $query query statement.
* @return string Returns an XHTML string
*/
public function output_html($data, $query = ''): string {
global $PAGE;
$PAGE->requires->js_call_amd('core_form/configtext_maxlength', 'init');

return parent::output_html($data, $query);
}
}

/**
Expand Down
3 changes: 3 additions & 0 deletions lib/form/amd/build/configtext_maxlength.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/form/amd/build/configtext_maxlength.min.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

121 changes: 121 additions & 0 deletions lib/form/amd/src/configtext_maxlength.js
@@ -0,0 +1,121 @@
// 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/>.

/**
* Validation for configtext_maxlength.
*
* @module core_form/configtext-maxlength
* @copyright 2021 The Open University
*/
import {get_string as getString} from 'core/str';
import Templates from 'core/templates';
import Notification from 'core/notification';
import {prefetchStrings, prefetchTemplates} from 'core/prefetch';

let registered = false;

/**
* Initialisation function.
*/
export const init = () => {
if (registered) {
return;
}
prefetchStrings('core', [
'maximumchars',
]);

prefetchTemplates([
'core_form/setting_validation_failure',
]);

registered = true;

document.addEventListener('input', e => {
const maxLengthField = e.target.closest('[data-validation-max-length]');
if (!maxLengthField) {
return;
}

if (maxLengthField.value.length > maxLengthField.dataset.validationMaxLength) {
// Disable the form for this field.
maxLengthField.form.addEventListener('submit', submissionCheck);
// Display an error.
getString('maximumchars', 'core', maxLengthField.dataset.validationMaxLength)
.then(errorMessage => {
return Templates.renderForPromise('core_form/setting_validation_failure', {
fieldid: maxLengthField.id,
message: errorMessage,
});
})
.then(errorTemplate => {
if (!maxLengthField.dataset.validationFailureId) {
const formWrapper = maxLengthField.closest('.form-text');
Templates.prependNodeContents(formWrapper, errorTemplate.html, errorTemplate.js);
maxLengthField.dataset.validationFailureId = `maxlength_error_${maxLengthField.id}`;
// Disable submit button when the message is displayed.
updateSubmitButton();
}
return;
})
.then(() => {
maxLengthField.setAttribute('aria-invalid', true);
const errorField = document.getElementById(maxLengthField.dataset.validationFailureId);
if (errorField) {
errorField.setAttribute('aria-describedby', maxLengthField.id);
}
return;
})
.catch(Notification.exception);
} else {
// Remove the old message.
const validationMessage = document.getElementById(maxLengthField.dataset.validationFailureId);
if (validationMessage) {
validationMessage.parentElement.remove();
delete maxLengthField.dataset.validationFailureId;
maxLengthField.removeAttribute('aria-invalid');
// Enable submit button when the message was removed.
updateSubmitButton();
}
}
});
};

/**
* Handle form submission.
*
* @param {Event} e The event.
*/
const submissionCheck = e => {
const maxLengthFields = e.target.querySelectorAll('[data-validation-max-length]');
const maxLengthFieldsArray = Array.from(maxLengthFields);
maxLengthFieldsArray.some(maxLengthField => {
// Focus on the first validation failure.
if (maxLengthField.value.length > maxLengthField.dataset.validationMaxLength) {
e.preventDefault();
maxLengthField.focus();
return true;
}
return false;
});
};

/**
* Update submit button.
*/
const updateSubmitButton = () => {
const shouldDisable = document.querySelector('form#adminsettings .error');
document.querySelector('form#adminsettings button[type="submit"]').disabled = !!shouldDisable;
};
36 changes: 36 additions & 0 deletions lib/form/templates/setting_validation_failure.mustache
@@ -0,0 +1,36 @@
{{!
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/>.
}}
{{!
@template core_form/setting_validation_failure
Error displayed when field fails validation (longer than max length).
Context variables required for this template:
* fieldid - element field id
* message - error message
Example context (json):
{
"fieldid": "test0",
"message": "test message"
}
}}
{{!
Setting error template for configtext_maxlength.
}}
<div>
<span class="error" id="maxlength_error_{{fieldid}}">{{message}}</span>
</div>

0 comments on commit 2375b00

Please sign in to comment.