From 580746539416a09aeea0697dbe18d76d0b81ce99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=BCndig?= Date: Sat, 18 Sep 2021 07:30:01 +0200 Subject: [PATCH] Added "add database columns" to form builder (#312) --- assets/js/builder.index.entity.modelform.js | 46 +++++++++ behaviors/IndexModelFormOperations.php | 94 +++++++++++++++++++ .../_add-fields-from-database-popup-form.htm | 28 ++++++ .../partials/_toolbar.htm | 10 ++ .../formbuilder/assets/js/formbuilder.js | 6 +- lang/en/lang.php | 2 + 6 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 behaviors/indexmodelformoperations/partials/_add-fields-from-database-popup-form.htm diff --git a/assets/js/builder.index.entity.modelform.js b/assets/js/builder.index.entity.modelform.js index 13618459..d3e86abe 100644 --- a/assets/js/builder.index.entity.modelform.js +++ b/assets/js/builder.index.entity.modelform.js @@ -63,6 +63,52 @@ ) } + ModelForm.prototype.cmdAddFieldsFromDatabase = function (ev) { + var $target = $(ev.currentTarget) + + // Always use the first placeholder to add controls + var $placeholder = this.getMasterTabsActivePane().find('.builder-control-list .control.placeholder:first')[0] + + // Filter all fields from the DataTable that have the "add" checkbox checked. + var fields = $target.find('.control-table').data('oc.table').dataSource.data.filter(function (column) { + return column.add + }).reverse() + + // Hide the poup and initialize the load indicator. + $target.closest('.control-popup').data('oc.popup').hide() + $.oc.stripeLoadIndicator.show() + + // When a control is added, an AJAX request is made which returns the widget's markup. + // We need to wait for each request to finish before we can add another field, since the + // addControlToPlaceholder requires a proper reflow of the whole form layout before + // a new field can be added. This addField helper function makes sure that all + // Promises are run in sequence to achieve this. + function addField (field) { + return function () { + var defer = $.Deferred() + $.oc.builder.formbuilder.controller.addControlToPlaceholder( + $placeholder, + field.type, + field.label ? field.label : field.column, + false, + field.column + ).complete(function () { + defer.resolve() + }) + return defer.promise() + }; + } + + /// Add all fields in sequence. + var allFields = $.when({}) + $.each(fields, function (index, field) { + allFields = allFields.then(addField(field)) + }); + + // Once everything is done, hide the load indicator. + $.when(allFields).always($.oc.builder.indexController.hideStripeIndicatorProxy) + } + ModelForm.prototype.cmdOpenForm = function(ev) { var form = $(ev.currentTarget).data('form'), model = $(ev.currentTarget).data('modelClass') diff --git a/behaviors/IndexModelFormOperations.php b/behaviors/IndexModelFormOperations.php index 4fcee76d..80243b3a 100644 --- a/behaviors/IndexModelFormOperations.php +++ b/behaviors/IndexModelFormOperations.php @@ -5,7 +5,9 @@ use RainLab\Builder\Classes\PluginCode; use RainLab\Builder\FormWidgets\FormBuilder; use RainLab\Builder\Classes\ModelModel; +use RainLab\Builder\Classes\ControlLibrary; use Backend\Classes\FormField; +use Backend\FormWidgets\DataTable; use ApplicationException; use Exception; use Request; @@ -127,6 +129,24 @@ public function onModelFormGetModelFields() ]; } + public function onModelShowAddFieldsFromDatabasePopup() + { + $columns = ModelModel::getModelColumnsAndTypes($this->getPluginCode(), Input::get('model_class')); + $config = $this->makeConfig($this->getAddFieldsFromDatabaseDataTableConfig()); + + $field = new FormField('add_fields_from_database', 'add_fields_from_database'); + $field->value = $this->getAddFieldsFromDatabaseDataTableValue($columns); + + $datatable = new DataTable($this->controller, $field, $config); + $datatable->alias = 'add_fields_from_database_datatable'; + $datatable->bindToController(); + + return $this->makePartial('add-fields-from-database-popup-form', [ + 'datatable' => $datatable, + 'pluginCode' => $this->getPluginCode()->toCode(), + ]); + } + protected function loadOrCreateFormFromPost() { $pluginCode = Request::input('plugin_code'); @@ -183,4 +203,78 @@ protected function mergeRegistryDataIntoResult(&$result, $model, $modelClass) 'modelClass' => $fullClassName ]; } + + /** + * Returns the configuration for the DataTable widget that + * is used in the "add fields from database" popup. + * + * @return array + */ + protected function getAddFieldsFromDatabaseDataTableConfig() + { + // Get all registered controls and build an array that uses the control types as key and value for each entry. + $controls = ControlLibrary::instance()->listControls(); + $fieldTypes = array_merge(array_keys($controls['Standard']), array_keys($controls['Widgets'])); + $options = array_combine($fieldTypes, $fieldTypes); + + return [ + 'toolbar' => false, + 'columns' => [ + 'add' => [ + 'title' => 'rainlab.builder::lang.common.add', + 'type' => 'checkbox', + 'width' => '50px', + ], + 'column' => [ + 'title' => 'rainlab.builder::lang.database.column_name_name', + 'readOnly' => true, + ], + 'label' => [ + 'title' => 'rainlab.builder::lang.list.column_name_label', + ], + 'type' => [ + 'title' => 'rainlab.builder::lang.form.control_widget_type', + 'type' => 'dropdown', + 'options' => $options, + ], + ], + ]; + } + + /** + * Returns the initial value for the DataTable widget that + * is used in the "add database columns" popup. + * + * @param array $columns + * + * @return array + */ + protected function getAddFieldsFromDatabaseDataTableValue(array $columns) + { + // Map database column types to widget types. + $typeMap = [ + 'string' => 'text', + 'integer' => 'number', + 'text' => 'textarea', + 'timestamp' => 'datepicker', + 'smallInteger' => 'number', + 'bigInteger' => 'number', + 'date' => 'datepicker', + 'time' => 'datepicker', + 'dateTime' => 'datepicker', + 'binary' => 'checkbox', + 'boolean' => 'checkbox', + 'decimal' => 'number', + 'double' => 'number', + ]; + + return array_map(function ($column) use ($typeMap) { + return [ + 'column' => $column['name'], + 'label' => str_replace('_', ' ', ucfirst($column['name'])), + 'type' => $typeMap[$column['type']] ?? $column['type'], + 'add' => false, + ]; + }, $columns); + } } diff --git a/behaviors/indexmodelformoperations/partials/_add-fields-from-database-popup-form.htm b/behaviors/indexmodelformoperations/partials/_add-fields-from-database-popup-form.htm new file mode 100644 index 00000000..fbad9d33 --- /dev/null +++ b/behaviors/indexmodelformoperations/partials/_add-fields-from-database-popup-form.htm @@ -0,0 +1,28 @@ +'modelForm:cmdAddFieldsFromDatabase' +]) ?> + + + + + + \ No newline at end of file diff --git a/behaviors/indexmodelformoperations/partials/_toolbar.htm b/behaviors/indexmodelformoperations/partials/_toolbar.htm index f24de8ca..a7039805 100644 --- a/behaviors/indexmodelformoperations/partials/_toolbar.htm +++ b/behaviors/indexmodelformoperations/partials/_toolbar.htm @@ -8,6 +8,16 @@ + + + +