From 7d6696e0792d3c6f8c9ef2651bd629caed6f7978 Mon Sep 17 00:00:00 2001 From: Sami Mokaddem Date: Mon, 14 Nov 2022 09:04:35 +0100 Subject: [PATCH] new: [metaFields] Adding support of sane_default + improving form & crud - WiP --- .../20221028000000_MetaFieldSaneDefault.php | 34 +++++++ src/Model/Entity/MetaTemplateField.php | 27 ++++++ src/Model/Table/MetaTemplateFieldsTable.php | 2 + templates/MetaTemplateFields/index.php | 8 ++ .../Form/Fields/dropdownField.php | 97 ++++++++++++++++--- .../genericElements/Form/metaTemplateForm.php | 13 ++- .../genericElements/Form/multiFieldButton.php | 29 +++--- .../Form/multiFieldScaffold.php | 19 +++- 8 files changed, 199 insertions(+), 30 deletions(-) create mode 100644 config/Migrations/20221028000000_MetaFieldSaneDefault.php diff --git a/config/Migrations/20221028000000_MetaFieldSaneDefault.php b/config/Migrations/20221028000000_MetaFieldSaneDefault.php new file mode 100644 index 0000000..b59149c --- /dev/null +++ b/config/Migrations/20221028000000_MetaFieldSaneDefault.php @@ -0,0 +1,34 @@ +table('meta_template_fields')->hasColumn('sane_default'); + if (!$exists) { + $this->table('meta_template_fields') + ->addColumn('sane_default', 'text', [ + 'default' => null, + 'null' => true, + 'limit' => MysqlAdapter::TEXT_LONG, + 'comment' => 'List of sane default values to be proposed', + ]) + ->addColumn('values_list', 'text', [ + 'default' => null, + 'null' => true, + 'limit' => MysqlAdapter::TEXT_LONG, + 'comment' => 'List of values that have to be used', + ]) + ->update(); + } + } +} diff --git a/src/Model/Entity/MetaTemplateField.php b/src/Model/Entity/MetaTemplateField.php index 7baf30a..570fef9 100644 --- a/src/Model/Entity/MetaTemplateField.php +++ b/src/Model/Entity/MetaTemplateField.php @@ -7,5 +7,32 @@ use Cake\ORM\Entity; class MetaTemplateField extends AppModel { + protected $_virtual = ['form_type', 'form_options', ]; + + protected function _getFormType() + { + $formType = 'text'; + if (!empty($this->sane_default) || !empty($this->values_list)) { + $formType = 'dropdown'; + } + return $formType; + } + + protected function _getFormOptions() + { + $formOptions = []; + if ($this->formType === 'dropdown') { + $selectOptions = !empty($this->sane_default) ? $this->sane_default : $this->values_list; + $selectOptions = array_combine($selectOptions, $selectOptions); + if (!empty($this->sane_default)) { + // $selectOptions['_custom'] = __('-- custom value --'); + $selectOptions[] = ['value' => '_custom', 'text' => __('-- custom value --'), 'class' => 'custom-value']; + } + $selectOptions[''] = __('-- no value --'); + $formOptions['options'] = $selectOptions; + // $formOptions['empty'] = [['value' => '', 'text' => __('-- select an options --'), 'hidden disabled selected value']]; + } + return $formOptions; + } } diff --git a/src/Model/Table/MetaTemplateFieldsTable.php b/src/Model/Table/MetaTemplateFieldsTable.php index 626a96c..857361c 100644 --- a/src/Model/Table/MetaTemplateFieldsTable.php +++ b/src/Model/Table/MetaTemplateFieldsTable.php @@ -27,6 +27,8 @@ class MetaTemplateFieldsTable extends AppTable $this->hasMany('MetaFields'); $this->setDisplayField('field'); + $this->getSchema()->setColumnType('sane_default', 'json'); + $this->getSchema()->setColumnType('values_list', 'json'); $this->loadTypeHandlers(); } diff --git a/templates/MetaTemplateFields/index.php b/templates/MetaTemplateFields/index.php index 4071d13..5f41b21 100644 --- a/templates/MetaTemplateFields/index.php +++ b/templates/MetaTemplateFields/index.php @@ -30,6 +30,14 @@ echo $this->element('genericElements/IndexTable/index_table', [ 'data_path' => 'multiple', 'field' => 'textarea' ], + [ + 'name' => __('Sane defaults'), + 'data_path' => 'sane_default' + ], + [ + 'name' => __('Values List'), + 'data_path' => 'values_list' + ], [ 'name' => __('Validation regex'), 'sort' => 'regex', diff --git a/templates/element/genericElements/Form/Fields/dropdownField.php b/templates/element/genericElements/Form/Fields/dropdownField.php index 26e8e88..b8d81b2 100644 --- a/templates/element/genericElements/Form/Fields/dropdownField.php +++ b/templates/element/genericElements/Form/Fields/dropdownField.php @@ -1,14 +1,87 @@ $fieldData['options'], - 'empty' => $fieldData['empty'] ?? false, - 'value' => $fieldData['value'] ?? null, - 'multiple' => $fieldData['multiple'] ?? false, - 'disabled' => $fieldData['disabled'] ?? false, - 'class' => ($fieldData['class'] ?? '') . ' formDropdown form-select', - 'default' => ($fieldData['default'] ?? null) - ]; - if (!empty($fieldData['label'])) { - $controlParams['label'] = $fieldData['label']; +$seed = 's-' . mt_rand(); +$controlParams = [ + 'type' => 'select', + 'options' => $fieldData['options'], + 'empty' => $fieldData['empty'] ?? false, + 'value' => $fieldData['value'] ?? null, + 'multiple' => $fieldData['multiple'] ?? false, + 'disabled' => $fieldData['disabled'] ?? false, + 'class' => ($fieldData['class'] ?? '') . ' formDropdown form-select', + 'default' => $fieldData['default'] ?? '', +]; +if (!empty($fieldData['field'])) { // used for multi meta-field form + $controlParams['field'] = $fieldData['field']; +} +if (!empty($fieldData['label'])) { + $controlParams['label'] = $fieldData['label']; +} +if ($controlParams['options'] instanceof \Cake\ORM\Query) { + $controlParams['options'] = $controlParams['options']->all()->toList(); +} +if (in_array('_custom', array_keys($controlParams['options']))) { + $customInputValue = $this->Form->getSourceValue($fieldData['field']); + if (!in_array($customInputValue, $controlParams['options'])) { + $controlParams['options'] = array_map(function ($option) { + if (is_array($option) && $option['value'] == '_custom') { + $option[] = 'selected'; + } + return $option; + }, $controlParams['options']); + } else { + $customInputValue = ''; } - echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData); + $customControlParams = [ + 'value' => $fieldData['value'] ?? null, + 'class' => 'd-none', + ]; + $controlParams['class'] .= ' dropdown-custom-value' . "-$seed"; + $adaptedField = $fieldData['field'] . '_custom'; + $controlParams['templates']['formGroup'] = sprintf( + '
{{input}}{{error}}%s
', + sprintf('', h($adaptedField), h($customInputValue)) + ); +} +echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData); +?> + + + + \ No newline at end of file diff --git a/templates/element/genericElements/Form/metaTemplateForm.php b/templates/element/genericElements/Form/metaTemplateForm.php index 0a4d934..56e0ac4 100644 --- a/templates/element/genericElements/Form/metaTemplateForm.php +++ b/templates/element/genericElements/Form/metaTemplateForm.php @@ -31,7 +31,11 @@ foreach ($metaTemplate->meta_template_fields as $metaTemplateField) { $metaField = reset($metaTemplateField->metaFields); $fieldData = [ 'label' => $metaTemplateField->label, + 'type' => $metaTemplateField->formType, ]; + if ($metaTemplateField->formType === 'dropdown') { + $fieldData = array_merge_recursive($fieldData, $metaTemplateField->formOptions); + } if (isset($metaField->id)) { $fieldData['field'] = sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.%s.value', $metaField->meta_template_id, $metaField->meta_template_field_id, $metaField->id); } else { @@ -63,7 +67,11 @@ foreach ($metaTemplate->meta_template_fields as $metaTemplateField) { $fieldData = [ 'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new.0', $metaTemplateField->meta_template_id, $metaTemplateField->id), 'label' => $metaTemplateField->label, + 'type' => $metaTemplateField->formType, ]; + if ($metaTemplateField->formType === 'dropdown') { + $fieldData = array_merge_recursive($fieldData, $metaTemplateField->formOptions); + } $fieldsHtml .= $this->element( 'genericElements/Form/fieldScaffold', [ @@ -74,4 +82,7 @@ foreach ($metaTemplate->meta_template_fields as $metaTemplateField) { } } } -echo $fieldsHtml; \ No newline at end of file +$fieldContainer = $this->Bootstrap->genNode('div', [ + 'class' => [], +], $fieldsHtml); +echo $fieldContainer; \ No newline at end of file diff --git a/templates/element/genericElements/Form/multiFieldButton.php b/templates/element/genericElements/Form/multiFieldButton.php index c7c778b..9cfd348 100644 --- a/templates/element/genericElements/Form/multiFieldButton.php +++ b/templates/element/genericElements/Form/multiFieldButton.php @@ -45,6 +45,8 @@ $seed = 'mfb-' . mt_rand(); $clonedContainer .removeClass('has-error') .find('.error-message ').remove() + $clonedContainer + .find('label.form-label').text('') const $clonedInput = $clonedContainer.find('input, select') if ($clonedInput.length > 0) { const injectedTemplateId = $clicked.closest('.multi-metafields-container').find('.new-metafield').length @@ -54,18 +56,21 @@ $seed = 'mfb-' . mt_rand(); } } - function adjustClonedInputAttr($input, injectedTemplateId) { - let explodedPath = $input.attr('field').split('.').splice(0, 5) - explodedPath.push('new', injectedTemplateId) - dottedPathStr = explodedPath.join('.') - brackettedPathStr = explodedPath.map((elem, i) => { - return i == 0 ? elem : `[${elem}]` - }).join('') - $input.attr('id', dottedPathStr) - .attr('field', dottedPathStr) - .attr('name', brackettedPathStr) - .val('') - .removeClass('is-invalid') + function adjustClonedInputAttr($inputs, injectedTemplateId) { + $inputs.each(function() { + const $input = $(this) + let explodedPath = $input.attr('field').split('.').splice(0, 5) + explodedPath.push('new', injectedTemplateId) + dottedPathStr = explodedPath.join('.') + brackettedPathStr = explodedPath.map((elem, i) => { + return i == 0 ? elem : `[${elem}]` + }).join('') + $input.attr('id', dottedPathStr) + .attr('field', dottedPathStr) + .attr('name', brackettedPathStr) + .val('') + .removeClass('is-invalid') + }) } })() \ No newline at end of file diff --git a/templates/element/genericElements/Form/multiFieldScaffold.php b/templates/element/genericElements/Form/multiFieldScaffold.php index 3a73125..89b405c 100644 --- a/templates/element/genericElements/Form/multiFieldScaffold.php +++ b/templates/element/genericElements/Form/multiFieldScaffold.php @@ -22,6 +22,7 @@ if (!empty($metaFieldsEntities)) { $metaFieldsEntity->meta_template_field_id, $metaFieldsEntity->id ), + 'type' => $metaTemplateField->formType, ]; if($metaFieldsEntity->isNew()) { $fieldData['field'] = sprintf( @@ -35,6 +36,9 @@ if (!empty($metaFieldsEntities)) { if ($labelPrintedOnce) { // Only the first input can have a label $fieldData['label'] = false; } + if ($metaTemplateField->formType === 'dropdown') { + $fieldData = array_merge_recursive($fieldData, $metaTemplateField->formOptions); + } $labelPrintedOnce = true; $fieldsHtml .= $this->element( 'genericElements/Form/fieldScaffold', @@ -49,14 +53,19 @@ if (!empty($metaTemplateField) && !empty($multiple)) { // Add multiple field but $metaTemplateField->label = Inflector::humanize($metaTemplateField->field); $emptyMetaFieldInput = ''; if (empty($metaFieldsEntities)) { // Include editable field for meta-template not containing a meta-field + $fieldData = [ + 'label' => $metaTemplateField->label, + 'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new.0', $metaTemplateField->meta_template_id, $metaTemplateField->id), + 'class' => 'new-metafield', + 'type' => $metaTemplateField->formType, + ]; + if ($metaTemplateField->formType === 'dropdown') { + $fieldData = array_merge_recursive($fieldData, $metaTemplateField->formOptions); + } $emptyMetaFieldInput = $this->element( 'genericElements/Form/fieldScaffold', [ - 'fieldData' => [ - 'label' => $metaTemplateField->label, - 'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new.0', $metaTemplateField->meta_template_id, $metaTemplateField->id), - 'class' => 'new-metafield', - ], + 'fieldData' => $fieldData, 'form' => $form, ] );