Merge pull request #19193 from MauricioFauth/config-inline-params-script-extraction

Extract config inline params JS from config/form_display/display.twig
This commit is contained in:
Maurício Meneghini Fauth 2024-06-06 08:29:05 -03:00 committed by GitHub
commit 4d668bd365
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 83 additions and 63 deletions

View File

@ -481,7 +481,7 @@
$workPath,
$translatedPath,
$userPrefsAllow,
$jsDefault,
$defaultValues,
)]]></code>
</PossiblyNullOperand>
<RiskyTruthyFalsyComparison>
@ -499,9 +499,6 @@
<code><![CDATA[$vName]]></code>
<code><![CDATA[$validator]]></code>
</MixedAssignment>
<MixedOperand>
<code><![CDATA[$vName]]></code>
</MixedOperand>
<RiskyTruthyFalsyComparison>
<code><![CDATA[! $isSetupScript]]></code>
<code><![CDATA[$this->config->get('is_setup')]]></code>

View File

@ -4,11 +4,11 @@ import { ajaxShowMessage } from './ajax-message.ts';
import isStorageSupported from './functions/isStorageSupported.ts';
import formatDateTime from './functions/formatDateTime.ts';
window.configInlineParams;
window.configScriptLoaded;
let configInlineParams: any[] | undefined;
let configScriptLoaded: boolean = false;
// default values for fields
window.defaultValues = {};
const defaultValues: object = {};
/**
* Returns field type
@ -170,21 +170,21 @@ function getAllValues () {
function checkFieldDefault (field, type) {
var $field = $(field);
var fieldId = $field.attr('id');
if (typeof window.defaultValues[fieldId] === 'undefined') {
if (typeof defaultValues[fieldId] === 'undefined') {
return true;
}
var isDefault = true;
var currentValue = getFieldValue($field, type);
if (type !== 'select') {
isDefault = currentValue === window.defaultValues[fieldId];
isDefault = currentValue === defaultValues[fieldId];
} else {
// compare arrays, will work for our representation of select values
if (currentValue.length !== window.defaultValues[fieldId].length) {
if (currentValue.length !== defaultValues[fieldId].length) {
isDefault = false;
} else {
for (var i = 0; i < currentValue.length; i++) {
if (currentValue[i] !== window.defaultValues[fieldId][i]) {
if (currentValue[i] !== defaultValues[fieldId][i]) {
isDefault = false;
break;
}
@ -313,7 +313,7 @@ const validators = {
* @param {boolean} onKeyUp whether fire on key up
* @param {any[]} params validation function parameters
*/
function registerFieldValidator (id, type, onKeyUp, params) {
function registerFieldValidator (id, type, onKeyUp, params = undefined) {
if (typeof window.validators[type] === 'undefined') {
return;
}
@ -509,21 +509,44 @@ function validateFieldAndFieldset (field, isKeyUp) {
}
function loadInlineConfig () {
if (! Array.isArray(window.configInlineParams)) {
if (! Array.isArray(configInlineParams)) {
return;
}
for (var i = 0; i < window.configInlineParams.length; ++i) {
if (typeof window.configInlineParams[i] === 'function') {
window.configInlineParams[i]();
for (var i = 0; i < configInlineParams.length; ++i) {
if (typeof configInlineParams[i] === 'function') {
configInlineParams[i]();
}
}
}
function setupValidation () {
validate = {};
window.configScriptLoaded = true;
if (window.configScriptLoaded && typeof window.configInlineParams !== 'undefined') {
const configInlineParamsData = $('#configInlineParamsData');
if (configInlineParamsData.length > 0) {
const fieldValidators = configInlineParamsData.data('fieldValidators');
const inlineDefaultValues = configInlineParamsData.data('defaultValues');
if (typeof configInlineParams === 'undefined' || !Array.isArray(configInlineParams)) {
configInlineParams = [];
}
configInlineParams.push(function () {
for (const validator of fieldValidators) {
if (validator.args) {
registerFieldValidator(validator.fieldId, validator.name, true, validator.args);
} else {
registerFieldValidator(validator.fieldId, validator.name, true);
}
}
});
$.extend(defaultValues, inlineDefaultValues);
}
configScriptLoaded = true;
if (configScriptLoaded && typeof configInlineParams !== 'undefined') {
Config.loadInlineConfig();
}
@ -598,11 +621,11 @@ function adjustPrefsNotification () {
*/
function restoreField (fieldId): void {
var $field = $('#' + fieldId);
if ($field.length === 0 || window.defaultValues[fieldId] === undefined) {
if ($field.length === 0 || defaultValues[fieldId] === undefined) {
return;
}
setFieldValue($field, getFieldType($field), window.defaultValues[fieldId]);
setFieldValue($field, getFieldType($field), defaultValues[fieldId]);
}
function setupRestoreField () {
@ -755,7 +778,7 @@ function on () {
$('.optbox input[type=button][name=submit_reset]').on('click', function () {
var fields = $(this).closest('fieldset').find('input, select, textarea');
for (var i = 0, imax = fields.length; i < imax; i++) {
setFieldValue(fields[i], getFieldType(fields[i]), window.defaultValues[fields[i].id]);
setFieldValue(fields[i], getFieldType(fields[i]), defaultValues[fields[i].id]);
}
setDisplayError();
@ -833,7 +856,6 @@ function on () {
const Config = {
getAllValues: getAllValues,
getIdPrefix: getIdPrefix,
registerFieldValidator: registerFieldValidator,
displayErrors: displayErrors,
loadInlineConfig: loadInlineConfig,
setupValidation: setupValidation,
@ -844,9 +866,6 @@ const Config = {
declare global {
interface Window {
configInlineParams: any[] | undefined;
configScriptLoaded: boolean | undefined;
defaultValues: object;
validators: typeof validators;
Config: typeof Config;
}

View File

@ -53,18 +53,6 @@
</div>
</form>
<script>
if (typeof window.configInlineParams === 'undefined' || !Array.isArray(window.configInlineParams)) {
window.configInlineParams = [];
}
window.configInlineParams.push(function () {
{{ js_array|join(';\n')|raw }};
$.extend(window.defaultValues,
{{ js_default|json_encode(constant('JSON_HEX_TAG'))|raw }}
);
});
if (typeof window.configScriptLoaded !== 'undefined' && window.configInlineParams) {
window.Config.loadInlineConfig();
}
</script>
<span id="configInlineParamsData"
data-field-validators="{{ field_validators|json_encode|e('html_attr') }}"
data-default-values="{{ default_values|json_encode|e('html_attr') }}"></span>

View File

@ -214,8 +214,8 @@ class FormDisplay
string|null $formAction = null,
array|null $hiddenFields = null,
): string {
$js = [];
$jsDefault = [];
$fieldValidators = [];
$defaultValues = [];
/**
* We do validation on page refresh when browser remembers field values,
@ -278,14 +278,14 @@ class FormDisplay
$workPath,
$translatedPath,
$userPrefsAllow,
$jsDefault,
$defaultValues,
);
// register JS validators for this field
if (! isset($validators[$path])) {
continue;
}
$this->formDisplayTemplate->addJsValidate($translatedPath, $validators[$path], $js);
$this->formDisplayTemplate->addJsValidate($translatedPath, $validators[$path], $fieldValidators);
}
}
@ -296,8 +296,8 @@ class FormDisplay
'tabs' => $tabs,
'forms' => $forms,
'show_buttons' => $showButtons,
'js_array' => $js,
'js_default' => $jsDefault,
'default_values' => $defaultValues,
'field_validators' => $fieldValidators,
]);
}

View File

@ -11,9 +11,6 @@ use PhpMyAdmin\Config;
use PhpMyAdmin\Template;
use function array_shift;
use function json_encode;
use const JSON_HEX_TAG;
/**
* PhpMyAdmin\Config\FormDisplayTemplate class
@ -127,18 +124,20 @@ class FormDisplayTemplate
/**
* Appends JS validation code to $js_array
*
* @param string $fieldId ID of field to validate
* @param string|mixed[] $validators validators callback
* @param mixed[] $jsArray will be updated with javascript code
* @param string $fieldId ID of field to validate
* @param string|mixed[] $validators validators callback
* @param mixed[] $fieldValidators will be updated with javascript code
*/
public function addJsValidate(string $fieldId, string|array $validators, array &$jsArray): void
public function addJsValidate(string $fieldId, string|array $validators, array &$fieldValidators): void
{
foreach ((array) $validators as $validator) {
$validator = (array) $validator;
$vName = array_shift($validator);
$vArgs = $validator !== [] ? ', ' . json_encode($validator, JSON_HEX_TAG) : '';
$jsArray[] = "window.Config.registerFieldValidator('"
. $fieldId . "', '" . $vName . "', true" . $vArgs . ')';
$fieldValidators[] = [
'fieldId' => $fieldId,
'name' => $vName,
'args' => $validator !== [] ? $validator : null,
];
}
}

View File

@ -242,10 +242,8 @@ class FormDisplayTemplateTest extends AbstractTestCase
self::assertSame(
[
'window.Config.registerFieldValidator(\'testID\', \'\\\';\', true, '
. '["\\\\r\\\\n\\\\\''
. '\u003CscrIpt\u003E\u003C\/\' + \'script\u003E"])',
'window.Config.registerFieldValidator(\'testID\', \'\', true)',
['fieldId' => 'testID', 'name' => '\\\';', 'args' => ['\r\n\\\'<scrIpt></\' + \'script>']],
['fieldId' => 'testID', 'name' => null, 'args' => null],
],
$js,
);

View File

@ -79,9 +79,28 @@ class PageSettingsTest extends AbstractTestCase
self::assertStringContainsString('<input type="hidden" name="submit_save" value="Browse">', $html);
self::assertStringContainsString(
"window.Config.registerFieldValidator('MaxRows', 'validatePositiveNumber', true);\n"
. "window.Config.registerFieldValidator('RepeatCells', 'validateNonNegativeNumber', true);\n"
. "window.Config.registerFieldValidator('LimitChars', 'validatePositiveNumber', true);\n",
'data-field-validators="&#x5B;&#x7B;&quot;fieldId&quot;&#x3A;&quot;MaxRows&quot;,'
. '&quot;name&quot;&#x3A;&quot;validatePositiveNumber&quot;,'
. '&quot;args&quot;&#x3A;null&#x7D;,&#x7B;&quot;fieldId&quot;&#x3A;&quot;RepeatCells&quot;,'
. '&quot;name&quot;&#x3A;&quot;validateNonNegativeNumber&quot;,'
. '&quot;args&quot;&#x3A;null&#x7D;,&#x7B;&quot;fieldId&quot;&#x3A;&quot;LimitChars&quot;,'
. '&quot;name&quot;&#x3A;&quot;validatePositiveNumber&quot;,&quot;args&quot;&#x3A;null&#x7D;&#x5D;"',
$html,
);
self::assertStringContainsString(
'data-default-values="&#x7B;&quot;TableNavigationLinksMode&quot;&#x3A;&#x5B;&quot;icons&quot;&#x5D;,'
. '&quot;ActionLinksMode&quot;&#x3A;&#x5B;&quot;both&quot;&#x5D;,'
. '&quot;ShowAll&quot;&#x3A;false,&quot;MaxRows&quot;&#x3A;&#x5B;25&#x5D;,'
. '&quot;Order&quot;&#x3A;&#x5B;&quot;SMART&quot;&#x5D;,'
. '&quot;BrowsePointerEnable&quot;&#x3A;true,&quot;BrowseMarkerEnable&quot;&#x3A;true,'
. '&quot;GridEditing&quot;&#x3A;&#x5B;&quot;double-click&quot;&#x5D;,'
. '&quot;SaveCellsAtOnce&quot;&#x3A;false,&quot;RepeatCells&quot;&#x3A;&quot;100&quot;,'
. '&quot;LimitChars&quot;&#x3A;&quot;50&quot;,'
. '&quot;RowActionLinks&quot;&#x3A;&#x5B;&quot;left&quot;&#x5D;,'
. '&quot;RowActionLinksWithoutUnique&quot;&#x3A;false,'
. '&quot;TablePrimaryKeyOrder&quot;&#x3A;&#x5B;&quot;NONE&quot;&#x5D;,'
. '&quot;RememberSorting&quot;&#x3A;true,'
. '&quot;RelationalDisplay&quot;&#x3A;&#x5B;&quot;K&quot;&#x5D;&#x7D;"',
$html,
);
}