diff --git a/.docs/actions.md b/.docs/actions.md index bfe8e3453..241bc17f0 100644 --- a/.docs/actions.md +++ b/.docs/actions.md @@ -1,24 +1,24 @@ Table of contents - [Actions](#actions) - - [Api](#api) - - [Parameters](#parameters) - - [Icon](#icon) - - [Class](#class) - - [Title](#title) - - [Confirmation](#confirmation) - - [Ajax](#ajax) - - [Redrawing the data](#redrawing-the-data) - - [Redrawing one row](#redrawing-one-row) - - [Sortable](#sortable) - - [Sorting handler](#sorting-handler) - - [MultiAction](#multiaction) - - [Item detail](#item-detail) - - [Item detail form](#item-detail-form) - - [Item detail template variables](#item-detail-template-variables) - - [Item detail render condition](#item-detail-render-condition) - - [ActionCallback](#actioncallback) - - [Toolbar button](#toolbar-button) + - [Api](#api) + - [Parameters](#parameters) + - [Icon](#icon) + - [Class](#class) + - [Title](#title) + - [Confirmation](#confirmation) + - [Ajax](#ajax) + - [Redrawing the data](#redrawing-the-data) + - [Redrawing one row](#redrawing-one-row) + - [Sortable](#sortable) + - [Sorting handler](#sorting-handler) + - [MultiAction](#multiaction) + - [Item detail](#item-detail) + - [Item detail form](#item-detail-form) + - [Item detail template variables](#item-detail-template-variables) + - [Item detail render condition](#item-detail-render-condition) + - [ActionCallback](#actioncallback) + - [Toolbar button](#toolbar-button) # Actions @@ -105,7 +105,7 @@ All links are by default not-ajax. Do you see the bold `ajax` class in previous ```php public function handleDelete($id) { - $this->connection->delete('ublaboo_example') + $this->connection->delete('example') ->where('id = ?', $id) ->execute(); @@ -127,7 +127,7 @@ When you are updating row data (i.e. status), you can send only one row as snipp ```php public function handleSetStatus($id, $status) { - $this->connection->update('ublaboo_example', ['status' => $satatus]) + $this->connection->update('example', ['status' => $satatus]) ->where('id = ?', $id) ->execute(); @@ -242,7 +242,7 @@ The name of the handler used for sorting can be changed: $grid->setSortableHandler('foo!'); ``` -Also when you are using datagrid in component, you have to alter the name a bit: +Also, when you are using datagrid in component, you have to alter the name a bit: ```php $grid->setSortableHandler('myComponent:sort!'); @@ -250,7 +250,7 @@ $grid->setSortableHandler('myComponent:sort!'); ## MultiAction -Same as there is column status with pretty dropdown menu, ublaboo datagrid comes with similar dropdown menu for actions. It is called MultiAction: +Same as there is column status with pretty dropdown menu, the datagrid comes with similar dropdown menu for actions. It is called MultiAction: ```php /** @@ -261,7 +261,7 @@ $grid->addMultiAction('multi_action', 'MultiAction') ->addAction('blah2', 'Blahblah2', 'blah!', ['name']); ``` -Sure you can alter multiaction class, icons, etc. Same you can change icon, class, etc of nested actions: +Sure you can alter multiaction class, icons, etc. Same you can change icon, class, etc. of nested actions: ```php $grid->getAction('multi_blah') @@ -312,7 +312,7 @@ $grid->setItemsDetailForm(function(Nette\Forms\Container $container) use ($grid, }); ``` -DataGrid user template: +Datagrid user template: ```latte {extends $originalTemplate} @@ -361,7 +361,7 @@ $grid->addActionCallback('custom_callback', '') }; ``` -You treat `ActionCallback` same as `Action`, except for some arguments passed to the `DataGrid::addActionCallback` method. +You treat `ActionCallback` same as `Action`, except for some arguments passed to the `Datagrid::addActionCallback` method. ## Toolbar button diff --git a/.docs/assets.md b/.docs/assets.md index 541d991db..d51a304a7 100644 --- a/.docs/assets.md +++ b/.docs/assets.md @@ -6,116 +6,103 @@ Table of contents # Assets -DataGrid needs for its precise functionality some third party scripts and styles. Install all required assets with NPM. +There are prepare JS/TS and CSS files for precise functionality. The best way is to use some frontend bundler, for example [Vite](https://vitejs.dev). -**CSS (external)** +## Installation -- bootstrap -- bootstrap datepicker -- bootstrap select - -**CSS** - -- datagrid.css -- datagrid-spinners.css - -**JS (external)** - -- jquery -- nette forms -- nette ajax / naja -- bootstrap -- bootstrap datepicker -- bootstrap select - -**JS** - -- datagrid.js -- datagrid-instant-url-refresh.js -- datagrid-spinners.js - -**Icons** - -You will probably want to use some icon font, but that is in your command. -On this project website we use font awesome (you can change the icon prefix by setting new value to static property `DataGrid::$iconPrefix = 'fa fa-';`). - -**Spinners** - -As you can see, there is also a `datagrid-spinners.js` script in a datagrid repository. If you include this file within you project layout, there are some actions, that will show spinner/some other animation when waiting for ajax response. Actions, that has somehow animated spinner: - -- Group actions -- Pagination -- Changing items per page -- Toggling item detail - loading the detail for the first time - -## NPM - -``` -npm install --save ublaboo-datagrid -``` - -package.json: +You need to install datagrid's assets. For example this way. ```json { - "dependencies": { - "bootstrap-datepicker": "^1.9", - "bootstrap-select": "^1.13", - "bootstrap": "^4.4.1", - "happy-inputs": "^2.0", - "jquery": "^3.4.1", - "jquery-ui-sortable": "^1.0", - "nette-forms": "^3.0", - "nette.ajax.js": "^2.3", - "popper.js": "^1.14.7", - "ublaboo-datagrid": "^6.2" - } + "dependencies": { + "@contributte/datagrid": "git+ssh://git@github.com:contributte/datagrid.git#next" + } } ``` -## Example html when not using NPM - -```html - - - - - - - - - - - - - +## - - +## Demo - - - - - - - - - - +**package.json** - - - - - +```json +{ + "dependencies": { + "@contributte/datagrid": "git+ssh://git@github.com:contributte/datagrid.git#next", + "@fortawesome/fontawesome-free": "^6.3.0", + "bootstrap": "^5.3.0-alpha3", + "naja": "^2.5.0", + "nette-forms": "^3.3.1", + "prismjs": "^1.29.0", + "sortablejs": "^1.15.0", + "tom-select": "^2.2.2", + "vanillajs-datepicker": "^1.3.1" + }, + "devDependencies": { + "@types/bootstrap-select": "^1.13.4", + "@types/jquery": "^3.5.16", + "@types/jqueryui": "^1.12.16", + "@types/sortablejs": "^1.15.1", + "@types/vanillajs-datepicker": "^1.2.1", + "autoprefixer": "^10.4.0", + "typescript": "^4.9.5", + "vite": "^2.6.10" + }, + "scripts": { + "watch": "vite build --watch --mode=development", + "build": "vite build --mode=production" + } +} +``` - - - - +**vite.config.js** + +```js +import { defineConfig } from 'vite'; +import { resolve } from 'path'; + +export default defineConfig(({ mode }) => { + const DEV = mode === 'development'; + + return { + publicDir: './assets/public', + resolve: { + alias: { + '@': resolve(__dirname, 'assets/js'), + '~': resolve(__dirname, 'node_modules'), + }, + }, + base: '/dist/', + server: { + open: false, + hmr: false, + }, + css: { + postcss: [ + "autoprefixer" + ] + }, + build: { + manifest: true, + assetsDir: '', + outDir: './www/dist/', + emptyOutDir: true, + minify: DEV ? false : 'esbuild', + rollupOptions: { + output: { + manualChunks: undefined, + chunkFileNames: '[name].js', + entryFileNames: '[name].js', + assetFileNames: '[name].[ext]', + }, + input: { + app: './assets/js/main.js' + } + } + }, + } +}); ``` diff --git a/.docs/columns.md b/.docs/columns.md index cd4f9f6e2..fe40b157d 100644 --- a/.docs/columns.md +++ b/.docs/columns.md @@ -1,35 +1,35 @@ Table of contents - [Columns](#columns) - - [Api](#api) - - [Parameters](#parameters) - - [Templates](#templates) - - [Renderers](#renderers) - - [Replacement](#replacement) - - [Escaping values](#escaping-values) - - [Sorting](#sorting) - - [Resetting pagination after sorting](#resetting-pagination-after-sorting) - - [Default sort](#default-sort) - - [Resetting default sort](#resetting-default-sort) - - [Multiple columns sort](#multiple-columns-sort) - - [Default per page](#default-per-page) - - [Custom sorting Callback](#custom-sorting-callback) - - [Align](#align) - - [Removing column](#removing-column) - - [Column Text](#column-text) - - [Column Number](#column-number) - - [Column DateTime](#column-datetime) - - [Column Link](#column-link) - - [Open in new tab](#open-in-new-tab) - - [Column Status](#column-status) - - [Hideable columns](#hideable-columns) - - [Default hide](#default-hide) - - [Columns Summary](#columns-summary) - - [Aggregation Function](#aggregation-function) - - [Single column](#single-column) - - [Multiple columns](#multiple-columns) - - [Column \(th>, td>\) attributes](#column-th-td-attributes) - - [Column callback](#column-callback) + - [Api](#api) + - [Parameters](#parameters) + - [Templates](#templates) + - [Renderers](#renderers) + - [Replacement](#replacement) + - [Escaping values](#escaping-values) + - [Sorting](#sorting) + - [Resetting pagination after sorting](#resetting-pagination-after-sorting) + - [Default sort](#default-sort) + - [Resetting default sort](#resetting-default-sort) + - [Multiple columns sort](#multiple-columns-sort) + - [Default per page](#default-per-page) + - [Custom sorting Callback](#custom-sorting-callback) + - [Align](#align) + - [Removing column](#removing-column) + - [Column Text](#column-text) + - [Column Number](#column-number) + - [Column DateTime](#column-datetime) + - [Column Link](#column-link) + - [Open in new tab](#open-in-new-tab) + - [Column Status](#column-status) + - [Hideable columns](#hideable-columns) + - [Default hide](#default-hide) + - [Columns Summary](#columns-summary) + - [Aggregation Function](#aggregation-function) + - [Single column](#single-column) + - [Multiple columns](#multiple-columns) + - [Column \(th>, td>\) attributes](#column-th-td-attributes) + - [Column callback](#column-callback) # Columns @@ -39,7 +39,7 @@ There are several column classes and they all have some common behaviour and pro ### Parameters -Lets add a simple text column like we've done before: +Let's add a simple text column like we've done before: ```php $grid->addColumnText('name', 'Name'); @@ -55,7 +55,7 @@ $grid->addColumnText('name3', 'Name', 'name'); ### Templates -Column may have it's own template. I will add one more parameter (optional) to the method `::setTemplate()`, just for fun: +Columns may have it's own template. I will add one more parameter (optional) to the method `::setTemplate()`, just for fun: ```php $grid->addColumnText('name', 'Name') @@ -76,7 +76,7 @@ $grid->addColumnText('name', 'Name') }); ``` -But hey, what if i want to replace **just some** rows? No problem, the second optional argument tells me (callback again) whether the datagrid should use your renderer or not. Example: +But hey, what if I want to replace **just some** rows? No problem, the second optional argument tells me (callback again) whether the datagrid should use your renderer or not. Example: ```php $grid->addColumnText('name', 'Name') @@ -117,7 +117,7 @@ $grid->addColumnText('name', 'Name') ->setSortable(); ``` -When using doctrine as data source, you can output data the object way using dot-notaion and property accessor. But when you are using collumn of related table for sorting, you probably want to use alias for sorting: +When using doctrine as data source, you can output data the object way using dot-notation and property accessor. But when you are using column of related table for sorting, you probably want to use alias for sorting: ```php $grid->addColumnText('role', 'User role', 'role.name') @@ -134,7 +134,7 @@ $grid->addColumnText('name', 'Name') ### Default sort -`DataGrid` implements default sorting mechanism: +`Datagrid` implements default sorting mechanism: ```php $grid->setDefaultSort(['name' => 'DESC']); @@ -142,7 +142,7 @@ $grid->setDefaultSort(['name' => 'DESC']); ### Resetting default sort -By default, once you reset the filter, default sort is applied. If you don't want to apply it after resetting the filter, pass FALSE as a second parameter to `DataGrid::setDefaultSort()`: +By default, once you reset the filter, default sort is applied. If you don't want to apply it after resetting the filter, pass FALSE as a second parameter to `Datagrid::setDefaultSort()`: ```php $grid->setDefaultSort(['id' => 'DESC'], FALSE); @@ -150,7 +150,7 @@ $grid->setDefaultSort(['id' => 'DESC'], FALSE); ### Multiple columns sort -Sorting by multiple columns is disabled by default. But can be enaled: +Sorting by multiple columns is disabled by default. But can be enabled: ```php $grid->setMultiSortEnabled($enabled = TRUE); // Pass FALSE to disable @@ -266,7 +266,7 @@ $grid->addColumnLink('name', 'Name', 'edit') ![Status 1](https://github.com/contributte/datagrid/blob/master/.docs/assets/status1.gif?raw=true) ![Status 1](https://github.com/contributte/datagrid/blob/master/.docs/assets/status2.gif?raw=true) -Once your item keep some "status" flag, it is appropriate to show user the status in highlighted form. Also there could be a dropdown with available statuses: +Once your item keep some "status" flag, it is appropriate to show user the status in highlighted form. Also, there could be a dropdown with available statuses: ```php $grid->addColumnStatus('status', 'Status') @@ -347,7 +347,7 @@ $grid->getColumn('status')->getOption(2) ![Columns Hiding](https://github.com/contributte/datagrid/blob/master/.docs/assets/hideable_columns.gif?raw=true) -In example datargid above, you can hide columns and then reveal them again. This feature is disabled by default. You can enable it like this: +In example datagrid above, you can hide columns and then reveal them again. This feature is disabled by default. You can enable it like this: ```php $grid->setColumnsHideable(); @@ -370,7 +370,7 @@ If default hide is used, new button is shown in that settings (gear) dropdown - ## Columns Summary -Datagrid implements a feature that allows you to display **sum** of column of displayed items at the bootom of the grid. Try it out: +Datagrid implements a feature that allows you to display **sum** of column of displayed items at the bottom of the grid. Try it out: ```php $grid->addColumnNumber('in', 'Income') @@ -422,11 +422,11 @@ $grid->addAggregationFunction('status', new FunctionSum('id')); This will render a sum of ids under the `"status"` column. -As mentioned above, there is one aggregation function prepared: `Ublaboo\DataGrid\AggregationFunction\FunctionSum`. You can implement whatever function you like, it just have to implement `Ublaboo\DataGrid\AggregationFunction\ISingleColumnAggregationFunction`. +As mentioned above, there is one aggregation function prepared: `Contributte\Datagrid\AggregationFunction\FunctionSum`. You can implement whatever function you like, it just have to implement `Contributte\Datagrid\AggregationFunction\ISingleColumnAggregationFunction`. ### Multiple columns -In case you want to make the aggreagation directly using SQL by your domain, you will probably use interface `IMultipleAggregationFunction` (instead of `ISingleColumnAggregationFunction`): +In case you want to make the aggregation directly using SQL by your domain, you will probably use interface `IMultipleAggregationFunction` (instead of `ISingleColumnAggregationFunction`): ```php $grid->setMultipleAggregationFunction( @@ -476,7 +476,7 @@ $grid->setMultipleAggregationFunction( ); ``` -This aggregatin is used along with `Dibi` in the demo. +This aggregating is used along with `Dibi` in the demo. ## Column (th>, td>) attributes @@ -499,7 +499,7 @@ $grid->addColumnText('name', 'Name') ## Column callback -When you need to modify columns just before rendering (meybe remove some status options or completely change renderer for partucular items), you can create column callback, that will be called with `$column` and `$item` in parameter: +When you need to modify columns just before rendering (maybe remove some status options or completely change renderer for particular items), you can create column callback, that will be called with `$column` and `$item` in parameter: ```php $grid->addColumnLink('link', 'Link', 'this#demo', 'name', ['id', 'surname' => 'name']); @@ -531,7 +531,7 @@ $grid->addColumnCallback('link', function($column, $item) { }); ``` -That is the code of the demove shown above. As you can see, item with id == 1 does have a empty link column and only 2 options in `ColumnStatus`. +That is the code of the demo shown above. As you can see, item with id == 1 does have an empty link column and only 2 options in `ColumnStatus`. ```php diff --git a/.docs/data-source.md b/.docs/data-source.md index 63fd00fcf..7887299b1 100644 --- a/.docs/data-source.md +++ b/.docs/data-source.md @@ -1,10 +1,10 @@ Table of contents - [Data sources](#data-sources) - - [ORM Relations](#orm-relations) - - [ApiDataSource](#apidatasource) - - [NextrasDataSource](#nextrasdatasource) - - [NetteDatabaseTableDataSource](#nettedatabasetabledatasource) + - [ORM Relations](#orm-relations) + - [ApiDataSource](#apidatasource) + - [NextrasDataSource](#nextrasdatasource) + - [NetteDatabaseTableDataSource](#nettedatabasetabledatasource) # Data sources @@ -44,7 +44,7 @@ Once you have set a data source, you can add columns to the datagrid. ## ORM Relations -When you are using for example Doctrine as a data source, you can easily access another related entites for rendering in column. Let's say you have an entity `User` and each instance can have a property `$name` and `$grandma`. `$grandma` is also an instance of `User` class. Displaying people and their grandmas is very simple then - just use this dot notation: +When you are using for example Doctrine as a data source, you can easily access another related entities for rendering in column. Let's say you have an entity `User` and each instance can have a property `$name` and `$grandma`. `$grandma` is also an instance of `User` class. Displaying people and their grandmas is very simple then - just use this dot notation: ```php $grid->addColumnText('name', 'Name', 'name'); @@ -59,7 +59,7 @@ Basic usage: ```php $grid->setDataSource( - new Ublaboo\DataGrid\DataSource\ApiDataSource('http://my.remote.api') + new Contributte\Datagrid\DataSource\ApiDataSource('http://my.remote.api') ); ``` @@ -67,7 +67,7 @@ The idea is simply to forward filtering/sorting/limit/... to remote api. Feel fr ## NextrasDataSource -There is one specific behaviour when using Netras ORM. When custom filter conditions are used, user has to work not with given `Collection` instance, but with `Collection::getQueryBuilder()`. That snippet of code will not work correctly, because `DbalCollection` calls clone on each of it's methods: +There is one specific behaviour when using Nextras ORM. When custom filter conditions are used, user has to work not with given `Collection` instance, but with `Collection::getQueryBuilder()`. That snippet of code will not work correctly, because `DbalCollection` calls clone on each of it's methods: ```php $grid->getFilter('name') diff --git a/.docs/export.md b/.docs/export.md index 4de88b390..ccdc97226 100644 --- a/.docs/export.md +++ b/.docs/export.md @@ -1,17 +1,17 @@ Table of contents - [Exports](#exports) - - [ExportCallback](#exportcallback) - - [CSV export](#csv-export) - - [\(Not\) Using templates in CSV export](#not-using-templates-in-csv-export) - - [Export columns](#export-columns) - - [Export encoding, delimiter](#export-encoding-delimiter) + - [ExportCallback](#exportcallback) + - [CSV export](#csv-export) + - [\(Not\) Using templates in CSV export](#not-using-templates-in-csv-export) + - [Export columns](#export-columns) + - [Export encoding, delimiter](#export-encoding-delimiter) # Exports ## ExportCallback -DataGrid allows you to export the data via `$grid->addExportCallback()`. The parameters are: +Datagrid allows you to export the data via `$grid->addExportCallback()`. The parameters are: ```php /** @@ -38,15 +38,15 @@ $grid->addExportCsv('Csv export (filtered)', 'examples.csv') ### (Not) Using templates in CSV export -ExportCsv ignores column template, because i don't like the idea Latte (tempalting engine for HTML) exporting data for CSV format. Using custom renderer sounds better to me in that case. +ExportCsv ignores column template, because i don't like the idea Latte (templating engine for HTML) exporting data for CSV format. Using custom renderer sounds better to me in that case. ## Export columns -When you exporting the data, you can have different columns in export and in the datagrid. Or differently rendered. So there is another method `Ublaboo\DataGrid\Export\Export::setColumns()`. You can create instances of another columns and pass them in array to this method. These will be rendered in export: +When you're exporting the data, you can have different columns in export and in the datagrid. Or differently rendered. So there is another method `Contributte\Datagrid\Export\Export::setColumns()`. You can create instances of another columns and pass them in array to this method. These will be rendered in export: ```php -$column_name = new Ublaboo\DataGrid\Column\ColumnText($grid, 'name', 'name', 'Name'); -$column_even = (new Ublaboo\DataGrid\Column\ColumnText($grid, 'name', 'even', 'Even ID (yes/no)')) +$column_name = new Contributte\Datagrid\Column\ColumnText($grid, 'name', 'name', 'Name'); +$column_even = (new Contributte\Datagrid\Column\ColumnText($grid, 'name', 'even', 'Even ID (yes/no)')) ->setRenderer(function(array $item): string { return $item['id'] % 2 ? 'No' : 'Yes'; }); @@ -61,7 +61,7 @@ $grid->addExportCsv('Csv export', 'examples_all.csv') ## Export encoding, delimiter -By default, DataGrid exports data in `utf-8` with semicolon delimiter `;`. This can be changed: +By default, Datagrid exports data in `utf-8` with semicolon delimiter `;`. This can be changed: ```php /** diff --git a/.docs/filters.md b/.docs/filters.md index 5cb530f43..c14061ffb 100644 --- a/.docs/filters.md +++ b/.docs/filters.md @@ -1,27 +1,27 @@ Table of contents - [Filters](#filters) - - [Api](#api) - - [Placeholder](#placeholder) - - [Custom where condition](#custom-where-condition) - - [Templates:](#templates) - - [Filter blocks](#filter-blocks) - - [Filter type blocks](#filter-type-blocks) - - [Removing filter](#removing-filter) - - [FilterText](#filtertext) - - [FilterSelect](#filterselect) - - [FilterMultiSelect](#filtermultiselect) - - [FilterDate](#filterdate) - - [FilterRange](#filterrange) - - [FilterDateRange](#filterdaterange) - - [Default filter values](#default-filter-values) - - [Resetting filter to default values](#resetting-filter-to-default-values) - - [Filters rendering](#filters-rendering) - - [Outer filters rendering](#outer-filters-rendering) - - [Session - remeber state](#session---remeber-state) - - [Session - filters / filter values changed](#session---filters--filter-values-changed) - - [URL refreshing - history API](#url-refreshing---history-api) - - [Auto submit](#auto-submit) + - [Api](#api) + - [Placeholder](#placeholder) + - [Custom where condition](#custom-where-condition) + - [Templates:](#templates) + - [Filter blocks](#filter-blocks) + - [Filter type blocks](#filter-type-blocks) + - [Removing filter](#removing-filter) + - [FilterText](#filtertext) + - [FilterSelect](#filterselect) + - [FilterMultiSelect](#filtermultiselect) + - [FilterDate](#filterdate) + - [FilterRange](#filterrange) + - [FilterDateRange](#filterdaterange) + - [Default filter values](#default-filter-values) + - [Resetting filter to default values](#resetting-filter-to-default-values) + - [Filters rendering](#filters-rendering) + - [Outer filters rendering](#outer-filters-rendering) + - [Session - remeber state](#session---remeber-state) + - [Session - filters / filter values changed](#session---filters--filter-values-changed) + - [URL refreshing - history API](#url-refreshing---history-api) + - [Auto submit](#auto-submit) # Filters @@ -111,7 +111,7 @@ There is how the default FilterText template looks like:
{label $input class =>; 'col-sm-3 control-label' /}
- {input $input, class => 'form-control input-sm', data-autosubmit => true} + {input $input, class => 'form-control form-control-sm', data-autosubmit => true}
@@ -218,7 +218,7 @@ $grid->addFilterDateRange('date_created', 'User registered:'); ## Default filter values -Datagrid filters can have contain default filter values. Once user changes the filter, default values are not longer applied to the filter. Example usage: +Datagrid filters can have default filter values. Once user changes the filter, default values are no longer applied to the filter. Example usage: ```php $grid->setDefaultFilter(['status' => 1, 'name' => 'Joe']); @@ -240,7 +240,7 @@ $grid->setDefaultFilter(['status' => [1], 'age' => ['from' => 18]]); ### Resetting filter to default values -By default, once you reset the filter, default fitler values are applied. If you don't want to apply them after resetting the filter, pass false as a second parameter to `DataGrid::setDefaultFilter()`: +By default, once you reset the filter, default fitler values are applied. If you don't want to apply them after resetting the filter, pass false as a second parameter to `Datagrid::setDefaultFilter()`: ```php $grid->setDefaultFilter('id' => 10, false); @@ -270,13 +270,13 @@ $grid->setOuterFilterRendering(); // - that is true. Or $grid->setOuterFilterRen ## Session - remeber state -Grid refreshes its state on several levels. One could be session. It is by defaut turned on, but can be disabled: +Grid refreshes its state on several levels. One could be session. It is by default turned on, but can be disabled: ```php $grid->setRememberState(false); // Or turned on again: $grid->setRememberState(true); ``` -If you want to keep hideable columns in session even when rememebr state is turned off, use second argument: +If you want to keep hideable columns in session even when remember state is turned off, use second argument: ```php $grid->setRememberState(false, true); @@ -284,7 +284,7 @@ $grid->setRememberState(false, true); ## Session - filters / filter values changed -When you set some filters and user do some filtering, values are stored in session. After that, when filters are changed (maybe some select options are removed, etc), datagrid would throw an exception, because it can not find particular filters / filter values that are still stored in session. You can supress those exception: +When you set some filters and user do some filtering, values are stored in session. After that, when filters are changed (maybe some select options are removed, etc.), datagrid would throw an exception, because it can not find particular filters / filter values that are still stored in session. You can suppress those exception: ```php $grid->setStrictSessionFilterValues(false); @@ -300,7 +300,7 @@ $grid->setRefreshUrl(false); // Or enabled again: $grid->setRefreshUrl(true); ## Auto submit -DataGrid filter is submitted automatically after keypress (there is of course a little delay). If you want to disable that feature and use customizable submit button instead, use this code: +Datagrid filter is submitted automatically after keypress (there is of course a little delay). If you want to disable that feature and use customizable submit button instead, use this code: ```php $grid->setAutoSubmit(false); diff --git a/.docs/group-action.md b/.docs/group-action.md index 1172dfbcd..ff26feb7b 100644 --- a/.docs/group-action.md +++ b/.docs/group-action.md @@ -1,14 +1,14 @@ Table of contents - [Group action](#group-action) - - [Api](#api) - - [Zero level](#zero-level) - - [One level](#one-level) - - [Two level](#two-level) - - [Text input](#text-input) - - [Textarea](#textarea) - - [Attributes, classes](#attributes-classes) - - [Happy inputs](#happy-inputs) + - [Api](#api) + - [Zero level](#zero-level) + - [One level](#one-level) + - [Two level](#two-level) + - [Text input](#text-input) + - [Textarea](#textarea) + - [Attributes, classes](#attributes-classes) + - [Happy inputs](#happy-inputs) # Group action @@ -32,10 +32,10 @@ $grid->addGroupButtonAction('Say hello')->onClick[] = [$this, 'sayHello']; ```php $grid->addGroupAction('Delete examples')->onSelect[] = [$this, 'deleteExamples']; -$grid->addGroupAction('Something alse')->onSelect[] = [$this, 'doSomethingElse']; +$grid->addGroupAction('Something else')->onSelect[] = [$this, 'doSomethingElse']; ``` -This will create one select box (['Delete examples', 'Something alse']) and submit button. If you submit that form, your handler will be called. It will be called via ajax. +This will create one select box (['Delete examples', 'Something else']) and submit button. If you submit that form, your handler will be called. It will be called via ajax. This is how your handler can look like: @@ -64,7 +64,7 @@ $grid->addGroupAction('Change order status', [ 2 => 'Ready', 3 => 'Processing', 4 => 'Sent', - 5 => 'Storno' + 5 => 'Canceled' ])->onSelect[] = [$this, 'groupChangeStatus']; $grid->addGroupAction('Send', [ @@ -97,7 +97,7 @@ public function groupChangeStatus(array $ids, $status): void ### Text input -Group action can also containe a text input instad of select (As show in example above - option called "**Add note**"). Example code: +Group action can also contain a text input instead of select (As show in example above - option called "**Add note**"). Example code: ```php $grid->addGroupTextAction('Add note') @@ -143,7 +143,7 @@ $grid->addGroupTextareaAction('aaaa') ## Happy inputs -DataGrid uses tiny library `happy` for those nice checkboxes. You can disable them: +Datagrid uses tiny library `happy` for those nice checkboxes. You can disable them: ```php $grid->useHappyComponents(false); diff --git a/.docs/index.md b/.docs/index.md index aec51d7eb..a9721d150 100644 --- a/.docs/index.md +++ b/.docs/index.md @@ -59,22 +59,22 @@ composer require ublaboo/datagrid - Hideable columns - Ajax spinners -DataGrid can do some really useful stuff. +Datagrid can do some really useful stuff. Let's create a datagrid component! We will demonstrate our examples in Presenters. ```php -use Ublaboo\DataGrid\DataGrid; +use Contributte\Datagrid\Datagrid; class SimplePresenter extends BasePresenter { public function createComponentSimpleGrid($name) { - $grid = new DataGrid($this, $name); + $grid = new Datagrid($this, $name); - $grid->setDataSource($this->db->select('*')->from('ublaboo_example')); + $grid->setDataSource($this->db->select('*')->from('example')); $grid->addColumnText('name', 'Name'); } diff --git a/.docs/inline-edit.md b/.docs/inline-edit.md index 8f1882a8f..7b384559a 100644 --- a/.docs/inline-edit.md +++ b/.docs/inline-edit.md @@ -1,12 +1,12 @@ Table of contents - [Inline editing](#inline-editing) - - [Small inline editing](#small-inline-editing) - - [Different input types and element attributes](#different-input-types-and-element-attributes) - - [Render different content then is edited](#render-different-content-then-is-edited) - - [Big inline editing](#big-inline-editing) - - [What happens after editing](#what-happens-after-editing) - - [Show non editing Columns](#show-non-editing-columns) + - [Small inline editing](#small-inline-editing) + - [Different input types and element attributes](#different-input-types-and-element-attributes) + - [Render different content then is edited](#render-different-content-then-is-edited) + - [Big inline editing](#big-inline-editing) + - [What happens after editing](#what-happens-after-editing) + - [Show non editing Columns](#show-non-editing-columns) # Inline editting @@ -85,9 +85,9 @@ Example useage: ```php /** - * @var Ublaboo\DataGrid\DataGrid + * @var Contributte\Datagrid\Datagrid */ -$grid = new DataGrid($this, $name); +$grid = new Datagrid($this, $name); /** * Big inline editing @@ -118,7 +118,7 @@ $grid->getInlineEdit()->onSubmit[] = function($id, Nette\Utils\ArrayHash $values ### What happens after editing -By default, after submitting inline edit, the row is redrawed and the green animated background is triggered. Bud if you want to do something else, you can, just create new listener to event `InlineEdit::onCustomRedraw()`: +By default, after submitting inline edit, the row is redrawn and the green animated background is triggered. Bud if you want to do something else, you can, just create new listener to event `InlineEdit::onCustomRedraw()`: ```php /** diff --git a/.docs/localization.md b/.docs/localization.md index 132cce4c9..e6f7ecaf5 100644 --- a/.docs/localization.md +++ b/.docs/localization.md @@ -5,17 +5,17 @@ Table of contents # Localization -As you can see in the example below, a `SimpleTranslator` class comes with datagrid (the example was translated to czech). You can use it as shown (you will do that probably in some factory for all datagrids in your application). Of course you can use your own translator - it just has to implement `Nette\Localization\ITranslator`. +As you can see in the example below, a `SimpleTranslator` class comes with datagrid (the example was translated to czech). You can use it as shown (you will do that probably in some factory for all datagrids in your application). Of course, you can use your own translator - it just has to implement `Nette\Localization\Translator`. ```php -public function createComponentLocalizationGrid($name): Ublaboo\DataGrid\DataGrid +public function createComponentLocalizationGrid($name): Contributte\Datagrid\Datagrid { - $grid = new DataGrid($this, $name); + $grid = new Datagrid($this, $name); - $grid->setDataSource($this->ndb->table('ublaboo_example')); + $grid->setDataSource($this->ndb->table('example')); $grid->addColumnNumber('id', 'Id') - ->setAlign('left') + ->setAlign('start') ->setSortable(); $grid->addColumnText('name', 'Name') @@ -23,22 +23,22 @@ public function createComponentLocalizationGrid($name): Ublaboo\DataGrid\DataGri $grid->addColumnDateTime('inserted', 'Inserted'); - $translator = new Ublaboo\DataGrid\Localization\SimpleTranslator([ - 'ublaboo_datagrid.no_item_found_reset' => 'Žádné položky nenalezeny. Filtr můžete vynulovat', - 'ublaboo_datagrid.no_item_found' => 'Žádné položky nenalezeny.', - 'ublaboo_datagrid.here' => 'zde', - 'ublaboo_datagrid.items' => 'Položky', - 'ublaboo_datagrid.all' => 'všechny', - 'ublaboo_datagrid.from' => 'z', - 'ublaboo_datagrid.reset_filter' => 'Resetovat filtr', - 'ublaboo_datagrid.group_actions' => 'Hromadné akce', - 'ublaboo_datagrid.show_all_columns' => 'Zobrazit všechny sloupce', - 'ublaboo_datagrid.hide_column' => 'Skrýt sloupec', - 'ublaboo_datagrid.action' => 'Akce', - 'ublaboo_datagrid.previous' => 'Předchozí', - 'ublaboo_datagrid.next' => 'Další', - 'ublaboo_datagrid.choose' => 'Vyberte', - 'ublaboo_datagrid.execute' => 'Provést', + $translator = new Contributte\Datagrid\Localization\SimpleTranslator([ + 'contributte_datagrid.no_item_found_reset' => 'Žádné položky nenalezeny. Filtr můžete vynulovat', + 'contributte_datagrid.no_item_found' => 'Žádné položky nenalezeny.', + 'contributte_datagrid.here' => 'zde', + 'contributte_datagrid.items' => 'Položky', + 'contributte_datagrid.all' => 'všechny', + 'contributte_datagrid.from' => 'z', + 'contributte_datagrid.reset_filter' => 'Resetovat filtr', + 'contributte_datagrid.group_actions' => 'Hromadné akce', + 'contributte_datagrid.show_all_columns' => 'Zobrazit všechny sloupce', + 'contributte_datagrid.hide_column' => 'Skrýt sloupec', + 'contributte_datagrid.action' => 'Akce', + 'contributte_datagrid.previous' => 'Předchozí', + 'contributte_datagrid.next' => 'Další', + 'contributte_datagrid.choose' => 'Vyberte', + 'contributte_datagrid.execute' => 'Provést', 'Name' => 'Jméno', 'Inserted' => 'Vloženo' diff --git a/.docs/row.md b/.docs/row.md index 88a27db21..21393e574 100644 --- a/.docs/row.md +++ b/.docs/row.md @@ -1,12 +1,12 @@ Table of contents - [Row](#row) - - [Row conditions](#row-conditions) - - [Allow Group Action](#allow-group-action) - - [Allow Inline Edit](#allow-inline-edit) - - [Allow Actions](#allow-actions) - - [Allow Action of MultiAction](#allow-action-of-multiaction) - - [Row callback](#row-callback) + - [Row conditions](#row-conditions) + - [Allow Group Action](#allow-group-action) + - [Allow Inline Edit](#allow-inline-edit) + - [Allow Actions](#allow-actions) + - [Allow Action of MultiAction](#allow-action-of-multiaction) + - [Row callback](#row-callback) # Row @@ -14,7 +14,7 @@ Table of contents ### Allow Group Action -Now all rows have to provide group action or editing. Or some other of your actions. You can forbid group acitons rendering for some items like this: +Now all rows have to provide group action or editing. Or some other of your actions. You can forbid group actions rendering for some items like this: ```php $grid->allowRowsGroupAction(function(Row $item): bool { @@ -24,7 +24,7 @@ $grid->allowRowsGroupAction(function(Row $item): bool { ### Allow Inline Edit -Also inline editing cound be disabled for some rows: +Also, inline editing can be disabled for some rows: ```php $grid->allowRowsInlineEdit(function(Row $item): bool { @@ -34,7 +34,7 @@ $grid->allowRowsInlineEdit(function(Row $item): bool { ### Allow Actions -It works simalary when you want to allow actions for just some of your items: +It works similarly, when you want to allow actions for just some of your items: ```php $grid->allowRowsAction('delete', function(Row $item): bool { diff --git a/.docs/tree-view.md b/.docs/tree-view.md index b84d3a443..d2cab9ccc 100644 --- a/.docs/tree-view.md +++ b/.docs/tree-view.md @@ -44,7 +44,7 @@ Click the link "Show me the code" above. This will show you the code of this dat ## Redrawing one row (ajax) -Different situation occurs when you need to redraw just one row. DataGrid does not know about all the items (it has originally only top level rows). So before you call `DataGrid::redrawItem()`, you have to set datagrid datasource where the item will be visible: +Different situation occurs when you need to redraw just one row. Datagrid does not know about all the items (it has originally only top level rows). So before you call `Datagrid::redrawItem()`, you have to set datagrid datasource where the item will be visible: ```php public function handleSetCategoryStatus($id, $status): void @@ -54,12 +54,12 @@ public function handleSetCategoryStatus($id, $status): void $this->flashMessage("Status of category [$id] was updated to [$status].", 'success'); $join = $this->db->select('COUNT(id) AS count, parent_category_id') - ->from('ublaboo_category') + ->from('category') ->groupBy('parent_category_id'); $fluent = $this->db ->select('c.*, c_b.count as has_children') - ->from('ublaboo_category', 'c') + ->from('category', 'c') ->leftJoin($join, 'c_b') ->on('c_b.parent_category_id = c.id'); diff --git a/.github/workflows/codesniffer.yml b/.github/workflows/codesniffer.yml index 429610ad0..99c0ec898 100644 --- a/.github/workflows/codesniffer.yml +++ b/.github/workflows/codesniffer.yml @@ -14,4 +14,4 @@ jobs: name: "Codesniffer" uses: contributte/.github/.github/workflows/codesniffer.yml@v1 with: - php: "8.1" + php: "8.3" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 995e29439..caa5f06fe 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -10,11 +10,11 @@ on: - cron: "0 8 * * 1" jobs: - test80: + test82: name: "Nette Tester" uses: contributte/.github/.github/workflows/nette-tester-mysql.yml@v1 with: - php: "8.1" + php: "8.3" database: tests coverage: true - makefile: coverage + make: coverage diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 69fdbbea9..c6f372726 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -14,4 +14,4 @@ jobs: name: "Phpstan" uses: contributte/.github/.github/workflows/phpstan.yml@v1 with: - php: "8.1" + php: "8.3" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a6f8382c3..63de088a3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,31 +10,23 @@ on: - cron: "0 8 * * 1" jobs: - test81: + test83: name: "Nette Tester" uses: contributte/.github/.github/workflows/nette-tester-mysql.yml@v1 with: - php: "8.1" - database: tests + php: "8.3" + database: tests - test80: + test82: name: "Nette Tester" uses: contributte/.github/.github/workflows/nette-tester-mysql.yml@v1 with: - php: "8.0" - database: tests + php: "8.2" + database: tests - test74: - name: "Nette Tester" - uses: contributte/.github/.github/workflows/nette-tester-mysql.yml@v1 - with: - php: "7.4" - database: tests - - test74-lower: + test81: name: "Nette Tester" uses: contributte/.github/.github/workflows/nette-tester-mysql.yml@v1 with: - php: "7.4" - composer: "composer update --no-interaction --no-progress --prefer-dist --prefer-stable --prefer-lowest" + php: "8.1" database: tests diff --git a/README.md b/README.md index 98d296b63..7033d2145 100755 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ For details on how to use this package, check out our [documentation](.docs). **Shortly** -You are looking at first class DataGrid for Nette Framework. Supported features: filtering, sorting, pagination, tree view, table view, translator and many others. +You are looking at first class datagrid for Nette Framework. Supported features: filtering, sorting, pagination, tree view, table view, translator and many others. Give us a star, it makes us so happy. Thanks ⭐.️ | What | Where | @@ -51,7 +51,8 @@ Give us a star, it makes us so happy. Thanks ⭐.️ | State | Version | Branch | Nette | PHP | |-------------|-----------|----------|--------|---------| -| dev | `^6.7.0` | `master` | `3.0+` | `>=7.2` | +| dev | `^7.0.0` | `master` | `3.0+` | `>=8.0` | +| stable | `^6.7.0` | `master` | `3.0+` | `>=7.2` | | stable | `^6.6.0` | `master` | `3.0+` | `>=7.2` | | stable | `^5.7.1` | `v5.x` | `2.3` | `^5.6` | | stable | `^4.4.22` | `v5.x` | `2.3` | `^5.6` | diff --git a/assets/ajax/index.ts b/assets/ajax/index.ts new file mode 100644 index 000000000..23b37df97 --- /dev/null +++ b/assets/ajax/index.ts @@ -0,0 +1 @@ +export * from "./naja"; diff --git a/assets/ajax/naja.ts b/assets/ajax/naja.ts new file mode 100644 index 000000000..fbe0658f4 --- /dev/null +++ b/assets/ajax/naja.ts @@ -0,0 +1,135 @@ +import type { Naja } from "naja"; +import type { + Ajax, + AjaxEventMap as BaseAjaxEventMap, + BaseRequestParams as AjaxBaseRequestParams, + BeforeEventDetail as BaseBeforeEventDetail, + DatagridPayload, + ErrorEventDetail as BaseErrorEventDetail, + EventDetail, + EventListener, + InteractEventDetail as BaseInteractEventDetail, + Payload, + RequestParams, + Response as AjaxResponse, + SuccessEventDetail as BaseSuccessEventDetail, +} from "../types"; +import { Datagrid } from "../datagrid"; +import { BeforeEvent, ErrorEvent, Payload as NajaPayload, SuccessEvent } from "naja/dist/Naja"; +import { InteractionEvent } from "naja/dist/core/UIHandler"; + +export interface BaseRequestParams extends AjaxBaseRequestParams, Request { + url: string; + method: string; +} + +export interface BeforeEventDetail extends BaseBeforeEventDetail { + params: EventDetail & RequestParams; +} + +export interface InteractEventDetail< + E extends HTMLElement = HTMLElement +> extends BaseInteractEventDetail, EventDetail { + element: E; +} + +export interface SuccessEventDetail< + P = DatagridPayload +> extends BaseSuccessEventDetail, EventDetail { + params: BaseRequestParams; + payload: Payload

& NajaPayload; + response: AjaxResponse & Response; +} + +export interface ErrorEventDetail< + E extends Error = Error, +> extends BaseErrorEventDetail, EventDetail { + params: BaseRequestParams; + response: (AjaxResponse & Response) | undefined; + error: E; +} + +export interface AjaxEventMap extends BaseAjaxEventMap { + before: CustomEvent; + interact: CustomEvent; + snippetUpdate: CustomEvent; + success: CustomEvent; + error: CustomEvent; +} + +export class NajaAjax extends EventTarget implements Ajax { + constructor(public client: C) { + if (!client.VERSION || client.VERSION < 2) { + throw new Error("NajaAjax supports Naja 2 and higher" + (client.VERSION ? `(version ${client.VERSION} provided)` : '')) + } + super(); + } + + onInit() { + this.client.addEventListener('before', (e) => { + return this.dispatch('before', { + params: e.detail + }); + }) + + this.client.uiHandler.addEventListener('interaction', (e) => { + if (!(e.detail.element instanceof HTMLElement)) { + throw new Error("Element is not an instanceof HTMLElement"); + } + + return this.dispatch('interact', { + ...e.detail, + element: e.detail.element as HTMLElement // Naja's event has a type of HTMLElement + }) + }) + + + this.client.addEventListener('success', (e) => { + return this.dispatch('success', { + ...e.detail, + params: e.detail.request, + payload: e.detail.payload as Payload + }); + }) + + this.client.addEventListener('error', (e) => { + return this.dispatch('error', { + ...e.detail, + params: e.detail.request, + response: e.detail.response, + }); + }) + + return this; + } + + async request(args: RequestParams): Promise

{ + return await this.client.makeRequest(args.method, args.url, args.data) as P; + } + + async submitForm(element: E): Promise

{ + return await this.client.uiHandler.submitForm(element) as P; + } + + dispatch< + K extends string, M extends BaseAjaxEventMap = AjaxEventMap + >(type: K, detail: K extends keyof M ? EventDetail : any, options?: boolean): boolean { + return this.dispatchEvent(new CustomEvent(type, {detail})); + } + + declare addEventListener: ( + type: K, + listener: EventListener, + options?: boolean | AddEventListenerOptions + ) => void; + + declare removeEventListener: ( + type: K, + listener: EventListener, + options?: boolean | AddEventListenerOptions + ) => void; + + declare dispatchEvent: ( + event: K extends keyof M ? M[K] : CustomEvent + ) => boolean; +} diff --git a/assets/css/datagrid-full.css b/assets/css/datagrid-full.css new file mode 100644 index 000000000..d42e516d7 --- /dev/null +++ b/assets/css/datagrid-full.css @@ -0,0 +1,4 @@ +@import "@fortawesome/fontawesome-free/css/all.css"; +@import 'bootstrap/dist/css/bootstrap.css'; +@import 'vanillajs-datepicker/css/datepicker-bs5.css'; +@import './datagrid.css'; diff --git a/assets/css/datagrid.css b/assets/css/datagrid.css new file mode 100644 index 000000000..660ed2de4 --- /dev/null +++ b/assets/css/datagrid.css @@ -0,0 +1,651 @@ +/* .datagrid--slide-toggle > td > div { + -webkit-transition: height .25s ease; + -o-transition: height .25s ease; + transition: height .25s ease; + overflow: hidden; +} */ + +.datagrid--content-row:not(.is-active) > td /*> div*/ +{ + display: none; +} + +@keyframes edited { + 0% { + background-color: #A6E2A9 + } + + 100% { + background-color: transparent + } + +} + +@keyframes edited-error { + 0% { + background-color: #E8AAA4 + } + + 100% { + background-color: transparent + } + +} + +[data-datagrid-name] { + background-color: #fff; + box-sizing: border-box; + padding: 1em +} + +[data-datagrid-name] .datagrid-input-group-full-width { + width: 100% +} + +[data-datagrid-name] .hidden { + display: none !important +} + +[data-datagrid-name] .datagrid-collapse-filters-button-row { + margin-bottom: 0.5em +} + +[data-datagrid-name] .col-action .dropdown { + display: inline-block +} + +[data-datagrid-name] .datagrid-row-inline-add.datagrid-row-inline-add-hidden { + display: none +} + +[data-datagrid-name] .datagrid-row-columns-summary td { + border-top: 2px solid #bbb; + border-left: 1px solid #eee; + border-right: 1px solid #eee; + font-weight: bold +} + +[data-datagrid-name] .datagrid-row-columns-summary td:first-child { + border-left: 1px solid #ddd +} + +[data-datagrid-name] .datagrid-row-columns-summary td:last-child { + border-right: 1px solid #ddd +} + +[data-datagrid-name] .datagrid-toolbar { + margin-top: .35em; + float: right; + display: inline-block +} + +[data-datagrid-name] .datagrid-toolbar > div > span { + margin-left: 1em +} + +[data-datagrid-name] .datagrid-toolbar > div > span > a { + margin-left: 0.5em +} + +[data-datagrid-name] .datagrid-toolbar > div { + display: inline-block +} + +.datagrid-toolbar .fa-square, .datagrid-toolbar .fa-check-square { + font-weight: normal; +} + +[data-datagrid-name] .datagrid-exports .btn { + margin-left: 0.5em +} + +[data-datagrid-name] .datagrid-exports .btn:first-child { + margin-left: 0 +} + +[data-datagrid-name] .datagrid-settings { + display: inline-block +} + +[data-datagrid-name] .datagrid-settings .dropdown-menu--grid { + font-size: 12px +} + +[data-datagrid-name] .datagrid-settings .dropdown-menu--grid li .fa { + margin-right: 0.5em +} + +[data-datagrid-name] .row-reset-filter { + text-align: right; + margin-bottom: 0.5em +} + +[data-datagrid-name] .row-filters .datagrid-row-outer-filters-group { + margin-bottom: 0.5em +} + +[data-datagrid-name] .datagrid-manual-submit { + margin-bottom: 0.5em +} + +[data-datagrid-name] .filter-range-delimiter { + text-align: center +} + +[data-datagrid-name] .bootstrap-select.input-sm > .btn { + padding: 5px 25px 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px +} + +[data-datagrid-name] table { + margin: 0 +} + +[data-datagrid-name] table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) { + width: auto +} + +[data-datagrid-name] table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) > .btn { + width: auto +} + +[data-datagrid-name] table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) .dropdown-menu li { + font-size: 13px +} + +[data-datagrid-name] table thead tr.row-group-actions th { + border-bottom-width: 0 !important; + background-color: #f9f9f9; +} + +[data-datagrid-name] table thead tr.row-group-actions .datagrid-selected-rows-count { + margin-left: 0.3em +} + +[data-datagrid-name] table thead tr th { + font-size: 90%; + vertical-align: top +} + +[data-datagrid-name] table thead tr th hr { + margin: 8px -8px +} + +[data-datagrid-name] table thead tr th .datagrid-column-header-additions { + float: right +} + +[data-datagrid-name] table thead tr th .datagrid-column-header-additions a[data-datagrid-reset-filter-by-column] { + margin-left: 0.3em; + color: #858585 +} + +[data-datagrid-name] table thead tr th .datagrid-column-header-additions .column-settings-menu { + opacity: 0; + cursor: pointer; + margin-left: 0.3em; + display: inline-block +} + +[data-datagrid-name] table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-menu, [data-datagrid-name] .dropdown .dropdown-menu .dropdown-item { + font-size: 12px; +} + +[data-datagrid-name] table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-menu li .fa { + margin-right: 0.5em; +} + +[data-datagrid-name] table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-toggle::after { + display: none !important +} + +[data-datagrid-name] .datagrid-col-filter-date-range { + width: auto; + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; +} + +[data-datagrid-name] .datagrid-col-filter-date-range > .input-group { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + width: 1%; + margin-bottom: 0; +} + +[data-datagrid-name] .datagrid-col-filter-datte-range-delimiter { + background-color: inherit; + border: none; + padding: .25rem .5rem +} + +[data-datagrid-name] table thead tr th .datagrid-col-filter-range .form-control { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px +} + +[data-datagrid-name] table thead tr th:hover .column-settings-menu { + opacity: 1 +} + +[data-datagrid-name] table tbody td { + vertical-align: middle +} + +[data-datagrid-name] table tbody tr.ui-sortable-helper { + display: table +} + +[data-datagrid-name] table tbody tr .datagrid-inline-edit .form-control { + margin: -3px; + padding-bottom: 4px; + padding-top: 4px; + height: 28px +} + +[data-datagrid-name] table tbody tr td[data-datagrid-editable-url].editing textarea { + padding: 2px; + margin: -3px +} + +[data-datagrid-name] table tbody tr td.edited { + animation-name: edited; + animation-duration: 1.2s; + animation-delay: 0ms; +} + +[data-datagrid-name] table tbody tr td.edited-error { + animation-name: edited-error; + animation-duration: 1.6s; + animation-delay: 0ms; +} + +[data-datagrid-name] table th.col-checkbox, [data-datagrid-name] table td.col-checkbox { + padding: 0; + width: 2.1em; + text-align: center; + vertical-align: middle +} + +[data-datagrid-name] table th.col-checkbox .happy-checkbox, [data-datagrid-name] table td.col-checkbox .happy-checkbox { + margin-right: 0 +} + +[data-datagrid-name] table th.col-checkbox.col-checkbox-first, [data-datagrid-name] table td.col-checkbox.col-checkbox-first { + border-top-color: transparent +} + +[data-datagrid-name] table th.col-checkbox { + background-color: #f9f9f9 +} + +[data-datagrid-name] table th.col-action, [data-datagrid-name] table td.col-action { + white-space: nowrap; + width: 10px +} + +[data-datagrid-name] table th.col-action { + text-align: center +} + +[data-datagrid-name] table td.col-action { + text-align: right +} + +[data-datagrid-name] table th.datagrid-fit-content, [data-datagrid-name] table td.datagrid-fit-content { + width: 1%; + white-space: nowrap +} + +[data-datagrid-name] .datagrid-tree > .datagrid-tree-header .datagrid-tree-item-right-actions-action { + opacity: 0 +} + +[data-datagrid-name] .datagrid-tree > .datagrid-tree-item { + margin-left: 20px +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item { + position: relative +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item.ui-sortable-placeholder { + visibility: visible !important; + background-color: rgba(70, 83, 93, 0.1) +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content { + position: relative; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + box-sizing: border-box; + height: 37px; + box-shadow: inset 0px -1px 1px -1px #9B9B9B +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left, [data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + align-items: center +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left { + order: 1 +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron { + -webkit-border-radius: 11px; + -moz-border-radius: 11px; + border-radius: 11px; + width: 22px; + height: 22px; + line-height: 20px; + vertical-align: middle; + background-color: #fff; + display: inline-block; + text-align: center; + position: relative; + margin: 0 5px 0 -27px; + transition: transform 0.2s ease-in-out +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron:hover { + -webkit-box-shadow: 0px 0px 3px 0px #b4b4b4; + -moz-box-shadow: 0px 0px 3px 0px #b4b4b4; + box-shadow: 0px 0px 3px 0px #b4b4b4 +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron.toggle-rotate { + transform: rotate(90deg) +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron .fa { + font-size: 10px; + transform: translate(1px, 0) +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right { + position: relative; + order: 2; + flex-basis: 50%; + display: flex; + flex-wrap: nowrap; + justify-content: flex-end; + flex-direction: row +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .btn { + margin-top: -3px +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns { + white-space: nowrap; + display: flex; + flex-basis: 70%; + flex-direction: row; + flex-wrap: nowrap; + justify-content: flex-end +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns .datagrid-tree-item-right-columns-column { + padding: 0 7px; + margin-right: 4px; + flex-basis: 25% +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns .datagrid-tree-item-right-columns-column:last-child { + margin-right: 0 +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions { + margin-left: 7px; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + align-items: center +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions .datagrid-tree-item-right-actions-action { + margin-right: 4px +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions .datagrid-tree-item-right-actions-action:last-child { + margin-right: 0 +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item .datagrid-tree-item-children:not(.datagrid-tree) { + margin-left: 28px +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item:not(.has-children) > .datagrid-tree-item-children { + box-sizing: border-box; + position: relative; + width: calc(100% - 28px); + min-height: 9px; + margin-top: -9px +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item.has-children > .datagrid-tree-item-children { + display: none +} + +[data-datagrid-name] .datagrid-tree .datagrid-tree-item.has-children > .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 14px) +} + +[data-datagrid-name] .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 14px) +} + +[data-datagrid-name] .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 28px) !important +} + +[data-datagrid-name] .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 42px) !important +} + +[data-datagrid-name] .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 56px) !important +} + +[data-datagrid-name] .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 74px) !important +} + +[data-datagrid-name] .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 88px) !important +} + +[data-datagrid-name] .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 102px) !important +} + +[data-datagrid-name] .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 116px) !important +} + +[data-datagrid-name] .btn { + transition: all 0.1s ease-in-out; + white-space: nowrap +} + +[data-datagrid-name] select { + text-transform: none; +} + +[data-datagrid-name] .row-grid-bottom { + font-size: 0; + padding: 8px; + border: 1px solid #ddd; + background-color: #f9f9f9; +} + +[data-datagrid-name] .row-grid-bottom .col-items { + font-size: 14px; + display: inline-block; + width: 25%; + margin-right: 0; + margin-left: 0; +} + +[data-datagrid-name] .row-grid-bottom .col-pagination { + font-size: 14px; + display: inline-block; + width: 50%; + margin-right: 0; + margin-left: 0; +} + +[data-datagrid-name] .row-grid-bottom .col-per-page { + font-size: 14px; + display: inline-flex; + justify-content: end; + align-items: center; + width: 25%; + margin-right: 0; + margin-left: 0; + text-align: right; + text-align: -webkit-right; +} + +[data-datagrid-name] .row-grid-bottom .col-per-page form { + display: inline-block +} + +[data-datagrid-name] .row-grid-bottom .col-per-page .form-control { + width: auto; + display: inline-block +} + +[data-datagrid-name] .row-grid-bottom .col-per-page .form-select { + margin-left: 0.25rem; + width: fit-content; +} + +[data-datagrid-name] .row-grid-bottom .datagrid-per-page-submit { + position: absolute; + visibility: hidden; + width: 0; + top: -200px +} + +[data-datagrid-name] .pagination.active > span { + color: #fff +} + +[data-datagrid-name] .pagination > a.disabled { + color: #989898; + cursor: not-allowed +} + +[data-datagrid-name] .pagination > a.active { + pointer-events: none; + cursor: default +} + +[data-datagrid-name] .row-group-actions th { + font-weight: normal +} + +[data-datagrid-name] .col-checkbox { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none +} + +[data-datagrid-name] .col-checkbox .happy-checkbox { + margin-top: 2px +} + +[data-datagrid-name] .datagrid-column-status-option-icon { + float: right +} + +@media (min-width: 768px) { + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .form-control[hidden] { + display: none; + } + + .ublaboo-datagrid-th-form-inline .form-control[hidden] { + display: none; + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .input-group { + display: inline-table; + vertical-align: middle + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .input-group .form-control { + width: auto + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .input-group > .form-control { + width: 100% + } + + [data-datagrid-name] .input-group-text { + height: calc(1.5em + 0.5rem + 2px); + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .control-label { + margin-bottom: 0; + vertical-align: middle + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .radio, [data-datagrid-name] .ublaboo-datagrid-th-form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .radio label, [data-datagrid-name] .ublaboo-datagrid-th-form-inline .checkbox label { + padding-left: 0 + } + + [data-datagrid-name] .ublaboo-datagrid-th-form-inline .radio input[type="radio"], [data-datagrid-name] .ublaboo-datagrid-th-form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0 + } + +} + +[data-datagrid-name] .btn-xs, [data-datagrid-name] .btn-group-xs > .btn { + font-size: 12px; + line-height: 1.5; + border-radius: .19rem; + padding: 0.063rem 0.313rem; +} + + +[data-datagrid-name] .dropdown-item { + line-height: 1.42857143; + font-size: 12px; + padding: 0.19rem 1.3rem; +} diff --git a/assets/css/happy.css.ts b/assets/css/happy.css.ts new file mode 100644 index 000000000..525ffbc50 --- /dev/null +++ b/assets/css/happy.css.ts @@ -0,0 +1,464 @@ +export const happyStyles = `/** + * From happy-inputs by paveljanda: + * https://github.com/paveljanda/happy/blob/94357b7146b5f3029cc565859a588c5832dd374a/src/happy.css + */ + +.happy-color, +.happy-checkbox, +.happy-radio { + color: #333333; +} + +.happy-color > b, +.happy-checkbox > b, +.happy-radio > b { + background-color: #333333; +} + +.happy-color.active, +.active.happy-checkbox, +.active.happy-radio { + color: #333333; +} + +.happy-color.active > b, +.active.happy-checkbox > b, +.active.happy-radio > b { + background-color: #333333; +} + +.happy-color.primary, +.primary.happy-checkbox, +.primary.happy-radio { + color: #333333; +} + +.happy-color.primary > b, +.primary.happy-checkbox > b, +.primary.happy-radio > b { + background-color: #333333; +} + +.happy-color.primary.active, +.primary.active.happy-checkbox, +.primary.active.happy-radio { + color: #4c86bb; +} + +.happy-color.primary.active > b, +.primary.active.happy-checkbox > b, +.primary.active.happy-radio > b { + background-color: #4c86bb; +} + +.happy-color.success, +.success.happy-checkbox, +.success.happy-radio { + color: #333333; +} + +.happy-color.success > b, +.success.happy-checkbox > b, +.success.happy-radio > b { + background-color: #333333; +} + +.happy-color.success.active, +.success.active.happy-checkbox, +.success.active.happy-radio { + color: #72b889; +} + +.happy-color.success.active > b, +.success.active.happy-checkbox > b, +.success.active.happy-radio > b { + background-color: #72b889; +} + +.happy-color.info, +.info.happy-checkbox, +.info.happy-radio { + color: #333333; +} + +.happy-color.info > b, +.info.happy-checkbox > b, +.info.happy-radio > b { + background-color: #333333; +} + +.happy-color.info.active, +.info.active.happy-checkbox, +.info.active.happy-radio { + color: #5bc0de; +} + +.happy-color.info.active > b, +.info.active.happy-checkbox > b, +.info.active.happy-radio > b { + background-color: #5bc0de; +} + +.happy-color.warning, +.warning.happy-checkbox, +.warning.happy-radio { + color: #333333; +} + +.happy-color.warning > b, +.warning.happy-checkbox > b, +.warning.happy-radio > b { + background-color: #333333; +} + +.happy-color.warning.active, +.warning.active.happy-checkbox, +.warning.active.happy-radio { + color: #f0bb65; +} + +.happy-color.warning.active > b, +.warning.active.happy-checkbox > b, +.warning.active.happy-radio > b { + background-color: #f0bb65; +} + +.happy-color.danger, +.danger.happy-checkbox, +.danger.happy-radio { + color: #333333; +} + +.happy-color.danger > b, +.danger.happy-checkbox > b, +.danger.happy-radio > b { + background-color: #333333; +} + +.happy-color.danger.active, +.danger.active.happy-checkbox, +.danger.active.happy-radio { + color: #ed6b6b; +} + +.happy-color.danger.active > b, +.danger.active.happy-checkbox > b, +.danger.active.happy-radio > b { + background-color: #ed6b6b; +} + +.happy-color.white, +.white.happy-checkbox, +.white.happy-radio { + color: #333333; +} + +.happy-color.white > b, +.white.happy-checkbox > b, +.white.happy-radio > b { + background-color: #333333; +} + +.happy-color.white.active, +.white.active.happy-checkbox, +.white.active.happy-radio { + color: #ffffff; +} + +.happy-color.white.active > b, +.white.active.happy-checkbox > b, +.white.active.happy-radio > b { + background-color: #ffffff; +} + +.happy-border-color, +.happy-radio { + border-color: rgba(51, 51, 51, 0.8); +} + +.happy-border-color.active, +.active.happy-radio { + border-color: #333333; +} + +.happy-border-color.primary, +.primary.happy-radio { + border-color: rgba(51, 51, 51, 0.8); +} + +.happy-border-color.primary.active, +.primary.active.happy-radio { + border-color: #4c86bb; +} + +.happy-border-color.success, +.success.happy-radio { + border-color: rgba(51, 51, 51, 0.8); +} + +.happy-border-color.success.active, +.success.active.happy-radio { + border-color: #72b889; +} + +.happy-border-color.info, +.info.happy-radio { + border-color: rgba(51, 51, 51, 0.8); +} + +.happy-border-color.info.active, +.info.active.happy-radio { + border-color: #5bc0de; +} + +.happy-border-color.warning, +.warning.happy-radio { + border-color: rgba(51, 51, 51, 0.8); +} + +.happy-border-color.warning.active, +.warning.active.happy-radio { + border-color: #f0bb65; +} + +.happy-border-color.danger, +.danger.happy-radio { + border-color: rgba(51, 51, 51, 0.8); +} + +.happy-border-color.danger.active, +.danger.active.happy-radio { + border-color: #ed6b6b; +} + +.happy-border-color.white, +.white.happy-radio { + border-color: rgba(51, 51, 51, 0.8); +} + +.happy-border-color.white.active, +.white.active.happy-radio { + border-color: #ffffff; +} + +/** + * Common + */ + +input[type="radio"].happy, +input[type="checkbox"].happy { + position: absolute; + top: -50%; + left: -50%; + opacity: 0; +} + +label:not(.selectable), +.noselect { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +label { + cursor: pointer; + position: relative; +} + +/** + * Checkbox + */ + +.happy-checkbox { + border-color: #333333; + margin-right: 0.2em; + position: relative; + display: inline-block; + line-height: 20px; + vertical-align: middle; + width: 16px; + height: 16px; + border-width: 2px; + border-style: solid; + cursor: pointer; + box-sizing: border-box; + top: -2px; + -webkit-border-radius: 2.66667px; + -moz-border-radius: 2.66667px; + border-radius: 2.66667px; +} + +.happy-checkbox svg { + position: absolute; + display: block; + top: -2px; + left: -2px; + height: 16px; + width: 16px; + opacity: 0; + -webkit-border-radius: 2.66667px; + -moz-border-radius: 2.66667px; + border-radius: 2.66667px; + background-color: #333333; + -ms-transform: scale(0.4); + -webkit-transform: scale(0.4); + transform: scale(0.4); + -ms-transition: all 180ms; + -webkit-transition: all 180ms; + transition: all 180ms; +} + +.happy-checkbox svg rect { + fill: white; +} + +.happy-checkbox svg rect:first-child { + -ms-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + +.happy-checkbox svg rect:nth-child(2) { + -ms-transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + /* fill: yellow; */ +} + +.happy-checkbox.thin { + border-width: 1px; +} + +.happy-checkbox.thin svg { + top: -1px; + left: -1px; +} + +.happy-checkbox.white { + border-color: #ffffff; +} + +.happy-checkbox.gray-border { + border-color: #858585; +} + +.happy-checkbox.primary-border { + border-color: #4c86bb; +} + +.happy-checkbox.success-border { + border-color: #72b889; +} + +.happy-checkbox.info-border { + border-color: #5bc0de; +} + +.happy-checkbox.warning-border { + border-color: #f0bb65; +} + +.happy-checkbox.danger-border { + border-color: #ed6b6b; +} + +.happy-checkbox.primary svg { + background-color: #4c86bb; +} + +.happy-checkbox.success svg { + background-color: #72b889; +} + +.happy-checkbox.info svg { + background-color: #5bc0de; +} + +.happy-checkbox.warning svg { + background-color: #f0bb65; +} + +.happy-checkbox.danger svg { + background-color: #ed6b6b; +} + +.happy-checkbox.white svg { + background-color: #ffffff; +} + +.happy-checkbox.white svg rect { + fill: #333333; +} + +.happy-checkbox.active { + border-color: transparent; +} + +.happy-checkbox.active svg { + opacity: 1; + -ms-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); +} + +/** + * Radio + */ + +.happy-radio { + position: relative; + display: inline-block; + line-height: 20px; + vertical-align: middle; + width: 16px; + height: 16px; + border-width: 2px; + border-style: solid; + cursor: pointer; + box-sizing: border-box; + top: -2px; + -webkit-border-radius: 16px; + -moz-border-radius: 16px; + border-radius: 16px; +} + +.happy-radio.thin { + border-width: 1.66667px; +} + +.happy-radio b { + position: absolute; + display: block; + top: 2px; + left: 2px; + bottom: 2px; + right: 2px; + opacity: 0; + -webkit-border-radius: 10.66667px; + -moz-border-radius: 10.66667px; + border-radius: 10.66667px; + -ms-transform: scale(0.4); + -webkit-transform: scale(0.4); + transform: scale(0.4); + -ms-transition: all 180ms; + -webkit-transition: all 180ms; + transition: all 180ms; +} + +.happy-radio.active b { + opacity: 1; + -ms-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); +} + +.happy-radio.focus { + outline: none; + -webkit-box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75); + -moz-box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75); + box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75); +} +`; diff --git a/assets/datagrid-instant-url-refresh.js b/assets/datagrid-instant-url-refresh.js deleted file mode 100644 index f4ae43c73..000000000 --- a/assets/datagrid-instant-url-refresh.js +++ /dev/null @@ -1,30 +0,0 @@ -var dataGridRegisterAjaxCall; - -if (typeof naja !== "undefined") { - dataGridRegisterAjaxCall = function (params) { - var method = params.type || 'GET'; - var data = params.data || null; - - naja.makeRequest(method, params.url, data, { - history: 'replace' - }) - .then(params.success) - .catch(params.error); - }; - -} else { - dataGridRegisterAjaxCall = function (params) { - $.nette.ajax(params); - }; -} - -document.addEventListener('DOMContentLoaded', function () { - var element = document.querySelector('.datagrid'); - - if (element !== null) { - return dataGridRegisterAjaxCall({ - type: 'GET', - url: element.getAttribute('data-refresh-state') - }); - } -}); diff --git a/assets/datagrid-spinners.css b/assets/datagrid-spinners.css deleted file mode 100755 index 818714dfc..000000000 --- a/assets/datagrid-spinners.css +++ /dev/null @@ -1,118 +0,0 @@ -@keyframes ublaboo-spinner-icon { - 0% { - transform: rotate(0); } - 50% { - transform: rotate(180deg); } - 100% { - transform: rotate(360deg); } } - -@-webkit-keyframes ublaboo-spinner-icon { - 0% { - transform: rotate(0); } - 50% { - transform: rotate(180deg); } - 100% { - transform: rotate(360deg); } } - -.ublaboo-spinner-icon > span { - animation-duration: 2s; - animation-delay: 0; - animation-iteration-count: infinite; - animation-timing-function: ease; - animation-name: ublaboo-spinner-icon; } - -@keyframes ublaboo-spinner-small { - 0% { - transform: translate(21.3px, 2.2px); } - 11.1% { - transform: translate(8.1px, 25.2px); } - 22.2% { - transform: translate(12.7px, -0.7px); } - 33.3% { - transform: translate(17.2px, 25.2px); } - 44.4% { - transform: translate(4.2px, 2.2px); } - 55.5% { - transform: translate(24.1px, 19.5px); } - 66.6% { - transform: translate(-0.3px, 10.3px); } - 77.7% { - transform: translate(25.8px, 10.3px); } - 88.8% { - transform: translate(1.2px, 19.3px); } - 100% { - transform: translate(21.3px, 2.2px); } } - -@-webkit-keyframes ublaboo-spinner-small { - 0% { - transform: translate(21.3px, 2.2px); } - 11.1% { - transform: translate(8.1px, 25.2px); } - 22.2% { - transform: translate(12.7px, -0.7px); } - 33.3% { - transform: translate(17.2px, 25.2px); } - 44.4% { - transform: translate(4.2px, 2.2px); } - 55.5% { - transform: translate(24.1px, 19.5px); } - 66.6% { - transform: translate(-0.3px, 10.3px); } - 77.7% { - transform: translate(25.8px, 10.3px); } - 88.8% { - transform: translate(1.2px, 19.3px); } - 100% { - transform: translate(21.3px, 2.2px); } } - -@keyframes ublaboo-spinner-in { - 0% { - opacity: 0; } - 100% { - opacity: 1; } } - -@-webkit-keyframes ublaboo-spinner-in { - 0% { - opacity: 0; } - 100% { - opacity: 1; } } - -.ublaboo-spinner { - line-height: 0; - display: inline-block; - margin: auto; - position: relative; - margin: 0 1em -11px 1em; - top: 1px; - opacity: 0; - animation-duration: 150ms; - animation-delay: 0; - animation-iteration-count: 1; - animation-timing-function: ease-in; - animation-name: ublaboo-spinner-in; - animation-fill-mode: forwards; } - .ublaboo-spinner > i { - position: absolute; - background-color: #37434f; - left: 0; - top: 0; - animation-duration: 6s; - animation-delay: 0; - animation-iteration-count: infinite; - animation-timing-function: ease; } - .ublaboo-spinner > i:nth-of-type(2) { - animation-delay: -1.5s; } - .ublaboo-spinner > i:nth-of-type(3) { - animation-delay: -3s; } - .ublaboo-spinner > i:nth-of-type(4) { - animation-delay: -4.5s; } - .ublaboo-spinner.ublaboo-spinner-small { - width: 28.0px; - height: 28.0px; } - .ublaboo-spinner.ublaboo-spinner-small > i { - width: 4.0px; - height: 4.0px; - border-radius: 2px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - animation-name: ublaboo-spinner-small; } diff --git a/assets/datagrid-spinners.js b/assets/datagrid-spinners.js deleted file mode 100644 index b6a0b2b26..000000000 --- a/assets/datagrid-spinners.js +++ /dev/null @@ -1,89 +0,0 @@ -var dataGridRegisterExtension; - -if (typeof naja !== "undefined") { - var isNaja2 = function () { return naja && naja.VERSION && naja.VERSION >= 2 }; - var najaEventParams = function (params) { return isNaja2() ? params.detail : params }; - var najaRequest = function (params) { return isNaja2() ? params.detail.request : params.xhr }; - dataGridRegisterExtension = function (name, extension) { - var init = extension.init; - var success = extension.success; - var before = extension.before; - var complete = extension.complete; - - - var NewExtension = function NewExtension(naja, name) { - this.name = name; - - this.initialize = function (naja) { - if(init) { - naja.addEventListener('init', function (params) { - init(najaEventParams(params).defaultOptions); - }); - } - - if(success) { - naja.addEventListener('success', function (params) { - var payload = isNaja2() ? params.detail.payload : params.response; - success(payload, najaEventParams(params).options); - }); - } - - if(before) { - naja.addEventListener('before', function (params) { - before(najaRequest(params), najaEventParams(params).options); - }); - } - - if(complete) { - naja.addEventListener('complete', function (params) { - complete(najaRequest(params), najaEventParams(params).options); - }); - } - } - if (!isNaja2()) { - this.initialize(naja); - } - return this; - } - - if (isNaja2()) { - naja.registerExtension(new NewExtension(null, name)); - } else { - naja.registerExtension(NewExtension, name); - } - }; -} else if ($.nette) { - dataGridRegisterExtension = function (name, extension) { - $.nette.ext(name, extension); - }; -} - -dataGridRegisterExtension('ublaboo-spinners', { - before: function(xhr, settings) { - var el, id, row_detail, spinner_template, grid_fullname; - if (settings.nette) { - el = settings.nette.el; - spinner_template = $('

'); - if (el.is('.datagrid [name="group_action[submit]"]')) { - return el.after(spinner_template); - } else if (el.is('.datagrid a') && el.data('toggle-detail')) { - id = settings.nette.el.attr('data-toggle-detail'); - grid_fullname = settings.nette.el.attr('data-toggle-detail-grid-fullname'); - row_detail = $('.item-detail-' + grid_fullname + '-id-' + id); - if (!row_detail.hasClass('loaded')) { - return el.addClass('ublaboo-spinner-icon'); - } - } else if (el.is('.datagrid .col-pagination a')) { - return el.closest('.row-grid-bottom').find('.col-per-page').prepend(spinner_template); - } else if (el.is('.datagrid .datagrid-per-page-submit')) { - return el.closest('.row-grid-bottom').find('.col-per-page').prepend(spinner_template); - } else if (el.is('.datagrid .reset-filter')) { - return el.closest('.row-grid-bottom').find('.col-per-page').prepend(spinner_template); - } - } - }, - complete: function() { - $('.ublaboo-spinner').remove(); - return $('.ublaboo-spinner-icon').removeClass('ublaboo-spinner-icon'); - } -}); diff --git a/assets/datagrid.css b/assets/datagrid.css deleted file mode 100755 index 30c58a69d..000000000 --- a/assets/datagrid.css +++ /dev/null @@ -1,641 +0,0 @@ -@keyframes edited { - 0% { - background-color: #A6E2A9 - } - - 100% { - background-color: transparent - } - -} - -@keyframes edited-error { - 0% { - background-color: #E8AAA4 - } - - 100% { - background-color: transparent - } - -} - -.datagrid { - background-color: #fff; - padding: 1em; - box-sizing: border-box -} - -.datagrid .datagrid-input-group-full-width { - width: 100% -} - -.datagrid .hidden { - display: none !important -} - -.datagrid .datagrid-collapse-filters-button-row { - margin-bottom: 0.5em -} - -.datagrid .col-action .dropdown { - display: inline-block -} - -.datagrid .datagrid-row-inline-add.datagrid-row-inline-add-hidden { - display: none -} - -.datagrid .datagrid-row-columns-summary td { - border-top: 2px solid #bbb; - border-left: 1px solid #eee; - border-right: 1px solid #eee; - font-weight: bold -} - -.datagrid .datagrid-row-columns-summary td:first-child { - border-left: 1px solid #ddd -} - -.datagrid .datagrid-row-columns-summary td:last-child { - border-right: 1px solid #ddd -} - -.datagrid .datagrid-toolbar { - margin-top: .35em; - float: right; - display: inline-block -} - -.datagrid .datagrid-toolbar > div > span { - margin-left: 1em -} - -.datagrid .datagrid-toolbar > div > span > a { - margin-left: 0.5em -} - -.datagrid .datagrid-toolbar > div { - display: inline-block -} - -.datagrid-toolbar .fa-square, .datagrid-toolbar .fa-check-square { - font-weight: normal; -} - -.datagrid .datagrid-exports .btn { - margin-left: 0.5em -} - -.datagrid .datagrid-exports .btn:first-child { - margin-left: 0 -} - -.datagrid .datagrid-settings { - display: inline-block -} - -.datagrid .datagrid-settings .dropdown-menu--grid { - font-size: 12px -} - -.datagrid .datagrid-settings .dropdown-menu--grid li .fa { - margin-right: 0.5em -} - -.datagrid .row-reset-filter { - text-align: right; - margin-bottom: 0.5em -} - -.datagrid .row-filters .datagrid-row-outer-filters-group { - margin-bottom: 0.5em -} - -.datagrid .datagrid-manual-submit { - margin-bottom: 0.5em -} - -.datagrid .filter-range-delimiter { - text-align: center -} - -.datagrid .bootstrap-select.input-sm > .btn { - padding: 5px 25px 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.datagrid table { - margin: 0 -} - -.datagrid table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) { - width: auto -} - -.datagrid table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) > .btn { - width: auto -} - -.datagrid table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) .dropdown-menu li { - font-size: 13px -} - -.datagrid table thead tr.row-group-actions th { - border-bottom-width: 0 !important; - background-color: #f9f9f9 -} - -.datagrid table thead tr.row-group-actions .datagrid-selected-rows-count { - margin-left: 0.3em -} - -.datagrid table thead tr th { - font-size: 90%; - vertical-align: top -} - -.datagrid table thead tr th hr { - margin: 8px -8px -} - -.datagrid table thead tr th .datagrid-column-header-additions { - float: right -} - -.datagrid table thead tr th .datagrid-column-header-additions a[data-datagrid-reset-filter-by-column] { - margin-left: 0.3em; - color: #858585 -} - -.datagrid table thead tr th .datagrid-column-header-additions .column-settings-menu { - opacity: 0; - cursor: pointer; - margin-left: 0.3em; - display: inline-block -} - -.datagrid table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-menu { - font-size: 12px -} - -.datagrid table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-menu li .fa { - margin-right: 0.5em -} - -.datagrid table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-toggle::after { - display: none !important -} - -.datagrid .datagrid-col-filter-date-range { - width: auto; - position: relative; - display: flex; - flex-wrap: wrap; - align-items: stretch; -} - -.datagrid .datagrid-col-filter-date-range > .input-group { - position: relative; - -ms-flex: 1 1 auto; - flex: 1 1 auto; - width: 1%; - margin-bottom: 0; -} - -.datagrid .datagrid-col-filter-datte-range-delimiter { - background-color: inherit; - border: none; - padding: .25rem .5rem -} - -.datagrid table thead tr th .datagrid-col-filter-range .form-control { - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px -} - -.datagrid table thead tr th:hover .column-settings-menu { - opacity: 1 -} - -.datagrid table tbody td { - vertical-align: middle -} - -.datagrid table tbody tr.ui-sortable-helper { - display: table -} - -.datagrid table tbody tr.row-item-detail { - display: none -} - -.datagrid table tbody tr.row-item-detail.toggled { - display: table-row -} - -.datagrid table tbody tr.row-item-detail .item-detail-content { - display: none -} - -.datagrid table tbody tr.row-item-detail-helper { - display: none -} - -.datagrid table tbody tr .datagrid-inline-edit .form-control { - margin: -3px; - padding-bottom: 4px; - padding-top: 4px; - height: 28px -} - -.datagrid table tbody tr td[data-datagrid-editable-url].editing textarea { - padding: 2px; - margin: -3px -} - -.datagrid table tbody tr td.edited { - animation-name: edited; - animation-duration: 1.2s; - animation-delay: 0 -} - -.datagrid table tbody tr td.edited-error { - animation-name: edited-error; - animation-duration: 1.6s; - animation-delay: 0 -} - -.datagrid table th.col-checkbox, .datagrid table td.col-checkbox { - padding: 0; - width: 2.1em; - text-align: center; - vertical-align: middle -} - -.datagrid table th.col-checkbox .happy-checkbox, .datagrid table td.col-checkbox .happy-checkbox { - margin-right: 0 -} - -.datagrid table th.col-checkbox.col-checkbox-first, .datagrid table td.col-checkbox.col-checkbox-first { - border-top-color: transparent -} - -.datagrid table th.col-checkbox { - background-color: #f9f9f9 -} - -.datagrid table th.col-action, .datagrid table td.col-action { - white-space: nowrap; - width: 10px -} - -.datagrid table th.col-action { - text-align: center -} - -.datagrid table td.col-action { - text-align: right -} - -.datagrid table th.datagrid-fit-content, .datagrid table td.datagrid-fit-content { - width: 1%; - white-space: nowrap -} - -.datagrid .datagrid-tree > .datagrid-tree-header .datagrid-tree-item-right-actions-action { - opacity: 0 -} - -.datagrid .datagrid-tree > .datagrid-tree-item { - margin-left: 20px -} - -.datagrid .datagrid-tree .datagrid-tree-item { - position: relative -} - -.datagrid .datagrid-tree .datagrid-tree-item.ui-sortable-placeholder { - visibility: visible !important; - background-color: rgba(70, 83, 93, 0.1) -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content { - position: relative; - display: flex; - flex-direction: row; - flex-wrap: nowrap; - justify-content: space-between; - box-sizing: border-box; - height: 37px; - box-shadow: inset 0px -1px 1px -1px #9B9B9B -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left, .datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - justify-content: space-between; - align-items: center -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left { - order: 1 -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron { - -webkit-border-radius: 11px; - -moz-border-radius: 11px; - border-radius: 11px; - width: 22px; - height: 22px; - line-height: 20px; - vertical-align: middle; - background-color: #fff; - display: inline-block; - text-align: center; - position: relative; - margin: 0 5px 0 -27px; - transition: transform 0.2s ease-in-out -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron:hover { - -webkit-box-shadow: 0px 0px 3px 0px #b4b4b4; - -moz-box-shadow: 0px 0px 3px 0px #b4b4b4; - box-shadow: 0px 0px 3px 0px #b4b4b4 -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron.toggle-rotate { - transform: rotate(90deg) -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron .fa { - font-size: 10px; - transform: translate(1px, 0) -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right { - position: relative; - order: 2; - flex-basis: 50%; - display: flex; - flex-wrap: nowrap; - justify-content: flex-end; - flex-direction: row -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .btn { - margin-top: -3px -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns { - white-space: nowrap; - display: flex; - flex-basis: 70%; - flex-direction: row; - flex-wrap: nowrap; - justify-content: flex-end -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns .datagrid-tree-item-right-columns-column { - padding: 0 7px; - margin-right: 4px; - flex-basis: 25% -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns .datagrid-tree-item-right-columns-column:last-child { - margin-right: 0 -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions { - margin-left: 7px; - display: flex; - flex-direction: row; - flex-wrap: nowrap; - justify-content: space-between; - align-items: center -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions .datagrid-tree-item-right-actions-action { - margin-right: 4px -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions .datagrid-tree-item-right-actions-action:last-child { - margin-right: 0 -} - -.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-children:not(.datagrid-tree) { - margin-left: 28px -} - -.datagrid .datagrid-tree .datagrid-tree-item:not(.has-children) > .datagrid-tree-item-children { - box-sizing: border-box; - position: relative; - width: calc(100% - 28px); - min-height: 9px; - margin-top: -9px -} - -.datagrid .datagrid-tree .datagrid-tree-item.has-children > .datagrid-tree-item-children { - display: none -} - -.datagrid .datagrid-tree .datagrid-tree-item.has-children > .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 14px) -} - -.datagrid .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 14px) -} - -.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 28px) !important -} - -.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 42px) !important -} - -.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 56px) !important -} - -.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 74px) !important -} - -.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 88px) !important -} - -.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 102px) !important -} - -.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { - flex-basis: calc(50% + 116px) !important -} - -.datagrid .btn { - transition: all 0.1s ease-in-out; - white-space: nowrap -} - -.datagrid select { - padding: 0; - text-transform: none -} - -.datagrid .row-grid-bottom { - font-size: 0; - padding: 8px; - background-color: #f9f9f9; - border: 1px solid #ddd; - border-top: 0 -} - -.datagrid .row-grid-bottom .col-items { - font-size: 14px; - display: inline-block; - width: 25% -} - -.datagrid .row-grid-bottom .col-pagination { - font-size: 14px; - display: inline-block; - width: 50% -} - -.datagrid .row-grid-bottom .col-per-page { - font-size: 14px; - display: inline-block; - width: 25% -} - -.datagrid .row-grid-bottom .col-per-page form { - display: inline-block -} - -.datagrid .row-grid-bottom .col-per-page .form-control { - width: auto; - display: inline-block -} - -.datagrid .row-grid-bottom .datagrid-per-page-submit { - position: absolute; - visibility: hidden; - width: 0; - top: -200px -} - -.datagrid .pagination.active > span { - color: #fff -} - -.datagrid .pagination > a.disabled { - color: #989898; - cursor: not-allowed -} - -.datagrid .pagination > a.active { - pointer-events: none; - cursor: default -} - -.datagrid .row-group-actions th { - font-weight: normal -} - -.datagrid .col-checkbox { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none -} - -.datagrid .col-checkbox .happy-checkbox { - margin-top: 2px -} - -.datagrid .datagrid-column-status-option-icon { - float: right -} - -@media (min-width:768px) { - .datagrid .ublaboo-datagrid-th-form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle - } - - .datagrid .ublaboo-datagrid-th-form-inline .form-control { - display: inline-block; - width: auto; - vertical-align: middle - } - - .datagrid .ublaboo-datagrid-th-form-inline .form-control[hidden] { - display:none; - } - - .ublaboo-datagrid-th-form-inline .form-control[hidden] { - display: none; - } - - .datagrid .ublaboo-datagrid-th-form-inline .input-group { - display: inline-table; - vertical-align: middle - } - - .datagrid .ublaboo-datagrid-th-form-inline .input-group .form-control { - width: auto - } - - .datagrid .ublaboo-datagrid-th-form-inline .input-group > .form-control { - width: 100% - } - - .datagrid .input-group-text { - height: calc(1.5em + 0.5rem + 2px); - } - - .datagrid .ublaboo-datagrid-th-form-inline .control-label { - margin-bottom: 0; - vertical-align: middle - } - - .datagrid .ublaboo-datagrid-th-form-inline .radio, .datagrid .ublaboo-datagrid-th-form-inline .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle - } - - .datagrid .ublaboo-datagrid-th-form-inline .radio label, .datagrid .ublaboo-datagrid-th-form-inline .checkbox label { - padding-left: 0 - } - - .datagrid .ublaboo-datagrid-th-form-inline .radio input[type="radio"], .datagrid .ublaboo-datagrid-th-form-inline .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0 - } - -} - -.datagrid .btn-xs, .datagrid .btn-group-xs > .btn { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.datagrid .dropdown-item { - padding: 3px 20px; - line-height: 1.42857143; - font-size: 12px; -} diff --git a/assets/datagrid.js b/assets/datagrid.js deleted file mode 100644 index 6788cecba..000000000 --- a/assets/datagrid.js +++ /dev/null @@ -1,917 +0,0 @@ -var dataGridRegisterExtension, dataGridRegisterAjaxCall, dataGridLoad, dataGridSubmitForm; - -if (typeof naja !== "undefined") { - var isNaja2 = function () { return naja && naja.VERSION && naja.VERSION >= 2 }; - var najaEventParams = function (params) { return isNaja2() ? params.detail : params }; - var najaRequest = function (params) { return isNaja2() ? params.detail.request : params.xhr }; - dataGridRegisterExtension = function (name, extension) { - var init = extension.init; - var success = extension.success; - var before = extension.before; - var complete = extension.complete; - var interaction = extension.interaction; - - - var NewExtension = function NewExtension(naja, name) { - this.name = name; - - this.initialize = function (naja) { - if(init) { - naja.addEventListener('init', function (params) { - init(najaEventParams(params).defaultOptions); - }); - } - - if(success) { - naja.addEventListener('success', function (params) { - var payload = isNaja2() ? params.detail.payload : params.response; - success(payload, najaEventParams(params).options); - }); - } - - var interactionTarget = naja; - if (isNaja2()) { - interactionTarget = interactionTarget.uiHandler; - } - - interactionTarget.addEventListener('interaction', function (params) { - if (isNaja2()) { - params.detail.options.nette = { - el: $(params.detail.element) - } - } else { - params.options.nette = { - el: $(params.element) - } - } - if (interaction) { - if (!interaction(najaEventParams(params).options)){ - params.preventDefault(); - } - } - }); - - if(before) { - naja.addEventListener('before', function (params) { - if (!before(najaRequest(params), najaEventParams(params).options)) - params.preventDefault(); - }); - } - - if(complete) { - naja.addEventListener('complete', function (params) { - complete(najaRequest(params), najaEventParams(params).options); - }); - } - } - if (!isNaja2()) { - this.initialize(naja); - } - return this; - } - - if (isNaja2()) { - naja.registerExtension(new NewExtension(null, name)); - } else { - naja.registerExtension(NewExtension, name); - } - }; - - - dataGridRegisterAjaxCall = function (params) { - var method = params.type || 'GET'; - var data = params.data || null; - - naja.makeRequest(method, params.url, data, {}) - .then(params.success) - .catch(params.error); - }; - - dataGridLoad = function () { - naja.load(); - }; - - dataGridSubmitForm = function (form) { - return naja.uiHandler.submitForm(form.get(0)); - }; -} else if ($.nette) { - dataGridRegisterExtension = function (name, extension) { - $.nette.ext(name, extension); - }; - dataGridRegisterAjaxCall = function (params) { - $.nette.ajax(params); - }; - dataGridLoad = function () { - $.nette.load(); - }; - dataGridSubmitForm = function (form) { - return form.submit(); - }; -} else { - throw new Error("Include Naja.js or nette.ajax for datagrids to work!") -} - - -var datagridFitlerMultiSelect, datagridGroupActionMultiSelect, datagridShiftGroupSelection, datagridSortable, datagridSortableTree, getEventDomPath, - indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - -$(document).on('click', '[data-datagrid-confirm]:not(.ajax)', function(e) { - if (!confirm($(e.target).closest('a').attr('data-datagrid-confirm'))) { - e.stopPropagation(); - return e.preventDefault(); - } -}); - -if (typeof naja !== "undefined") { - dataGridRegisterExtension('datagrid.confirm', { - interaction: function(settings) { - var confirm_message; - if (settings.nette) { - confirm_message = settings.nette.el.data('datagrid-confirm'); - if (confirm_message) { - return confirm(confirm_message); - } - } - return true; - } - }); -} else { - dataGridRegisterExtension('datagrid.confirm', { - before: function(xhr, settings) { - var confirm_message; - if (settings.nette) { - confirm_message = settings.nette.el.data('datagrid-confirm'); - if (confirm_message) { - return confirm(confirm_message); - } - } - return true; - } - }); -} - - -$(document).on('change', 'select[data-autosubmit-per-page]', function() { - var button; - button = $(this).parent().find('input[type=submit]'); - if (button.length === 0) { - button = $(this).parent().find('button[type=submit]'); - } - return button.click(); -}).on('change', 'select[data-autosubmit]', function() { - return dataGridSubmitForm($(this).closest('form').first()); -}).on('change', 'input[data-autosubmit][data-autosubmit-change]', function(e) { - var $this, code; - code = e.which || e.keyCode || 0; - clearTimeout(window.datagrid_autosubmit_timer); - $this = $(this); - return window.datagrid_autosubmit_timer = setTimeout((function(_this) { - return function() { - return dataGridSubmitForm($this.closest('form').first()); - }; - })(this), 200); -}).on('keyup', 'input[data-autosubmit]', function(e) { - var $this, code; - code = e.which || e.keyCode || 0; - if ((code !== 13) && ((code >= 9 && code <= 40) || (code >= 112 && code <= 123))) { - return; - } - clearTimeout(window.datagrid_autosubmit_timer); - $this = $(this); - return window.datagrid_autosubmit_timer = setTimeout((function(_this) { - return function() { - return dataGridSubmitForm($this.closest('form').first()); - }; - })(this), 200); -}).on('keydown', '.datagrid-inline-edit input', function(e) { - var code; - code = e.which || e.keyCode || 0; - if (code === 13) { - e.stopPropagation(); - e.preventDefault(); - return $(this).closest('tr').find('.col-action-inline-edit [name="inline_edit[submit]"]').click(); - } -}); - -$(document).on('keydown', 'input[data-datagrid-manualsubmit]', function(e) { - var code; - code = e.which || e.keyCode || 0; - if (code === 13) { - e.stopPropagation(); - e.preventDefault(); - return dataGridSubmitForm($(this).closest('form').first()); - } -}); - -getEventDomPath = function(e) { - var node, path; - if (indexOf.call(e, path) >= 0) { - return e.path; - } - path = []; - node = e.target; - while (node !== document.body) { - if (node === null) { - break; - } - path.push(node); - node = node.parentNode; - } - return path; -}; - -datagridShiftGroupSelection = function() { - var last_checkbox; - last_checkbox = null; - return document.addEventListener('click', function(e) { - var checkboxes_rows, current_checkbox_row, el, event, i, ie, input, j, k, last_checkbox_row, last_checkbox_tbody, len, len1, len2, ref, ref1, results, row, rows; - ref = getEventDomPath(e); - for (i = 0, len = ref.length; i < len; i++) { - el = ref[i]; - if ($(el).is('.col-checkbox') && last_checkbox && e.shiftKey) { - current_checkbox_row = $(el).closest('tr'); - last_checkbox_row = last_checkbox.closest('tr'); - last_checkbox_tbody = last_checkbox_row.closest('tbody'); - checkboxes_rows = last_checkbox_tbody.find('tr').toArray(); - if (current_checkbox_row.index() > last_checkbox_row.index()) { - rows = checkboxes_rows.slice(last_checkbox_row.index(), current_checkbox_row.index()); - } else if (current_checkbox_row.index() < last_checkbox_row.index()) { - rows = checkboxes_rows.slice(current_checkbox_row.index() + 1, last_checkbox_row.index()); - } - if (!rows) { - return; - } - for (j = 0, len1 = rows.length; j < len1; j++) { - row = rows[j]; - input = $(row).find('.col-checkbox input[type=checkbox]')[0]; - if (input) { - input.checked = true; - ie = window.navigator.userAgent.indexOf("MSIE "); - if (ie) { - event = document.createEvent('Event'); - event.initEvent('change', true, true); - } else { - event = new Event('change', { - 'bubbles': true - }); - } - input.dispatchEvent(event); - } - } - } - } - ref1 = getEventDomPath(e); - results = []; - for (k = 0, len2 = ref1.length; k < len2; k++) { - el = ref1[k]; - if ($(el).is('.col-checkbox')) { - results.push(last_checkbox = $(el)); - } else { - results.push(void 0); - } - } - return results; - }); -}; - -datagridShiftGroupSelection(); - -document.addEventListener('change', function(e) { - var buttons, checked_inputs, counter, event, grid, i, ie, input, inputs, len, results, select, total; - grid = e.target.getAttribute('data-check'); - if (grid) { - checked_inputs = document.querySelectorAll('input[data-check-all-' + grid + ']:checked'); - select = document.querySelector('.datagrid-' + grid + ' select[name="group_action[group_action]"]'); - buttons = document.querySelectorAll('.datagrid-' + grid + ' .row-group-actions *[type="submit"]'); - counter = document.querySelector('.datagrid-' + grid + ' .datagrid-selected-rows-count'); - - if (checked_inputs.length) { - if (buttons) { - buttons.forEach(function (button) { - button.disabled = false; - }); - } - if (select) { - select.disabled = false; - } - total = document.querySelectorAll('input[data-check-all-' + grid + ']').length; - if (counter) { - counter.innerHTML = checked_inputs.length + '/' + total; - } - } else { - if (buttons) { - buttons.forEach(function (button) { - button.disabled = true; - }); - } - if (select) { - select.disabled = true; - select.value = ""; - } - if (counter) { - counter.innerHTML = ""; - } - } - ie = window.navigator.userAgent.indexOf("MSIE "); - if (ie) { - event = document.createEvent('Event'); - event.initEvent('change', true, true); - } else { - event = new Event('change', { - 'bubbles': true - }); - } - if (select) { - select.dispatchEvent(event); - } - } - grid = e.target.getAttribute('data-check-all'); - if (grid) { - inputs = document.querySelectorAll('input[type=checkbox][data-check-all-' + grid + ']'); - results = []; - for (i = 0, len = inputs.length; i < len; i++) { - input = inputs[i]; - input.checked = e.target.checked; - ie = window.navigator.userAgent.indexOf("MSIE "); - if (ie) { - event = document.createEvent('Event'); - event.initEvent('change', true, true); - } else { - event = new Event('change', { - 'bubbles': true - }); - } - results.push(input.dispatchEvent(event)); - } - return results; - } -}); - - -window.datagridSerializeUrl = function(obj, prefix) { -var str = []; -for(var p in obj) { - if (obj.hasOwnProperty(p)) { - var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p]; - if (v !== null && v !== "") { - if (typeof v == "object") { - var r = window.datagridSerializeUrl(v, k); - if (r) { - str.push(r); - } - } else { - str.push(encodeURIComponent(k) + "=" + encodeURIComponent(v)); - } - } - } -} -return str.join("&"); -} -; - -datagridSortable = function() { - if (typeof $.fn.sortable === 'undefined') { - return; - } - return $('.datagrid [data-sortable]').sortable({ - handle: '.handle-sort', - items: 'tr', - axis: 'y', - update: function(event, ui) { - var component_prefix, data, item_id, next_id, prev_id, row, url; - row = ui.item.closest('tr[data-id]'); - item_id = row.data('id'); - prev_id = null; - next_id = null; - if (row.prev().length) { - prev_id = row.prev().data('id'); - } - if (row.next().length) { - next_id = row.next().data('id'); - } - url = $(this).data('sortable-url'); - data = {}; - component_prefix = row.closest('.datagrid').find('tbody').attr('data-sortable-parent-path'); - data[(component_prefix + '-item_id').replace(/^-/, '')] = item_id; - if (prev_id !== null) { - data[(component_prefix + '-prev_id').replace(/^-/, '')] = prev_id; - } - if (next_id !== null) { - data[(component_prefix + '-next_id').replace(/^-/, '')] = next_id; - } - return dataGridRegisterAjaxCall({ - type: 'GET', - url: url, - data: data, - error: function(jqXHR, textStatus, errorThrown) { - return alert(jqXHR.statusText); - } - }); - }, - helper: function(e, ui) { - ui.children().each(function() { - return $(this).width($(this).width()); - }); - return ui; - } - }); -}; - -$(function() { - return datagridSortable(); -}); - -if (typeof datagridSortableTree === 'undefined') { - datagridSortableTree = function() { - if (typeof $('.datagrid-tree-item-children').sortable === 'undefined') { - return; - } - return $('.datagrid-tree-item-children').sortable({ - handle: '.handle-sort', - items: '.datagrid-tree-item:not(.datagrid-tree-header)', - toleranceElement: '> .datagrid-tree-item-content', - connectWith: '.datagrid-tree-item-children', - update: function(event, ui) { - var component_prefix, data, item_id, next_id, parent, parent_id, prev_id, row, url; - $('.toggle-tree-to-delete').remove(); - row = ui.item.closest('.datagrid-tree-item[data-id]'); - item_id = row.data('id'); - prev_id = null; - next_id = null; - parent_id = null; - if (row.prev().length) { - prev_id = row.prev().data('id'); - } - if (row.next().length) { - next_id = row.next().data('id'); - } - parent = row.parent().closest('.datagrid-tree-item'); - if (parent.length) { - parent.find('.datagrid-tree-item-children').first().css({ - display: 'block' - }); - parent.addClass('has-children'); - parent_id = parent.data('id'); - } - url = $(this).data('sortable-url'); - if (!url) { - return; - } - parent.find('[data-toggle-tree]').first().removeClass('hidden'); - component_prefix = row.closest('.datagrid-tree').attr('data-sortable-parent-path'); - data = {}; - data[(component_prefix + '-item_id').replace(/^-/, '')] = item_id; - if (prev_id !== null) { - data[(component_prefix + '-prev_id').replace(/^-/, '')] = prev_id; - } - if (next_id !== null) { - data[(component_prefix + '-next_id').replace(/^-/, '')] = next_id; - } - data[(component_prefix + '-parent_id').replace(/^-/, '')] = parent_id; - return dataGridRegisterAjaxCall({ - type: 'GET', - url: url, - data: data, - error: function(jqXHR, textStatus, errorThrown) { - if (errorThrown !== 'abort') { - return alert(jqXHR.statusText); - } - } - }); - }, - stop: function(event, ui) { - return $('.toggle-tree-to-delete').removeClass('toggle-tree-to-delete'); - }, - start: function(event, ui) { - var parent; - parent = ui.item.parent().closest('.datagrid-tree-item'); - if (parent.length) { - if (parent.find('.datagrid-tree-item').length === 2) { - return parent.find('[data-toggle-tree]').addClass('toggle-tree-to-delete'); - } - } - } - }); - }; -} - -$(function() { - return datagridSortableTree(); -}); - -dataGridRegisterExtension('datagrid.happy', { - success: function() { - var c, checked_rows, class_selector, classes, event, grid, grids, i, ie, input, j, len, len1, results; - if (window.happy) { - window.happy.reset(); - } - grids = $('.datagrid'); - results = []; - for (i = 0, len = grids.length; i < len; i++) { - grid = grids[i]; - classes = grid.classList; - class_selector = ''; - for (j = 0, len1 = classes.length; j < len1; j++) { - c = classes[j]; - class_selector = class_selector + '.' + c; - } - checked_rows = document.querySelectorAll(class_selector + ' ' + 'input[data-check]:checked'); - if (checked_rows.length === 1 && checked_rows[0].getAttribute('name') === 'toggle-all') { - input = document.querySelector(class_selector + ' input[name=toggle-all]'); - if (input) { - input.checked = false; - ie = window.navigator.userAgent.indexOf("MSIE "); - if (ie) { - event = document.createEvent('Event'); - event.initEvent('change', true, true); - } else { - event = new Event('change', { - 'bubbles': true - }); - } - results.push(input.dispatchEvent(event)); - } else { - results.push(void 0); - } - } else { - results.push(void 0); - } - } - return results; - } -}); - -dataGridRegisterExtension('datagrid.sortable', { - success: function() { - return datagridSortable(); - } -}); - -dataGridRegisterExtension('datagrid.forms', { - success: function() { - return $('.datagrid').find('form').each(function() { - return window.Nette.initForm(this); - }); - } -}); - -dataGridRegisterExtension('datagrid.url', { - success: function(payload) { - var host, path, query, url; - if (payload._datagrid_url) { - if (window.history.replaceState) { - host = window.location.protocol + "//" + window.location.host; - path = window.location.pathname; - query = window.datagridSerializeUrl(payload.state).replace(/&+$/gm, ''); - if (query) { - url = host + path + "?" + query.replace(/\&*$/, ''); - } else { - url = host + path; - } - url += window.location.hash; - if (window.location.href !== url) { - return window.history.replaceState({ - path: url - }, '', url); - } - } - } - } -}); - -dataGridRegisterExtension('datagrid.sort', { - success: function(payload) { - var href, key, ref, results; - if (payload._datagrid_sort) { - ref = payload._datagrid_sort; - results = []; - for (key in ref) { - href = ref[key]; - results.push($('#datagrid-sort-' + key).attr('href', href)); - } - return results; - } - } -}); - -dataGridRegisterExtension('datargid.item_detail', { - before: function(xhr, settings) { - var id, row_detail, grid_fullname; - if (settings.nette && settings.nette.el.attr('data-toggle-detail')) { - id = settings.nette.el.attr('data-toggle-detail'); - grid_fullname = settings.nette.el.attr('data-toggle-detail-grid-fullname'); - row_detail = $('.item-detail-' + grid_fullname + '-id-' + id); - if (row_detail.hasClass('loaded')) { - if (!row_detail.find('.item-detail-content').length) { - row_detail.removeClass('toggled'); - return true; - } - if (row_detail.hasClass('toggled')) { - row_detail.find('.item-detail-content').slideToggle('fast', (function(_this) { - return function() { - return row_detail.toggleClass('toggled'); - }; - })(this)); - } else { - row_detail.toggleClass('toggled'); - row_detail.find('.item-detail-content').slideToggle('fast'); - } - return false; - } else { - return row_detail.addClass('loaded'); - } - } - return true; - }, - success: function(payload) { - var id, row_detail, grid_fullname; - if (payload._datagrid_toggle_detail && payload._datagrid_name) { - id = payload._datagrid_toggle_detail; - grid_fullname = payload._datagrid_name; - row_detail = $('.item-detail-' + grid_fullname + '-id-' + id); - row_detail.toggleClass('toggled'); - return row_detail.find('.item-detail-content').slideToggle('fast'); - } - } -}); - -dataGridRegisterExtension('datagrid.tree', { - before: function(xhr, settings) { - var children_block; - if (settings.nette && settings.nette.el.attr('data-toggle-tree')) { - settings.nette.el.toggleClass('toggle-rotate'); - children_block = settings.nette.el.closest('.datagrid-tree-item').find('.datagrid-tree-item-children').first(); - if (children_block.hasClass('loaded')) { - children_block.slideToggle('fast'); - return false; - } - } - return true; - }, - success: function(payload) { - var children_block, content, id, name, ref, snippet, template; - if (payload._datagrid_tree) { - id = payload._datagrid_tree; - children_block = $('.datagrid-tree-item[data-id="' + id + '"]').find('.datagrid-tree-item-children').first(); - children_block.addClass('loaded'); - ref = payload.snippets; - for (name in ref) { - snippet = ref[name]; - content = $(snippet); - template = $('
'); - template.attr('data-id', content.attr('data-id')); - template.append(content); - if (content.data('has-children')) { - template.addClass('has-children'); - } - children_block.append(template); - } - children_block.addClass('loaded'); - children_block.slideToggle('fast'); - dataGridLoad(); - } - return datagridSortableTree(); - } -}); - -$(document).on('click', '[data-datagrid-editable-url]', function(event) { - var attr_name, attr_value, attrs, cell, cellValue, cell_height, cell_lines, cell_padding, input, line_height, submit, valueToEdit; - cell = $(this); - if (event.target.tagName.toLowerCase() === 'a') { - return; - } - if (cell.hasClass('datagrid-inline-edit')) { - return; - } - if (!cell.hasClass('editing')) { - cell.addClass('editing'); - cellValue = cell.html().trim().replace('
', '\n'); - if (cell.attr('data-datagrid-editable-value')) { - valueToEdit = String(cell.data('datagrid-editable-value')); - } else { - valueToEdit = cellValue; - } - cell.data('originalValue', cellValue); - cell.data('valueToEdit', valueToEdit); - if (cell.data('datagrid-editable-type') === 'textarea') { - input = $(''); - cell_padding = parseInt(cell.css('padding').replace(/[^-\d\.]/g, ''), 10); - cell_height = cell.outerHeight(); - line_height = Math.round(parseFloat(cell.css('line-height'))); - cell_lines = (cell_height - (2 * cell_padding)) / line_height; - input.attr('rows', Math.round(cell_lines)); - } else if (cell.data('datagrid-editable-type') === 'select') { - input = $(cell.data('datagrid-editable-element')); - input.find("option[value='" + valueToEdit + "']").prop('selected', true); - } else { - input = $(''); - input.val(valueToEdit); - } - attrs = cell.data('datagrid-editable-attrs'); - for (attr_name in attrs) { - attr_value = attrs[attr_name]; - input.attr(attr_name, attr_value); - } - cell.removeClass('edited'); - cell.html(input); - submit = function(cell, el) { - var value; - value = el.val(); - if (value !== cell.data('valueToEdit')) { - dataGridRegisterAjaxCall({ - url: cell.data('datagrid-editable-url'), - data: { - value: value - }, - type: 'POST', - success: function(payload) { - if (cell.data('datagrid-editable-type') === 'select') { - cell.html(input.find("option[value='" + value + "']").html()); - } else { - if (payload._datagrid_editable_new_value) { - value = payload._datagrid_editable_new_value; - } - cell.html(value); - } - return cell.addClass('edited'); - }, - error: function() { - cell.html(cell.data('originalValue')); - return cell.addClass('edited-error'); - } - }); - } else { - cell.html(cell.data('originalValue')); - } - return setTimeout(function() { - return cell.removeClass('editing'); - }, 1200); - }; - cell.find('input,textarea,select').focus().on('blur', function() { - return submit(cell, $(this)); - }).on('keydown', function(e) { - if (cell.data('datagrid-editable-type') !== 'textarea') { - if (e.which === 13) { - e.stopPropagation(); - e.preventDefault(); - return submit(cell, $(this)); - } - } - if (e.which === 27) { - e.stopPropagation(); - e.preventDefault(); - cell.removeClass('editing'); - return cell.html(cell.data('originalValue')); - } - }); - return cell.find('select').on('change', function() { - return submit(cell, $(this)); - }); - } -}); - -dataGridRegisterExtension('datagrid.after_inline_edit', { - success: function(payload) { - var grid = $('.datagrid-' + payload._datagrid_name); - - if (payload._datagrid_inline_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'); - } - } -}); - -$(document).on('mouseup', '[data-datagrid-cancel-inline-add]', function(e) { - var code = e.which || e.keyCode || 0; - if (code === 1) { - e.stopPropagation(); - e.preventDefault(); - return $('.datagrid-row-inline-add').addClass('datagrid-row-inline-add-hidden'); - } -}); - -dataGridRegisterExtension('datagrid-toggle-inline-add', { - success: function(payload) { - var grid = $('.datagrid-' + payload._datagrid_name); - - if (payload._datagrid_inline_adding) { - var row = grid.find('.datagrid-row-inline-add'); - - if (row.hasClass('datagrid-row-inline-add-hidden')) { - row.removeClass('datagrid-row-inline-add-hidden'); - } - - row.find('input:not([readonly]),textarea:not([readonly])').first().focus(); - } - } -}); - -datagridFitlerMultiSelect = function() { - var select = $('.selectpicker').first(); - - if ($.fn.selectpicker) { - return $.fn.selectpicker.defaults = { - countSelectedText: select.data('i18n-selected'), - iconBase: '', - tickIcon: select.data('selected-icon-check') - }; - } -}; - -$(function() { - return datagridFitlerMultiSelect(); -}); - -datagridGroupActionMultiSelect = function() { - var selects; - - if (!$.fn.selectpicker) { - return; - } - - selects = $('[data-datagrid-multiselect-id]'); - - return selects.each(function() { - var id; - if ($(this).hasClass('selectpicker')) { - $(this).removeAttr('id'); - id = $(this).data('datagrid-multiselect-id'); - $(this).on('loaded.bs.select', function(e) { - $(this).parent().attr('style', 'display:none;'); - return $(this).parent().find('.hidden').removeClass('hidden').addClass('btn-default btn-secondary'); - }); - return $(this).on('rendered.bs.select', function(e) { - return $(this).parent().attr('id', id); - }); - } - }); -}; - -$(function() { - return datagridGroupActionMultiSelect(); -}); - -dataGridRegisterExtension('datagrid.fitlerMultiSelect', { - success: function() { - datagridFitlerMultiSelect(); - if ($.fn.selectpicker) { - return $('.selectpicker').selectpicker({ - iconBase: 'fa' - }); - } - } -}); - -dataGridRegisterExtension('datagrid.groupActionMultiSelect', { - success: function() { - return datagridGroupActionMultiSelect(); - } -}); - -dataGridRegisterExtension('datagrid.inline-editing', { - success: function(payload) { - var grid; - if (payload._datagrid_inline_editing) { - grid = $('.datagrid-' + payload._datagrid_name); - return grid.find('.datagrid-inline-edit-trigger').addClass('hidden'); - } - } -}); - -dataGridRegisterExtension('datagrid.redraw-item', { - success: function(payload) { - var row; - if (payload._datagrid_redraw_item_class) { - row = $('tr[data-id="' + payload._datagrid_redraw_item_id + '"]'); - return row.attr('class', payload._datagrid_redraw_item_class); - } - } -}); - -dataGridRegisterExtension('datagrid.reset-filter-by-column', { - success: function(payload) { - var grid, href, i, key, len, ref; - if (!payload._datagrid_name) { - return; - } - grid = $('.datagrid-' + payload._datagrid_name); - grid.find('[data-datagrid-reset-filter-by-column]').addClass('hidden'); - if (payload.non_empty_filters && payload.non_empty_filters.length) { - 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'); - } - href = grid.find('.reset-filter').attr('href'); - return grid.find('[data-datagrid-reset-filter-by-column]').each(function() { - var new_href; - key = $(this).attr('data-datagrid-reset-filter-by-column'); - new_href = href.replace('do=' + payload._datagrid_name + '-resetFilter', 'do=' + payload._datagrid_name + '-resetColumnFilter'); - new_href += '&' + payload._datagrid_name + '-key=' + key; - return $(this).attr('href', new_href); - }); - } - } -}); diff --git a/assets/datagrid.ts b/assets/datagrid.ts new file mode 100644 index 000000000..de36fcaa0 --- /dev/null +++ b/assets/datagrid.ts @@ -0,0 +1,145 @@ +import { defaultDatagridNameResolver, isEnter } from "./utils"; +import type { Ajax, DatagridEventMap, DatagridOptions, EventDetail, EventListener, } from "./types"; + +export class Datagrid extends EventTarget { + private static readonly defaultOptions: DatagridOptions = { + confirm: confirm, + resolveDatagridName: defaultDatagridNameResolver, + plugins: [], + }; + + public readonly name: string; + + public readonly ajax: Ajax; + + private readonly options: DatagridOptions; + + constructor( + public readonly el: HTMLElement, + ajax: Ajax | ((grid: Datagrid) => Ajax), + options: Partial + ) { + super(); + + this.options = { + ...Datagrid.defaultOptions, + ...options, + }; + + const name = this.resolveDatagridName(); + + if (!name) { + throw new Error("Cannot resolve name of a datagrid!"); + } + + this.name = name; + + this.ajax = typeof ajax === "function" ? ajax(this) : ajax; + + this.ajax.addEventListener("success", e => { + if (e.detail.payload?._datagrid_name === this.name && e.detail.payload?._datagrid_init) { + this.init(); + } + }); + + this.init(); + } + + public init() { + let cancelled = !this.dispatch('beforeInit', {datagrid: this}) + if (!cancelled) { + this.options.plugins.forEach((plugin) => { + plugin.onDatagridInit?.(this) + }) + } + + // Uncheck toggle-all + const checkedRows = this.el.querySelectorAll("input[data-check]:checked"); + if (checkedRows.length === 1 && checkedRows[0].getAttribute("name") === "toggle-all") { + const input = checkedRows[0]; + if (input) { + input.checked = false; + } + } + + this.el.querySelectorAll("input[data-datagrid-manualsubmit]").forEach(inputEl => { + const form = inputEl.closest("form"); + if (!form) return; + + inputEl.addEventListener("keydown", e => { + if (!isEnter(e)) return; + + e.stopPropagation(); + e.preventDefault(); + return this.ajax.submitForm(form); + }); + }); + + this.ajax.addEventListener("success", ({detail: {payload}}) => { + // todo: maybe move? + if (payload._datagrid_name && payload._datagrid_name === this.name) { + this.el.querySelector("[data-datagrid-reset-filter-by-column]") + ?.classList.add("hidden"); + + if (payload.non_empty_filters && payload.non_empty_filters.length >= 1) { + const resets = Array.from(this.el.querySelectorAll( + `[data-datagrid-reset-filter-by-column]` + )); + + const getColumnName = (el: HTMLElement) => el.getAttribute( + "data-datagrid-reset-filter-by-column" + ) + + /// tf? + for (const columnName of payload.non_empty_filters) { + resets.find(getColumnName)?.classList.remove("hidden"); + } + + const href = this.el.querySelector(".reset-filter") + ?.getAttribute("href"); + + if (href) { + resets.forEach((el) => { + const columnName = getColumnName(el); + + const newHref = href.replace("-resetFilter", "-resetColumnFilter"); + el.setAttribute("href", `${newHref}&${this.name}-key=${columnName}`); + }) + } + } + } + }) + + this.dispatch('afterInit', {datagrid: this}); + } + + public confirm(message: string): boolean { + return this.options.confirm.bind(this)(message); + } + + public resolveDatagridName(): string | null { + return this.options.resolveDatagridName.bind(this)(this.el); + } + + dispatch< + K extends string, M extends DatagridEventMap = DatagridEventMap + >(type: K, detail: K extends keyof M ? EventDetail : any, options?: boolean): boolean { + return this.dispatchEvent(new CustomEvent(type, {detail})); + } + + declare addEventListener: ( + type: K, + listener: EventListener, + options?: boolean | AddEventListenerOptions + ) => void; + + declare removeEventListener: ( + type: K, + listener: EventListener, + options?: boolean | AddEventListenerOptions + ) => void; + + declare dispatchEvent: ( + event: K extends keyof M ? M[K] : CustomEvent + ) => boolean; +} diff --git a/assets/datagrids.ts b/assets/datagrids.ts new file mode 100644 index 000000000..fef2503fe --- /dev/null +++ b/assets/datagrids.ts @@ -0,0 +1,80 @@ +import { Datagrid } from "./datagrid"; +import { + AutosubmitPlugin, + CheckboxPlugin, + ConfirmPlugin, + HappyPlugin, + InlinePlugin, + NetteFormsPlugin, + SelectpickerPlugin, + SortablePlugin +} from "./plugins"; +import { Ajax, DatagridsOptions } from "./types"; +import { SortableJS } from "./integrations/sortable-js"; +import { DatepickerPlugin } from "./plugins/integrations/datepicker"; +import { BootstrapSelect, Happy, VanillaDatepicker } from "./integrations"; + +export class Datagrids { + private datagrids: Datagrid[] = []; + + readonly options: DatagridsOptions; + + readonly root: HTMLElement; + + constructor(readonly ajax: Ajax, options: Partial = {}) { + this.options = { + selector: "div[data-datagrid-name]", + datagrid: {}, + root: document.body, + ...options, + }; + + const root = typeof this.options.root === "string" + ? document.querySelector(this.options.root) + : this.options.root; + + if (!root || !(root instanceof HTMLElement)) { + throw new Error("Root element not found or is not an HTMLElement"); + } + + this.root = root; + + this.init(); + } + + init() { + this.ajax.onInit(); + (this.options.datagrid?.plugins ?? []).forEach((plugin) => plugin.onInit?.(this)); + + this.initDatagrids(); + } + + initDatagrids() { + this.datagrids = Array.from(this.root.querySelectorAll(this.options.selector)).map( + datagrid => new Datagrid(datagrid, this.ajax, this.options.datagrid) + ); + } +} + +export const createDatagrids = (ajax: Ajax, _options: Partial = {}) => { + return new Datagrids(ajax, _options); +}; + +export const createFullDatagrids = (ajax: Ajax, _options: Partial = {}) => { + return createDatagrids(ajax, { + datagrid: { + plugins: [ + new AutosubmitPlugin(), + new CheckboxPlugin(), + new ConfirmPlugin(), + new InlinePlugin(), + new NetteFormsPlugin(), + new HappyPlugin(new Happy()), + new SortablePlugin(new SortableJS()), + new DatepickerPlugin(new VanillaDatepicker()), + new SelectpickerPlugin(new BootstrapSelect()) + ], + }, + ..._options, + }) +}; diff --git a/assets/index.ts b/assets/index.ts new file mode 100644 index 000000000..39d8538bf --- /dev/null +++ b/assets/index.ts @@ -0,0 +1,6 @@ +export * from "./datagrid"; +export * from "./plugins"; +export * from "./integrations"; + +export * from "./datagrids" +export * from "./datagrid"; diff --git a/assets/integrations/bootstrap-select.ts b/assets/integrations/bootstrap-select.ts new file mode 100644 index 000000000..d551de1aa --- /dev/null +++ b/assets/integrations/bootstrap-select.ts @@ -0,0 +1,43 @@ +import { Selectpicker } from "../types"; +import { window } from "../utils"; + +export class BootstrapSelect implements Selectpicker { + initSelectpickers(elements: HTMLElement[]): void { + if (window().jQuery) { + const $ = window().jQuery; + if ($?.fn.selectpicker) { + $.fn.selectpicker.defaults = { + countSelectedText: elements[0].getAttribute("i18n-selected") ?? "", + iconBase: "fa", + tickIcon: elements[0].getAttribute("selected-icon-check") ?? "fa fa-check", + }; + + elements.forEach(element => + $(element) + .removeClass("form-select form-select-sm") + .addClass("form-control form-control-sm") + .selectpicker("destroy") + .selectpicker({}) + ); + + Array.from(elements) + .filter(element => element.hasAttribute("data-datagrid-multiselect-id")) + .forEach(element => { + const $picker = $(element); + const $parent = $picker.parent(); + + $picker.removeAttr("id"); + const id = element.getAttribute("data-datagrid-multiselect-id"); + + $picker.on("loaded.bs.select", () => { + $parent.attr("style", "display: none;"); + $parent.find(".hidden").removeClass("hidden").addClass("btn-default btn-secondary"); + }); + + $picker.on("rendered.bs.select", () => $parent.attr("id", id)); + }); + } + } + } + +} diff --git a/assets/integrations/happy.ts b/assets/integrations/happy.ts new file mode 100644 index 000000000..fb09196b7 --- /dev/null +++ b/assets/integrations/happy.ts @@ -0,0 +1,222 @@ +import { happyStyles } from "../css/happy.css"; + +/** + * Slightly cleaned up & typed version of happy-inputs by paveljanda. + */ +export class Happy { + private colors: string[] = ["primary", "success", "info", "warning", "danger", "white", "gray"]; + + private templates = { + radio: '
', + checkbox: + '
', + text: "", + textarea: "", + }; + + init() { + if (!document.querySelector('[data-happy-stylesheet]')) { + document.head.append(``) + } + this.removeBySelector(".happy-radio"); + this.removeBySelector(".happy-checkbox"); + + this.initRadio(); + this.initCheckbox(); + } + + /** + * @deprecated + */ + reset() { + this.init(); + } + + addColorToInput(input: HTMLElement, happyInput: HTMLElement, classString: string) { + if (input.classList.contains(classString)) { + happyInput.classList.add(classString); + } + + classString = `${classString}-border`; + + if (input.classList.contains(classString)) { + happyInput.classList.add(classString); + } + } + + // i... you know what, no, let "thinkess" be "thinkess" + addThinkessToInput(input: HTMLElement, happyInput: HTMLElement) { + if (input.classList.contains("thin")) { + happyInput.classList.add("thin"); + } + } + + setNames(input: HTMLElement, happyInput: HTMLElement) { + happyInput.setAttribute("data-name", input.getAttribute("name") ?? ""); + + var value = input.getAttribute("value"); + + if (value !== "undefined" && value !== null) { + happyInput.setAttribute("data-value", input.getAttribute("value") ?? ""); + } + } + + removeBySelector(selector: string) { + document.querySelectorAll(selector).forEach(el => el.parentNode?.removeChild(el)); + } + + initRadio() { + document.querySelectorAll("input[type=radio].happy").forEach(input => { + /** + * Paste happy component into html + */ + input.insertAdjacentHTML("afterend", this.templates.radio); + + const happyInput = input.nextElementSibling; + + if (happyInput instanceof HTMLElement) { + /** + * Add optional colors + */ + this.colors.forEach(color => { + this.addColorToInput(input, happyInput, color); + this.setNames(input, happyInput); + }); + + this.addThinkessToInput(input, happyInput); + } + + /** + * Init state + */ + this.checkRadioState(input); + + /** + * Set aciton functionality for native change + */ + document.addEventListener("change", this.radioOnChange.bind(this)); + }); + } + + initCheckbox() { + document.querySelectorAll("input[type=checkbox].happy").forEach(input => { + /** + * Paste happy component into html + */ + input.insertAdjacentHTML("afterend", this.templates.checkbox); + + const happyInput = input.nextElementSibling; + + /** + * Add optional colors + */ + if (happyInput instanceof HTMLElement) { + this.colors.forEach(color => { + this.addColorToInput(input, happyInput, color); + this.setNames(input, happyInput); + }); + + this.addThinkessToInput(input, happyInput); + } + + /** + * Init state + */ + this.checkCheckboxState(input); + + /** + * Set action functionality for click || native change + */ + document.addEventListener("click", this.checkCheckboxStateOnClick.bind(this)); + document.addEventListener("change", this.checkCheckboxStateOnChange.bind(this)); + }); + } + + checkCheckboxStateOnClick(event: Event) { + const target = event.target; + + // When target is SVGSVGElement (), return parentNode, + // When target is a SVGGraphicsElement (,...), find and return it's parent node + // otherwise return target itself. + const happyInput = + target instanceof SVGSVGElement + ? target.parentNode + : target instanceof SVGGraphicsElement + ? target.closest("svg")?.parentNode + : target; + + if (!(happyInput instanceof HTMLElement) || !happyInput.classList.contains("happy-checkbox")) { + return; + } + + event.preventDefault(); + + const name = happyInput.getAttribute("data-name"); + const value = happyInput.getAttribute("data-value"); + + const input = document.querySelector( + `.happy-checkbox[data-name="${name}"]` + (!!value ? `[value="${value}"]` : "") + ); + if (!(input instanceof HTMLInputElement)) return; + + const checked = happyInput.classList.contains("active"); + + input.checked = !checked; + checked ? happyInput.classList.remove("active") : happyInput.classList.add("active"); + } + + checkCheckboxStateOnChange({target}: Event) { + if (!(target instanceof HTMLInputElement)) return; + + if (target.classList.contains("happy")) { + this.checkCheckboxState(target); + } + } + + checkRadioState(input: HTMLInputElement) { + if (!input.checked || !input.hasAttribute("name")) return; + + const name = input.getAttribute("name"); + const value = input.getAttribute("value"); + + const element = document.querySelector( + `.happy-checkbox[data-name="${name}"]` + (!!value ? `[data-value="${value}"]` : "") + ); + + if (element) { + element.classList.add("active"); + } + } + + checkCheckboxState(input: HTMLInputElement) { + const name = input.getAttribute("name"); + if (!name) return; + + const value = input.getAttribute("value"); + const element = document.querySelector( + `.happy-checkbox[data-name="${name}"]` + (!!value ? `[data-value="${value}"]` : "") + ); + + if (!element) return; + + input.checked ? element.classList.add("active") : element.classList.remove("active"); + } + + radioOnChange({target}: Event) { + // Check whether target is
${snippet}
`; + + childrenBlock.innerHTML = template; + } + //children_block.addClass('loaded'); + //children_block.slideToggle('fast'); + } + } + }) + return true; + } +} diff --git a/assets/plugins/index.ts b/assets/plugins/index.ts new file mode 100644 index 000000000..99b83aed8 --- /dev/null +++ b/assets/plugins/index.ts @@ -0,0 +1,12 @@ +export * from "./integrations/datepicker"; +export * from "./integrations/happy"; +export * from "./integrations/nette-forms" +export * from "./integrations/selectpicker"; +export * from "./integrations/sortable"; + +export * from "./features/autosubmit"; +export * from "./features/checkboxes"; +export * from "./features/confirm"; +export * from "./features/editable"; +export * from "./features/inline"; +export * from "./features/item-detail"; diff --git a/assets/plugins/integrations/datepicker.ts b/assets/plugins/integrations/datepicker.ts new file mode 100644 index 000000000..5ba14ac32 --- /dev/null +++ b/assets/plugins/integrations/datepicker.ts @@ -0,0 +1,17 @@ +import { Datagrid } from "../.."; +import { DatagridPlugin, Datepicker } from "../../types"; + +export class DatepickerPlugin implements DatagridPlugin { + constructor(private datepicker: Datepicker) { + } + + onDatagridInit(datagrid: Datagrid): boolean { + const elements = datagrid.el.querySelectorAll("input[data-provide='datepicker']"); + + if (elements.length >= 1) { + this.datepicker.initDatepickers(Array.from(elements), datagrid); + } + + return true; + } +} diff --git a/assets/plugins/integrations/happy.ts b/assets/plugins/integrations/happy.ts new file mode 100644 index 000000000..e7596a8c3 --- /dev/null +++ b/assets/plugins/integrations/happy.ts @@ -0,0 +1,19 @@ +import { Datagrid } from "../.."; +import { DatagridPlugin } from "../../types"; +import { window } from "../../utils"; +import type { Happy } from "../../integrations"; + +export class HappyPlugin implements DatagridPlugin { + constructor(private happy?: Happy) { + } + + onDatagridInit(datagrid: Datagrid): boolean { + const happy = this.happy ?? window().happy ?? null; + + if (happy) { + happy.init(); + } + + return true; + } +} diff --git a/assets/plugins/integrations/nette-forms.ts b/assets/plugins/integrations/nette-forms.ts new file mode 100644 index 000000000..5c0748665 --- /dev/null +++ b/assets/plugins/integrations/nette-forms.ts @@ -0,0 +1,18 @@ +import { DatagridPlugin, Nette } from "../../types"; +import { Datagrid } from "../.."; +import { window } from "../../utils"; + +export class NetteFormsPlugin implements DatagridPlugin { + constructor(private nette?: Nette) { + } + + onDatagridInit(datagrid: Datagrid): boolean { + const nette = this.nette ?? window().Nette ?? null; + + if (nette) { + datagrid.el.querySelectorAll("form").forEach(form => nette.initForm(form)); + } + + return true; + } +} diff --git a/assets/plugins/integrations/selectpicker.ts b/assets/plugins/integrations/selectpicker.ts new file mode 100644 index 000000000..a95e2af61 --- /dev/null +++ b/assets/plugins/integrations/selectpicker.ts @@ -0,0 +1,17 @@ +import { DatagridPlugin, Selectpicker } from "../../types"; +import { Datagrid } from "../.."; + +export class SelectpickerPlugin implements DatagridPlugin { + constructor(private selectpicker: Selectpicker) { + } + + onDatagridInit(datagrid: Datagrid): boolean { + const elements = datagrid.el.querySelectorAll(".selectpicker"); + + if (elements.length >= 1) { + this.selectpicker.initSelectpickers(Array.from(elements), datagrid); + } + + return true; + } +} diff --git a/assets/plugins/integrations/sortable.ts b/assets/plugins/integrations/sortable.ts new file mode 100644 index 000000000..4a787cf70 --- /dev/null +++ b/assets/plugins/integrations/sortable.ts @@ -0,0 +1,61 @@ +import { Datagrid } from "../../datagrid"; +import { DatagridPlugin, Sortable } from "../../types"; + +export class SortablePlugin implements DatagridPlugin { + constructor(private sortable: Sortable) { + } + + onDatagridInit(datagrid: Datagrid): boolean { + datagrid.ajax.addEventListener('before', (event) => { + // TODO old ln 694... wtf? + }) + + this.sortable.initSortable(datagrid); + + datagrid.ajax.addEventListener('success', ({detail: {payload}}) => { + if (payload._datagrid_sort) { + for (const key in payload._datagrid_sort) { + const href = payload._datagrid_sort[key]; + const element = datagrid.el.querySelector(`#datagrid-sort-${key}`); + + if (element) { + // TODO: Only for BC support, to be removed + element.setAttribute("href", href); + + element.setAttribute("data-href", href); + } + } + this.sortable.initSortable(datagrid); + } + + if (payload._datagrid_tree) { + const childrenContainer = datagrid.el.querySelector( + `.datagrid-tree-item[data-id='${payload._datagrid_tree}'] .datagrid-tree-item-children` + ); + if (childrenContainer && payload.snippets) { + childrenContainer.classList.add("loaded"); + for (const key in payload.snippets) { + const snippet = payload.snippets[key]; + + const doc = new DOMParser().parseFromString(snippet, 'text/html'); + const element = doc.firstElementChild; + if (element) { + const treeItem = document.createElement("div"); + treeItem.id = key; + treeItem.classList.add("datagrid-tree-item") + treeItem.setAttribute("data-id", key); + if (element.hasAttribute("has-children")) { + treeItem.classList.add("has-children"); + } + + childrenContainer.append(treeItem); + // attachSlideToggle(childrenContainer); + } + } + } + this.sortable.initSortableTree(datagrid); + } + }) + return true; + } +} diff --git a/assets/types/ajax.d.ts b/assets/types/ajax.d.ts new file mode 100644 index 000000000..c4ae89639 --- /dev/null +++ b/assets/types/ajax.d.ts @@ -0,0 +1,136 @@ +import { EventDetail, EventListener, EventMap } from "."; +import { Datagrid } from ".."; + +export interface BaseRequestParams { + method: "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "CONNECT" | "OPTIONS" | "TRACE" | "PATCH" | string; + url: string; +} + +export interface RequestParams extends BaseRequestParams { + data: D; +} + +export interface DatagridPayload { + _datagrid_name?: string; + _datagrid_toggle_detail?: string + _datagrid_inline_editing?: boolean; + _datagrid_inline_adding?: boolean; + _datagrid_inline_edited?: boolean; + _datagrid_inline_edit_cancel?: boolean; + _datagrid_url?: boolean; + _datagrid_sort?: Record; + _datagrid_tree?: string; + _datagrid_editable_new_value?: string; + _datagrid_redraw_item_id?: string; + _datagrid_redraw_item_class?: string; + _datagrid_init?: boolean; + non_empty_filters?: string[]; +} + +export interface DatagridState { + "grid-page": number | null, + "grid-perPage": number, + // TODO + "grid-sort": any | null, + "grid-filter": any | null +} + +export type Payload

= P & { + snippets?: Record; + redirect?: string; + state: S; +}; + +export interface Response { + headers: Record | Headers; + status: number; +} + +export interface BeforeEventDetail { + params: RequestParams; +} + +export interface InteractEventDetail { + element: E; +} + +export interface SuccessEventDetail

{ + params: BaseRequestParams; + payload: Payload

; + response: Response; +} + +export interface ErrorEventDetail { + params: BaseRequestParams; + response?: Response; + error?: E; +} + +export interface AjaxEventMap extends EventMap { + before: CustomEvent; + interact: CustomEvent; + snippetUpdate: CustomEvent; + success: CustomEvent; + error: CustomEvent; +} + +export interface Ajax extends EventTarget { + client: C; + + /** + * Initialization of the Ajax instance, called in createDatagrids(). + * @return this + */ + onInit(): this; + + /** + * Initializes a Datagrid instance. + * @param grid The Datagrid instance + */ + onDatagridInit?(grid: G): void; + + /** + * Sends a request to the server. + */ + request(args: RequestParams): Promise

; + + /** + * Submits a form + */ + submitForm(element: E): Promise

; + + /** + * Shortcut for dispatchEvent + * @internal + */ + dispatch( + type: K, + detail: K extends keyof M ? EventDetail : any, + options?: boolean + ): boolean; + + /** + * Note: For events dispatched directly from the underlying client, {@see Ajax.client}} + **/ + addEventListener( + type: K, + listener: EventListener, + options?: boolean | AddEventListenerOptions + ): void; + + /** + * Note: For events dispatched directly from the underlying client, {@see Ajax.client}} + **/ + removeEventListener( + type: K, + listener: EventListener, + options?: boolean | AddEventListenerOptions + ): void; + + /** + * @internal + */ + dispatchEvent( + event: K extends keyof M ? M[K] : CustomEvent + ): boolean; +} diff --git a/assets/types/datagrid.d.ts b/assets/types/datagrid.d.ts new file mode 100644 index 000000000..d62468ce5 --- /dev/null +++ b/assets/types/datagrid.d.ts @@ -0,0 +1,31 @@ +import { Datagrid, Datagrids } from ".."; +import { EventMap } from "."; + +export interface DatagridEventDetail { + datagrid: Datagrid; +} + +export interface DatagridEventMap extends EventMap { + beforeInit: CustomEvent; + afterInit: CustomEvent; +} + +export interface DatagridPlugin { + onInit?(datagrids: Datagrids): void; + + onDatagridInit?(datagrid: Datagrid): boolean; +} + +export interface DatagridOptions { + confirm(this: Datagrid, message: string): boolean; + + // Returning null will skip this datagrid + resolveDatagridName: (this: Datagrid, datagrid: HTMLElement) => string | null; + plugins: DatagridPlugin[]; +} + +export interface DatagridsOptions { + datagrid: Partial; + selector: string; + root: HTMLElement | string; +} diff --git a/assets/types/index.d.ts b/assets/types/index.d.ts new file mode 100644 index 000000000..4cd5750d7 --- /dev/null +++ b/assets/types/index.d.ts @@ -0,0 +1,41 @@ +import { Happy } from "../integrations"; +import TomSelect from "tom-select"; + +export interface Nette { + initForm: (form: HTMLFormElement) => void; +} + +export type Constructor = new (...args: any[]) => T; + +export type KeysOf = { [P in keyof T]: TVal; } + +export interface ExtendedWindow extends Window { + jQuery?: any; + Nette?: Nette; + TomSelect?: Constructor; + happy?: Happy; +} + +// https://github.com/naja-js/naja/blob/384d298a9199bf778985d1bcf5747fe8de305b22/src/utils.ts +type EventListenerFunction = ( + this: ET, + event: E +) => boolean | void | Promise; + +interface EventListenerObject { + handleEvent(event: E): void | Promise; +} + +export type EventListener = + | EventListenerFunction + | EventListenerObject + | null; + +export type EventDetail = E extends CustomEvent ? D : never; + +export interface EventMap extends Record { +} + +export * from "./datagrid"; +export * from "./integrations"; +export * from "./ajax"; diff --git a/assets/types/integrations.d.ts b/assets/types/integrations.d.ts new file mode 100644 index 000000000..15ddbcc57 --- /dev/null +++ b/assets/types/integrations.d.ts @@ -0,0 +1,15 @@ +import { Datagrid } from ".."; + +export interface Sortable { + initSortable(datagrid: Datagrid): void; + + initSortableTree(datagrid: Datagrid): void; +} + +export interface Selectpicker { + initSelectpickers(elements: HTMLElement[], datagrid: Datagrid): void; +} + +export interface Datepicker { + initDatepickers(elements: HTMLInputElement[], datagrid: Datagrid): void; +} diff --git a/assets/utils.ts b/assets/utils.ts new file mode 100644 index 000000000..85966da3a --- /dev/null +++ b/assets/utils.ts @@ -0,0 +1,179 @@ +import { Datagrid } from "./datagrid"; +import { ExtendedWindow } from "./types"; + +export function isPromise(p: any): p is Promise { + return typeof p === "object" && typeof p.then === "function"; +} + +export function isInKeyRange(e: KeyboardEvent, min: number, max: number): boolean { + const code = e.key.length === 1 ? e.key.charCodeAt(0) : 0; + return code >= min && code <= max; +} + +export function isEnter(e: KeyboardEvent): boolean { + return e.key === "Enter"; +} + +export function isEsc(e: KeyboardEvent): boolean { + return e.key === "Escape"; +} + +export function isFunctionKey(e: KeyboardEvent): boolean { + return e.key.length === 2 && e.key.startsWith("F"); +} + +export function window(): ExtendedWindow { + return (window ?? {}) as unknown as ExtendedWindow; +} + +export function slideDown(element: HTMLElement, cb?: (nextStateShown: boolean) => unknown) { + element.style.height = 'auto'; + + let height = element.clientHeight + "px"; + + element.style.height = '0px'; + + setTimeout(function () { + element.style.height = height; + cb?.(true); + }, 0); +} + +export function slideUp(element: HTMLElement, cb?: (nextStateShown: boolean) => unknown) { + element.style.height = '0px'; + + setTimeout(() => { + cb?.(false); + }, 250); // TODO +} + +export function slideToggle(element: HTMLElement, isVisible: boolean, cb?: (nextStateShown: boolean) => unknown) { + if (!isVisible) { + slideDown(element, cb); + } else { + slideUp(element, cb); + } +} + +export function attachSlideToggle(element: HTMLElement, control: HTMLElement, cb?: (nextStateShown: boolean) => unknown) { + if (!control.classList.contains("datagrid--slide-toggle")) { + let sliding = false; + control.classList.add("datagrid--slide-toggle"); + + slideDown(element, cb); + + control.addEventListener('click', () => { + if (sliding) return; + sliding = true; + slideToggle(element, control.classList.contains('is-active'), (active) => { + sliding = false + if (active) { + control.classList.add("is-active"); + } else { + control.classList.remove("is-active"); + } + }); + }); + } +} + +export function qs(params: Record, prefix: string = ""): string { + const encodedParams = []; + + for (const _key in params) { + const value = params[_key]; + // Cannot do !value as that would also exclude valid negative values such as 0 or false + if (value === null || value === undefined) continue; + + const key = prefix ? `${prefix}[${_key}]` : _key; + + // Skip empty strings + if (typeof value === "string" && value.trim().length < 1) continue; + + if (typeof value === "object") { + const nestedParams = qs(value, key); + // Don't include if object is empty + if (nestedParams.length >= 1) { + encodedParams.push(nestedParams); + } + + continue; + } + + encodedParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + } + + return encodedParams.join("&").replace(/&+$/gm, "").replace(/&*$/, ""); +} + +export function calculateCellLines(el: HTMLElement) { + const cellPadding = el.style.padding ? parseInt(el.style.padding.replace(/[^-\d\.]/g, ""), 10) : 0; + const cellHeight = el.getBoundingClientRect().height; + const lineHeight = Math.round(parseFloat(el.style.lineHeight ?? "0")); + const cellLines = Math.round((cellHeight - 2 * cellPadding) / lineHeight); + + return cellLines; +} + +// A little better debounce ;) +export function debounce unknown | Promise>( + fn: TFun, + slowdown: number = 200 +): (...args: TArgs[]) => void { + let timeout: ReturnType | null = null; + let blockedByPromise: boolean = false; + + return (...args) => { + if (blockedByPromise) return; + + timeout && clearTimeout(timeout); + timeout = setTimeout(() => { + const result = fn(...args); + + if (isPromise(result)) { + blockedByPromise = true; + result.finally(() => { + blockedByPromise = false; + }); + } + }, slowdown); + }; +} + +export function defaultDatagridNameResolver(this: Datagrid, datagrid: HTMLElement) { + // This attribute is not present by default, though if you're going to use this library + // it's recommended to add it, because when not present, the fallback way is to parse the datagrid- class, + // which is definitely far from reliable. Alternatively (mainly in case of a custom datagrid class), + // you can pass your own resolveDatagridName function to the option. + const attrName = datagrid.getAttribute("data-datagrid-name"); + if (attrName) return attrName; + + console.warn( + "Deprecated name resolution for datagrid", + datagrid, + ": Please add a data-datagrid-name attribute instead!\n" + + "Currently, the Datagrid library relies on matching the name from the 'datagrid-[name]' class, which is unreliable " + + "and may cause bugs if the default class names are not used (eg. if you add a datagrid-xx class, or change the name class completely!)\n" + + "Alternatively, you can customize the name resolution with the `resolveDatagridName` option. See TBD for more info." // TODO + ); + + const classes = datagrid.classList.value.split(" "); + + // Returns the first datagrid-XXX match + for (const className of classes) { + if (!className.startsWith("datagrid-")) continue; + + const [, ...split] = className.split("-"); + const name = split.join("-"); + + // In case nothing actually follows the prefix (className = "datagrid-") + if (name.length < 1) { + console.error(`Failed to resolve datagrid name - ambigious class name '${className}'`); + return null; + } + + return name; + } + + return null; +} diff --git a/compatibility.php b/compatibility.php new file mode 100644 index 000000000..26fca7fa0 --- /dev/null +++ b/compatibility.php @@ -0,0 +1,556 @@ +=7.2", + "php": ">=8.1", "contributte/application": "^0.5.0", "nette/di": "^3.0.0", "nette/forms": "^3.1.3", @@ -42,19 +43,20 @@ "symfony/property-access": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "require-dev": { + "contributte/qa": "^0.3.0", "dibi/dibi": "^3.0.0 || ^4.0.0", + "doctrine/annotations": "^1.12.1", "doctrine/cache": "^1.11.0", "doctrine/orm": "^2.11.1", - "doctrine/annotations": "^1.12.1", - "elasticsearch/elasticsearch": "^7.1", - "contributte/code-rules": "^1.1.0", + "elasticsearch/elasticsearch": "^8.6", "mockery/mockery": "^1.3.3", "nette/database": "^3.0.2", "nette/tester": "^2.3.4", - "nextras/dbal": "^3.0.1 || ^4.0", - "nextras/orm": "^3.1.0 || ^4.0", - "ninjify/coding-standard": "^0.12.1", + "nextras/dbal": "^4.0", + "nextras/orm": "^4.0", + "phpstan/phpstan-deprecation-rules": "^1.1", "phpstan/phpstan-nette": "^1.0.0", + "phpstan/phpstan-strict-rules": "^1.4", "tharos/leanmapper": "^3.4.2 || ^4.0.0", "tracy/tracy": "^2.6.3" }, @@ -64,12 +66,13 @@ "sort-packages": true, "allow-plugins": { "composer/package-versions-deprecated": true, - "dealerdirect/phpcodesniffer-composer-installer": true + "dealerdirect/phpcodesniffer-composer-installer": true, + "php-http/discovery": true } }, "extra": { "branch-alias": { - "dev-master": "6.10.x-dev" + "dev-master": "7.x-dev" } } } diff --git a/package.json b/package.json index ae8876f5f..a1ecb2261 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,39 @@ { - "name": "ublaboo-datagrid", - "version": "6.9.1", - "description": "Assets for php composer package ublaboo/datagrid", - "keywords": [ - "ublaboo", - "contributte", - "datagrid" - ], - "author": "Pavel Janda ", - "license": "MIT", - "main": "assets/datagrid.js", - "files": [ - "assets/*" - ], - "scripts": { - "release-dry": "npm publish --dry-run", - "release": "npm publish" - } + "name": "@contributte/datagrid", + "version": "6.9.1", + "description": "Assets for contributte/datagrid", + "keywords": [ + "contributte", + "datagrid", + "tables" + ], + "license": "MIT", + "main": "assets/datagrid.js", + "files": [ + "assets/*" + ], + "scripts": { + "release-dry": "npm publish --dry-run", + "release": "npm publish" + }, + "dependencies": { + "naja": "^2.5.0" + }, + "devDependencies": { + "@fortawesome/fontawesome-free": "^6.3.0", + "bootstrap": "^5.3.0-alpha3", + "nette-forms": "^3.3.1", + "prismjs": "^1.29.0", + "sortablejs": "^1.15.0", + "tom-select": "^2.2.2", + "vanillajs-datepicker": "^1.3.1", + "@types/bootstrap-select": "^1.13.4", + "@types/jquery": "^3.5.16", + "@types/jqueryui": "^1.12.16", + "@types/sortablejs": "^1.15.1", + "@types/vanillajs-datepicker": "^1.2.1", + "autoprefixer": "^10.4.0", + "typescript": "^4.9.5", + "vite": "^2.6.10" + } } diff --git a/phpstan.neon b/phpstan.neon index 59f4c075a..0d42c5665 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,8 @@ includes: - - ./vendor/contributte/code-rules/paveljanda/phpstan.neon - - ./vendor/phpstan/phpstan-nette/extension.neon - - ./vendor/phpstan/phpstan-nette/rules.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon + - vendor/phpstan/phpstan-nette/extension.neon + - vendor/phpstan/phpstan-nette/rules.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon parameters: level: 8 @@ -9,25 +10,18 @@ parameters: paths: - src - reportMaybesInPropertyPhpDocTypes: false + checkMissingIterableValueType: false + checkGenericClassInNonGenericObjectType: false ignoreErrors: - message: '/^Call to an undefined method Nette\\Bridges\\ApplicationLatte\\Template::add\(\)\.$/' count: 2 - path: src/DataGrid.php + path: src/Datagrid.php - - message: '/^Instanceof between Ublaboo\\DataGrid\\Filter\\Filter and Ublaboo\\DataGrid\\Filter\\FilterDateRange will always evaluate to false\.$/' + message: '/^Instanceof between Contributte\\Datagrid\\Filter\\Filter and Contributte\\Datagrid\\Filter\\FilterDateRange will always evaluate to false\.$/' count: 1 - path: src/DataGrid.php - - - message: '/^Class dibi referenced with incorrect case\: Dibi\.$/' - count: 1 - path: src/DataModel.php - - - message: '/^Call to an undefined method Nextras\\Orm\\Collection\\ICollection\:\:getQueryBuilder\(\)\.$/' - count: 2 - path: src/DataSource/NextrasDataSource.php + path: src/Datagrid.php - message: '/^Class Dibi\\Drivers\\MsSqlDriver not found\.$/' count: 1 @@ -37,13 +31,13 @@ parameters: count: 1 path: src/DataSource/DibiFluentMssqlDataSource.php - - message: "#^Cannot call method filterData\\(\\) on Ublaboo\\\\DataGrid\\\\DataModel\\|null\\.$#" + message: "#^Cannot call method filterData\\(\\) on Contributte\\\\Datagrid\\\\DataModel\\|null\\.$#" count: 1 - path: src/DataGrid.php + path: src/Datagrid.php - - message: "#^Cannot call method filterRow\\(\\) on Ublaboo\\\\DataGrid\\\\DataModel\\|null\\.$#" + message: "#^Cannot call method filterRow\\(\\) on Contributte\\\\Datagrid\\\\DataModel\\|null\\.$#" count: 1 - path: src/DataGrid.php + path: src/Datagrid.php - message: "#^Parameter \\#1 \\$x of method Doctrine\\\\ORM\\\\Query\\\\Expr\\:\\:like\\(\\) expects string, Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Func given\\.$#" count: 1 @@ -52,10 +46,6 @@ parameters: message: '#string\\|Stringable#' count: 1 path: src/Column/Action.php - - # In PHP 8+, the Stringable typehint should be used, and this can be removed. - message: '#string\\|Stringable#' - count: 1 - path: src/DataGrid.php - # In PHP 8+, the Stringable typehint should be used, and this can be removed. message: '#string\\|Stringable#' count: 3 diff --git a/ruleset.xml b/ruleset.xml index 72336d57d..585d73c35 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -1,45 +1,54 @@ - - - - - - - - - - - + + + + + + + + - - - + + + - - - - - - - - - - - - tests/Cases/DataSources/NextrasDataSourceTest.phpt tests/Cases/DataSources/DoctrineDataSourceTest.phpt + + + *tests/Cases/* + + + + *tests/Cases/* + + + + compatibility.php + + + + *tests/Cases/* + + + + *tests/Cases/* + + + + *tests/Cases/* + diff --git a/src/AggregationFunction/FunctionSum.php b/src/AggregationFunction/FunctionSum.php index a5e800da1..7fb74c42b 100644 --- a/src/AggregationFunction/FunctionSum.php +++ b/src/AggregationFunction/FunctionSum.php @@ -1,61 +1,33 @@ -column = $column; - $this->dataType = $dataType; + public function __construct(protected string $column, protected string $dataType = IAggregationFunction::DATA_TYPE_PAGINATED) + { } - public function getFilterDataType(): string { return $this->dataType; } - - /** - * @param Fluent|QueryBuilder|Collection|Selection|ICollection $dataSource - */ - public function processDataSource($dataSource): void + public function processDataSource(Fluent|QueryBuilder|Collection|Selection|ICollection $dataSource): void { if ($dataSource instanceof Fluent) { $connection = $dataSource->getConnection(); @@ -65,11 +37,11 @@ public function processDataSource($dataSource): void } if ($dataSource instanceof QueryBuilder) { - $column = Strings::contains($this->column, '.') + $column = str_contains($this->column, '.') ? $this->column : current($dataSource->getRootAliases()) . '.' . $this->column; - $this->result = $dataSource + $this->result = (int) $dataSource ->select(sprintf('SUM(%s)', $column)) ->setMaxResults(1) ->setFirstResult(0) @@ -85,17 +57,13 @@ public function processDataSource($dataSource): void }); } - if ( $dataSource instanceof DbalCollection) { - foreach( $dataSource->fetchAll() as $item ) - $this->result += $item->getValue( $this->column ); + if ($dataSource instanceof DbalCollection) { + foreach ($dataSource->fetchAll() as $item) + $this->result += $item->getValue($this->column); } } - - /** - * @return mixed - */ - public function renderResult() + public function renderResult(): mixed { $result = $this->result; @@ -106,7 +74,6 @@ public function renderResult() return $result; } - /** * @return static */ @@ -116,4 +83,5 @@ public function setRenderer(?callable $callback = null): self return $this; } + } diff --git a/src/AggregationFunction/IAggregatable.php b/src/AggregationFunction/IAggregatable.php index 79b8c6382..dcbf73bf4 100644 --- a/src/AggregationFunction/IAggregatable.php +++ b/src/AggregationFunction/IAggregatable.php @@ -1,11 +1,10 @@ -hasColumnsSummary()) { - throw new DataGridException('You can use either ColumnsSummary or AggregationFunctions'); + throw new DatagridException('You can use either ColumnsSummary or AggregationFunctions'); } if (!$this->dataModel instanceof DataModel) { - throw new DataGridException('You have to set a data source first.'); + throw new DatagridException('You have to set a data source first.'); } if (isset($this->aggregationFunctions[$key])) { - throw new DataGridException('There is already a AggregationFunction defined on column ' . $key); + throw new DatagridException('There is already a AggregationFunction defined on column ' . $key); } if ($this->multipleAggregationFunction instanceof IMultipleAggregationFunction) { - throw new DataGridException('You can not use both AggregationFunctions and MultipleAggregationFunction'); + throw new DatagridException('You can not use both AggregationFunctions and MultipleAggregationFunction'); } $this->aggregationFunctions[$key] = $aggregationFunction; @@ -51,21 +44,20 @@ public function addAggregationFunction( return $this; } - /** * @return static - * @throws DataGridException + * @throws DatagridException */ public function setMultipleAggregationFunction( IMultipleAggregationFunction $multipleAggregationFunction ): self { if ($this->hasColumnsSummary()) { - throw new DataGridException('You can use either ColumnsSummary or AggregationFunctions'); + throw new DatagridException('You can use either ColumnsSummary or AggregationFunctions'); } if ($this->aggregationFunctions !== []) { - throw new DataGridException('You can not use both AggregationFunctions and MultipleAggregationFunction'); + throw new DatagridException('You can not use both AggregationFunctions and MultipleAggregationFunction'); } $this->multipleAggregationFunction = $multipleAggregationFunction; @@ -73,9 +65,8 @@ public function setMultipleAggregationFunction( return $this; } - /** - * @throws DataGridException + * @throws DatagridException */ public function beforeDataModelFilter(IDataSource $dataSource): void { @@ -84,7 +75,7 @@ public function beforeDataModelFilter(IDataSource $dataSource): void } if (!$dataSource instanceof IAggregatable) { - throw new DataGridException('Used DataSource has to implement IAggregatable for aggegations to work'); + throw new DatagridException('Used DataSource has to implement IAggregatable for aggegations to work'); } if ($this->multipleAggregationFunction !== null) { @@ -104,9 +95,8 @@ public function beforeDataModelFilter(IDataSource $dataSource): void } } - /** - * @throws DataGridException + * @throws DatagridException */ public function afterDataModelFilter(IDataSource $dataSource): void { @@ -115,7 +105,7 @@ public function afterDataModelFilter(IDataSource $dataSource): void } if (!$dataSource instanceof IAggregatable) { - throw new DataGridException('Used DataSource has to implement IAggregatable for aggegations to work'); + throw new DatagridException('Used DataSource has to implement IAggregatable for aggegations to work'); } if ($this->multipleAggregationFunction !== null) { @@ -133,9 +123,8 @@ public function afterDataModelFilter(IDataSource $dataSource): void } } - /** - * @throws DataGridException + * @throws DatagridException */ public function afterDataModelPaginated(IDataSource $dataSource): void { @@ -144,7 +133,7 @@ public function afterDataModelPaginated(IDataSource $dataSource): void } if (!$dataSource instanceof IAggregatable) { - throw new DataGridException('Used DataSource has to implement IAggregatable for aggegations to work'); + throw new DatagridException('Used DataSource has to implement IAggregatable for aggegations to work'); } if ($this->multipleAggregationFunction !== null) { @@ -162,13 +151,11 @@ public function afterDataModelPaginated(IDataSource $dataSource): void } } - public function hasSomeAggregationFunction(): bool { return $this->aggregationFunctions !== [] || $this->multipleAggregationFunction !== null; } - /** * @return array */ @@ -177,9 +164,9 @@ public function getAggregationFunctions(): array return $this->aggregationFunctions; } - public function getMultipleAggregationFunction(): ?IMultipleAggregationFunction { return $this->multipleAggregationFunction; } + } diff --git a/src/Column/Action.php b/src/Column/Action.php old mode 100644 new mode 100755 index 6107c5e55..42743bc9e --- a/src/Column/Action.php +++ b/src/Column/Action.php @@ -1,21 +1,19 @@ -href = $href; - $this->params = $params; $this->class = sprintf('btn btn-xs %s', $grid::$btnSecondaryClass); } - - /** - * @return mixed - */ - public function render(Row $row) + public function render(Row $row): mixed { if (!$this->shouldBeRendered($row)) { return null; @@ -108,10 +68,11 @@ public function render(Row $row) try { return $this->useRenderer($row); - } catch (DataGridColumnRendererException $e) { + } catch (DatagridColumnRendererException) { + // No need to worry. } - $link = $this->createLink( + $link = $this->getCustomHref($row) ?? $this->createLink( $this->grid, $this->href, $this->getItemParams($row, $this->params) + $this->parameters @@ -156,7 +117,6 @@ public function render(Row $row) return $a; } - /** * @return static */ @@ -167,13 +127,11 @@ public function addParameters(array $parameters): self return $this; } - /** - * @param string|callable $title * @return static - * @throws DataGridException + * @throws DatagridException */ - public function setTitle($title): self + public function setTitle(string|callable $title): self { $this->checkPropertyStringOrCallable($title, 'title'); @@ -182,9 +140,8 @@ public function setTitle($title): self return $this; } - /** - * @throws DataGridException + * @throws DatagridException */ public function getTitle(Row $row): ?string { @@ -194,13 +151,42 @@ public function getTitle(Row $row): ?string return $this->getPropertyStringOrCallableGetString($row, $this->title, 'title'); } + /** + * @return static + * @throws DatagridException + */ + public function setCustomHref(string|callable $customHref): self + { + $this->checkPropertyStringOrCallable($customHref, 'customHref'); + + $this->customHref = $customHref; + + return $this; + } + + /** + * @throws DatagridException + */ + public function getCustomHref(Row $row): ?string + { + if (!isset($this->customHref)) { + return null; + } + + /** + * If user callback was used for setting action customHref, it has to return string + */ + return $this->getPropertyStringOrCallableGetString($row, $this->customHref, 'customHref'); + } /** + * Set attribute class + * * @param string|callable $class * @return static - * @throws DataGridException + * @throws DatagridException */ - public function setClass($class): self + public function setClass(null|string|callable $class): self { $this->checkPropertyStringOrCallable($class, 'class'); @@ -209,9 +195,8 @@ public function setClass($class): self return $this; } - /** - * @throws DataGridException + * @throws DatagridException */ public function getClass(Row $row): ?string { @@ -221,13 +206,11 @@ public function getClass(Row $row): ?string return $this->getPropertyStringOrCallableGetString($row, $this->class, 'class'); } - /** - * @param string|callable $icon * @return static - * @throws DataGridException + * @throws DatagridException */ - public function setIcon($icon): self + public function setIcon(string|callable $icon): self { $this->checkPropertyStringOrCallable($icon, 'icon'); @@ -236,9 +219,8 @@ public function setIcon($icon): self return $this; } - /** - * @throws DataGridException + * @throws DatagridException */ public function getIcon(Row $row): ?string { @@ -248,7 +230,6 @@ public function getIcon(Row $row): ?string return $this->getPropertyStringOrCallableGetString($row, $this->icon, 'icon'); } - /** * @return static */ @@ -259,9 +240,8 @@ public function setConfirmation(IConfirmation $confirmation): self return $this; } - /** - * @throws DataGridException + * @throws DatagridException */ public function getConfirmationDialog(Row $row): ?string { @@ -287,22 +267,19 @@ public function getConfirmationDialog(Row $row): ?string ); } - throw new DataGridException('Unsupported confirmation'); + throw new DatagridException('Unsupported confirmation'); } - /** - * @param mixed $value * @return static */ - public function setDataAttribute(string $key, $value): self + public function setDataAttribute(string $key, mixed $value): self { $this->dataAttributes[$key] = $value; return $this; } - /** * @return static */ @@ -313,14 +290,12 @@ public function addAttributes(array $attrs): self return $this; } - /** - * @param string|callable|null $property - * @throws DataGridException + * @throws DatagridException */ public function getPropertyStringOrCallableGetString( Row $row, - $property, + string|callable|null $property, string $name ): ?string { @@ -332,7 +307,7 @@ public function getPropertyStringOrCallableGetString( $value = call_user_func($property, $row->getItem()); if (!is_string($value)) { - throw new DataGridException("Action {$name} callback has to return a string"); + throw new DatagridException(sprintf('Action %s callback has to return a string', $name)); } return $value; @@ -341,13 +316,11 @@ public function getPropertyStringOrCallableGetString( return $property; } - public function isOpenInNewTab(): bool { return $this->openInNewTab; } - /** * @return static */ @@ -358,23 +331,21 @@ public function setOpenInNewTab(bool $openInNewTab = true): self return $this; } - /** - * @param mixed $property - * @throws DataGridException + * @throws DatagridException */ - protected function checkPropertyStringOrCallable($property, string $name): void + protected function checkPropertyStringOrCallable(mixed $property, string $name): void { if (!is_string($property) && !is_callable($property) && $property !== null) { - throw new DataGridException( + throw new DatagridException( sprintf('Action %s has to be either string or a callback returning string', $name) ); } } - protected function translate(string $message): string { return $this->grid->getTranslator()->translate($message); } + } diff --git a/src/Column/Action/Confirmation/CallbackConfirmation.php b/src/Column/Action/Confirmation/CallbackConfirmation.php index 911dcb3a4..5a6ef2706 100644 --- a/src/Column/Action/Confirmation/CallbackConfirmation.php +++ b/src/Column/Action/Confirmation/CallbackConfirmation.php @@ -1,26 +1,21 @@ -callback = $callback; } - public function getCallback(): callable { return $this->callback; } + } diff --git a/src/Column/Action/Confirmation/IConfirmation.php b/src/Column/Action/Confirmation/IConfirmation.php index 942f34346..d6776f823 100644 --- a/src/Column/Action/Confirmation/IConfirmation.php +++ b/src/Column/Action/Confirmation/IConfirmation.php @@ -1,8 +1,6 @@ -question = $question; - $this->placeholderName = $placeholderName; } - public function getQuestion(): string { return $this->question; } - public function getPlaceholderName(): ?string { return $this->placeholderName; } + } diff --git a/src/Column/ActionCallback.php b/src/Column/ActionCallback.php index 68b339f2e..94ecc48d3 100644 --- a/src/Column/ActionCallback.php +++ b/src/Column/ActionCallback.php @@ -1,11 +1,9 @@ -href is a identifier of user callback @@ -33,4 +28,5 @@ protected function createLink(DataGrid $grid, string $href, array $params): stri return $this->grid->link('actionCallback!', $params); } + } diff --git a/src/Column/Column.php b/src/Column/Column.php index e7e4f7efb..d46ef0661 100644 --- a/src/Column/Column.php +++ b/src/Column/Column.php @@ -1,14 +1,12 @@ - 'form-control']]; + protected array $editableElement = ['textarea', ['class' => 'form-control']]; - /** - * @var bool - */ - protected $defaultHide = false; + protected bool $defaultHide = false; - /** - * @var array|Html[]|null[] - */ - protected $elementCache = ['td' => null, 'th' => null]; + /** @var array|Html[]|null[] */ + protected array $elementCache = ['td' => null, 'th' => null]; - /** - * @var callable|null - */ + /** @var callable|null */ protected $editableValueCallback = null; - /** - * @return mixed - */ - public function render(Row $row) + public function render(Row $row): mixed { try { return $this->useRenderer($row); - } catch (DataGridColumnRendererException $e) { + } catch (DatagridColumnRendererException) { /** * Do not use renderer */ @@ -121,7 +73,6 @@ public function render(Row $row) return $this->getColumnValue($row); } - /** * Should be column values escaped in latte? * @@ -134,13 +85,11 @@ public function setTemplateEscaping(bool $templateEscaping = true): self return $this; } - public function isTemplateEscaped(): bool { return $this->templateEscaping; } - /** * Should be column header escaped in latte? * @@ -153,20 +102,17 @@ public function setHeaderEscaping(bool $headerEscaping = false): self return $this; } - public function isHeaderEscaped(): bool { return $this->headerEscaping; } - /** * Set column sortable or not * - * @param bool|string $sortable * @return static */ - public function setSortable($sortable = true): self + public function setSortable(bool|string $sortable = true): self { $this->sortable = is_string($sortable) ? $sortable @@ -175,7 +121,6 @@ public function setSortable($sortable = true): self return $this; } - /** * Tell whether column is sortable */ @@ -188,7 +133,6 @@ public function isSortable(): bool return $this->sortable !== ''; } - /** * Set column translatable or not * @@ -201,7 +145,6 @@ public function setTranslatableHeader(bool $translatableHeader = true): self return $this; } - /** * Tell wheter column is translatable */ @@ -210,7 +153,6 @@ public function isTranslatableHeader(): bool return $this->translatableHeader; } - /** * Shoud be the pagination reseted after sorting? * @@ -223,7 +165,6 @@ public function setSortableResetPagination(bool $sortableResetPagination = true) return $this; } - /** * Do reset pagination after sorting? */ @@ -232,7 +173,6 @@ public function sortableResetPagination(): bool return $this->sortableResetPagination; } - /** * Set custom ORDER BY clause * @@ -245,7 +185,6 @@ public function setSortableCallback(callable $sortableCallback): self return $this; } - /** * Get custom ORDER BY clause */ @@ -254,7 +193,6 @@ public function getSortableCallback(): ?callable return $this->sortableCallback; } - public function getSortingColumn(): string { return is_string($this->sortable) @@ -262,28 +200,21 @@ public function getSortingColumn(): string : $this->column; } - public function getColumnName(): string { return $this->column; } - - /** - * @return mixed - */ - public function getColumnValue(Row $row) + public function getColumnValue(Row $row): mixed { return $row->getValue($this->column); } - public function getName(): string { return $this->name; } - /** * Column may have its own template * @@ -297,7 +228,6 @@ public function setTemplate(?string $template, array $templateVariables = []): s return $this; } - /** * Column can have variables that will be passed to custom template scope */ @@ -306,7 +236,6 @@ public function getTemplateVariables(): array return $this->templateVariables; } - /** * Tell whether column has its owntemplate */ @@ -315,7 +244,6 @@ public function hasTemplate(): bool return $this->template !== null; } - /** * Get column template path */ @@ -324,16 +252,14 @@ public function getTemplate(): ?string return $this->template; } - /** * Tell whether data source is sorted by this column */ public function isSortedBy(): bool { - return (bool) $this->sort; + return $this->sort !== ''; } - /** * Tell column his sorting options * @@ -346,7 +272,6 @@ public function setSort(string $sort): self return $this; } - /** * What sorting will be applied after next click? */ @@ -365,7 +290,6 @@ public function getSortNext(): array return [$this->key => 'ASC']; } - public function hasSortNext(): bool { foreach ($this->getSortNext() as $order) { @@ -375,13 +299,11 @@ public function hasSortNext(): bool return false; } - public function isSortAsc(): bool { return $this->sort === 'ASC'; } - /** * Set column alignment * @@ -394,7 +316,6 @@ public function setAlign(string $align): self return $this; } - /** * Has column some alignment? */ @@ -403,16 +324,14 @@ public function hasAlign(): bool return (bool) $this->align; } - /** * Get column alignment */ public function getAlign(): string { - return $this->align ?? 'left'; + return $this->align ?? 'start'; } - /** * @return static */ @@ -425,7 +344,6 @@ public function setFitContent(bool $fitContent = true): self return $this; } - /** * Set callback that will be called after inline editing * @@ -438,7 +356,6 @@ public function setEditableCallback(callable $editableCallback): self return $this; } - /** * Return callback that is used after inline editing */ @@ -447,7 +364,6 @@ public function getEditableCallback(): ?callable return $this->editableCallback; } - /** * Set inline editing just if condition is truthy * @@ -460,13 +376,11 @@ public function setEditableOnConditionCallback(callable $editableConditionCallba return $this; } - public function getEditableOnConditionCallback(): ?callable { return $this->editableConditionCallback; } - public function isEditable(?Row $row = null): bool { if ($this->getEditableCallback() !== null) { @@ -484,7 +398,6 @@ public function isEditable(?Row $row = null): bool return false; } - /** * Element is by default textarea, user can change that * @@ -497,7 +410,6 @@ public function setEditableInputType(string $elType, array $attrs = []): self return $this; } - /** * Change small inline edit input type to select * @@ -518,7 +430,6 @@ public function setEditableInputTypeSelect(array $options = [], array $attrs = [ return $this->setEditableInputType('select', $attrs); } - /** * @return static */ @@ -529,19 +440,16 @@ public function setEditableValueCallback(callable $editableValueCallback): self return $this; } - public function getEditableValueCallback(): ?callable { return $this->editableValueCallback; } - public function getEditableInputType(): array { return $this->editableElement; } - /** * Set attributes for both th and td element * @@ -555,7 +463,6 @@ public function addCellAttributes(array $attrs): self return $this; } - /** * Get th/td column element */ @@ -568,7 +475,6 @@ public function getElementPrototype(string $tag): Html return $this->elementCache[$tag] = Html::el($tag); } - /** * Method called from datagrid template, set appropriate classes and another attributes */ @@ -597,7 +503,7 @@ public function getElementForRender(string $tag, string $key, ?Row $row = null): $el->data('datagrid-editable-url', $link); $el->data('datagrid-editable-type', $this->editableElement[0]); - $el->data('datagrid-editable-attrs', json_encode($this->editableElement[1])); + $el->data('datagrid-editable-attrs', json_encode($this->editableElement[1], JSON_THROW_ON_ERROR)); if ($this->getEditableValueCallback() !== null) { $el->data( @@ -610,7 +516,6 @@ public function getElementForRender(string $tag, string $key, ?Row $row = null): return $el; } - /** * @return static */ @@ -625,13 +530,11 @@ public function setDefaultHide(bool $defaultHide = true): self return $this; } - public function getDefaultHide(): bool { return $this->defaultHide; } - public function getColumn(): string { return $this->column; @@ -647,7 +550,6 @@ public function setReplacement(array $replacements): self return $this; } - /** * Get row item params (E.g. action may be called id => $item->id, name => $item->name, ...) */ @@ -661,4 +563,5 @@ protected function getItemParams(Row $row, array $paramsList): array return $return; } + } diff --git a/src/Column/ColumnDateTime.php b/src/Column/ColumnDateTime.php index 212846629..cbc5ffc97 100644 --- a/src/Column/ColumnDateTime.php +++ b/src/Column/ColumnDateTime.php @@ -1,26 +1,18 @@ -format($this->format); - } catch (DataGridDateTimeHelperException $e) { + } catch (DatagridDateTimeHelperException) { /** * Otherwise just return raw string */ @@ -45,7 +37,6 @@ public function getColumnValue(Row $row): string return $value->format($this->format); } - /** * @return static */ @@ -55,4 +46,5 @@ public function setFormat(string $format): self return $this; } + } diff --git a/src/Column/ColumnLink.php b/src/Column/ColumnLink.php index 3e3ccd045..7be353cfe 100644 --- a/src/Column/ColumnLink.php +++ b/src/Column/ColumnLink.php @@ -1,85 +1,47 @@ -href = $href; - $this->params = $params; } - - /** - * @return mixed - */ - public function render(Row $row) + public function render(Row $row): mixed { /** * Renderer function may be used */ try { return $this->useRenderer($row); - } catch (DataGridColumnRendererException $e) { + } catch (DatagridColumnRendererException) { /** * Do not use renderer */ @@ -120,7 +82,7 @@ public function render(Row $row) if ($this->icon !== null) { $a->addHtml( - Html::el('span')->setAttribute('class', DataGrid::$iconPrefix . $this->icon) + Html::el('span')->setAttribute('class', Datagrid::$iconPrefix . $this->icon) ); if (strlen($value) > 0) { @@ -137,7 +99,6 @@ public function render(Row $row) return $element; } - /** * @return static */ @@ -148,7 +109,6 @@ public function addParameters(array $parameters): self return $this; } - /** * @return static */ @@ -159,19 +119,16 @@ public function setIcon(?string $icon = null): self return $this; } - /** - * @param mixed $value * @return static */ - public function setDataAttribute(string $key, $value): self + public function setDataAttribute(string $key, mixed $value): self { $this->dataAttributes[$key] = $value; return $this; } - /** * @return static */ @@ -182,13 +139,11 @@ public function setTitle(string $title): self return $this; } - public function getTitle(): ?string { return $this->title; } - /** * @return static */ @@ -199,19 +154,16 @@ public function setClass(?string $class): self return $this; } - public function getClass(): ?string { return $this->class; } - public function isOpenInNewTab(): bool { return $this->openInNewTab; } - /** * @return static */ @@ -221,4 +173,5 @@ public function setOpenInNewTab(bool $openInNewTab = true): self return $this; } + } diff --git a/src/Column/ColumnNumber.php b/src/Column/ColumnNumber.php index c2b6a9611..64e6ff088 100644 --- a/src/Column/ColumnNumber.php +++ b/src/Column/ColumnNumber.php @@ -1,32 +1,21 @@ -numberFormat[2], ]; } + } diff --git a/src/Column/ColumnStatus.php b/src/Column/ColumnStatus.php index d013e33fd..9a92a80e0 100644 --- a/src/Column/ColumnStatus.php +++ b/src/Column/ColumnStatus.php @@ -1,16 +1,14 @@ -setTemplate(__DIR__ . '/../templates/column_status.latte'); } - public function getKey(): string { return $this->key; } - public function getOptions(): array { return $this->options; } - /** - * @param mixed $value - * @throws DataGridColumnStatusException + * @throws DatagridColumnStatusException */ - public function getOption($value): Option + public function getOption(mixed $value): Option { foreach ($this->options as $option) { if ($option->getValue() === $value) { @@ -77,16 +62,14 @@ public function getOption($value): Option } } - throw new DataGridColumnStatusException("Option [$value] does not exist"); + throw new DatagridColumnStatusException(sprintf('Option [%s] does not exist', $value)); } - public function getColumn(): string { return $this->column; } - /** * Find selected option for current item/row */ @@ -101,15 +84,13 @@ public function getCurrentOption(Row $row): ?Option return null; } - /** - * @param mixed $value - * @throws DataGridColumnStatusException + * @throws DatagridColumnStatusException */ - public function addOption($value, string $text): Option + public function addOption(mixed $value, string $text): Option { if (!is_scalar($value)) { - throw new DataGridColumnStatusException('Option value has to be scalar'); + throw new DatagridColumnStatusException('Option value has to be scalar'); } $option = new Option($this->grid, $this, $value, $text); @@ -119,10 +100,10 @@ public function addOption($value, string $text): Option return $option; } - /** * Set all options at once * + * @param string[] $options * @return static */ public function setOptions(array $options): self @@ -134,11 +115,7 @@ public function setOptions(array $options): self return $this; } - - /** - * @param mixed $value - */ - public function removeOption($value): void + public function removeOption(mixed $value): void { foreach ($this->options as $key => $option) { if ($option->getValue() === $value) { @@ -147,7 +124,6 @@ public function removeOption($value): void } } - /** * Column can have variables that will be passed to custom template scope */ @@ -161,11 +137,11 @@ public function getTemplateVariables(): array ]); } - public function setReplacement(array $replacements): Column { - throw new DataGridColumnStatusException( + throw new DatagridColumnStatusException( 'Cannot set replacement for Column Status. For status texts replacement use ->setOptions($replacements)' ); } + } diff --git a/src/Column/ColumnText.php b/src/Column/ColumnText.php index 2d34e188c..e6b8b7473 100644 --- a/src/Column/ColumnText.php +++ b/src/Column/ColumnText.php @@ -1,8 +1,6 @@ -grid = $grid; - $this->key = $key; - $this->column = $column; - $this->name = $name; } - - /** - * @param string|array|null $columns - */ - public function setFilterText($columns = null): FilterText + public function setFilterText(string|array|null $columns = null): FilterText { if ($columns === null) { $columns = [$this->column]; @@ -66,55 +30,51 @@ public function setFilterText($columns = null): FilterText return $this->grid->addFilterText($this->key, $this->name, $columns); } - public function setFilterSelect( array $options, ?string $column = null ): FilterSelect { - $column = $column ?? $this->column; + $column ??= $this->column; return $this->grid->addFilterSelect($this->key, $this->name, $options, $column); } - public function setFilterMultiSelect( array $options, ?string $column = null ): FilterMultiSelect { - $column = $column ?? $this->column; + $column ??= $this->column; return $this->grid->addFilterMultiSelect($this->key, $this->name, $options, $column); } - public function setFilterDate(?string $column = null): FilterDate { - $column = $column ?? $this->column; + $column ??= $this->column; return $this->grid->addFilterDate($this->key, $this->name, $column); } - public function setFilterRange( ?string $column = null, string $nameSecond = '-' ): FilterRange { - $column = $column ?? $this->column; + $column ??= $this->column; return $this->grid->addFilterRange($this->key, $this->name, $column, $nameSecond); } - public function setFilterDateRange( ?string $column = null, string $nameSecond = '-' ): FilterDateRange { - $column = $column ?? $this->column; + $column ??= $this->column; return $this->grid->addFilterDateRange($this->key, $this->name, $column, $nameSecond); } + } diff --git a/src/Column/ItemDetail.php b/src/Column/ItemDetail.php index 563009b21..6259fdbb6 100644 --- a/src/Column/ItemDetail.php +++ b/src/Column/ItemDetail.php @@ -1,21 +1,19 @@ -grid = $grid; - $this->primaryWhereColumn = $primaryWhereColumn; - - $this->title = 'ublaboo_datagrid.show'; + $this->title = 'contributte_datagrid.show'; $this->class = sprintf('btn btn-xs %s ajax', $grid::$btnSecondaryClass); $this->icon = 'eye'; } - /** * Render row item detail button */ @@ -98,22 +68,17 @@ public function renderButton(Row $row): Html ); } - if ($this->class !== null) { + if ($this->class !== '') { $a->setAttribute('class', $this->class); } return $a; } - - /** - * @param mixed $item - * @return mixed - */ - public function render($item) + public function render(mixed $item): mixed { if ($this->getType() === 'block') { - throw new DataGridItemDetailException('ItemDetail is set to render as block, but block #detail is not defined'); + throw new DatagridItemDetailException('ItemDetail is set to render as block, but block #detail is not defined'); } if ($this->getRenderer() === null) { @@ -123,13 +88,11 @@ public function render($item) return call_user_func($this->getRenderer(), $item); } - public function getPrimaryWhereColumn(): string { return $this->primaryWhereColumn; } - /** * Set item detail type * @@ -142,7 +105,6 @@ public function setType(string $type): self return $this; } - /** * Get item detail type */ @@ -151,7 +113,6 @@ public function getType(): ?string return $this->type; } - /** * Set item detail template * @@ -164,7 +125,6 @@ public function setTemplate(string $template): self return $this; } - /** * Get item detail template */ @@ -173,7 +133,6 @@ public function getTemplate(): ?string return $this->template; } - /** * @return static */ @@ -184,13 +143,11 @@ public function setRenderer(callable $renderer): self return $this; } - public function getRenderer(): ?callable { return $this->renderer; } - /** * @return static */ @@ -201,13 +158,11 @@ public function setForm(ItemDetailForm $form): self return $this; } - public function getForm(): ?ItemDetailForm { return $this->form; } - /** * @return static */ @@ -218,7 +173,6 @@ public function setTemplateParameters(array $templateParameters): self return $this; } - public function getTemplateVariables(): array { return $this->templateParameters; diff --git a/src/Column/MultiAction.php b/src/Column/MultiAction.php index 0770e0db5..1439fb59f 100644 --- a/src/Column/MultiAction.php +++ b/src/Column/MultiAction.php @@ -1,20 +1,18 @@ -setTemplate(__DIR__ . '/../templates/column_multi_action.latte'); } - public function renderButton(): Html { $button = Html::el('button') ->setAttribute('type', 'button') - ->data('toggle', 'dropdown'); + ->data('bs-toggle', 'dropdown'); $this->tryAddIcon($button, $this->getIcon(), $this->getName()); @@ -85,7 +70,6 @@ public function renderButton(): Html return $button; } - /** * @return static */ @@ -97,12 +81,12 @@ public function addAction( ): self { if (isset($this->actions[$key])) { - throw new DataGridException( + throw new DatagridException( sprintf('There is already action at key [%s] defined for MultiAction.', $key) ); } - $href = $href ?? $key; + $href ??= $key; if ($params === null) { $params = [$this->grid->getPrimaryKey()]; @@ -117,7 +101,6 @@ public function addAction( return $this; } - /** * @return array */ @@ -126,11 +109,10 @@ public function getActions(): array return $this->actions; } - public function getAction(string $key): Action { if (!isset($this->actions[$key])) { - throw new DataGridException( + throw new DatagridException( sprintf('There is no action at key [%s] defined for MultiAction.', $key) ); } @@ -138,7 +120,6 @@ public function getAction(string $key): Action return $this->actions[$key]; } - /** * Column can have variables that will be passed to custom template scope */ @@ -149,7 +130,6 @@ public function getTemplateVariables(): array ]); } - public function setRowCondition( string $actionKey, callable $rowCondition @@ -158,7 +138,6 @@ public function setRowCondition( $this->rowConditions[$actionKey] = $rowCondition; } - public function testRowCondition(string $actionKey, Row $row): bool { if (!isset($this->rowConditions[$actionKey])) { @@ -167,4 +146,5 @@ public function testRowCondition(string $actionKey, Row $row): bool return (bool) call_user_func($this->rowConditions[$actionKey], $row->getItem()); } + } diff --git a/src/Column/Renderer.php b/src/Column/Renderer.php index 70b168ed6..22c6c472f 100644 --- a/src/Column/Renderer.php +++ b/src/Column/Renderer.php @@ -1,23 +1,16 @@ -conditionCallback = $conditionCallback; } - /** * Get custom renderer callback */ @@ -36,7 +28,6 @@ public function getCallback(): callable return $this->callback; } - /** * Get custom renderer condition callback */ @@ -44,4 +35,5 @@ public function getConditionCallback(): ?callable { return $this->conditionCallback; } + } diff --git a/src/ColumnsSummary.php b/src/ColumnsSummary.php index efa9e69a7..c173d84c6 100644 --- a/src/ColumnsSummary.php +++ b/src/ColumnsSummary.php @@ -1,58 +1,37 @@ -summary = array_fill_keys(array_values($columns), 0); - $this->datagrid = $datagrid; $this->rowCallback = $rowCallback; foreach (array_keys($this->summary) as $key) { @@ -67,7 +46,6 @@ public function __construct( } } - public function add(Row $row): void { foreach (array_keys($this->summary) as $key) { @@ -78,12 +56,12 @@ public function add(Row $row): void } } - public function render(string $key): ?string { try { return $this->useRenderer($key); - } catch (DataGridColumnRendererException $e) { + } catch (DatagridColumnRendererException) { + // No need to worry. } if (!isset($this->summary[$key])) { @@ -98,11 +76,7 @@ public function render(string $key): ?string ); } - - /** - * @return mixed - */ - public function useRenderer(string $key) + public function useRenderer(string $key): mixed { if (!isset($this->summary[$key])) { return null; @@ -111,19 +85,17 @@ public function useRenderer(string $key) $renderer = $this->getRenderer(); if ($renderer === null) { - throw new DataGridColumnRendererException; + throw new DatagridColumnRendererException(); } return call_user_func_array($renderer->getCallback(), [$this->summary[$key], $key]); } - public function getRenderer(): ?Renderer { return $this->renderer; } - /** * @return static */ @@ -134,7 +106,6 @@ public function setRenderer(callable $renderer): self return $this; } - /** * @return static */ @@ -150,7 +121,6 @@ public function setFormat( return $this; } - public function someColumnsExist(array $columns): bool { foreach (array_keys($columns) as $key) { @@ -162,7 +132,6 @@ public function someColumnsExist(array $columns): bool return false; } - /** * @return static */ @@ -173,19 +142,15 @@ public function setPositionTop(bool $top = true): self return $this; } - public function getPositionTop(): bool { return $this->positionTop; } - /** * Get value from column using Row::getValue() or custom callback - * - * @return mixed */ - private function getValue(Row $row, Column $column) + private function getValue(Row $row, Column $column): mixed { if ($this->rowCallback === null) { return $row->getValue($column->getColumn()); @@ -193,4 +158,5 @@ private function getValue(Row $row, Column $column) return call_user_func_array($this->rowCallback, [$row->getItem(), $column->getColumn()]); } + } diff --git a/src/Components/DataGridPaginator/DataGridPaginator.php b/src/Components/DatagridPaginator/DatagridPaginator.php similarity index 72% rename from src/Components/DataGridPaginator/DataGridPaginator.php rename to src/Components/DatagridPaginator/DatagridPaginator.php index ee4c5c39d..f01265105 100644 --- a/src/Components/DataGridPaginator/DataGridPaginator.php +++ b/src/Components/DatagridPaginator/DatagridPaginator.php @@ -1,6 +1,4 @@ -translator = $translator; - $this->iconPrefix = $iconPrefix; - $this->btnSecondaryClass = $btnSecondaryClass; + public function __construct(private Translator $translator, private string $iconPrefix = 'fa fa-', private string $btnSecondaryClass = 'btn-default btn-secondary') + { } - public function setTemplateFile(string $templateFile): void { $this->templateFile = $templateFile; } - public function getTemplateFile(): string { return $this->templateFile ?? __DIR__ . '/templates/data_grid_paginator.latte'; } - public function getOriginalTemplateFile(): string { return __DIR__ . '/templates/data_grid_paginator.latte'; } - public function getPaginator(): Paginator { if ($this->paginator === null) { @@ -88,7 +54,6 @@ public function getPaginator(): Paginator return $this->paginator; } - public function render(): void { $paginator = $this->getPaginator(); @@ -101,10 +66,8 @@ public function render(): void $arr = range(max($paginator->firstPage, $page - 2), (int) min($paginator->lastPage, $page + 2)); /** - * Something to do with steps in tempale... + * Something to do with steps in template... * [Default $count = 3;] - * - * @var int */ $count = 1; @@ -141,7 +104,6 @@ public function render(): void $this->getTemplate()->render(); } - /** * Loads state informations. */ @@ -149,8 +111,9 @@ public function loadState(array $params): void { parent::loadState($params); - if ($this->getParent() instanceof DataGrid) { + if ($this->getParent() instanceof Datagrid) { $this->getPaginator()->page = $this->getParent()->page; } } + } diff --git a/src/Components/DataGridPaginator/templates/data_grid_paginator.latte b/src/Components/DatagridPaginator/templates/data_grid_paginator.latte similarity index 79% rename from src/Components/DataGridPaginator/templates/data_grid_paginator.latte rename to src/Components/DatagridPaginator/templates/data_grid_paginator.latte index cfcb4e1df..132676c85 100644 --- a/src/Components/DataGridPaginator/templates/data_grid_paginator.latte +++ b/src/Components/DatagridPaginator/templates/data_grid_paginator.latte @@ -12,7 +12,7 @@ {else} + {='contributte_datagrid.previous'|translate} {foreach $steps as $step} {if $step == $paginator->page} @@ -25,9 +25,9 @@ {/foreach} {if $paginator->isLast()} - {='ublaboo_datagrid.next'|translate} + {='contributte_datagrid.next'|translate} {else} -

diff --git a/src/CsvDataModel.php b/src/CsvDataModel.php index c53aca4dc..2e1fc971a 100644 --- a/src/CsvDataModel.php +++ b/src/CsvDataModel.php @@ -1,43 +1,20 @@ - - */ - protected $columns; - - /** - * @var ITranslator + * @param Column[] $columns */ - protected $translator; - - - public function __construct( - array $data, - array $columns, - ITranslator $translator - ) + public function __construct(protected array $data, protected array $columns, protected Translator $translator) { - $this->data = $data; - $this->columns = $columns; - $this->translator = $translator; } - /** * Get data with header and "body" */ @@ -56,7 +33,6 @@ public function getSimpleData(bool $includeHeader = true): array return $return; } - public function getHeader(): array { $header = []; @@ -68,13 +44,10 @@ public function getHeader(): array return $header; } - /** * Get item values saved into row - * - * @param mixed $item */ - public function getRow($item): array + public function getRow(mixed $item): array { $row = []; diff --git a/src/DataModel.php b/src/DataModel.php index d6a4394f0..db72f7c47 100644 --- a/src/DataModel.php +++ b/src/DataModel.php @@ -1,30 +1,33 @@ -getConnection()->getDriver(); - if ($driver instanceof Dibi\Drivers\OdbcDriver) { + if ($driver instanceof OdbcDriver) { $source = new DibiFluentMssqlDataSource($source, $primaryKey); - } elseif ($driver instanceof Dibi\Drivers\MsSqlDriver) { + } elseif ($driver instanceof MsSqlDriver) { $source = new DibiFluentMssqlDataSource($source, $primaryKey); - } elseif ($driver instanceof Dibi\Drivers\PostgreDriver) { + } elseif ($driver instanceof PostgreDriver) { $source = new DibiFluentPostgreDataSource($source, $primaryKey); - } elseif ($driver instanceof Dibi\Drivers\SqlsrvDriver) { + } elseif ($driver instanceof SqlsrvDriver) { $source = new DibiFluentMssqlDataSource($source, $primaryKey); } else { @@ -91,11 +76,7 @@ public function __construct($source, string $primaryKey) } elseif ($source instanceof Selection) { $driver = NetteDatabaseSelectionHelper::getDriver($source); - if ($driver instanceof NDBDrivers\MsSqlDriver || $driver instanceof NDBDrivers\SqlsrvDriver) { - $source = new NetteDatabaseTableMssqlDataSource($source, $primaryKey); - } else { - $source = new NetteDatabaseTableDataSource($source, $primaryKey); - } + $source = $driver instanceof NDBMsSqlDriver || $driver instanceof NDBSqlsrvDriver ? new NetteDatabaseTableMssqlDataSource($source, $primaryKey) : new NetteDatabaseTableDataSource($source, $primaryKey); } elseif ($source instanceof QueryBuilder) { $source = new DoctrineDataSource($source, $primaryKey); @@ -105,25 +86,23 @@ public function __construct($source, string $primaryKey) } elseif ($source instanceof ICollection) { $source = new NextrasDataSource($source, $primaryKey); - } else { - throw new DataGridWrongDataSourceException(sprintf( - 'DataGrid can not take [%s] as data source.', - is_object($source) ? get_class($source) : 'null' + } elseif (!($source instanceof IDataSource)) { + throw new DatagridWrongDataSourceException(sprintf( + 'Datagrid can not take [%s] as data source.', + is_object($source) ? $source::class : 'null' )); } $this->dataSource = $source; } - public function getDataSource(): IDataSource { return $this->dataSource; } - public function filterData( - ?DataGridPaginator $paginatorComponent, + ?DatagridPaginator $paginatorComponent, Sorting $sorting, array $filters ): iterable @@ -154,15 +133,12 @@ public function filterData( return $this->dataSource->sort($sorting)->getData(); } - - /** - * @return mixed - */ - public function filterRow(array $condition) + public function filterRow(array $condition): mixed { $this->onBeforeFilter($this->dataSource); $this->onAfterFilter($this->dataSource); return $this->dataSource->filterOne($condition)->getData(); } + } diff --git a/src/DataSource/ApiDataSource.php b/src/DataSource/ApiDataSource.php index 3626bbeeb..dc88d6fd3 100644 --- a/src/DataSource/ApiDataSource.php +++ b/src/DataSource/ApiDataSource.php @@ -1,79 +1,36 @@ -url = $url; - $this->queryParams = $queryParams; } - - // ******************************************************************************* - // * IDataSource implementation * - // ******************************************************************************* - - public function getCount(): int { return $this->getResponse(['count' => '']); } - /** * {@inheritDoc} */ @@ -89,7 +46,6 @@ public function getData(): array ]); } - /** * {@inheritDoc} */ @@ -122,7 +78,6 @@ public function filter(array $filters): void } } - /** * {@inheritDoc} */ @@ -134,7 +89,6 @@ public function filterOne(array $condition): IDataSource return $this; } - public function limit(int $offset, int $limit): IDataSource { $this->offset = $offset; @@ -143,7 +97,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - public function sort(Sorting $sorting): IDataSource { /** @@ -157,13 +110,10 @@ public function sort(Sorting $sorting): IDataSource return $this; } - /** * Get data of remote source - * - * @return mixed */ - protected function getResponse(array $params = []) + protected function getResponse(array $params = []): mixed { $queryString = http_build_query($params + $this->queryParams); $url = sprintf('%s?%s', $this->url, $queryString); @@ -174,6 +124,7 @@ protected function getResponse(array $params = []) throw new UnexpectedValueException(sprintf('Could not open URL %s', $url)); } - return json_decode($content); + return json_decode($content, null, 512, JSON_THROW_ON_ERROR); } + } diff --git a/src/DataSource/ArrayDataSource.php b/src/DataSource/ArrayDataSource.php index aecc8c17a..b92a60cce 100644 --- a/src/DataSource/ArrayDataSource.php +++ b/src/DataSource/ArrayDataSource.php @@ -1,58 +1,40 @@ -setData($dataSource); } - - // ******************************************************************************* - // * IDataSource implementation * - // ******************************************************************************* - - public function getCount(): int { - return sizeof($this->data); + return count($this->data); } - /** * {@inheritDoc} */ @@ -61,7 +43,6 @@ public function getData(): array return $this->data; } - /** * {@inheritDoc} */ @@ -76,16 +57,13 @@ public function filter(array $filters): void ); $this->setData($data); } else { - $data = array_filter($this->data, function ($row) use ($filter) { - return $this->applyFilter($row, $filter); - }); + $data = array_filter($this->data, fn ($row) => $this->applyFilter($row, $filter)); $this->setData($data); } } } } - /** * {@inheritDoc} */ @@ -106,7 +84,6 @@ public function filterOne(array $condition): IDataSource return $this; } - public function limit(int $offset, int $limit): IDataSource { $data = array_slice($this->data, $offset, $limit); @@ -115,7 +92,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - public function sort(Sorting $sorting): IDataSource { if (is_callable($sorting->getSortCallback())) { @@ -126,7 +102,7 @@ public function sort(Sorting $sorting): IDataSource ); if (!is_array($data)) { - throw new DataGridArrayDataSourceException('Sorting callback has to return array'); + throw new DatagridArrayDataSourceException('Sorting callback has to return array'); } $this->setData($data); @@ -167,12 +143,7 @@ public function sort(Sorting $sorting): IDataSource return $this; } - - /** - * @param mixed $row - * @return mixed - */ - protected function applyFilter($row, Filter $filter) + protected function applyFilter(mixed $row, Filter $filter): mixed { if (is_array($row) || $row instanceof ArrayAccess) { if ($filter instanceof FilterDate) { @@ -210,7 +181,7 @@ protected function applyFilter($row, Filter $filter) $row_value = strtolower(Strings::toAscii((string) $row[$column])); foreach ($words as $word) { - if (strpos($row_value, strtolower(Strings::toAscii($word))) !== false) { + if (str_contains($row_value, strtolower(Strings::toAscii($word)))) { return $row; } } @@ -220,11 +191,7 @@ protected function applyFilter($row, Filter $filter) return false; } - - /** - * @param mixed $row - */ - protected function applyFilterMultiSelect($row, FilterMultiSelect $filter): bool + protected function applyFilterMultiSelect(mixed $row, FilterMultiSelect $filter): bool { $condition = $filter->getCondition(); $values = $condition[$filter->getColumn()]; @@ -232,11 +199,7 @@ protected function applyFilterMultiSelect($row, FilterMultiSelect $filter): bool return in_array($row[$filter->getColumn()], $values, true); } - - /** - * @param mixed $row - */ - protected function applyFilterRange($row, FilterRange $filter): bool + protected function applyFilterRange(mixed $row, FilterRange $filter): bool { $condition = $filter->getCondition(); $values = $condition[$filter->getColumn()]; @@ -256,11 +219,7 @@ protected function applyFilterRange($row, FilterRange $filter): bool return true; } - - /** - * @param mixed $row - */ - protected function applyFilterDateRange($row, FilterDateRange $filter): bool + protected function applyFilterDateRange(mixed $row, FilterDateRange $filter): bool { $format = $filter->getPhpFormat(); $condition = $filter->getCondition(); @@ -277,7 +236,7 @@ protected function applyFilterDateRange($row, FilterDateRange $filter): bool */ try { $row_value = DateTimeHelper::tryConvertToDate($row_value); - } catch (DataGridDateTimeHelperException $e) { + } catch (DatagridDateTimeHelperException) { /** * Otherwise just return raw string */ @@ -300,7 +259,7 @@ protected function applyFilterDateRange($row, FilterDateRange $filter): bool */ try { $row_value = DateTimeHelper::tryConvertToDate($row_value); - } catch (DataGridDateTimeHelperException $e) { + } catch (DatagridDateTimeHelperException) { /** * Otherwise just return raw string */ @@ -316,13 +275,10 @@ protected function applyFilterDateRange($row, FilterDateRange $filter): bool return true; } - /** * Apply fitler date and tell whether row value matches or not - * - * @param mixed $row */ - protected function applyFilterDate($row, FilterDate $filter): bool + protected function applyFilterDate(mixed $row, FilterDate $filter): bool { $format = $filter->getPhpFormat(); $condition = $filter->getCondition(); @@ -338,7 +294,7 @@ protected function applyFilterDate($row, FilterDate $filter): bool */ try { $row_value = DateTimeHelper::tryConvertToDateTime($row_value); - } catch (DataGridDateTimeHelperException $e) { + } catch (DatagridDateTimeHelperException) { /** * Otherwise just return raw string */ @@ -352,7 +308,6 @@ protected function applyFilterDate($row, FilterDate $filter): bool return false; } - /** * Set the data */ @@ -362,4 +317,5 @@ private function setData(array $dataSource): IDataSource return $this; } + } diff --git a/src/DataSource/DibiFluentDataSource.php b/src/DataSource/DibiFluentDataSource.php index 81336b20a..ecce4212b 100755 --- a/src/DataSource/DibiFluentDataSource.php +++ b/src/DataSource/DibiFluentDataSource.php @@ -1,61 +1,37 @@ -dataSource = $dataSource; - $this->primaryKey = $primaryKey; } - - // ******************************************************************************* - // * IDataSource implementation * - // ******************************************************************************* - - public function getCount(): int { return $this->dataSource->count(); } - /** * {@inheritDoc} */ @@ -64,7 +40,6 @@ public function getData(): array return $this->data !== [] ? $this->data : $this->dataSource->fetchAll(); } - /** * {@inheritDoc} */ @@ -75,7 +50,6 @@ public function filterOne(array $condition): IDataSource return $this; } - public function limit(int $offset, int $limit): IDataSource { $this->dataSource->limit($limit)->offset($offset); @@ -85,7 +59,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - public function sort(Sorting $sorting): IDataSource { if (is_callable($sorting->getSortCallback())) { @@ -123,13 +96,11 @@ public function sort(Sorting $sorting): IDataSource return $this; } - public function processAggregation(IAggregationFunction $function): void { $function->processDataSource(clone $this->dataSource); } - protected function applyFilterDate(FilterDate $filter): void { $conditions = $filter->getCondition(); @@ -138,12 +109,11 @@ protected function applyFilterDate(FilterDate $filter): void $date = DateTimeHelper::tryConvertToDateTime($conditions[$filter->getColumn()], [$filter->getPhpFormat()]); $this->dataSource->where('DATE(%n) = ?', $filter->getColumn(), $date->format('Y-m-d')); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } - protected function applyFilterDateRange(FilterDateRange $filter): void { $conditions = $filter->getCondition(); @@ -157,7 +127,7 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $dateFrom->setTime(0, 0, 0); $this->dataSource->where('DATE(%n) >= ?', $filter->getColumn(), $dateFrom); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } @@ -168,13 +138,12 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $dateTo->setTime(23, 59, 59); $this->dataSource->where('DATE(%n) <= ?', $filter->getColumn(), $dateTo); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } } - protected function applyFilterRange(FilterRange $filter): void { $conditions = $filter->getCondition(); @@ -191,7 +160,6 @@ protected function applyFilterRange(FilterRange $filter): void } } - protected function applyFilterText(FilterText $filter): void { $condition = $filter->getCondition(); @@ -199,10 +167,10 @@ protected function applyFilterText(FilterText $filter): void $or = []; foreach ($condition as $column => $value) { - $column = Helpers::escape($driver, $column, \dibi::IDENTIFIER); + $column = Helpers::escape($driver, $column, dibi::IDENTIFIER); if ($filter->isExactSearch()) { - $this->dataSource->where("$column = %s", $value); + $this->dataSource->where(sprintf('%s = %%s', $column), $value); continue; } @@ -210,26 +178,25 @@ protected function applyFilterText(FilterText $filter): void $words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value); foreach ($words as $word) { - $or[] = ["$column LIKE %~like~", $word]; + $or[] = [sprintf('%s LIKE %%~like~', $column), $word]; } } - if (sizeof($or) > 1) { + if (count($or) > 1) { $this->dataSource->where('(%or)', $or); } else { $this->dataSource->where($or); } } - protected function applyFilterMultiSelect(FilterMultiSelect $filter): void { $condition = $filter->getCondition(); $values = $condition[$filter->getColumn()]; - if (sizeof($values) > 1) { + if ((is_countable($values) ? count($values) : 0) > 1) { $value1 = array_shift($values); - $length = sizeof($values); + $length = count($values); $i = 1; $this->dataSource->where('(%n = ?', $filter->getColumn(), $value1); @@ -248,18 +215,14 @@ protected function applyFilterMultiSelect(FilterMultiSelect $filter): void } } - protected function applyFilterSelect(FilterSelect $filter): void { $this->dataSource->where($filter->getCondition()); } - - /** - * {@inheritDoc} - */ - protected function getDataSource() + protected function getDataSource(): Fluent { return $this->dataSource; } + } diff --git a/src/DataSource/DibiFluentMssqlDataSource.php b/src/DataSource/DibiFluentMssqlDataSource.php index fe6b76145..641ddb719 100755 --- a/src/DataSource/DibiFluentMssqlDataSource.php +++ b/src/DataSource/DibiFluentMssqlDataSource.php @@ -1,39 +1,28 @@ -dataSource; @@ -42,7 +31,6 @@ public function getCount(): int return $clone->count(); } - /** * {@inheritDoc} */ @@ -53,7 +41,6 @@ public function filterOne(array $condition): IDataSource return $this; } - public function limit(int $offset, int $limit): IDataSource { $sql = (string) $this->dataSource; @@ -70,7 +57,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - protected function applyFilterDate(FilterDate $filter): void { $conditions = $filter->getCondition(); @@ -86,12 +72,11 @@ protected function applyFilterDate(FilterDate $filter): void $filter->getColumn(), $date->format('Ymd') ); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } - protected function applyFilterDateRange(FilterDateRange $filter): void { $conditions = $filter->getCondition(); @@ -116,7 +101,6 @@ protected function applyFilterDateRange(FilterDateRange $filter): void } } - protected function applyFilterText(FilterText $filter): void { $condition = $filter->getCondition(); @@ -124,21 +108,22 @@ protected function applyFilterText(FilterText $filter): void $or = []; foreach ($condition as $column => $value) { - $column = Helpers::escape($driver, $column, \dibi::IDENTIFIER); + $column = Helpers::escape($driver, $column, dibi::IDENTIFIER); if ($filter->isExactSearch()) { - $this->dataSource->where("$column = %s", $value); + $this->dataSource->where(sprintf('%s = %%s', $column), $value); continue; } - $or[] = "$column LIKE \"%$value%\""; + $or[] = sprintf('%s LIKE "%%%s%%"', $column, $value); } - if (sizeof($or) > 1) { + if (count($or) > 1) { $this->dataSource->where('(%or)', $or); } else { $this->dataSource->where($or); } } + } diff --git a/src/DataSource/DibiFluentPostgreDataSource.php b/src/DataSource/DibiFluentPostgreDataSource.php index 3c9f08074..3761e8062 100755 --- a/src/DataSource/DibiFluentPostgreDataSource.php +++ b/src/DataSource/DibiFluentPostgreDataSource.php @@ -1,10 +1,8 @@ -isExactSearch()) { - $this->dataSource->where("$column = %s", $value); + $this->dataSource->where(sprintf('%s = %%s', $column), $value); continue; } @@ -28,14 +26,15 @@ protected function applyFilterText(FilterText $filter): void $words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value); foreach ($words as $word) { - $or[] = "$column ILIKE " . $driver->escapeText('%' . $word . '%'); + $or[] = $column . ' ILIKE ' . $driver->escapeText('%' . $word . '%'); } } - if (sizeof($or) > 1) { + if (count($or) > 1) { $this->dataSource->where('(%or)', $or); } else { $this->dataSource->where($or); } } + } diff --git a/src/DataSource/DoctrineCollectionDataSource.php b/src/DataSource/DoctrineCollectionDataSource.php index 9f4806c19..170472398 100755 --- a/src/DataSource/DoctrineCollectionDataSource.php +++ b/src/DataSource/DoctrineCollectionDataSource.php @@ -1,68 +1,48 @@ -criteria = Criteria::create(); $this->dataSource = $collection; - $this->primaryKey = $primaryKey; } - - // ******************************************************************************* - // * IDataSource implementation * - // ******************************************************************************* - - public function getCount(): int { return $this->dataSource->matching($this->criteria)->count(); } - /** * {@inheritDoc} */ @@ -71,7 +51,6 @@ public function getData(): array return $this->dataSource->matching($this->criteria)->toArray(); } - /** * {@inheritDoc} */ @@ -89,7 +68,6 @@ public function filterOne(array $condition): IDataSource return $this; } - public function limit(int $offset, int $limit): IDataSource { $this->criteria->setFirstResult($offset)->setMaxResults($limit); @@ -97,7 +75,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - public function sort(Sorting $sorting): IDataSource { if (is_callable($sorting->getSortCallback())) { @@ -121,22 +98,19 @@ public function sort(Sorting $sorting): IDataSource return $this; } - public function processAggregation(IAggregationFunction $function): void { $function->processDataSource(clone $this->dataSource); } - /** - * {@inheritDoc} + * @return Collection&Selectable */ - public function getDataSource() + public function getDataSource(): mixed { return $this->dataSource; } - protected function applyFilterDate(FilterDate $filter): void { foreach ($filter->getCondition() as $value) { @@ -147,13 +121,12 @@ protected function applyFilterDate(FilterDate $filter): void $to = Criteria::expr()->lte($filter->getColumn(), $date->format('Y-m-d 23:59:59')); $this->criteria->andWhere($from)->andWhere($to); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } } - protected function applyFilterDateRange(FilterDateRange $filter): void { $conditions = $filter->getCondition(); @@ -161,34 +134,33 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $valueFrom = $values['from']; - if ((bool) $valueFrom) { + if ($valueFrom) { try { $dateFrom = DateTimeHelper::tryConvertToDateTime($valueFrom, [$filter->getPhpFormat()]); $dateFrom->setTime(0, 0, 0); $expr = Criteria::expr()->gte($filter->getColumn(), $dateFrom->format('Y-m-d H:i:s')); $this->criteria->andWhere($expr); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } $valueTo = $values['to']; - if ((bool) $valueTo) { + if ($valueTo) { try { $dateTo = DateTimeHelper::tryConvertToDateTime($valueTo, [$filter->getPhpFormat()]); $dateTo->setTime(23, 59, 59); $expr = Criteria::expr()->lte($filter->getColumn(), $dateTo->format('Y-m-d H:i:s')); $this->criteria->andWhere($expr); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } } - protected function applyFilterRange(FilterRange $filter): void { $conditions = $filter->getCondition(); @@ -207,7 +179,6 @@ protected function applyFilterRange(FilterRange $filter): void } } - protected function applyFilterText(FilterText $filter): void { $exprs = []; @@ -230,7 +201,6 @@ protected function applyFilterText(FilterText $filter): void $this->criteria->andWhere($expr); } - protected function applyFilterMultiSelect(FilterMultiSelect $filter): void { $values = $filter->getCondition()[$filter->getColumn()]; @@ -239,7 +209,6 @@ protected function applyFilterMultiSelect(FilterMultiSelect $filter): void $this->criteria->andWhere($expr); } - protected function applyFilterSelect(FilterSelect $filter): void { foreach ($filter->getCondition() as $column => $value) { diff --git a/src/DataSource/DoctrineDataSource.php b/src/DataSource/DoctrineDataSource.php index 7d01d222e..4249eda21 100755 --- a/src/DataSource/DoctrineDataSource.php +++ b/src/DataSource/DoctrineDataSource.php @@ -1,26 +1,24 @@ - */ + protected array $hints = []; - /** - * @var array - */ - protected $hints = []; - - - public function __construct(QueryBuilder $dataSource, string $primaryKey) + public function __construct(QueryBuilder $dataSource, protected string $primaryKey) { $this->placeholder = count($dataSource->getParameters()); $this->dataSource = $dataSource; - $this->primaryKey = $primaryKey; } - - /** - * @param mixed $value - */ - public function setQueryHint(string $name, $value): IDataSource + public function setQueryHint(string $name, mixed $value): IDataSource { $this->hints[$name] = $value; return $this; } - public function getQuery(): Query { $query = $this->dataSource->getQuery(); @@ -93,12 +68,6 @@ public function getQuery(): Query return $query; } - - // ******************************************************************************* - // * IDataSource implementation * - // ******************************************************************************* - - public function getCount(): int { if ($this->usePaginator()) { @@ -112,7 +81,6 @@ public function getCount(): int return (int) $dataSource->getQuery()->getSingleScalarResult(); } - /** * {@inheritDoc} */ @@ -131,7 +99,6 @@ public function getData(): array return $data; } - /** * {@inheritDoc} */ @@ -142,14 +109,13 @@ public function filterOne(array $condition): IDataSource foreach ($condition as $column => $value) { $c = $this->checkAliases($column); - $this->dataSource->andWhere("$c = :$p") + $this->dataSource->andWhere(sprintf('%s = :%s', $c, $p)) ->setParameter($p, $value); } return $this; } - public function limit(int $offset, int $limit): IDataSource { $this->dataSource->setFirstResult($offset)->setMaxResults($limit); @@ -157,7 +123,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - public function sort(Sorting $sorting): IDataSource { if (is_callable($sorting->getSortCallback())) { @@ -188,26 +153,23 @@ public function sort(Sorting $sorting): IDataSource return $this; } - /** * Get unique int value for each instance class (self) */ public function getPlaceholder(): string { - $return = 'param' . (string) ($this->placeholder + 1); + $return = 'param' . ($this->placeholder + 1); $this->placeholder++; return $return; } - public function processAggregation(IAggregationFunction $function): void { $function->processDataSource(clone $this->dataSource); } - protected function applyFilterDate(FilterDate $filter): void { $p1 = $this->getPlaceholder(); @@ -218,16 +180,15 @@ protected function applyFilterDate(FilterDate $filter): void $date = DateTimeHelper::tryConvertToDateTime($value, [$filter->getPhpFormat()]); $c = $this->checkAliases($column); - $this->dataSource->andWhere("$c >= :$p1 AND $c <= :$p2") + $this->dataSource->andWhere(sprintf('%s >= :%s AND %s <= :%s', $c, $p1, $c, $p2)) ->setParameter($p1, $date->format('Y-m-d 00:00:00')) ->setParameter($p2, $date->format('Y-m-d 23:59:59')); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } } - protected function applyFilterDateRange(FilterDateRange $filter): void { $conditions = $filter->getCondition(); @@ -243,11 +204,11 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $p = $this->getPlaceholder(); - $this->dataSource->andWhere("$c >= :$p")->setParameter( + $this->dataSource->andWhere(sprintf('%s >= :%s', $c, $p))->setParameter( $p, $dateFrom->format('Y-m-d H:i:s') ); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } @@ -259,17 +220,16 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $p = $this->getPlaceholder(); - $this->dataSource->andWhere("$c <= :$p")->setParameter( + $this->dataSource->andWhere(sprintf('%s <= :%s', $c, $p))->setParameter( $p, $dateTo->format('Y-m-d H:i:s') ); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } } - protected function applyFilterRange(FilterRange $filter): void { $conditions = $filter->getCondition(); @@ -280,16 +240,15 @@ protected function applyFilterRange(FilterRange $filter): void if (is_numeric($valueFrom)) { $p = $this->getPlaceholder(); - $this->dataSource->andWhere("$c >= :$p")->setParameter($p, $valueFrom); + $this->dataSource->andWhere(sprintf('%s >= :%s', $c, $p))->setParameter($p, $valueFrom); } if (is_numeric($valueTo)) { $p = $this->getPlaceholder(); - $this->dataSource->andWhere("$c <= :$p")->setParameter($p, $valueTo); + $this->dataSource->andWhere(sprintf('%s <= :%s', $c, $p))->setParameter($p, $valueTo); } } - protected function applyFilterText(FilterText $filter): void { $condition = $filter->getCondition(); @@ -313,7 +272,7 @@ protected function applyFilterText(FilterText $filter): void $exprs[] = $this->dataSource->expr()->like( $this->dataSource->expr()->lower($c), $this->dataSource->expr()->lower( - $this->dataSource->expr()->literal("%$word%") + $this->dataSource->expr()->literal('%' . $word . '%') ) ); } @@ -324,7 +283,6 @@ protected function applyFilterText(FilterText $filter): void $this->dataSource->andWhere($or); } - protected function applyFilterMultiSelect(FilterMultiSelect $filter): void { $c = $this->checkAliases($filter->getColumn()); @@ -336,7 +294,6 @@ protected function applyFilterMultiSelect(FilterMultiSelect $filter): void $this->dataSource->andWhere($expr)->setParameter($p, $values); } - protected function applyFilterSelect(FilterSelect $filter): void { $p = $this->getPlaceholder(); @@ -344,24 +301,19 @@ protected function applyFilterSelect(FilterSelect $filter): void foreach ($filter->getCondition() as $column => $value) { $c = $this->checkAliases($column); - $this->dataSource->andWhere("$c = :$p") + $this->dataSource->andWhere(sprintf('%s = :%s', $c, $p)) ->setParameter($p, $value); } } - - /** - * {@inheritDoc} - */ - protected function getDataSource() + protected function getDataSource(): QueryBuilder { return $this->dataSource; } - private function checkAliases(string $column): string { - if (Strings::contains($column, '.')) { + if (str_contains($column, '.')) { return $column; } @@ -369,7 +321,7 @@ private function checkAliases(string $column): string $rootAlias = $this->dataSource->getRootAliases(); if ($rootAlias === []) { - throw new DataGridException('No root alias given from datasource'); + throw new DatagridException('No root alias given from datasource'); } $this->rootAlias = current($rootAlias); @@ -378,7 +330,6 @@ private function checkAliases(string $column): string return $this->rootAlias . '.' . $column; } - private function usePaginator(): bool { $hasJoin = (bool) $this->dataSource->getDQLPart('join'); @@ -386,4 +337,5 @@ private function usePaginator(): bool return $hasJoin || $hasGroupBy; } + } diff --git a/src/DataSource/ElasticsearchDataSource.php b/src/DataSource/ElasticsearchDataSource.php index 50a409da0..cd7435235 100644 --- a/src/DataSource/ElasticsearchDataSource.php +++ b/src/DataSource/ElasticsearchDataSource.php @@ -1,58 +1,44 @@ -client = $client; $this->searchParamsBuilder = new SearchParamsBuilder($indexName); if ($rowFactory === null) { - $rowFactory = static function (array $hit): array { - return $hit['_source']; - }; + $rowFactory = static fn (array $hit): array => $hit['_source']; } $this->rowFactory = $rowFactory; } - public function getCount(): int { $searchResult = $this->client->search($this->searchParamsBuilder->buildParams()); if (!isset($searchResult['hits'])) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } return is_array($searchResult['hits']['total']) @@ -60,7 +46,6 @@ public function getCount(): int : $searchResult['hits']['total']; } - /** * {@inheritDoc} */ @@ -69,13 +54,12 @@ public function getData(): array $searchResult = $this->client->search($this->searchParamsBuilder->buildParams()); if (!isset($searchResult['hits'])) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } return array_map($this->rowFactory, $searchResult['hits']['hits']); } - /** * {@inheritDoc} */ @@ -88,7 +72,6 @@ public function filterOne(array $condition): IDataSource return $this; } - public function limit(int $offset, int $limit): IDataSource { $this->searchParamsBuilder->setFrom($offset); @@ -97,7 +80,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - public function applyFilterDate(FilterDate $filter): void { foreach ($filter->getCondition() as $column => $value) { @@ -120,7 +102,6 @@ public function applyFilterDate(FilterDate $filter): void } } - public function applyFilterDateRange(FilterDateRange $filter): void { foreach ($filter->getCondition() as $column => $values) { @@ -147,7 +128,6 @@ public function applyFilterDateRange(FilterDateRange $filter): void } } - public function applyFilterRange(FilterRange $filter): void { foreach ($filter->getCondition() as $column => $value) { @@ -155,7 +135,6 @@ public function applyFilterRange(FilterRange $filter): void } } - public function applyFilterText(FilterText $filter): void { foreach ($filter->getCondition() as $column => $value) { @@ -167,7 +146,6 @@ public function applyFilterText(FilterText $filter): void } } - public function applyFilterMultiSelect(FilterMultiSelect $filter): void { foreach ($filter->getCondition() as $column => $values) { @@ -175,7 +153,6 @@ public function applyFilterMultiSelect(FilterMultiSelect $filter): void } } - public function applyFilterSelect(FilterSelect $filter): void { foreach ($filter->getCondition() as $column => $value) { @@ -183,15 +160,15 @@ public function applyFilterSelect(FilterSelect $filter): void } } - /** * {@inheritDoc} - * @throws \RuntimeException + * + * @throws RuntimeException */ public function sort(Sorting $sorting): IDataSource { if (is_callable($sorting->getSortCallback())) { - throw new \RuntimeException('No can do - not implemented yet'); + throw new RuntimeException('No can do - not implemented yet'); } foreach ($sorting->getSort() as $column => $order) { @@ -203,13 +180,9 @@ public function sort(Sorting $sorting): IDataSource return $this; } - - /** - * {@inheritDoc} - */ - protected function getDataSource() + protected function getDataSource(): SearchParamsBuilder { - return $this->client; + return $this->searchParamsBuilder; } } diff --git a/src/DataSource/FilterableDataSource.php b/src/DataSource/FilterableDataSource.php index 26caf414d..2cb2e8cd6 100644 --- a/src/DataSource/FilterableDataSource.php +++ b/src/DataSource/FilterableDataSource.php @@ -1,39 +1,19 @@ -dataSource = $dataSource; - $this->primaryKey = $primaryKey; } - - // ******************************************************************************* - // * IDataSource implementation * - // ******************************************************************************* - - public function getCount(): int { $dataSourceSqlBuilder = $this->dataSource->getSqlBuilder(); @@ -56,7 +32,7 @@ public function getCount(): int try { $primary = $this->dataSource->getPrimary(); - } catch (LogicException $e) { + } catch (LogicException) { if ($dataSourceSqlBuilder->getGroup() !== '') { return $this->dataSource->count( 'DISTINCT ' . Strings::replace($dataSourceSqlBuilder->getGroup(), '~ (DESC|ASC)~') @@ -77,7 +53,6 @@ public function getCount(): int ); } - /** * {@inheritDoc} */ @@ -88,7 +63,6 @@ public function getData(): array : $this->dataSource->fetchAll(); } - /** * {@inheritDoc} */ @@ -99,7 +73,6 @@ public function filterOne(array $condition): IDataSource return $this; } - /** * @phpstan-param positive-int|0 $offset * @phpstan-param positive-int|0 $limit @@ -111,7 +84,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - public function sort(Sorting $sorting): IDataSource { if (is_callable($sorting->getSortCallback())) { @@ -130,7 +102,7 @@ public function sort(Sorting $sorting): IDataSource $this->dataSource->getSqlBuilder()->setOrder([], []); foreach ($sort as $column => $order) { - $this->dataSource->order("$column $order"); + $this->dataSource->order(sprintf('%s %s', $column, $order)); } } else { /** @@ -144,13 +116,11 @@ public function sort(Sorting $sorting): IDataSource return $this; } - public function processAggregation(IAggregationFunction $function): void { $function->processDataSource(clone $this->dataSource); } - protected function applyFilterDate(FilterDate $filter): void { $conditions = $filter->getCondition(); @@ -158,13 +128,12 @@ protected function applyFilterDate(FilterDate $filter): void try { $date = DateTimeHelper::tryConvertToDateTime($conditions[$filter->getColumn()], [$filter->getPhpFormat()]); - $this->dataSource->where("DATE({$filter->getColumn()}) = ?", $date->format('Y-m-d')); - } catch (DataGridDateTimeHelperException $ex) { + $this->dataSource->where(sprintf('DATE(%s) = ?', $filter->getColumn()), $date->format('Y-m-d')); + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } - protected function applyFilterDateRange(FilterDateRange $filter): void { $conditions = $filter->getCondition(); @@ -178,10 +147,10 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $dateFrom->setTime(0, 0, 0); $this->dataSource->where( - "DATE({$filter->getColumn()}) >= ?", + sprintf('DATE(%s) >= ?', $filter->getColumn()), $dateFrom->format('Y-m-d') ); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } @@ -191,14 +160,16 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $dateTo = DateTimeHelper::tryConvertToDateTime($valueTo, [$filter->getPhpFormat()]); $dateTo->setTime(23, 59, 59); - $this->dataSource->where("DATE({$filter->getColumn()}) <= ?", $dateTo->format('Y-m-d')); - } catch (DataGridDateTimeHelperException $ex) { + $this->dataSource->where( + sprintf('DATE(%s) <= ?', $filter->getColumn()), + $dateTo->format('Y-m-d') + ); + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } } - protected function applyFilterRange(FilterRange $filter): void { $conditions = $filter->getCondition(); @@ -207,15 +178,14 @@ protected function applyFilterRange(FilterRange $filter): void $valueTo = $conditions[$filter->getColumn()]['to']; if ($valueFrom) { - $this->dataSource->where("{$filter->getColumn()} >= ?", $valueFrom); + $this->dataSource->where(sprintf('%s >= ?', $filter->getColumn()), $valueFrom); } if ($valueTo) { - $this->dataSource->where("{$filter->getColumn()} <= ?", $valueTo); + $this->dataSource->where(sprintf('%s <= ?', $filter->getColumn()), $valueTo); } } - protected function applyFilterText(FilterText $filter): void { $or = []; @@ -229,49 +199,48 @@ protected function applyFilterText(FilterText $filter): void $args = []; if ($filter->isExactSearch()) { - $like .= "$column = ? OR "; - $args[] = "$value"; + $like .= sprintf('%s = ? OR ', $column); + $args[] = sprintf('%s', $value); } else { $words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value); foreach ($words as $word) { - $like .= "$column LIKE ? OR "; - $args[] = "%$word%"; + $like .= sprintf('%s LIKE ? OR ', $column); + $args[] = sprintf('%%%s%%', $word); } } $like = substr($like, 0, strlen($like) - 4) . ')'; $or[] = $like; - $bigOr .= "$like OR "; - $bigOrArgs = array_merge($bigOrArgs, $args); + $bigOr .= sprintf('%s OR ', $like); + $bigOrArgs = [...$bigOrArgs, ...$args]; } - if (sizeof($or) > 1) { + if (count($or) > 1) { $bigOr = substr($bigOr, 0, strlen($bigOr) - 4) . ')'; - $query = array_merge([$bigOr], $bigOrArgs); + $query = [...[$bigOr], ...$bigOrArgs]; call_user_func_array([$this->dataSource, 'where'], $query); } else { - $query = array_merge($or, $args); + $query = [...$or, ...$args]; call_user_func_array([$this->dataSource, 'where'], $query); } } - protected function applyFilterMultiSelect(FilterMultiSelect $filter): void { $condition = $filter->getCondition(); $values = $condition[$filter->getColumn()]; $or = '('; - if (sizeof($values) > 1) { - $length = sizeof($values); + if ((is_countable($values) ? count($values) : 0) > 1) { + $length = is_countable($values) ? count($values) : 0; $i = 1; - for ($iterator = 0; $iterator < count($values); $iterator++) { + for ($iterator = 0; $iterator < (is_countable($values) ? count($values) : 0); $iterator++) { if ($i === $length) { $or .= $filter->getColumn() . ' = ?)'; } else { @@ -289,18 +258,14 @@ protected function applyFilterMultiSelect(FilterMultiSelect $filter): void } } - protected function applyFilterSelect(FilterSelect $filter): void { $this->dataSource->where($filter->getCondition()); } - - /** - * {@inheritDoc} - */ - protected function getDataSource() + protected function getDataSource(): Selection { return $this->dataSource; } + } diff --git a/src/DataSource/NetteDatabaseTableMssqlDataSource.php b/src/DataSource/NetteDatabaseTableMssqlDataSource.php index 20249f83a..348537467 100755 --- a/src/DataSource/NetteDatabaseTableMssqlDataSource.php +++ b/src/DataSource/NetteDatabaseTableMssqlDataSource.php @@ -1,13 +1,11 @@ -getColumn()], [$filter->getPhpFormat()]); $this->dataSource->where( - "CONVERT(varchar(10), {$filter->getColumn()}, 112) = ?", + sprintf('CONVERT(varchar(10), %s, 112) = ?', $filter->getColumn()), $date->format('Ymd') ); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } - protected function applyFilterDateRange(FilterDateRange $filter): void { $conditions = $filter->getCondition(); @@ -42,10 +39,10 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $dateFrom->setTime(0, 0, 0); $this->dataSource->where( - "CONVERT(varchar(10), {$filter->getColumn()}, 112) >= ?", + sprintf('CONVERT(varchar(10), %s, 112) >= ?', $filter->getColumn()), $dateFrom->format('Ymd') ); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } @@ -56,12 +53,13 @@ protected function applyFilterDateRange(FilterDateRange $filter): void $dateTo->setTime(23, 59, 59); $this->dataSource->where( - "CONVERT(varchar(10), {$filter->getColumn()}, 112) <= ?", + sprintf('CONVERT(varchar(10), %s, 112) <= ?', $filter->getColumn()), $dateTo->format('Ymd') ); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } } + } diff --git a/src/DataSource/NextrasDataSource.php b/src/DataSource/NextrasDataSource.php index c78127c7a..624cb155e 100755 --- a/src/DataSource/NextrasDataSource.php +++ b/src/DataSource/NextrasDataSource.php @@ -1,71 +1,38 @@ -dataSource = $dataSource; - $this->primaryKey = $primaryKey; - // Support version 4.0 with 3.1 backward compatibility - $this->dbalCollectionClass = class_exists('Nextras\Orm\Collection\DbalCollection') - ? 'Nextras\Orm\Collection\DbalCollection' - : 'Nextras\Orm\Mapper\Dbal\DbalCollection'; } - - // ******************************************************************************* - // * IDataSource implementation * - // ******************************************************************************* - - public function getCount(): int { return $this->dataSource->countStored(); } - /** * {@inheritDoc} */ @@ -79,7 +46,6 @@ public function getData(): array : $this->dataSource->fetchAll(); } - /** * {@inheritDoc} */ @@ -96,7 +62,6 @@ public function filterOne(array $condition): IDataSource return $this; } - public function limit(int $offset, int $limit): IDataSource { $this->dataSource = $this->dataSource->limitBy($limit, $offset); @@ -104,7 +69,6 @@ public function limit(int $offset, int $limit): IDataSource return $this; } - public function sort(Sorting $sorting): IDataSource { if (is_callable($sorting->getSortCallback())) { @@ -127,25 +91,14 @@ public function sort(Sorting $sorting): IDataSource ); } } else { - if (!$this->dataSource instanceof $this->dbalCollectionClass) { - throw new UnexpectedValueException( - sprintf( - 'Expeting %s, got %s', - $this->dbalCollectionClass, - get_class($this->dataSource) - ) - ); - } + if ($this->dataSource instanceof DbalCollection) { + $order = $this->dataSource->getQueryBuilder()->getClause('order'); - /** - * Has the statement already a order by clause? - */ - $order = $this->dataSource->getQueryBuilder()->getClause('order'); - - if (ArraysHelper::testEmpty($order)) { - $this->dataSource = $this->dataSource->orderBy( - $this->prepareColumn($this->primaryKey) - ); + if (ArraysHelper::testEmpty($order)) { + $this->dataSource = $this->dataSource->orderBy( + $this->prepareColumn($this->primaryKey) + ); + } } } @@ -154,10 +107,9 @@ public function sort(Sorting $sorting): IDataSource public function processAggregation(IAggregationFunction $function): void { - $function->processDataSource( clone $this->dataSource ); + $function->processDataSource(clone $this->dataSource); } - protected function applyFilterDate(FilterDate $filter): void { foreach ($filter->getCondition() as $column => $value) { @@ -169,13 +121,12 @@ protected function applyFilterDate(FilterDate $filter): void $this->prepareColumn($column) . '>=' => $date->setTime(0, 0, 0), $this->prepareColumn($column) . '<=' => $date_end->setTime(23, 59, 59), ]); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } } - protected function applyFilterDateRange(FilterDateRange $filter): void { $conditions = $filter->getCondition(); @@ -192,7 +143,7 @@ protected function applyFilterDateRange(FilterDateRange $filter): void [$filter->getPhpFormat()] ); $dataCondition[$this->prepareColumn($filter->getColumn()) . '>='] = $dateFrom->setTime(0, 0, 0); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } @@ -204,7 +155,7 @@ protected function applyFilterDateRange(FilterDateRange $filter): void [$filter->getPhpFormat()] ); $dataCondition[$this->prepareColumn($filter->getColumn()) . '<='] = $dateTo->setTime(23, 59, 59); - } catch (DataGridDateTimeHelperException $ex) { + } catch (DatagridDateTimeHelperException) { // ignore the invalid filter value } } @@ -214,7 +165,6 @@ protected function applyFilterDateRange(FilterDateRange $filter): void } } - protected function applyFilterRange(FilterRange $filter): void { $conditions = $filter->getCondition(); @@ -237,84 +187,38 @@ protected function applyFilterRange(FilterRange $filter): void } } - protected function applyFilterText(FilterText $filter): void { - // native handling with LikeFunction in v4 - if (class_exists(LikeExpression::class)) { - $conditions = [ - ICollection::OR, - ]; + $conditions = [ + ICollection::OR, + ]; + + foreach ($filter->getCondition() as $column => $value) { + $preparedColumn = $this->prepareColumn($column); - foreach ($filter->getCondition() as $column => $value) { - $preparedColumn = $this->prepareColumn($column); + if ($filter->isExactSearch()) { + $conditions[] = [ + $preparedColumn => $value, + ]; + } else { + $words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value); - if ($filter->isExactSearch()) { + foreach ($words as $word) { $conditions[] = [ - $preparedColumn => $value, + $preparedColumn . '~' => LikeExpression::contains($word), ]; - } else { - $words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value); - - foreach ($words as $word) { - $conditions[] = [ - $preparedColumn . '~' => LikeExpression::contains($word), - ]; - } } } - - $this->dataSource = $this->dataSource->findBy($conditions); - - return; - } - - $condition = $filter->getCondition(); - $expr = '('; - $params = []; - - foreach ($condition as $column => $value) { - if ($filter->isExactSearch()) { - $expr .= '%column = %s OR '; - $params[] = $column; - $params[] = "$value"; - - continue; - } - - $words = $filter->hasSplitWordsSearch() === false ? [$value] : explode(' ', $value); - - foreach ($words as $word) { - $expr .= '%column LIKE %s OR '; - $params[] = $column; - $params[] = "%$word%"; - } } - $expr = preg_replace('/ OR $/', ')', $expr); - - array_unshift($params, $expr); - - if (!$this->dataSource instanceof $this->dbalCollectionClass) { - throw new UnexpectedValueException( - sprintf( - 'Expeting %s, got %s', - $this->dbalCollectionClass, - get_class($this->dataSource) - ) - ); - } - - $this->dataSource->getQueryBuilder()->andWhere(...$params); + $this->dataSource = $this->dataSource->findBy($conditions); } - protected function applyFilterMultiSelect(FilterMultiSelect $filter): void { $this->applyFilterSelect($filter); } - protected function applyFilterSelect(FilterSelect $filter): void { $this->dataSource = $this->dataSource->findBy( @@ -322,30 +226,21 @@ protected function applyFilterSelect(FilterSelect $filter): void ); } - - /** - * {@inheritDoc} - */ - protected function getDataSource() + protected function getDataSource(): ICollection { return $this->dataSource; } - /** - * Adjust column from DataGrid 'foreignKey.column' to Nextras 'this->foreignKey->column' + * Adjust column from Datagrid 'foreignKey.column' to Nextras 'this->foreignKey->column' */ private function prepareColumn(string $column): string { - if (Strings::contains($column, '.')) { - // 'this->' is deprecated in v4 - $prefix = $this->dbalCollectionClass === 'Nextras\Orm\Collection\DbalCollection' - ? '' - : 'this->'; - - return $prefix . str_replace('.', '->', $column); + if (str_contains($column, '.')) { + return str_replace('.', '->', $column); } return $column; } + } diff --git a/src/DataSource/SearchParamsBuilder.php b/src/DataSource/SearchParamsBuilder.php index 642f85661..8320c7b3c 100644 --- a/src/DataSource/SearchParamsBuilder.php +++ b/src/DataSource/SearchParamsBuilder.php @@ -1,115 +1,70 @@ -indexName = $indexName; } - public function addPhrasePrefixQuery(string $field, string $query): void { $this->phrasePrefixQueries[] = [$field => $query]; } - - /** - * @param mixed $query - */ - public function addMatchQuery(string $field, $query): void + public function addMatchQuery(string $field, mixed $query): void { $this->matchQueries[] = [$field => $query]; } - public function addBooleanMatchQuery(string $field, array $queries): void { $this->booleanMatchQueries[] = [$field => $queries]; } - public function addRangeQuery(string $field, ?int $from, ?int $to): void { $this->rangeQueries[] = [$field => ['from' => $from, 'to' => $to]]; } - public function addIdsQuery(array $ids): void { $this->idsQueries[] = $ids; } - public function setSort(array $sort): void { $this->sort = $sort; } - public function setFrom(int $from): void { $this->from = $from; } - public function setSize(int $size): void { $this->size = $size; } - public function buildParams(): array { $return = [ @@ -226,4 +181,5 @@ public function buildParams(): array return $return; } + } diff --git a/src/DataGrid.php b/src/Datagrid.php similarity index 80% rename from src/DataGrid.php rename to src/Datagrid.php index a606127a2..11e35fcdd 100644 --- a/src/DataGrid.php +++ b/src/Datagrid.php @@ -1,11 +1,48 @@ - - */ - protected $columns = []; + /** @var array */ + protected array $columns = []; - /** - * @var array|array - */ - protected $actions = []; + /** @var array|array */ + protected array $actions = []; - /** - * @var GroupActionCollection|null - */ - protected $groupActionCollection; + protected ?GroupActionCollection $groupActionCollection = null; - /** - * @var array - */ - protected $filters = []; + /** @var array */ + protected array $filters = []; - /** - * @var array - */ - protected $exports = []; + /** @var array */ + protected array $exports = []; - /** - * @var array - */ - protected $toolbarButtons = []; + /** @var array */ + protected array $toolbarButtons = []; - /** - * @var DataModel|null - */ - protected $dataModel; + protected ?DataModel $dataModel = null; - /** - * @var string - */ - protected $primaryKey = 'id'; + protected string $primaryKey = 'id'; - /** - * @var bool - */ - protected $doPaginate = true; + protected bool $doPaginate = true; - /** - * @var bool - */ - protected $csvExport = true; + protected bool $csvExport = true; - /** - * @var bool - */ - protected $csvExportFiltered = true; + protected bool $csvExportFiltered = true; - /** - * @var bool - */ - protected $sortable = false; + protected bool $sortable = false; - /** - * @var bool - */ - protected $multiSort = false; + protected bool $multiSort = false; - /** - * @var string - */ - protected $sortableHandler = 'sort!'; + protected string $sortableHandler = 'sort!'; - /** - * @var string|null - */ - protected $originalTemplate = null; + protected ?string $originalTemplate = null; - /** - * @var array - */ - protected $redrawItem = []; + protected array $redrawItem = []; - /** - * @var ITranslator|null - */ - protected $translator = null; + protected ?Translator $translator = null; - /** - * @var bool - */ - protected $forceFilterActive = false; + protected bool $forceFilterActive = false; - /** - * @var callable|null - */ + /** @var callable|null */ protected $treeViewChildrenCallback = null; - /** - * @var callable|null - */ + /** @var callable|null */ protected $treeViewHasChildrenCallback = null; - /** - * @var string|null - */ - protected $treeViewHasChildrenColumn = null; + protected ?string $treeViewHasChildrenColumn = null; - /** - * @var bool - */ - protected $outerFilterRendering = false; + protected bool $outerFilterRendering = false; - /** - * @var int - */ - protected $outerFilterColumnsCount = 2; + protected int $outerFilterColumnsCount = 2; - /** - * @var bool - */ - protected $collapsibleOuterFilters = true; + protected bool $collapsibleOuterFilters = true; - /** - * @var array|string[] - */ - protected $columnsExportOrder = []; + /** @var array|string[] */ + protected array $columnsExportOrder = []; - /** - * @var bool - */ - protected $rememberState = true; + protected bool $rememberState = true; - /** - * @var bool - */ - protected $rememberHideableColumnsState = true; + protected bool $rememberHideableColumnsState = true; - /** - * @var bool - */ - protected $refreshURL = true; + protected bool $refreshURL = true; - /** - * @var SessionSection - */ - protected $gridSession; + protected SessionSection $gridSession; - /** - * @var ItemDetail|null - */ - protected $itemsDetail; + protected ?ItemDetail $itemsDetail = null; - /** - * @var array - */ - protected $rowConditions = [ + protected array $rowConditions = [ 'group_action' => false, 'action' => [], ]; - /** - * @var array - */ - protected $columnCallbacks = []; - - /** - * @var bool - */ - protected $canHideColumns = false; + protected array $columnCallbacks = []; - /** - * @var array - */ - protected $columnsVisibility = []; + protected bool $canHideColumns = false; - /** - * @var InlineEdit|null - */ - protected $inlineEdit = null; + protected array $columnsVisibility = []; - /** - * @var InlineAdd|null - */ - protected $inlineAdd = null; + protected ?InlineEdit $inlineEdit = null; - /** - * @var bool - */ - protected $snippetsSet = false; + protected ?InlineAdd $inlineAdd = null; - /** - * @var bool - */ - protected $someColumnDefaultHide = false; + protected bool $snippetsSet = false; - /** - * @var ColumnsSummary|null - */ - protected $columnsSummary; + protected bool $someColumnDefaultHide = false; - /** - * @var bool - */ - protected $autoSubmit = true; + protected ?ColumnsSummary $columnsSummary = null; - /** - * @var SubmitButton|null - */ - protected $filterSubmitButton = null; + protected bool $autoSubmit = true; - /** - * @var bool - */ - protected $hasColumnReset = true; + protected ?SubmitButton $filterSubmitButton = null; - /** - * @var bool - */ - protected $showSelectedRowsCount = true; + protected bool $hasColumnReset = true; - /** - * @var string|null - */ - private $customPaginatorTemplate = null; + protected bool $showSelectedRowsCount = true; - /** - * @var string|null - */ - private $componentFullName; + private ?string $customPaginatorTemplate = null; + private ?string $componentFullName = null; public function __construct(?IContainer $parent = null, ?string $name = null) { @@ -485,10 +310,10 @@ function (Presenter $presenter): void { } $this->componentFullName = $this->lookupPath(); - }); + } + ); } - /******************************************************************************** * RENDERING * ********************************************************************************/ @@ -498,17 +323,17 @@ public function render(): void * Check whether datagrid has set some columns, initiated data source, etc */ if (!($this->dataModel instanceof DataModel)) { - throw new DataGridException('You have to set a data source first.'); + throw new DatagridException('You have to set a data source first.'); } if ($this->columns === []) { - throw new DataGridException('You have to add at least one column.'); + throw new DatagridException('You have to add at least one column.'); } $template = $this->getTemplate(); if (!$template instanceof Template) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $template->setTranslator($this->getTranslator()); @@ -523,15 +348,11 @@ public function render(): void */ $rows = []; - if ($this->redrawItem !== []) { - $items = $this->dataModel->filterRow($this->redrawItem); - } else { - $items = $this->dataModel->filterData( - $this->getPaginator(), - $this->createSorting($this->sort, $this->sortCallback), - $this->assembleFilters() - ); - } + $items = $this->redrawItem !== [] ? $this->dataModel->filterRow($this->redrawItem) : $this->dataModel->filterData( + $this->getPaginator(), + $this->createSorting($this->sort, $this->sortCallback), + $this->assembleFilters() + ); $hasGroupActionOnRows = false; @@ -627,7 +448,7 @@ public function setRowCallback(callable $callback): self public function setPrimaryKey(string $primaryKey): self { if ($this->dataModel instanceof DataModel) { - throw new DataGridException('Please set datagrid primary key before setting datasource.'); + throw new DatagridException('Please set datagrid primary key before setting datasource.'); } $this->primaryKey = $primaryKey; @@ -635,13 +456,11 @@ public function setPrimaryKey(string $primaryKey): self return $this; } - /** - * @param mixed $source * @return static * @throws InvalidArgumentException */ - public function setDataSource($source): self + public function setDataSource(mixed $source): self { $this->dataModel = new DataModel($source, $this->primaryKey); @@ -652,11 +471,7 @@ public function setDataSource($source): self return $this; } - - /** - * @return IDataSource|array|null - */ - public function getDataSource() + public function getDataSource(): IDataSource|array|null { return isset($this->dataModel) ? $this->dataModel->getDataSource() @@ -678,13 +493,11 @@ public function setTemplateFile(string $templateFile): self return $this; } - public function getTemplateFile(): string { return $this->templateFile ?? $this->getOriginalTemplateFile(); } - public function getOriginalTemplateFile(): string { return __DIR__ . '/templates/datagrid.latte'; @@ -700,7 +513,6 @@ public function useHappyComponents(bool $useHappyComponents): self return $this; } - public function shouldUseHappyComponents(): bool { return $this->useHappyComponents; @@ -711,11 +523,10 @@ public function shouldUseHappyComponents(): bool * SORTING * ********************************************************************************/ - /** - * @param string|array $sort - * @return static - */ - public function setDefaultSort($sort, bool $useOnReset = true): self + /** + * @return static + */ + public function setDefaultSort(string|array $sort, bool $useOnReset = true): self { $sort = is_string($sort) ? [$sort => 'ASC'] @@ -727,7 +538,6 @@ public function setDefaultSort($sort, bool $useOnReset = true): self return $this; } - /** * Return default sort for column, if specified */ @@ -740,7 +550,6 @@ public function getColumnDefaultSort(string $columnKey): ?string return null; } - /** * User may set default sorting, apply it */ @@ -761,15 +570,14 @@ public function findDefaultSort(): void $this->saveSessionData('_grid_sort', $this->sort); } - /** * @return static - * @throws DataGridException + * @throws DatagridException */ public function setSortable(bool $sortable = true): self { if ($this->getItemsDetail() !== null) { - throw new DataGridException('You can not use both sortable datagrid and items detail.'); + throw new DatagridException('You can not use both sortable datagrid and items detail.'); } $this->sortable = $sortable; @@ -777,7 +585,6 @@ public function setSortable(bool $sortable = true): self return $this; } - public function isSortable(): bool { return $this->sortable; @@ -793,7 +600,6 @@ public function setMultiSortEnabled(bool $multiSort = true): self return $this; } - public function isMultiSortEnabled(): bool { return $this->multiSort; @@ -809,13 +615,11 @@ public function setSortableHandler(string $handler = 'sort!'): self return $this; } - public function getSortableHandler(): string { return $this->sortableHandler; } - public function getSortNext(Column $column): array { $sort = $column->getSortNext(); @@ -827,7 +631,6 @@ public function getSortNext(Column $column): array return array_filter($sort); } - /******************************************************************************** * TREE VIEW * ********************************************************************************/ @@ -836,14 +639,12 @@ public function isTreeView(): bool return $this->treeViewChildrenCallback !== null; } - /** - * @param string|callable $treeViewHasChildrenColumn * @return static */ public function setTreeView( callable $getChildrenCallback, - $treeViewHasChildrenColumn = 'has_children' + string|callable $treeViewHasChildrenColumn = 'has_children' ): self { if (is_callable($treeViewHasChildrenColumn)) { @@ -869,26 +670,20 @@ public function setTreeView( return $this; } - public function hasTreeViewChildrenCallback(): bool { return is_callable($this->treeViewHasChildrenCallback); } - - /** - * @param mixed $item - */ - public function treeViewChildrenCallback($item): bool + public function treeViewChildrenCallback(mixed $item): bool { if ($this->treeViewHasChildrenCallback === null) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } return (bool) call_user_func($this->treeViewHasChildrenCallback, $item); } - /******************************************************************************** * COLUMNS * ********************************************************************************/ @@ -898,7 +693,7 @@ public function addColumnText( ?string $column = null ): ColumnText { - $column = $column ?? $key; + $column ??= $key; $columnText = new ColumnText($this, $key, $column, $name); $this->addColumn($key, $columnText); @@ -906,7 +701,6 @@ public function addColumnText( return $columnText; } - public function addColumnLink( string $key, string $name, @@ -915,8 +709,8 @@ public function addColumnLink( ?array $params = null ): ColumnLink { - $column = $column ?? $key; - $href = $href ?? $key; + $column ??= $key; + $href ??= $key; if ($params === null) { $params = [$this->primaryKey]; @@ -928,14 +722,13 @@ public function addColumnLink( return $columnLink; } - public function addColumnNumber( string $key, string $name, ?string $column = null ): ColumnNumber { - $column = $column ?? $key; + $column ??= $key; $columnNumber = new ColumnNumber($this, $key, $column, $name); $this->addColumn($key, $columnNumber); @@ -943,14 +736,13 @@ public function addColumnNumber( return $columnNumber; } - public function addColumnDateTime( string $key, string $name, ?string $column = null ): ColumnDateTime { - $column = $column ?? $key; + $column ??= $key; $columnDateTime = new ColumnDateTime($this, $key, $column, $name); $this->addColumn($key, $columnDateTime); @@ -958,14 +750,13 @@ public function addColumnDateTime( return $columnDateTime; } - public function addColumnStatus( string $key, string $name, ?string $column = null ): ColumnStatus { - $column = $column ?? $key; + $column ??= $key; $columnStatus = new ColumnStatus($this, $key, $column, $name); $this->addColumn($key, $columnStatus); @@ -973,14 +764,13 @@ public function addColumnStatus( return $columnStatus; } - /** - * @throws DataGridColumnNotFoundException + * @throws DatagridColumnNotFoundException */ public function getColumn(string $key): Column { if (!isset($this->columns[$key])) { - throw new DataGridColumnNotFoundException( + throw new DatagridColumnNotFoundException( sprintf('There is no column at key [%s] defined.', $key) ); } @@ -998,7 +788,6 @@ public function removeColumn(string $key): self return $this; } - /******************************************************************************** * ACTIONS * ********************************************************************************/ @@ -1011,7 +800,7 @@ public function addAction( { $this->addActionCheck($key); - $href = $href ?? $key; + $href ??= $key; if ($params === null) { $params = [$this->primaryKey]; @@ -1020,7 +809,6 @@ public function addAction( return $this->actions[$key] = new Action($this, $key, $href, $name, $params); } - public function addActionCallback( string $key, string $name, @@ -1040,7 +828,6 @@ public function addActionCallback( return $action; } - public function addMultiAction(string $key, string $name): MultiAction { $this->addActionCheck($key); @@ -1052,15 +839,13 @@ public function addMultiAction(string $key, string $name): MultiAction return $action; } - /** - * @return Action|MultiAction - * @throws DataGridException + * @throws DatagridException */ - public function getAction(string $key) + public function getAction(string $key): Action|MultiAction { if (!isset($this->actions[$key])) { - throw new DataGridException(sprintf('There is no action at key [%s] defined.', $key)); + throw new DatagridException(sprintf('There is no action at key [%s] defined.', $key)); } return $this->actions[$key]; @@ -1076,14 +861,10 @@ public function removeAction(string $key): self return $this; } - - /** - * @param array|string $columns - */ public function addFilterText( string $key, string $name, - $columns = null + array|string|null $columns = null ): FilterText { $columns = $columns === null ? [$key] : (is_string($columns) ? [$columns] : $columns); @@ -1093,7 +874,6 @@ public function addFilterText( return $this->filters[$key] = new FilterText($this, $key, $name, $columns); } - public function addFilterSelect( string $key, string $name, @@ -1101,14 +881,13 @@ public function addFilterSelect( ?string $column = null ): FilterSelect { - $column = $column ?? $key; + $column ??= $key; $this->addFilterCheck($key); return $this->filters[$key] = new FilterSelect($this, $key, $name, $options, $column); } - public function addFilterMultiSelect( string $key, string $name, @@ -1116,24 +895,22 @@ public function addFilterMultiSelect( ?string $column = null ): FilterMultiSelect { - $column = $column ?? $key; + $column ??= $key; $this->addFilterCheck($key); return $this->filters[$key] = new FilterMultiSelect($this, $key, $name, $options, $column); } - public function addFilterDate(string $key, string $name, ?string $column = null): FilterDate { - $column = $column ?? $key; + $column ??= $key; $this->addFilterCheck($key); return $this->filters[$key] = new FilterDate($this, $key, $name, $column); } - public function addFilterRange( string $key, string $name, @@ -1141,16 +918,15 @@ public function addFilterRange( string $nameSecond = '-' ): FilterRange { - $column = $column ?? $key; + $column ??= $key; $this->addFilterCheck($key); return $this->filters[$key] = new FilterRange($this, $key, $name, $column, $nameSecond); } - /** - * @throws DataGridException + * @throws DatagridException */ public function addFilterDateRange( string $key, @@ -1159,17 +935,13 @@ public function addFilterDateRange( string $nameSecond = '-' ): FilterDateRange { - $column = $column ?? $key; + $column ??= $key; $this->addFilterCheck($key); return $this->filters[$key] = new FilterDateRange($this, $key, $name, $column, $nameSecond); } - - - - /** * Fill array of Filter\Filter[] with values from $this->filter persistent parameter * Fill array of Column\Column[] with values from $this->sort persistent parameter @@ -1185,7 +957,7 @@ public function assembleFilters(): array continue; } - if (is_array($value) || $value instanceof Traversable) { + if (is_iterable($value)) { if (!ArraysHelper::testEmpty($value)) { $this->filters[$key]->setValue($value); } @@ -1217,11 +989,10 @@ public function removeFilter(string $key): self return $this; } - public function getFilter(string $key): Filter { if (!isset($this->filters[$key])) { - throw new DataGridException(sprintf('Filter [%s] is not defined', $key)); + throw new DatagridException(sprintf('Filter [%s] is not defined', $key)); } return $this->filters[$key]; @@ -1237,7 +1008,6 @@ public function setStrictSessionFilterValues(bool $strictSessionFilterValues = t return $this; } - /******************************************************************************** * FILTERING * ********************************************************************************/ @@ -1248,6 +1018,10 @@ public function isFilterActive(): bool return $is_filter || $this->forceFilterActive; } + public function isFilterDefault(): bool + { + return $this->filter === $this->defaultFilter; + } /** * Tell that filter is active from whatever reasons @@ -1261,7 +1035,6 @@ public function setFilterActive(): self return $this; } - /** * Set filter values (force - overwrite user data) * @@ -1276,12 +1049,11 @@ public function setFilter(array $filter): self return $this; } - /** * If we want to sent some initial filter * * @return static - * @throws DataGridException + * @throws DatagridException */ public function setDefaultFilter(array $defaultFilter, bool $useOnReset = true): self { @@ -1290,20 +1062,20 @@ public function setDefaultFilter(array $defaultFilter, bool $useOnReset = true): $filter = $this->getFilter($key); if ($filter === null) { - throw new DataGridException( + throw new DatagridException( sprintf('Can not set default value to nonexisting filter [%s]', $key) ); } if ($filter instanceof FilterMultiSelect && !is_array($value)) { - throw new DataGridException( + throw new DatagridException( sprintf('Default value of filter [%s] - MultiSelect has to be an array', $key) ); } if ($filter instanceof FilterRange || $filter instanceof FilterDateRange) { if (!is_array($value)) { - throw new DataGridException( + throw new DatagridException( sprintf('Default value of filter [%s] - Range/DateRange has to be an array [from/to => ...]', $key) ); } @@ -1312,7 +1084,7 @@ public function setDefaultFilter(array $defaultFilter, bool $useOnReset = true): unset($temp['from'], $temp['to']); if (count($temp) > 0) { - throw new DataGridException( + throw new DatagridException( sprintf( 'Default value of filter [%s] - Range/DateRange can contain only [from/to => ...] values', $key @@ -1328,7 +1100,6 @@ public function setDefaultFilter(array $defaultFilter, bool $useOnReset = true): return $this; } - public function findDefaultFilter(): void { if ($this->filter !== []) { @@ -1348,7 +1119,6 @@ public function findDefaultFilter(): void } } - public function createComponentFilter(): Form { $form = new Form($this, 'filter'); @@ -1363,9 +1133,9 @@ public function createComponentFilter(): Form $inline_edit_container = $form->addContainer('inline_edit'); if ($this->inlineEdit instanceof InlineEdit) { - $inline_edit_container->addSubmit('submit', 'ublaboo_datagrid.save') + $inline_edit_container->addSubmit('submit', 'contributte_datagrid.save') ->setValidationScope([$inline_edit_container]); - $inline_edit_container->addSubmit('cancel', 'ublaboo_datagrid.cancel') + $inline_edit_container->addSubmit('cancel', 'contributte_datagrid.cancel') ->setValidationScope(null); $this->inlineEdit->onControlAdd($inline_edit_container); @@ -1378,11 +1148,11 @@ public function createComponentFilter(): Form $inlineAddContainer = $form->addContainer('inline_add'); if ($this->inlineAdd instanceof InlineAdd) { - $inlineAddContainer->addSubmit('submit', 'ublaboo_datagrid.save') + $inlineAddContainer->addSubmit('submit', 'contributte_datagrid.save') ->setValidationScope([$inlineAddContainer]); - $inlineAddContainer->addSubmit('cancel', 'ublaboo_datagrid.cancel') + $inlineAddContainer->addSubmit('cancel', 'contributte_datagrid.cancel') ->setValidationScope(null) - ->setAttribute('data-datagrid-cancel-inline-add', true); + ->setHtmlAttribute('data-datagrid-cancel-inline-add', true); $this->inlineAdd->onControlAdd($inlineAddContainer); $this->inlineAdd->onControlAfterAdd($inlineAddContainer); @@ -1434,7 +1204,7 @@ public function createComponentFilter(): Form $select->setValue($this->getPerPage()); } - $form->addSubmit('perPage_submit', 'ublaboo_datagrid.per_page_submit') + $form->addSubmit('perPage_submit', 'contributte_datagrid.per_page_submit') ->setValidationScope([$select]); } @@ -1445,7 +1215,6 @@ public function createComponentFilter(): Form return $form; } - public function setFilterContainerDefaults(Container $container, array $values, ?string $parentKey = null): void { foreach ($container->getComponents() as $key => $control) { @@ -1461,12 +1230,8 @@ public function setFilterContainerDefaults(Container $container, array $values, $value = $values[$key]; - if ($value instanceof \DateTime) { - if ($parentKey !== null) { - $filter = $this->getFilter($parentKey); - } else { - $filter = $this->getFilter((string) $key); - } + if ($value instanceof DateTime) { + $filter = $parentKey !== null ? $this->getFilter($parentKey) : $this->getFilter((string) $key); if ($filter instanceof IFilterDate) { $value = $value->format($filter->getPhpFormat()); @@ -1474,8 +1239,8 @@ public function setFilterContainerDefaults(Container $container, array $values, } try { - if (!$control instanceof IControl) { - throw new \UnexpectedValueException; + if (!$control instanceof FormControl) { + throw new UnexpectedValueException(); } $control->setValue($value); @@ -1488,7 +1253,6 @@ public function setFilterContainerDefaults(Container $container, array $values, } } - /** * Set $this->filter values after filter form submitted */ @@ -1498,7 +1262,7 @@ public function filterSucceeded(NetteForm $form): void return; } - $values = (array) $form->getUnsafeValues(null); + $values = (array) $form->getUntrustedValues(null); if ($this->getPresenterInstance()->isAjax()) { if (isset($form['group_action']['submit']) && $form['group_action']['submit']->isSubmittedBy()) { @@ -1530,12 +1294,12 @@ public function filterSucceeded(NetteForm $form): void || !$edit['submit'] instanceof FormsSubmitButton || !$edit['cancel'] instanceof FormsSubmitButton ) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } if ($edit['submit']->isSubmittedBy() || $edit['cancel']->isSubmittedBy()) { - $id = $form->getHttpData(Form::DATA_LINE, 'inline_edit[_id]'); - $primaryWhereColumn = $form->getHttpData(Form::DATA_LINE, 'inline_edit[_primary_where_column]'); + $id = $form->getHttpData(Form::DataLine, 'inline_edit[_id]'); + $primaryWhereColumn = $form->getHttpData(Form::DataLine, 'inline_edit[_primary_where_column]'); if ($edit['submit']->isSubmittedBy() && $edit->getErrors() === []) { $this->inlineEdit->onSubmit($id, $values['inline_edit']); @@ -1575,7 +1339,7 @@ public function filterSucceeded(NetteForm $form): void || !$add['submit'] instanceof FormsSubmitButton || !$add['cancel'] instanceof FormsSubmitButton ) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } if ($add['submit']->isSubmittedBy() || $add['cancel']->isSubmittedBy()) { @@ -1597,7 +1361,7 @@ public function filterSucceeded(NetteForm $form): void $values = $values['filter']; if (!$values instanceof ArrayHash) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } foreach ($values as $key => $value) { @@ -1649,13 +1413,11 @@ public function setOuterFilterRendering(bool $outerFilterRendering = true): self return $this; } - public function hasOuterFilterRendering(): bool { return $this->outerFilterRendering; } - /** * @return static * @throws InvalidArgumentException @@ -1677,7 +1439,6 @@ public function setOuterFilterColumnsCount(int $count): self return $this; } - public function getOuterFilterColumnsCount(): int { return $this->outerFilterColumnsCount; @@ -1693,17 +1454,15 @@ public function setCollapsibleOuterFilters(bool $collapsibleOuterFilters = true) return $this; } - public function hasCollapsibleOuterFilters(): bool { return $this->collapsibleOuterFilters; } - /** * Try to restore session stuff * - * @throws DataGridFilterNotFoundException + * @throws DatagridFilterNotFoundException */ public function findSessionValues(): void { @@ -1750,9 +1509,9 @@ public function findSessionValues(): void $this->filter[$key] = $value; - } catch (DataGridException $e) { + } catch (DatagridException) { if ($this->strictSessionFilterValues) { - throw new DataGridFilterNotFoundException( + throw new DatagridFilterNotFoundException( sprintf('Session filter: Filter [%s] not found', $key) ); } @@ -1768,7 +1527,7 @@ public function findSessionValues(): void try { $column = $this->getColumn((string) $key); - } catch (DataGridColumnNotFoundException $e) { + } catch (DatagridColumnNotFoundException) { $this->deleteSessionData('_grid_sort'); $this->sort = []; @@ -1782,7 +1541,6 @@ public function findSessionValues(): void } } - /******************************************************************************** * EXPORTS * ********************************************************************************/ @@ -1795,7 +1553,6 @@ public function addExportCallback( return $this->addToExports(new Export($this, $text, $callback, $filtered)); } - public function addExportCsvFiltered( string $text, string $csvFileName, @@ -1807,7 +1564,6 @@ public function addExportCsvFiltered( return $this->addExportCsv($text, $csvFileName, $outputEncoding, $delimiter, $includeBom, true); } - public function addExportCsv( string $text, string $csvFileName, @@ -1824,7 +1580,6 @@ public function addExportCsv( return $exportCsv; } - public function resetExportsLinks(): void { foreach ($this->exports as $id => $export) { @@ -1840,7 +1595,7 @@ public function resetExportsLinks(): void ********************************************************************************/ /** - * @throws DataGridException + * @throws DatagridException */ public function addToolbarButton( string $href, @@ -1849,7 +1604,7 @@ public function addToolbarButton( ): ToolbarButton { if (isset($this->toolbarButtons[$href])) { - throw new DataGridException( + throw new DatagridException( sprintf('There is already toolbar button at key [%s] defined.', $href) ); } @@ -1857,14 +1612,13 @@ public function addToolbarButton( return $this->toolbarButtons[$href] = new ToolbarButton($this, $href, $text, $params); } - /** - * @throws DataGridException + * @throws DatagridException */ public function getToolbarButton(string $key): ToolbarButton { if (!isset($this->toolbarButtons[$key])) { - throw new DataGridException( + throw new DatagridException( sprintf('There is no toolbar button at key [%s] defined.', $key) ); } @@ -1882,7 +1636,6 @@ public function removeToolbarButton(string $key): self return $this; } - /******************************************************************************** * GROUP ACTIONS * ********************************************************************************/ @@ -1891,37 +1644,31 @@ public function addGroupAction(string $title, array $options = []): GroupAction return $this->getGroupActionCollection()->addGroupSelectAction($title, $options); } - public function addGroupButtonAction(string $title, ?string $class = null): GroupButtonAction { return $this->getGroupActionCollection()->addGroupButtonAction($title, $class); } - public function addGroupSelectAction(string $title, array $options = []): GroupAction { return $this->getGroupActionCollection()->addGroupSelectAction($title, $options); } - public function addGroupMultiSelectAction(string $title, array $options = []): GroupAction { return $this->getGroupActionCollection()->addGroupMultiSelectAction($title, $options); } - public function addGroupTextAction(string $title): GroupAction { return $this->getGroupActionCollection()->addGroupTextAction($title); } - public function addGroupTextareaAction(string $title): GroupAction { return $this->getGroupActionCollection()->addGroupTextareaAction($title); } - public function getGroupActionCollection(): GroupActionCollection { if ($this->groupActionCollection === null) { @@ -1931,13 +1678,11 @@ public function getGroupActionCollection(): GroupActionCollection return $this->groupActionCollection; } - public function hasGroupActions(): bool { return $this->groupActionCollection instanceof GroupActionCollection; } - public function shouldShowSelectedRowsCount(): bool { return $this->showSelectedRowsCount; @@ -1953,7 +1698,6 @@ public function setShowSelectedRowsCount(bool $show = true): self return $this; } - /******************************************************************************** * HANDLERS * ********************************************************************************/ @@ -1965,9 +1709,8 @@ public function handlePage(int $page): void $this->reload(['table']); } - /** - * @throws DataGridColumnNotFoundException + * @throws DatagridColumnNotFoundException */ public function handleSort(array $sort): void { @@ -1979,7 +1722,7 @@ public function handleSort(array $sort): void try { $column = $this->getColumn($key); - } catch (DataGridColumnNotFoundException $e) { + } catch (DatagridColumnNotFoundException) { unset($sort[$key]); continue; @@ -2000,7 +1743,6 @@ public function handleSort(array $sort): void $this->reloadTheWholeGrid(); } - public function handleResetFilter(): void { /** @@ -2021,17 +1763,7 @@ public function handleResetFilter(): void : iterator_to_array($this->getSessionData()); foreach (array_keys($sessionData) as $key) { - if ( - !in_array($key, [ - '_grid_perPage', - '_grid_sort', - '_grid_page', - '_grid_has_filtered', - '_grid_has_sorted', - '_grid_hidden_columns', - '_grid_hidden_columns_manipulated', - ], true) - ) { + if (!in_array($key, ['_grid_perPage', '_grid_sort', '_grid_page', '_grid_has_filtered', '_grid_has_sorted', '_grid_hidden_columns', '_grid_hidden_columns_manipulated'], true)) { $this->deleteSessionData((string) $key); } } @@ -2041,7 +1773,6 @@ public function handleResetFilter(): void $this->reloadTheWholeGrid(); } - public function handleResetColumnFilter(string $key): void { $this->deleteSessionData($key); @@ -2060,13 +1791,11 @@ public function setColumnReset(bool $reset = true): self return $this; } - public function hasColumnReset(): bool { return $this->hasColumnReset; } - /** * @param array $filters */ @@ -2087,14 +1816,10 @@ public function sendNonEmptyFiltersInPayload(array $filters): void $this->getPresenterInstance()->payload->non_empty_filters = $non_empty_filters; } - - /** - * @param mixed $id - */ - public function handleExport($id): void + public function handleExport(mixed $id): void { if (!isset($this->exports[$id])) { - throw new Nette\Application\ForbiddenRequestException; + throw new ForbiddenRequestException(); } if ($this->columnsExportOrder !== []) { @@ -2117,7 +1842,7 @@ public function handleExport($id): void } if ($this->dataModel === null) { - throw new DataGridException('You have to set a data source first.'); + throw new DatagridException('You have to set a data source first.'); } $rows = []; @@ -2143,14 +1868,10 @@ public function handleExport($id): void } } - - /** - * @param mixed $parent - */ - public function handleGetChildren($parent): void + public function handleGetChildren(mixed $parent): void { if (!is_callable($this->treeViewChildrenCallback)) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $this->setDataSource(call_user_func($this->treeViewChildrenCallback, $parent)); @@ -2167,22 +1888,18 @@ public function handleGetChildren($parent): void } } - - /** - * @param mixed $id - */ - public function handleGetItemDetail($id): void + public function handleGetItemDetail(mixed $id): void { $template = $this->getTemplate(); if (!$template instanceof Template) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $template->add('toggle_detail', $id); if ($this->itemsDetail === null) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $this->redrawItem = [$this->itemsDetail->getPrimaryWhereColumn() => $id]; @@ -2205,25 +1922,20 @@ public function handleGetItemDetail($id): void } } - - /** - * @param mixed $id - * @param mixed $key - */ - public function handleEdit($id, $key): void + public function handleEdit(mixed $id, mixed $key): void { $column = $this->getColumn($key); $request = $this->getPresenterInstance()->getRequest(); if (!$request instanceof Request) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $value = $request->getPost('value'); // Could be null of course if ($column->getEditableCallback() === null) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $newValue = $column->getEditableCallback()($id, $value); @@ -2237,7 +1949,6 @@ public function handleEdit($id, $key): void } } - /** * @param array|string[] $snippets */ @@ -2268,7 +1979,6 @@ public function reload(array $snippets = []): void } } - public function reloadTheWholeGrid(): void { if ($this->getPresenterInstance()->isAjax()) { @@ -2283,26 +1993,20 @@ public function reloadTheWholeGrid(): void } } - public function handleChangeStatus(string $id, string $key, string $value): void { if (!isset($this->columns[$key])) { - throw new DataGridException(sprintf('ColumnStatus[%s] does not exist', $key)); + throw new DatagridException(sprintf('ColumnStatus[%s] does not exist', $key)); } if (!$this->columns[$key] instanceof ColumnStatus) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $this->columns[$key]->onChange($id, $value); } - - /** - * @param string|int $id - * @param mixed $primaryWhereColumn - */ - public function redrawItem($id, $primaryWhereColumn = null): void + public function redrawItem(string|int $id, mixed $primaryWhereColumn = null): void { $this->snippetsSet = true; @@ -2315,7 +2019,6 @@ public function redrawItem($id, $primaryWhereColumn = null): void $this->onRedraw(); } - public function handleShowAllColumns(): void { $this->deleteSessionData('_grid_hidden_columns'); @@ -2323,10 +2026,10 @@ public function handleShowAllColumns(): void $this->redrawControl(); + $this->onShowAllColumns(); $this->onRedraw(); } - public function handleShowDefaultColumns(): void { $this->deleteSessionData('_grid_hidden_columns'); @@ -2334,10 +2037,10 @@ public function handleShowDefaultColumns(): void $this->redrawControl(); + $this->onShowDefaultColumns(); $this->onRedraw(); } - public function handleShowColumn(string $column): void { $columns = $this->getSessionData('_grid_hidden_columns'); @@ -2355,10 +2058,10 @@ public function handleShowColumn(string $column): void $this->redrawControl(); + $this->onColumnShow($column); $this->onRedraw(); } - public function handleHideColumn(string $column): void { /** @@ -2377,20 +2080,16 @@ public function handleHideColumn(string $column): void $this->redrawControl(); + $this->onColumnHide($column); $this->onRedraw(); } - - /** - * @param mixed $__key - * @param mixed $__id - */ - public function handleActionCallback($__key, $__id): void + public function handleActionCallback(mixed $__key, mixed $__id): void { $action = $this->getAction($__key); if (!($action instanceof ActionCallback)) { - throw new DataGridException( + throw new DatagridException( sprintf('Action [%s] does not exist or is not an callback aciton.', $__key) ); } @@ -2410,7 +2109,7 @@ public function handleActionCallback($__key, $__id): void public function setItemsPerPageList(array $itemsPerPageList, bool $includeAll = true): self { if ($itemsPerPageList === []) { - throw new \InvalidArgumentException('$itemsPerPageList can not be an empty array'); + throw new InvalidArgumentException('$itemsPerPageList can not be an empty array'); } $this->itemsPerPageList = $itemsPerPageList; @@ -2432,7 +2131,6 @@ public function setDefaultPerPage(int $count): self return $this; } - /** * User may set default "items per page" value, apply it */ @@ -2449,10 +2147,9 @@ public function findDefaultPerPage(): void $this->saveSessionData('_grid_perPage', $this->perPage); } - - public function createComponentPaginator(): DataGridPaginator + public function createComponentPaginator(): DatagridPaginator { - $component = new DataGridPaginator( + $component = new DatagridPaginator( $this->getTranslator(), static::$iconPrefix, static::$btnSecondaryClass @@ -2472,11 +2169,7 @@ public function createComponentPaginator(): DataGridPaginator return $component; } - - /** - * @return int|string - */ - public function getPerPage() + public function getPerPage(): int|string { $itemsPerPageList = array_keys($this->getItemsPerPageList()); @@ -2492,9 +2185,8 @@ public function getPerPage() : (int) $perPage; } - /** - * @return array|array|int[]|array|string[] + * @return array|array|int[]|array|string[]|\Stringable[] */ public function getItemsPerPageList(): array { @@ -2505,13 +2197,12 @@ public function getItemsPerPageList(): array } if (array_key_exists('all', $list)) { - $list['all'] = $this->getTranslator()->translate('ublaboo_datagrid.all'); + $list['all'] = $this->getTranslator()->translate('contributte_datagrid.all'); } return $list; } - /** * @return static */ @@ -2522,14 +2213,12 @@ public function setPagination(bool $doPaginate): self return $this; } - public function isPaginated(): bool { return $this->doPaginate; } - - public function getPaginator(): ?DataGridPaginator + public function getPaginator(): ?DatagridPaginator { if ($this->isPaginated() && $this->perPage !== 'all') { return $this['paginator']; @@ -2546,18 +2235,17 @@ public function getPaginator(): ?DataGridPaginator /** * @return static */ - public function setTranslator(ITranslator $translator): self + public function setTranslator(Translator $translator): self { $this->translator = $translator; return $this; } - - public function getTranslator(): ITranslator + public function getTranslator(): Translator { if ($this->translator === null) { - $this->translator = new SimpleTranslator; + $this->translator = new SimpleTranslator(); } return $this->translator; @@ -2584,16 +2272,15 @@ public function setColumnsOrder(array $order): self } } - if (sizeof($new_order) === sizeof($this->columns)) { + if (count($new_order) === count($this->columns)) { $this->columns = $new_order; } else { - throw new DataGridException('When changing columns order, you have to specify all columns'); + throw new DatagridException('When changing columns order, you have to specify all columns'); } return $this; } - /** * Columns order may be different for export and normal grid * @@ -2607,7 +2294,6 @@ public function setColumnsExportOrder(array $order): self return $this; } - /******************************************************************************** * SESSION & URL * ********************************************************************************/ @@ -2618,7 +2304,6 @@ public function getSessionSectionName(): string return $presenter->getName() . ':' . $this->getUniqueId(); } - /** * @return static */ @@ -2630,7 +2315,6 @@ public function setRememberState(bool $remember = true, bool $rememberHideableCo return $this; } - /** * @return static */ @@ -2641,16 +2325,9 @@ public function setRefreshUrl(bool $refresh = true): self return $this; } - - /** - * @param mixed $defaultValue - * @return mixed - */ - public function getSessionData(?string $key = null, $defaultValue = null) + public function getSessionData(?string $key = null, mixed $defaultValue = null): mixed { - $getValue = function() use ($key, $defaultValue) { - return ($key !== null ? $this->gridSession[$key] : $this->gridSession) ?? $defaultValue; - }; + $getValue = fn () => ($key !== null ? $this->gridSession[$key] : $this->gridSession) ?? $defaultValue; if ($this->rememberState) { return ($getValue)(); @@ -2665,11 +2342,7 @@ public function getSessionData(?string $key = null, $defaultValue = null) : $defaultValue; } - - /** - * @param mixed $value - */ - public function saveSessionData(string $key, $value): void + public function saveSessionData(string $key, mixed $value): void { if ($this->rememberState) { $this->gridSession[$key] = $value; @@ -2678,7 +2351,6 @@ public function saveSessionData(string $key, $value): void } } - public function deleteSessionData(string $key): void { unset($this->gridSession[$key]); @@ -2697,14 +2369,13 @@ public function getItemsDetail(): ?ItemDetail return $this->itemsDetail; } - /** * @param mixed $detail callable|string|bool */ - public function setItemsDetail($detail = true, ?string $primaryWhereColumn = null): ItemDetail + public function setItemsDetail(mixed $detail = true, ?string $primaryWhereColumn = null): ItemDetail { if ($this->isSortable()) { - throw new DataGridException('You can not use both sortable datagrid and items detail.'); + throw new DatagridException('You can not use both sortable datagrid and items detail.'); } $this->itemsDetail = new ItemDetail($this, $primaryWhereColumn ?? $this->primaryKey); @@ -2730,13 +2401,12 @@ public function setItemsDetail($detail = true, ?string $primaryWhereColumn = nul $this->itemsDetail->setType('block'); } else { - throw new DataGridException('::setItemsDetail() can be called either with no parameters or with parameter = template path or callable renderer.'); + throw new DatagridException('::setItemsDetail() can be called either with no parameters or with parameter = template path or callable renderer.'); } return $this->itemsDetail; } - /** * @return static */ @@ -2750,10 +2420,9 @@ public function setItemsDetailForm(callable $callableSetContainer): self return $this; } - throw new DataGridException('Please set the ItemDetail first.'); + throw new DatagridException('Please set the ItemDetail first.'); } - public function getItemDetailForm(): ?Container { if ($this->itemsDetail instanceof ItemDetail) { @@ -2763,7 +2432,6 @@ public function getItemDetailForm(): ?Container return null; } - /******************************************************************************** * ROW PRIVILEGES * ********************************************************************************/ @@ -2772,21 +2440,18 @@ public function allowRowsGroupAction(callable $condition): void $this->rowConditions['group_action'] = $condition; } - public function allowRowsInlineEdit(callable $condition): void { $this->rowConditions['inline_edit'] = $condition; } - public function allowRowsAction(string $key, callable $condition): void { $this->rowConditions['action'][$key] = $condition; } - /** - * @throws DataGridException + * @throws DatagridException */ public function allowRowsMultiAction( string $multiActionKey, @@ -2795,13 +2460,13 @@ public function allowRowsMultiAction( ): void { if (!isset($this->actions[$multiActionKey])) { - throw new DataGridException( + throw new DatagridException( sprintf('There is no action at key [%s] defined.', $multiActionKey) ); } if (!$this->actions[$multiActionKey] instanceof MultiAction) { - throw new DataGridException( + throw new DatagridException( sprintf('Action at key [%s] is not a MultiAction.', $multiActionKey) ); } @@ -2809,11 +2474,7 @@ public function allowRowsMultiAction( $this->actions[$multiActionKey]->setRowCondition($actionKey, $condition); } - - /** - * @return bool|callable - */ - public function getRowCondition(string $name, ?string $key = null) + public function getRowCondition(string $name, ?string $key = null): bool|callable { if (!isset($this->rowConditions[$name])) { return false; @@ -2828,7 +2489,6 @@ public function getRowCondition(string $name, ?string $key = null) return $condition[$key] ?? false; } - /******************************************************************************** * COLUMN CALLBACK * ********************************************************************************/ @@ -2837,13 +2497,11 @@ public function addColumnCallback(string $key, callable $callback): void $this->columnCallbacks[$key] = $callback; } - public function getColumnCallback(string $key): ?callable { return $this->columnCallbacks[$key] ?? null; } - /******************************************************************************** * INLINE EDIT * ********************************************************************************/ @@ -2854,13 +2512,11 @@ public function addInlineEdit(?string $primaryWhereColumn = null): InlineEdit return $this->inlineEdit; } - public function getInlineEdit(): ?InlineEdit { return $this->inlineEdit; } - public function handleShowInlineAdd(): void { if ($this->inlineAdd !== null) { @@ -2879,11 +2535,7 @@ public function handleShowInlineAdd(): void } } - - /** - * @param mixed $id - */ - public function handleInlineEdit($id): void + public function handleInlineEdit(mixed $id): void { if ($this->inlineEdit !== null) { $this->inlineEdit->setItemId($id); @@ -2894,7 +2546,7 @@ public function handleInlineEdit($id): void $inlineEditContainer = $filterContainer['inline_edit']; if (!$inlineEditContainer instanceof Container) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $inlineEditContainer->addHidden('_id', $id); @@ -2911,7 +2563,6 @@ public function handleInlineEdit($id): void } } - /******************************************************************************** * INLINE ADD * ********************************************************************************/ @@ -2920,13 +2571,12 @@ public function addInlineAdd(): InlineAdd $this->inlineAdd = new InlineAdd($this); $this->inlineAdd - ->setTitle('ublaboo_datagrid.add') + ->setTitle('contributte_datagrid.add') ->setIcon('plus'); return $this->inlineAdd; } - public function getInlineAdd(): ?InlineAdd { return $this->inlineAdd; @@ -2945,7 +2595,6 @@ public function canHideColumns(): bool return $this->canHideColumns; } - /** * Order Grid to set columns hideable. * @@ -2958,7 +2607,6 @@ public function setColumnsHideable(): self return $this; } - /******************************************************************************** * COLUMNS SUMMARY * ********************************************************************************/ @@ -2967,14 +2615,13 @@ public function hasColumnsSummary(): bool return $this->columnsSummary instanceof ColumnsSummary; } - /** * @param array|string[] $columns */ public function setColumnsSummary(array $columns, ?callable $rowCallback = null): ColumnsSummary { if ($this->hasSomeAggregationFunction()) { - throw new DataGridException('You can use either ColumnsSummary or AggregationFunctions'); + throw new DatagridException('You can use either ColumnsSummary or AggregationFunctions'); } $this->columnsSummary = new ColumnsSummary($this, $columns, $rowCallback); @@ -2982,7 +2629,6 @@ public function setColumnsSummary(array $columns, ?callable $rowCallback = null) return $this->columnsSummary; } - public function getColumnsSummary(): ?ColumnsSummary { return $this->columnsSummary; @@ -2995,18 +2641,18 @@ public function getColumnsSummary(): ?ColumnsSummary /** * Gets component's full name in component tree - * @throws DataGridHasToBeAttachedToPresenterComponentException + * + * @throws DatagridHasToBeAttachedToPresenterComponentException */ public function getFullName(): string { if ($this->componentFullName === null) { - throw new DataGridHasToBeAttachedToPresenterComponentException('Datagrid needs to be attached to presenter in order to get its full name.'); + throw new DatagridHasToBeAttachedToPresenterComponentException('Datagrid needs to be attached to presenter in order to get its full name.'); } return $this->componentFullName; } - /** * Tell grid filters to by submitted automatically * @@ -3019,17 +2665,15 @@ public function setAutoSubmit(bool $autoSubmit = true): self return $this; } - public function hasAutoSubmit(): bool { return $this->autoSubmit; } - public function getFilterSubmitButton(): SubmitButton { if ($this->hasAutoSubmit()) { - throw new DataGridException('DataGrid has auto-submit. Turn it off before setting filter submit button.'); + throw new DatagridException('Datagrid has auto-submit. Turn it off before setting filter submit button.'); } if ($this->filterSubmitButton === null) { @@ -3049,7 +2693,7 @@ public function getFilterSubmitButton(): SubmitButton */ public function getColumnsCount(): int { - $count = sizeof($this->getColumns()); + $count = count($this->getColumns()); if ($this->actions !== [] || $this->isSortable() @@ -3066,7 +2710,6 @@ public function getColumnsCount(): int return $count; } - /** * @internal */ @@ -3075,7 +2718,6 @@ public function getPrimaryKey(): string return $this->primaryKey; } - /** * @return array * @internal @@ -3113,13 +2755,13 @@ public function getColumns(): array unset($return[$column]); } } - } catch (DataGridHasToBeAttachedToPresenterComponentException $e) { + } catch (DatagridHasToBeAttachedToPresenterComponentException) { + // No need to worry } return $return; } - /** * @internal */ @@ -3134,7 +2776,6 @@ public function getColumnsVisibility(): array return $return; } - /** * @internal */ @@ -3143,10 +2784,10 @@ public function getParentComponent(): Component $parent = parent::getParent(); if (!$parent instanceof Component) { - throw new DataGridHasToBeAttachedToPresenterComponentException( + throw new DatagridHasToBeAttachedToPresenterComponentException( sprintf( - 'DataGrid is attached to: "%s", but instance of %s is needed.', - ($parent !== null ? get_class($parent) : 'null'), + 'Datagrid is attached to: "%s", but instance of %s is needed.', + ($parent !== null ? $parent::class : 'null'), Component::class ) ); @@ -3155,10 +2796,9 @@ public function getParentComponent(): Component return $parent; } - /** * @internal - * @throws \UnexpectedValueException + * @throws UnexpectedValueException */ public function getSortableParentPath(): string { @@ -3169,7 +2809,7 @@ public function getSortableParentPath(): string $presenter = $this->getParentComponent()->lookupPath(IPresenter::class, false); if ($presenter === null) { - throw new \UnexpectedValueException( + throw new UnexpectedValueException( sprintf('%s needs %s', self::class, IPresenter::class) ); } @@ -3177,7 +2817,6 @@ public function getSortableParentPath(): string return $presenter; } - /** * Some of datagrid columns may be hidden by default * @@ -3191,7 +2830,6 @@ public function setSomeColumnDefaultHide(bool $defaultHide): self return $this; } - /** * Are some of columns hidden bydefault? * @@ -3202,7 +2840,6 @@ public function hasSomeColumnDefaultHide(): bool return $this->someColumnDefaultHide; } - /** * Simply refresh url * @@ -3219,7 +2856,6 @@ public function handleRefreshState(): void $this->redrawControl('non-existing-snippet'); } - /** * @internal */ @@ -3228,7 +2864,6 @@ public function setCustomPaginatorTemplate(string $templateFile): void $this->customPaginatorTemplate = $templateFile; } - protected function createSorting(array $sort, ?callable $sortCallback = null): Sorting { foreach ($sort as $key => $order) { @@ -3241,7 +2876,7 @@ protected function createSorting(array $sort, ?callable $sortCallback = null): S try { $column = $this->getColumn($key); - } catch (DataGridColumnNotFoundException $e) { + } catch (DatagridColumnNotFoundException) { continue; } @@ -3255,14 +2890,13 @@ protected function createSorting(array $sort, ?callable $sortCallback = null): S return new Sorting($sort, $sortCallback); } - /** - * @throws DataGridException + * @throws DatagridException */ protected function addColumn(string $key, Column $column): Column { if (isset($this->columns[$key])) { - throw new DataGridException( + throw new DatagridException( sprintf('There is already column at key [%s] defined.', $key) ); } @@ -3274,46 +2908,39 @@ protected function addColumn(string $key, Column $column): Column return $this->columns[$key] = $column; } - /** * Check whether given key already exists in $this->filters * - * @throws DataGridException + * @throws DatagridException */ protected function addActionCheck(string $key): void { if (isset($this->actions[$key])) { - throw new DataGridException( + throw new DatagridException( sprintf('There is already action at key [%s] defined.', $key) ); } }/******************************************************************************** - * FILTERS * - ********************************************************************************/ - + * FILTERS * + ********************************************************************************/ /** * Check whether given key already exists in $this->filters * - * @throws DataGridException + * @throws DatagridException */ protected function addFilterCheck(string $key): void { if (isset($this->filters[$key])) { - throw new DataGridException( + throw new DatagridException( sprintf('There is already action at key [%s] defined.', $key) ); } } - protected function addToExports(Export $export): Export { - if (sizeof($this->exports) > 0) { - $id = sizeof($this->exports) + 1; - } else { - $id = 1; - } + $id = count($this->exports) > 0 ? count($this->exports) + 1 : 1; $link = new Link($this, 'export!', ['id' => $id]); @@ -3322,7 +2949,6 @@ protected function addToExports(Export $export): Export return $this->exports[$id] = $export; } - private function getPresenterInstance(): Presenter { return $this->getPresenter(); diff --git a/src/Exception/DataGridActionCallbackException.php b/src/Exception/DataGridActionCallbackException.php deleted file mode 100644 index cbc66b25a..000000000 --- a/src/Exception/DataGridActionCallbackException.php +++ /dev/null @@ -1,12 +0,0 @@ -grid = $grid; $this->text = $text; $this->callback = $callback; - $this->filtered = $filtered; $this->title = $text; } - public function render(): Html { $a = Html::el('a', [ @@ -106,7 +73,6 @@ public function render(): Html return $a; } - /** * @return static */ @@ -117,7 +83,6 @@ public function setConfirmDialog(string $confirmDialog): self return $this; } - /** * Tell export which columns to use when exporting data * @@ -130,7 +95,6 @@ public function setColumns(array $columns): self return $this; } - /** * Get columns for export */ @@ -139,7 +103,6 @@ public function getColumns(): array return $this->columns; } - /** * Export signal url * @@ -152,7 +115,6 @@ public function setLink(Link $link): self return $this; } - /** * Tell export whether to be called via ajax or not * @@ -165,13 +127,11 @@ public function setAjax(bool $ajax = true): self return $this; } - public function isAjax(): bool { return $this->ajax; } - /** * Is export filtered? */ @@ -180,7 +140,6 @@ public function isFiltered(): bool return $this->filtered; } - /** * Call export callback */ @@ -189,15 +148,14 @@ public function invoke(iterable $data): void ($this->callback)($data, $this->grid); } - /** * Adds target to html:a [_blank, _self, _parent, _top] - * @param string|null $target */ - public function setTarget($target = null): void + public function setTarget(?string $target = null): void { if (in_array($target, ['_blank', '_self', '_parent', '_top'], true)) { $this->target = $target; } } + } diff --git a/src/Export/ExportCsv.php b/src/Export/ExportCsv.php index 9e219fac2..eb84ddfda 100644 --- a/src/Export/ExportCsv.php +++ b/src/Export/ExportCsv.php @@ -1,18 +1,16 @@ -getColumns(); if ($columns === []) { @@ -62,4 +64,5 @@ private function getExportCallback( )); }; } + } diff --git a/src/Filter/Filter.php b/src/Filter/Filter.php index 18e13813b..6ba00ab5d 100644 --- a/src/Filter/Filter.php +++ b/src/Filter/Filter.php @@ -1,86 +1,39 @@ - ['form-control', 'input-sm', 'form-control-sm'], + protected array $attributes = [ + 'class' => ['form-control', 'form-control-sm'], ]; - /** - * @var string|null - */ - private $placeholder; - - - abstract public function getCondition(): array; - + private ?string $placeholder = null; - public function __construct( - DataGrid $grid, - string $key, - string $name - ) + public function __construct(protected Datagrid $grid, protected string $key, protected string $name) { - $this->grid = $grid; - $this->key = $key; - $this->name = $name; } + abstract public function getCondition(): array; /** * Get filter key @@ -90,7 +43,6 @@ public function getKey(): string return $this->key; } - /** * Get filter name */ @@ -99,7 +51,6 @@ public function getName(): string return $this->name; } - /** * Tell whether value has been set in this fitler */ @@ -108,12 +59,10 @@ public function isValueSet(): bool return $this->valueSet; } - /** - * @param mixed $value * @return static */ - public function setValue($value): self + public function setValue(mixed $value): self { $this->value = $value; $this->valueSet = true; @@ -121,16 +70,11 @@ public function setValue($value): self return $this; } - - /** - * @return mixed - */ - public function getValue() + public function getValue(): mixed { return $this->value; } - /** * Set HTML attribute "placeholder" * @@ -143,13 +87,11 @@ public function setPlaceholder(string $placeholder): self return $this; } - public function getPlaceholder(): ?string { return $this->placeholder; } - /** * Set custom condition on filter * @@ -162,13 +104,11 @@ public function setCondition(callable $conditionCallback): self return $this; } - public function getConditionCallback(): ?callable { return $this->conditionCallback; } - /** * @return static */ @@ -179,55 +119,47 @@ public function setTemplate(string $template): self return $this; } - public function getTemplate(): ?string { return $this->template; } - public function getType(): ?string { return $this->type; } - /** - * @param mixed $value * @return static */ - public function addAttribute(string $name, $value): self + public function addAttribute(string $name, mixed $value): self { $this->attributes[$name][] = $value; return $this; } - /** - * @param mixed $value * @return static */ - public function setAttribute(string $name, $value): self + public function setAttribute(string $name, mixed $value): self { $this->attributes[$name] = (array) $value; return $this; } - public function getAttributes(): array { return $this->attributes; } - protected function addAttributes(BaseControl $input): BaseControl { if ($this->grid->hasAutoSubmit()) { - $input->setAttribute('data-autosubmit', true); + $input->setHtmlAttribute('data-autosubmit', true); } else { - $input->setAttribute('data-datagrid-manualsubmit', true); + $input->setHtmlAttribute('data-datagrid-manualsubmit', true); } foreach ($this->attributes as $key => $value) { @@ -236,7 +168,7 @@ protected function addAttributes(BaseControl $input): BaseControl $value = implode(' ', $value); } - $input->setAttribute($key, $value); + $input->setHtmlAttribute($key, $value); } return $input; diff --git a/src/Filter/FilterDate.php b/src/Filter/FilterDate.php index d000d4f0e..171211a36 100644 --- a/src/Filter/FilterDate.php +++ b/src/Filter/FilterDate.php @@ -1,51 +1,39 @@ -addText($this->key, $this->name); - $control->setAttribute('data-provide', 'datepicker') - ->setAttribute('data-date-orientation', 'bottom') - ->setAttribute('data-date-format', $this->getJsFormat()) - ->setAttribute('data-date-today-highlight', 'true') - ->setAttribute('data-date-autoclose', 'true'); + $control->setHtmlAttribute('data-provide', 'datepicker') + ->setHtmlAttribute('data-date-orientation', 'bottom') + ->setHtmlAttribute('data-date-format', $this->getJsFormat()) + ->setHtmlAttribute('data-date-today-highlight', 'true') + ->setHtmlAttribute('data-date-autoclose', 'true'); $this->addAttributes($control); if ($this->grid->hasAutoSubmit()) { - $control->setAttribute('data-autosubmit-change', true); + $control->setHtmlAttribute('data-autosubmit-change', true); } if ($this->getPlaceholder() !== null) { - $control->setAttribute('placeholder', $this->getPlaceholder()); + $control->setHtmlAttribute('placeholder', $this->getPlaceholder()); } } - /** * Set format for datepicker etc */ @@ -56,7 +44,6 @@ public function setFormat(string $phpFormat, string $jsFormat): IFilterDate return $this; } - /** * Get php format for datapicker */ @@ -65,7 +52,6 @@ public function getPhpFormat(): string return $this->format[0]; } - /** * Get js format for datepicker */ diff --git a/src/Filter/FilterDateRange.php b/src/Filter/FilterDateRange.php index 83ef35186..37916f1fc 100644 --- a/src/Filter/FilterDateRange.php +++ b/src/Filter/FilterDateRange.php @@ -1,28 +1,17 @@ -addText('from', $this->name); - $from->setAttribute('data-provide', 'datepicker') - ->setAttribute('data-date-orientation', 'bottom') - ->setAttribute('data-date-format', $this->getJsFormat()) - ->setAttribute('data-date-today-highlight', 'true') - ->setAttribute('data-date-autoclose', 'true'); + $from->setHtmlAttribute('data-provide', 'datepicker') + ->setHtmlAttribute('data-date-orientation', 'bottom') + ->setHtmlAttribute('data-date-format', $this->getJsFormat()) + ->setHtmlAttribute('data-date-today-highlight', 'true') + ->setHtmlAttribute('data-date-autoclose', 'true'); $to = $container->addText('to', $this->nameSecond); - $to->setAttribute('data-provide', 'datepicker') - ->setAttribute('data-date-orientation', 'bottom') - ->setAttribute('data-date-format', $this->getJsFormat()) - ->setAttribute('data-date-today-highlight', 'true') - ->setAttribute('data-date-autoclose', 'true'); + $to->setHtmlAttribute('data-provide', 'datepicker') + ->setHtmlAttribute('data-date-orientation', 'bottom') + ->setHtmlAttribute('data-date-format', $this->getJsFormat()) + ->setHtmlAttribute('data-date-today-highlight', 'true') + ->setHtmlAttribute('data-date-autoclose', 'true'); $this->addAttributes($from); $this->addAttributes($to); if ($this->grid->hasAutoSubmit()) { - $from->setAttribute('data-autosubmit-change', true); - $to->setAttribute('data-autosubmit-change', true); + $from->setHtmlAttribute('data-autosubmit-change', true); + $to->setHtmlAttribute('data-autosubmit-change', true); } $placeholders = $this->getPlaceholders(); @@ -61,18 +50,17 @@ public function addToFormContainer(Container $container): void $textFrom = reset($placeholders); if ($textFrom) { - $from->setAttribute('placeholder', $textFrom); + $from->setHtmlAttribute('placeholder', $textFrom); } $textTo = end($placeholders); if ($textTo && ($textTo !== $textFrom)) { - $to->setAttribute('placeholder', $textTo); + $to->setHtmlAttribute('placeholder', $textTo); } } } - /** * Set format for datepicker etc */ @@ -83,7 +71,6 @@ public function setFormat(string $phpFormat, string $jsFormat): IFilterDate return $this; } - /** * Get php format for datapicker */ @@ -92,7 +79,6 @@ public function getPhpFormat(): string return $this->format[0]; } - /** * Get js format for datepicker */ diff --git a/src/Filter/FilterMultiSelect.php b/src/Filter/FilterMultiSelect.php index 0707aca0c..b41fb6937 100644 --- a/src/Filter/FilterMultiSelect.php +++ b/src/Filter/FilterMultiSelect.php @@ -1,34 +1,25 @@ - ['form-control', 'input-sm', 'selectpicker', 'form-control-sm'], + protected array $attributes = [ + 'class' => ['form-select', 'selectpicker', 'form-select-sm'], 'data-selected-text-format' => ['count'], ]; - public function __construct( - DataGrid $grid, + Datagrid $grid, string $key, string $name, array $options, @@ -37,10 +28,9 @@ public function __construct( { parent::__construct($grid, $key, $name, $options, $column); - $this->addAttribute('data-selected-icon-check', DataGrid::$iconPrefix . 'check'); + $this->addAttribute('data-selected-icon-check', Datagrid::$iconPrefix . 'check'); } - /** * Get filter condition */ @@ -55,7 +45,6 @@ public function getCondition(): array return $return; } - protected function addControl( Container $container, string $key, @@ -66,7 +55,7 @@ protected function addControl( /** * Set some translated texts */ - $form = $container->lookup('Nette\Application\UI\Form'); + $form = $container->lookup(Form::class); if (!$form instanceof Form) { throw new UnexpectedValueException(); @@ -80,11 +69,11 @@ protected function addControl( $this->addAttribute( 'title', - $translator->translate('ublaboo_datagrid.multiselect_choose') + $translator->translate('contributte_datagrid.multiselect_choose') ); $this->addAttribute( 'data-i18n-selected', - $translator->translate('ublaboo_datagrid.multiselect_selected') + $translator->translate('contributte_datagrid.multiselect_selected') ); /** @@ -96,4 +85,5 @@ protected function addControl( return $input; } + } diff --git a/src/Filter/FilterRange.php b/src/Filter/FilterRange.php index 48c91d80a..c796d5ef8 100644 --- a/src/Filter/FilterRange.php +++ b/src/Filter/FilterRange.php @@ -1,50 +1,30 @@ -nameSecond = $nameSecond; } - public function addToFormContainer(Container $container): void { $container = $container->addContainer($this->key); @@ -61,18 +41,17 @@ public function addToFormContainer(Container $container): void $text_from = reset($placeholders); if ($text_from) { - $from->setAttribute('placeholder', $text_from); + $from->setHtmlAttribute('placeholder', $text_from); } $text_to = end($placeholders); if ($text_to && ($text_to !== $text_from)) { - $to->setAttribute('placeholder', $text_to); + $to->setHtmlAttribute('placeholder', $text_to); } } } - /** * Set html attr placeholder of both inputs * @@ -85,7 +64,6 @@ public function setPlaceholders(array $placeholders): self return $this; } - /** * Get html attr placeholders */ @@ -94,7 +72,6 @@ public function getPlaceholders(): array return $this->placeholders; } - /** * Get filter condition */ @@ -109,4 +86,5 @@ public function getCondition(): array ], ]; } + } diff --git a/src/Filter/FilterSelect.php b/src/Filter/FilterSelect.php index 56ade6aa6..2cf8c51bb 100644 --- a/src/Filter/FilterSelect.php +++ b/src/Filter/FilterSelect.php @@ -1,58 +1,39 @@ - ['form-select', 'form-select-sm'], + ]; - /** - * @var string - */ - protected $template = 'datagrid_filter_select.latte'; + protected ?string $template = 'datagrid_filter_select.latte'; - /** - * @var string - */ - protected $type = 'select'; - - /** - * @var string|null - */ - protected $prompt = null; + protected ?string $type = 'select'; + protected ?string $prompt = null; public function __construct( - DataGrid $grid, + Datagrid $grid, string $key, string $name, - array $options, + protected array $options, string $column ) { parent::__construct($grid, $key, $name, $column); - - $this->options = $options; } - public function addToFormContainer(Container $container): void { $form = $container->lookup(Form::class); @@ -74,7 +55,6 @@ public function addToFormContainer(Container $container): void } } - /** * @return static */ @@ -85,31 +65,26 @@ public function setTranslateOptions(bool $translateOptions = true): self return $this; } - public function getOptions(): array { return $this->options; } - public function getTranslateOptions(): bool { return $this->translateOptions; } - public function getCondition(): array { return [$this->column => $this->getValue()]; } - public function getPrompt(): ?string { return $this->prompt; } - /** * @return static */ @@ -120,7 +95,6 @@ public function setPrompt(?string $prompt): self return $this; } - protected function addControl( Container $container, string $key, @@ -138,4 +112,5 @@ protected function addControl( return $input; } + } diff --git a/src/Filter/FilterText.php b/src/Filter/FilterText.php index 3860d7984..664becb58 100644 --- a/src/Filter/FilterText.php +++ b/src/Filter/FilterText.php @@ -1,56 +1,34 @@ -columns = $columns; } - /** * Adds text field to filter form */ @@ -61,11 +39,10 @@ public function addToFormContainer(Container $container): void $this->addAttributes($control); if ($this->getPlaceholder() !== null) { - $control->setAttribute('placeholder', $this->getPlaceholder()); + $control->setHtmlAttribute('placeholder', $this->getPlaceholder()); } } - /** * Return array of conditions to put in result [column1 => value, column2 => value] * If more than one column exists in fitler text, @@ -77,13 +54,11 @@ public function getCondition(): array return array_fill_keys($this->columns, $this->getValue()); } - public function isExactSearch(): bool { return $this->exact; } - /** * @return static */ @@ -94,7 +69,6 @@ public function setExactSearch(bool $exact = true): self return $this; } - /** * @return static */ @@ -105,9 +79,9 @@ public function setSplitWordsSearch(bool $splitWordsSearch): self return $this; } - public function hasSplitWordsSearch(): bool { return $this->splitWordsSearch; } + } diff --git a/src/Filter/IFilterDate.php b/src/Filter/IFilterDate.php index cfe8b9f17..2e1534af0 100644 --- a/src/Filter/IFilterDate.php +++ b/src/Filter/IFilterDate.php @@ -1,8 +1,6 @@ -column = $column; } - /** * Get filter column */ @@ -36,9 +25,9 @@ public function getColumn(): string return $this->column; } - public function getCondition(): array { return [$this->column => $this->getValue()]; } + } diff --git a/src/Filter/SubmitButton.php b/src/Filter/SubmitButton.php index 72dce15fa..d43918bd2 100644 --- a/src/Filter/SubmitButton.php +++ b/src/Filter/SubmitButton.php @@ -1,17 +1,16 @@ -text); - $this->grid = $grid; - - $this->text = 'ublaboo_datagrid.filter_submit_button'; + $this->text = 'contributte_datagrid.filter_submit_button'; $this->class = 'btn btn-sm btn-primary'; $this->icon = 'search'; $this->control = Html::el('button', ['type' => 'submit', 'name' => 'submit']); } - - /** - * @param string|object $caption - */ - public function getControl($caption = null): Html + public function getControl(Stringable|string|null $caption = null): Html { $el = parent::getControl($caption); @@ -56,7 +43,7 @@ public function getControl($caption = null): Html $el->addHtml( Html::el('span')->appendAttribute( 'class', - DataGrid::$iconPrefix . $this->getIcon() + Datagrid::$iconPrefix . $this->getIcon() ) ); @@ -69,4 +56,5 @@ public function getControl($caption = null): Html return $el; } + } diff --git a/src/GroupAction/GroupAction.php b/src/GroupAction/GroupAction.php index cd343fb88..e233d7372 100644 --- a/src/GroupAction/GroupAction.php +++ b/src/GroupAction/GroupAction.php @@ -1,8 +1,6 @@ -title = $title; } - public function getTitle(): string { return $this->title; } - /** * @return static */ @@ -57,27 +38,24 @@ public function setClass(string $class): self return $this; } - public function getClass(): string { return $this->class; } - /** - * @param mixed $value * @return static */ - public function setAttribute(string $key, $value): self + public function setAttribute(string $key, mixed $value): self { $this->attributes[$key] = $value; return $this; } - public function getAttributes(): array { return $this->attributes; } + } diff --git a/src/GroupAction/GroupActionCollection.php b/src/GroupAction/GroupActionCollection.php index 488ef61e1..26db2bcb7 100644 --- a/src/GroupAction/GroupActionCollection.php +++ b/src/GroupAction/GroupActionCollection.php @@ -1,39 +1,28 @@ - - */ - protected $groupActions = []; - - /** - * @var DataGrid - */ - protected $datagrid; + /** @var array */ + protected array $groupActions = []; - - public function __construct(DataGrid $datagrid) + public function __construct(protected Datagrid $datagrid) { - $this->datagrid = $datagrid; } - public function addToFormContainer(Container $container): void { /** @var Form $form */ @@ -43,7 +32,7 @@ public function addToFormContainer(Container $container): void $main_options = []; if ($translator === null) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } /** @@ -56,13 +45,13 @@ public function addToFormContainer(Container $container): void /** * User may set a class to the form control */ - $control->setAttribute('class', $action->getClass()); + $control->setHtmlAttribute('class', $action->getClass()); /** * User may set additional attribtues to the form control */ foreach ($action->getAttributes() as $name => $value) { - $control->setAttribute($name, $value); + $control->setHtmlAttribute($name, $value); } } } @@ -77,7 +66,7 @@ public function addToFormContainer(Container $container): void } $groupActionSelect = $container->addSelect('group_action', '', $main_options) - ->setPrompt('ublaboo_datagrid.choose'); + ->setPrompt('contributte_datagrid.choose'); /** * Third for creating select for each "sub"-action @@ -89,60 +78,60 @@ public function addToFormContainer(Container $container): void if ($action->hasOptions()) { if ($action instanceof GroupMultiSelectAction) { $control = $container->addMultiSelect((string) $id, '', $action->getOptions()); - $control->setAttribute('data-datagrid-multiselect-id', $lookupPath . self::ID_ATTRIBUTE_PREFIX . $id); - $control->setAttribute('data-style', 'hidden'); - $control->setAttribute('data-selected-icon-check', DataGrid::$iconPrefix . 'check'); + $control->setHtmlAttribute('data-datagrid-multiselect-id', $lookupPath . self::ID_ATTRIBUTE_PREFIX . $id); + $control->setHtmlAttribute('data-style', 'hidden'); + $control->setHtmlAttribute('data-selected-icon-check', Datagrid::$iconPrefix . 'check'); } else { $control = $container->addSelect((string) $id, '', $action->getOptions()); } - $control->setAttribute('id', $lookupPath . self::ID_ATTRIBUTE_PREFIX . $id); + $control->setHtmlAttribute('id', $lookupPath . self::ID_ATTRIBUTE_PREFIX . $id); } } elseif ($action instanceof GroupTextAction) { $control = $container->addText((string) $id, ''); - $control->setAttribute('id', $lookupPath . self::ID_ATTRIBUTE_PREFIX . $id) - ->addConditionOn($groupActionSelect, Form::EQUAL, $id) - ->setRequired('ublaboo_datagrid.choose_input_required') + $control->setHtmlAttribute('id', $lookupPath . self::ID_ATTRIBUTE_PREFIX . $id) + ->addConditionOn($groupActionSelect, Form::Equal, $id) + ->setRequired('contributte_datagrid.choose_input_required') ->endCondition(); } elseif ($action instanceof GroupTextareaAction) { $control = $container->addTextArea((string) $id, ''); - $control->setAttribute('id', $lookupPath . self::ID_ATTRIBUTE_PREFIX . $id) - ->addConditionOn($groupActionSelect, Form::EQUAL, $id) - ->setRequired('ublaboo_datagrid.choose_input_required'); + $control->setHtmlAttribute('id', $lookupPath . self::ID_ATTRIBUTE_PREFIX . $id) + ->addConditionOn($groupActionSelect, Form::Equal, $id) + ->setRequired('contributte_datagrid.choose_input_required'); } if (isset($control)) { /** * User may set a class to the form control */ - $control->setAttribute('class', $action->getClass()); + $control->setHtmlAttribute('class', $action->getClass()); /** * User may set additional attribtues to the form control */ foreach ($action->getAttributes() as $name => $value) { - $control->setAttribute($name, $value); + $control->setHtmlAttribute($name, $value); } } } if ($main_options !== []) { foreach (array_keys($this->groupActions) as $id) { - $groupActionSelect->addCondition(Form::EQUAL, $id) + $groupActionSelect->addCondition(Form::Equal, $id) ->toggle($lookupPath . self::ID_ATTRIBUTE_PREFIX . $id); } - $groupActionSelect->addCondition(Form::FILLED) + $groupActionSelect->addCondition(Form::Filled) ->toggle( strtolower($this->datagrid->getFullName()) . 'group_action_submit' ); - $container->addSubmit('submit', 'ublaboo_datagrid.execute') + $container->addSubmit('submit', 'contributte_datagrid.execute') ->setValidationScope([$container]) - ->setAttribute( + ->setHtmlAttribute( 'id', strtolower($this->datagrid->getFullName()) . 'group_action_submit' ); @@ -155,7 +144,6 @@ public function addToFormContainer(Container $container): void }; } - /** * Pass "sub"-form submission forward to custom submit function */ @@ -176,11 +164,8 @@ public function submitted(NetteForm $form): void return; } - /** - * @todo Define items IDs - */ $httpIds = $form->getHttpData( - Form::DATA_LINE | Form::DATA_KEYS, + Form::DataLine | Form::DataKeys, strtolower($this->datagrid->getFullName()) . '_group_action_item[]' ); @@ -191,12 +176,12 @@ public function submitted(NetteForm $form): void $this->groupActions[$id]->onSelect($ids, $values[$id] ?? null); if (!$form['group_action'] instanceof Container) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } if (isset($form['group_action']['group_action'])) { if (!$form['group_action']['group_action'] instanceof SelectBox) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } $form['group_action']['group_action']->setValue(null); @@ -205,89 +190,63 @@ public function submitted(NetteForm $form): void $groupButtonAction = $this->groupActions[$submitter->getName()]; if (!$groupButtonAction instanceof GroupButtonAction) { - throw new \UnexpectedValueException('This action is supposed to be a GroupButtonAction'); + throw new UnexpectedValueException('This action is supposed to be a GroupButtonAction'); } $groupButtonAction->onClick($ids); } } - /** * Add one group button action to collection of actions */ public function addGroupButtonAction(string $title, ?string $class = null): GroupButtonAction { - if (count($this->groupActions) > 0) { - $id = count($this->groupActions) + 1; - } else { - $id = 1; - } + $id = count($this->groupActions) > 0 ? count($this->groupActions) + 1 : 1; return $this->groupActions[$id] = new GroupButtonAction($title, $class); } - /** * Add one group action (select box) to collection of actions */ public function addGroupSelectAction(string $title, array $options): GroupAction { - if (count($this->groupActions) > 0) { - $id = count($this->groupActions) + 1; - } else { - $id = 1; - } + $id = count($this->groupActions) > 0 ? count($this->groupActions) + 1 : 1; return $this->groupActions[$id] = new GroupSelectAction($title, $options); } - /** * Add one group action (multiselect box) to collection of actions */ public function addGroupMultiSelectAction(string $title, array $options): GroupAction { - if (count($this->groupActions) > 0) { - $id = count($this->groupActions) + 1; - } else { - $id = 1; - } + $id = count($this->groupActions) > 0 ? count($this->groupActions) + 1 : 1; return $this->groupActions[$id] = new GroupMultiSelectAction($title, $options); } - /** * Add one group action (text input) to collection of actions */ public function addGroupTextAction(string $title): GroupAction { - if (count($this->groupActions) > 0) { - $id = count($this->groupActions) + 1; - } else { - $id = 1; - } + $id = count($this->groupActions) > 0 ? count($this->groupActions) + 1 : 1; return $this->groupActions[$id] = new GroupTextAction($title); } - /** * Add one group action (textarea) to collection of actions */ public function addGroupTextareaAction(string $title): GroupAction { - if (count($this->groupActions) > 0) { - $id = count($this->groupActions) + 1; - } else { - $id = 1; - } + $id = count($this->groupActions) > 0 ? count($this->groupActions) + 1 : 1; return $this->groupActions[$id] = new GroupTextareaAction($title); } - public function getGroupAction(string $title): GroupAction { foreach ($this->groupActions as $action) { @@ -296,21 +255,20 @@ public function getGroupAction(string $title): GroupAction } } - throw new DataGridGroupActionException("Group action $title does not exist."); + throw new DatagridGroupActionException(sprintf('Group action %s does not exist.', $title)); } - private function getFormSubmitter(NetteForm $form): ?SubmitButton { $container = $form['group_action']; if (!$container instanceof Container) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } if (isset($container['submit'])) { if (!$container['submit'] instanceof SubmitButton) { - throw new \UnexpectedValueException; + throw new UnexpectedValueException(); } if ($container['submit']->isSubmittedBy()) { @@ -326,4 +284,5 @@ private function getFormSubmitter(NetteForm $form): ?SubmitButton return null; } + } diff --git a/src/GroupAction/GroupButtonAction.php b/src/GroupAction/GroupButtonAction.php index ea9bd0e1c..9a09dcd7b 100644 --- a/src/GroupAction/GroupButtonAction.php +++ b/src/GroupAction/GroupButtonAction.php @@ -1,8 +1,6 @@ -class = $class; } } diff --git a/src/GroupAction/GroupMultiSelectAction.php b/src/GroupAction/GroupMultiSelectAction.php index 52102b9ce..d8a9afdc1 100644 --- a/src/GroupAction/GroupMultiSelectAction.php +++ b/src/GroupAction/GroupMultiSelectAction.php @@ -1,8 +1,6 @@ -options = $options; } - public function getOptions(): array { return $this->options; } - /** * Has the action some options? */ @@ -34,4 +22,5 @@ public function hasOptions(): bool { return $this->options !== []; } + } diff --git a/src/GroupAction/GroupTextAction.php b/src/GroupAction/GroupTextAction.php index c09b50f80..10fb8d760 100644 --- a/src/GroupAction/GroupTextAction.php +++ b/src/GroupAction/GroupTextAction.php @@ -1,8 +1,6 @@ -shouldBeRendered; } - - + public function setShouldBeRendered(bool $shouldBeRendered): void { $this->shouldBeRendered = $shouldBeRendered; } + } diff --git a/src/InlineEdit/InlineEdit.php b/src/InlineEdit/InlineEdit.php index 087b5c7ee..4dc311633 100644 --- a/src/InlineEdit/InlineEdit.php +++ b/src/InlineEdit/InlineEdit.php @@ -1,26 +1,24 @@ -grid = $grid; - $this->primaryWhereColumn = $primaryWhereColumn; - - $this->title = 'ublaboo_datagrid.edit'; + $this->title = 'contributte_datagrid.edit'; $this->class = sprintf('btn btn-xs %s ajax', $grid::$btnSecondaryClass); $this->icon = 'pencil pencil-alt'; $this->onControlAfterAdd[] = [$this, 'addControlsClasses']; } - /** - * @param mixed $id * @return static */ - public function setItemId($id): self + public function setItemId(mixed $id): self { $this->itemID = $id; return $this; } - - /** - * @return mixed - */ - public function getItemId() + public function getItemId(): mixed { return $this->itemID; } - public function getPrimaryWhereColumn(): ?string { return $this->primaryWhereColumn; } - public function renderButton(Row $row): Html { $a = Html::el('a') @@ -144,7 +103,7 @@ public function renderButton(Row $row): Html ); } - if ($this->class !== null) { + if ($this->class !== '') { $a->appendAttribute('class', $this->class); } @@ -153,7 +112,6 @@ public function renderButton(Row $row): Html return $a; } - /** * Render row item detail button */ @@ -173,14 +131,13 @@ public function renderButtonAdd(): Html ); } - if ($this->class !== null) { + if ($this->class !== '') { $a->appendAttribute('class', $this->class); } return $a; } - /** * @return static */ @@ -191,19 +148,16 @@ public function setPositionTop(bool $positionTop = true): self return $this; } - public function isPositionTop(): bool { return $this->positionTop; } - public function isPositionBottom(): bool { return !$this->positionTop; } - public function addControlsClasses(Container $container): void { foreach ($container->getControls() as $key => $control) { @@ -213,14 +167,16 @@ public function addControlsClasses(Container $container): void $control->setAttribute('class', 'btn btn-xs btn-primary'); break; + case 'cancel': $control->setValidationScope([]); $control->setAttribute('class', 'btn btn-xs btn-danger'); break; + default: if ($control->getControl()->getAttribute('class') === null) { - $control->setAttribute('class', 'form-control input-sm form-control-sm'); + $control->setAttribute('class', 'form-control form-control-sm'); } break; @@ -228,7 +184,6 @@ public function addControlsClasses(Container $container): void } } - /** * @return static */ @@ -239,9 +194,9 @@ public function setShowNonEditingColumns(bool $show = true): self return $this; } - public function showNonEditingColumns(): bool { return $this->showNonEditingColumns; } + } diff --git a/src/Localization/SimpleTranslator.php b/src/Localization/SimpleTranslator.php index 1ff11bafd..7097edf99 100644 --- a/src/Localization/SimpleTranslator.php +++ b/src/Localization/SimpleTranslator.php @@ -1,66 +1,70 @@ - 'No items found. You can reset the filter', - 'ublaboo_datagrid.no_item_found' => 'No items found.', - 'ublaboo_datagrid.here' => 'here', - 'ublaboo_datagrid.items' => 'Items', - 'ublaboo_datagrid.all' => 'all', - 'ublaboo_datagrid.from' => 'from', - 'ublaboo_datagrid.reset_filter' => 'Reset filter', - 'ublaboo_datagrid.group_actions' => 'Group actions', - 'ublaboo_datagrid.show' => 'Show', - 'ublaboo_datagrid.add' => 'Add', - 'ublaboo_datagrid.edit' => 'Edit', - 'ublaboo_datagrid.show_all_columns' => 'Show all columns', - 'ublaboo_datagrid.show_default_columns' => 'Show default columns', - 'ublaboo_datagrid.hide_column' => 'Hide column', - 'ublaboo_datagrid.action' => 'Action', - 'ublaboo_datagrid.previous' => 'Previous', - 'ublaboo_datagrid.next' => 'Next', - 'ublaboo_datagrid.choose' => 'Choose', - 'ublaboo_datagrid.choose_input_required' => 'Group action text not allow empty value', - 'ublaboo_datagrid.execute' => 'Execute', - 'ublaboo_datagrid.save' => 'Save', - 'ublaboo_datagrid.cancel' => 'Cancel', - 'ublaboo_datagrid.multiselect_choose' => 'Choose', - 'ublaboo_datagrid.multiselect_selected' => '{0} selected', - 'ublaboo_datagrid.filter_submit_button' => 'Filter', - 'ublaboo_datagrid.show_filter' => 'Show filter', - 'ublaboo_datagrid.per_page_submit' => 'Change', + private array $dictionary = [ + 'contributte_datagrid.no_item_found_reset' => 'No items found. You can reset the filter', + 'contributte_datagrid.no_item_found' => 'No items found.', + 'contributte_datagrid.here' => 'here', + 'contributte_datagrid.items' => 'Items', + 'contributte_datagrid.all' => 'all', + 'contributte_datagrid.from' => 'from', + 'contributte_datagrid.reset_filter' => 'Reset filter', + 'contributte_datagrid.group_actions' => 'Group actions', + 'contributte_datagrid.show' => 'Show', + 'contributte_datagrid.add' => 'Add', + 'contributte_datagrid.edit' => 'Edit', + 'contributte_datagrid.show_all_columns' => 'Show all columns', + 'contributte_datagrid.show_default_columns' => 'Show default columns', + 'contributte_datagrid.hide_column' => 'Hide column', + 'contributte_datagrid.action' => 'Action', + 'contributte_datagrid.previous' => 'Previous', + 'contributte_datagrid.next' => 'Next', + 'contributte_datagrid.choose' => 'Choose', + 'contributte_datagrid.choose_input_required' => 'Group action text not allow empty value', + 'contributte_datagrid.execute' => 'Execute', + 'contributte_datagrid.save' => 'Save', + 'contributte_datagrid.cancel' => 'Cancel', + 'contributte_datagrid.multiselect_choose' => 'Choose', + 'contributte_datagrid.multiselect_selected' => '{0} selected', + 'contributte_datagrid.filter_submit_button' => 'Filter', + 'contributte_datagrid.show_filter' => 'Show filter', + 'contributte_datagrid.per_page_submit' => 'Change', ]; - public function __construct(array $dictionary = []) { + // BC support for 'ublaboo' translations + $oldPrefix = 'ublaboo_'; + $newPrefix = 'contributte_'; + foreach ($dictionary as $key => $value) { + if (str_starts_with($key, $oldPrefix)) { + $newKey = $newPrefix . substr($key, strlen($oldPrefix)); + // Only change the keys that are in the default $dictionary (other keys are left as-is) + if (array_key_exists($newKey, $this->dictionary)) { + trigger_error(sprintf("Translation key '%s' is deprecated, please use '%s' instead", $key, $newKey), E_USER_DEPRECATED); + unset($dictionary[$key]); + $dictionary[$newKey] = $value; + } + } + } + $this->dictionary = array_merge($this->dictionary, $dictionary); } - - /** - * @param mixed $message - * @param mixed ...$parameters - */ - public function translate($message, ...$parameters): string + public function translate(mixed $message, mixed ...$parameters): string { return $this->dictionary[$message] ?? $message; } - public function setDictionary(array $dictionary): void { $this->dictionary = $dictionary; } + } diff --git a/src/Row.php b/src/Row.php index b109e9314..c6bcd82a9 100644 --- a/src/Row.php +++ b/src/Row.php @@ -1,9 +1,10 @@ -control = Html::el('tr'); - $this->datagrid = $datagrid; - $this->item = $item; - $this->primaryKey = $primaryKey; $this->id = $this->getValue($primaryKey); if ($datagrid->getColumnsSummary() instanceof ColumnsSummary) { @@ -59,11 +30,7 @@ public function __construct(DataGrid $datagrid, $item, string $primaryKey) } } - - /** - * @return mixed - */ - public function getId() + public function getId(): mixed { if (is_object($this->id) && method_exists($this->id, '__toString')) { return (string) $this->id; @@ -72,12 +39,7 @@ public function getId() return $this->id; } - - /** - * @param mixed $key - * @return mixed - */ - public function getValue($key) + public function getValue(mixed $key): mixed { if ($this->item instanceof Entity) { return $this->getLeanMapperEntityProperty($this->item, $key); @@ -106,19 +68,21 @@ public function getValue($key) return (string) $arrayValue; } + if (interface_exists(\BackedEnum::class) && $arrayValue instanceof \BackedEnum) { + return $arrayValue->value; + } + return $arrayValue; } return $this->getDoctrineEntityProperty($this->item, $key); } - public function getControl(): Html { return $this->control; } - public function getControlClass(): string { $class = $this->control->getAttribute('class'); @@ -130,11 +94,7 @@ public function getControlClass(): string return implode(' ', array_keys($class)); } - - /** - * @return mixed - */ - public function getActiveRowProperty(ActiveRow $item, string $key) + public function getActiveRowProperty(ActiveRow $item, string $key): mixed { if (preg_match('/^:([a-zA-Z0-9_$]+)\.([a-zA-Z0-9_$]+)(:([a-zA-Z0-9_$]+))?$/', $key, $matches) === 1) { $relatedTable = $matches[1]; @@ -143,7 +103,7 @@ public function getActiveRowProperty(ActiveRow $item, string $key) try { $relatedRow = $item->related($relatedTable, $throughColumn)->fetch(); - } catch (MemberAccessException $e) { + } catch (MemberAccessException) { return null; } @@ -159,7 +119,7 @@ public function getActiveRowProperty(ActiveRow $item, string $key) try { $referencedRow = $item->ref($referencedTable, $throughColumn); - } catch (MemberAccessException $e) { + } catch (MemberAccessException) { return null; } @@ -171,13 +131,10 @@ public function getActiveRowProperty(ActiveRow $item, string $key) return $item[$key]; } - /** * LeanMapper: Access object properties to get a item value - * - * @return mixed */ - public function getLeanMapperEntityProperty(Entity $item, string $key) + public function getLeanMapperEntityProperty(Entity $item, string $key): mixed { $properties = explode('.', $key); $value = $item; @@ -191,7 +148,7 @@ public function getLeanMapperEntityProperty(Entity $item, string $key) if (!$value->__isset($property)) { if ($this->datagrid->strictEntityProperty) { - throw new DataGridException(sprintf( + throw new DatagridException(sprintf( 'Target Property [%s] is not an object or is empty, trying to get [%s]', $value, str_replace('.', '->', $key) @@ -207,13 +164,10 @@ public function getLeanMapperEntityProperty(Entity $item, string $key) return $value; } - /** * Nextras: Access object properties to get a item value - * - * @return mixed */ - public function getNextrasEntityProperty(NextrasEntity $item, string $key) + public function getNextrasEntityProperty(NextrasEntity $item, string $key): mixed { $properties = explode('.', $key); $value = $item; @@ -221,7 +175,7 @@ public function getNextrasEntityProperty(NextrasEntity $item, string $key) while ($property = array_shift($properties)) { if (!$value->__isset($property)) { if ($this->datagrid->strictEntityProperty) { - throw new DataGridException(sprintf( + throw new DatagridException(sprintf( 'Target Property [%s] is not an object or is empty, trying to get [%s]', $value, str_replace('.', '->', $key) @@ -237,15 +191,10 @@ public function getNextrasEntityProperty(NextrasEntity $item, string $key) return $value; } - /** * Doctrine: Access object properties to get a item value - * - * @param mixed $item - * @param mixed $key - * @return mixed */ - public function getDoctrineEntityProperty($item, $key) + public function getDoctrineEntityProperty(mixed $item, mixed $key): mixed { $properties = explode('.', $key); $value = $item; @@ -254,7 +203,7 @@ public function getDoctrineEntityProperty($item, $key) while ($property = array_shift($properties)) { if (!is_object($value) && ! (bool) $value) { if ($this->datagrid->strictEntityProperty) { - throw new DataGridException(sprintf( + throw new DatagridException(sprintf( 'Target Property [%s] is not an object or is empty, trying to get [%s]', $value, str_replace('.', '->', $key) @@ -271,21 +220,21 @@ public function getDoctrineEntityProperty($item, $key) return (string) $value; } + if (interface_exists(\BackedEnum::class) && $value instanceof \BackedEnum) { + return $value->value; + } + return $value; } - /** * Get original item - * - * @return mixed */ - public function getItem() + public function getItem(): mixed { return $this->item; } - /** * Has particular row group actions allowed? */ @@ -300,13 +249,10 @@ public function hasGroupAction(): bool return true; } - /** * Has particular row a action allowed? - * - * @param mixed $key */ - public function hasAction($key): bool + public function hasAction(mixed $key): bool { $condition = $this->datagrid->getRowCondition('action', $key); @@ -317,7 +263,6 @@ public function hasAction($key): bool return true; } - /** * Has particular row inlie edit allowed? */ @@ -332,7 +277,6 @@ public function hasInlineEdit(): bool return true; } - public function applyColumnCallback(string $key, Column $column): Column { $callback = $this->datagrid->getColumnCallback($key); @@ -344,7 +288,6 @@ public function applyColumnCallback(string $key, Column $column): Column return $column; } - /** * Key may contain ".", get rid of it (+ the table alias) */ @@ -358,4 +301,5 @@ private function formatDibiRowKey(string $key): string return $key; } + } diff --git a/src/Status/Option.php b/src/Status/Option.php index ee6d6f17c..24cb5f234 100644 --- a/src/Status/Option.php +++ b/src/Status/Option.php @@ -1,102 +1,46 @@ -grid = $grid; - $this->columnStatus = $columnStatus; - $this->value = $value; - $this->text = $text; } - - /** - * @return mixed - */ - public function getValue() + public function getValue(): mixed { return $this->value; } - public function endOption(): ColumnStatus { return $this->columnStatus; } - /** * @return static */ @@ -107,13 +51,11 @@ public function setTitle(string $title): self return $this; } - public function getTitle(): ?string { return $this->title; } - /** * @return static */ @@ -128,13 +70,11 @@ public function setClass(string $class, ?string $classSecondary = null): self return $this; } - public function getClass(): ?string { return $this->class; } - /** * @return static */ @@ -145,13 +85,11 @@ public function setClassSecondary(string $classSecondary): self return $this; } - public function getClassSecondary(): string { return $this->classSecondary; } - /** * @return static */ @@ -162,13 +100,11 @@ public function setClassInDropdown(string $classInDropdown): self return $this; } - public function getClassInDropdown(): string { return $this->classInDropdown; } - /** * @return static */ @@ -179,13 +115,11 @@ public function setIcon(string $icon): self return $this; } - public function getIcon(): ?string { return $this->icon; } - /** * @return static */ @@ -196,19 +130,16 @@ public function setIconSecondary(string $iconSecondary): self return $this; } - public function getIconSecondary(): ?string { return $this->iconSecondary; } - public function getText(): string { return $this->text; } - /** * @return static */ @@ -219,7 +150,6 @@ public function setConfirmation(IConfirmation $confirmation): self return $this; } - public function getConfirmationDialog(Row $row): ?string { if ($this->confirmation === null) { @@ -244,6 +174,7 @@ public function getConfirmationDialog(Row $row): ?string ); } - throw new DataGridException('Unsupported confirmation'); + throw new DatagridException('Unsupported confirmation'); } + } diff --git a/src/Toolbar/ToolbarButton.php b/src/Toolbar/ToolbarButton.php index 8e1db6106..96579bcca 100644 --- a/src/Toolbar/ToolbarButton.php +++ b/src/Toolbar/ToolbarButton.php @@ -1,19 +1,17 @@ -grid = $grid; - $this->href = $href; $this->text = $text; - $this->params = $params; } - /** * Render toolbar button */ @@ -71,7 +44,7 @@ public function renderButton(): Html try { // Renderer function may be used return $this->useRenderer(); - } catch (DataGridColumnRendererException $e) { + } catch (DatagridColumnRendererException) { // Do not use renderer } @@ -103,12 +76,10 @@ public function renderButton(): Html return $a; } - /** - * @param array $attrs * @return static */ - public function addAttributes(array $attrs) + public function addAttributes(array $attrs): static { $this->attributes += $attrs; @@ -124,4 +95,5 @@ public function setConfirmDialog(string $confirmDialog): self return $this; } + } diff --git a/src/Traits/TButtonCaret.php b/src/Traits/TButtonCaret.php index 9d7d8309a..60f17ad14 100644 --- a/src/Traits/TButtonCaret.php +++ b/src/Traits/TButtonCaret.php @@ -1,16 +1,11 @@ -caret; diff --git a/src/Traits/TButtonClass.php b/src/Traits/TButtonClass.php index 4762237e0..10b1474b4 100644 --- a/src/Traits/TButtonClass.php +++ b/src/Traits/TButtonClass.php @@ -1,16 +1,11 @@ -class; diff --git a/src/Traits/TButtonIcon.php b/src/Traits/TButtonIcon.php index a32f33748..8a64c84fe 100644 --- a/src/Traits/TButtonIcon.php +++ b/src/Traits/TButtonIcon.php @@ -1,16 +1,11 @@ -icon; diff --git a/src/Traits/TButtonRenderer.php b/src/Traits/TButtonRenderer.php index 344b81f1d..29ed033b8 100644 --- a/src/Traits/TButtonRenderer.php +++ b/src/Traits/TButtonRenderer.php @@ -1,44 +1,35 @@ -getRenderer(); $args = $row instanceof Row ? [$row->getItem()] : []; if ($renderer === null) { - throw new DataGridColumnRendererException; + throw new DatagridColumnRendererException(); } if ($renderer->getConditionCallback() !== null) { if (call_user_func_array($renderer->getConditionCallback(), $args) === false) { - throw new DataGridColumnRendererException; + throw new DatagridColumnRendererException(); } return call_user_func_array($renderer->getCallback(), $args); @@ -47,12 +38,11 @@ public function useRenderer(?Row $row = null) return call_user_func_array($renderer->getCallback(), $args); } - /** * Set renderer callback and (it may be optional - the condition callback will decide) * * @return static - * @throws DataGridException + * @throws DatagridException */ public function setRenderer( callable $renderer, @@ -60,7 +50,7 @@ public function setRenderer( ): self { if ($this->hasReplacements()) { - throw new DataGridException('Use either Column::setReplacement() or Column::setRenderer, not both.'); + throw new DatagridException('Use either Column::setReplacement() or Column::setRenderer, not both.'); } $this->renderer = new Renderer($renderer, $conditionCallback); @@ -68,7 +58,6 @@ public function setRenderer( return $this; } - /** * @return static */ @@ -80,19 +69,16 @@ public function setRendererOnCondition( return $this->setRenderer($renderer, $conditionCallback); } - public function getRenderer(): ?Renderer { return $this->renderer; } - public function hasReplacements(): bool { return $this->replacements !== []; } - public function applyReplacements(Row $row, string $column): array { $value = $row->getValue($column); diff --git a/src/Traits/TButtonText.php b/src/Traits/TButtonText.php index 8d9d5ed4d..418f31b26 100644 --- a/src/Traits/TButtonText.php +++ b/src/Traits/TButtonText.php @@ -1,16 +1,11 @@ -text; diff --git a/src/Traits/TButtonTitle.php b/src/Traits/TButtonTitle.php index 1479c5681..32d0efaab 100644 --- a/src/Traits/TButtonTitle.php +++ b/src/Traits/TButtonTitle.php @@ -1,17 +1,11 @@ -title; } + } diff --git a/src/Traits/TButtonTryAddIcon.php b/src/Traits/TButtonTryAddIcon.php index a06e2db7e..03e1a62b5 100644 --- a/src/Traits/TButtonTryAddIcon.php +++ b/src/Traits/TButtonTryAddIcon.php @@ -1,11 +1,9 @@ -addHtml(Html::el('span')->setAttribute('class', trim($iconClass))); @@ -26,4 +24,5 @@ public function tryAddIcon(Html $el, ?string $iconString, string $name): void } } } + } diff --git a/src/Traits/TLink.php b/src/Traits/TLink.php index d49c4b26d..57f120eef 100644 --- a/src/Traits/TLink.php +++ b/src/Traits/TLink.php @@ -1,29 +1,27 @@ -getPresenter(); - if (strpos($href, ':') !== false) { + if (str_contains($href, ':')) { return $presenter->link($href, $params); } @@ -45,15 +43,15 @@ protected function createLink( try { $link = $targetComponent->link($href, $params); - } catch (InvalidLinkException $e) { + } catch (InvalidLinkException) { $link = false; } if (is_string($link)) { if ( - strpos($link, '#error') === 0 || - (strrpos($href, '!') !== false && strpos($link, '#') === 0) || - (in_array($presenter->invalidLinkMode, [Presenter::INVALID_LINK_WARNING, Presenter::INVALID_LINK_SILENT], true) && strpos($link, '#') === 0) + str_starts_with($link, '#error') || + (strrpos($href, '!') !== false && str_starts_with($link, '#')) || + (in_array($presenter->invalidLinkMode, [Presenter::InvalidLinkWarning, Presenter::InvalidLinkSilent], true) && str_starts_with($link, '#')) ) { continue; // Did not find signal handler } @@ -68,12 +66,11 @@ protected function createLink( throw $this->createHierarchyLookupException($grid, $href, $params); } - private function createHierarchyLookupException( - DataGrid $grid, + Datagrid $grid, string $href, array $params - ): DataGridLinkCreationException + ): DatagridLinkCreationException { $parent = $grid->getParent(); $presenter = $grid->getPresenter(); @@ -84,13 +81,13 @@ private function createHierarchyLookupException( ); } - $desiredHandler = get_class($parent) . '::handle' . ucfirst($href) . '()'; + $desiredHandler = $parent::class . '::handle' . ucfirst($href) . '()'; - return new DataGridLinkCreationException( - 'DataGrid could not create link "' + return new DatagridLinkCreationException( + 'Datagrid could not create link "' . $href . '" - did not find any signal handler in componenet hierarchy from ' - . get_class($parent) . ' up to the ' - . get_class($presenter) . '. ' + . $parent::class . ' up to the ' + . $presenter::class . '. ' . 'Try adding handler ' . $desiredHandler ); } diff --git a/src/Traits/TRenderCondition.php b/src/Traits/TRenderCondition.php index 7d0560bb9..aebf8712f 100644 --- a/src/Traits/TRenderCondition.php +++ b/src/Traits/TRenderCondition.php @@ -1,17 +1,13 @@ -renderConditionCallback; @@ -33,4 +28,5 @@ public function shouldBeRendered(Row $row): bool ? ($condition)($row->getItem()) : true; } + } diff --git a/src/Utils/ArraysHelper.php b/src/Utils/ArraysHelper.php index 8a4bb76d5..aa5bb85e9 100644 --- a/src/Utils/ArraysHelper.php +++ b/src/Utils/ArraysHelper.php @@ -1,10 +1,6 @@ -getTimezone(); - $date = new \DateTime('now', $tz !== false ? $tz : null); + $date = new DateTime('now', $tz !== false ? $tz : null); $date->setTimestamp($value->getTimestamp()); return $date; } foreach ($formats as $format) { - $date = \DateTime::createFromFormat($format, (string) $value); + $date = DateTime::createFromFormat($format, (string) $value); if ($date === false) { continue; @@ -81,13 +76,13 @@ public static function fromString($value, array $formats = []): \DateTime $timestamp = strtotime((string) $value); if ($timestamp !== false) { - $date = new \DateTime; + $date = new DateTime(); $date->setTimestamp($timestamp); return $date; } - throw new DataGridDateTimeHelperException(); + throw new DatagridDateTimeHelperException(); } } diff --git a/src/Utils/ItemDetailForm.php b/src/Utils/ItemDetailForm.php index f88eef584..8cbfd3f5a 100644 --- a/src/Utils/ItemDetailForm.php +++ b/src/Utils/ItemDetailForm.php @@ -1,40 +1,31 @@ - - */ - private $containerSetByName = []; + /** @var ?array */ + private ?array $httpPost = null; + /** @var array */ + private array $containerSetByName = []; public function __construct(callable $callableSetContainer) { $this->monitor( Presenter::class, - function(Presenter $presenter): void { + function (Presenter $presenter): void { $this->loadHttpData(); } ); @@ -42,20 +33,12 @@ function(Presenter $presenter): void { $this->callableSetContainer = $callableSetContainer; } - - /** - * @param mixed $name - */ - public function offsetGet($name): IComponent + public function offsetGet(mixed $name): IComponent { return $this->getComponentAndSetContainer($name); } - - /** - * @param mixed $name - */ - public function getComponentAndSetContainer($name): IComponent + public function getComponentAndSetContainer(mixed $name): IComponent { $container = $this->addContainer($name); @@ -68,22 +51,16 @@ public function getComponentAndSetContainer($name): IComponent return $container; } - /** - * @return mixed|null * @throws UnexpectedValueException */ - private function getHttpData() + private function getHttpData(): mixed { if ($this->httpPost === null) { - $lookupPath = $this->lookupPath('Nette\Forms\Form'); + $lookupPath = $this->lookupPath(Form::class); $form = $this->getForm(); - if ($lookupPath === null || $form === null) { - throw new UnexpectedValueException; - } - - $path = explode(self::NAME_SEPARATOR, $lookupPath); + $path = explode(self::NameSeparator, $lookupPath); $this->httpPost = Arrays::get($form->getHttpData(), $path, null); } @@ -91,7 +68,6 @@ private function getHttpData() return $this->httpPost; } - /** * @throws UnexpectedValueException */ @@ -99,18 +75,15 @@ private function loadHttpData(): void { $form = $this->getForm(); - if ($form === null) { - throw new UnexpectedValueException; - } - if ($form->isSubmitted() === false) { return; } foreach ((array) $this->getHttpData() as $name => $value) { - if ((is_array($value) || $value instanceof Traversable)) { + if ((is_iterable($value))) { $this->getComponentAndSetContainer($name); } } } + } diff --git a/src/Utils/NetteDatabaseSelectionHelper.php b/src/Utils/NetteDatabaseSelectionHelper.php index 5b9861054..992f25194 100644 --- a/src/Utils/NetteDatabaseSelectionHelper.php +++ b/src/Utils/NetteDatabaseSelectionHelper.php @@ -1,35 +1,30 @@ -getConnection(); - return $connection->getSupplementalDriver(); + return $connection->getDriver(); } - - /** - * @return mixed - */ - public static function getContext(Selection $selection) + public static function getContext(Selection $selection): Explorer { $reflection = new ReflectionClass($selection); - $context_property = $reflection->getProperty('context'); - $context_property->setAccessible(true); + $explorerProperty = $reflection->getProperty('explorer'); + $explorerProperty->setAccessible(true); - return $context_property->getValue($selection); + return $explorerProperty->getValue($selection); } } diff --git a/src/Utils/PropertyAccessHelper.php b/src/Utils/PropertyAccessHelper.php index 08d7876e2..65c602fb4 100644 --- a/src/Utils/PropertyAccessHelper.php +++ b/src/Utils/PropertyAccessHelper.php @@ -1,8 +1,6 @@ -getValue($class, $property); } diff --git a/src/Utils/Sorting.php b/src/Utils/Sorting.php index eef6e6d0b..c7aaa6427 100644 --- a/src/Utils/Sorting.php +++ b/src/Utils/Sorting.php @@ -1,30 +1,21 @@ -sort = $sort; $this->sortCallback = $sortCallback; } - /** * @return array|string[] */ @@ -33,7 +24,6 @@ public function getSort(): array return $this->sort; } - public function getSortCallback(): ?callable { return $this->sortCallback; diff --git a/src/templates/column_multi_action.latte b/src/templates/column_multi_action.latte index b55921b49..ad26c649e 100644 --- a/src/templates/column_multi_action.latte +++ b/src/templates/column_multi_action.latte @@ -1,5 +1,5 @@ {** - * @param $multiAction Ublaboo\DataGrid\Column\MultiAction + * @param $multiAction Contributte\Datagrid\Column\MultiAction *}