From eab3226eb52928cbe00df81520dd122d1fb3fe15 Mon Sep 17 00:00:00 2001 From: vojtechbuba Date: Sun, 17 Jul 2022 21:55:13 +0200 Subject: [PATCH 1/4] Can change grid datamodel Simple refactoring, just introducing interface for datamodel. This change is without bc break. Now it is possible do to change datamodel with new method setDataModel. --- src/DataGrid.php | 38 +++++-- src/DataModel.php | 2 +- src/DataModelInterface.php | 27 +++++ ...nitializingDataModelCallbacksException.php | 13 +++ src/RestBasedDataModel.php | 100 ++++++++++++++++++ 5 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 src/DataModelInterface.php create mode 100644 src/Exception/InitializingDataModelCallbacksException.php create mode 100644 src/RestBasedDataModel.php diff --git a/src/DataGrid.php b/src/DataGrid.php index 81e328da2..d9801d885 100644 --- a/src/DataGrid.php +++ b/src/DataGrid.php @@ -36,10 +36,12 @@ use Ublaboo\DataGrid\Column\MultiAction; use Ublaboo\DataGrid\Components\DataGridPaginator\DataGridPaginator; use Ublaboo\DataGrid\DataSource\IDataSource; +use Ublaboo\DataGrid\Exception\CannotChangeDataModelException; use Ublaboo\DataGrid\Exception\DataGridColumnNotFoundException; use Ublaboo\DataGrid\Exception\DataGridException; use Ublaboo\DataGrid\Exception\DataGridFilterNotFoundException; use Ublaboo\DataGrid\Exception\DataGridHasToBeAttachedToPresenterComponentException; +use Ublaboo\DataGrid\Exception\InitializingDataModelCallbacksException; use Ublaboo\DataGrid\Export\Export; use Ublaboo\DataGrid\Export\ExportCsv; use Ublaboo\DataGrid\Filter\Filter; @@ -237,7 +239,7 @@ class DataGrid extends Control protected $toolbarButtons = []; /** - * @var DataModel|null + * @var DataModelInterface|null */ protected $dataModel; @@ -494,7 +496,7 @@ public function render(): void /** * Check whether datagrid has set some columns, initiated data source, etc */ - if (!($this->dataModel instanceof DataModel)) { + if (!($this->dataModel instanceof DataModelInterface)) { throw new DataGridException('You have to set a data source first.'); } @@ -623,7 +625,7 @@ public function setRowCallback(callable $callback): self */ public function setPrimaryKey(string $primaryKey): self { - if ($this->dataModel instanceof DataModel) { + if ($this->dataModel instanceof DataModelInterface) { throw new DataGridException('Please set datagrid primary key before setting datasource.'); } @@ -637,14 +639,26 @@ public function setPrimaryKey(string $primaryKey): self * @param mixed $source * @return static * @throws InvalidArgumentException + * @throws InitializingDataModelCallbacksException */ public function setDataSource($source): self { $this->dataModel = new DataModel($source, $this->primaryKey); - $this->dataModel->onBeforeFilter[] = [$this, 'beforeDataModelFilter']; - $this->dataModel->onAfterFilter[] = [$this, 'afterDataModelFilter']; - $this->dataModel->onAfterPaginated[] = [$this, 'afterDataModelPaginated']; + $this->initializeCallbacks(); + + return $this; + } + + + /** + * @throws InitializingDataModelCallbacksException + */ + public function setDataModel(DataModelInterface $dataModel): self + { + $this->dataModel = $dataModel; + + $this->initializeCallbacks(); return $this; } @@ -3324,4 +3338,16 @@ private function getPresenterInstance(): Presenter return $this->getPresenter(); } + + private function initializeCallbacks(): void + { + if ($this->dataModel === null) { + throw new InitializingDataModelCallbacksException(); + } + + $this->dataModel->onBeforeFilter[] = [$this, 'beforeDataModelFilter']; + $this->dataModel->onAfterFilter[] = [$this, 'afterDataModelFilter']; + $this->dataModel->onAfterPaginated[] = [$this, 'afterDataModelPaginated']; + } + } diff --git a/src/DataModel.php b/src/DataModel.php index d6a4394f0..20fd2c707 100644 --- a/src/DataModel.php +++ b/src/DataModel.php @@ -31,7 +31,7 @@ * @method onAfterFilter(IDataSource $dataSource) * @method onAfterPaginated(IDataSource $dataSource) */ -final class DataModel +final class DataModel implements DataModelInterface { use SmartObject; diff --git a/src/DataModelInterface.php b/src/DataModelInterface.php new file mode 100644 index 000000000..ca398bb04 --- /dev/null +++ b/src/DataModelInterface.php @@ -0,0 +1,27 @@ +dataSource = $source; + } + + + public function getDataSource(): IDataSource + { + return $this->dataSource; + } + + + public function filterData( + ?DataGridPaginator $paginatorComponent, + Sorting $sorting, + array $filters + ): iterable + { + $this->onBeforeFilter($this->dataSource); + + $this->dataSource->filter($filters); + + $this->onAfterFilter($this->dataSource); + + /** + * Paginator is optional + */ + if ($paginatorComponent !== null) { + $paginator = $paginatorComponent->getPaginator(); + + $this->dataSource->sort($sorting)->limit( + $paginator->getOffset(), + $paginator->getItemsPerPage() + ); + + $this->onAfterPaginated($this->dataSource); + + $data = $this->dataSource->getData(); + $paginator->setItemCount($this->dataSource->getCount()); + + return $data; + } + + return $this->dataSource->sort($sorting)->getData(); + } + + + /** + * @return mixed + */ + public function filterRow(array $condition) + { + $this->onBeforeFilter($this->dataSource); + $this->onAfterFilter($this->dataSource); + + return $this->dataSource->filterOne($condition)->getData(); + } +} From 0d5edc6a942b1025bbe6f13fcb9c3665e2019cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20=C5=A0er=C3=BD?= Date: Mon, 12 Sep 2022 09:50:04 +0200 Subject: [PATCH 2/4] Fixing missing quotes in CSS attribute selectors. When data attribute has a value eg. with `.`, the jQuery sizzle engine throws an error when there are no qutes around the value. --- assets/datagrid.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/datagrid.js b/assets/datagrid.js index d3c97db7a..97178323e 100644 --- a/assets/datagrid.js +++ b/assets/datagrid.js @@ -775,7 +775,7 @@ dataGridRegisterExtension('datagrid.after_inline_edit', { var grid = $('.datagrid-' + payload._datagrid_name); if (payload._datagrid_inline_edited) { - grid.find('tr[data-id=' + payload._datagrid_inline_edited + '] > td').addClass('edited'); + grid.find('tr[data-id="' + payload._datagrid_inline_edited + '"] > td').addClass('edited'); return grid.find('.datagrid-inline-edit-trigger').removeClass('hidden'); } else if (payload._datagrid_inline_edit_cancel) { return grid.find('.datagrid-inline-edit-trigger').removeClass('hidden'); @@ -884,7 +884,7 @@ dataGridRegisterExtension('datagrid.redraw-item', { success: function(payload) { var row; if (payload._datagrid_redraw_item_class) { - row = $('tr[data-id=' + payload._datagrid_redraw_item_id + ']'); + row = $('tr[data-id="' + payload._datagrid_redraw_item_id + '"]'); return row.attr('class', payload._datagrid_redraw_item_class); } } @@ -902,7 +902,7 @@ dataGridRegisterExtension('datagrid.reset-filter-by-column', { ref = payload.non_empty_filters; for (i = 0, len = ref.length; i < len; i++) { key = ref[i]; - grid.find('[data-datagrid-reset-filter-by-column=' + key + ']').removeClass('hidden'); + grid.find('[data-datagrid-reset-filter-by-column="' + key + '"]').removeClass('hidden'); } href = grid.find('.reset-filter').attr('href'); return grid.find('[data-datagrid-reset-filter-by-column]').each(function() { From 5b2070bb76898e37347ed2c5891998858e4ec362 Mon Sep 17 00:00:00 2001 From: davidspilka Date: Wed, 5 Oct 2022 17:35:00 +0200 Subject: [PATCH 3/4] Defining blocks for column actions and inline add/edit buttons - defining blocks for column actions and inline add/edit buttons - these blocks can be overwritten and custom render can be used (change order, grouping of buttons, etc.) --- src/templates/datagrid.latte | 46 ++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/templates/datagrid.latte b/src/templates/datagrid.latte index 3a70f59bb..61f86891d 100644 --- a/src/templates/datagrid.latte +++ b/src/templates/datagrid.latte @@ -270,8 +270,10 @@ {/foreach} - {input $filter['inline_edit']['cancel'], class => 'btn btn-xs btn-danger'} - {input $filter['inline_edit']['submit'], class => 'btn btn-xs btn-primary'} + {block inline-edit-buttons} + {input $filter['inline_edit']['cancel'], class => 'btn btn-xs btn-danger'} + {input $filter['inline_edit']['submit'], class => 'btn btn-xs btn-primary'} + {/block} {input $filter['inline_edit']['_id']} {input $filter['inline_edit']['_primary_where_column']} @@ -292,24 +294,26 @@ {$td->endTag()|noescape} {/foreach} - {foreach $actions as $key => $action} - {if $row->hasAction($key)} - {if $action->hasTemplate()} - {include $action->getTemplate(), item => $item, (expand) $action->getTemplateVariables(), row => $row} - {else} - {$action->render($row)|noescape} + {block col-actions} + {foreach $actions as $key => $action} + {if $row->hasAction($key)} + {if $action->hasTemplate()} + {include $action->getTemplate(), item => $item, (expand) $action->getTemplateVariables(), row => $row} + {else} + {$action->render($row)|noescape} + {/if} {/if} + {/foreach} + + + + {if $inlineEdit && $row->hasInlineEdit()} + {$inlineEdit->renderButton($row)|noescape} {/if} - {/foreach} - - - - {if $inlineEdit && $row->hasInlineEdit()} - {$inlineEdit->renderButton($row)|noescape} - {/if} - {if $itemsDetail && $itemsDetail->shouldBeRendered($row)} - {$itemsDetail->renderButton($row)|noescape} - {/if} + {if $itemsDetail && $itemsDetail->shouldBeRendered($row)} + {$itemsDetail->renderButton($row)|noescape} + {/if} + {/block} {/if} @@ -437,8 +441,10 @@ {/foreach} - {input $filter['inline_add']['cancel']} - {input $filter['inline_add']['submit']} + {block inline-add-buttons} + {input $filter['inline_add']['cancel']} + {input $filter['inline_add']['submit']} + {/block} {/if} From d22f09edc6a0d681c899aef9cdde8fd8ed9f459b Mon Sep 17 00:00:00 2001 From: davidspilka Date: Wed, 12 Oct 2022 14:46:23 +0200 Subject: [PATCH 4/4] Fixing custom classes on checkbox in inline edit - `\Nette\Forms\Controls\Checkbox::getControl` returns label part and control part like one ``\Nette\Utils\Html` and then `$control->getControl()->getAttribute('class')` is always null and custom defined classes are always overwritten by `$control->setAttribute('class', 'form-control input-sm form-control-sm');` - fixed by using `\Nette\Forms\Controls\BaseControl::getControlPrototype` which always returns only control part without label part --- src/InlineEdit/InlineEdit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InlineEdit/InlineEdit.php b/src/InlineEdit/InlineEdit.php index 33733ff7c..167e49eed 100644 --- a/src/InlineEdit/InlineEdit.php +++ b/src/InlineEdit/InlineEdit.php @@ -219,7 +219,7 @@ public function addControlsClasses(Container $container): void break; default: - if ($control->getControl()->getAttribute('class') === null) { + if ($control->getControlPrototype()->getAttribute('class') === null) { $control->setAttribute('class', 'form-control input-sm form-control-sm'); }