diff --git a/.gitattributes b/.gitattributes index 1185e15..47ea9b3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,7 +5,7 @@ .editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore -.php_cs export-ignore .scrutinizer.yml export-ignore -.travis.yml export-ignore -phpunit.xml export-ignore +.styleci.yml export-ignore +phpstan.neon.dist export-ignore +phpunit.xml.dist export-ignore diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index a1eb104..87ed63d 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,3 @@ +github: yajra patreon: yajra custom: https://www.paypal.me/yajra diff --git a/.github/workflows/tests.yml b/.github/workflows/continuous-integration.yml similarity index 72% rename from .github/workflows/tests.yml rename to .github/workflows/continuous-integration.yml index 85e883a..49f05ab 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/continuous-integration.yml @@ -1,23 +1,25 @@ -name: tests +name: Continuous Integration on: push: + branches: + - master + - '*.x' pull_request: schedule: - cron: '0 0 * * *' jobs: tests: - runs-on: ubuntu-latest strategy: fail-fast: true matrix: - php: [7.3, 7.4, 8.0] - stability: [prefer-lowest, prefer-stable] + php: [8.2, 8.3, 8.4] + stability: [prefer-stable] - name: PHP ${{ matrix.php }} - ${{ matrix.stability }} + name: PHP ${{ matrix.php }} - STABILITY ${{ matrix.stability }} steps: - name: Checkout code @@ -27,7 +29,6 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, memcached tools: composer:v2 coverage: none @@ -42,4 +43,4 @@ jobs: command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress - name: Execute tests - run: vendor/bin/phpunit --verbose + run: vendor/bin/phpunit diff --git a/.github/workflows/pint.yml b/.github/workflows/pint.yml new file mode 100644 index 0000000..c07577f --- /dev/null +++ b/.github/workflows/pint.yml @@ -0,0 +1,33 @@ +name: PHP Linting + +on: + pull_request: + push: + branches: + - master + - '*.x' + +jobs: + pint: + name: Pint + + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + + - name: "laravel-pint" + uses: aglipanci/laravel-pint-action@latest + with: + preset: laravel + verboseMode: true + + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "fix: pint :robot:" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..bae8b28 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,22 @@ +name: Close inactive issues +on: + schedule: + - cron: "30 1 * * *" + +jobs: + close-issues: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v5 + with: + days-before-issue-stale: 30 + days-before-issue-close: 7 + stale-issue-label: "stale" + stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." + close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale." + days-before-pr-stale: -1 + days-before-pr-close: -1 + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..4dccad0 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,39 @@ +name: Static Analysis + +on: + push: + branches: + - master + - '*.x' + + pull_request: + + schedule: + - cron: '0 0 * * *' + +jobs: + static-analysis-phpstan: + + name: Source Code + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + tools: composer:v2 + coverage: none + + - name: Install dependencies + uses: nick-fields/retry@v3 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress + + - name: Run Static Analysis + run: vendor/bin/phpstan diff --git a/.gitignore b/.gitignore index df0e1ea..c2e4bf9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /coverage composer.phar composer.lock +/.phpunit.cache/test-results diff --git a/.php_cs b/.php_cs deleted file mode 100644 index e8c5a2a..0000000 --- a/.php_cs +++ /dev/null @@ -1,77 +0,0 @@ -finder(DefaultFinder::create()->in(__DIR__)) - ->fixers($fixers) - ->level(FixerInterface::NONE_LEVEL) - ->setUsingCache(true); diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 0000000..0285f17 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1 @@ +preset: laravel diff --git a/CHANGELOG.md b/CHANGELOG.md index 99a5bba..04d08aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,775 +1,18 @@ # Laravel DataTables Html Plugin. -[![Latest Stable Version](https://poser.pugx.org/yajra/laravel-datatables-html/v/stable.png)](https://packagist.org/packages/yajra/laravel-datatables-html) -[![Total Downloads](https://poser.pugx.org/yajra/laravel-datatables-html/downloads.png)](https://packagist.org/packages/yajra/laravel-datatables-html) -[![Build Status](https://travis-ci.org/yajra/laravel-datatables-html.png?branch=master)](https://travis-ci.org/yajra/laravel-datatables-html) -[![Latest Unstable Version](https://poser.pugx.org/yajra/laravel-datatables-html/v/unstable.svg)](https://packagist.org/packages/yajra/laravel-datatables-html) -[![License](https://poser.pugx.org/yajra/laravel-datatables-html/license.svg)](https://packagist.org/packages/yajra/laravel-datatables-html) - ## CHANGELOG -### v4.41.1 - 03-05-2022 - -- Fix Field::attr() doc block. - -### v4.41.0 - 10-07-2021 - -- Add exportFormat method. #160 - -### v4.40.0 - 10-04-2021 - -- Add method getTableId() #159 - -### v4.39.1 - 09-12-2021 - -- Fix doc block and add array as acceptable Column editField value. - -### v4.39.0 - 09-12-2021 - -- Add missing select field options as of Editor 1.5.4. - -### v4.38.0 - 06-20-2021 - -- Fix fetching of editor table #158 -- Add method to get all editors instances. -- Add method to get dataTable options array. -- Set serverSide and processing option as true by default. - -### v4.37.0 - 05-17-2021 - -- Implement authorizations on Editor builder. - -### v4.36.3 - 04-23-2021 - -- Fix conflicts with createInline button. Use render instead of altering the data. - -### v4.36.2 - 03-19-2021 - -- Fix exportable flag, should be false. - -### v4.36.1 - 12-05-2020 - -- Fix adding of class on Select plugin / extension. [#154] - -### v4.36.0 - 11-14-2020 - -- Add drawCallbackWithLivewire api. -- Solution as per issue https://github.com/yajra/laravel-datatables/issues/2401. - -### v4.35.2 - 11-14-2020 - -- Add missing button options as per [docs](https://datatables.net/reference/option/#buttons). - -### v4.35.1 - 11-03-2020 - -- Add missing upload field options as per doc. [#152] - -### v4.35.0 - 11-03-2020 - -- Add formatted column factory. [#147] - -### v4.34.0 - 10-31-2020 - -- Add support for search panes extension. [#137] - -### v4.33.0 - 10-30-2020 - -- Make LaravelDataTables javascript namespace configurable. [#145], credits to @om3rcitak - -### v4.32.0 - 10-10-2020 - -- Add function argument to override the default options from php scripts. [#144] - -### v4.31.0 - 10-09-2020 - -- Add button customize option value. [#142], credits to @gredimano -- Fix https://github.com/yajra/laravel-datatables/issues/1541 -- Add template and method to wrap scripts with a function. [#143] - -### v4.30.3 - 10-06-2020 - -- Wait for DOM before executing script using jQuery [#138] -- Fix [#133] - -### v4.30.2 - 10-06-2020 - -- Fix chrome bfcache issue with editor. [#139], credits to @jiwom -- Allow using callbacks as a data value. [#127], credits to @mgralikowski - -### v4.30.1 - 09-29-2020 - -- Fix [#134] laravel 8 dependencies [#135], credits to @dyanakiev. - -### v4.30.0 - 06-18-2020 - -- Add button align property setter. - -### v4.29.0 - 06-17-2020 - -- Add column responsive priority setter. [#131], credits to @SamDeimos. - -### v4.28.0 - 06-10-2020 - -- Allow eloquent builder instance on BelongsTo model field. - -### v4.27.0 - 05-29-2020 - -- Add renderRaw method to set render value as is. - -### v4.26.1 - 05-29-2020 - -- Fix array listing and allow customer separator. - -### v4.26.0 - 05-29-2020 - -- Add support for comma separated list from an array of objects. - -### v4.25.1 - 04-17-2020 - -- Fix PR [#125]. - -### v4.25.0 - 04-17-2020 - -- HTML title for columns labels [#125], credits to @mgralikowski. - -### v4.24.0 - 04-02-2020 - -- Add TextArea rows & cols fluent attribute setter. - -### v4.23.1 - 03-04-2020 - -- Improve addClass method. [#117], credits to @matteocostantini. - -### v4.23.0 - 03-04-2020 - -- Allow Laravel 7 [#124], credits to @barryvdh. - -### v4.22.0 - 03-03-2020 - -- Add shortcut method `hidden` to hide column instead of `visible(false)`. - -### v4.21.1 - 02-21-2020 - -- Use full url on ajax if not set. [#122] -- Fix [yajra/laravel-datatables#2322](https://github.com/yajra/laravel-datatables/issues/2322). -- Fix [#121] - -### v4.21.0 - 02-18-2020 - -- Add editor button formMessage and formTitle fluent setter. - -### v4.20.2 - 02-17-2020 - -- Fix export function not working when base url is set on header. - -### v4.20.1 - 11-11-2019 - -- Fix substring to substr [#116]. - -### v4.20.0 - 11-11-2019 - -- Improve adding custom action to buttons. [#114], credits to @om3rcitak. - -### v4.19.4 - 10-02-2019 - -- Fix serialization of renderJs parameters. [#110] -- Allow array parameter on buttons option for api consistency. [#111] -- Allow array parameter on editors option for api consistency. [#112] - -### v4.19.3 - 09-27-2019 - -- Fix Button class doc return type to static. - -### v4.19.2 - 09-27-2019 - -- Fix authorization options to allow null. - -### v4.19.1 - 09-27-2019 - -- Fix missing button name attr setter. - -### v4.19.0 - 09-25-2019 - -- Add Editor formOptions setter as per docs: https://editor.datatables.net/reference/option/formOptions. - -### v4.18.2 - 09-25-2019 - -- Fix ajax data if value is an array. - -### v4.18.1 - 09-25-2019 - -- Add ajax url setter. -- Fix ajax option if array was passed. - -### v4.18.0 - 09-23-2019 - -- Add makeIfCannot authorization. - -```php -Field\Text::makeIfCannot('evaluate', 'evaluator_id')->data('evaluator.name')... -``` - -### v4.17.0 - 09-23-2019 - -- Add support for Field class authorizations. -- Fix doc blocks and phpstorm warnings. - -```php -Field\Select::makeIfCan('evaluate', 'evaluator_id')... -Field\Select::makeIf(true, 'evaluator_id')... -Field\Select::makeIf(function() { return true; }, 'evaluator_id')... -``` - -### v4.16.0 - 09-20-2019 - -- Add action script helpers. -- New actions: `actionSubmit(), actionClose(), actionHandler('editor-method-handler')` - -```php -Button::make('edit') - ->editor('evaluator') - ->text(' Evaluate') - ->formButtons([ - Button::raw('Approve') - ->className('btn btn-success ml-2') - ->actionHandler('approve'), - Button::raw('Decline') - ->className('btn btn-danger ml-2') - ->actionHandler('decline'), - Button::raw('Cancel') - ->className('btn btn-secondary ml-2') - ->actionClose(), - ]) - ->className('btn-success'), -``` - -- Add missing formButtons and action setter. -- Add raw buttons factory. - -```php -Button::make('edit') - ->editor('approver') - ->text(' Approve Leave') - ->formButtons([ - Button::raw('Approve') - ->className('btn btn-success') - ->action('function() { this.submit(); }'), - Button::raw('Cancel') - ->className('btn btn-secondary ml-2') - ->action('function() { this.close(); }'), - ]) - ->className('btn-success'), -``` - -### v4.14.2 - 09-17-2019 - -- Add missing Button buttons setter. - -### v4.14.1 - 09-16-2019 - -- Fix Number field and set type attr to number. -- Add missing attr setter. -- Fix doc blocks for better IDE support. - -### v4.14.0 - 09-16-2019 - -- Add more dateTime opts setter. - -### v4.13.0 - 09-14-2019 - -- Add renderJs ability to pass parameter to js from php argument. -- `->renderJs('prefix', 'hrs')` == `->renderJs('prefix("hrs")')` - -### v4.12.0 - 09-14-2019 - -- Add renderJs helper to use the built-in and custom renderer. -- Ex: `->renderJs("boolean()")`, `->renderJs("number()")`. - -### v4.11.0 - 09-13-2019 - -- Add select2 ajax option support. [#109] - -### v4.10.1 - 09-10-2019 - -- Remove editor dependency when display the image. -- Fix js issue when editing. - -### v4.10.0 - 09-10-2019 - -- Fix displaying of uploaded image preview. -- Add File editor instance setter. - -### v4.9.0 - 09-10-2019 - -- Add File and Image editor fields. [#108] - -### v4.8.0 - 09-04-2019 - -- Add support Laravel 6.0 & remove deprecated functions [#107], credits to @sangnguyenplus. - -### v4.7.1 - 08-31-2019 - -- Unset editor events key when serializing to array or json. -- Fix editor events script builder. - -### v4.7.0 - 08-29-2019 - -- Add BelongsTo field builder. - -```php -BelongsTo::model(Model::class, 'name') -``` - -### v4.6.0 - 08-29-2019 - -- Return static on Field for better IDE support. -- Add initial support for Select2 editor plugin. - -### v4.5.4 - 08-22-2019 - -- Add missing buttons columns & exportOptions setter. - -### v4.5.3 - 08-17-2019 - -- Fix error when no editor fields was defined. [52f0537c5913c84fb5e8a58bbd7db142b987daaf](https://github.com/yajra/laravel-datatables-html/commit/52f0537c5913c84fb5e8a58bbd7db142b987daaf) -- Return false when validating callback value is an array or an object. [b76cdf806c85368fce70a9034153dec6e107dd2f](https://github.com/yajra/laravel-datatables-html/commit/52f0537c5913c84fb5e8a58bbd7db142b987daaf) - -### v4.5.2 - 08-13-2019 - -- Fix [#102] language key and use i18n. [#103], credits to @matteocostantini. - -### v4.5.1 - 07-05-2019 - -- Add fluent column footer setter. [#101] - -### v4.5.0 - 06-27-2019 - -- Add ability to generate dataTables options for external js use. [#99] - -### v4.4.1 - 04-25-2019 - -- Add title attribute for table headers. [#94], credits to @HOFFMACHINE. - - -### v4.4.0 - 02-27-2019 - -- Add support for Laravel 5.8 / DataTables v9.0 [#90]. - -### v4.3.2 - 02-05-2019 - -- Avoid call parseRender when render attribute is null. [#87] credits to @JulianBustamante. - -### v4.3.1 - 11-21-2018 - -- Allow null string computed column title. - -### v4.3.0 - 11-21-2018 - -#### Added - -- Builder Support for the following plugins: - -- [x] AutoFill -- [x] ColReorder -- [x] FixedColumns -- [x] FixedHeader -- [x] KeyTable -- [x] Responsive -- [x] RowGroup -- [x] RowReorder -- [x] Scroller -- [x] Select - -- Builder Support for setting the language: - -- [x] Language -- [x] Language\Aria -- [x] Language\AutoFill -- [x] Language\Paginate -- [x] Language\Select - -- Add missing column option setters: - -- [x] data -- [x] orderData -- [x] orderDataType -- [x] orderSequence -- [x] cellType -- [x] type -- [x] contentPadding -- [x] createdCell -- [x] editField - -### v4.2.1 - 11-21-2018 - -- Fix computed column title if nothing is set. - -### v4.2.0 - 11-20-2018 - -- Add ajaxWithForm api to process dataTables with form data. [#86] - -### v4.1.0 - 11-16-2018 - -- Add full Editor events script builder as per https://editor.datatables.net/reference/event/. - -```php -Editor::make('create') - ->on('create', 'js-script-here') - ->onCreate('js-script-here') // event via magic method. - ->fields([ - Fields\Text::make('name'), - Fields\Text::make('email'), - ]); -``` - -- Add missing `idSrc` Editor option setter. -- Add missing `display` Editor option setter. - -> NOTE: You need to force [publish](https://github.com/yajra/laravel-datatables-html#publish-assets-optional) the blade templates to be able to use the features if needed. - -### v4.0.0 - 11-14-2018 - -#### ADDED - -Add full builder support for the following options based on https://datatables.net/reference/option/. - -##### Add builder support for the following plugins: - -- [x] AutoFill -- [x] Buttons -- [x] ColReorder -- [x] FixedColumns -- [x] FixedHeader -- [x] KeyTable -- [x] Responsive -- [x] RowGroup -- [x] RowReorder -- [x] Scroller -- [x] Select - -> Note: All plugins requires their corresponding asset files. - -##### Add Buttons builder with support for authorization. - -```php -->buttons( - Button::makeIfCan('manage-users', 'create')->editor('editor'), - Button::makeIf(true, 'edit')->editor('editor'), - Button::make('remove')->editor('editor')->className('btn-danger'), - Button::make('colvis')->text(''), - Button::make('export'), - Button::make('print'), - Button::make('reset'), - Button::make('reload') -) -``` - -#### CHANGED - -- `Editor` class was moved from `Yajra\DataTables\Html\Editor` to `Yajra\DataTables\Html\Editor\Editor`. -- All fields were moved from `Yajra\DataTables\Html\Editor` to `Yajra\DataTables\Html\Editor\Fields` namespace. - -### v3.13.0 - 11-10-2018 - -- Add missing visible option setter. [#83] -- Add new fields, fix dateTime field format. [#84] - -#### Changed - -- Fix field and column computed title. - -From `created_at` with title `Created_At` -To `created_at` with title `Created At` - -#### Fixed - -- Fix DateTime field. -- Set format to `YYYY-MM-DD hh:mm a`. -- Add `military()` setter to set the time to military format. - -#### Added New Fields - -- Boolean -- Date -- Time -- Text -- Number - -### v3.12.7 - 11-03-2018 - -- Add checker if className is not yet set when adding class. - -### v3.12.6 - 11-03-2018 - -- Fix setting of title. -- Add title option for checkbox column. - -### v3.12.5 - 11-03-2018 - -- Add name arg for computed column. - -### v3.12.4 - 11-03-2018 - -- Fix options: Use 1 and 0 for true or false. - -### v3.12.3 - Skipped (My Bad) - -### v3.12.2 - 11-03-2018 - -- Add missing field options setter and add docs link. - -### v3.12.1 - 11-03-2018 - -- Add to method to append a class to the field. - -### v3.12.0 - 11-03-2018 - -- Add editor options collection builder. [#80] - -### v3.11.0 - 11-02-2018 - -- Add option to prepend action column. [#77] -- Enhance column fluent builder. [#78] - -### v3.10.0 - 11-02-2018 - -- Add support for DataTables Editor script generation. [#73] -- Fix script template config key `datatables-html.script`. -- Add method to `getAjaxUrl()`. - -### v3.9.0 - 11-02-2018 - -- Add support for [built-in render helpers](https://datatables.net/manual/data/renderers#Built-in-helpers). [#71], credits to @Razoxane. - -### v3.8.1 - 10-30-2018 - -- Fix the default name of index column to follow DT syntax. [#69], credits to @jaydons. -- Fix missing periods. [#70], credits to @jaydons. - -### v3.8.0 - 09-05-2018 - -- Add support for Laravel 5.7 - -### v3.7.2 - 07-06-2018 - -- Fix callback check on empty values. [#62] Credits to @apreiml. - -### v3.7.1 - 03-16-2018 - -- Add parameter in addCheckbox to prepend or append the checkbox column [#55], credits to @karmendra - -### v3.7.0 - 02-21-2018 - -- Adding ajaxParameters to minifiedAjax [#57], credits to @lk77 -- Fixes the issue with the missing name attribute default mentioned in [#58]. PR [#59], credits to @Namoshek - -### v3.6.0 - 02-11-2018 - -- Add support for Laravel 5.6. [#56] - -### v3.5.2 - 01-11-2018 - -- Moving callback condition to config [#54], credits to @lk77. - -### v3.5.1 - 12-27-2017 - -- Allow jQuery functions callback. [#52], credits to @OzanKurt. - -### v3.5.0 - 12-24-2017 - -- Improve handling of function callbacks and better editor support. [#49] - -### v3.4.0 - 12-18-2017 - -- Implement buttons support for editor. [#47] - -### v3.3.0 - 12-15-2017 - -- Add postAjax() to Html Builder [#45], credits to @ElfSundae. -- Fix https://github.com/yajra/laravel-datatables-html/pull/13#issuecomment-337947000. - -### v3.2.1 - 10-18-2017 - -- Fix HtmlServiceProvider. [#38], credits to @ElfSundae. -- Fix changelog PR links. [#39] - -### v3.2.0 - 10-13-2017 - -- Review tableAttributes getter and setter [#31] -- Fix CS. [#36] -- Add setTableId() to Html Builder [#35]. -- Add addTableClass, removeTableClass to Html Builder [#37] -- All changes credits to @ElfSundae. - -### v3.1.0 - 09-14-2017 - -- Added generateJson to Html/Builder [#29], credits to @lk77. - -### v3.0.3 - 09-12-2017 - -- Fix column attributes removed when generate script. [#28], credits to @as247. -- Fix https://github.com/yajra/laravel-datatables/issues/1380. - -### v3.0.2 - 09-09-2017 - -- Fix Request class doc blocks. -- Fix typo Datatables to DataTables. - -### v3.0.1 - 09-09-2017 - -- Add fnServerParams to validCallbacks [#26]. Credits to @cracki. - -### v3.0.0 - 08-31-2017 - -- v3.0 stable release. - -### v2.0.6 - 07-29-2017 - -- Adding type GET to minifiedAjax in Html/Builder [#21], credits to @lk77. - -### v2.0.5 - 06-29-2017 - -- Fix fetching of default table id from config. [#19] - -### v2.0.4 - 06-29-2017 - -- Fix missing semi-colon. - -### v2.0.3 - 06-29-2017 - -- Script cleanup [#18] -- Clean up extra space and floating ; on generated ajax data script. -- Do not include attributes on generated column scripts. - -### v2.0.2 - 06-29-2017 - -- Fix parsing of column functions. [#17] - -### v2.0.1 - 06-29-2017 - -- Fix parsing of ajax data where function is rendered as string. [#16] - -### v2.0.0 - 06-28-2017 - -- Add support for Laravel 5.5 -- Removed unused classes on constructor. - - UrlGenerator - - FormBuilder -- Fix addCheckbox. -- Use HtmlString when generating table and scripts markup. -- Make default table attributes configurable. Fix [#3] -- Use PHPUNIT 6.x, update tests. -- Add macroable trait for builder extension via macro calls. - -### v1.4.1 - 06-26-2017 - -- Set default ajax url to empty string. - -### v1.4.0 - 06-26-2017 - -- Add minifiedAjax method to minify url generated when using get request. [#13] -- Fixes `php artisan serve` and IE issues on long URL. -- Related Issues: - yajra/laravel-datatables#1225 - yajra/laravel-datatables#1205 - yajra/laravel-datatables#826 - yajra/laravel-datatables#671 - etc... - -### v1.3.0 - 06-24-2017 - -- Adding addBefore and addColumnBefore in Builder. -- PR [#12], credits to @lk77. - -### v1.2.0 - 03-28-2017 - -- Add method to remove column by names. [#9] - -### v1.1.1 - 03-28-2017 - -- Fix columns setter. [#8] +### UNRELEASED -### v1.1.0 - 02-03-2017 +### v12.0.2 (2025-04-28) -- Configurable header attributes. [#4] -- Credits to @alfa6661. +- fix: use DOMContentLoaded #237 +- fix: https://github.com/yajra/laravel-datatables-html/pull/235 -### v1.0.0 - 01-27-2017 +### v12.0.1 (2025-03-31) -- First release. +- feat: select keyboard navigation and selection #236 -[#4]: https://github.com/yajra/laravel-datatables-html/pull/4 -[#8]: https://github.com/yajra/laravel-datatables-html/pull/8 -[#9]: https://github.com/yajra/laravel-datatables-html/pull/9 -[#12]: https://github.com/yajra/laravel-datatables-html/pull/12 -[#13]: https://github.com/yajra/laravel-datatables-html/pull/13 -[#16]: https://github.com/yajra/laravel-datatables-html/pull/16 -[#17]: https://github.com/yajra/laravel-datatables-html/pull/17 -[#18]: https://github.com/yajra/laravel-datatables-html/pull/18 -[#19]: https://github.com/yajra/laravel-datatables-html/pull/19 -[#21]: https://github.com/yajra/laravel-datatables-html/pull/21 -[#26]: https://github.com/yajra/laravel-datatables-html/pull/26 -[#28]: https://github.com/yajra/laravel-datatables-html/pull/28 -[#29]: https://github.com/yajra/laravel-datatables-html/pull/29 -[#31]: https://github.com/yajra/laravel-datatables-html/pull/31 -[#35]: https://github.com/yajra/laravel-datatables-html/pull/35 -[#36]: https://github.com/yajra/laravel-datatables-html/pull/36 -[#37]: https://github.com/yajra/laravel-datatables-html/pull/37 -[#38]: https://github.com/yajra/laravel-datatables-html/pull/38 -[#39]: https://github.com/yajra/laravel-datatables-html/pull/39 -[#47]: https://github.com/yajra/laravel-datatables-html/pull/47 -[#49]: https://github.com/yajra/laravel-datatables-html/pull/49 -[#52]: https://github.com/yajra/laravel-datatables-html/pull/52 -[#54]: https://github.com/yajra/laravel-datatables-html/pull/54 -[#56]: https://github.com/yajra/laravel-datatables-html/pull/56 -[#57]: https://github.com/yajra/laravel-datatables-html/pull/57 -[#59]: https://github.com/yajra/laravel-datatables-html/pull/59 -[#55]: https://github.com/yajra/laravel-datatables-html/pull/55 -[#62]: https://github.com/yajra/laravel-datatables-html/pull/62 -[#69]: https://github.com/yajra/laravel-datatables-html/pull/69 -[#70]: https://github.com/yajra/laravel-datatables-html/pull/70 -[#71]: https://github.com/yajra/laravel-datatables-html/pull/71 -[#73]: https://github.com/yajra/laravel-datatables-html/pull/73 -[#77]: https://github.com/yajra/laravel-datatables-html/pull/77 -[#78]: https://github.com/yajra/laravel-datatables-html/pull/78 -[#80]: https://github.com/yajra/laravel-datatables-html/pull/80 -[#83]: https://github.com/yajra/laravel-datatables-html/pull/83 -[#84]: https://github.com/yajra/laravel-datatables-html/pull/84 -[#86]: https://github.com/yajra/laravel-datatables-html/pull/86 -[#87]: https://github.com/yajra/laravel-datatables-html/pull/87 -[#90]: https://github.com/yajra/laravel-datatables-html/pull/90 -[#94]: https://github.com/yajra/laravel-datatables-html/pull/94 -[#99]: https://github.com/yajra/laravel-datatables-html/pull/99 -[#101]: https://github.com/yajra/laravel-datatables-html/pull/101 -[#103]: https://github.com/yajra/laravel-datatables-html/pull/103 -[#107]: https://github.com/yajra/laravel-datatables-html/pull/107 -[#108]: https://github.com/yajra/laravel-datatables-html/pull/108 -[#109]: https://github.com/yajra/laravel-datatables-html/pull/109 -[#110]: https://github.com/yajra/laravel-datatables-html/pull/110 -[#111]: https://github.com/yajra/laravel-datatables-html/pull/111 -[#112]: https://github.com/yajra/laravel-datatables-html/pull/112 -[#114]: https://github.com/yajra/laravel-datatables-html/pull/114 -[#116]: https://github.com/yajra/laravel-datatables-html/pull/116 -[#122]: https://github.com/yajra/laravel-datatables-html/pull/122 -[#124]: https://github.com/yajra/laravel-datatables-html/pull/124 -[#117]: https://github.com/yajra/laravel-datatables-html/pull/117 -[#125]: https://github.com/yajra/laravel-datatables-html/pull/125 -[#131]: https://github.com/yajra/laravel-datatables-html/pull/131 -[#135]: https://github.com/yajra/laravel-datatables-html/pull/135 -[#127]: https://github.com/yajra/laravel-datatables-html/pull/127 -[#139]: https://github.com/yajra/laravel-datatables-html/pull/139 -[#138]: https://github.com/yajra/laravel-datatables-html/pull/138 -[#133]: https://github.com/yajra/laravel-datatables-html/pull/133 -[#142]: https://github.com/yajra/laravel-datatables-html/pull/142 -[#143]: https://github.com/yajra/laravel-datatables-html/pull/143 -[#144]: https://github.com/yajra/laravel-datatables-html/pull/144 -[#137]: https://github.com/yajra/laravel-datatables-html/pull/137 -[#147]: https://github.com/yajra/laravel-datatables-html/pull/147 -[#152]: https://github.com/yajra/laravel-datatables-html/pull/152 -[#154]: https://github.com/yajra/laravel-datatables-html/pull/154 +### v12.0.0 (2025-02-26) -[#134]: https://github.com/yajra/laravel-datatables-html/issues/134 -[#3]: https://github.com/yajra/laravel-datatables-html/issues/3 -[#58]: https://github.com/yajra/laravel-datatables-html/issues/58 -[#102]: https://github.com/yajra/laravel-datatables-html/issues/102 -[#121]: https://github.com/yajra/laravel-datatables-html/issues/121 +- feat: Laravel 12 support #234 diff --git a/LICENSE.md b/LICENSE.md index 7c2696e..178e525 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ (The MIT License) -Copyright (c) 2013-2018 Arjay Angeles +Copyright (c) 2013-2022 Arjay Angeles Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 2072a3b..9103975 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,66 @@ -# Laravel DataTables Html Plugin. +# Laravel DataTables Html Plugin -[![Laravel 5.4+](https://img.shields.io/badge/Laravel-5.4+-orange.svg)](http://laravel.com) +[![Laravel 12.x](https://img.shields.io/badge/Laravel-12.x-orange.svg)](http://laravel.com) [![Latest Stable Version](https://img.shields.io/packagist/v/yajra/laravel-datatables-html.svg)](https://packagist.org/packages/yajra/laravel-datatables-html) -![Build Status](https://github.com/yajra/laravel-datatables-html/workflows/tests/badge.svg) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/yajra/laravel-datatables-html/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/yajra/laravel-datatables-html/?branch=master) [![Total Downloads](https://img.shields.io/packagist/dt/yajra/laravel-datatables-html.svg)](https://packagist.org/packages/yajra/laravel-datatables-html) [![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://packagist.org/packages/yajra/laravel-datatables-html) +[![Continuous Integration](https://github.com/yajra/laravel-datatables-html/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/yajra/laravel-datatables-html/actions/workflows/continuous-integration.yml) +[![Static Analysis](https://github.com/yajra/laravel-datatables-html/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/yajra/laravel-datatables-html/actions/workflows/static-analysis.yml) +[![PHP Linting](https://github.com/yajra/laravel-datatables-html/actions/workflows/pint.yml/badge.svg)](https://github.com/yajra/laravel-datatables-html/actions/workflows/pint.yml) + This package is a plugin of [Laravel DataTables](https://github.com/yajra/laravel-datatables) for generating dataTables script using PHP. ## Requirements -- [Laravel 5.4+](https://github.com/laravel/framework) -- [Laravel DataTables v7.x|v8.x|9.x](https://github.com/yajra/laravel-datatables) + +- [Laravel 12.x](https://github.com/laravel/framework) +- [Laravel DataTables](https://github.com/yajra/laravel-datatables) ## Documentations + - [Laravel DataTables Documentation](http://yajrabox.com/docs/laravel-datatables) -- [Demo Application](http://datatables.yajrabox.com) is available for artisan's reference. + +## Laravel Version Compatibility + +| Laravel | Package | +|:--------------|:--------| +| 8.x and below | 4.x | +| 9.x | 9.x | +| 10.x | 10.x | +| 11.x | 11.x | +| 12.x | 12.x | ## Quick Installation -`composer require yajra/laravel-datatables-html:^4.0` -#### Service Provider (Optional on Laravel 5.5+) -`Yajra\DataTables\HtmlServiceProvider::class` +`composer require yajra/laravel-datatables-html:^12` + +#### Setup scripts with ViteJS + +Set the default javascript type to `module` by setting `Builder::useVite()` in the `AppServiceProvider`. + +```php +namespace App\Providers; + +use Illuminate\Pagination\Paginator; +use Illuminate\Support\ServiceProvider; +use Yajra\DataTables\Html\Builder; + +class AppServiceProvider extends ServiceProvider +{ + /** + * Bootstrap any application services. + */ + public function boot(): void + { + Paginator::useBootstrapFive(); + Builder::useVite(); + } +} +``` #### Publish Assets (Optional) + `$ php artisan vendor:publish --tag=datatables-html` And that's it! Start building out some awesome DataTables! diff --git a/UPGRADE.md b/UPGRADE.md index 453dc3e..011b035 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1 +1,5 @@ # Upgrade Notes + +## v10 to v11 + +- Editor `scope` method has been renamed to `formScope`. diff --git a/composer.json b/composer.json index 81f5b85..784ffcb 100644 --- a/composer.json +++ b/composer.json @@ -1,50 +1,68 @@ { - "name": "yajra/laravel-datatables-html", - "description": "Laravel DataTables HTML builder plugin for Laravel 5.4+.", - "keywords": [ - "laravel", - "dataTables", - "jquery", - "html", - "js" - ], - "license": "MIT", - "authors": [ - { - "name": "Arjay Angeles", - "email": "aqangeles@gmail.com" - } - ], - "require": { - "php": "^7.1.3|^8", - "ext-json": "*", - "yajra/laravel-datatables-oracle": "~9.0", - "laravelcollective/html": "^5.4|^6" - }, - "require-dev": { - "mockery/mockery": "^1.3.1", - "phpunit/phpunit": "^9.3" - }, - "autoload": { - "psr-4": { - "Yajra\\DataTables\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Yajra\\DataTables\\Tests\\": "tests/" - } - }, - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" + "name": "yajra/laravel-datatables-html", + "description": "Laravel DataTables HTML builder plugin", + "keywords": [ + "yajra", + "laravel", + "dataTables", + "jquery", + "html", + "js" + ], + "license": "MIT", + "authors": [ + { + "name": "Arjay Angeles", + "email": "aqangeles@gmail.com" + } + ], + "require": { + "php": "^8.2", + "ext-json": "*", + "yajra/laravel-datatables-oracle": "^12.0" }, - "laravel": { - "providers": [ - "Yajra\\DataTables\\HtmlServiceProvider" - ] - } - }, - "minimum-stability": "dev", - "prefer-stable": true + "require-dev": { + "larastan/larastan": "^3.1", + "orchestra/testbench": "^10", + "laravel/pint": "^1.21", + "rector/rector": "^2.0", + "livewire/livewire": "^3.4" + }, + "suggest": { + "laravel/livewire": "Required for Livewire layout support." + }, + "autoload": { + "psr-4": { + "Yajra\\DataTables\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Yajra\\DataTables\\Html\\Tests\\": "tests/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + }, + "laravel": { + "providers": [ + "Yajra\\DataTables\\HtmlServiceProvider" + ] + } + }, + "scripts": { + "test": "./vendor/bin/phpunit", + "pint": "./vendor/bin/pint", + "rector": "./vendor/bin/rector", + "stan": "./vendor/bin/phpstan analyse --memory-limit=2G --ansi --no-progress --no-interaction --configuration=phpstan.neon.dist", + "pr": [ + "@rector", + "@pint", + "@stan", + "@test" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..23d24cc --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,20 @@ +includes: + - ./vendor/larastan/larastan/extension.neon + +parameters: + + paths: + - src + + level: 9 + + ignoreErrors: + - '#Unsafe usage of new static\(\).#' + - identifier: missingType.generics + - identifier: missingType.iterableValue + - identifier: binaryOp.invalid + - identifier: return.type + - identifier: argument.type + + excludePaths: + - ./src/Html/Fluent.php diff --git a/phpunit.xml b/phpunit.xml index 3366726..2cb7512 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,23 +1,8 @@ - - - - ./tests/ - - - - - ./vendor - - + + + + ./tests/ + + diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..93061b6 --- /dev/null +++ b/pint.json @@ -0,0 +1,3 @@ +{ + "preset": "laravel" +} diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..ca7ca05 --- /dev/null +++ b/rector.php @@ -0,0 +1,22 @@ +paths([ + __DIR__.'/src', + __DIR__.'/tests', + ]); + + // register a single rule + $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); + + // define sets of rules + $rectorConfig->sets([ + LevelSetList::UP_TO_PHP_82, + ]); +}; diff --git a/src/Html/Builder.php b/src/Html/Builder.php index 8edd318..9172874 100644 --- a/src/Html/Builder.php +++ b/src/Html/Builder.php @@ -2,135 +2,138 @@ namespace Yajra\DataTables\Html; -use Collective\Html\HtmlBuilder; use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\View\Factory; -use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\HtmlString; -use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; +use Yajra\DataTables\Utilities\Helper; class Builder { - use Macroable; - use HasOptions; - use HasTable; - use HasEditor; - use Columns\Index; use Columns\Action; use Columns\Checkbox; + use Columns\Index; + use HasEditor; + use HasOptions; + use HasTable; + use Macroable; // Select plugin constants. - const SELECT_STYLE_API = 'api'; - const SELECT_STYLE_SINGLE = 'single'; - const SELECT_STYLE_MULTI = 'multi'; - const SELECT_STYLE_OS = 'os'; - const SELECT_STYLE_MULTI_SHIFT = 'multi+shift'; - const SELECT_ITEMS_ROW = 'row'; - const SELECT_ITEMS_COLUMN = 'column'; - const SELECT_ITEMS_CELL = 'cell'; + final public const SELECT_STYLE_API = 'api'; - /** - * @var Collection - */ - public $collection; + final public const SELECT_STYLE_SINGLE = 'single'; - /** - * @var Repository - */ - public $config; + final public const SELECT_STYLE_MULTI = 'multi'; - /** - * @var Factory - */ - public $view; + final public const SELECT_STYLE_OS = 'os'; + + final public const SELECT_STYLE_MULTI_SHIFT = 'multi+shift'; + + final public const SELECT_ITEMS_ROW = 'row'; + + final public const SELECT_ITEMS_COLUMN = 'column'; + + final public const SELECT_ITEMS_CELL = 'cell'; /** - * @var HtmlBuilder + * The default type to use for the DataTables javascript. */ - public $html; + protected static string $jsType = 'text/javascript'; /** - * @var array + * @var Collection */ - protected $tableAttributes = []; + public Collection $collection; /** - * @var string + * @var array */ - protected $template = ''; + protected array $tableAttributes = []; + + protected string $template = ''; + + protected array $attributes = [ + 'serverSide' => true, + 'processing' => true, + ]; + + protected string|array $ajax = ''; + + protected array $additionalScripts = []; + + public function __construct(public Repository $config, public Factory $view, public HtmlBuilder $html) + { + /** @var array $defaults */ + $defaults = $this->config->get('datatables-html.table', []); + + $this->collection = new Collection; + $this->tableAttributes = $defaults; + } /** - * @var array + * Set the default type to module for the DataTables javascript. */ - protected $attributes = []; + public static function useVite(): void + { + static::$jsType = 'module'; + } /** - * @param Repository $config - * @param Factory $view - * @param HtmlBuilder $html + * Set the default type to text/javascript for the DataTables javascript. */ - public function __construct(Repository $config, Factory $view, HtmlBuilder $html) + public static function useWebpack(): void { - $this->config = $config; - $this->view = $view; - $this->html = $html; - $this->collection = new Collection; - $this->tableAttributes = $this->config->get('datatables-html.table', []); - $this->attributes = [ - 'serverSide' => true, - 'processing' => true, - ]; + static::$jsType = 'text/javascript'; } /** * Generate DataTable javascript. - * - * @param null $script - * @param array $attributes - * @return \Illuminate\Support\HtmlString - * @throws \Exception */ - public function scripts($script = null, array $attributes = ['type' => 'text/javascript']) + public function scripts(?string $script = null, array $attributes = []): HtmlString { $script = $script ?: $this->generateScripts(); - $attributes = $this->html->attributes($attributes); + $attributes = $this->html->attributes( + array_merge($attributes, ['type' => $attributes['type'] ?? static::$jsType]) + ); - return new HtmlString("{$script}\n"); + return new HtmlString("$script"); } /** * Get generated raw scripts. - * - * @return \Illuminate\Support\HtmlString - * @throws \Exception */ - public function generateScripts() + public function generateScripts(): HtmlString { $parameters = $this->generateJson(); return new HtmlString( - sprintf($this->template(), $this->getTableAttribute('id'), $parameters) + trim(sprintf($this->template(), $this->getTableAttribute('id'), $parameters)) ); } /** * Get generated json configuration. - * - * @return string */ - public function generateJson() + public function generateJson(): string { return $this->parameterize($this->getOptions()); } + /** + * Generate DataTables js parameters. + */ + public function parameterize(array $attributes = []): string + { + $parameters = (new Parameters($attributes))->toArray(); + + return Helper::toJsonScript($parameters); + } + /** * Get DataTable options array. - * - * @return array */ - public function getOptions() + public function getOptions(): array { return array_merge( $this->attributes, [ @@ -145,92 +148,42 @@ public function getOptions() ); } - /** - * Generate DataTables js parameters. - * - * @param array $attributes - * @return string - */ - public function parameterize($attributes = []) - { - $parameters = (new Parameters($attributes))->toArray(); - - $values = []; - $replacements = []; - - foreach (Arr::dot($parameters) as $key => $value) { - if ($this->isCallbackFunction($value, $key)) { - $values[] = trim($value); - Arr::set($parameters, $key, '%' . $key . '%'); - $replacements[] = '"%' . $key . '%"'; - } - } - - $new = []; - foreach ($parameters as $key => $value) { - Arr::set($new, $key, $value); - } - - $json = json_encode($new); - - $json = str_replace($replacements, $values, $json); - - return $json; - } - - /** - * Check if given key & value is a valid callback js function. - * - * @param string $value - * @param string $key - * @return bool - */ - protected function isCallbackFunction($value, $key) - { - if (empty($value)) { - return false; - } - - $callbacks = $this->config->get('datatables-html.callback', ['$', '$.', 'function']); - - return Str::startsWith(trim($value), $callbacks) || Str::contains($key, 'editor'); - } - /** * Get javascript template to use. - * - * @return string */ - protected function template() + protected function template(): string { - $template = $this->template ?: $this->config->get('datatables-html.script', 'datatables::script'); + /** @var view-string $configTemplate */ + $configTemplate = $this->config->get('datatables-html.script', 'datatables::script'); + + $template = $this->template ?: $configTemplate; - return $this->view->make($template, ['editors' => $this->editors])->render(); + return $this->view->make($template, ['editors' => $this->editors, 'scripts' => $this->additionalScripts])->render(); } /** * Generate DataTable's table html. - * - * @param array $attributes - * @param bool $drawFooter - * @param bool $drawSearch - * @return \Illuminate\Support\HtmlString */ - public function table(array $attributes = [], $drawFooter = false, $drawSearch = false) + public function table(array $attributes = [], bool $drawFooter = false, bool $drawSearch = false): HtmlString { $this->setTableAttributes($attributes); $th = $this->compileTableHeaders(); $htmlAttr = $this->html->attributes($this->tableAttributes); - $tableHtml = ''; - $searchHtml = $drawSearch ? '' . implode('', - $this->compileTableSearchHeaders()) . '' : ''; - $tableHtml .= '' . implode('', $th) . '' . $searchHtml . ''; + $tableHtml = ''; + $searchHtml = $drawSearch + ? ''.implode('', $this->compileTableSearchHeaders()).'' + : ''; + + $tableHtml .= 'theadClass ?? '').'>'; + $tableHtml .= ''.implode('', $th).''.$searchHtml.''; + if ($drawFooter) { $tf = $this->compileTableFooter(); - $tableHtml .= '' . implode('', $tf) . ''; + $tableHtml .= ''.implode('', $tf).''; } + $tableHtml .= '
'; return new HtmlString($tableHtml); @@ -239,10 +192,9 @@ public function table(array $attributes = [], $drawFooter = false, $drawSearch = /** * Configure DataTable's parameters. * - * @param array $attributes * @return $this */ - public function parameters(array $attributes = []) + public function parameters(array $attributes = []): static { $this->attributes = array_merge($this->attributes, $attributes); @@ -250,52 +202,65 @@ public function parameters(array $attributes = []) } /** - * Set custom javascript template. + * Generate scripts that set the dataTables options into a variable. * - * @param string $template * @return $this */ - public function setTemplate($template) + public function asOptions(): static { - $this->template = $template; - - return $this; + return $this->setTemplate('datatables::options'); } /** - * Make a data script to be appended on ajax request of dataTables. + * Set custom javascript template. * - * @param array $data - * @return string + * @return $this */ - protected function makeDataScript(array $data) + public function setTemplate(string $template): static { - $script = ''; - foreach ($data as $key => $value) { - $dataValue = $this->isCallbackFunction($value, $key) ? $value : "'{$value}'"; - $script .= PHP_EOL . "data.{$key} = {$dataValue};"; - } + $this->template = $template; - return $script; + return $this; } /** - * Generate scripts that sets the dataTables options into a variable. + * Wrap dataTable scripts with a function. * * @return $this */ - public function asOptions() + public function asFunction(): static { - return $this->setTemplate('datatables::options'); + return $this->setTemplate('datatables::function'); + } + + public function getAttributes(): array + { + return $this->attributes; + } + + public function getAttribute(string $key, mixed $default = ''): mixed + { + return $this->attributes[$key] ?? $default; + } + + public function getAjax(?string $key = null): array|string + { + if (! is_null($key)) { + return $this->ajax[$key] ?? ''; + } + + return $this->ajax; } /** - * Wrap dataTable scripts with a function. + * Add additional scripts to the DataTables JS initialization. * * @return $this */ - public function asFunction() + public function addScript(string $view): static { - return $this->setTemplate('datatables::function'); + $this->additionalScripts[] = $view; + + return $this; } } diff --git a/src/Html/Button.php b/src/Html/Button.php index e63c6a3..0823962 100755 --- a/src/Html/Button.php +++ b/src/Html/Button.php @@ -2,20 +2,19 @@ namespace Yajra\DataTables\Html; -use Illuminate\Support\Fluent; +use Closure; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Support\Traits\Macroable; class Button extends Fluent implements Arrayable { use HasAuthorizations; + use Macroable; /** * Make a new button instance. - * - * @param string|array $options - * @return static */ - public static function make($options = []) + public static function make(array|string $options = []): static { if (is_string($options)) { return new static(['extend' => $options]); @@ -26,11 +25,8 @@ public static function make($options = []) /** * Make a raw button that does not extend anything. - * - * @param array $options - * @return static */ - public static function raw($options = []) + public static function raw(array|string $options = []): static { if (is_string($options)) { return new static(['text' => $options]); @@ -42,11 +38,11 @@ public static function raw($options = []) /** * Set attr option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.attr */ - public function attr(array $value) + public function attr(array $value): static { $this->attributes['attr'] = $value; @@ -56,11 +52,11 @@ public function attr(array $value) /** * Set available option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.available */ - public function available($value) + public function available(string $value): static { if ($this->isFunction($value)) { $this->attributes['available'] = $value; @@ -73,23 +69,20 @@ public function available($value) /** * Check if a given value is a function. - * - * @param string $value - * @return bool */ - protected function isFunction($value) + protected function isFunction(string $value): bool { - return substr($value, 0, 8) == 'function'; + return str_starts_with($value, 'function'); } /** * Set enabled option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.enabled */ - public function enabled($value = true) + public function enabled(bool $value = true): static { $this->attributes['enabled'] = $value; @@ -99,11 +92,11 @@ public function enabled($value = true) /** * Set init option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.init */ - public function init($value) + public function init(string $value): static { if ($this->isFunction($value)) { $this->attributes['init'] = $value; @@ -117,11 +110,11 @@ public function init($value) /** * Set key option value. * - * @param string|array $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.key */ - public function key($value) + public function key(array|string $value): static { $this->attributes['key'] = $value; @@ -131,11 +124,11 @@ public function key($value) /** * Set extend option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.extend */ - public function extend($value) + public function extend(string $value): static { $this->attributes['extend'] = $value; @@ -145,11 +138,11 @@ public function extend($value) /** * Set editor option value. * - * @param string $value * @return $this + * * @see https://editor.datatables.net/reference/button */ - public function editor($value) + public function editor(string $value): static { $this->attributes['editor'] = $value; @@ -159,11 +152,11 @@ public function editor($value) /** * Set buttons option value. * - * @param array $buttons * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons */ - public function buttons(array $buttons) + public function buttons(array $buttons): static { foreach ($buttons as $key => $button) { if ($button instanceof Arrayable) { @@ -177,11 +170,11 @@ public function buttons(array $buttons) } /** - * @param array $buttons * @return $this + * * @see https://editor.datatables.net/examples/api/cancelButton */ - public function formButtons(array $buttons) + public function formButtons(array $buttons): static { foreach ($buttons as $key => $button) { if ($button instanceof Arrayable) { @@ -195,14 +188,14 @@ public function formButtons(array $buttons) } /** - * @param mixed $message * @return $this + * * @see https://editor.datatables.net/examples/api/removeMessage * @see https://editor.datatables.net/reference/button/create * @see https://editor.datatables.net/reference/button/edit * @see https://editor.datatables.net/reference/button/remove */ - public function formMessage($message) + public function formMessage(string $message): static { $this->attributes['formMessage'] = $message; @@ -210,13 +203,13 @@ public function formMessage($message) } /** - * @param mixed $title * @return $this + * * @see https://editor.datatables.net/reference/button/create * @see https://editor.datatables.net/reference/button/edit * @see https://editor.datatables.net/reference/button/remove */ - public function formTitle($title) + public function formTitle(string $title): static { $this->attributes['formTitle'] = $title; @@ -226,11 +219,11 @@ public function formTitle($title) /** * Set className option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.className */ - public function className($value) + public function className(string $value): static { $this->attributes['className'] = $value; @@ -240,11 +233,11 @@ public function className($value) /** * Set destroy option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.destroy */ - public function destroy($value) + public function destroy(string $value): static { if ($this->isFunction($value)) { $this->attributes['destroy'] = $value; @@ -258,11 +251,11 @@ public function destroy($value) /** * Set customize option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/button/excelHtml5 */ - public function customize($value) + public function customize(string $value): static { $this->attributes['customize'] = $value; @@ -272,28 +265,29 @@ public function customize($value) /** * Append a class name to column. * - * @param string $class * @return $this */ - public function addClass($class) + public function addClass(string $class): static { if (! isset($this->attributes['className'])) { $this->attributes['className'] = $class; - } else { - $this->attributes['className'] .= " $class"; + + return $this; } + $this->attributes['className'] = $this->attributes['className']." $class"; + return $this; } /** * Set text option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.text */ - public function text($value) + public function text(string $value): static { $this->attributes['text'] = $value; @@ -303,11 +297,11 @@ public function text($value) /** * Set titleAttr option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.titleAttr */ - public function titleAttr($value) + public function titleAttr(string $value): static { $this->attributes['titleAttr'] = $value; @@ -317,11 +311,11 @@ public function titleAttr($value) /** * Set name option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.name */ - public function name($value) + public function name(string $value): static { $this->attributes['name'] = $value; @@ -331,11 +325,11 @@ public function name($value) /** * Set namespace option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.namespace */ - public function namespace($value) + public function namespace(string $value): static { $this->attributes['namespace'] = $value; @@ -345,11 +339,11 @@ public function namespace($value) /** * Set tag option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/buttons.buttons.tag */ - public function tag($value) + public function tag(string $value): static { $this->attributes['tag'] = $value; @@ -359,10 +353,9 @@ public function tag($value) /** * Set columns option value. * - * @param mixed $value * @return $this */ - public function columns($value) + public function columns(array|string $value): static { $this->attributes['columns'] = $value; @@ -372,10 +365,9 @@ public function columns($value) /** * Set exportOptions option value. * - * @param mixed $value * @return $this */ - public function exportOptions($value) + public function exportOptions(array|string $value): static { $this->attributes['exportOptions'] = $value; @@ -385,24 +377,21 @@ public function exportOptions($value) /** * Set action to submit the form. * - * @return \Yajra\DataTables\Html\Button + * @return $this */ - public function actionSubmit() + public function actionSubmit(): static { - $this->attributes['action'] = 'function() { this.submit(); }'; - - return $this; + return $this->action('function() { this.submit(); }'); } /** * Set action option value. * - * @param string $value * @return $this */ - public function action($value) + public function action(string $value): static { - if (substr($value, 0, 8) == 'function') { + if (str_starts_with($value, 'function')) { $this->attributes['action'] = $value; } else { $this->attributes['action'] = "function(e, dt, node, config) { $value }"; @@ -414,38 +403,60 @@ public function action($value) /** * Set editor class action handler. * - * @param string $action - * @return \Yajra\DataTables\Html\Button + * @return $this */ - public function actionHandler($action) + public function actionHandler(string $action): static { - $this->attributes['action'] = "function() { this.submit(null, null, function(data) { data.action = '{$action}'; return data; }) }"; - - return $this; + return $this->action("function() { this.submit(null, null, function(data) { data.action = '{$action}'; return data; }) }"); } /** * Set action to close the form. * - * @return \Yajra\DataTables\Html\Button + * @return $this */ - public function actionClose() + public function actionClose(): static { - $this->attributes['action'] = 'function() { this.close(); }'; - - return $this; + return $this->action('function() { this.close(); }'); } /** * Set button alignment. * - * @param string $align - * @return \Yajra\DataTables\Html\Button + * @return $this */ - public function align($align = 'button-left') + public function align(string $align = 'button-left'): static { $this->attributes['align'] = $align; return $this; } + + /** + * Handle dynamic calls to the fluent instance or macroable methods. + * + * @param string $method + * @param array $parameters + * @return mixed + * + * @throws \BadMethodCallException + */ + public function __call($method, $parameters) + { + // Check if the method is a macro (Macroable functionality). + if (static::hasMacro($method)) { + $macro = static::$macros[$method]; + + if ($macro instanceof Closure) { + $macro = $macro->bindTo($this, static::class); + } + + return $macro(...$parameters); + } + + // Fallback to Fluent behavior if it's not a macro. + $this->attributes[$method] = count($parameters) > 0 ? reset($parameters) : true; + + return $this; + } } diff --git a/src/Html/Column.php b/src/Html/Column.php index c98ab6b..fcebc04 100644 --- a/src/Html/Column.php +++ b/src/Html/Column.php @@ -3,23 +3,38 @@ namespace Yajra\DataTables\Html; use Illuminate\Support\Arr; -use Illuminate\Support\Fluent; use Illuminate\Support\Str; use Yajra\DataTables\Html\Options\Plugins\SearchPanes; /** - * @property string data - * @property string name - * @property string orderable - * @property string searchable - * @property string printable - * @property string exportable - * @property string footer - * @property array attributes + * @property array|string $data + * @property string $name + * @property string $title + * @property string $titleAttr + * @property bool $orderable + * @property bool $searchable + * @property bool $printable + * @property bool $exportable + * @property array|string $footer + * @property array $attributes + * @property string $render + * @property string $className + * @property string $editField + * @property int|array $orderData + * @property string $orderDataType + * @property string $orderSequence + * @property string $cellType + * @property string $type + * @property string $contentPadding + * @property string $createdCell + * @property string $exportFormat + * @property callable $exportRender + * * @see https://datatables.net/reference/option/#columns */ class Column extends Fluent { + use HasAuthorizations; use SearchPanes; /** @@ -27,23 +42,23 @@ class Column extends Fluent */ public function __construct($attributes = []) { - $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : self::titleFormat($attributes['data']); - $attributes['orderable'] = isset($attributes['orderable']) ? $attributes['orderable'] : true; - $attributes['searchable'] = isset($attributes['searchable']) ? $attributes['searchable'] : true; - $attributes['exportable'] = isset($attributes['exportable']) ? $attributes['exportable'] : true; - $attributes['printable'] = isset($attributes['printable']) ? $attributes['printable'] : true; - $attributes['footer'] = isset($attributes['footer']) ? $attributes['footer'] : ''; - $attributes['attributes'] = isset($attributes['attributes']) ? $attributes['attributes'] : []; + $attributes['title'] ??= self::titleFormat($attributes['data'] ?? ''); + $attributes['orderable'] ??= true; + $attributes['searchable'] ??= true; + $attributes['exportable'] ??= true; + $attributes['printable'] ??= true; + $attributes['footer'] ??= ''; + $attributes['attributes'] ??= []; // Allow methods override attribute value foreach ($attributes as $attribute => $value) { - $method = 'parse' . ucfirst(strtolower($attribute)); - if (!is_null($value) && method_exists($this, $method)) { + $method = 'parse'.ucfirst(strtolower($attribute)); + if (! is_null($value) && method_exists($this, $method)) { $attributes[$attribute] = $this->$method($value); } } - if (!isset($attributes['name']) && isset($attributes['data'])) { + if (! isset($attributes['name']) && isset($attributes['data'])) { $attributes['name'] = $attributes['data']; } @@ -52,23 +67,30 @@ public function __construct($attributes = []) /** * Format string to title case. + */ + public static function titleFormat(string $value): string + { + return Str::title(str_replace(['.', '_'], ' ', Str::snake($value))); + } + + /** + * Set column title. + * + * @return $this * - * @param string $value - * @return string + * @see https://datatables.net/reference/option/columns.title */ - public static function titleFormat($value) + public function title(string $value): static { - return Str::title(str_replace('_', ' ', $value)); + $this->attributes['title'] = $value; + + return $this; } /** * Create a computed column that is not searchable/orderable. - * - * @param string $data - * @param string|null $title - * @return Column */ - public static function computed($data, $title = null) + public static function computed(string $data, ?string $title = null): Column { if (is_null($title)) { $title = self::titleFormat($data); @@ -80,11 +102,11 @@ public static function computed($data, $title = null) /** * Set column searchable flag. * - * @param bool $flag * @return $this + * * @see https://datatables.net/reference/option/columns.searchable */ - public function searchable(bool $flag = true) + public function searchable(bool $flag = true): static { $this->attributes['searchable'] = $flag; @@ -94,61 +116,43 @@ public function searchable(bool $flag = true) /** * Set column orderable flag. * - * @param bool $flag * @return $this + * * @see https://datatables.net/reference/option/columns.orderable */ - public function orderable(bool $flag = true) + public function orderable(bool $flag = true): static { $this->attributes['orderable'] = $flag; return $this; } - /** - * Set column title. - * - * @param string $value - * @return $this - * @see https://datatables.net/reference/option/columns.title - */ - public function title($value) - { - $this->attributes['title'] = $value; - - return $this; - } - /** * Make a new column instance. - * - * @param string $data - * @param string $name - * @return Column */ - public static function make($data, $name = '') + public static function make(array|string $data = [], string $name = ''): static { - $attr = [ - 'data' => $data, - 'name' => $name ?: $data, - ]; + $attr = $data; + if (is_string($data)) { + $attr = [ + 'data' => $data, + 'name' => $name ?: $data, + ]; + } return new static($attr); } /** * Make a new formatted column instance. - * - * @param string $name - * @return Column */ - public static function formatted($name) + public static function formatted(string $name): static { $attr = [ 'data' => $name, 'name' => $name, 'title' => self::titleFormat($name), - 'render' => 'full.' . $name . '_formatted', + 'render' => 'full.'.$name.'_formatted', ]; return new static($attr); @@ -156,11 +160,8 @@ public static function formatted($name) /** * Create a checkbox column. - * - * @param string $title - * @return Column */ - public static function checkbox($title = '') + public static function checkbox(string $title = ''): static { return static::make('') ->content('') @@ -174,10 +175,9 @@ public static function checkbox($title = '') /** * Set column exportable flag. * - * @param bool $flag * @return $this */ - public function exportable(bool $flag = true) + public function exportable(bool $flag = true): static { $this->attributes['exportable'] = $flag; @@ -187,11 +187,11 @@ public function exportable(bool $flag = true) /** * Set column class name. * - * @param string $class * @return $this + * * @see https://datatables.net/reference/option/columns.className */ - public function className($class) + public function className(string $class): static { $this->attributes['className'] = $class; @@ -201,11 +201,11 @@ public function className($class) /** * Set column default content. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/columns.defaultContent */ - public function content($value) + public function content(string $value): static { $this->attributes['defaultContent'] = $value; @@ -215,11 +215,11 @@ public function content($value) /** * Set column responsive priority. * - * @param int|string $value * @return $this + * * @see https://datatables.net/reference/option/columns.responsivePriority */ - public function responsivePriority($value) + public function responsivePriority(int|string $value): static { $this->attributes['responsivePriority'] = $value; @@ -230,9 +230,10 @@ public function responsivePriority($value) * Set column hidden state. * * @return $this + * * @see https://datatables.net/reference/option/columns.visible */ - public function hidden() + public function hidden(): static { return $this->visible(false); } @@ -240,11 +241,11 @@ public function hidden() /** * Set column visible flag. * - * @param bool $flag * @return $this + * * @see https://datatables.net/reference/option/columns.visible */ - public function visible(bool $flag = true) + public function visible(bool $flag = true): static { $this->attributes['visible'] = $flag; @@ -254,12 +255,11 @@ public function visible(bool $flag = true) /** * Append a class name to field. * - * @param string $class * @return $this */ - public function addClass($class) + public function addClass(string $class): static { - if (!isset($this->attributes['className'])) { + if (! isset($this->attributes['className'])) { $this->attributes['className'] = $class; } else { $this->attributes['className'] .= " $class"; @@ -271,10 +271,9 @@ public function addClass($class) /** * Set column printable flag. * - * @param bool $flag * @return $this */ - public function printable(bool $flag = true) + public function printable(bool $flag = true): static { $this->attributes['printable'] = $flag; @@ -284,11 +283,11 @@ public function printable(bool $flag = true) /** * Set column width value. * - * @param int|string $value * @return $this + * * @see https://datatables.net/reference/option/columns.width */ - public function width($value) + public function width(int|string $value): static { $this->attributes['width'] = $value; @@ -298,11 +297,12 @@ public function width($value) /** * Set column data option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/columns.data + * @see https://datatables.net/manual/data/orthogonal-data */ - public function data($value) + public function data(array|string $value): static { $this->attributes['data'] = $value; @@ -312,11 +312,11 @@ public function data($value) /** * Set column name option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/columns.name */ - public function name($value) + public function name(string $value): static { $this->attributes['name'] = $value; @@ -326,11 +326,11 @@ public function name($value) /** * Set column edit field option value. * - * @param string|array $value * @return $this + * * @see https://datatables.net/reference/option/columns.editField */ - public function editField($value) + public function editField(array|string $value): static { $this->attributes['editField'] = $value; @@ -340,11 +340,11 @@ public function editField($value) /** * Set column orderData option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.orderData */ - public function orderData($value) + public function orderData(array|int $value): static { $this->attributes['orderData'] = $value; @@ -354,11 +354,11 @@ public function orderData($value) /** * Set column orderDataType option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.orderDataType */ - public function orderDataType($value) + public function orderDataType(string $value): static { $this->attributes['orderDataType'] = $value; @@ -368,11 +368,11 @@ public function orderDataType($value) /** * Set column orderSequence option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.orderSequence */ - public function orderSequence($value) + public function orderSequence(array $value): static { $this->attributes['orderSequence'] = $value; @@ -382,11 +382,11 @@ public function orderSequence($value) /** * Set column cellType option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.cellType */ - public function cellType($value) + public function cellType(string $value = 'th'): static { $this->attributes['cellType'] = $value; @@ -396,11 +396,11 @@ public function cellType($value) /** * Set column type option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.type */ - public function type($value) + public function type(string $value): static { $this->attributes['type'] = $value; @@ -410,11 +410,11 @@ public function type($value) /** * Set column contentPadding option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.contentPadding */ - public function contentPadding($value) + public function contentPadding(string $value): static { $this->attributes['contentPadding'] = $value; @@ -424,11 +424,11 @@ public function contentPadding($value) /** * Set column createdCell option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.createdCell */ - public function createdCell($value) + public function createdCell(string $value): static { $this->attributes['createdCell'] = $value; @@ -438,23 +438,23 @@ public function createdCell($value) /** * Use the js renderer "$.fn.dataTable.render.". * - * @param mixed $value - * @param mixed ...$params + * @param int|string|null ...$params * @return $this + * * @see https://datatables.net/reference/option/columns.render */ - public function renderJs($value, ...$params) + public function renderJs(string $value, ...$params): static { if ($params) { $value .= '('; foreach ($params as $param) { - $value .= "'{$param}',"; + $value .= sprintf("'%s',", $param); } $value = mb_substr($value, 0, -1); $value .= ')'; } - $renderer = '$.fn.dataTable.render.' . $value; + $renderer = '$.fn.dataTable.render.'.$value; return $this->render($renderer); } @@ -462,11 +462,11 @@ public function renderJs($value, ...$params) /** * Set column renderer. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.render */ - public function render($value) + public function render(mixed $value): static { $this->attributes['render'] = $this->parseRender($value); @@ -474,12 +474,21 @@ public function render($value) } /** - * Parse render attribute. + * Set Callback function to render column for Print + Export * - * @param mixed $value - * @return string|null + * @return $this + */ + public function exportRender(callable $callback): static + { + $this->attributes['exportRender'] = $callback; + + return $this; + } + + /** + * Parse render attribute. */ - public function parseRender($value) + public function parseRender(mixed $value): ?string { /** @var \Illuminate\Contracts\View\Factory $view */ $view = app('view'); @@ -494,7 +503,7 @@ public function parseRender($value) return $value($parameters); } elseif ($this->isBuiltInRenderFunction($value)) { return $value; - } elseif ($view->exists($value)) { + } elseif (is_string($value) && strlen($value) < 256 && $view->exists($value)) { return $view->make($value)->with($parameters)->render(); } @@ -503,11 +512,8 @@ public function parseRender($value) /** * Check if given key & value is a valid datatables built-in renderer function. - * - * @param string $value - * @return bool */ - private function isBuiltInRenderFunction($value) + private function isBuiltInRenderFunction(string $value): bool { if (empty($value)) { return false; @@ -518,11 +524,8 @@ private function isBuiltInRenderFunction($value) /** * Display render value as is. - * - * @param mixed $value - * @return string */ - private function parseRenderAsString($value) + private function parseRenderAsString(string $value): string { return "function(data,type,full,meta){return $value;}"; } @@ -530,11 +533,11 @@ private function parseRenderAsString($value) /** * Set column renderer with give raw value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columns.render */ - public function renderRaw($value) + public function renderRaw(mixed $value): static { $this->attributes['render'] = $value; @@ -544,10 +547,9 @@ public function renderRaw($value) /** * Set column footer. * - * @param mixed $value * @return $this */ - public function footer($value) + public function footer(mixed $value): static { $this->attributes['footer'] = $value; @@ -555,12 +557,11 @@ public function footer($value) } /** - * Set custom html title instead defult label. + * Set custom html title instead default label. * - * @param mixed $value * @return $this */ - public function titleAttr($value) + public function titleAttr(mixed $value): static { $this->attributes['titleAttr'] = $value; @@ -570,22 +571,23 @@ public function titleAttr($value) /** * Set excel column format when exporting. * - * @param string $format * @return $this + * * @see https://github.com/yajra/laravel-datatables-export */ - public function exportFormat($format) + public function exportFormat(string|callable $format): static { $this->attributes['exportFormat'] = $format; return $this; } - /** - * @return array - */ - public function toArray() + public function toArray(): array { + if (! $this->isAuthorized()) { + return []; + } + return Arr::except($this->attributes, [ 'printable', 'exportable', diff --git a/src/Html/ColumnDefinition.php b/src/Html/ColumnDefinition.php index 4a4fba9..a05cf29 100644 --- a/src/Html/ColumnDefinition.php +++ b/src/Html/ColumnDefinition.php @@ -2,16 +2,51 @@ namespace Yajra\DataTables\Html; -use Illuminate\Support\Fluent; - -class ColumnDefinition extends Fluent +/** + * @see https://datatables.net/reference/option/columnDefs + */ +class ColumnDefinition extends Column { - use HasOptions; + /** + * @param array $attributes + */ + public function __construct($attributes = []) + { + parent::__construct($attributes); + + $this->attributes = $attributes; + } + + /** + * @return $this + * + * @see https://datatables.net/reference/option/columnDefs.targets + */ + public function targets(array|string|int $value): static + { + $this->attributes['targets'] = $value; + + return $this; + } - public function targets($value) + /** + * @return $this + * + * @see https://datatables.net/reference/option/columns + */ + public function columns(array $value): static { - $this->attributes['targets'] = (array) $value; + $this->attributes['columns'] = $value; return $this; } + + public function toArray(): array + { + $array = parent::toArray(); + + unset($array['attributes']); + + return $array; + } } diff --git a/src/Html/ColumnDefinitions.php b/src/Html/ColumnDefinitions.php index 83816de..2e213e3 100644 --- a/src/Html/ColumnDefinitions.php +++ b/src/Html/ColumnDefinitions.php @@ -4,7 +4,4 @@ use Illuminate\Support\Collection; -class ColumnDefinitions extends Collection -{ - -} +class ColumnDefinitions extends Collection {} diff --git a/src/Html/Columns/Action.php b/src/Html/Columns/Action.php index 2e6d7b3..d18be02 100644 --- a/src/Html/Columns/Action.php +++ b/src/Html/Columns/Action.php @@ -7,13 +7,11 @@ trait Action { /** - * Add a action column. + * Add an action column. * - * @param array $attributes - * @param bool $prepend * @return $this */ - public function addAction(array $attributes = [], $prepend = false) + public function addAction(array $attributes = [], bool $prepend = false): static { $attributes = array_merge([ 'defaultContent' => '', diff --git a/src/Html/Columns/Checkbox.php b/src/Html/Columns/Checkbox.php index 3816a2b..dc29677 100644 --- a/src/Html/Columns/Checkbox.php +++ b/src/Html/Columns/Checkbox.php @@ -9,15 +9,14 @@ trait Checkbox /** * Add a checkbox column. * - * @param array $attributes - * @param bool|int $position true to prepend, false to append or a zero-based index for positioning + * @param bool|int $position true to prepend, false to append or a zero-based index for positioning * @return $this */ - public function addCheckbox(array $attributes = [], $position = false) + public function addCheckbox(array $attributes = [], bool|int $position = false): static { $attributes = array_merge([ - 'defaultContent' => 'html->attributes($attributes) . '/>', - 'title' => 'html->attributes($attributes + ['id' => 'dataTablesCheckbox']) . '/>', + 'defaultContent' => 'html->attributes($attributes).'/>', + 'title' => 'html->attributes($attributes + ['id' => 'dataTablesCheckbox']).'/>', 'data' => 'checkbox', 'name' => 'checkbox', 'orderable' => false, diff --git a/src/Html/Columns/Index.php b/src/Html/Columns/Index.php index 9672653..3bdfa6c 100644 --- a/src/Html/Columns/Index.php +++ b/src/Html/Columns/Index.php @@ -9,10 +9,9 @@ trait Index /** * Add a index column. * - * @param array $attributes * @return $this */ - public function addIndex(array $attributes = []) + public function addIndex(array $attributes = []): static { $indexColumn = $this->config->get('datatables.index_column', 'DT_RowIndex'); diff --git a/src/Html/Editor/Editor.php b/src/Html/Editor/Editor.php index d6617af..4e9b4b8 100644 --- a/src/Html/Editor/Editor.php +++ b/src/Html/Editor/Editor.php @@ -4,29 +4,50 @@ use Illuminate\Support\Arr; use Illuminate\Support\Str; -use Illuminate\Support\Fluent; +use Illuminate\Support\Traits\Macroable; +use Yajra\DataTables\Html\Editor\Fields\Field; +use Yajra\DataTables\Html\Fluent; use Yajra\DataTables\Html\HasAuthorizations; use Yajra\DataTables\Utilities\Helper; -use Yajra\DataTables\Html\Editor\Fields\Field; +/** + * @property string $instance + * @property string|null $table + * @property string|array|null $ajax + * @property array $fields + * @property string|null $template + * @property string $idSrc + * @property string $display + * @property string $scripts + * @property array $formOptions + */ class Editor extends Fluent { - use HasEvents; use HasAuthorizations; + use HasEvents, Macroable { + Macroable::__call as macroCall; + } + + final public const DISPLAY_LIGHTBOX = 'lightbox'; + + final public const DISPLAY_ENVELOPE = 'envelope'; - const DISPLAY_LIGHTBOX = 'lightbox'; - const DISPLAY_ENVELOPE = 'envelope'; - const DISPLAY_BOOTSTRAP = 'bootstrap'; - const DISPLAY_FOUNDATION = 'foundation'; - const DISPLAY_JQUERYUI = 'jqueryui'; + final public const DISPLAY_BOOTSTRAP = 'bootstrap'; + + final public const DISPLAY_FOUNDATION = 'foundation'; + + final public const DISPLAY_JQUERYUI = 'jqueryui'; + + public array $events = []; /** * Editor constructor. * - * @param string|array $instance + * @param string|array $instance */ public function __construct($instance = 'editor') { + $attributes = []; $attributes['instance'] = $instance; parent::__construct($attributes); @@ -34,11 +55,8 @@ public function __construct($instance = 'editor') /** * Make new Editor instance. - * - * @param string $instance - * @return Editor */ - public static function make($instance = 'editor') + public static function make(array|string $instance = 'editor'): static { if (is_array($instance)) { $instance = $instance['editor'] ?? 'editor'; @@ -50,10 +68,9 @@ public static function make($instance = 'editor') /** * Append raw scripts. * - * @param string $scripts - * @return Editor + * @return $this */ - public function scripts($scripts) + public function scripts(string $scripts): static { $this->attributes['scripts'] = $scripts; @@ -63,10 +80,9 @@ public function scripts($scripts) /** * Set Editor's variable name / instance. * - * @param $instance * @return $this */ - public function instance($instance) + public function instance(string $instance): static { $this->attributes['instance'] = $instance; @@ -76,11 +92,11 @@ public function instance($instance) /** * Set Editor's ajax parameter. * - * @param string|array $ajax * @return $this + * * @see https://editor.datatables.net/reference/option/ajax */ - public function ajax($ajax) + public function ajax(array|string $ajax): static { $this->attributes['ajax'] = $ajax; @@ -90,11 +106,11 @@ public function ajax($ajax) /** * Set Editor's table source. * - * @param string $table * @return $this + * * @see https://editor.datatables.net/reference/option/table */ - public function table($table) + public function table(string $table): static { $this->attributes['table'] = $table; @@ -104,11 +120,11 @@ public function table($table) /** * Set Editor's idSrc option. * - * @param string $idSrc * @return $this + * * @see https://editor.datatables.net/reference/option/idSrc */ - public function idSrc($idSrc = 'DT_RowId') + public function idSrc(string $idSrc = 'DT_RowId'): static { $this->attributes['idSrc'] = $idSrc; @@ -118,11 +134,11 @@ public function idSrc($idSrc = 'DT_RowId') /** * Set Editor's display option. * - * @param string $display * @return $this + * * @see https://editor.datatables.net/reference/option/display */ - public function display($display) + public function display(string $display): static { $this->attributes['display'] = $display; @@ -132,11 +148,11 @@ public function display($display) /** * Set Editor's fields. * - * @param array $fields * @return $this + * * @see https://editor.datatables.net/reference/option/fields */ - public function fields(array $fields) + public function fields(array $fields): static { $this->attributes['fields'] = $fields; @@ -144,30 +160,28 @@ public function fields(array $fields) } /** - * Set Editor's formOptions. + * Set Editor's bubble formOptions. * - * @param mixed $formOptions * @return $this - * @see https://editor.datatables.net/reference/option/formOptions - * @see https://editor.datatables.net/reference/type/form-options + * + * @see https://editor.datatables.net/reference/option/formOptions.bubble */ - public function formOptions(array $formOptions) + public function formOptionsBubble(array|FormOptions $formOptions): static { - $this->attributes['formOptions'] = $formOptions; - - return $this; + return $this->formOptions(['bubble' => Helper::castToArray($formOptions)]); } /** - * Set Editor's bubble formOptions. + * Set Editor's formOptions. * - * @param mixed $formOptions * @return $this - * @see https://editor.datatables.net/reference/option/formOptions.bubble + * + * @see https://editor.datatables.net/reference/option/formOptions + * @see https://editor.datatables.net/reference/type/form-options */ - public function formOptionsBubble(array $formOptions) + public function formOptions(array $formOptions): static { - $this->attributes['formOptions']['bubble'] = Helper::castToArray($formOptions);; + $this->attributes['formOptions'] = $formOptions; return $this; } @@ -175,39 +189,35 @@ public function formOptionsBubble(array $formOptions) /** * Set Editor's inline formOptions. * - * @param mixed $formOptions * @return $this + * * @see https://editor.datatables.net/reference/option/formOptions.inline */ - public function formOptionsInline($formOptions) + public function formOptionsInline(array|FormOptions $formOptions): static { - $this->attributes['formOptions']['inline'] = Helper::castToArray($formOptions); - - return $this; + return $this->formOptions(['inline' => Helper::castToArray($formOptions)]); } /** * Set Editor's main formOptions. * - * @param mixed $formOptions * @return $this + * * @see https://editor.datatables.net/reference/option/formOptions.main */ - public function formOptionsMain($formOptions) + public function formOptionsMain(array|FormOptions $formOptions): static { - $this->attributes['formOptions']['main'] = Helper::castToArray($formOptions); - - return $this; + return $this->formOptions(['main' => Helper::castToArray($formOptions)]); } /** * Set Editor's language. * - * @param array $language * @return $this + * * @see https://editor.datatables.net/reference/option/i18n */ - public function language(array $language) + public function language(array $language): static { $this->attributes['i18n'] = $language; @@ -217,11 +227,11 @@ public function language(array $language) /** * Set Editor's template. * - * @param string $template * @return $this + * * @see https://editor.datatables.net/reference/option/template */ - public function template($template) + public function template(string $template): static { $this->attributes['template'] = $template; @@ -230,16 +240,18 @@ public function template($template) /** * Convert the fluent instance to an array. - * - * @return array */ - public function toArray() + public function toArray(): array { + if (! $this->isAuthorized()) { + return []; + } + $array = parent::toArray(); unset($array['events']); - foreach (Arr::get($array, 'fields', []) as $key => &$field) { + foreach ((array) Arr::get($array, 'fields', []) as $key => &$field) { if ($field instanceof Field) { Arr::set($array['fields'], $key, $field->toArray()); } @@ -251,53 +263,76 @@ public function toArray() /** * Convert the fluent instance to JSON. * - * @param int $options - * @return string + * @param int $options */ - public function toJson($options = 0) + public function toJson($options = 0): string { $parameters = $this->jsonSerialize(); unset($parameters['events']); - $values = []; - $replacements = []; + return Helper::toJsonScript($parameters, $options); + } - foreach (Arr::dot($parameters) as $key => $value) { - if ($this->isCallbackFunction($value, $key)) { - $values[] = trim($value); - Arr::set($parameters, $key, '%' . $key . '%'); - $replacements[] = '"%' . $key . '%"'; - } - } + /** + * Hide fields on create action. + * + * @return $this + */ + public function hiddenOnCreate(array $fields): static + { + return $this->hiddenOn('create', $fields); + } - $new = []; - foreach ($parameters as $key => $value) { - Arr::set($new, $key, $value); + /** + * Hide fields on specific action. + * + * @return $this + */ + public function hiddenOn(string $action, array $fields): static + { + $script = 'function(e, mode, action) {'; + $script .= "if (action === '$action') {"; + foreach ($fields as $field) { + $script .= "this.hide('$field');"; } + $script .= '} else {'; + foreach ($fields as $field) { + $script .= "this.show('$field');"; + } + $script .= '}'; + $script .= 'return true;'; + $script .= '}'; - $json = json_encode($new, $options); - - $json = str_replace($replacements, $values, $json); + $this->onPreOpen($script); - return $json; + return $this; } /** - * Check if given key & value is a valid callback js function. + * Hide fields on edit action. * - * @param string $value - * @param string $key - * @return bool + * @return $this */ - protected function isCallbackFunction($value, $key) + public function hiddenOnEdit(array $fields): static + { + return $this->hiddenOn('edit', $fields); + } + + public function __call($method, $parameters): static { - if (empty($value) || is_object($value) || is_array($value)) { - return false; + if (Str::startsWith($method, 'on')) { + $event = Str::camel(substr($method, 2, strlen($method) - 2)); + + return $this->on($event, $parameters[0]); } - $callbacks = config('datatables-html.callback', ['$', '$.', 'function']); + $macroCall = $this->macroCall($method, $parameters); + + if (! $macroCall instanceof Editor) { + abort(500, sprintf('Method %s::%s must return an Editor instance.', static::class, $method)); + } - return Str::startsWith(trim($value), $callbacks) || Str::contains($key, ['editor', 'minDate', 'maxDate']); + return $this; } } diff --git a/src/Html/Editor/Fields/BelongsTo.php b/src/Html/Editor/Fields/BelongsTo.php index b09a29d..2bc8fe6 100644 --- a/src/Html/Editor/Fields/BelongsTo.php +++ b/src/Html/Editor/Fields/BelongsTo.php @@ -2,54 +2,26 @@ namespace Yajra\DataTables\Html\Editor\Fields; -use Illuminate\Support\Str; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Str; class BelongsTo extends Select { /** - * @param string|Builder $class - * @param string $text - * @param string $id - * @param string|null $foreign - * @return \Yajra\DataTables\Html\Editor\Fields\Field|static + * @param class-string<\Illuminate\Database\Eloquent\Model>|Builder $class */ - public static function model($class, $text, $id = 'id', $foreign = null) + public static function model(Builder|string $class, string $text, string $id = 'id', ?string $foreign = null): static { if ($class instanceof Builder) { $table = $class->getModel()->getTable(); } else { - $table = app($class)->getTable(); + $table = (new $class)->getTable(); } - $table = Str::singular($table); - $foreign = $foreign ?? $table . '_id'; + $table = Str::singular($table); + $foreign ??= $table.'_id'; return self::make($foreign, Str::title($table)) - ->modelOptions($class, $text, $id); - } - - /** - * Add a placeholder and allow clear. - * Note: This requires editor select2 plugin. - * - * @see https://editor.datatables.net/plug-ins/field-type/editor.select2 - * @param string $text - * @param null|string $id - * @param bool $allowClear - * @return $this - */ - public function placeholder($text, $id = null, $allowClear = true) - { - $this->type('select2') - ->opts([ - 'allowClear' => $allowClear, - 'placeholder' => [ - 'id' => $id, - 'text' => $text, - ], - ]); - - return $this; + ->modelOptions($class, $text, $id); } } diff --git a/src/Html/Editor/Fields/Boolean.php b/src/Html/Editor/Fields/Boolean.php index 86e8e49..9259d24 100644 --- a/src/Html/Editor/Fields/Boolean.php +++ b/src/Html/Editor/Fields/Boolean.php @@ -6,12 +6,8 @@ class Boolean extends Checkbox { /** * Make a new instance of a field. - * - * @param string $name - * @param string $label - * @return static|\Yajra\DataTables\Html\Editor\Fields\Field */ - public static function make($name, $label = '') + public static function make(array|string $name, string $label = ''): static { return parent::make($name, $label)->separator(',')->options( Options::make()->append('', 1) diff --git a/src/Html/Editor/Fields/Checkbox.php b/src/Html/Editor/Fields/Checkbox.php index ae02689..f55024e 100644 --- a/src/Html/Editor/Fields/Checkbox.php +++ b/src/Html/Editor/Fields/Checkbox.php @@ -4,5 +4,5 @@ class Checkbox extends Field { - protected $type = 'checkbox'; + protected string $type = 'checkbox'; } diff --git a/src/Html/Editor/Fields/Date.php b/src/Html/Editor/Fields/Date.php index 7c689ba..99f7e8f 100644 --- a/src/Html/Editor/Fields/Date.php +++ b/src/Html/Editor/Fields/Date.php @@ -6,12 +6,8 @@ class Date extends DateTime { /** * Make a new instance of a field. - * - * @param string $name - * @param string $label - * @return static|\Yajra\DataTables\Html\Editor\Fields\Field */ - public static function make($name, $label = '') + public static function make(array|string $name, string $label = ''): static { return parent::make($name, $label)->format('YYYY-MM-DD'); } diff --git a/src/Html/Editor/Fields/DateTime.php b/src/Html/Editor/Fields/DateTime.php index bb64673..de9824a 100644 --- a/src/Html/Editor/Fields/DateTime.php +++ b/src/Html/Editor/Fields/DateTime.php @@ -4,16 +4,12 @@ class DateTime extends Field { - protected $type = 'datetime'; + protected string $type = 'datetime'; /** * Make a new instance of a field. - * - * @param string $name - * @param string $label - * @return static|\Yajra\DataTables\Html\Editor\Fields\Field */ - public static function make($name, $label = '') + public static function make(array|string $name, string $label = ''): static { return parent::make($name, $label)->format('YYYY-MM-DD hh:mm a'); } @@ -23,105 +19,141 @@ public static function make($name, $label = '') * * @return $this */ - public function military() + public function military(): static { return $this->format('YYYY-MM-DD HH:mm'); } /** - * @param \DateTime $dateTime - * @param string $format * @return $this + * * @see https://editor.datatables.net/examples/dates/options-min-max.html */ - public function minDate(\DateTime $dateTime, $format = 'Y-m-d') + public function minDate(\DateTime $dateTime, string $format = 'Y-m-d'): static { - $this->attributes['opts']['minDate'] = "new Date('" . $dateTime->format($format) . "')"; - - return $this; + return $this->opts(['minDate' => "new Date('".$dateTime->format($format)."')"]); } /** - * @param \DateTime $dateTime - * @param string $format * @return $this + * * @see https://editor.datatables.net/examples/dates/options-min-max.html */ - public function maxDate(\DateTime $dateTime, $format = 'Y-m-d') + public function maxDate(\DateTime $dateTime, string $format = 'Y-m-d'): static { - $this->attributes['opts']['maxDate'] = "new Date('" . $dateTime->format($format) . "')"; - - return $this; + return $this->opts(['maxDate' => "new Date('".$dateTime->format($format)."')"]); } /** - * @param bool $state * @return $this + * * @see https://editor.datatables.net/examples/dates/options-week-numbers.html */ - public function showWeekNumber($state = true) + public function showWeekNumber(bool $state = true): static { - $this->attributes['opts']['showWeekNumber'] = $state; - - return $this; + return $this->opts(['showWeekNumber' => $state]); } /** - * @param array $days * @return $this + * * @see https://editor.datatables.net/examples/dates/options-disable-days.html */ - public function disableDays(array $days) + public function disableDays(array $days): static { - $this->attributes['opts']['disableDays'] = $days; + return $this->opts(['disableDays' => $days]); + } - return $this; + /** + * @return $this + * + * @see https://editor.datatables.net/examples/dates/time-increment.html + */ + public function minutesIncrement(int $minutes): static + { + return $this->opts(['minutesIncrement' => $minutes]); } /** - * @param int $minutes * @return $this + * * @see https://editor.datatables.net/examples/dates/time-increment.html */ - public function minutesIncrement($minutes) + public function secondsIncrement(int $seconds): static { - $this->attributes['opts']['minutesIncrement'] = $minutes; + return $this->opts(['secondsIncrement' => $seconds]); + } - return $this; + /** + * @return $this + * + * @see https://editor.datatables.net/examples/dates/datetime.html + */ + public function hoursAvailable(array $hours): static + { + return $this->opts(['hoursAvailable' => $hours]); } /** - * @param int $seconds * @return $this - * @see https://editor.datatables.net/examples/dates/time-increment.html + * + * @see https://editor.datatables.net/examples/dates/datetime.html + */ + public function minutesAvailable(array $minutes): static + { + return $this->opts(['minutesAvailable' => $minutes]); + } + + /** + * The format of the date string loaded from the server for the field's + * value and also for sending to the server on form submission. + * The formatting options are defined by Moment.js. + * + * @return $this + * + * @see https://editor.datatables.net/reference/field/datetime#Options + * @see https://momentjs.com/docs/#/displaying/format/ */ - public function secondsIncrement($seconds) + public function wireFormat(string $format = 'YYYY-MM-DDTHH:mm:ss.000000Z'): static { - $this->attributes['opts']['secondsIncrement'] = $seconds; + $this->attributes['wireFormat'] = $format; return $this; } /** - * @param array $hours + * Allow (default), or disallow, the end user to type into the date / time input element. + * If disallowed, they must use the calendar picker to enter data. This can be useful + * if you are using a more complex date format and wish to disallow the user from + * potentially making typing mistakes, although note that it does also disallow + * pasting of data. + * * @return $this - * @see https://editor.datatables.net/examples/dates/datetime.html + * + * @see https://editor.datatables.net/reference/field/datetime#Options */ - public function hoursAvailable(array $hours) + public function keyInput(bool $state = true): static { - $this->attributes['opts']['hoursAvailable'] = $hours; + $this->attributes['keyInput'] = $state; return $this; } /** - * @param array $minutes + * The format of the date string that will be shown to the end user in the input element. + * The formatting options are defined by Moment.js. If a format is used that is not + * ISO8061 (i.e. YYYY-MM-DD) and Moment.js has not been included, Editor will + * throw an error stating that Moment.js must be included for custom + * formatting to be used. + * * @return $this - * @see https://editor.datatables.net/examples/dates/datetime.html + * + * @see https://editor.datatables.net/reference/field/datetime#Options + * @see https://momentjs.com/docs/#/displaying/format/ */ - public function minutesAvailable(array $minutes) + public function displayFormat(string $format = 'YYYY-MM-DD hh:mm a'): static { - $this->attributes['opts']['minutesAvailable'] = $minutes; + $this->attributes['displayFormat'] = $format; return $this; } diff --git a/src/Html/Editor/Fields/Field.php b/src/Html/Editor/Fields/Field.php index 0dc37c0..f3c737a 100644 --- a/src/Html/Editor/Fields/Field.php +++ b/src/Html/Editor/Fields/Field.php @@ -2,9 +2,13 @@ namespace Yajra\DataTables\Html\Editor\Fields; -use Illuminate\Support\Str; -use Illuminate\Support\Fluent; +use Closure; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Query\Builder as QueryBuilder; +use Illuminate\Support\Str; +use Illuminate\Support\Traits\Macroable; +use Yajra\DataTables\Html\Fluent; use Yajra\DataTables\Html\HasAuthorizations; /** @@ -13,41 +17,36 @@ class Field extends Fluent { use HasAuthorizations; + use Macroable; /** * Field type. - * - * @var string */ - protected $type = 'text'; + protected string $type = 'text'; /** * Password constructor. * - * @param array $attributes + * @param array $attributes */ public function __construct($attributes = []) { - $attributes['type'] = $attributes['type'] ?? $this->type; + $attributes['type'] ??= $this->type; parent::__construct($attributes); } /** * Make a new instance of a field. - * - * @param string $name - * @param string $label - * @return static|\Yajra\DataTables\Html\Editor\Fields\Field */ - public static function make($name, $label = '') + public static function make(array|string $name, string $label = ''): static { if (is_array($name)) { return new static($name); } $data = [ - 'name' => $name, + 'name' => $name, 'label' => $label ?: Str::title(str_replace('_', ' ', $name)), ]; @@ -55,11 +54,11 @@ public static function make($name, $label = '') } /** - * @param string $label * @return $this + * * @see https://editor.datatables.net/reference/option/fields.label */ - public function label($label) + public function label(string $label): static { $this->attributes['label'] = $label; @@ -67,11 +66,11 @@ public function label($label) } /** - * @param string $name * @return $this + * * @see https://editor.datatables.net/reference/option/fields.name */ - public function name($name) + public function name(string $name): static { $this->attributes['name'] = $name; @@ -79,11 +78,11 @@ public function name($name) } /** - * @param string $data * @return $this + * * @see https://editor.datatables.net/reference/option/fields.data */ - public function data($data) + public function data(string $data): static { $this->attributes['data'] = $data; @@ -91,13 +90,14 @@ public function data($data) } /** - * @param string $type * @return $this + * * @see https://editor.datatables.net/reference/option/fields.type */ - public function type($type) + public function type(string $type): static { $this->attributes['type'] = $type; + $this->type = $type; return $this; } @@ -105,25 +105,40 @@ public function type($type) /** * Get options from a model. * - * @param mixed $model - * @param string $value - * @param string $key + * @param \Illuminate\Database\Eloquent\Builder|class-string<\Illuminate\Database\Eloquent\Model> $model * @return $this */ - public function modelOptions($model, $value, $key = 'id') + public function modelOptions(Builder|string $model, string $value, string $key = 'id'): static { return $this->options( Options::model($model, $value, $key) ); } + /** + * Get options from a Enum::cases(). + * + * @return $this + */ + public function enumOptions(array $cases): static + { + $options = []; + foreach ($cases as $case) { + $options[] = [ + 'value' => $case->value, + 'label' => $case->value, + ]; + } + + return $this->options($options); + } + /** * Set select options. * - * @param array|mixed $options * @return $this */ - public function options($options) + public function options(array|Arrayable $options): static { if ($options instanceof Arrayable) { $options = $options->toArray(); @@ -137,15 +152,15 @@ public function options($options) /** * Get options from a table. * - * @param mixed $table - * @param string $value - * @param string $key - * @param \Closure $whereCallback - * @param string|null $key * @return $this */ - public function tableOptions($table, $value, $key = 'id', \Closure $whereCallback = null, $connection = null) - { + public function tableOptions( + QueryBuilder|Closure|string $table, + string $value, + string $key = 'id', + ?Closure $whereCallback = null, + ?string $connection = null + ): static { return $this->options( Options::table($table, $value, $key, $whereCallback, $connection) ); @@ -154,10 +169,9 @@ public function tableOptions($table, $value, $key = 'id', \Closure $whereCallbac /** * Set checkbox separator. * - * @param string $separator * @return $this */ - public function separator($separator = ',') + public function separator(string $separator = ','): static { $this->attributes['separator'] = $separator; @@ -167,11 +181,11 @@ public function separator($separator = ',') /** * Set dateTime format. * - * @param string $format * @return $this + * * @see https://editor.datatables.net/reference/field/datetime */ - public function format($format) + public function format(string $format): static { $this->attributes['format'] = $format; @@ -181,11 +195,11 @@ public function format($format) /** * Set field default value. * - * @param mixed $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.def */ - public function default($value) + public function default(float|bool|int|string|array $value): static { $this->attributes['def'] = $value; @@ -195,11 +209,11 @@ public function default($value) /** * Set field message value. * - * @param string $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.message */ - public function message($value) + public function message(string $value): static { $this->attributes['message'] = $value; @@ -209,11 +223,11 @@ public function message($value) /** * Set field fieldInfo value. * - * @param string $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.fieldInfo */ - public function fieldInfo($value) + public function fieldInfo(string $value): static { $this->attributes['fieldInfo'] = $value; @@ -223,11 +237,11 @@ public function fieldInfo($value) /** * Set field labelInfo value. * - * @param string $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.labelInfo */ - public function labelInfo($value) + public function labelInfo(string $value): static { $this->attributes['labelInfo'] = $value; @@ -237,11 +251,11 @@ public function labelInfo($value) /** * Set field entityDecode value. * - * @param mixed|bool $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.entityDecode */ - public function entityDecode($value) + public function entityDecode(bool $value): static { $this->attributes['entityDecode'] = $value; @@ -251,11 +265,11 @@ public function entityDecode($value) /** * Set field multiEditable value. * - * @param mixed|bool $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.multiEditable */ - public function multiEditable($value) + public function multiEditable(bool $value): static { $this->attributes['multiEditable'] = $value; @@ -265,11 +279,11 @@ public function multiEditable($value) /** * Set field id value. * - * @param string $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.id */ - public function id($value) + public function id(string $value): static { $this->attributes['id'] = $value; @@ -279,11 +293,11 @@ public function id($value) /** * Set field submit value. * - * @param bool $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.submit */ - public function submit($value) + public function submit(bool $value): static { $this->attributes['submit'] = $value; @@ -293,11 +307,11 @@ public function submit($value) /** * Set field compare value. * - * @param bool $value * @return $this + * * @see https://editor.datatables.net/reference/option/fields.compare */ - public function compare($value) + public function compare(bool $value): static { $this->attributes['compare'] = $value; @@ -307,26 +321,69 @@ public function compare($value) /** * Set field opts value. * - * @param bool $value * @return $this + * + * @see https://datatables.net/forums/discussion/comment/156581/#Comment_156581 + */ + public function opts(array $value): static + { + if (! isset($this->attributes['opts'])) { + $this->attributes['opts'] = $value; + } else { + $this->attributes['opts'] = array_merge((array) $this->attributes['opts'], $value); + } + + return $this; + } + + /** + * Set field element html attributes. + * + * @return $this + * + * @see https://datatables.net/forums/discussion/comment/156581/#Comment_156581 */ - public function opts(array $value) + public function attr(string $attribute, int|bool|string $value): static { - $this->attributes['opts'] = $value; + if (! isset($this->attributes['attr'])) { + $this->attributes['attr'] = []; + } + + $attributes = (array) $this->attributes['attr']; + $attributes[$attribute] = $value; + + $this->attributes['attr'] = $attributes; return $this; } + public function getType(): string + { + return $this->type; + } + /** - * Set field attr option. + * Replace null values with the field's default on edit. * - * @param string $attribute - * @param mixed $value * @return $this + * + * @see https://editor.datatables.net/reference/option/fields.nullDefault + */ + public function nullDefault(bool $value = true): static + { + $this->attributes['nullDefault'] = $value; + + return $this; + } + + /** + * @return $this + * + * @see https://editor.datatables.net/reference/option/fields.className */ - public function attr($attribute, $value) + public function className(string $className): static { - $this->attributes['attr'][$attribute] = $value; + $this->attributes['className'] = $className; return $this; } diff --git a/src/Html/Editor/Fields/File.php b/src/Html/Editor/Fields/File.php index 265d9fe..a10a8c6 100644 --- a/src/Html/Editor/Fields/File.php +++ b/src/Html/Editor/Fields/File.php @@ -9,33 +9,24 @@ */ class File extends Field { - protected $type = 'upload'; + protected string $type = 'upload'; /** - * Editor instance. - * - * @var string + * Editor instance variable name. */ - protected $editor = 'editor'; + protected string $editor = 'editor'; - /** - * @param string $name - * @param string $label - * @return static|\Yajra\DataTables\Html\Editor\Fields\Field - */ - public static function make($name, $label = '') + public static function make(array|string $name, string $label = ''): static { - /** @var \Yajra\DataTables\Html\Editor\Fields\File $field */ $field = parent::make($name, $label); return $field->displayFile()->clearText()->noImageText(); } /** - * @param string $value * @return $this */ - public function ajax($value) + public function ajax(string $value): static { $this->attributes['ajax'] = $value; @@ -43,10 +34,9 @@ public function ajax($value) } /** - * @param string $value * @return $this */ - public function ajaxData($value) + public function ajaxData(string $value): static { $this->attributes['ajaxData'] = $value; @@ -54,10 +44,9 @@ public function ajaxData($value) } /** - * @param bool $value * @return $this */ - public function dragDrop($value = true) + public function dragDrop(bool $value = true): static { $this->attributes['dragDrop'] = $value; @@ -65,10 +54,9 @@ public function dragDrop($value = true) } /** - * @param string $value * @return $this */ - public function dragDropText($value) + public function dragDropText(string $value): static { $this->attributes['dragDropText'] = $value; @@ -76,10 +64,9 @@ public function dragDropText($value) } /** - * @param string $value * @return $this */ - public function fileReadText($value) + public function fileReadText(string $value): static { $this->attributes['fileReadText'] = $value; @@ -87,10 +74,9 @@ public function fileReadText($value) } /** - * @param string $value * @return $this */ - public function noFileText($value) + public function noFileText(string $value): static { $this->attributes['noFileText'] = $value; @@ -98,10 +84,9 @@ public function noFileText($value) } /** - * @param string $value * @return $this */ - public function processingText($value) + public function processingText(string $value): static { $this->attributes['processingText'] = $value; @@ -109,10 +94,9 @@ public function processingText($value) } /** - * @param string $value * @return $this */ - public function uploadText($value) + public function uploadText(string $value): static { $this->attributes['uploadText'] = $value; @@ -122,10 +106,9 @@ public function uploadText($value) /** * Set editor instance for file upload. * - * @param string $editor * @return $this */ - public function editor($editor) + public function editor(string $editor): static { $this->editor = $editor; @@ -137,16 +120,21 @@ public function editor($editor) * * @return $this */ - public function displayImage() + public function displayImage(): static { - return $this->display("function (file_id) { return file_id ? '' : null; }"); + // TODO: Use Laravel filesystem instead of hard coded storage path + return $this->display(<<<'SCRIPT' + function (file_id) { + return file_id ? '' : null; + } +SCRIPT + ); } /** - * @param string $value * @return $this */ - public function display($value) + public function display(string $value): static { $this->attributes['display'] = $value; @@ -158,16 +146,15 @@ public function display($value) * * @return $this */ - public function displayFile() + public function displayFile(): static { - return $this->display("function (file_id) { return file_id; }"); + return $this->display('function (file_id) { return file_id; }'); } /** - * @param string $value * @return $this */ - public function clearText($value = 'Clear') + public function clearText(string $value = 'Clear'): static { $this->attributes['clearText'] = $value; @@ -175,10 +162,9 @@ public function clearText($value = 'Clear') } /** - * @param string $value * @return $this */ - public function noImageText($value = 'No image') + public function noImageText(string $value = 'No image'): static { $this->attributes['noImageText'] = $value; @@ -186,10 +172,9 @@ public function noImageText($value = 'No image') } /** - * @param bool $state * @return $this */ - public function multiple($state = true) + public function multiple(bool $state = true): static { if ($state) { $this->type('uploadMany'); diff --git a/src/Html/Editor/Fields/Hidden.php b/src/Html/Editor/Fields/Hidden.php index de9288d..b7e27af 100644 --- a/src/Html/Editor/Fields/Hidden.php +++ b/src/Html/Editor/Fields/Hidden.php @@ -4,5 +4,5 @@ class Hidden extends Field { - protected $type = 'hidden'; + protected string $type = 'hidden'; } diff --git a/src/Html/Editor/Fields/Image.php b/src/Html/Editor/Fields/Image.php index 608b2d8..5f3eb8e 100644 --- a/src/Html/Editor/Fields/Image.php +++ b/src/Html/Editor/Fields/Image.php @@ -9,14 +9,9 @@ */ class Image extends File { - protected $type = 'upload'; + protected string $type = 'upload'; - /** - * @param string $name - * @param string $label - * @return \Yajra\DataTables\Html\Editor\Fields\File - */ - public static function make($name, $label = '') + public static function make(array|string $name, string $label = ''): static { return parent::make($name, $label)->displayImage(); } diff --git a/src/Html/Editor/Fields/Number.php b/src/Html/Editor/Fields/Number.php index 560a90d..9dde165 100644 --- a/src/Html/Editor/Fields/Number.php +++ b/src/Html/Editor/Fields/Number.php @@ -4,7 +4,7 @@ class Number extends Field { - public static function make($name, $label = '') + public static function make(array|string $name, string $label = ''): static { return parent::make($name, $label)->attr('type', 'number'); } diff --git a/src/Html/Editor/Fields/Options.php b/src/Html/Editor/Fields/Options.php index 97eafde..dfd1509 100644 --- a/src/Html/Editor/Fields/Options.php +++ b/src/Html/Editor/Fields/Options.php @@ -2,18 +2,23 @@ namespace Yajra\DataTables\Html\Editor\Fields; -use Illuminate\Database\Eloquent\Builder; +use Closure; +use Illuminate\Contracts\Database\Eloquent\Builder as EloquentBuilder; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; +/** + * @template TKey of array-key + * @template TValue + */ class Options extends Collection { /** * Return a Yes/No options. - * - * @return Options */ - public static function yesNo() + public static function yesNo(): static { $data = [ ['label' => __('Yes'), 'value' => 1], @@ -26,54 +31,45 @@ public static function yesNo() /** * Get options from a model. * - * @param mixed $model - * @param string $value - * @param string $key - * @return Collection + * @param class-string|\Illuminate\Database\Eloquent\Builder $model */ - public static function model($model, $value, $key = 'id') + public static function model(string|EloquentBuilder $model, string $value, string $key = 'id'): Collection { - if (! $model instanceof Builder) { + if (! $model instanceof EloquentBuilder) { $model = $model::query(); } - return $model->get()->map(function ($model) use ($value, $key) { - return [ - 'value' => $model->{$key}, - 'label' => $model->{$value}, - ]; - }); + return $model->get()->map(fn ($model) => [ + 'value' => $model->{$key}, + 'label' => $model->{$value}, + ]); } /** * Get options from a table. - * - * @param mixed $table - * @param string $value - * @param string $key - * @param \Closure $whereCallback - * @param string|null $key - * @return Collection */ - public static function table($table, $value, $key = 'id', \Closure $whereCallback = null, $connection = null) - { + public static function table( + Closure|Builder|string $table, + string $value, + string $key = 'id', + ?Closure $callback = null, + ?string $connection = null + ): Collection { $query = DB::connection($connection) - ->table($table) - ->select("{$value} as label", "{$key} as value"); + ->table($table) + ->select("$value as label", "$key as value"); - if ($whereCallback) { - $query->where($whereCallback); + if (is_callable($callback)) { + $callback($query); } - return $query->get(); + return $query->get()->map(fn ($row) => (array) $row); } /** * Return a True/False options. - * - * @return Options */ - public static function trueFalse() + public static function trueFalse(): static { $data = [ ['label' => __('True'), 'value' => 1], @@ -85,12 +81,8 @@ public static function trueFalse() /** * Push an item onto the end of the collection. - * - * @param mixed $value - * @param mixed $key - * @return Options */ - public function append($value, $key) + public function append(string $value, int|string $key): static { return $this->push(['label' => $value, 'value' => $key]); } @@ -98,11 +90,10 @@ public function append($value, $key) /** * Push an item onto the beginning of the collection. * - * @param mixed $value - * @param mixed $key - * @return \Illuminate\Support\Collection + * @param TValue $value + * @param TKey $key */ - public function prepend($value, $key = null) + public function prepend($value, $key = null): static { $data = ['label' => $value, 'value' => $key]; diff --git a/src/Html/Editor/Fields/Password.php b/src/Html/Editor/Fields/Password.php index 6e5a3a6..fa201ed 100644 --- a/src/Html/Editor/Fields/Password.php +++ b/src/Html/Editor/Fields/Password.php @@ -4,5 +4,5 @@ class Password extends Field { - protected $type = 'password'; + protected string $type = 'password'; } diff --git a/src/Html/Editor/Fields/Radio.php b/src/Html/Editor/Fields/Radio.php index b49a706..9f3dc43 100644 --- a/src/Html/Editor/Fields/Radio.php +++ b/src/Html/Editor/Fields/Radio.php @@ -4,5 +4,5 @@ class Radio extends Field { - protected $type = 'radio'; + protected string $type = 'radio'; } diff --git a/src/Html/Editor/Fields/ReadOnly.php b/src/Html/Editor/Fields/ReadOnly.php deleted file mode 100644 index d1b6f6e..0000000 --- a/src/Html/Editor/Fields/ReadOnly.php +++ /dev/null @@ -1,8 +0,0 @@ -attributes['multiple'] = $value; @@ -25,17 +24,17 @@ public function multiple(bool $value = true) /** * Set field optionsPair value. * - * @param string|array $label - * @param string $value * @return $this */ - public function optionsPair($label = 'label', $value = 'value') + public function optionsPair(array|string $label = 'label', string $value = 'value'): static { if (is_array($label)) { $this->attributes['optionsPair'] = $label; } else { - $this->attributes['optionsPair']['label'] = $label; - $this->attributes['optionsPair']['value'] = $value; + $this->attributes['optionsPair'] = [ + 'label' => $label, + 'value' => $value, + ]; } return $this; @@ -44,10 +43,9 @@ public function optionsPair($label = 'label', $value = 'value') /** * Set field placeholder value. * - * @param string $value * @return $this */ - public function placeholder($value) + public function placeholder(string $value): static { $this->attributes['placeholder'] = $value; @@ -57,10 +55,9 @@ public function placeholder($value) /** * Set field placeholderDisabled value. * - * @param bool $value * @return $this */ - public function placeholderDisabled(bool $value) + public function placeholderDisabled(bool $value): static { $this->attributes['placeholderDisabled'] = $value; @@ -70,10 +67,9 @@ public function placeholderDisabled(bool $value) /** * Set field placeholderValue value. * - * @param string $value * @return $this */ - public function placeholderValue($value) + public function placeholderValue(string $value): static { $this->attributes['placeholderValue'] = $value; diff --git a/src/Html/Editor/Fields/Select2.php b/src/Html/Editor/Fields/Select2.php index 4d28b12..e16f045 100644 --- a/src/Html/Editor/Fields/Select2.php +++ b/src/Html/Editor/Fields/Select2.php @@ -7,114 +7,110 @@ */ class Select2 extends Select { - protected $type = 'select2'; + protected string $type = 'select2'; /** - * @param bool $state * @return $this */ - public function allowClear($state = true) + public function allowClear(bool $state = true): static { - $this->attributes['opts']['allowClear'] = $state; + return $this->opts(['allowClear' => $state]); + } - return $this; + /** + * @return $this + */ + public function placeholder(string $value): static + { + return $this->optsPlaceholder($value); } /** - * @param string $text - * @param string|null $id * @return $this */ - public function placeholder($text = '', $id = null) + public function optsPlaceholder(string $text = '', string $id = ''): static { - $this->attributes['opts']['placeholder'] = [ - 'id' => $id, - 'text' => $text, - ]; + return $this->opts([ + 'placeholder' => [ + 'id' => $id, + 'text' => $text, + ], + ]); + } - return $this; + public function multiple(bool $value = true): static + { + return $this->opts(['multiple' => $value]); } /** * Set select2 ajax option. * - * @param mixed $value * @return $this */ - public function ajax($value) + public function ajax(array|string $value): static { + $ajax = $this->opts['ajax'] ?? []; + if (is_array($value)) { - $this->attributes['opts']['ajax'] = $value; - } else { - $this->attributes['opts']['ajax']['url'] = $value; + return $this->opts(['ajax' => array_merge($ajax, $value)]); } - return $this; + return $this->opts(['ajax' => array_merge($ajax, ['url' => $value])]); } /** * Set select2 ajax url option. * - * @param mixed $value * @return $this */ - public function ajaxUrl($value) + public function ajaxUrl(string $value): static { - $this->attributes['opts']['ajax']['url'] = $value; - - return $this; + return $this->ajax(['url' => $value]); } /** * Set select2 ajaxDelay option. * - * @param mixed $value * @return $this */ - public function ajaxDelay($value = 250) + public function ajaxDelay(int $value = 250): static { - $this->attributes['opts']['ajax']['delay'] = $value; - - return $this; + return $this->ajax(['delay' => $value]); } /** * Set select2 ajax data option. * - * @param mixed $data * @return $this */ - public function ajaxData($data) + public function ajaxData(array|string $data): static { if (is_array($data)) { $script = 'function(params) {'; foreach ($data as $key => $value) { - $value = json_encode($value); - $script .= " params.{$key} = {$value}; "; + $value = json_encode($value, JSON_THROW_ON_ERROR); + $script .= " params.$key = $value; "; } $script .= 'return params; }'; $data = $script; } - $this->attributes['opts']['ajax']['data'] = $data; - - return $this; + return $this->ajax(['data' => $data]); } /** * Set select2 ajax processResults option to process a paginated results. * - * @param string $display - * @param string $id * @return $this */ - public function processPaginatedResults($display = 'text', $id = 'id') + public function processPaginatedResults(string $display = 'text', string $id = 'id', string $wrap = 'results'): static { $script = 'function(data, params) { '; $script .= 'params.page = params.page || 1; '; - $script .= "data.data.map(function(e) { e.text = e.{$display}; e.id = e.{$id}; return e; }); "; - $script .= 'return { results: data.data, pagination: { more: data.current_page < data.last_page } };'; + $script .= "data.$wrap.map(function(e) { e.text = e.$display; e.id = e.$id; return e; }); "; + $script .= "return { results: data.$wrap, pagination: { more: data.meta.current_page < data.meta.last_page } };"; $script .= '}'; return $this->processResults($script); @@ -123,13 +119,10 @@ public function processPaginatedResults($display = 'text', $id = 'id') /** * Set select2 ajax processResults option. * - * @param string $value * @return $this */ - public function processResults($value) + public function processResults(string $value): static { - $this->attributes['opts']['ajax']['processResults'] = $value; - - return $this; + return $this->ajax(['processResults' => $value]); } } diff --git a/src/Html/Editor/Fields/Tags.php b/src/Html/Editor/Fields/Tags.php new file mode 100644 index 0000000..2b910be --- /dev/null +++ b/src/Html/Editor/Fields/Tags.php @@ -0,0 +1,143 @@ +attributes['ajax'] = $url; + + return $this; + } + + /** + * @see https://editor.datatables.net/reference/field/tags#display + */ + public function display(string $display): static + { + $this->attributes['display'] = $display; + + return $this; + } + + /** + * @see https://editor.datatables.net/reference/field/tags#escapeLabelHtml + */ + public function escapeLabelHtml(bool $escape): static + { + $this->attributes['escapeLabelHtml'] = $escape; + + return $this; + } + + /** + * @see https://editor.datatables.net/reference/field/tags#i18n + */ + public function i18n(array $i18n): static + { + $options = isset($this->attributes['i18n']) + ? (array) $this->attributes['i18n'] + : []; + + $this->attributes['i18n'] = array_merge($options, $i18n); + + return $this; + } + + /** + * @see https://editor.datatables.net/reference/field/tags#i18n + */ + public function addButton(string $text): static + { + return $this->i18n(['addButton' => $text]); + } + + /** + * @see https://editor.datatables.net/reference/field/tags#i18n + */ + public function inputPlaceholder(string $text): static + { + return $this->i18n(['inputPlaceholder' => $text]); + } + + /** + * @see https://editor.datatables.net/reference/field/tags#i18n + */ + public function noResults(string $text): static + { + return $this->i18n(['noResults' => $text]); + } + + /** + * @see https://editor.datatables.net/reference/field/tags#i18n + */ + public function title(string $text): static + { + return $this->i18n(['title' => $text]); + } + + /** + * @see https://editor.datatables.net/reference/field/tags#i18n + */ + public function placeholder(string $text): static + { + return $this->i18n(['placeholder' => $text]); + } + + /** + * @see https://editor.datatables.net/reference/field/tags#limit + */ + public function limit(int $limit): static + { + $this->attributes['limit'] = $limit; + + return $this; + } + + /** + * @see https://editor.datatables.net/reference/field/tags#multiple + */ + public function multiple(bool $multiple = true): static + { + $this->attributes['multiple'] = $multiple; + + return $this; + } + + /** + * @see https://editor.datatables.net/reference/field/tags#options + */ + public function options(array|Arrayable $options): static + { + return parent::options($options); + } + + /** + * @see https://editor.datatables.net/reference/field/tags#separator + */ + public function separator(string $separator = ','): static + { + return parent::separator($separator); + } + + /** + * @see https://editor.datatables.net/reference/field/tags#unique + */ + public function unique(bool $unique = true): static + { + $this->attributes['unique'] = $unique; + + return $this; + } +} diff --git a/src/Html/Editor/Fields/Text.php b/src/Html/Editor/Fields/Text.php index 2e5c502..7e89242 100644 --- a/src/Html/Editor/Fields/Text.php +++ b/src/Html/Editor/Fields/Text.php @@ -2,6 +2,4 @@ namespace Yajra\DataTables\Html\Editor\Fields; -class Text extends Field -{ -} +class Text extends Field {} diff --git a/src/Html/Editor/Fields/TextArea.php b/src/Html/Editor/Fields/TextArea.php index 15dcdc9..666bc1e 100644 --- a/src/Html/Editor/Fields/TextArea.php +++ b/src/Html/Editor/Fields/TextArea.php @@ -4,22 +4,14 @@ class TextArea extends Field { - protected $type = 'textarea'; + protected string $type = 'textarea'; - /** - * @param int $value - * @return static - */ - public function rows($value) + public function rows(int $value): static { return $this->attr('rows', $value); } - /** - * @param int $value - * @return static - */ - public function cols($value) + public function cols(int $value): static { return $this->attr('cols', $value); } diff --git a/src/Html/Editor/Fields/Time.php b/src/Html/Editor/Fields/Time.php index f457463..1923b46 100644 --- a/src/Html/Editor/Fields/Time.php +++ b/src/Html/Editor/Fields/Time.php @@ -6,14 +6,9 @@ class Time extends DateTime { /** * Make a new instance of a field. - * - * @param string $name - * @param string $label - * @return static|\Yajra\DataTables\Html\Editor\Fields\File */ - public static function make($name, $label = '') + public static function make(array|string $name, string $label = ''): static { - /** @var \Yajra\DataTables\Html\Editor\Fields\Time $field */ $field = parent::make($name, $label); return $field->format('hh:mm a'); @@ -24,7 +19,7 @@ public static function make($name, $label = '') * * @return $this */ - public function military() + public function military(): static { return $this->format('HH:mm'); } diff --git a/src/Html/Editor/FormOptions.php b/src/Html/Editor/FormOptions.php index 475faef..03c149c 100644 --- a/src/Html/Editor/FormOptions.php +++ b/src/Html/Editor/FormOptions.php @@ -2,27 +2,24 @@ namespace Yajra\DataTables\Html\Editor; -use Illuminate\Support\Fluent; +use Yajra\DataTables\Html\Fluent; /** * @see https://editor.datatables.net/reference/type/form-options */ class FormOptions extends Fluent { - /** - * @param array $attributes - * @return \Yajra\DataTables\Html\Editor\FormOptions - */ - public static function make($attributes = []) + public static function make(array $attributes = []): static { return new static($attributes); } /** - * @param int $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#focus */ - public function focus($value = 0) + public function focus(int|string|null $value = null): static { $this->attributes['focus'] = $value; @@ -30,21 +27,23 @@ public function focus($value = 0) } /** - * @param bool $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#nest */ - public function message($value = false) + public function nest(bool $value): static { - $this->attributes['message'] = $value; + $this->attributes['nest'] = $value; return $this; } /** - * @param string $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#onBackground */ - public function onBackground($value = 'blur') + public function onBackground(string $value = 'blur'): static { $this->attributes['onBackground'] = $value; @@ -52,10 +51,11 @@ public function onBackground($value = 'blur') } /** - * @param string $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#onBlur */ - public function onBlur($value = 'close') + public function onBlur(string $value = 'close'): static { $this->attributes['onBlur'] = $value; @@ -63,10 +63,11 @@ public function onBlur($value = 'close') } /** - * @param string $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#onComplete */ - public function onComplete($value = 'close') + public function onComplete(string $value = 'close'): static { $this->attributes['onComplete'] = $value; @@ -74,10 +75,11 @@ public function onComplete($value = 'close') } /** - * @param string $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#onEsc */ - public function onEsc($value = 'close') + public function onEsc(string $value = 'close'): static { $this->attributes['onEsc'] = $value; @@ -85,10 +87,11 @@ public function onEsc($value = 'close') } /** - * @param string $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#onFieldError */ - public function onFieldError($value = 'focus') + public function onFieldError(string $value = 'focus'): static { $this->attributes['onFieldError'] = $value; @@ -96,10 +99,11 @@ public function onFieldError($value = 'focus') } /** - * @param string $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#onReturn */ - public function onReturn($value = 'submit') + public function onReturn(string $value = 'submit'): static { $this->attributes['onReturn'] = $value; @@ -107,10 +111,11 @@ public function onReturn($value = 'submit') } /** - * @param string $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#submit */ - public function submit($value = 'changed') + public function submit(string $value = 'changed'): static { $this->attributes['submit'] = $value; @@ -118,21 +123,35 @@ public function submit($value = 'changed') } /** - * @param bool $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#scope */ - public function title($value = false) + public function formScope(string $value = 'row'): static { - $this->attributes['title'] = $value; + $this->attributes['scope'] = $value; + + return $this; + } + + /** + * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#buttons + */ + public function buttons(array|string $value): static + { + $this->attributes['buttons'] = $value; return $this; } /** - * @param bool $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#drawType */ - public function drawType($value = false) + public function drawType(string $value = ''): static { $this->attributes['drawType'] = $value; @@ -140,12 +159,49 @@ public function drawType($value = false) } /** - * @param string $value * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#message */ - public function scope($value = 'row') + public function message(bool|string $value = ''): static { - $this->attributes['scope'] = $value; + $this->attributes['message'] = $value; + + return $this; + } + + /** + * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#submitTrigger + */ + public function submitTrigger(int|string $value): static + { + $this->attributes['submitTrigger'] = $value; + + return $this; + } + + /** + * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#submitHtml + */ + public function submitHtml(string $value): static + { + $this->attributes['submitHtml'] = $value; + + return $this; + } + + /** + * @return $this + * + * @see https://editor.datatables.net/reference/type/form-options#title + */ + public function title(bool|string $value): static + { + $this->attributes['title'] = $value; return $this; } diff --git a/src/Html/Editor/HasEvents.php b/src/Html/Editor/HasEvents.php index 67581db..ee57589 100644 --- a/src/Html/Editor/HasEvents.php +++ b/src/Html/Editor/HasEvents.php @@ -5,72 +5,75 @@ use Illuminate\Support\Str; /** - * @method Editor onClose($script) - * @method Editor onCreate($script) - * @method Editor onDisplayOrder($script) - * @method Editor onEdit($script) - * @method Editor onInitCreate($script) - * @method Editor onInitEdit($script) - * @method Editor onInitRemove($script) - * @method Editor onInitSubmit($script) - * @method Editor onOpen($script) - * @method Editor onPostCreate($script) - * @method Editor onPostEdit($script) - * @method Editor onPostRemove($script) - * @method Editor onPostSubmit($script) - * @method Editor onPostUpload($script) - * @method Editor onPreBlur($script) - * @method Editor onPreBlurCancelled($script) - * @method Editor onPreCreate($script) - * @method Editor onPreEdit($script) - * @method Editor onPreOpen($script) - * @method Editor onPreOpenCancelled($script) - * @method Editor onPreRemove($script) - * @method Editor onPreSubmit($script) - * @method Editor onPreSubmitCancelled($script) - * @method Editor onPreUpload($script) - * @method Editor onPreUploadCancelled($script) - * @method Editor onProcessing($script) - * @method Editor onRemove($script) - * @method Editor onSetData($script) - * @method Editor onSubmitComplete($script) - * @method Editor onSubmitError($script) - * @method Editor onSubmitSuccess($script) - * @method Editor onSubmitUnsuccessful($script) - * @method Editor onUploadXhrError($script) - * @method Editor onUploadXhrSuccess($script) + * @method $this onClose($script) + * @method $this onClosed($script) + * @method $this onCreate($script) + * @method $this onDisplayOrder($script) + * @method $this onEdit($script) + * @method $this onInitCreate($script) + * @method $this onInitEdit($script) + * @method $this onInitEditor($script) + * @method $this onInitRemove($script) + * @method $this onInitSubmit($script) + * @method $this onOpen($script) + * @method $this onOpened($script) + * @method $this onPostCreate($script) + * @method $this onPostEdit($script) + * @method $this onPostRemove($script) + * @method $this onPostSubmit($script) + * @method $this onPostUpload($script) + * @method $this onPreBlur($script) + * @method $this onPreBlurCancelled($script) + * @method $this onPreClose($script) + * @method $this onPreCreate($script) + * @method $this onPreEdit($script) + * @method $this onPreOpen($script) + * @method $this onPreOpenCancelled($script) + * @method $this onPreRemove($script) + * @method $this onPreSubmit($script) + * @method $this onPreSubmitCancelled($script) + * @method $this onPreUpload($script) + * @method $this onPreUploadCancelled($script) + * @method $this onProcessing($script) + * @method $this onRemove($script) + * @method $this onSetData($script) + * @method $this onSubmitComplete($script) + * @method $this onSubmitError($script) + * @method $this onSubmitSuccess($script) + * @method $this onSubmitUnsuccessful($script) + * @method $this onUploadXhrError($script) + * @method $this onUploadXhrSuccess($script) */ trait HasEvents { /** * Magic method handler for editor events. * - * @param string $name - * @param mixed $arguments + * @param string $method + * @param array{0: string} $parameters * @return $this */ - public function __call($name, $arguments) + public function __call($method, $parameters) { - if (Str::startsWith($name, 'on')) { - $event = Str::camel(substr($name, 2, strlen($name) - 2)); + if (Str::startsWith($method, 'on')) { + $event = Str::camel(substr($method, 2, strlen($method) - 2)); - return $this->on($event, $arguments[0]); + return $this->on($event, $parameters[0]); } - return parent::__call($name, $arguments); + return parent::__call($method, $parameters); } /** * Add Editor event listener scripts. * - * @param string $event - * @param string $script * @return $this + * * @see https://editor.datatables.net/reference/event */ - public function on($event, $script) + public function on(string $event, mixed $script): static { - $this->attributes['events'][] = [ + $this->events[] = [ 'event' => $event, 'script' => value($script), ]; diff --git a/src/Html/Enums/LayoutPosition.php b/src/Html/Enums/LayoutPosition.php new file mode 100644 index 0000000..9865d04 --- /dev/null +++ b/src/Html/Enums/LayoutPosition.php @@ -0,0 +1,28 @@ + 0) { + $parts = Str::of($this->value)->ucsplit(); + + return $parts->shift().$order.$parts->first(); + } + + return $this->value; + } +} diff --git a/src/Html/Fluent.php b/src/Html/Fluent.php new file mode 100644 index 0000000..2ff5837 --- /dev/null +++ b/src/Html/Fluent.php @@ -0,0 +1,235 @@ + + * @implements \ArrayAccess + */ +class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable +{ + /** + * All of the attributes set on the fluent instance. + * + * @var array + */ + protected $attributes = []; + + /** + * Create a new fluent instance. + * + * @param iterable $attributes + * @return void + */ + public function __construct($attributes = []) + { + foreach ($attributes as $key => $value) { + $this->attributes[$key] = $value; + } + } + + /** + * Get an attribute from the fluent instance using "dot" notation. + * + * @template TGetDefault + * + * @param TKey $key + * @param TGetDefault|(\Closure(): TGetDefault) $default + * @return TValue|TGetDefault + */ + public function get($key, $default = null) + { + return data_get($this->attributes, $key, $default); + } + + /** + * Get an attribute from the fluent instance. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public function value($key, $default = null) + { + if (array_key_exists($key, $this->attributes)) { + return $this->attributes[$key]; + } + + return value($default); + } + + /** + * Get the value of the given key as a new Fluent instance. + * + * @param string $key + * @param mixed $default + * @return static + */ + public function scope($key, $default = null) + { + return new static( + (array) $this->get($key, $default) + ); + } + + /** + * Get the attributes from the fluent instance. + * + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * Convert the fluent instance to an array. + * + * @return array + */ + public function toArray() + { + return $this->attributes; + } + + /** + * Convert the fluent instance to a Collection. + * + * @param string|null $key + * @return \Illuminate\Support\Collection + */ + public function collect($key = null) + { + return new Collection($this->get($key)); + } + + /** + * Convert the object into something JSON serializable. + * + * @return array + */ + public function jsonSerialize(): array + { + return $this->toArray(); + } + + /** + * Convert the fluent instance to JSON. + * + * @param int $options + * @return string + */ + public function toJson($options = 0) + { + return json_encode($this->jsonSerialize(), $options); + } + + /** + * Determine if the given offset exists. + * + * @param TKey $offset + */ + public function offsetExists($offset): bool + { + return isset($this->attributes[$offset]); + } + + /** + * Get the value for a given offset. + * + * @param TKey $offset + * @return TValue|null + */ + public function offsetGet($offset): mixed + { + return $this->value($offset); + } + + /** + * Set the value at the given offset. + * + * @param TKey $offset + * @param TValue $value + */ + public function offsetSet($offset, $value): void + { + $this->attributes[$offset] = $value; + } + + /** + * Unset the value at the given offset. + * + * @param TKey $offset + */ + public function offsetUnset($offset): void + { + unset($this->attributes[$offset]); + } + + /** + * Handle dynamic calls to the fluent instance to set attributes. + * + * @param TKey $method + * @param array{0: ?TValue} $parameters + * @return $this + */ + public function __call($method, $parameters) + { + $this->attributes[$method] = count($parameters) > 0 ? reset($parameters) : true; + + return $this; + } + + /** + * Dynamically retrieve the value of an attribute. + * + * @param TKey $key + * @return TValue|null + */ + public function __get($key) + { + return $this->value($key); + } + + /** + * Dynamically set the value of an attribute. + * + * @param TKey $key + * @param TValue $value + * @return void + */ + public function __set($key, $value) + { + $this->offsetSet($key, $value); + } + + /** + * Dynamically check if an attribute is set. + * + * @param TKey $key + * @return bool + */ + public function __isset($key) + { + return $this->offsetExists($key); + } + + /** + * Dynamically unset an attribute. + * + * @param TKey $key + * @return void + */ + public function __unset($key) + { + $this->offsetUnset($key); + } +} diff --git a/src/Html/HasAuthorizations.php b/src/Html/HasAuthorizations.php index b93f445..17af1db 100644 --- a/src/Html/HasAuthorizations.php +++ b/src/Html/HasAuthorizations.php @@ -8,42 +8,45 @@ trait HasAuthorizations { /** * Flag to check if user is authorized to use the button. - * - * @var bool */ - protected $authorized = true; + protected bool $authorized = true; /** * Make a button if condition is true. - * - * @param bool|callable $condition - * @param string|array $options - * @return static */ - public static function makeIf($condition, $options = []) + public static function makeIf(callable|bool $condition, array|string $options = []): static { - if (value($condition)) { + if (is_callable($condition)) { + $condition = value($condition); + } + + if ($condition === true) { return static::make($options); } - return static::make([])->authorized(false); + return app(static::class)->authorized(false); + } + + /** + * Set authorization status of the button. + */ + public function authorized(callable|bool $bool): static + { + $this->authorized = (bool) value($bool); + + return $this; } /** * Make a button if the user is authorized. - * - * @param string $permission - * @param string|array $options - * @param Authorizable|null $user - * @return static */ - public static function makeIfCan($permission, $options = [], Authorizable $user = null) + public static function makeIfCan(string $permission, array|string $options = [], ?Authorizable $user = null): static { if (is_null($user)) { $user = auth()->user(); } - if ($user->can($permission)) { + if ($user instanceof Authorizable && $user->can($permission)) { return static::make($options); } @@ -52,49 +55,40 @@ public static function makeIfCan($permission, $options = [], Authorizable $user /** * Make a button if the user is not authorized. - * - * @param string $permission - * @param string|array $options - * @param Authorizable|null $user - * @return static */ - public static function makeIfCannot($permission, $options = [], Authorizable $user = null) - { + public static function makeIfCannot( + string $permission, + array|string $options = [], + ?Authorizable $user = null + ): static { if (is_null($user)) { $user = auth()->user(); } - if (! $user->can($permission)) { + if ($user instanceof Authorizable && ! $user->can($permission)) { return static::make($options); } - return static::make([])->authorized(false); + return app(static::class)->authorized(false); } /** - * Set authorization status of the button. - * - * @param bool|callable $bool - * @return static + * Convert the Fluent instance to an array. */ - public function authorized($bool) + public function toArray(): array { - $this->authorized = value($bool); + if (! $this->isAuthorized()) { + return []; + } - return $this; + return parent::toArray(); } /** - * Convert the Fluent instance to an array. - * - * @return array + * Check if instance is authorized */ - public function toArray() + public function isAuthorized(): bool { - if ($this->authorized) { - return parent::toArray(); - } - - return []; + return $this->authorized; } } diff --git a/src/Html/HasEditor.php b/src/Html/HasEditor.php index 4b76cfe..5726a15 100644 --- a/src/Html/HasEditor.php +++ b/src/Html/HasEditor.php @@ -8,27 +8,31 @@ trait HasEditor { /** * Collection of Editors. - * - * @var null|Editor */ - protected $editors = []; + protected array $editors = []; /** * Attach multiple editors to builder. * - * @param array|mixed ...$editors + * @param array|mixed ...$editors * @return $this + * * @see https://editor.datatables.net/ - * @throws \Exception */ - public function editors(...$editors) + public function editors(...$editors): static { if (is_array($editors[0])) { $editors = $editors[0]; } + $this->editors = []; + foreach ($editors as $editor) { - $this->editor($editor); + if ($editor instanceof Editor) { + $this->editor($editor); + } else { + $this->editor(new Editor($editor)); + } } return $this; @@ -37,51 +41,31 @@ public function editors(...$editors) /** * Integrate with DataTables Editor. * - * @param array|Editor $fields * @return $this + * * @see https://editor.datatables.net/ - * @throws \Exception */ - public function editor($fields) + public function editor(Editor $editor): static { - $this->setTemplate($this->config->get('datatables-html.editor', 'datatables::editor')); - - $editor = $this->newEditor($fields); + /** @var string $template */ + $template = $this->config->get('datatables-html.editor', 'datatables::editor'); - $this->editors[] = $editor; - - return $this; - } - - /** - * @param array|Editor $fields - * @return array|Editor - * @throws \Exception - */ - protected function newEditor($fields) - { - if ($fields instanceof Editor) { - $editor = $fields; - } else { - $editor = new Editor; - $editor->fields($fields); - } + $this->setTemplate($template); if (! $editor->table) { - $editor->table('#' . $this->getTableAttribute('id')); + $editor->table('#'.$this->getTableAttribute('id')); } if (! $editor->ajax) { $editor->ajax($this->getAjaxUrl()); } - return $editor; + $this->editors[] = $editor; + + return $this; } - /** - * @return array|null - */ - public function getEditors() + public function getEditors(): array { return $this->editors; } diff --git a/src/Html/HasOptions.php b/src/Html/HasOptions.php index ce95441..14fcd6d 100644 --- a/src/Html/HasOptions.php +++ b/src/Html/HasOptions.php @@ -2,8 +2,6 @@ namespace Yajra\DataTables\Html; -use Yajra\DataTables\Html\Options; - /** * DataTables - Options builder. * @@ -11,10 +9,10 @@ */ trait HasOptions { - use Options\HasFeatures; - use Options\HasData; + use Options\HasAjax; use Options\HasCallbacks; use Options\HasColumns; + use Options\HasFeatures; use Options\HasInternationalisation; use Options\Plugins\AutoFill; use Options\Plugins\Buttons; @@ -26,17 +24,17 @@ trait HasOptions use Options\Plugins\RowGroup; use Options\Plugins\RowReorder; use Options\Plugins\Scroller; - use Options\Plugins\Select; use Options\Plugins\SearchPanes; + use Options\Plugins\Select; /** * Set deferLoading option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/deferLoading */ - public function deferLoading($value = null) + public function deferLoading(array|int|null $value = null): static { $this->attributes['deferLoading'] = $value; @@ -46,11 +44,11 @@ public function deferLoading($value = null) /** * Set destroy option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/destroy */ - public function destroy(bool $value = false) + public function destroy(bool $value = false): static { $this->attributes['destroy'] = $value; @@ -60,11 +58,11 @@ public function destroy(bool $value = false) /** * Set displayStart option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/displayStart */ - public function displayStart(int $value = 0) + public function displayStart(int $value = 0): static { $this->attributes['displayStart'] = $value; @@ -74,25 +72,50 @@ public function displayStart(int $value = 0) /** * Set dom option value. * - * @param string $value * @return $this + * + * @deprecated Use layout() method instead. * @see https://datatables.net/reference/option/dom */ - public function dom(string $value) + public function dom(string $value): static { $this->attributes['dom'] = $value; return $this; } + /** + * Set layout option value. + * + * @return $this + * + * @see https://datatables.net/reference/option/layout + */ + public function layout(array|Layout|callable $value): static + { + if ($value instanceof Layout) { + $value = $value->toArray(); + } + + if (is_callable($value)) { + $layout = new Layout; + $value($layout); + $value = $layout->toArray(); + } + + $this->attributes['layout'] = $value; + + return $this; + } + /** * Set lengthMenu option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/lengthMenu */ - public function lengthMenu(array $value = [10, 25, 50, 100]) + public function lengthMenu(array $value = [10, 25, 50, 100]): static { $this->attributes['lengthMenu'] = $value; @@ -102,11 +125,11 @@ public function lengthMenu(array $value = [10, 25, 50, 100]) /** * Set orders option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/order */ - public function orders(array $value) + public function orders(array $value): static { $this->attributes['order'] = $value; @@ -116,11 +139,11 @@ public function orders(array $value) /** * Set orderCellsTop option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/orderCellsTop */ - public function orderCellsTop(bool $value = false) + public function orderCellsTop(bool $value = false): static { $this->attributes['orderCellsTop'] = $value; @@ -130,11 +153,11 @@ public function orderCellsTop(bool $value = false) /** * Set orderClasses option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/orderClasses */ - public function orderClasses(bool $value = true) + public function orderClasses(bool $value = true): static { $this->attributes['orderClasses'] = $value; @@ -144,12 +167,11 @@ public function orderClasses(bool $value = true) /** * Order option builder. * - * @param int|array $index - * @param string $direction * @return $this + * * @see https://datatables.net/reference/option/order */ - public function orderBy($index, $direction = 'desc') + public function orderBy(array|int $index, string $direction = 'desc'): static { if ($direction != 'desc') { $direction = 'asc'; @@ -167,12 +189,11 @@ public function orderBy($index, $direction = 'desc') /** * Order Fixed option builder. * - * @param int|array $index - * @param string $direction * @return $this + * * @see https://datatables.net/reference/option/orderFixed */ - public function orderByFixed($index, $direction = 'desc') + public function orderByFixed(array|int $index, string $direction = 'desc'): static { if ($direction != 'desc') { $direction = 'asc'; @@ -190,11 +211,11 @@ public function orderByFixed($index, $direction = 'desc') /** * Set orderMulti option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/orderMulti */ - public function orderMulti(bool $value = true) + public function orderMulti(bool $value = true): static { $this->attributes['orderMulti'] = $value; @@ -204,11 +225,11 @@ public function orderMulti(bool $value = true) /** * Set pageLength option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/pageLength */ - public function pageLength(int $value = 10) + public function pageLength(int $value = 10): static { $this->attributes['pageLength'] = $value; @@ -218,11 +239,11 @@ public function pageLength(int $value = 10) /** * Set pagingType option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/pagingType */ - public function pagingType(string $value = 'simple_numbers') + public function pagingType(string $value = 'simple_numbers'): static { $this->attributes['pagingType'] = $value; @@ -232,11 +253,11 @@ public function pagingType(string $value = 'simple_numbers') /** * Set renderer option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/renderer */ - public function renderer($value = 'bootstrap') + public function renderer(string $value = 'bootstrap'): static { $this->attributes['renderer'] = $value; @@ -246,11 +267,11 @@ public function renderer($value = 'bootstrap') /** * Set retrieve option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/retrieve */ - public function retrieve(bool $value = false) + public function retrieve(bool $value = false): static { $this->attributes['retrieve'] = $value; @@ -260,11 +281,11 @@ public function retrieve(bool $value = false) /** * Set rowId option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/rowId */ - public function rowId(string $value = 'DT_RowId') + public function rowId(string $value = 'DT_RowId'): static { $this->attributes['rowId'] = $value; @@ -274,11 +295,11 @@ public function rowId(string $value = 'DT_RowId') /** * Set scrollCollapse option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/scrollCollapse */ - public function scrollCollapse($value = false) + public function scrollCollapse(bool $value = false): static { $this->attributes['scrollCollapse'] = $value; @@ -288,11 +309,11 @@ public function scrollCollapse($value = false) /** * Set search option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/search */ - public function search(array $value) + public function search(array $value): static { $this->attributes['search'] = $value; @@ -302,11 +323,11 @@ public function search(array $value) /** * Set searchCols option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/searchCols */ - public function searchCols(array $value) + public function searchCols(array $value): static { $this->attributes['searchCols'] = $value; @@ -316,11 +337,11 @@ public function searchCols(array $value) /** * Set searchDelay option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/searchDelay */ - public function searchDelay(int $value) + public function searchDelay(int $value): static { $this->attributes['searchDelay'] = $value; @@ -330,11 +351,11 @@ public function searchDelay(int $value) /** * Set stateDuration option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/stateDuration */ - public function stateDuration(int $value) + public function stateDuration(int $value): static { $this->attributes['stateDuration'] = $value; @@ -344,11 +365,11 @@ public function stateDuration(int $value) /** * Set stripeClasses option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/stripeClasses */ - public function stripeClasses(array $value) + public function stripeClasses(array $value): static { $this->attributes['stripeClasses'] = $value; @@ -358,14 +379,37 @@ public function stripeClasses(array $value) /** * Set tabIndex option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/tabIndex */ - public function tabIndex(int $value = 0) + public function tabIndex(int $value = 0): static { $this->attributes['tabIndex'] = $value; return $this; } + + /** + * @return $this + */ + public function setPluginAttribute(string $key, array|bool $value): static + { + if (is_array($value)) { + $this->attributes[$key] = array_merge((array) ($this->attributes[$key] ?? []), $value); + } else { + $this->attributes[$key] = $value; + } + + return $this; + } + + public function getPluginAttribute(string $plugin, ?string $key = null): mixed + { + if (is_null($key)) { + return $this->attributes[$plugin] ?? true; + } + + return $this->attributes[$plugin][$key] ?? false; + } } diff --git a/src/Html/HasTable.php b/src/Html/HasTable.php index 67b85db..aa6c4bb 100644 --- a/src/Html/HasTable.php +++ b/src/Html/HasTable.php @@ -6,28 +6,12 @@ trait HasTable { - /** - * Retrieves HTML table attribute value. - * - * @param string $attribute - * @return mixed - * @throws \Exception - */ - public function getTableAttribute($attribute) - { - if (! array_key_exists($attribute, $this->tableAttributes)) { - throw new \Exception("Table attribute '{$attribute}' does not exist."); - } - - return $this->tableAttributes[$attribute]; - } + protected ?string $theadClass = null; /** * Get table computed table attributes. - * - * @return array */ - public function getTableAttributes() + public function getTableAttributes(): array { return $this->tableAttributes; } @@ -35,32 +19,19 @@ public function getTableAttributes() /** * Sets HTML table "id" attribute. * - * @param string $id * @return $this */ - public function setTableId($id) + public function setTableId(string $id): static { return $this->setTableAttribute('id', $id); } - /** - * Get HTML table "id" attribute. - * - * @return string - */ - public function getTableId() - { - return $this->getTableAttribute('id'); - } - /** * Sets HTML table attribute(s). * - * @param string|array $attribute - * @param mixed $value * @return $this */ - public function setTableAttribute($attribute, $value = null) + public function setTableAttribute(array|string $attribute, ?string $value = null): static { if (is_array($attribute)) { return $this->setTableAttributes($attribute); @@ -74,10 +45,9 @@ public function setTableAttribute($attribute, $value = null) /** * Sets multiple HTML table attributes at once. * - * @param array $attributes * @return $this */ - public function setTableAttributes(array $attributes) + public function setTableAttributes(array $attributes): static { foreach ($attributes as $attribute => $value) { $this->tableAttributes[$attribute] = $value; @@ -86,37 +56,63 @@ public function setTableAttributes(array $attributes) return $this; } + /** + * Get HTML table "id" attribute. + */ + public function getTableId(): string + { + return $this->getTableAttribute('id'); + } + + /** + * Retrieves HTML table attribute value. + */ + public function getTableAttribute(string $attribute): string + { + return $this->tableAttributes[$attribute] ?? ''; + } + /** * Add class names to the "class" attribute of HTML table. * - * @param string|array $class * @return $this */ - public function addTableClass($class) + public function addTableClass(array|string $class): static { $class = is_array($class) ? implode(' ', $class) : $class; $currentClass = Arr::get(array_change_key_case($this->tableAttributes), 'class'); - $classes = preg_split('#\s+#', $currentClass . ' ' . $class, null, PREG_SPLIT_NO_EMPTY); - $class = implode(' ', array_unique($classes)); + $classes = preg_split('#\s+#', $currentClass.' '.$class, -1, PREG_SPLIT_NO_EMPTY); + $class = implode(' ', array_unique((array) $classes)); return $this->setTableAttribute('class', $class); } + /** + * Set table > thead class names. + * + * @return $this + */ + public function setTableHeadClass(string $class): static + { + $this->theadClass = " class=\"$class\""; + + return $this; + } + /** * Remove class names from the "class" attribute of HTML table. * - * @param string|array $class * @return $this */ - public function removeTableClass($class) + public function removeTableClass(array|string $class): static { $class = is_array($class) ? implode(' ', $class) : $class; - $currentClass = Arr::get(array_change_key_case($this->tableAttributes), 'class'); + $currentClass = $this->getTableAttribute('class'); $classes = array_diff( - preg_split('#\s+#', $currentClass, null, PREG_SPLIT_NO_EMPTY), - preg_split('#\s+#', $class, null, PREG_SPLIT_NO_EMPTY) + (array) preg_split('#\s+#', (string) $currentClass, -1, PREG_SPLIT_NO_EMPTY), + (array) preg_split('#\s+#', $class, -1, PREG_SPLIT_NO_EMPTY) ); $class = implode(' ', array_unique($classes)); @@ -125,57 +121,64 @@ public function removeTableClass($class) /** * Compile table headers and to support responsive extension. - * - * @return array */ - protected function compileTableHeaders() + protected function compileTableHeaders(): array { $th = []; - foreach ($this->collection->toArray() as $row) { - $thAttr = $this->html->attributes(array_merge( - Arr::only($row, ['class', 'id', 'title', 'width', 'style', 'data-class', 'data-hide']), - $row['attributes'], - isset($row['titleAttr']) ? ['title' => $row['titleAttr']] : [] - )); - $th[] = '' . $row['title'] . ''; - } + + $this->collection->each(function (Column $column) use (&$th) { + $only = Arr::only( + $column->toArray(), + ['class', 'id', 'title', 'width', 'style', 'data-class', 'data-hide'] + ); + + $attributes = array_merge( + $only, + $column->attributes, + isset($column['titleAttr']) ? ['title' => $column['titleAttr']] : [] + ); + + $thAttr = $this->html->attributes($attributes); + $th[] = ''.$column['title'].''; + }); return $th; } /** * Compile table search headers. - * - * @return array */ - protected function compileTableSearchHeaders() + protected function compileTableSearchHeaders(): array { $search = []; - foreach ($this->collection->all() as $key => $row) { - $search[] = $row['searchable'] ? '' . (isset($row->search) ? $row->search : '') . '' : ''; - } + + $this->collection->each(function (Column $column) use (&$search) { + $search[] = $column['searchable'] ? ''.($column['search'] ?? '').'' : ''; + }); return $search; } /** * Compile table footer contents. - * - * @return array */ - protected function compileTableFooter() + protected function compileTableFooter(): array { $footer = []; - foreach ($this->collection->all() as $row) { - if (is_array($row->footer)) { - $footerAttr = $this->html->attributes(Arr::only($row->footer, - ['class', 'id', 'title', 'width', 'style', 'data-class', 'data-hide'])); - $title = isset($row->footer['title']) ? $row->footer['title'] : ''; - $footer[] = '' . $title . ''; + + $this->collection->each(function (Column $column) use (&$footer) { + if (is_array($column->footer)) { + $footerAttr = $this->html->attributes( + Arr::only($column->footer, ['class', 'id', 'title', 'width', 'style', 'data-class', 'data-hide']) + ); + + $title = $column->footer['title'] ?? ''; + + $footer[] = ''.$title.''; } else { - $footer[] = '' . $row->footer . ''; + $footer[] = ''.$column->footer.''; } - } + }); return $footer; } diff --git a/src/Html/HtmlBuilder.php b/src/Html/HtmlBuilder.php new file mode 100644 index 0000000..cf02734 --- /dev/null +++ b/src/Html/HtmlBuilder.php @@ -0,0 +1,436 @@ +url->asset($url, $secure); + + return $this->toHtmlString('attributes($attributes).'>'); + } + + /** + * Transform the string to an Html serializable object + */ + protected function toHtmlString(string $html): HtmlString + { + return new HtmlString($html); + } + + /** + * Build an HTML attribute string from an array. + */ + public function attributes(array $attributes): string + { + $html = []; + + foreach ($attributes as $key => $value) { + $element = $this->attributeElement($key, $value); + + if (! is_null($element)) { + $html[] = $element; + } + } + + return ! empty($html) ? ' '.implode(' ', $html) : ''; + } + + /** + * Build a single attribute element. + */ + protected function attributeElement(string $key, mixed $value): mixed + { + // For numeric keys we will assume that the value is a boolean attribute + // where the presence of the attribute represents a true value and the + // absence represents a false value. + // This will convert HTML attributes such as "required" to a correct + // form instead of using incorrect numerics. + if (is_numeric($key)) { + return $value; + } + + // Treat boolean attributes as HTML properties + if (is_bool($value) && $key !== 'value') { + return $value ? $key : ''; + } + + if (is_array($value) && $key === 'class') { + return 'class="'.implode(' ', $value).'"'; + } + + if (is_bool($value) || is_float($value) || is_int($value) || is_resource($value) || is_string($value)) { + return $key.'="'.e(strval($value), false).'"'; + } + + return null; + } + + /** + * Generate a link to a CSS file. + */ + public function style(string $url, array $attributes = [], ?bool $secure = null): HtmlString + { + $defaults = ['media' => 'all', 'type' => 'text/css', 'rel' => 'stylesheet']; + + $attributes = array_merge($defaults, $attributes); + + $attributes['href'] = $this->url->asset($url, $secure); + + return $this->toHtmlString('attributes($attributes).'>'); + } + + /** + * Generate an HTML image element. + */ + public function image(string $url, ?string $alt = null, array $attributes = [], ?bool $secure = null): HtmlString + { + $attributes['alt'] = $alt; + + return $this->toHtmlString('attributes($attributes).'>'); + } + + /** + * Generate a link to a Favicon file. + */ + public function favicon(string $url, array $attributes = [], ?bool $secure = null): HtmlString + { + $defaults = ['rel' => 'shortcut icon', 'type' => 'image/x-icon']; + + $attributes = array_merge($defaults, $attributes); + + $attributes['href'] = $this->url->asset($url, $secure); + + return $this->toHtmlString('attributes($attributes).'>'); + } + + /** + * Generate a HTTPS HTML link. + */ + public function secureLink( + string $url, + ?string $title = null, + array $attributes = [], + bool $escape = true + ): HtmlString { + return $this->link($url, $title, $attributes, true, $escape); + } + + /** + * Generate a HTML link. + */ + public function link( + string $url, + ?string $title = null, + array $attributes = [], + ?bool $secure = null, + bool $escape = true + ): HtmlString { + $url = $this->url->to($url, [], $secure); + + if (is_null($title)) { + $title = $url; + } + + if ($escape) { + $title = $this->entities($title); + } + + return $this->toHtmlString( + 'attributes($attributes).'>'.$title.'' + ); + } + + /** + * Convert an HTML string to entities. + */ + public function entities(string $value): string + { + return htmlentities($value, ENT_QUOTES, 'UTF-8', false); + } + + /** + * Generate a HTTPS HTML link to an asset. + */ + public function linkSecureAsset( + string $url, + ?string $title = null, + array $attributes = [], + bool $escape = true + ): HtmlString { + return $this->linkAsset($url, $title, $attributes, true, $escape); + } + + /** + * Generate a HTML link to an asset. + */ + public function linkAsset( + string $url, + ?string $title = null, + array $attributes = [], + ?bool $secure = null, + bool $escape = true + ): HtmlString { + $url = $this->url->asset($url, $secure); + + return $this->link($url, $title ?: $url, $attributes, $secure, $escape); + } + + /** + * Generate a HTML link to a named route. + */ + public function linkRoute( + string $name, + ?string $title = null, + array $parameters = [], + array $attributes = [], + ?bool $secure = null, + bool $escape = true + ): HtmlString { + return $this->link($this->url->route($name, $parameters), $title, $attributes, $secure, $escape); + } + + /** + * Generate a HTML link to a controller action. + */ + public function linkAction( + string $action, + ?string $title = null, + array $parameters = [], + array $attributes = [], + ?bool $secure = null, + bool $escape = true + ): HtmlString { + return $this->link($this->url->action($action, $parameters), $title, $attributes, $secure, $escape); + } + + /** + * Generate a HTML link to an email address. + */ + public function mailto(string $email, ?string $title = null, array $attributes = [], bool $escape = true): HtmlString + { + $email = $this->email($email); + + $title = $title ?: $email; + + if ($escape) { + $title = $this->entities($title); + } + + $email = $this->obfuscate('mailto:').$email; + + return $this->toHtmlString('attributes($attributes).'>'.$title.''); + } + + /** + * Obfuscate an e-mail address to prevent spam-bots from sniffing it. + */ + public function email(string $email): string + { + return str_replace('@', '@', $this->obfuscate($email)); + } + + /** + * Obfuscate a string to prevent spam-bots from sniffing it. + * + * @throws \Exception + */ + public function obfuscate(string $value): string + { + $safe = ''; + + foreach (str_split($value) as $letter) { + if (ord($letter) > 128) { + return $letter; + } + + // To properly obfuscate the value, we will randomly convert each letter to + // its entity or hexadecimal representation, keeping a bot from sniffing + // the randomly obfuscated letters out of the string on the responses. + switch (random_int(1, 3)) { + case 1: + $safe .= '&#'.ord($letter).';'; + break; + + case 2: + $safe .= '&#x'.dechex(ord($letter)).';'; + break; + + case 3: + $safe .= $letter; + } + } + + return $safe; + } + + /** + * Generates non-breaking space entities based on number supplied. + */ + public function nbsp(int $num = 1): string + { + return str_repeat(' ', $num); + } + + /** + * Generate an ordered list of items. + */ + public function ol(array $list, array $attributes = []): HtmlString|string + { + return $this->listing('ol', $list, $attributes); + } + + /** + * Create a listing HTML element. + */ + protected function listing(string $type, array $list, array $attributes = []): HtmlString|string + { + $html = ''; + + if (empty($list)) { + return $html; + } + + // Essentially we will just spin through the list and build the list of the HTML + // elements from the array. We will also handled nested lists in case that is + // present in the array. Then we will build out the final listing elements. + foreach ($list as $key => $value) { + $html .= $this->listingElement($key, $type, $value); + } + + $attributes = $this->attributes($attributes); + + return $this->toHtmlString("<{$type}{$attributes}>{$html}"); + } + + /** + * Create the HTML for a listing element. + */ + protected function listingElement(mixed $key, string $type, mixed $value): HtmlString|string + { + if (is_array($value)) { + return $this->nestedListing($key, $type, $value); + } else { + if (is_bool($value) + || is_float($value) + || is_int($value) + || is_resource($value) + || is_string($value) + || is_null($value) + ) { + return '
  • '.e(strval($value), false).'
  • '; + } + } + + return '
  • '.$value.'
  • '; + } + + /** + * Create the HTML for a nested listing attribute. + */ + protected function nestedListing(mixed $key, string $type, array $value): HtmlString|string + { + if (is_int($key)) { + return $this->listing($type, $value); + } else { + return '
  • '.$key.$this->listing($type, $value).'
  • '; + } + } + + /** + * Generate an un-ordered list of items. + */ + public function ul(array $list, array $attributes = []): HtmlString|string + { + return $this->listing('ul', $list, $attributes); + } + + /** + * Generate a description list of items. + */ + public function dl(array $list, array $attributes = []): HtmlString + { + $attributes = $this->attributes($attributes); + + $html = ""; + + foreach ($list as $key => $value) { + $value = (array) $value; + + $html .= "
    $key
    "; + + foreach ($value as $v_value) { + $html .= "
    $v_value
    "; + } + } + + $html .= ''; + + return $this->toHtmlString($html); + } + + /** + * Generate a meta tag. + */ + public function meta(string $name, string $content, array $attributes = []): HtmlString + { + $defaults = compact('name', 'content'); + + $attributes = array_merge($defaults, $attributes); + + return $this->toHtmlString('attributes($attributes).'>'); + } + + /** + * Generate an html tag. + */ + public function tag(string $tag, mixed $content, array $attributes = []): HtmlString + { + $content = is_array($content) ? implode('', $content) : $content; + + if (is_bool($content) + || is_float($content) + || is_int($content) + || is_resource($content) + || is_string($content) + || is_null($content) + ) { + return $this->toHtmlString( + '<'.$tag.$this->attributes($attributes).'>'.$this->toHtmlString(strval($content)).'' + ); + } + + return $this->toHtmlString('<'.$tag.$this->attributes($attributes).'>'.$content.''); + } +} diff --git a/src/Html/Layout.php b/src/Html/Layout.php new file mode 100644 index 0000000..c3a952e --- /dev/null +++ b/src/Html/Layout.php @@ -0,0 +1,149 @@ +attributes[LayoutPosition::Top->withOrder($order)] = $options; + + return $this; + } + + public function topStart(string|array|null $options, ?int $order = null): static + { + $this->attributes[LayoutPosition::TopStart->withOrder($order)] = $options; + + return $this; + } + + public function topEnd(string|array|null $options, ?int $order = null): static + { + $this->attributes[LayoutPosition::TopEnd->withOrder($order)] = $options; + + return $this; + } + + public function topView(string $selector, ?int $order = null): static + { + return $this->top($this->renderCustomElement($selector), $order); + } + + public function topStartView(string $selector, ?int $order = null): static + { + return $this->topStart($this->renderCustomElement($selector), $order); + } + + public function topEndView(string $selector, ?int $order = null): static + { + return $this->topEnd($this->renderCustomElement($selector), $order); + } + + public function bottom(array|string|null $options, ?int $order = null): static + { + $this->attributes[LayoutPosition::Bottom->withOrder($order)] = $options; + + return $this; + } + + public function bottomStart(string|array|null $options, ?int $order = null): static + { + $this->attributes[LayoutPosition::BottomStart->withOrder($order)] = $options; + + return $this; + } + + public function bottomEnd(string|array|null $options, ?int $order = null): static + { + $this->attributes[LayoutPosition::BottomEnd->withOrder($order)] = $options; + + return $this; + } + + public function bottomView(string $selector, ?int $order = null): static + { + return $this->bottom($this->renderCustomElement($selector), $order); + } + + public function bottomStartView(string $selector, ?int $order = null): static + { + return $this->bottomStart($this->renderCustomElement($selector), $order); + } + + public function bottomEndView(string $selector, ?int $order = null): static + { + return $this->bottomEnd($this->renderCustomElement($selector), $order); + } + + /** + * @throws Throwable + */ + public function addView( + Component|Renderable|string $view, + LayoutPosition $layoutPosition, + ?int $order = null + ): static { + if ($view instanceof Component) { + $view = Blade::renderComponent($view); + } + + $html = $view instanceof Renderable ? $view->render() : Blade::render($view); + + $element = json_encode($html); + + if ($element === false) { + throw new InvalidArgumentException("Cannot render view [$html] to json."); + } + + $this->attributes[$layoutPosition->withOrder($order)] = $this->renderCustomElement($element, false); + + return $this; + } + + /** + * @param class-string $component + * + * @throws Throwable + */ + public function addLivewire( + string $component, + LayoutPosition $layoutPosition, + ?int $order = null + ): static { + $html = json_encode(Livewire::mount($component)); + + if ($html === false) { + throw new InvalidArgumentException("Cannot render Livewire component [$component] to json."); + } + + $this->attributes[$layoutPosition->withOrder($order)] = $this->renderCustomElement($html, false); + + return $this; + } + + private function renderCustomElement(string $element, bool $asJsSelector = true): string + { + $html = $asJsSelector ? "$('{$element}').html()" : $element; + + return "function() { return $html; }"; + } +} diff --git a/src/Html/Options/HasData.php b/src/Html/Options/HasAjax.php similarity index 50% rename from src/Html/Options/HasData.php rename to src/Html/Options/HasAjax.php index 21e750b..50d8a75 100644 --- a/src/Html/Options/HasData.php +++ b/src/Html/Options/HasAjax.php @@ -3,26 +3,39 @@ namespace Yajra\DataTables\Html\Options; use Illuminate\Support\Arr; +use Yajra\DataTables\Utilities\Helper; /** * DataTables - Data option builder. * * @see https://datatables.net/reference/option/ */ -trait HasData +trait HasAjax { /** - * @var string|array + * Setup "ajax" parameter with POST method. + * + * @return $this */ - protected $ajax = ''; + public function postAjax(array|string $attributes = ''): static + { + if (! is_array($attributes)) { + $attributes = ['url' => $attributes]; + } + + unset($attributes['method']); + Arr::set($attributes, 'type', 'POST'); + Arr::set($attributes, 'headers.X-HTTP-Method-Override', 'GET'); + + return $this->ajax($attributes); + } /** * Setup ajax parameter. * - * @param string|array $attributes * @return $this */ - public function ajax($attributes = '') + public function ajax(array|string $attributes = ''): static { $this->ajax = $attributes; @@ -30,56 +43,91 @@ public function ajax($attributes = '') } /** - * Setup "ajax" parameter with POST method. - * - * @param string|array $attributes * @return $this */ - public function postAjax($attributes = '') + public function postAjaxWithForm(string $url, string $formSelector): static { - if (! is_array($attributes)) { - $attributes = ['url' => (string) $attributes]; - } + $attributes = ['url' => $url]; - unset($attributes['method']); Arr::set($attributes, 'type', 'POST'); Arr::set($attributes, 'headers.X-HTTP-Method-Override', 'GET'); + $script = $this->getScriptWithFormSelector($formSelector); + + $attributes['data'] = "function(data) { $script }"; + return $this->ajax($attributes); } + protected function getScriptWithFormSelector(string $formSelector): string + { + return << 1) { + data[group[0].name] = []; + $.each(group, function(i, obj) { + data[obj.name].push(obj.value) + }) + } else { + data[group[0].name] = group[0].value; + } +}); +CDATA; + } + /** * Setup ajax parameter for datatables pipeline plugin. * - * @param string $url - * @param string $pages * @return $this + * + * @see https://datatables.net/examples/server_side/pipeline.html */ - public function pipeline($url, $pages) + public function pipeline(string $url, int $pages = 5): static { - $this->ajax = "$.fn.dataTable.pipeline({ url: '{$url}', pages: {$pages} })"; + return $this->ajax("$.fn.dataTable.pipeline({ url: '$url', pages: $pages })"); + } - return $this; + /** + * Get ajax url. + */ + public function getAjaxUrl(): string + { + if (is_array($this->ajax)) { + return $this->ajax['url'] ?: url()->current(); + } + + return $this->ajax ?: url()->current(); + } + + /** + * Set ajax url with data added from form. + * + * @return $this + */ + public function ajaxWithForm(string $url, string $formSelector): static + { + return $this->minifiedAjax($url, $this->getScriptWithFormSelector($formSelector)); } /** * Minify ajax url generated when using get request * by deleting unnecessary url params. * - * @param string $url - * @param string $script - * @param array $data - * @param array $ajaxParameters * @return $this */ - public function minifiedAjax($url = '', $script = null, $data = [], $ajaxParameters = []) - { + public function minifiedAjax( + string $url = '', + ?string $script = null, + array $data = [], + array $ajaxParameters = [] + ): static { $this->ajax = []; $appendData = $this->makeDataScript($data); $this->ajax['url'] = empty($url) ? url()->full() : $url; $this->ajax['type'] = 'GET'; - if (isset($this->attributes['serverSide']) ? $this->attributes['serverSide'] : true) { + if (! isset($this->attributes['serverSide']) || $this->attributes['serverSide']) { $this->ajax['data'] = 'function(data) { for (var i = 0, len = data.columns.length; i < len; i++) { if (!data.columns[i].search.value) delete data.columns[i].search; @@ -108,35 +156,16 @@ public function minifiedAjax($url = '', $script = null, $data = [], $ajaxParamet } /** - * Get ajax url. - * - * @return array|mixed|string + * Make a data script to be appended on ajax request of dataTables. */ - public function getAjaxUrl() + protected function makeDataScript(array $data): string { - if (is_array($this->ajax)) { - return $this->ajax['url'] ?: url()->current(); + $script = ''; + foreach ($data as $key => $value) { + $dataValue = Helper::isJavascript($value, $key) ? $value : (is_string($value) ? "'$value'" : $value); + $script .= PHP_EOL."data.$key = $dataValue;"; } - return $this->ajax ?: url()->current(); - } - - /** - * Set ajax url with data added from form. - * - * @param string $url - * @param string $formSelector - * @return $this - */ - public function ajaxWithForm($url, $formSelector) - { - $script = <<minifiedAjax($url, $script); + return $script; } } diff --git a/src/Html/Options/HasCallbacks.php b/src/Html/Options/HasCallbacks.php index 5bb200c..d63d8bc 100644 --- a/src/Html/Options/HasCallbacks.php +++ b/src/Html/Options/HasCallbacks.php @@ -12,11 +12,11 @@ trait HasCallbacks /** * Set createdRow option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/createdRow */ - public function createdRow($script) + public function createdRow(string $script): static { $this->attributes['createdRow'] = $script; @@ -26,11 +26,11 @@ public function createdRow($script) /** * Set drawCallback option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/drawCallback */ - public function drawCallback($script) + public function drawCallback(string $script): static { $this->attributes['drawCallback'] = $script; @@ -41,11 +41,11 @@ public function drawCallback($script) * Set drawCallback option value with Livewire integration. * Solution as per issue https://github.com/yajra/laravel-datatables/issues/2401. * - * @param mixed|null $script * @return $this + * * @see https://datatables.net/reference/option/drawCallback */ - public function drawCallbackWithLivewire($script = null) + public function drawCallbackWithLivewire(?string $script = null): static { $js = "function(settings) { if (window.livewire) { @@ -63,11 +63,11 @@ public function drawCallbackWithLivewire($script = null) /** * Set footerCallback option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/footerCallback */ - public function footerCallback($script) + public function footerCallback(string $script): static { $this->attributes['footerCallback'] = $script; @@ -77,11 +77,11 @@ public function footerCallback($script) /** * Set formatNumber option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/formatNumber */ - public function formatNumber($script) + public function formatNumber(string $script): static { $this->attributes['formatNumber'] = $script; @@ -91,11 +91,11 @@ public function formatNumber($script) /** * Set headerCallback option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/headerCallback */ - public function headerCallback($script) + public function headerCallback(string $script): static { $this->attributes['headerCallback'] = $script; @@ -105,11 +105,11 @@ public function headerCallback($script) /** * Set infoCallback option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/infoCallback */ - public function infoCallback($script) + public function infoCallback(string $script): static { $this->attributes['infoCallback'] = $script; @@ -119,11 +119,11 @@ public function infoCallback($script) /** * Set initComplete option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/initComplete */ - public function initComplete($script) + public function initComplete(string $script): static { $this->attributes['initComplete'] = $script; @@ -133,11 +133,11 @@ public function initComplete($script) /** * Set preDrawCallback option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/preDrawCallback */ - public function preDrawCallback($script) + public function preDrawCallback(string $script): static { $this->attributes['preDrawCallback'] = $script; @@ -147,11 +147,11 @@ public function preDrawCallback($script) /** * Set rowCallback option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/rowCallback */ - public function rowCallback($script) + public function rowCallback(string $script): static { $this->attributes['rowCallback'] = $script; @@ -161,11 +161,11 @@ public function rowCallback($script) /** * Set stateLoadCallback option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/stateLoadCallback */ - public function stateLoadCallback($script) + public function stateLoadCallback(string $script): static { $this->attributes['stateLoadCallback'] = $script; @@ -175,11 +175,11 @@ public function stateLoadCallback($script) /** * Set stateLoaded option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/stateLoaded */ - public function stateLoaded($script) + public function stateLoaded(string $script): static { $this->attributes['stateLoaded'] = $script; @@ -189,11 +189,11 @@ public function stateLoaded($script) /** * Set stateLoadParams option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/stateLoadParams */ - public function stateLoadParams($script) + public function stateLoadParams(string $script): static { $this->attributes['stateLoadParams'] = $script; @@ -203,11 +203,11 @@ public function stateLoadParams($script) /** * Set stateSaveCallback option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/stateSaveCallback */ - public function stateSaveCallback($script) + public function stateSaveCallback(string $script): static { $this->attributes['stateSaveCallback'] = $script; @@ -217,11 +217,11 @@ public function stateSaveCallback($script) /** * Set stateSaveParams option value. * - * @param mixed $script * @return $this + * * @see https://datatables.net/reference/option/stateSaveParams */ - public function stateSaveParams($script) + public function stateSaveParams(string $script): static { $this->attributes['stateSaveParams'] = $script; diff --git a/src/Html/Options/HasColumns.php b/src/Html/Options/HasColumns.php index f477a90..5444ce0 100644 --- a/src/Html/Options/HasColumns.php +++ b/src/Html/Options/HasColumns.php @@ -2,10 +2,9 @@ namespace Yajra\DataTables\Html\Options; +use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Collection; -use Illuminate\Support\Str; use Yajra\DataTables\Html\Column; -use Illuminate\Contracts\Support\Arrayable; /** * DataTables - Columns option builder. @@ -17,11 +16,11 @@ trait HasColumns /** * Set columnDefs option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columnDefs */ - public function columnDefs($value) + public function columnDefs(array|Arrayable|callable $value): static { if (is_callable($value)) { $value = app()->call($value); @@ -31,6 +30,14 @@ public function columnDefs($value) $value = $value->toArray(); } + if (is_array($value)) { + foreach ($value as $key => $def) { + if ($def instanceof Arrayable) { + $value[$key] = $def->toArray(); + } + } + } + $this->attributes['columnDefs'] = $value; return $this; @@ -39,11 +46,11 @@ public function columnDefs($value) /** * Add a columnDef option. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/columnDefs */ - public function addColumnDef($value) + public function addColumnDef(array|Arrayable|callable $value): static { if (is_callable($value)) { $value = app()->call($value); @@ -61,35 +68,35 @@ public function addColumnDef($value) /** * Set columns option value. * - * @param array $columns * @return $this + * * @see https://datatables.net/reference/option/columns */ - public function columns(array $columns) + public function columns(array $columns): static { $this->collection = new Collection; foreach ($columns as $key => $value) { if (! is_a($value, Column::class)) { if (is_array($value)) { - $attributes = array_merge( - [ - 'name' => $value['name'] ?? $value['data'] ?? $key, - 'data' => $value['data'] ?? $key, - ], - $this->setTitle($key, $value) - ); + $attributes = array_merge($value, [ + 'name' => $value['name'] ?? $value['data'] ?? $key, + 'data' => $value['data'] ?? $key, + ]); } else { $attributes = [ 'name' => $value, 'data' => $value, - 'title' => $this->getQualifiedTitle($value), ]; } $this->collection->push(new Column($attributes)); } else { - $this->collection->push($value); + + // Only add the column if it is authorized, otherwise ignore it. + if ($value->isAuthorized()) { + $this->collection->push($value); + } } } @@ -97,41 +104,29 @@ public function columns(array $columns) } /** - * Set title attribute of an array if not set. + * Add a column in collection using attributes. * - * @param string $title - * @param array $attributes - * @return array + * @return $this */ - public function setTitle($title, array $attributes) + public function addColumn(array|Column $attributes): static { - if (! isset($attributes['title'])) { - $attributes['title'] = $this->getQualifiedTitle($title); + if (is_array($attributes)) { + $this->collection->push(new Column($attributes)); + } else { + $this->add($attributes); } - return $attributes; - } - - /** - * Convert string into a readable title. - * - * @param string $title - * @return string - */ - public function getQualifiedTitle($title) - { - return Str::title(str_replace(['.', '_'], ' ', Str::snake($title))); + return $this; } /** - * Add a column in collection usingsl attributes. + * Add a Column object in collection. * - * @param array $attributes * @return $this */ - public function addColumn(array $attributes) + public function add(Column $column): static { - $this->collection->push(new Column($attributes)); + $this->collection->push($column); return $this; } @@ -139,10 +134,9 @@ public function addColumn(array $attributes) /** * Add a Column object at the beginning of collection. * - * @param \Yajra\DataTables\Html\Column $column * @return $this */ - public function addBefore(Column $column) + public function addBefore(Column $column): static { $this->collection->prepend($column); @@ -152,25 +146,15 @@ public function addBefore(Column $column) /** * Add a column at the beginning of collection using attributes. * - * @param array $attributes - * @return $this - */ - public function addColumnBefore(array $attributes) - { - $this->collection->prepend(new Column($attributes)); - - return $this; - } - - /** - * Add a Column object in collection. - * - * @param \Yajra\DataTables\Html\Column $column * @return $this */ - public function add(Column $column) + public function addColumnBefore(array|Column $attributes): static { - $this->collection->push($column); + if (is_array($attributes)) { + $this->collection->prepend(new Column($attributes)); + } else { + $this->addBefore($attributes); + } return $this; } @@ -178,9 +162,9 @@ public function add(Column $column) /** * Get collection of columns. * - * @return \Illuminate\Support\Collection + * @return \Illuminate\Support\Collection */ - public function getColumns() + public function getColumns(): Collection { return $this->collection; } @@ -188,15 +172,14 @@ public function getColumns() /** * Remove column by name. * - * @param array $names + * @param array $names * @return $this */ - public function removeColumn(...$names) + public function removeColumn(...$names): static { foreach ($names as $name) { - $this->collection = $this->collection->filter(function (Column $column) use ($name) { - return $column->name !== $name; - })->flatten(); + // @phpstan-ignore-next-line + $this->collection = $this->collection->filter(fn (Column $column) => $column->name !== $name)->flatten(); } return $this; diff --git a/src/Html/Options/HasFeatures.php b/src/Html/Options/HasFeatures.php index 4db77e7..4a69b75 100644 --- a/src/Html/Options/HasFeatures.php +++ b/src/Html/Options/HasFeatures.php @@ -12,11 +12,11 @@ trait HasFeatures /** * Set autoWidth option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/autoWidth */ - public function autoWidth(bool $value = true) + public function autoWidth(bool $value = true): static { $this->attributes['autoWidth'] = $value; @@ -26,11 +26,11 @@ public function autoWidth(bool $value = true) /** * Set deferRender option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/deferRender */ - public function deferRender(bool $value = true) + public function deferRender(bool $value = true): static { $this->attributes['deferRender'] = $value; @@ -40,11 +40,11 @@ public function deferRender(bool $value = true) /** * Set info option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/info */ - public function info(bool $value = true) + public function info(bool $value = true): static { $this->attributes['info'] = $value; @@ -54,11 +54,11 @@ public function info(bool $value = true) /** * Set lengthChange option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/lengthChange */ - public function lengthChange(bool $value = true) + public function lengthChange(bool $value = true): static { $this->attributes['lengthChange'] = $value; @@ -68,11 +68,11 @@ public function lengthChange(bool $value = true) /** * Set ordering option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/ordering */ - public function ordering(bool $value = true) + public function ordering(bool $value = true): static { $this->attributes['ordering'] = $value; @@ -82,11 +82,11 @@ public function ordering(bool $value = true) /** * Set processing option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/processing */ - public function processing(bool $value = true) + public function processing(bool $value = true): static { $this->attributes['processing'] = $value; @@ -96,11 +96,11 @@ public function processing(bool $value = true) /** * Set scrollX option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/scrollX */ - public function scrollX(bool $value = true) + public function scrollX(bool $value = true): static { $this->attributes['scrollX'] = $value; @@ -110,11 +110,11 @@ public function scrollX(bool $value = true) /** * Set scrollY option value. * - * @param bool|mixed $value * @return $this + * * @see https://datatables.net/reference/option/scrollY */ - public function scrollY($value = true) + public function scrollY(bool|string $value = true): static { $this->attributes['scrollY'] = $value; @@ -124,11 +124,11 @@ public function scrollY($value = true) /** * Set paging option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/paging */ - public function paging(bool $value = true) + public function paging(bool $value = true): static { $this->attributes['paging'] = $value; @@ -138,11 +138,11 @@ public function paging(bool $value = true) /** * Set searching option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/searching */ - public function searching(bool $value = true) + public function searching(bool $value = true): static { $this->attributes['searching'] = $value; @@ -152,11 +152,11 @@ public function searching(bool $value = true) /** * Set serverSide option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/serverSide */ - public function serverSide(bool $value = true) + public function serverSide(bool $value = true): static { $this->attributes['serverSide'] = $value; @@ -166,11 +166,11 @@ public function serverSide(bool $value = true) /** * Set stateSave option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/stateSave */ - public function stateSave(bool $value = true) + public function stateSave(bool $value = true): static { $this->attributes['stateSave'] = $value; diff --git a/src/Html/Options/HasInternationalisation.php b/src/Html/Options/HasInternationalisation.php index 7c93a4e..6ca09bb 100644 --- a/src/Html/Options/HasInternationalisation.php +++ b/src/Html/Options/HasInternationalisation.php @@ -2,8 +2,6 @@ namespace Yajra\DataTables\Html\Options; -use Yajra\DataTables\Html\Options\Languages; - /** * DataTables - Internationalisation option builder. * @@ -17,33 +15,31 @@ trait HasInternationalisation use Languages\Select; /** - * Set language option value. + * Set language decimal option value. * - * @param string|array $value * @return $this - * @see https://datatables.net/reference/option/language + * + * @see https://datatables.net/reference/option/language.decimal */ - public function language($value) + public function languageDecimal(string $value): static { - if (is_array($value)) { - $this->attributes['language'] = $value; - } else { - $this->attributes['language']['url'] = $value; - } - - return $this; + return $this->language(['decimal' => $value]); } /** - * Set language decimal option value. + * Set language option value. * - * @param string $value * @return $this - * @see https://datatables.net/reference/option/language.decimal + * + * @see https://datatables.net/reference/option/language */ - public function languageDecimal($value) + public function language(array|string $value): static { - $this->attributes['language']['decimal'] = $value; + if (is_array($value)) { + $this->attributes['language'] = array_merge((array) ($this->attributes['language'] ?? []), $value); + } else { + $this->attributes['language']['url'] = $value; + } return $this; } @@ -51,182 +47,165 @@ public function languageDecimal($value) /** * Set language emptyTable option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.emptyTable */ - public function languageEmptyTable($value) + public function languageEmptyTable(string $value): static { - $this->attributes['language']['emptyTable'] = $value; - - return $this; + return $this->language(['emptyTable' => $value]); } /** * Set language info option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.info */ - public function languageInfo($value) + public function languageInfo(string $value): static { - $this->attributes['language']['info'] = $value; - - return $this; + return $this->language(['info' => $value]); } /** * Set language infoEmpty option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.infoEmpty */ - public function languageInfoEmpty($value) + public function languageInfoEmpty(string $value): static { - $this->attributes['language']['infoEmpty'] = $value; - - return $this; + return $this->language(['infoEmpty' => $value]); } /** * Set language infoFiltered option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.infoFiltered */ - public function languageInfoFiltered($value) + public function languageInfoFiltered(string $value): static { - $this->attributes['language']['infoFiltered'] = $value; - - return $this; + return $this->language(['infoFiltered' => $value]); } /** * Set language infoPostFix option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.infoPostFix */ - public function languageInfoPostFix($value) + public function languageInfoPostFix(string $value): static { - $this->attributes['language']['infoPostFix'] = $value; - - return $this; + return $this->language(['infoPostFix' => $value]); } /** * Set language lengthMenu option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.lengthMenu */ - public function languageLengthMenu($value) + public function languageLengthMenu(string $value): static { - $this->attributes['language']['lengthMenu'] = $value; - - return $this; + return $this->language(['lengthMenu' => $value]); } /** * Set language loadingRecords option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.loadingRecords */ - public function languageLoadingRecords($value) + public function languageLoadingRecords(string $value): static { - $this->attributes['language']['loadingRecords'] = $value; - - return $this; + return $this->language(['loadingRecords' => $value]); } /** * Set language processing option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.processing */ - public function languageProcessing($value) + public function languageProcessing(string $value): static { - $this->attributes['language']['processing'] = $value; - - return $this; + return $this->language(['processing' => $value]); } /** * Set language search option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.search */ - public function languageSearch($value) + public function languageSearch(string $value): static { - $this->attributes['language']['search'] = $value; - - return $this; + return $this->language(['search' => $value]); } /** * Set language searchPlaceholder option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.searchPlaceholder */ - public function languageSearchPlaceholder($value) + public function languageSearchPlaceholder(string $value): static { - $this->attributes['language']['searchPlaceholder'] = $value; - - return $this; + return $this->language(['searchPlaceholder' => $value]); } /** * Set language thousands option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.thousands */ - public function languageThousands($value) + public function languageThousands(string $value): static { - $this->attributes['language']['thousands'] = $value; - - return $this; + return $this->language(['thousands' => $value]); } /** * Set language url option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.url */ - public function languageUrl($value) + public function languageUrl(string $value): static { - $this->attributes['language']['url'] = $value; - - return $this; + return $this->language(['url' => $value]); } /** * Set language zeroRecords option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.zeroRecords */ - public function languageZeroRecords($value) + public function languageZeroRecords(string $value): static { - $this->attributes['language']['zeroRecords'] = $value; + return $this->language(['zeroRecords' => $value]); + } - return $this; + public function getLanguage(?string $key = null): mixed + { + if (is_null($key)) { + return $this->attributes['language'] ?? []; + } + + return $this->attributes['language'][$key] ?? ''; } } diff --git a/src/Html/Options/Languages/Aria.php b/src/Html/Options/Languages/Aria.php index 0ca389c..a32f936 100644 --- a/src/Html/Options/Languages/Aria.php +++ b/src/Html/Options/Languages/Aria.php @@ -7,112 +7,96 @@ trait Aria /** * Set language aria option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/language.aria */ - public function languageAria(array $value) + public function languageAria(array $value): static { - $this->attributes['language']['aria'] = $value; - - return $this; + return $this->language(['aria' => $value]); } /** * Set language aria paginate option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/language.aria.paginate */ - public function languageAriaPaginate(array $value) + public function languageAriaPaginate(array $value): static { - $this->attributes['language']['aria']['paginate'] = $value; - - return $this; + return $this->languageAria(['paginate' => $value]); } /** * Set language aria paginate first option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.aria.paginate.first */ - public function languageAriaPaginateFirst($value) + public function languageAriaPaginateFirst(string $value): static { - $this->attributes['language']['aria']['paginate']['first'] = $value; - - return $this; + return $this->languageAriaPaginate(['first' => $value]); } /** * Set language aria paginate last option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.aria.paginate.last */ - public function languageAriaPaginateLast($value) + public function languageAriaPaginateLast(string $value): static { - $this->attributes['language']['aria']['paginate']['last'] = $value; - - return $this; + return $this->languageAriaPaginate(['last' => $value]); } /** * Set language aria paginate next option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.aria.paginate.next */ - public function languageAriaPaginateNext($value) + public function languageAriaPaginateNext(string $value): static { - $this->attributes['language']['aria']['paginate']['next'] = $value; - - return $this; + return $this->languageAriaPaginate(['next' => $value]); } /** * Set language aria paginate previous option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.aria.paginate.previous */ - public function languageAriaPaginatePrevious($value) + public function languageAriaPaginatePrevious(string $value): static { - $this->attributes['language']['aria']['paginate']['previous'] = $value; - - return $this; + return $this->languageAriaPaginate(['previous' => $value]); } /** * Set language aria sortAscending option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.aria.sortAscending */ - public function languageAriaSortAscending($value) + public function languageAriaSortAscending(string $value): static { - $this->attributes['language']['aria']['sortAscending'] = $value; - - return $this; + return $this->languageAria(['sortAscending' => $value]); } /** * Set language aria sortDescending option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.aria.sortDescending */ - public function languageAriaSortDescending($value) + public function languageAriaSortDescending(string $value): static { - $this->attributes['language']['aria']['sortDescending'] = $value; - - return $this; + return $this->languageAria(['sortDescending' => $value]); } } diff --git a/src/Html/Options/Languages/AutoFill.php b/src/Html/Options/Languages/AutoFill.php index 5207d9a..9fa96c5 100644 --- a/src/Html/Options/Languages/AutoFill.php +++ b/src/Html/Options/Languages/AutoFill.php @@ -7,112 +7,96 @@ trait AutoFill /** * Set language autoFill option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/language.autoFill */ - public function languageAutoFill(array $value) + public function languageAutoFill(array $value): static { - $this->attributes['language']['autoFill'] = $value; - - return $this; + return $this->language(['autoFill' => $value]); } /** * Set language autoFill button option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.autoFill.button */ - public function languageAutoFillButton($value) + public function languageAutoFillButton(string $value): static { - $this->attributes['language']['autoFill']['button'] = $value; - - return $this; + return $this->languageAutoFill(['button' => $value]); } /** * Set language autoFill cancel option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.autoFill.cancel */ - public function languageAutoFillCancel($value) + public function languageAutoFillCancel(string $value): static { - $this->attributes['language']['autoFill']['cancel'] = $value; - - return $this; + return $this->languageAutoFill(['cancel' => $value]); } /** * Set language autoFill fill option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.autoFill.fill */ - public function languageAutoFillFill($value) + public function languageAutoFillFill(string $value): static { - $this->attributes['language']['autoFill']['fill'] = $value; - - return $this; + return $this->languageAutoFill(['fill' => $value]); } /** * Set language autoFill fillHorizontal option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.autoFill.fillHorizontal */ - public function languageAutoFillFillHorizontal($value) + public function languageAutoFillFillHorizontal(string $value): static { - $this->attributes['language']['autoFill']['fillHorizontal'] = $value; - - return $this; + return $this->languageAutoFill(['fillHorizontal' => $value]); } /** * Set language autoFill fillVertical option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.autoFill.fillVertical */ - public function languageAutoFillFillVertical($value) + public function languageAutoFillFillVertical(string $value): static { - $this->attributes['language']['autoFill']['fillVertical'] = $value; - - return $this; + return $this->languageAutoFill(['fillVertical' => $value]); } /** * Set language autoFill increment option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.autoFill.increment */ - public function languageAutoFillIncrement($value) + public function languageAutoFillIncrement(string $value): static { - $this->attributes['language']['autoFill']['increment'] = $value; - - return $this; + return $this->languageAutoFill(['increment' => $value]); } /** * Set language autoFill info option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.autoFill.info */ - public function languageAutoFillInfo($value) + public function languageAutoFillInfo(string $value): static { - $this->attributes['language']['autoFill']['info'] = $value; - - return $this; + return $this->languageAutoFill(['info' => $value]); } } diff --git a/src/Html/Options/Languages/Paginate.php b/src/Html/Options/Languages/Paginate.php index 46fa9a8..c22d261 100644 --- a/src/Html/Options/Languages/Paginate.php +++ b/src/Html/Options/Languages/Paginate.php @@ -7,70 +7,60 @@ trait Paginate /** * Set language aria paginate option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/language.paginate */ - public function languagePaginate(array $value) + public function languagePaginate(array $value): static { - $this->attributes['language']['paginate'] = $value; - - return $this; + return $this->language(['paginate' => $value]); } /** * Set language aria paginate first option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.paginate.first */ - public function languagePaginateFirst($value) + public function languagePaginateFirst(string $value): static { - $this->attributes['language']['paginate']['first'] = $value; - - return $this; + return $this->languagePaginate(['first' => $value]); } /** * Set language aria paginate last option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.paginate.last */ - public function languagePaginateLast($value) + public function languagePaginateLast(string $value): static { - $this->attributes['language']['paginate']['last'] = $value; - - return $this; + return $this->languagePaginate(['last' => $value]); } /** * Set language aria paginate next option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.paginate.next */ - public function languagePaginateNext($value) + public function languagePaginateNext(string $value): static { - $this->attributes['language']['paginate']['next'] = $value; - - return $this; + return $this->languagePaginate(['next' => $value]); } /** * Set language aria paginate previous option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/language.paginate.previous */ - public function languagePaginatePrevious($value) + public function languagePaginatePrevious(string $value): static { - $this->attributes['language']['paginate']['previous'] = $value; - - return $this; + return $this->languagePaginate(['previous' => $value]); } } diff --git a/src/Html/Options/Languages/Select.php b/src/Html/Options/Languages/Select.php index 910c897..791c019 100644 --- a/src/Html/Options/Languages/Select.php +++ b/src/Html/Options/Languages/Select.php @@ -7,56 +7,48 @@ trait Select /** * Set language select option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/language.select */ - public function languageSelect($value) + public function languageSelect(array $value): static { - $this->attributes['language']['select'] = $value; - - return $this; + return $this->language(['select' => $value]); } /** * Set language select cells option value. * - * @param string|array $value * @return $this + * * @see https://datatables.net/reference/option/language.select.cells */ - public function languageSelectCells($value) + public function languageSelectCells(array|string $value): static { - $this->attributes['language']['select']['cells'] = $value; - - return $this; + return $this->languageSelect(['cells' => $value]); } /** * Set language select columns option value. * - * @param string|array $value * @return $this + * * @see https://datatables.net/reference/option/language.select.columns */ - public function languageSelectColumns($value) + public function languageSelectColumns(array|string $value): static { - $this->attributes['language']['select']['columns'] = $value; - - return $this; + return $this->languageSelect(['columns' => $value]); } /** * Set language select rows option value. * - * @param string|array $value * @return $this + * * @see https://datatables.net/reference/option/language.select.rows */ - public function languageSelectRows($value) + public function languageSelectRows(array|string $value): static { - $this->attributes['language']['select']['rows'] = $value; - - return $this; + return $this->languageSelect(['rows' => $value]); } } diff --git a/src/Html/Options/Plugins/AutoFill.php b/src/Html/Options/Plugins/AutoFill.php index 5e17405..e9ac52b 100644 --- a/src/Html/Options/Plugins/AutoFill.php +++ b/src/Html/Options/Plugins/AutoFill.php @@ -12,129 +12,120 @@ trait AutoFill { /** - * Set autoFill option value. - * Enable and configure the AutoFill extension for DataTables. + * Set autoFill alwaysAsk option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/autoFill + * + * @see https://datatables.net/reference/option/autoFill.alwaysAsk */ - public function autoFill($value = true) + public function autoFillAlwaysAsk(bool $value = true): static { - $this->attributes['autoFill'] = $value; - - return $this; + return $this->autoFill(['alwaysAsk' => $value]); } /** - * Set autoFill alwaysAsk option value. + * Set autoFill option value. + * Enable and configure the AutoFill extension for DataTables. * - * @param bool $value * @return $this - * @see https://datatables.net/reference/option/autoFill.alwaysAsk + * + * @see https://datatables.net/reference/option/autoFill */ - public function autoFillAlwaysAsk(bool $value = true) + public function autoFill(array|bool $value = true): static { - $this->attributes['autoFill']['alwaysAsk'] = $value; - - return $this; + return $this->setPluginAttribute('autoFill', $value); } /** * Set autoFill columns option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/autoFill.columns */ - public function autoFillColumns($value) + public function autoFillColumns(array|string $value): static { - $this->attributes['autoFill']['columns'] = $value; - - return $this; + return $this->autoFill(['columns' => $value]); } /** * Set autoFill editor option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/autoFill.editor */ - public function autoFillEditor($value) + public function autoFillEditor(string $value): static { - $this->attributes['autoFill']['editor'] = $value; - - return $this; + return $this->autoFill(['editor' => $value]); } /** * Set autoFill enable option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/autoFill.enable */ - public function autoFillEnable(bool $value = true) + public function autoFillEnable(bool $value = true): static { - $this->attributes['autoFill']['enable'] = $value; - - return $this; + return $this->autoFill(['enable' => $value]); } /** * Set autoFill focus option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/autoFill.focus */ - public function autoFillFocus($value = null) + public function autoFillFocus(?string $value = null): static { - $this->attributes['autoFill']['focus'] = $value; - - return $this; + return $this->autoFill(['focus' => $value]); } /** * Set autoFill horizontal option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/autoFill.horizontal */ - public function autoFillHorizontal(bool $value = true) + public function autoFillHorizontal(bool $value = true): static { - $this->attributes['autoFill']['horizontal'] = $value; - - return $this; + return $this->autoFill(['horizontal' => $value]); } /** * Set autoFill update option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/autoFill.update */ - public function autoFillUpdate(bool $value = true) + public function autoFillUpdate(bool $value = true): static { - $this->attributes['autoFill']['update'] = $value; - - return $this; + return $this->autoFill(['update' => $value]); } /** * Set autoFill vertical option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/autoFill.vertical */ - public function autoFillVertical(bool $value = true) + public function autoFillVertical(bool $value = true): static + { + return $this->autoFill(['vertical' => $value]); + } + + public function getAutoFill(?string $key = null): mixed { - $this->attributes['autoFill']['vertical'] = $value; + if (is_null($key)) { + return $this->attributes['autoFill'] ?? true; + } - return $this; + return $this->attributes['autoFill'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/Buttons.php b/src/Html/Options/Plugins/Buttons.php index fbced7c..91378f1 100644 --- a/src/Html/Options/Plugins/Buttons.php +++ b/src/Html/Options/Plugins/Buttons.php @@ -3,6 +3,7 @@ namespace Yajra\DataTables\Html\Options\Plugins; use Illuminate\Contracts\Support\Arrayable; +use Yajra\DataTables\Html\Button; /** * DataTables - Buttons plugin option builder. @@ -15,12 +16,15 @@ trait Buttons /** * Attach multiple buttons to builder. * - * @param array|mixed ...$buttons + * @param array|mixed ...$buttons * @return $this + * * @see https://www.datatables.net/extensions/buttons/ */ - public function buttons(...$buttons) + public function buttons(...$buttons): static { + $this->attributes['buttons'] = []; + if (is_array($buttons[0])) { $buttons = $buttons[0]; } @@ -31,4 +35,22 @@ public function buttons(...$buttons) return $this; } + + /** + * @return $this + */ + public function addButton(Button $button): static + { + $this->attributes['buttons'][] = $button->toArray(); + + return $this; + } + + /** + * Get builder buttons. + */ + public function getButtons(): array + { + return $this->attributes['buttons'] ?? []; + } } diff --git a/src/Html/Options/Plugins/ColReorder.php b/src/Html/Options/Plugins/ColReorder.php index fc67f1a..561b980 100644 --- a/src/Html/Options/Plugins/ColReorder.php +++ b/src/Html/Options/Plugins/ColReorder.php @@ -12,87 +12,84 @@ trait ColReorder { /** - * Set colReorder option value. - * Enable and configure the AutoFill extension for DataTables. + * Set colReorder enable option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/colReorder + * + * @see https://datatables.net/reference/option/colReorder.enable */ - public function colReorder($value = true) + public function colReorderEnable(bool $value = true): static { - $this->attributes['colReorder'] = $value; - - return $this; + return $this->colReorder(['enable' => $value]); } /** - * Set colReorder enable option value. + * Set colReorder option value. + * Enable and configure the AutoFill extension for DataTables. * - * @param bool $value * @return $this - * @see https://datatables.net/reference/option/colReorder.enable + * + * @see https://datatables.net/reference/option/colReorder */ - public function colReorderEnable(bool $value = true) + public function colReorder(array|bool $value = true): static { - $this->attributes['colReorder']['enable'] = $value; - - return $this; + return $this->setPluginAttribute('colReorder', $value); } /** * Set colReorder fixedColumnsLeft option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/colReorder.fixedColumnsLeft */ - public function colReorderFixedColumnsLeft(int $value = 0) + public function colReorderFixedColumnsLeft(int $value = 0): static { - $this->attributes['colReorder']['fixedColumnsLeft'] = $value; - - return $this; + return $this->colReorder(['fixedColumnsLeft' => $value]); } /** * Set colReorder fixedColumnsRight option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/colReorder.fixedColumnsRight */ - public function colReorderFixedColumnsRight(int $value = 0) + public function colReorderFixedColumnsRight(int $value = 0): static { - $this->attributes['colReorder']['fixedColumnsRight'] = $value; - - return $this; + return $this->colReorder(['fixedColumnsRight' => $value]); } /** * Set colReorder order option value. * - * @param array $value * @return $this + * * @see https://datatables.net/reference/option/colReorder.order */ - public function colReorderOrder(array $value = []) + public function colReorderOrder(array $value = []): static { - $this->attributes['colReorder']['order'] = $value; - - return $this; + return $this->colReorder(['order' => $value]); } /** * Set colReorder realtime option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/colReorder.realtime */ - public function colReorderRealtime(bool $value = true) + public function colReorderRealtime(bool $value = true): static + { + return $this->colReorder(['realtime' => $value]); + } + + public function getColReorder(?string $key = null): mixed { - $this->attributes['colReorder']['realtime'] = $value; + if (is_null($key)) { + return $this->attributes['colReorder'] ?? true; + } - return $this; + return $this->attributes['colReorder'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/FixedColumns.php b/src/Html/Options/Plugins/FixedColumns.php index d63e607..5926f58 100644 --- a/src/Html/Options/Plugins/FixedColumns.php +++ b/src/Html/Options/Plugins/FixedColumns.php @@ -12,58 +12,59 @@ trait FixedColumns { /** - * Set fixedColumns option value. + * Set fixedColumns heightMatch option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/fixedColumns + * + * @see https://datatables.net/reference/option/fixedColumns.heightMatch */ - public function fixedColumns($value = true) + public function fixedColumnsHeightMatch(string $value = 'semiauto'): static { - $this->attributes['fixedColumns'] = $value; - - return $this; + return $this->fixedColumns(['heightMatch' => $value]); } /** - * Set fixedColumns heightMatch option value. + * Set fixedColumns option value. * - * @param string $value * @return $this - * @see https://datatables.net/reference/option/fixedColumns.heightMatch + * + * @see https://datatables.net/reference/option/fixedColumns */ - public function fixedColumnsHeightMatch($value = 'semiauto') + public function fixedColumns(array|bool $value = true): static { - $this->attributes['fixedColumns']['heightMatch'] = $value; - - return $this; + return $this->setPluginAttribute('fixedColumns', $value); } /** * Set fixedColumns leftColumns option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/fixedColumns.leftColumns */ - public function fixedColumnsLeftColumns(int $value = 1) + public function fixedColumnsLeftColumns(int $value = 1): static { - $this->attributes['fixedColumns']['leftColumns'] = $value; - - return $this; + return $this->fixedColumns(['leftColumns' => $value]); } /** * Set fixedColumns rightColumns option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/fixedColumns.rightColumns */ - public function fixedColumnsRightColumns(int $value = 0) + public function fixedColumnsRightColumns(int $value = 0): static + { + return $this->fixedColumns(['rightColumns' => $value]); + } + + public function getFixedColumns(?string $key = null): mixed { - $this->attributes['fixedColumns']['rightColumns'] = $value; + if (is_null($key)) { + return $this->attributes['fixedColumns'] ?? true; + } - return $this; + return $this->attributes['fixedColumns'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/FixedHeader.php b/src/Html/Options/Plugins/FixedHeader.php index 2a34429..54b5301 100644 --- a/src/Html/Options/Plugins/FixedHeader.php +++ b/src/Html/Options/Plugins/FixedHeader.php @@ -12,72 +12,71 @@ trait FixedHeader { /** - * Set fixedHeader option value. + * Set fixedHeader footer option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/fixedHeader + * + * @see https://datatables.net/reference/option/fixedHeader.footer */ - public function fixedHeader($value = true) + public function fixedHeaderFooter(bool $value = true): static { - $this->attributes['fixedHeader'] = $value; - - return $this; + return $this->fixedHeader(['footer' => $value]); } /** - * Set fixedHeader footer option value. + * Set fixedHeader option value. * - * @param bool $value * @return $this - * @see https://datatables.net/reference/option/fixedHeader.footer + * + * @see https://datatables.net/reference/option/fixedHeader */ - public function fixedHeaderFooter(bool $value = true) + public function fixedHeader(array|bool $value = true): static { - $this->attributes['fixedHeader']['footer'] = $value; - - return $this; + return $this->setPluginAttribute('fixedHeader', $value); } /** * Set fixedHeader footerOffset option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/fixedHeader.footerOffset */ - public function fixedHeaderFooterOffset(int $value = 0) + public function fixedHeaderFooterOffset(int $value = 0): static { - $this->attributes['fixedHeader']['footerOffset'] = $value; - - return $this; + return $this->fixedHeader(['footerOffset' => $value]); } /** * Set fixedHeader header option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/fixedHeader.header */ - public function fixedHeaderHeader(bool $value = true) + public function fixedHeaderHeader(bool $value = true): static { - $this->attributes['fixedHeader']['header'] = $value; - - return $this; + return $this->fixedHeader(['header' => $value]); } /** * Set fixedHeader headerOffset option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/fixedHeader.headerOffset */ - public function fixedHeaderHeaderOffset(int $value = 0) + public function fixedHeaderHeaderOffset(int $value = 0): static + { + return $this->fixedHeader(['headerOffset' => $value]); + } + + public function getFixedHeader(?string $key = null): mixed { - $this->attributes['fixedHeader']['headerOffset'] = $value; + if (is_null($key)) { + return $this->attributes['fixedHeader'] ?? true; + } - return $this; + return $this->attributes['fixedHeader'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/KeyTable.php b/src/Html/Options/Plugins/KeyTable.php index 4b84e09..b34f048 100644 --- a/src/Html/Options/Plugins/KeyTable.php +++ b/src/Html/Options/Plugins/KeyTable.php @@ -12,184 +12,167 @@ trait KeyTable { /** - * Set keys option value. + * Set keys blurable option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/keys + * + * @see https://datatables.net/reference/option/keys.blurable */ - public function keys($value = true) + public function keysBlurable(bool $value = true): static { - $this->attributes['keys'] = $value; - - return $this; + return $this->keys(['blurable' => $value]); } /** - * Set keys blurable option value. + * Set keys option value. * - * @param bool $value * @return $this - * @see https://datatables.net/reference/option/keys.blurable + * + * @see https://datatables.net/reference/option/keys */ - public function keysBlurable(bool $value = true) + public function keys(array|bool $value = true): static { - $this->attributes['keys']['blurable'] = $value; - - return $this; + return $this->setPluginAttribute('keys', $value); } /** * Set keys className option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/keys.className */ - public function keysClassName($value = 'focus') + public function keysClassName(string $value = 'focus'): static { - $this->attributes['keys']['className'] = $value; - - return $this; + return $this->keys(['className' => $value]); } /** * Set keys clipboard option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/keys.clipboard */ - public function keysClipboard(bool $value = true) + public function keysClipboard(bool $value = true): static { - $this->attributes['keys']['clipboard'] = $value; - - return $this; + return $this->keys(['clipboard' => $value]); } /** * Set keys clipboardOrthogonal option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/keys.clipboardOrthogonal */ - public function keysClipboardOrthogonal($value = 'display') + public function keysClipboardOrthogonal(string $value = 'display'): static { - $this->attributes['keys']['clipboardOrthogonal'] = $value; - - return $this; + return $this->keys(['clipboardOrthogonal' => $value]); } /** * Set keys columns option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/keys.columns */ - public function keysColumns($value) + public function keysColumns(array|string $value): static { - $this->attributes['keys']['columns'] = $value; - - return $this; + return $this->keys(['columns' => $value]); } /** * Set keys editAutoSelect option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/keys.editAutoSelect */ - public function keysEditAutoSelect(bool $value = true) + public function keysEditAutoSelect(bool $value = true): static { - $this->attributes['keys']['editAutoSelect'] = $value; - - return $this; + return $this->keys(['editAutoSelect' => $value]); } /** * Set keys editOnFocus option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/keys.editOnFocus */ - public function keysEditOnFocus(bool $value = true) + public function keysEditOnFocus(bool $value = true): static { - $this->attributes['keys']['editOnFocus'] = $value; - - return $this; + return $this->keys(['editOnFocus' => $value]); } /** * Set keys editor option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/keys.editor */ - public function keysEditor($value) + public function keysEditor(string $value): static { - $this->attributes['keys']['editor'] = $value; - - return $this; + return $this->keys(['editor' => $value]); } /** * Set keys editorKeys option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/keys.editorKeys */ - public function keysEditorKeys($value = 'navigation-only') + public function keysEditorKeys(string $value = 'navigation-only'): static { - $this->attributes['keys']['editorKeys'] = $value; - - return $this; + return $this->keys(['editorKeys' => $value]); } /** * Set keys focus option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/keys.focus */ - public function keysFocus($value) + public function keysFocus(string $value): static { - $this->attributes['keys']['focus'] = $value; - - return $this; + return $this->keys(['focus' => $value]); } /** - * Set keys keys option value. + * Set key's keys option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/keys.keys */ - public function keysKeys($value) + public function keysKeys(?array $value = null): static { - $this->attributes['keys']['keys'] = $value; - - return $this; + return $this->keys(['keys' => $value]); } /** * Set keys tabIndex option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/keys.tabIndex */ - public function keysTabIndex($value) + public function keysTabIndex(int $value): static + { + return $this->keys(['tabIndex' => $value]); + } + + public function getKeys(?string $key = null): mixed { - $this->attributes['keys']['tabIndex'] = $value; + if (is_null($key)) { + return $this->attributes['keys'] ?? true; + } - return $this; + return $this->attributes['keys'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/Responsive.php b/src/Html/Options/Plugins/Responsive.php index afd678d..d5fd11a 100644 --- a/src/Html/Options/Plugins/Responsive.php +++ b/src/Html/Options/Plugins/Responsive.php @@ -12,114 +12,114 @@ trait Responsive { /** - * Set responsive option value. + * Set responsive breakpoints option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/responsive + * + * @see https://datatables.net/reference/option/responsive.breakpoints */ - public function responsive($value = true) + public function responsiveBreakpoints(array $value): static { - $this->attributes['responsive'] = $value; - - return $this; + return $this->responsive(['breakpoints' => $value]); } /** - * Set responsive breakpoints option value. + * Set responsive option value. * - * @param mixed $value * @return $this - * @see https://datatables.net/reference/option/responsive.breakpoints + * + * @see https://datatables.net/reference/option/responsive */ - public function responsiveBreakpoints($value) + public function responsive(array|bool $value = true): static { - $this->attributes['responsive']['breakpoints'] = $value; - - return $this; + return $this->setPluginAttribute('responsive', $value); } /** - * Set responsive details option value. + * Set responsive details display option value. * - * @param mixed $value * @return $this - * @see https://datatables.net/reference/option/responsive.details + * + * @see https://datatables.net/reference/option/responsive.details.display */ - public function responsiveDetails($value) + public function responsiveDetailsDisplay(array|string $value): static { - $this->attributes['responsive']['details'] = $value; - - return $this; + return $this->responsiveDetails(['display' => $value]); } /** - * Set responsive details display option value. + * Set responsive details option value. * - * @param mixed $value * @return $this - * @see https://datatables.net/reference/option/responsive.details.display + * + * @see https://datatables.net/reference/option/responsive.details */ - public function responsiveDetailsDisplay($value) + public function responsiveDetails(bool|array $value): static { - $this->attributes['responsive']['details']['display'] = $value; - - return $this; + $responsive = (array) $this->getResponsive(); + if (is_array($value)) { + $responsive['details'] = array_merge((array) ($responsive['details'] ?? []), $value); + } else { + $responsive['details'] = $value; + } + + return $this->responsive($responsive); } /** * Set responsive details renderer option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/responsive.details.renderer */ - public function responsiveDetailsRenderer($value) + public function responsiveDetailsRenderer(string $value): static { - $this->attributes['responsive']['details']['renderer'] = $value; - - return $this; + return $this->responsiveDetails(['renderer' => $value]); } /** * Set responsive details target option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/responsive.details.target */ - public function responsiveDetailsTarget($value) + public function responsiveDetailsTarget(int|string $value): static { - $this->attributes['responsive']['details']['target'] = $value; - - return $this; + return $this->responsiveDetails(['target' => $value]); } /** * Set responsive details type option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/responsive.details.type */ - public function responsiveDetailsType($value) + public function responsiveDetailsType(string $value): static { - $this->attributes['responsive']['details']['type'] = $value; - - return $this; + return $this->responsiveDetails(['type' => $value]); } /** * Set responsive orthogonal option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/responsive.orthogonal */ - public function responsiveOrthogonal($value) + public function responsiveOrthogonal(string $value): static + { + return $this->responsive(['orthogonal' => $value]); + } + + public function getResponsive(?string $key = null): mixed { - $this->attributes['responsive']['orthogonal'] = $value; + if (is_null($key)) { + return $this->attributes['responsive'] ?? true; + } - return $this; + return $this->attributes['responsive'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/RowGroup.php b/src/Html/Options/Plugins/RowGroup.php index 2d41e51..cca6da3 100644 --- a/src/Html/Options/Plugins/RowGroup.php +++ b/src/Html/Options/Plugins/RowGroup.php @@ -12,128 +12,119 @@ trait RowGroup { /** - * Set rowGroup option value. + * Set rowGroup className option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/rowGroup + * + * @see https://datatables.net/reference/option/rowGroup.className */ - public function rowGroup($value = true) + public function rowGroupUpdate(string $value = 'group'): static { - $this->attributes['rowGroup'] = $value; - - return $this; + return $this->rowGroup(['className' => $value]); } /** - * Set rowGroup className option value. + * Set rowGroup option value. * - * @param string $value * @return $this - * @see https://datatables.net/reference/option/rowGroup.className + * + * @see https://datatables.net/reference/option/rowGroup */ - public function rowGroupUpdate($value = 'group') + public function rowGroup(array|bool $value = true): static { - $this->attributes['rowGroup']['className'] = $value; - - return $this; + return $this->setPluginAttribute('rowGroup', $value); } /** * Set rowGroup dataSrc option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowGroup.dataSrc */ - public function rowGroupDataSrc($value = 0) + public function rowGroupDataSrc(array|int|string $value = 0): static { - $this->attributes['rowGroup']['dataSrc'] = $value; - - return $this; + return $this->rowGroup(['dataSrc' => $value]); } /** * Set rowGroup emptyDataGroup option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowGroup.emptyDataGroup */ - public function rowGroupEmptyDataGroup($value = 'No Group') + public function rowGroupEmptyDataGroup(string $value = 'No Group'): static { - $this->attributes['rowGroup']['emptyDataGroup'] = $value; - - return $this; + return $this->rowGroup(['emptyDataGroup' => $value]); } /** * Set rowGroup enable option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/rowGroup.enable */ - public function rowGroupEnable(bool $value = true) + public function rowGroupEnable(bool $value = true): static { - $this->attributes['rowGroup']['enable'] = $value; - - return $this; + return $this->rowGroup(['enable' => $value]); } /** * Set rowGroup endClassName option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowGroup.endClassName */ - public function rowGroupEndClassName($value = 'group-end') + public function rowGroupEndClassName(string $value = 'group-end'): static { - $this->attributes['rowGroup']['endClassName'] = $value; - - return $this; + return $this->rowGroup(['endClassName' => $value]); } /** * Set rowGroup endRender option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowGroup.endRender */ - public function rowGroupEndRender($value) + public function rowGroupEndRender(string $value): static { - $this->attributes['rowGroup']['endRender'] = $value; - - return $this; + return $this->rowGroup(['endRender' => $value]); } /** * Set rowGroup startClassName option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowGroup.startClassName */ - public function rowGroupStartClassName($value = 'group-start') + public function rowGroupStartClassName(string $value = 'group-start'): static { - $this->attributes['rowGroup']['startClassName'] = $value; - - return $this; + return $this->rowGroup(['startClassName' => $value]); } /** * Set rowGroup startRender option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowGroup.startRender */ - public function rowGroupStartRender($value) + public function rowGroupStartRender(?string $value = null): static + { + return $this->rowGroup(['startRender' => $value]); + } + + public function getRowGroup(?string $key = null): mixed { - $this->attributes['rowGroup']['startRender'] = $value; + if (is_null($key)) { + return $this->attributes['rowGroup'] ?? true; + } - return $this; + return $this->attributes['rowGroup'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/RowReorder.php b/src/Html/Options/Plugins/RowReorder.php index d4050a6..262533c 100644 --- a/src/Html/Options/Plugins/RowReorder.php +++ b/src/Html/Options/Plugins/RowReorder.php @@ -12,114 +12,107 @@ trait RowReorder { /** - * Set rowReorder option value. + * Set rowReorder dataSrc option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/rowReorder + * + * @see https://datatables.net/reference/option/rowReorder.dataSrc */ - public function rowReorder($value = true) + public function rowReorderDataSrc(array|int $value = 0): static { - $this->attributes['rowReorder'] = $value; - - return $this; + return $this->rowReorder(['dataSrc' => $value]); } /** - * Set rowReorder dataSrc option value. + * Set rowReorder option value. * - * @param mixed $value * @return $this - * @see https://datatables.net/reference/option/rowReorder.dataSrc + * + * @see https://datatables.net/reference/option/rowReorder */ - public function rowReorderDataSrc($value = 0) + public function rowReorder(array|bool $value = true): static { - $this->attributes['rowReorder']['dataSrc'] = $value; - - return $this; + return $this->setPluginAttribute('rowReorder', $value); } /** * Set rowReorder editor option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowReorder.editor */ - public function rowReorderEditor($value = null) + public function rowReorderEditor(?string $value = null): static { - $this->attributes['rowReorder']['editor'] = $value; - - return $this; + return $this->rowReorder(['editor' => $value]); } /** * Set rowReorder enable option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/rowReorder.enable */ - public function rowReorderEnable(bool $value = true) + public function rowReorderEnable(bool $value = true): static { - $this->attributes['rowReorder']['enable'] = $value; - - return $this; + return $this->rowReorder(['enable' => $value]); } /** * Set rowReorder formOptions option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowReorder.formOptions */ - public function rowReorderFormOptions($value) + public function rowReorderFormOptions(array $value): static { - $this->attributes['rowReorder']['formOptions'] = $value; - - return $this; + return $this->rowReorder(['formOptions' => $value]); } /** * Set rowReorder selector option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/rowReorder.selector */ - public function rowReorderSelector($value = 'td:first-child') + public function rowReorderSelector(string $value = 'td:first-child'): static { - $this->attributes['rowReorder']['selector'] = $value; - - return $this; + return $this->rowReorder(['selector' => $value]); } /** * Set rowReorder snapX option value. * - * @param mixed $value * @return $this + * * @see https://datatables.net/reference/option/rowReorder.snapX */ - public function rowReorderSnapX($value = true) + public function rowReorderSnapX(bool|int $value = true): static { - $this->attributes['rowReorder']['snapX'] = $value; - - return $this; + return $this->rowReorder(['snapX' => $value]); } /** * Set rowReorder update option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/rowReorder.update */ - public function rowReorderUpdate(bool $value = true) + public function rowReorderUpdate(bool $value = true): static + { + return $this->rowReorder(['update' => $value]); + } + + public function getRowReorder(?string $key = null): mixed { - $this->attributes['rowReorder']['update'] = $value; + if (is_null($key)) { + return $this->attributes['rowReorder'] ?? true; + } - return $this; + return $this->attributes['rowReorder'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/Scroller.php b/src/Html/Options/Plugins/Scroller.php index 37b4ce3..96d23bf 100644 --- a/src/Html/Options/Plugins/Scroller.php +++ b/src/Html/Options/Plugins/Scroller.php @@ -12,86 +12,83 @@ trait Scroller { /** - * Set scroller option value. + * Set scroller boundaryScale option value. * - * @param bool|array $value * @return $this - * @see https://datatables.net/reference/option/scroller + * + * @see https://datatables.net/reference/option/scroller.boundaryScale */ - public function scroller($value = true) + public function scrollerBoundaryScale(float $value = 0.5): static { - $this->attributes['scroller'] = $value; - - return $this; + return $this->scroller(['boundaryScale' => $value]); } /** - * Set scroller boundaryScale option value. + * Set scroller option value. * - * @param float $value * @return $this - * @see https://datatables.net/reference/option/scroller.boundaryScale + * + * @see https://datatables.net/reference/option/scroller */ - public function scrollerBoundaryScale($value = 0.5) + public function scroller(array|bool $value = true): static { - $this->attributes['scroller']['boundaryScale'] = $value; - - return $this; + return $this->setPluginAttribute('scroller', $value); } /** * Set scroller displayBuffer option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/scroller.displayBuffer */ - public function scrollerDisplayBuffer($value = 9) + public function scrollerDisplayBuffer(int $value = 9): static { - $this->attributes['scroller']['displayBuffer'] = $value; - - return $this; + return $this->scroller(['displayBuffer' => $value]); } /** * Set scroller loadingIndicator option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/scroller.loadingIndicator */ - public function scrollerLoadingIndicator(bool $value = true) + public function scrollerLoadingIndicator(bool $value = true): static { - $this->attributes['scroller']['loadingIndicator'] = $value; - - return $this; + return $this->scroller(['loadingIndicator' => $value]); } /** * Set scroller rowHeight option value. * - * @param int|string $value * @return $this + * * @see https://datatables.net/reference/option/scroller.rowHeight */ - public function scrollerRowHeight($value = 'auto') + public function scrollerRowHeight(int|string $value = 'auto'): static { - $this->attributes['scroller']['rowHeight'] = $value; - - return $this; + return $this->scroller(['rowHeight' => $value]); } /** * Set scroller serverWait option value. * - * @param int $value * @return $this + * * @see https://datatables.net/reference/option/scroller.serverWait */ - public function scrollerServerWait($value = 200) + public function scrollerServerWait(int $value = 200): static + { + return $this->scroller(['serverWait' => $value]); + } + + public function getScroller(?string $key = null): mixed { - $this->attributes['scroller']['serverWait'] = $value; + if (is_null($key)) { + return $this->attributes['scroller'] ?? true; + } - return $this; + return $this->attributes['scroller'][$key] ?? false; } } diff --git a/src/Html/Options/Plugins/SearchPanes.php b/src/Html/Options/Plugins/SearchPanes.php index 5b966c3..5bd95cb 100644 --- a/src/Html/Options/Plugins/SearchPanes.php +++ b/src/Html/Options/Plugins/SearchPanes.php @@ -2,8 +2,8 @@ namespace Yajra\DataTables\Html\Options\Plugins; -use Yajra\DataTables\Html\SearchPane; use Illuminate\Contracts\Support\Arrayable; +use Yajra\DataTables\Html\SearchPane; /** * DataTables - Search panes plugin option builder. @@ -16,11 +16,11 @@ trait SearchPanes /** * Set searchPane option value. * - * @param bool|array $value * @return $this + * * @see https://datatables.net/reference/option/searchPanes */ - public function searchPanes($value = true) + public function searchPanes(array|Arrayable|bool|callable $value = true): static { if (is_callable($value)) { $value = app()->call($value); @@ -38,4 +38,13 @@ public function searchPanes($value = true) return $this; } + + public function getSearchPanes(?string $key = null): mixed + { + if (is_null($key)) { + return $this->attributes['searchPanes'] ?? true; + } + + return $this->attributes['searchPanes'][$key] ?? false; + } } diff --git a/src/Html/Options/Plugins/Select.php b/src/Html/Options/Plugins/Select.php index ac971c8..056d8e6 100644 --- a/src/Html/Options/Plugins/Select.php +++ b/src/Html/Options/Plugins/Select.php @@ -12,221 +12,220 @@ */ trait Select { - /** - * Set select option value. - * - * @param bool|array $value - * @return $this - * @see https://datatables.net/reference/option/select - */ - public function select($value = true) - { - $this->attributes['select'] = $value; - - return $this; - } - /** * Set select blurable option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/select.blurable */ - public function selectBlurable(bool $value = true) + public function selectBlurable(bool $value = true): static { - $this->attributes['select']['blurable'] = $value; - - return $this; + return $this->select(['blurable' => $value]); } /** * Set select className option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/select.className */ - public function selectClassName($value = 'selected') + public function selectClassName(string $value = 'selected'): static { - $this->attributes['select']['className'] = $value; - - return $this; + return $this->select(['className' => $value]); } /** * Append a class name to className option value. * - * @param string $class * @return $this */ - public function selectAddClassName($class) + public function selectAddClassName(string $class): static { if (! isset($this->attributes['select']['className'])) { $this->attributes['select']['className'] = $class; } else { $this->attributes['select']['className'] .= " $class"; } + return $this; } /** * Set select info option value. * - * @param bool $value * @return $this + * * @see https://datatables.net/reference/option/select.info */ - public function selectInfo(bool $value = true) + public function selectInfo(bool $value = true): static { - $this->attributes['select']['info'] = $value; - - return $this; + return $this->select(['info' => $value]); } /** * Set select items option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/select.items */ - public function selectItems($value = 'row') + public function selectItems(string $value = 'row'): static { - $this->attributes['select']['items'] = $value; - - return $this; + return $this->select(['items' => $value]); } /** * Set select items option value to row. * * @return $this + * * @see https://datatables.net/reference/option/select.items */ - public function selectItemsRow() + public function selectItemsRow(): static { - $this->attributes['select']['items'] = Builder::SELECT_ITEMS_ROW; - - return $this; + return $this->select(['items' => Builder::SELECT_ITEMS_ROW]); } /** * Set select items option value to column. * * @return $this + * * @see https://datatables.net/reference/option/select.items */ - public function selectItemsColumn() + public function selectItemsColumn(): static { - $this->attributes['select']['items'] = Builder::SELECT_ITEMS_COLUMN; - - return $this; + return $this->select(['items' => Builder::SELECT_ITEMS_COLUMN]); } /** * Set select items option value to cell. * * @return $this + * * @see https://datatables.net/reference/option/select.items */ - public function selectItemsCell() + public function selectItemsCell(): static { - $this->attributes['select']['items'] = Builder::SELECT_ITEMS_CELL; - - return $this; + return $this->select(['items' => Builder::SELECT_ITEMS_CELL]); } /** * Set select selector option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/select.selector */ - public function selectSelector($value = 'td') + public function selectSelector(string $value = 'td'): static { - $this->attributes['select']['selector'] = $value; - - return $this; + return $this->select(['selector' => $value]); } /** * Set select style option value. * - * @param string $value * @return $this + * * @see https://datatables.net/reference/option/select.style */ - public function selectStyle($value = 'os') + public function selectStyle(string $value = 'os'): static { - $this->attributes['select']['style'] = $value; - - return $this; + return $this->select(['style' => $value]); } /** * Set select style option value to api. * * @return $this + * * @see https://datatables.net/reference/option/select.style */ - public function selectStyleApi() + public function selectStyleApi(): static { - $this->attributes['select']['style'] = Builder::SELECT_STYLE_API; - - return $this; + return $this->select(['style' => Builder::SELECT_STYLE_API]); } /** * Set select style option value to single. * * @return $this + * * @see https://datatables.net/reference/option/select.style */ - public function selectStyleSingle() + public function selectStyleSingle(): static { - $this->attributes['select']['style'] = Builder::SELECT_STYLE_SINGLE; + return $this->select(['style' => Builder::SELECT_STYLE_SINGLE]); + } - return $this; + /** + * Set select option value. + * + * @return $this + * + * @see https://datatables.net/reference/option/select + */ + public function select(bool|array $value = true): static + { + return $this->setPluginAttribute('select', $value); } /** * Set select style option value to multi. * * @return $this + * * @see https://datatables.net/reference/option/select.style */ - public function selectStyleMulti() + public function selectStyleMulti(): static { - $this->attributes['select']['style'] = Builder::SELECT_STYLE_MULTI; - - return $this; + return $this->select(['style' => Builder::SELECT_STYLE_MULTI]); } /** * Set select style option value to os. * * @return $this + * * @see https://datatables.net/reference/option/select.style */ - public function selectStyleOS() + public function selectStyleOS(): static { - $this->attributes['select']['style'] = Builder::SELECT_STYLE_OS; - - return $this; + return $this->select(['style' => Builder::SELECT_STYLE_OS]); } /** * Set select style option value to multi+shift. * * @return $this + * * @see https://datatables.net/reference/option/select.style */ - public function selectStyleMultiShift() + public function selectStyleMultiShift(): static { - $this->attributes['select']['style'] = Builder::SELECT_STYLE_MULTI_SHIFT; + return $this->select(['style' => Builder::SELECT_STYLE_MULTI_SHIFT]); + } - return $this; + /** + * Select keyboard navigation and selection. + * + * @return $this + * + * @see https://datatables.net/extensions/select/examples/initialisation/keys + */ + public function selectKeys(bool $enabled = true): static + { + return $this->select(['keys' => $enabled]); + } + + public function getSelect(?string $key = null): mixed + { + if (is_null($key)) { + return $this->attributes['select'] ?? true; + } + + return $this->attributes['select'][$key] ?? false; } } diff --git a/src/Html/Parameters.php b/src/Html/Parameters.php index ca93fba..4d3faee 100644 --- a/src/Html/Parameters.php +++ b/src/Html/Parameters.php @@ -2,18 +2,10 @@ namespace Yajra\DataTables\Html; -use Illuminate\Support\Fluent; - -/** - * @property bool serverSide - * @property bool processing - * @property mixed ajax - * @property array columns - */ class Parameters extends Fluent { /** - * @var array + * @var array */ protected $attributes = [ 'serverSide' => true, diff --git a/src/Html/SearchPane.php b/src/Html/SearchPane.php index 7b2a0bc..da90b11 100644 --- a/src/Html/SearchPane.php +++ b/src/Html/SearchPane.php @@ -2,27 +2,29 @@ namespace Yajra\DataTables\Html; -use Illuminate\Support\Fluent; +use Closure; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Yajra\DataTables\Html\Editor\Fields\Options; class SearchPane extends Fluent { - /** - * @param array $options - * @return static - */ - public static function make(array $options = []) + public function __construct($attributes = []) + { + parent::__construct(['show' => true] + $attributes); + } + + public static function make(array $options = []): static { return new static($options); } /** - * @param bool $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.cascadePanes */ - public function cascadePanes($value = true) + public function cascadePanes(bool $value = true): static { $this->attributes['cascadePanes'] = $value; @@ -30,11 +32,11 @@ public function cascadePanes($value = true) } /** - * @param bool $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.clear */ - public function clear($value = true) + public function clear(bool $value = true): static { $this->attributes['clear'] = $value; @@ -42,11 +44,11 @@ public function clear($value = true) } /** - * @param array $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.columns */ - public function columns(array $value = []) + public function columns(array $value = []): static { $this->attributes['columns'] = $value; @@ -54,11 +56,11 @@ public function columns(array $value = []) } /** - * @param bool $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.controls */ - public function controls($value = true) + public function controls(bool $value = true): static { $this->attributes['controls'] = $value; @@ -66,12 +68,12 @@ public function controls($value = true) } /** - * @param array $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.dtOpts * @see https://datatables.net/reference/option/columns.searchPanes.dtOpts */ - public function dtOpts(array $value = []) + public function dtOpts(array $value = []): static { $this->attributes['dtOpts'] = $value; @@ -79,11 +81,11 @@ public function dtOpts(array $value = []) } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.emptyMessage */ - public function emptyMessage($value) + public function emptyMessage(string $value): static { $this->attributes['emptyMessage'] = $value; @@ -91,11 +93,11 @@ public function emptyMessage($value) } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.filterChanged */ - public function filterChanged($value) + public function filterChanged(string $value): static { $this->attributes['filterChanged'] = $value; @@ -103,11 +105,11 @@ public function filterChanged($value) } /** - * @param bool $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.hideCount */ - public function hideCount($value = true) + public function hideCount(bool $value = true): static { $this->attributes['hideCount'] = $value; @@ -115,11 +117,11 @@ public function hideCount($value = true) } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.layout */ - public function layout($value) + public function layout(string $value): static { $this->attributes['layout'] = $value; @@ -127,11 +129,11 @@ public function layout($value) } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.order */ - public function order($value) + public function order(array $value): static { $this->attributes['order'] = $value; @@ -139,11 +141,11 @@ public function order($value) } /** - * @param boolean $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.orderable */ - public function orderable($value = true) + public function orderable(bool $value = true): static { $this->attributes['orderable'] = $value; @@ -151,11 +153,11 @@ public function orderable($value = true) } /** - * @param array $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.panes */ - public function panes(array $value) + public function panes(array $value): static { $panes = collect($value)->map(function ($pane) { if ($pane instanceof Arrayable) { @@ -171,11 +173,11 @@ public function panes(array $value) } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.threshold */ - public function threshold($value) + public function threshold(float $value): static { $this->attributes['threshold'] = $value; @@ -183,11 +185,11 @@ public function threshold($value) } /** - * @param boolean $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.viewTotal */ - public function viewTotal($value = true) + public function viewTotal(bool $value = true): static { $this->attributes['viewTotal'] = $value; @@ -195,11 +197,11 @@ public function viewTotal($value = true) } /** - * @param boolean $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.viewTotal */ - public function hideTotal($value = true) + public function hideTotal(bool $value = true): static { $this->attributes['viewTotal'] = ! $value; @@ -209,24 +211,19 @@ public function hideTotal($value = true) /** * Get options from a model. * - * @param mixed $model - * @param string $value - * @param string $key - * @return $this + * @param class-string<\Illuminate\Database\Eloquent\Model>|EloquentBuilder $model */ - public function modelOptions($model, $value, $key = 'id') + public function modelOptions(EloquentBuilder|string $model, string $value, string $key = 'id'): SearchPane { - return $this->options( - Options::model($model, $value, $key) - ); + return $this->options(Options::model($model, $value, $key)); } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/columns.searchPanes.options */ - public function options($value) + public function options(array|Arrayable $value): static { if ($value instanceof Arrayable) { $value = $value->toArray(); @@ -240,26 +237,24 @@ public function options($value) /** * Get options from a table. * - * @param mixed $table - * @param string $value - * @param string $key - * @param \Closure $whereCallback - * @param string|null $key * @return $this */ - public function tableOptions($table, $value, $key = 'id', \Closure $whereCallback = null, $connection = null) - { - return $this->options( - Options::table($table, $value, $key, $whereCallback, $connection) - ); + public function tableOptions( + string $table, + string $value, + string $key = 'id', + ?Closure $callback = null, + ?string $connection = null + ): static { + return $this->options(Options::table($table, $value, $key, $callback, $connection)); } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/columns.searchPanes.className */ - public function className($value) + public function className(string $value): static { $this->attributes['className'] = $value; @@ -267,11 +262,11 @@ public function className($value) } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/searchPanes.panes.header */ - public function header($value) + public function header(string $value): static { $this->attributes['header'] = $value; @@ -279,11 +274,11 @@ public function header($value) } /** - * @param bool $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/columns.searchPanes.show */ - public function show($value = true) + public function show(bool $value = true): static { $this->attributes['show'] = $value; @@ -291,11 +286,11 @@ public function show($value = true) } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/columns.searchPanes.name */ - public function name($value) + public function name(string $value): static { $this->attributes['name'] = $value; @@ -303,14 +298,38 @@ public function name($value) } /** - * @param mixed $value - * @return static + * @return $this + * * @see https://datatables.net/reference/option/columns.searchPanes.orthogonal */ - public function orthogonal($value) + public function orthogonal(array|string $value): static { $this->attributes['orthogonal'] = $value; return $this; } + + /** + * @return $this + * + * @see https://datatables.net/reference/option/searchPanes.collapse + */ + public function collapse(bool $value = true): static + { + $this->attributes['collapse'] = $value; + + return $this; + } + + /** + * @return $this + * + * @see https://datatables.net/reference/option/searchPanes.initCollapsed + */ + public function initCollapsed(bool $value = false): static + { + $this->attributes['initCollapsed'] = $value; + + return $this; + } } diff --git a/src/HtmlServiceProvider.php b/src/HtmlServiceProvider.php index 343278b..b0de459 100644 --- a/src/HtmlServiceProvider.php +++ b/src/HtmlServiceProvider.php @@ -3,18 +3,15 @@ namespace Yajra\DataTables; use Illuminate\Support\ServiceProvider; -use Collective\Html\HtmlServiceProvider as CollectiveHtml; class HtmlServiceProvider extends ServiceProvider { /** * Bootstrap the application events. - * - * @return void */ - public function boot() + public function boot(): void { - $this->loadViewsFrom(__DIR__ . '/resources/views', 'datatables'); + $this->loadViewsFrom(__DIR__.'/resources/views', 'datatables'); if ($this->app->runningInConsole()) { $this->publishAssets(); @@ -24,27 +21,23 @@ public function boot() /** * Publish datatables assets. */ - protected function publishAssets() + protected function publishAssets(): void { $this->publishes([ - __DIR__ . '/resources/views' => base_path('/resources/views/vendor/datatables'), - __DIR__ . '/resources/config/config.php' => config_path('datatables-html.php'), + __DIR__.'/resources/views' => base_path('/resources/views/vendor/datatables'), + __DIR__.'/resources/config/config.php' => config_path('datatables-html.php'), ], 'datatables-html'); } /** * Register the service provider. - * - * @return void */ - public function register() + public function register(): void { - $this->mergeConfigFrom(__DIR__ . '/resources/config/config.php', 'datatables-html'); + $this->mergeConfigFrom(__DIR__.'/resources/config/config.php', 'datatables-html'); - $this->app->register(CollectiveHtml::class); + $this->app->bind('datatables.html', fn () => $this->app->make(Html\Builder::class)); - $this->app->bind('datatables.html', function () { - return $this->app->make(Html\Builder::class); - }); + DataTables::macro('getHtmlBuilder', fn (): Html\Builder => app('datatables.html')); } } diff --git a/src/resources/config/config.php b/src/resources/config/config.php index 516d313..40a996a 100644 --- a/src/resources/config/config.php +++ b/src/resources/config/config.php @@ -12,15 +12,9 @@ */ 'table' => [ 'class' => 'table', - 'id' => 'dataTableBuilder', + 'id' => 'dataTableBuilder', ], - /* - * Default condition to determine if a parameter is a callback or not. - * Callbacks needs to start by those terms or they will be casted to string. - */ - 'callback' => ['$', '$.', 'function'], - /* * Html builder script template. */ diff --git a/src/resources/views/editor.blade.php b/src/resources/views/editor.blade.php index 3a464d5..3f274d4 100644 --- a/src/resources/views/editor.blade.php +++ b/src/resources/views/editor.blade.php @@ -1,4 +1,4 @@ -$(function(){ +document.addEventListener("DOMContentLoaded", function(){ window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} = window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} || {}; $.ajaxSetup({headers: {'X-CSRF-TOKEN': '{{csrf_token()}}'}}); @foreach($editors as $editor) @@ -9,4 +9,7 @@ @endforeach @endforeach window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"] = $("#%1$s").DataTable(%2$s); -}); \ No newline at end of file +}); +@foreach ($scripts as $script) +@include($script) +@endforeach diff --git a/src/resources/views/functions/batch_remove.blade.php b/src/resources/views/functions/batch_remove.blade.php new file mode 100644 index 0000000..192a7e5 --- /dev/null +++ b/src/resources/views/functions/batch_remove.blade.php @@ -0,0 +1,14 @@ +$(function(){ + @foreach($editors as $editor) + {{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s-{{$editor->instance}}"].on('preSubmit', function(e, data, action) { + if (action !== 'remove') return; + + for (let row_id of Object.keys(data.data)) + { + data.data[row_id] = { + DT_RowId: data.data[row_id].DT_RowId + }; + } + }); + @endforeach +}); diff --git a/src/resources/views/scout.blade.php b/src/resources/views/scout.blade.php new file mode 100644 index 0000000..506ad40 --- /dev/null +++ b/src/resources/views/scout.blade.php @@ -0,0 +1,23 @@ +$(function(){ + $('#%1$s').on('xhr.dt', function (e, settings, json, xhr) { + if (json == null || !('disableOrdering' in json)) return; + + let table = {{ config('datatables-html.namespace', 'LaravelDataTables') }}[$(this).attr('id')]; + if (json.disableOrdering) { + table.settings()[0].aoColumns.forEach(function(column) { + column.bSortable = false; + $(column.nTh).removeClass('sorting_asc sorting_desc sorting').addClass('sorting_disabled'); + }); + } else { + let changed = false; + table.settings()[0].aoColumns.forEach(function(column) { + if (column.bSortable) return; + column.bSortable = true; + changed = true; + }); + if (changed) { + table.draw(); + } + } + }); +}); diff --git a/src/resources/views/script.blade.php b/src/resources/views/script.blade.php index 82b3282..4d3b205 100644 --- a/src/resources/views/script.blade.php +++ b/src/resources/views/script.blade.php @@ -1 +1,4 @@ -$(function(){window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}=window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}||{};window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"]=$("#%1$s").DataTable(%2$s);}); +document.addEventListener("DOMContentLoaded",function(){window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}=window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}||{};window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"]=$("#%1$s").DataTable(%2$s);}); +@foreach ($scripts as $script) +@include($script) +@endforeach diff --git a/tests/.gitkeep b/tests/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/Html/Builder/BuilderOptionsLanguageTest.php b/tests/Html/Builder/BuilderOptionsLanguageTest.php new file mode 100644 index 0000000..9567d16 --- /dev/null +++ b/tests/Html/Builder/BuilderOptionsLanguageTest.php @@ -0,0 +1,113 @@ +getHtmlBuilder(); + $builder->languageAria(['paginate' => ['first' => 'First']]); + $this->assertEquals(['paginate' => ['first' => 'First']], $builder->getLanguage('aria')); + + $builder->languageAriaPaginate(['first' => 'First']); + $this->assertEquals(['first' => 'First'], $builder->getLanguage('aria')['paginate']); + + $builder->languageAriaPaginateFirst('First'); + $this->assertEquals('First', $builder->getLanguage('aria')['paginate']['first']); + + $builder->languageAriaPaginateLast('Last'); + $this->assertEquals('Last', $builder->getLanguage('aria')['paginate']['last']); + + $builder->languageAriaPaginateNext('Next'); + $this->assertEquals('Next', $builder->getLanguage('aria')['paginate']['next']); + + $builder->languageAriaPaginatePrevious('Previous'); + $this->assertEquals('Previous', $builder->getLanguage('aria')['paginate']['previous']); + + $builder->languageAriaSortAscending('languageAriaSortAscending'); + $this->assertEquals('languageAriaSortAscending', $builder->getLanguage('aria')['sortAscending']); + + $builder->languageAriaSortDescending('languageAriaSortDescending'); + $this->assertEquals('languageAriaSortDescending', $builder->getLanguage('aria')['sortDescending']); + } + + #[Test] + public function it_has_language_autofill_options() + { + $builder = $this->getHtmlBuilder(); + $builder->languageAutoFill(['button' => 'button']); + $this->assertEquals(['button' => 'button'], $builder->getLanguage('autoFill')); + + $builder->languageAutoFillButton('button'); + $this->assertEquals('button', $builder->getLanguage('autoFill')['button']); + + $builder->languageAutoFillCancel('cancel'); + $this->assertEquals('cancel', $builder->getLanguage('autoFill')['cancel']); + + $builder->languageAutoFillFill('fill'); + $this->assertEquals('fill', $builder->getLanguage('autoFill')['fill']); + + $builder->languageAutoFillFillHorizontal('languageAutoFillFillHorizontal'); + $this->assertEquals('languageAutoFillFillHorizontal', $builder->getLanguage('autoFill')['fillHorizontal']); + + $builder->languageAutoFillFillVertical('languageAutoFillFillVertical'); + $this->assertEquals('languageAutoFillFillVertical', $builder->getLanguage('autoFill')['fillVertical']); + + $builder->languageAutoFillIncrement('languageAutoFillIncrement'); + $this->assertEquals('languageAutoFillIncrement', $builder->getLanguage('autoFill')['increment']); + + $builder->languageAutoFillInfo('languageAutoFillInfo'); + $this->assertEquals('languageAutoFillInfo', $builder->getLanguage('autoFill')['info']); + } + + #[Test] + public function it_has_language_paginate_options() + { + $builder = $this->getHtmlBuilder(); + $builder->languagePaginate(['first' => 'First']); + $this->assertEquals(['first' => 'First'], $builder->getLanguage('paginate')); + + $builder->languagePaginateFirst('languagePaginateFirst'); + $this->assertEquals('languagePaginateFirst', $builder->getLanguage('paginate')['first']); + + $builder->languagePaginateLast('languagePaginateLast'); + $this->assertEquals('languagePaginateLast', $builder->getLanguage('paginate')['last']); + + $builder->languagePaginateNext('languagePaginateNext'); + $this->assertEquals('languagePaginateNext', $builder->getLanguage('paginate')['next']); + + $builder->languagePaginatePrevious('languagePaginatePrevious'); + $this->assertEquals('languagePaginatePrevious', $builder->getLanguage('paginate')['previous']); + } + + #[Test] + public function it_has_language_select_options() + { + $builder = $this->getHtmlBuilder(); + $builder->languageSelect(['cells' => 1]); + $this->assertEquals(['cells' => 1], $builder->getLanguage('select')); + + $builder->languageSelectCells('languageSelectCells'); + $this->assertEquals('languageSelectCells', $builder->getLanguage('select')['cells']); + + $builder->languageSelectCells([1, 2, 3]); + $this->assertEquals([1, 2, 3], $builder->getLanguage('select')['cells']); + + $builder->languageSelectColumns('languageSelectColumns'); + $this->assertEquals('languageSelectColumns', $builder->getLanguage('select')['columns']); + + $builder->languageSelectColumns([1, 2, 3]); + $this->assertEquals([1, 2, 3], $builder->getLanguage('select')['columns']); + + $builder->languageSelectRows('languageSelectRows'); + $this->assertEquals('languageSelectRows', $builder->getLanguage('select')['rows']); + + $builder->languageSelectRows([1, 2, 3]); + $this->assertEquals([1, 2, 3], $builder->getLanguage('select')['rows']); + } +} diff --git a/tests/Html/Builder/BuilderOptionsPluginsTest.php b/tests/Html/Builder/BuilderOptionsPluginsTest.php new file mode 100644 index 0000000..5c0e3e5 --- /dev/null +++ b/tests/Html/Builder/BuilderOptionsPluginsTest.php @@ -0,0 +1,334 @@ +getHtmlBuilder(); + + $this->assertTrue($builder->getAutoFill()); + + $builder->autoFill(); + $this->assertTrue($builder->getAttribute('autoFill')); + + $builder->autoFill(false); + $this->assertFalse($builder->getAttribute('autoFill')); + + $builder->autoFillAlwaysAsk() + ->autoFillColumns('autoFillColumns') + ->autoFillEditor('autoFillEditor') + ->autoFillEnable() + ->autoFillFocus('autoFillFocus') + ->autoFillHorizontal() + ->autoFillUpdate() + ->autoFillVertical(); + + $this->assertTrue($builder->getAutoFill('alwaysAsk')); + $this->assertEquals('autoFillColumns', $builder->getAutoFill('columns')); + $this->assertEquals('autoFillEditor', $builder->getAutoFill('editor')); + $this->assertEquals(true, $builder->getAutoFill('enable')); + $this->assertEquals('autoFillFocus', $builder->getAutoFill('focus')); + $this->assertEquals(true, $builder->getAutoFill('horizontal')); + $this->assertEquals(true, $builder->getAutoFill('update')); + $this->assertEquals(true, $builder->getAutoFill('vertical')); + + $builder->autoFillColumns([1, 2]); + $this->assertEquals([1, 2], $builder->getAutoFill('columns')); + } + + #[Test] + public function it_has_buttons_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->buttons( + Button::make('create'), + Button::make('edit'), + ); + + $this->assertCount(2, $builder->getAttribute('buttons')); + $this->assertCount(2, $builder->getButtons()); + $this->assertIsArray($builder->getButtons()[0]); + + $builder->buttons([Button::make('remove')]); + $this->assertCount(1, $builder->getButtons()); + + $builder->addButton(Button::make('edit')); + $this->assertCount(2, $builder->getButtons()); + } + + #[Test] + public function it_has_col_reorder_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->colReorder(); + + $this->assertTrue($builder->getAttribute('colReorder')); + $this->assertTrue($builder->getColReorder()); + + $builder->colReorderEnable() + ->colReorderFixedColumnsLeft(1) + ->colReorderFixedColumnsRight(1) + ->colReorderOrder([1]) + ->colReorderRealtime(); + + $this->assertTrue($builder->getColReorder('enable')); + $this->assertEquals(1, $builder->getColReorder('fixedColumnsLeft')); + $this->assertEquals(1, $builder->getColReorder('fixedColumnsRight')); + $this->assertEquals([1], $builder->getColReorder('order')); + $this->assertEquals(true, $builder->getColReorder('realtime')); + } + + #[Test] + public function it_has_fixed_columns_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->fixedColumns(); + + $this->assertTrue($builder->getAttribute('fixedColumns')); + $this->assertTrue($builder->getFixedColumns()); + + $builder->fixedColumnsHeightMatch() + ->fixedColumnsLeftColumns() + ->fixedColumnsRightColumns(); + + $this->assertEquals('semiauto', $builder->getFixedColumns('heightMatch')); + $this->assertEquals(1, $builder->getFixedColumns('leftColumns')); + $this->assertEquals(0, $builder->getFixedColumns('rightColumns')); + } + + #[Test] + public function it_has_fixed_header_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->fixedHeader(); + + $this->assertTrue($builder->getAttribute('fixedHeader')); + $this->assertTrue($builder->getFixedHeader()); + + $builder->fixedHeaderFooter() + ->fixedHeaderFooterOffset() + ->fixedHeaderHeader() + ->fixedHeaderHeaderOffset(); + + $this->assertEquals(true, $builder->getFixedHeader('footer')); + $this->assertEquals(0, $builder->getFixedHeader('offset')); + $this->assertEquals(true, $builder->getFixedHeader('header')); + $this->assertEquals(0, $builder->getFixedHeader('headerOffset')); + } + + #[Test] + public function it_has_keys_plugin() + { + + $builder = $this->getHtmlBuilder(); + $builder->keys(); + + $this->assertTrue($builder->getAttribute('keys')); + $this->assertTrue($builder->getKeys()); + + $builder->keysBlurable() + ->keysClassName() + ->keysClipboard() + ->keysClipboardOrthogonal() + ->keysColumns('name') + ->keysEditAutoSelect() + ->keysEditOnFocus() + ->keysEditor('editor') + ->keysEditorKeys() + ->keysFocus(':eq(0)') + ->keysKeys(['charCodeAt(0)']) + ->keysTabIndex(1); + + $this->assertEquals(true, $builder->getKeys('blurable')); + $this->assertEquals('focus', $builder->getKeys('className')); + $this->assertEquals(true, $builder->getKeys('clipboard')); + $this->assertEquals('display', $builder->getKeys('clipboardOrthogonal')); + $this->assertEquals('name', $builder->getKeys('columns')); + $this->assertEquals(true, $builder->getKeys('editAutoSelect')); + $this->assertEquals(true, $builder->getKeys('editOnFocus')); + $this->assertEquals('editor', $builder->getKeys('editor')); + $this->assertEquals('navigation-only', $builder->getKeys('editorKeys')); + $this->assertEquals(':eq(0)', $builder->getKeys('focus')); + $this->assertEquals(['charCodeAt(0)'], $builder->getKeys('keys')); + $this->assertEquals(1, $builder->getKeys('tabIndex')); + } + + #[Test] + public function it_has_responsive_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->responsive(); + + $this->assertTrue($builder->getAttribute('responsive')); + $this->assertTrue($builder->getResponsive()); + + $builder->responsiveBreakpoints([1]) + ->responsiveDetailsDisplay('display') + ->responsiveDetailsRenderer('renderer') + ->responsiveDetailsTarget('target') + ->responsiveDetailsType('type') + ->responsiveOrthogonal('orthogonal'); + $this->assertEquals([1], $builder->getResponsive('breakpoints')); + $this->assertEquals('display', $builder->getResponsive('details')['display']); + $this->assertEquals('renderer', $builder->getResponsive('details')['renderer']); + $this->assertEquals('target', $builder->getResponsive('details')['target']); + $this->assertEquals('type', $builder->getResponsive('details')['type']); + $this->assertEquals('orthogonal', $builder->getResponsive('orthogonal')); + } + + #[Test] + public function it_has_row_group_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->rowGroup(); + + $this->assertTrue($builder->getAttribute('rowGroup')); + $this->assertTrue($builder->getRowGroup()); + + $builder->rowGroupDataSrc([1]) + ->rowGroupEmptyDataGroup() + ->rowGroupEnable() + ->rowGroupEndClassName() + ->rowGroupEndRender('fn') + ->rowGroupStartClassName() + ->rowGroupStartRender(); + + $this->assertEquals([1], $builder->getRowGroup('dataSrc')); + $this->assertEquals('No Group', $builder->getRowGroup('emptyDataGroup')); + $this->assertEquals(true, $builder->getRowGroup('enable')); + $this->assertEquals('group-end', $builder->getRowGroup('endClassName')); + $this->assertEquals('fn', $builder->getRowGroup('endRender')); + $this->assertEquals('group-start', $builder->getRowGroup('startClassName')); + $this->assertEquals(null, $builder->getRowGroup('startRender')); + } + + #[Test] + public function it_has_row_reorder_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->rowReorder(); + + $this->assertTrue($builder->getAttribute('rowReorder')); + $this->assertTrue($builder->getRowReorder()); + + $builder->rowReorderDataSrc([1]) + ->rowReorderEditor('editor') + ->rowReorderEnable() + ->rowReorderFormOptions(['main' => []]) + ->rowReorderSelector() + ->rowReorderSnapX() + ->rowReorderUpdate(); + + $this->assertEquals([1], $builder->getRowReorder('dataSrc')); + $this->assertEquals('editor', $builder->getRowReorder('editor')); + $this->assertEquals(true, $builder->getRowReorder('enable')); + $this->assertEquals(['main' => []], $builder->getRowReorder('formOptions')); + $this->assertEquals('td:first-child', $builder->getRowReorder('selector')); + $this->assertEquals(true, $builder->getRowReorder('snapX')); + $this->assertEquals(true, $builder->getRowReorder('update')); + } + + #[Test] + public function it_has_scroller_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->scroller(); + + $this->assertTrue($builder->getAttribute('scroller')); + $this->assertTrue($builder->getScroller()); + + $builder->scrollerBoundaryScale() + ->scrollerDisplayBuffer() + ->scrollerLoadingIndicator() + ->scrollerRowHeight() + ->scrollerServerWait(); + + $this->assertEquals(0.5, $builder->getScroller('boundaryScale')); + $this->assertEquals(9, $builder->getScroller('displayBuffer')); + $this->assertEquals(true, $builder->getScroller('loadingIndicator')); + $this->assertEquals('auto', $builder->getScroller('rowHeight')); + $this->assertEquals(200, $builder->getScroller('serverWait')); + } + + #[Test] + public function it_has_search_panes_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->searchPanes(); + + $this->assertEquals(['show' => true], $builder->getAttribute('searchPanes')); + $this->assertIsArray($builder->getSearchPanes()); + + $builder->searchPanes(false); + $this->assertEquals(['show' => false], $builder->getAttribute('searchPanes')); + + $builder->searchPanes(['hide' => true]); + $this->assertEquals(['hide' => true], $builder->getAttribute('searchPanes')); + + $builder->searchPanes(fn () => ['show' => true]); + $this->assertEquals(['show' => true], $builder->getAttribute('searchPanes')); + + $builder->searchPanes(SearchPane::make()->show()->cascadePanes()); + $this->assertEquals(['show' => true, 'cascadePanes' => true], $builder->getAttribute('searchPanes')); + } + + #[Test] + public function it_has_select_plugin() + { + $builder = $this->getHtmlBuilder(); + $builder->select(); + + $this->assertTrue($builder->getAttribute('select')); + $this->assertTrue($builder->getSelect()); + + $builder->selectBlurable() + ->selectClassName() + ->selectInfo() + ->selectItems() + ->selectSelector() + ->selectStyle(); + + $this->assertEquals(true, $builder->getSelect('blurable')); + $this->assertEquals('selected', $builder->getSelect('className')); + $this->assertEquals(true, $builder->getSelect('info')); + $this->assertEquals('row', $builder->getSelect('items')); + $this->assertEquals('td', $builder->getSelect('selector')); + $this->assertEquals('os', $builder->getSelect('style')); + + $builder->selectAddClassName('test'); + $this->assertEquals('selected test', $builder->getSelect('className')); + + $builder->selectItemsRow(); + $this->assertEquals(Builder::SELECT_ITEMS_ROW, $builder->getSelect('items')); + + $builder->selectItemsColumn(); + $this->assertEquals(Builder::SELECT_ITEMS_COLUMN, $builder->getSelect('items')); + + $builder->selectItemsCell(); + $this->assertEquals(Builder::SELECT_ITEMS_CELL, $builder->getSelect('items')); + + $builder->selectStyleSingle(); + $this->assertEquals(Builder::SELECT_STYLE_SINGLE, $builder->getSelect('style')); + + $builder->selectStyleMulti(); + $this->assertEquals(Builder::SELECT_STYLE_MULTI, $builder->getSelect('style')); + + $builder->selectStyleOS(); + $this->assertEquals(Builder::SELECT_STYLE_OS, $builder->getSelect('style')); + + $builder->selectStyleMultiShift(); + $this->assertEquals(Builder::SELECT_STYLE_MULTI_SHIFT, $builder->getSelect('style')); + + $builder->selectStyleApi(); + $this->assertEquals(Builder::SELECT_STYLE_API, $builder->getSelect('style')); + } +} diff --git a/tests/Html/Builder/BuilderOptionsTest.php b/tests/Html/Builder/BuilderOptionsTest.php new file mode 100644 index 0000000..1d2ca0e --- /dev/null +++ b/tests/Html/Builder/BuilderOptionsTest.php @@ -0,0 +1,287 @@ +getHtmlBuilder(); + + $builder + ->createdRow('function() {}') + ->drawCallback('function() {}') + ->footerCallback('function() {}') + ->formatNumber('function() {}') + ->headerCallback('function() {}') + ->infoCallback('function() {}') + ->initComplete('function() {}') + ->preDrawCallback('function() {}') + ->rowCallback('function() {}') + ->stateLoadCallback('function() {}') + ->stateLoaded('function() {}') + ->stateLoadParams('function() {}') + ->stateSaveCallback('function() {}') + ->stateSaveParams('function() {}'); + + $this->assertEquals('function() {}', $builder->getAttribute('createdRow')); + $this->assertEquals('function() {}', $builder->getAttribute('drawCallback')); + $this->assertEquals('function() {}', $builder->getAttribute('footerCallback')); + $this->assertEquals('function() {}', $builder->getAttribute('formatNumber')); + $this->assertEquals('function() {}', $builder->getAttribute('infoCallback')); + $this->assertEquals('function() {}', $builder->getAttribute('preDrawCallback')); + $this->assertEquals('function() {}', $builder->getAttribute('stateLoaded')); + $this->assertEquals('function() {}', $builder->getAttribute('stateSaveCallback')); + $this->assertEquals('function() {}', $builder->getAttribute('stateSaveParams')); + + $builder->drawCallbackWithLivewire(); + $this->assertStringContainsString('window.livewire.rescan()', $builder->getAttribute('drawCallback')); + + $builder->drawCallbackWithLivewire('test livewire'); + $this->assertStringContainsString('test livewire', $builder->getAttribute('drawCallback')); + } + + #[Test] + public function it_has_columns_options() + { + $builder = $this->getHtmlBuilder(); + + $builder->columnDefs(['target' => [1]]) + ->addColumnDef(['target' => [1]]) + ->addColumnDef(['target' => [2]]) + ->columns([ + Column::make('id'), + Column::make('name'), + ]); + + $this->assertEquals([1], $builder->getAttribute('columnDefs')['target']); + $this->assertEquals([1], $builder->getAttribute('columnDefs')[0]['target']); + $this->assertEquals([2], $builder->getAttribute('columnDefs')[1]['target']); + $this->assertCount(2, $builder->getColumns()); + $this->assertInstanceOf(Column::class, $builder->getColumns()[0]); + $this->assertEquals('id', $builder->getColumns()[0]['data']); + $this->assertEquals('id', $builder->getColumns()[0]['name']); + $this->assertEquals('Id', $builder->getColumns()[0]['title']); + + $builder->addColumn(['data' => 'email']); + + $this->assertCount(3, $builder->getColumns()); + $this->assertInstanceOf(Column::class, $builder->getColumns()[2]); + $this->assertEquals('email', $builder->getColumns()[2]['data']); + $this->assertEquals('email', $builder->getColumns()[2]['name']); + $this->assertEquals('Email', $builder->getColumns()[2]['title']); + + $builder->addColumn(Column::make('created_at')); + + $this->assertCount(4, $builder->getColumns()); + $this->assertInstanceOf(Column::class, $builder->getColumns()[3]); + $this->assertEquals('created_at', $builder->getColumns()[3]['data']); + $this->assertEquals('created_at', $builder->getColumns()[3]['name']); + $this->assertEquals('Created At', $builder->getColumns()[3]['title']); + + $builder->addColumnBefore(['data' => 'updated_at']); + + $this->assertCount(5, $builder->getColumns()); + $this->assertInstanceOf(Column::class, $builder->getColumns()[0]); + $this->assertEquals('updated_at', $builder->getColumns()[0]['data']); + $this->assertEquals('updated_at', $builder->getColumns()[0]['name']); + $this->assertEquals('Updated At', $builder->getColumns()[0]['title']); + + $builder->addBefore(Column::make('deleted_at')); + + $this->assertCount(6, $builder->getColumns()); + $this->assertInstanceOf(Column::class, $builder->getColumns()[0]); + $this->assertEquals('deleted_at', $builder->getColumns()[0]['data']); + $this->assertEquals('deleted_at', $builder->getColumns()[0]['name']); + $this->assertEquals('Deleted At', $builder->getColumns()[0]['title']); + + $builder->removeColumn('created_at', 'updated_at'); + $this->assertCount(4, $builder->getColumns()); + } + + #[Test] + public function it_has_ajax_options() + { + $builder = $this->getHtmlBuilder(); + + $builder->postAjax('/test'); + + $this->assertEquals('/test', $builder->getAjaxUrl()); + $this->assertEquals([ + 'url' => '/test', + 'type' => 'POST', + 'headers' => [ + 'X-HTTP-Method-Override' => 'GET', + ], + ], $builder->getAjax()); + + $builder->ajax('/test'); + $this->assertEquals('/test', $builder->getAjaxUrl()); + + $builder->ajax(['url' => '/test']); + $this->assertEquals('/test', $builder->getAjax('url')); + + $builder->pipeline('/test'); + $this->assertEquals("$.fn.dataTable.pipeline({ url: '/test', pages: 5 })", $builder->getAjaxUrl()); + + $builder->pipeline('/test', 6); + $this->assertEquals("$.fn.dataTable.pipeline({ url: '/test', pages: 6 })", $builder->getAjaxUrl()); + + $builder->ajaxWithForm('/test', '#formId'); + $this->assertStringContainsString('data.columns.length', $builder->getAjax()['data']); + $this->assertStringContainsString('delete data.columns[i].search;', $builder->getAjax('data')); + $this->assertStringContainsString('#formId', $builder->getAjax('data')); + + $builder->minifiedAjax('/test', 'custom_script', ['id' => 123, 'name' => 'yajra']); + $this->assertEquals('/test', $builder->getAjax('url')); + $this->assertStringContainsString('custom_script', $builder->getAjax('data')); + $this->assertStringContainsString('data.id = 123', $builder->getAjax('data')); + $this->assertStringContainsString("data.name = 'yajra'", $builder->getAjax('data')); + + $builder->postAjaxWithForm('/test', '#formId'); + $this->assertStringContainsString('find("input, select, textarea").serializeArray()', $builder->getAjax()['data']); + $this->assertStringContainsString('#formId', $builder->getAjax('data')); + } + + #[Test] + public function it_has_features_options() + { + $builder = $this->getHtmlBuilder(); + $builder->autoWidth() + ->deferRender() + ->info() + ->lengthChange() + ->ordering() + ->processing() + ->scrollX() + ->scrollY() + ->paging() + ->searching() + ->serverSide() + ->stateSave(); + + $this->assertEquals(true, $builder->getAttribute('autoWidth')); + $this->assertEquals(true, $builder->getAttribute('deferRender')); + $this->assertEquals(true, $builder->getAttribute('info')); + $this->assertEquals(true, $builder->getAttribute('lengthChange')); + $this->assertEquals(true, $builder->getAttribute('ordering')); + $this->assertEquals(true, $builder->getAttribute('processing')); + $this->assertEquals(true, $builder->getAttribute('scrollX')); + $this->assertEquals(true, $builder->getAttribute('scrollY')); + $this->assertEquals(true, $builder->getAttribute('paging')); + $this->assertEquals(true, $builder->getAttribute('searching')); + $this->assertEquals(true, $builder->getAttribute('serverSide')); + $this->assertEquals(true, $builder->getAttribute('stateSave')); + + $builder->scrollY('50vh'); + $this->assertEquals('50vh', $builder->getAttribute('scrollY')); + } + + #[Test] + public function it_has_internationalisation_options() + { + $builder = $this->getHtmlBuilder(); + + $builder->language('/language-url') + ->languageDecimal(',') + ->languageEmptyTable('languageEmptyTable') + ->languageInfo('languageInfo') + ->languageInfoEmpty('languageInfoEmpty') + ->languageInfoFiltered('languageInfoFiltered') + ->languageInfoPostFix('languageInfoPostFix') + ->languageLengthMenu('languageLengthMenu') + ->languageLoadingRecords('languageLoadingRecords') + ->languageProcessing('languageProcessing') + ->languageSearch('languageSearch') + ->languageSearchPlaceholder('languageSearchPlaceholder') + ->languageThousands('languageThousands') + ->languageZeroRecords('languageZeroRecords'); + + $this->assertEquals('/language-url', $builder->getAttribute('language')['url']); + $this->assertEquals(',', $builder->getLanguage('decimal')); + $this->assertEquals('languageEmptyTable', $builder->getLanguage('emptyTable')); + $this->assertEquals('languageInfo', $builder->getLanguage('info')); + $this->assertEquals('languageInfoEmpty', $builder->getLanguage('infoEmpty')); + $this->assertEquals('languageInfoFiltered', $builder->getLanguage('infoFiltered')); + $this->assertEquals('languageInfoPostFix', $builder->getLanguage('infoPostFix')); + $this->assertEquals('languageLengthMenu', $builder->getLanguage('lengthMenu')); + $this->assertEquals('languageLoadingRecords', $builder->getLanguage('loadingRecords')); + $this->assertEquals('languageProcessing', $builder->getLanguage('processing')); + $this->assertEquals('languageSearch', $builder->getLanguage('search')); + $this->assertEquals('languageSearchPlaceholder', $builder->getLanguage('searchPlaceholder')); + $this->assertEquals('languageThousands', $builder->getLanguage('thousands')); + $this->assertEquals('languageZeroRecords', $builder->getLanguage('zeroRecords')); + + $builder->languageUrl('languageUrl'); + $this->assertEquals('languageUrl', $builder->getLanguage('url')); + } + + #[Test] + public function it_has_plugin_attribute_getter() + { + $builder = $this->getHtmlBuilder(); + + $builder->selectStyleSingle(); + + $this->assertEquals(Builder::SELECT_STYLE_SINGLE, $builder->getPluginAttribute('select', 'style')); + } + + #[Test] + public function it_has_options() + { + $builder = $this->getHtmlBuilder(); + $builder->deferLoading(10) + ->destroy(true) + ->displayStart(1) + ->dom('Bf') + ->lengthMenu() + ->orders([[1, 'asc']]) + ->orderCellsTop() + ->orderClasses() + ->orderBy(2) + ->orderBy(3, 'asc') + ->orderByFixed(3, 'asc') + ->orderMulti() + ->pageLength() + ->pagingType() + ->renderer() + ->retrieve() + ->rowId() + ->scrollCollapse() + ->search([]) + ->searchCols([]) + ->searchDelay(10) + ->stateDuration(10) + ->stripeClasses(['stripeClasses']) + ->tabIndex(2); + + $this->assertEquals(10, $builder->getAttribute('deferLoading')); + $this->assertEquals(true, $builder->getAttribute('destroy')); + $this->assertEquals(1, $builder->getAttribute('displayStart')); + $this->assertEquals('Bf', $builder->getAttribute('dom')); + $this->assertEquals([10, 25, 50, 100], $builder->getAttribute('lengthMenu')); + $this->assertEquals([1, 'asc'], $builder->getAttribute('order')[0]); + $this->assertEquals([2, 'desc'], $builder->getAttribute('order')[1]); + $this->assertEquals([3, 'asc'], $builder->getAttribute('order')[2]); + $this->assertEquals(false, $builder->getAttribute('orderCellsTop')); + $this->assertEquals(true, $builder->getAttribute('orderClasses')); + $this->assertEquals([[3, 'asc']], $builder->getAttribute('orderFixed')); + $this->assertEquals(true, $builder->getAttribute('orderMulti')); + $this->assertEquals(10, $builder->getAttribute('pageLength')); + $this->assertEquals('simple_numbers', $builder->getAttribute('pagingType')); + $this->assertEquals('bootstrap', $builder->getAttribute('renderer')); + $this->assertEquals(false, $builder->getAttribute('scrollCollapse')); + $this->assertEquals([], $builder->getAttribute('search')); + $this->assertEquals([], $builder->getAttribute('searchCols')); + $this->assertEquals(10, $builder->getAttribute('searchDelay')); + $this->assertEquals(10, $builder->getAttribute('stateDuration')); + $this->assertEquals(['stripeClasses'], $builder->getAttribute('stripeClasses')); + $this->assertEquals(2, $builder->getAttribute('tabIndex')); + } +} diff --git a/tests/Html/Builder/BuilderTest.php b/tests/Html/Builder/BuilderTest.php new file mode 100644 index 0000000..1b61ef2 --- /dev/null +++ b/tests/Html/Builder/BuilderTest.php @@ -0,0 +1,306 @@ +getHtmlBuilder()->scripts()->toHtml(); + + $this->assertStringContainsString('type="text/javascript"', $html); + } + + #[Test] + public function it_can_set_script_type_attribute() + { + $html = $this->getHtmlBuilder()->scripts(attributes: ['type' => 'module'])->toHtml(); + + $this->assertStringContainsString('type="module"', $html); + } + + #[Test] + public function it_can_set_multiple_script_attributes() + { + $html = $this->getHtmlBuilder()->scripts(attributes: ['prop1' => 'val1', 'prop2' => 'val2'])->toHtml(); + + $this->assertStringContainsString('prop1="val1"', $html); + $this->assertStringContainsString('prop2="val2"', $html); + } + + #[Test] + public function it_can_use_vitejs_module_script() + { + Builder::useVite(); + + $this->assertStringContainsString('type="module"', $this->getHtmlBuilder()->scripts()->toHtml()); + + Builder::useWebpack(); + } + + #[Test] + public function it_can_resolved_builder_class() + { + $builder = $this->getHtmlBuilder(); + + $this->assertInstanceOf(Builder::class, $builder); + + $builder = app('datatables.html'); + $this->assertInstanceOf(Builder::class, $builder); + } + + #[Test] + public function it_can_read_table_id_from_config() + { + $this->assertEquals('dataTableBuilder', $this->getHtmlBuilder()->getTableId()); + + config()->set('datatables-html.table.id', 'test'); + + $this->assertEquals('test', $this->getHtmlBuilder()->getTableId()); + } + + #[Test] + public function it_can_change_namespace() + { + $builder = $this->getHtmlBuilder(); + + $this->assertStringContainsString('LaravelDataTables', $builder->scripts()->toHtml()); + + config()->set('datatables-html.namespace', 'TestDataTables'); + + $this->assertStringContainsString('TestDataTables', $builder->scripts()->toHtml()); + } + + #[Test] + public function it_can_generate_table_html_and_scripts() + { + $builder = $this->getHtmlBuilder(); + + $builder->setTableId('foo-table') + ->columns([ + Column::make('foo'), + Column::make('baz'), + ]); + + $table = $builder->table()->toHtml(); + + $expected = '
    FooBaz
    '; + $this->assertEquals($expected, $table); + + $script = $builder->scripts()->toHtml(); + $expected = ''; + $this->assertEquals($expected, $script); + + $expected = 'document.addEventListener("DOMContentLoaded",function(){window.LaravelDataTables=window.LaravelDataTables||{};window.LaravelDataTables["foo-table"]=$("#foo-table").DataTable({"serverSide":true,"processing":true,"ajax":"","columns":[{"data":"foo","name":"foo","title":"Foo","orderable":true,"searchable":true},{"data":"baz","name":"baz","title":"Baz","orderable":true,"searchable":true}]});});'; + $this->assertEquals($expected, $builder->generateScripts()->toHtml()); + } + + #[Test] + public function it_can_set_table_attribute() + { + $builder = $this->getHtmlBuilder(); + + $builder->setTableAttribute('attr', 'val'); + + $this->assertEquals('val', $builder->getTableAttribute('attr')); + } + + #[Test] + public function it_can_set_table_id_attribute() + { + $builder = $this->getHtmlBuilder(); + + $builder->setTableId('val'); + + $this->assertEquals('val', $builder->getTableAttribute('id')); + } + + #[Test] + public function it_can_set_multiple_table_attributes() + { + $builder = $this->getHtmlBuilder(); + + $builder->setTableAttribute(['prop1' => 'val1', 'prop2' => 'val2']); + + $this->assertEquals('val1', $builder->getTableAttribute('prop1')); + $this->assertEquals('val2', $builder->getTableAttribute('prop2')); + } + + #[Test] + public function it_can_get_inexistent_table_attribute_throws() + { + $builder = $this->getHtmlBuilder(); + + $attr = $builder->getTableAttribute('boohoo'); + + $this->assertEmpty($attr); + } + + #[Test] + public function it_can_add_table_class_attribute() + { + $builder = $this->getHtmlBuilder(); + $this->assertEquals('table', $builder->getTableAttribute('class')); + + $builder->addTableClass('foo'); + $this->assertEquals('table foo', $builder->getTableAttribute('class')); + + $builder->addTableClass(' foo bar '); + $this->assertEquals('table foo bar', $builder->getTableAttribute('class')); + + $builder->addTableClass([' a-b ', 'foo c bar', 'key' => 'value']); + $this->assertEquals('table foo bar a-b c value', $builder->getTableAttribute('class')); + } + + #[Test] + public function it_can_remove_table_class_attribute() + { + $builder = $this->getHtmlBuilder(); + $builder->setTableAttribute('class', ' foo bar a b c '); + + $builder->removeTableClass('bar'); + $this->assertEquals('foo a b c', $builder->getTableAttribute('class')); + + $builder->removeTableClass(' x c y '); + $this->assertEquals('foo a b', $builder->getTableAttribute('class')); + + $builder->removeTableClass(['a' => ' b ', ' foo bar ']); + $this->assertEquals('a', $builder->getTableAttribute('class')); + } + + #[Test] + public function it_can_add_checkbox() + { + $builder = $this->getHtmlBuilder(); + $builder->addCheckbox(); + + $column = $builder->getColumns()[0]; + + $this->assertCount(1, $builder->getColumns()); + $this->assertInstanceOf(Column::class, $column); + $this->assertEquals(false, $column->orderable); + $this->assertEquals(false, $column->searchable); + $this->assertEquals(false, $column->exportable); + $this->assertEquals(true, $column->printable); + } + + #[Test] + public function it_can_add_index_column() + { + $builder = $this->getHtmlBuilder(); + $builder->addIndex(); + + $column = $builder->getColumns()[0]; + + $this->assertCount(1, $builder->getColumns()); + $this->assertInstanceOf(Column::class, $column); + $this->assertEquals(false, $column->orderable); + $this->assertEquals(false, $column->searchable); + $this->assertEquals(false, $column->exportable); + $this->assertEquals(true, $column->printable); + } + + #[Test] + public function it_can_add_action_column() + { + $builder = $this->getHtmlBuilder(); + $builder->addAction(); + + $column = $builder->getColumns()[0]; + + $this->assertCount(1, $builder->getColumns()); + $this->assertInstanceOf(Column::class, $column); + $this->assertEquals(false, $column->orderable); + $this->assertEquals(false, $column->searchable); + $this->assertEquals(false, $column->exportable); + $this->assertEquals(true, $column->printable); + } + + #[Test] + public function it_has_column_defs() + { + $builder = $this->getHtmlBuilder(); + $builder->columnDefs([['targets' => '_all']]); + + $this->assertEquals([['targets' => '_all']], $builder->getAttribute('columnDefs')); + $this->assertCount(1, $builder->getAttribute('columnDefs')); + + $builder->columnDefs([ColumnDefinition::make()->targets('_all')->visible()]); + + $this->assertEquals([['targets' => '_all', 'visible' => true]], $builder->getAttribute('columnDefs')); + $this->assertCount(1, $builder->getAttribute('columnDefs')); + + $builder->addColumnDef(ColumnDefinition::make()->targets([1])); + $this->assertEquals(['targets' => [1]], $builder->getAttribute('columnDefs')[1]); + $this->assertCount(2, $builder->getAttribute('columnDefs')); + + $builder->columnDefs(ColumnDefinitions::make()->push(ColumnDefinition::make()->targets(1))); + $this->assertEquals([['targets' => 1]], $builder->getAttribute('columnDefs')); + $this->assertCount(1, $builder->getAttribute('columnDefs')); + } + + #[Test] + public function it_has_table_options() + { + $builder = $this->getHtmlBuilder(); + $builder->setTableId('my-table'); + + $this->assertEquals('my-table', $builder->getTableId()); + $this->assertEquals(['id' => 'my-table', 'class' => 'table'], $builder->getTableAttributes()); + + $builder->setTableAttribute('class', 'dTable'); + $this->assertEquals(['id' => 'my-table', 'class' => 'dTable'], $builder->getTableAttributes()); + + $builder->addTableClass('table'); + $this->assertEquals(['id' => 'my-table', 'class' => 'dTable table'], $builder->getTableAttributes()); + + $builder->removeTableClass('dTable'); + $this->assertEquals(['id' => 'my-table', 'class' => 'table'], $builder->getTableAttributes()); + + $this->assertInstanceOf(HtmlString::class, $builder->table()); + $this->assertEquals('
    ', $builder->table()->toHtml()); + + $builder->setTableHeadClass('thead-dark'); + $this->assertEquals('
    ', $builder->table()->toHtml()); + } + + #[Test] + public function it_has_editors() + { + $builder = $this->getHtmlBuilder(); + + $builder->editor(Editor::make()); + $this->assertCount(1, $builder->getEditors()); + + $builder->editors([ + Editor::make(), + Editor::make('edit'), + ]); + $this->assertCount(2, $builder->getEditors()); + } + + #[Test] + public function it_ignores_unauthorized_columns(): void + { + $builder = $this->getHtmlBuilder(); + + $builder->columns([ + Column::makeIf(false) + ->title('unauthorized_column'), + + Column::make('authorized_column'), + ]); + + $this->assertCount(1, $builder->getColumns()); + } +} diff --git a/tests/Html/Builder/LayoutTest.php b/tests/Html/Builder/LayoutTest.php new file mode 100644 index 0000000..3f46723 --- /dev/null +++ b/tests/Html/Builder/LayoutTest.php @@ -0,0 +1,319 @@ +top('test'); + $this->assertEquals('test', $layout->get('top')); + + $layout->bottom('test'); + $this->assertEquals('test', $layout->get('bottom')); + + $layout->topStart('test'); + $this->assertEquals('test', $layout->get('topStart')); + + $layout->topEnd('test'); + $this->assertEquals('test', $layout->get('topEnd')); + + $layout->bottomStart('test'); + $this->assertEquals('test', $layout->get('bottomStart')); + + $layout->bottomEnd('test'); + $this->assertEquals('test', $layout->get('bottomEnd')); + + $layout->top('test', 1); + $this->assertEquals('test', $layout->get('top1')); + + $layout->bottom('test', 1); + $this->assertEquals('test', $layout->get('bottom1')); + + $layout->topStart('test', 1); + $this->assertEquals('test', $layout->get('top1Start')); + + $layout->bottomStart('test', 1); + $this->assertEquals('test', $layout->get('bottom1Start')); + + $layout->topEnd('test', 1); + $this->assertEquals('test', $layout->get('top1End')); + + $layout->bottomEnd('test', 1); + $this->assertEquals('test', $layout->get('bottom1End')); + } + + #[Test] + public function it_can_be_used_in_builder(): void + { + $builder = resolve(Builder::class); + $builder->layout(function (Layout $layout) { + $layout->top('test'); + $layout->bottom('test'); + $layout->topStart('test'); + $layout->topEnd('test'); + $layout->bottomStart('test'); + $layout->bottomEnd('test'); + $layout->top('test', 1); + $layout->bottom('test', 1); + $layout->topStart('test', 1); + $layout->bottomStart('test', 1); + $layout->topEnd('test', 1); + $layout->bottomEnd('test', 1); + }); + + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('top', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('bottom', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('topStart', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('topEnd', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('bottomStart', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('bottomEnd', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('top1', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('bottom1', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('top1Start', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('bottom1Start', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('top1End', $builder->getAttributes()['layout']); + $this->assertArrayHasKey('bottom1End', $builder->getAttributes()['layout']); + } + + #[Test] + public function it_has_factory_method(): void + { + $layout = Layout::make(); + $this->assertInstanceOf(Layout::class, $layout); + + $builder = resolve(Builder::class); + $builder->layout(Layout::make()); + + $this->assertArrayHasKey('layout', $builder->getAttributes()); + } + + #[Test] + public function it_can_be_macroable(): void + { + Layout::macro('test', fn () => 'test'); + + $layout = new Layout; + $this->assertEquals('test', $layout->test()); + } + + #[Test] + public function it_can_accept_array(): void + { + $layout = new Layout(['top' => 'test']); + $this->assertEquals('test', $layout->get('top')); + } + + #[Test] + public function it_can_accept_array_as_parameter(): void + { + $layout = Layout::make(['top' => 'test']); + $this->assertEquals('test', $layout->get('top')); + } + + #[Test] + public function it_can_accept_array_as_parameter_in_builder(): void + { + $builder = resolve(Builder::class); + $builder->layout(['top' => 'test']); + + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('top', $builder->getAttributes()['layout']); + } + + #[Test] + public function it_can_accept_callable_as_parameter_in_builder(): void + { + $builder = resolve(Builder::class); + $builder->layout(fn (Layout $layout) => $layout->top('test')); + + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('top', $builder->getAttributes()['layout']); + } + + #[Test] + public function it_can_accept_js_selector_for_layout_content(): void + { + $builder = resolve(Builder::class); + $builder->layout(fn (Layout $layout) => $layout->topView('#test')); + + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('top', $builder->getAttributes()['layout']); + $this->assertEquals("function() { return $('#test').html(); }", $builder->getAttributes()['layout']['top']); + + $builder->layout(fn (Layout $layout) => $layout->bottomView('#test')); + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('bottom', $builder->getAttributes()['layout']); + $this->assertEquals("function() { return $('#test').html(); }", $builder->getAttributes()['layout']['bottom']); + + $builder->layout(fn (Layout $layout) => $layout->topStartView('#test')); + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('topStart', $builder->getAttributes()['layout']); + $this->assertEquals("function() { return $('#test').html(); }", + $builder->getAttributes()['layout']['topStart']); + + $builder->layout(fn (Layout $layout) => $layout->topEndView('#test')); + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('topEnd', $builder->getAttributes()['layout']); + $this->assertEquals("function() { return $('#test').html(); }", $builder->getAttributes()['layout']['topEnd']); + + $builder->layout(fn (Layout $layout) => $layout->bottomStartView('#test')); + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('bottomStart', $builder->getAttributes()['layout']); + $this->assertEquals("function() { return $('#test').html(); }", + $builder->getAttributes()['layout']['bottomStart']); + + $builder->layout(fn (Layout $layout) => $layout->bottomEndView('#test')); + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('bottomEnd', $builder->getAttributes()['layout']); + $this->assertEquals( + "function() { return $('#test').html(); }", + $builder->getAttributes()['layout']['bottomEnd'] + ); + } + + #[Test] + public function it_can_accept_view_instance_or_string_for_layout_content(): void + { + $builder = resolve(Builder::class); + + $view = view('test-view'); + + $builder->layout(fn (Layout $layout) => $layout + ->addView( + view: new TestView, + layoutPosition: LayoutPosition::Top, + ) + ->addView( + view: new TestInlineView, + layoutPosition: LayoutPosition::Bottom, + ) + ->addView( + view: $view, + layoutPosition: LayoutPosition::TopStart, + order: 1 + ) + ->addView( + view: 'test-view', + layoutPosition: LayoutPosition::BottomEnd, + order: 2 + ) + ->addView( + view: (new TestView)->render(), + layoutPosition: LayoutPosition::Top, + order: 3 + ) + ->addView( + view: (new TestInlineView)->render(), + layoutPosition: LayoutPosition::Bottom, + order: 4 + ) + ); + + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertCount(6, $builder->getAttributes()['layout']); + + $this->assertArrayHasKey('top', $builder->getAttributes()['layout']); + $this->assertEquals( + 'function() { return '.json_encode($view->render()).'; }', + $builder->getAttributes()['layout']['top'] + ); + + $this->assertArrayHasKey('bottom', $builder->getAttributes()['layout']); + $this->assertEquals( + 'function() { return '.json_encode('

    Test Inline View

    ').'; }', + $builder->getAttributes()['layout']['bottom'] + ); + + $this->assertArrayHasKey('top1Start', $builder->getAttributes()['layout']); + $this->assertEquals( + 'function() { return '.json_encode($view->render()).'; }', + $builder->getAttributes()['layout']['top1Start'] + ); + + $this->assertArrayHasKey('bottom2End', $builder->getAttributes()['layout']); + $this->assertEquals( + 'function() { return '.json_encode($view->render()).'; }', + $builder->getAttributes()['layout']['bottom2End'] + ); + + $this->assertArrayHasKey('top3', $builder->getAttributes()['layout']); + $this->assertEquals( + 'function() { return '.json_encode($view->render()).'; }', + $builder->getAttributes()['layout']['top3'] + ); + + $this->assertArrayHasKey('bottom4', $builder->getAttributes()['layout']); + $this->assertEquals( + 'function() { return '.json_encode('

    Test Inline View

    ').'; }', + $builder->getAttributes()['layout']['bottom4'] + ); + } + + #[Test] + public function it_throws_an_exception_if_the_view_does_not_exist_when_adding_view(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('View [non-existent-view] not found.'); + + $builder = resolve(Builder::class); + $builder->layout(fn (Layout $layout) => $layout + ->addView( + view: 'non-existent-view', + layoutPosition: LayoutPosition::Top, + ) + ->addView( + view: view('non-existent-view'), + layoutPosition: LayoutPosition::Bottom, + )); + } + + #[Test] + public function it_can_accept_livewire_component_as_layout_content(): void + { + $builder = resolve(Builder::class); + $builder->layout(fn (Layout $layout) => $layout + ->addLivewire(TestLivewire::class, LayoutPosition::TopStart, 1) + ->addLivewire(TestLivewire::class, LayoutPosition::BottomEnd, 2)); + + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('top1Start', $builder->getAttributes()['layout']); + $this->assertStringContainsString( + 'test livewire', + $builder->getAttributes()['layout']['top1Start'] + ); + + $this->assertArrayHasKey('layout', $builder->getAttributes()); + $this->assertArrayHasKey('bottom2End', $builder->getAttributes()['layout']); + $this->assertStringContainsString( + 'test livewire', + $builder->getAttributes()['layout']['bottom2End'] + ); + } + + #[Test] + public function it_throws_an_exception_if_the_livewire_component_does_not_exist_when_adding_livewire_component(): void + { + $this->expectException(ComponentNotFoundException::class); + $this->expectExceptionMessage('Unable to find component: [Yajra\DataTables\Html\Tests\TestComponents\TestView]'); + + $builder = resolve(Builder::class); + $builder->layout(fn (Layout $layout) => $layout + ->addLivewire(TestView::class, LayoutPosition::Top) + ->addLivewire(TestView::class, LayoutPosition::Bottom)); + } +} diff --git a/tests/Html/Column/ColumnDefinitionTest.php b/tests/Html/Column/ColumnDefinitionTest.php new file mode 100644 index 0000000..47bff1d --- /dev/null +++ b/tests/Html/Column/ColumnDefinitionTest.php @@ -0,0 +1,29 @@ +targets([1]) + ->columns([]) + ->cellType() + ->className('my-class') + ->contentPadding('mmm') + ->createdCell('fn'); + + $this->assertEquals([1], $def->targets); + $this->assertEquals([], $def->columns); + $this->assertEquals('th', $def->cellType); + $this->assertEquals('my-class', $def->className); + $this->assertEquals('mmm', $def->contentPadding); + $this->assertEquals('fn', $def->createdCell); + } +} diff --git a/tests/Html/Column/ColumnTest.php b/tests/Html/Column/ColumnTest.php new file mode 100644 index 0000000..c5da073 --- /dev/null +++ b/tests/Html/Column/ColumnTest.php @@ -0,0 +1,226 @@ +assertInstanceOf(Column::class, $column); + } + + #[Test] + public function it_has_default_properties() + { + $column = Column::make('name'); + + $this->assertEquals('name', $column->name); + $this->assertEquals('name', $column->data); + $this->assertEquals('Name', $column->title); + $this->assertEquals('', $column->render); + $this->assertEquals(true, $column->exportable); + $this->assertEquals(true, $column->printable); + $this->assertEquals(true, $column->orderable); + $this->assertEquals(true, $column->searchable); + $this->assertEquals([], $column->attributes); + $this->assertEquals('', $column->footer); + } + + #[Test] + public function it_can_format_title() + { + $this->assertEquals('Title', Column::titleFormat('title')); + } + + #[Test] + public function it_can_make_computed_column() + { + $column = Column::computed('name'); + + $this->assertEquals('name', $column->name); + $this->assertEquals('name', $column->data); + $this->assertEquals('Name', $column->title); + $this->assertEquals('', $column->render); + $this->assertEquals(true, $column->exportable); + $this->assertEquals(true, $column->printable); + $this->assertEquals(false, $column->orderable); + $this->assertEquals(false, $column->searchable); + $this->assertEquals([], $column->attributes); + $this->assertEquals('', $column->footer); + } + + #[Test] + public function it_can_make_formatted_column() + { + $column = Column::formatted('name'); + + $this->assertEquals('name', $column->name); + $this->assertEquals('name', $column->data); + $this->assertEquals('Name', $column->title); + $this->assertEquals('function(data,type,full,meta){return full.name_formatted;}', $column->render); + $this->assertEquals(true, $column->exportable); + $this->assertEquals(true, $column->printable); + $this->assertEquals(true, $column->orderable); + $this->assertEquals(true, $column->searchable); + $this->assertEquals([], $column->attributes); + $this->assertEquals('', $column->footer); + } + + #[Test] + public function it_can_make_a_checkbox() + { + $column = Column::checkbox('name'); + + $this->assertEquals('', $column->name); + $this->assertEquals('', $column->data); + $this->assertEquals('name', $column->title); + $this->assertEquals('', $column->render); + $this->assertEquals(true, $column->printable); + $this->assertEquals(false, $column->exportable); + $this->assertEquals(false, $column->orderable); + $this->assertEquals(false, $column->searchable); + $this->assertEquals('select-checkbox', $column->className); + $this->assertEquals([], $column->attributes); + $this->assertEquals('', $column->footer); + } + + #[Test] + public function it_has_property_setters() + { + $column = Column::checkbox('name'); + + $column->name('test'); + $this->assertEquals('test', $column->name); + + $column->data('test'); + $this->assertEquals('test', $column->data); + + $column->title('test'); + $this->assertEquals('test', $column->title); + + $column->editField('test'); + $this->assertEquals('test', $column->editField); + + $column->orderData(1); + $this->assertEquals(1, $column->orderData); + + $column->orderData([1]); + $this->assertEquals([1], $column->orderData); + + $column->orderDataType('test'); + $this->assertEquals('test', $column->orderDataType); + + $column->orderSequence(['test']); + $this->assertEquals(['test'], $column->orderSequence); + + $column->cellType('test'); + $this->assertEquals('test', $column->cellType); + + $column->type('test'); + $this->assertEquals('test', $column->type); + + $column->contentPadding('test'); + $this->assertEquals('test', $column->contentPadding); + + $column->createdCell('test'); + $this->assertEquals('test', $column->createdCell); + + $column->titleAttr('test'); + $this->assertEquals('test', $column->titleAttr); + + $column->exportFormat('test'); + $this->assertEquals('test', $column->exportFormat); + } + + #[Test] + public function it_can_render_scripts() + { + $column = Column::make('name'); + + $column->render('test'); + $this->assertEquals('function(data,type,full,meta){return test;}', $column->render); + + $column->render('$.fn.dataTable.render.test'); + $this->assertEquals('$.fn.dataTable.render.test', $column->render); + + $column->renderJs('test'); + $this->assertEquals('$.fn.dataTable.render.test', $column->render); + + $column->renderRaw('test'); + $this->assertEquals('test', $column->render); + } + + #[Test] + public function it_allows_orthogonal_data() + { + $expected = [ + '_' => 'test', + 'sort' => 'test', + 'filter' => 'test', + 'type' => 'test', + ]; + $column = Column::make('name')->data($expected); + + $this->assertEquals($expected, $column->data); + } + + #[Test] + public function it_has_responsive_priority() + { + $column = Column::make('name'); + $column->responsivePriority(1); + + $this->assertEquals(1, $column->responsivePriority); + } + + #[Test] + public function it_can_add_class() + { + $column = Column::make('name')->className('text-sm'); + $this->assertEquals('text-sm', $column->className); + + $column->addClass('font-bold'); + $this->assertEquals('text-sm font-bold', $column->className); + } + + #[Test] + public function it_has_authorizations() + { + $column = Column::makeIf(true, 'name'); + $this->assertEquals([ + 'name' => 'name', + 'data' => 'name', + 'title' => 'Name', + 'orderable' => true, + 'searchable' => true, + 'attributes' => [], + ], $column->toArray()); + + $column = Column::makeIf(false, 'name'); + $this->assertEquals([], $column->toArray()); + } + + #[Test] + public function it_can_be_serialized() + { + $column = Column::make('name'); + $this->assertEquals([ + 'name' => 'name', + 'data' => 'name', + 'title' => 'Name', + 'orderable' => true, + 'searchable' => true, + 'attributes' => [], + ], $column->toArray()); + + $expected = '{"data":"name","name":"name","title":"Name","orderable":true,"searchable":true,"attributes":[]}'; + $this->assertEquals($expected, $column->toJson()); + } +} diff --git a/tests/Html/Editor/EditorFormOptionsTest.php b/tests/Html/Editor/EditorFormOptionsTest.php new file mode 100644 index 0000000..ae45186 --- /dev/null +++ b/tests/Html/Editor/EditorFormOptionsTest.php @@ -0,0 +1,52 @@ +assertInstanceOf(FormOptions::class, $options); + + $options->focus(1) + ->message('message') + ->onBackground('onBackground') + ->onBlur('onBlur') + ->onComplete('onComplete') + ->onEsc('onEsc') + ->onFieldError('onFieldError') + ->onReturn('onReturn') + ->submit('submit') + ->title('title') + ->drawType('drawType') + ->formScope('scope') + ->nest(false) + ->buttons([]) + ->submitTrigger(1) + ->submitHtml('submitHtml'); + + $this->assertEquals(1, $options->focus); + $this->assertEquals('message', $options->message); + $this->assertEquals('onBackground', $options->onBackground); + $this->assertEquals('onBlur', $options->onBlur); + $this->assertEquals('onComplete', $options->onComplete); + $this->assertEquals('onEsc', $options->onEsc); + $this->assertEquals('onFieldError', $options->onFieldError); + $this->assertEquals('onReturn', $options->onReturn); + $this->assertEquals('submit', $options->submit); + $this->assertEquals('title', $options->title); + $this->assertEquals('drawType', $options->drawType); + $this->assertEquals('scope', $options->scope); + $this->assertEquals(false, $options->nest); + $this->assertEquals([], $options->buttons); + $this->assertEquals(1, $options->submitTrigger); + $this->assertEquals('submitHtml', $options->submitHtml); + } +} diff --git a/tests/Html/Editor/EditorTest.php b/tests/Html/Editor/EditorTest.php new file mode 100644 index 0000000..fbb2fd3 --- /dev/null +++ b/tests/Html/Editor/EditorTest.php @@ -0,0 +1,197 @@ +getEditor(); + + $this->assertInstanceOf(Editor::class, $editor); + $this->assertEquals('editor', $editor->instance); + $this->assertEmpty($editor->fields); + $this->assertEmpty($editor->ajax); + $this->assertEmpty($editor->template); + + $editor + ->idSrc() + ->fields([ + Text::make('name'), + ]) + ->ajax('/test') + ->template('#template'); + + $this->assertCount(1, $editor->fields); + $this->assertEquals('/test', $editor->ajax); + $this->assertEquals('#template', $editor->template); + $this->assertEquals('DT_RowId', $editor->idSrc); + } + + protected function getEditor(string $instance = 'editor'): Editor + { + return Editor::make($instance); + } + + #[Test] + public function it_can_have_events() + { + $editor = $this->getEditor(); + + $editor->onPostSubmit('post'); + $editor->onDisplayOrder('display'); + + $this->assertCount(2, $editor->events); + + $event = [ + 'event' => 'postSubmit', + 'script' => 'post', + ]; + + $this->assertEquals($event, $editor->events[0]); + } + + #[Test] + public function it_can_show_hide_fields() + { + $editor = $this->getEditor(); + + $editor->hiddenOnCreate(['name']); + $editor->hiddenOnEdit(['email']); + + $this->assertCount(2, $editor->events); + + $this->assertEquals('preOpen', $editor->events[0]['event']); + $this->assertStringContainsString("action === 'create'", $editor->events[0]['script']); + $this->assertStringContainsString("this.hide('name')", $editor->events[0]['script']); + + $this->assertEquals('preOpen', $editor->events[1]['event']); + $this->assertStringContainsString("action === 'edit'", $editor->events[1]['script']); + $this->assertStringContainsString("this.hide('email')", $editor->events[1]['script']); + } + + #[Test] + public function it_has_authorizations() + { + $editor = Editor::makeIf(true, 'editor') + ->fields([ + Text::make('name'), + ]); + $this->assertInstanceOf(Editor::class, $editor); + $this->assertEquals(true, $editor->isAuthorized()); + $this->assertEquals([ + 'instance' => 'editor', + 'fields' => [ + Text::make('name')->toArray(), + ], + ], $editor->toArray()); + + $editor = Editor::makeIf(false, 'editor') + ->fields([ + Text::make('name'), + ]); + $this->assertInstanceOf(Editor::class, $editor); + $this->assertEquals(false, $editor->isAuthorized()); + $this->assertCount(1, $editor->fields); + $this->assertEquals([], $editor->toArray()); + + $editor = Editor::makeIfCan('ability', 'editor'); + $this->assertInstanceOf(Editor::class, $editor); + $this->assertEquals(false, $editor->isAuthorized()); + $this->assertEquals([], $editor->toArray()); + + $editor = Editor::makeIfCannot('ability', 'editor'); + $this->assertInstanceOf(Editor::class, $editor); + $this->assertEquals(false, $editor->isAuthorized()); + $this->assertEquals([], $editor->toArray()); + } + + #[Test] + public function it_can_be_serialized_to_array() + { + $editor = Editor::make() + ->ajax('') + ->fields([ + Text::make('name'), + ]); + + $this->assertEquals([ + 'instance' => 'editor', + 'ajax' => '', + 'fields' => [ + Text::make('name')->toArray(), + ], + ], $editor->toArray()); + } + + #[Test] + public function it_can_be_serialized_to_json_string() + { + $editor = Editor::make() + ->ajax('') + ->fields([ + Text::make('name'), + ]); + + $expected = '{"instance":"editor","ajax":"","fields":[{"name":"name","label":"Name","type":"text"}]}'; + $this->assertEquals($expected, $editor->toJson()); + } + + #[Test] + public function it_has_form_options() + { + $editor = Editor::make() + ->formOptions([ + 'main' => [ + 'esc' => true, + ], + ]); + + $this->assertEquals([ + 'main' => [ + 'esc' => true, + ], + ], $editor->formOptions); + + $editor->formOptionsMain(['esc' => true]); + $this->assertEquals(['esc' => true], $editor->formOptions['main']); + + $editor->formOptionsBubble(['esc' => true]); + $this->assertEquals(['esc' => true], $editor->formOptions['bubble']); + + $editor->formOptionsInline(['esc' => true]); + $this->assertEquals(['esc' => true], $editor->formOptions['inline']); + } + + #[Test] + public function it_has_display_constants() + { + $editor = Editor::make()->display(Editor::DISPLAY_BOOTSTRAP); + $this->assertEquals('bootstrap', $editor->display); + + $editor->display(Editor::DISPLAY_ENVELOPE); + $this->assertEquals('envelope', $editor->display); + + $editor->display(Editor::DISPLAY_FOUNDATION); + $this->assertEquals('foundation', $editor->display); + + $editor->display(Editor::DISPLAY_JQUERYUI); + $this->assertEquals('jqueryui', $editor->display); + + $editor->display(Editor::DISPLAY_LIGHTBOX); + $this->assertEquals('lightbox', $editor->display); + } + + #[Test] + public function it_has_scripts() + { + $editor = Editor::make()->scripts('fn'); + $this->assertEquals('fn', $editor->scripts); + } +} diff --git a/tests/Html/Editor/Fields/FieldOptionsTest.php b/tests/Html/Editor/Fields/FieldOptionsTest.php new file mode 100644 index 0000000..413dab6 --- /dev/null +++ b/tests/Html/Editor/Fields/FieldOptionsTest.php @@ -0,0 +1,91 @@ +assertEquals([ + ['label' => __('True'), 'value' => 1], + ['label' => __('False'), 'value' => 0], + ], $options->toArray()); + } + + #[Test] + public function it_has_yes_no() + { + $options = Options::yesNo(); + + $this->assertEquals([ + ['label' => __('Yes'), 'value' => 1], + ['label' => __('No'), 'value' => 0], + ], $options->toArray()); + } + + #[Test] + public function it_can_append_and_prepend() + { + $options = Options::yesNo(); + + $this->assertEquals([ + ['label' => __('Yes'), 'value' => 1], + ['label' => __('No'), 'value' => 0], + ], $options->toArray()); + + $options->append(__('Maybe'), 2); + $this->assertEquals([ + ['label' => __('Yes'), 'value' => 1], + ['label' => __('No'), 'value' => 0], + ['label' => __('Maybe'), 'value' => 2], + ], $options->toArray()); + + $options->prepend(__('IDK'), 3); + $this->assertEquals([ + ['label' => __('IDK'), 'value' => 3], + ['label' => __('Yes'), 'value' => 1], + ['label' => __('No'), 'value' => 0], + ['label' => __('Maybe'), 'value' => 2], + ], $options->toArray()); + } + + #[Test] + public function it_can_get_options_from_table() + { + $options = Options::table('users', 'name'); + $this->assertCount(20, $options); + } + + #[Test] + public function it_can_get_options_from_query() + { + $options = Options::table(DB::table('users')->where('id', 1), 'name'); + $this->assertCount(1, $options); + } + + #[Test] + public function it_can_get_options_from_model() + { + $options = Options::model(User::class, 'name'); + $this->assertCount(20, $options); + } + + #[Test] + public function it_can_get_options_from_model_builder() + { + $options = Options::model(User::query()->whereKey(1), 'name'); + $this->assertCount(1, $options); + } +} diff --git a/tests/Html/Editor/Fields/FieldTest.php b/tests/Html/Editor/Fields/FieldTest.php new file mode 100644 index 0000000..bba6ef4 --- /dev/null +++ b/tests/Html/Editor/Fields/FieldTest.php @@ -0,0 +1,296 @@ +assertInstanceOf(Fields\Field::class, $field); + $this->assertEquals('Name', $field->label); + $this->assertEquals('name', $field->name); + $this->assertEquals('text', $field->getType()); + } + + #[Test] + public function it_can_set_properties() + { + $field = Fields\Field::make('name'); + + $field->label('Test'); + $field->name('Test'); + $field->data('Test'); + $field->type('Test'); + + $this->assertEquals('Test', $field->label); + $this->assertEquals('Test', $field->name); + $this->assertEquals('Test', $field->data); + $this->assertEquals('Test', $field->getType()); + } + + #[Test] + public function it_can_create_belongs_to_field() + { + $field = Fields\BelongsTo::model(User::class, 'name'); + $this->assertInstanceOf(Fields\BelongsTo::class, $field); + $this->assertEquals('select', $field->getType()); + $this->assertEquals('user_id', $field->name); + $this->assertEquals('User', $field->label); + } + + #[Test] + public function it_can_create_boolean_field() + { + $field = Fields\Boolean::make('name'); + $this->assertInstanceOf(Fields\Boolean::class, $field); + $this->assertEquals('checkbox', $field->getType()); + $this->assertEquals('name', $field->name); + $this->assertEquals('Name', $field->label); + $this->assertEquals(',', $field->separator); + $this->assertEquals([['label' => '', 'value' => 1]], $field->options); + } + + #[Test] + public function it_can_create_date_field() + { + $field = Fields\Date::make('name'); + $this->assertInstanceOf(Fields\Date::class, $field); + $this->assertEquals('datetime', $field->getType()); + $this->assertEquals('name', $field->name); + $this->assertEquals('Name', $field->label); + $this->assertEquals('YYYY-MM-DD', $field->format); + } + + #[Test] + public function it_can_create_datetime_field() + { + $field = Fields\DateTime::make('name'); + $this->assertInstanceOf(Fields\DateTime::class, $field); + $this->assertEquals('datetime', $field->getType()); + $this->assertEquals('name', $field->name); + $this->assertEquals('Name', $field->label); + $this->assertEquals('YYYY-MM-DD hh:mm a', $field->format); + + $field->military(); + $this->assertEquals('YYYY-MM-DD HH:mm', $field->format); + + $min = now(); + $field->minDate($min); + $date = $min->format('Y-m-d'); + $this->assertEquals("new Date('$date')", $field->opts['minDate']); + + $max = now(); + $field->maxDate($max); + $date = $max->format('Y-m-d'); + $this->assertEquals("new Date('$date')", $field->opts['maxDate']); + + $field->showWeekNumber(false); + $this->assertEquals(false, $field->opts['showWeekNumber']); + + $field->disableDays([1, 2, 3]); + $this->assertEquals([1, 2, 3], $field->opts['disableDays']); + + $field->minutesIncrement(2); + $this->assertEquals(2, $field->opts['minutesIncrement']); + + $field->secondsIncrement(2); + $this->assertEquals(2, $field->opts['secondsIncrement']); + + $field->hoursAvailable([1, 2]); + $this->assertEquals([1, 2], $field->opts['hoursAvailable']); + + $field->minutesAvailable([1, 2]); + $this->assertEquals([1, 2], $field->opts['minutesAvailable']); + + $field->keyInput(false); + $this->assertEquals(false, $field->getAttributes()['keyInput']); + + $field->displayFormat('LLL'); + $this->assertEquals('LLL', $field->getAttributes()['displayFormat']); + + $field->wireFormat('LLL'); + $this->assertEquals('LLL', $field->getAttributes()['wireFormat']); + } + + #[Test] + public function it_can_create_file_field() + { + $field = Fields\File::make('name'); + $this->assertInstanceOf(Fields\File::class, $field); + $this->assertEquals('upload', $field->getType()); + // TODO: add more file field test + } + + #[Test] + public function it_can_create_hidden_field() + { + $field = Fields\Hidden::make('name'); + $this->assertInstanceOf(Fields\Hidden::class, $field); + $this->assertEquals('hidden', $field->getType()); + } + + #[Test] + public function it_can_create_image_field() + { + $field = Fields\Image::make('name'); + $this->assertInstanceOf(Fields\Image::class, $field); + $this->assertEquals('upload', $field->getType()); + } + + #[Test] + public function it_can_create_number_field() + { + $field = Fields\Number::make('name'); + $this->assertInstanceOf(Fields\Number::class, $field); + $this->assertEquals('text', $field->getType()); + } + + #[Test] + public function it_can_create_password_field() + { + $field = Fields\Password::make('name'); + $this->assertInstanceOf(Fields\Password::class, $field); + $this->assertEquals('password', $field->getType()); + } + + #[Test] + public function it_can_create_radio_field() + { + $field = Fields\Radio::make('name'); + $this->assertInstanceOf(Fields\Radio::class, $field); + $this->assertEquals('radio', $field->getType()); + } + + #[Test] + public function it_can_create_read_only_field() + { + $field = Fields\ReadOnlyField::make('name'); + $this->assertInstanceOf(Fields\ReadOnlyField::class, $field); + $this->assertEquals('readonly', $field->getType()); + } + + #[Test] + public function it_can_create_select_field() + { + $field = Fields\Select::make('name'); + $this->assertInstanceOf(Fields\Select::class, $field); + $this->assertEquals('select', $field->getType()); + } + + #[Test] + public function it_can_create_select2_field() + { + $field = Fields\Select2::make('name') + ->allowClear() + ->optsPlaceholder('Test') + ->modelOptions(User::class, 'name') + ->ajax('/url'); + + $this->assertInstanceOf(Fields\Select2::class, $field); + $this->assertEquals('select2', $field->getType()); + $this->assertEquals('/url', $field->opts['ajax']['url']); + $this->assertEquals('Test', $field->opts['placeholder']['text']); + $this->assertEquals('', $field->opts['placeholder']['id']); + $this->assertCount(20, $field->options); + + $field->processResults('fn'); + $this->assertEquals('fn', $field->opts['ajax']['processResults']); + + $field->processPaginatedResults('username', 'user_id'); + $this->assertEquals('/url', $field->opts['ajax']['url']); + $this->assertStringContainsString('e.text = e.username', $field->opts['ajax']['processResults']); + $this->assertStringContainsString('e.id = e.user_id', $field->opts['ajax']['processResults']); + $this->assertStringContainsString('data.results.map', $field->opts['ajax']['processResults']); + + $field->processPaginatedResults('username', 'user_id', 'data'); + $this->assertStringContainsString('data.data.map', $field->opts['ajax']['processResults']); + + $field->placeholder('New Placeholder'); + $this->assertEquals('New Placeholder', $field->opts['placeholder']['text']); + + $field->ajaxData('fn'); + $this->assertEquals('fn', $field->opts['ajax']['data']); + + $field->ajaxData(['foo' => 'bar']); + $this->assertStringContainsString('params.foo = "bar"', $field->opts['ajax']['data']); + + $field->ajaxDelay(200); + $this->assertEquals(200, $field->opts['ajax']['delay']); + + $field->ajaxUrl('/test'); + $this->assertEquals('/test', $field->opts['ajax']['url']); + } + + #[Test] + public function it_can_create_text_field() + { + $field = Fields\Text::make('name') + ->attr('style', 'display: none;'); + + $this->assertInstanceOf(Fields\Text::class, $field); + $this->assertEquals('text', $field->getType()); + $this->assertEquals('display: none;', $field->attr['style']); + } + + #[Test] + public function it_can_create_textarea_field() + { + $field = Fields\TextArea::make('name'); + $this->assertInstanceOf(Fields\TextArea::class, $field); + $this->assertEquals('textarea', $field->getType()); + + $field->rows(5); + $this->assertEquals('5', $field->attr['rows']); + + $field->cols(5); + $this->assertEquals('5', $field->attr['cols']); + } + + #[Test] + public function it_can_create_time_field() + { + $field = Fields\Time::make('name'); + $this->assertInstanceOf(Fields\Time::class, $field); + $this->assertEquals('datetime', $field->getType()); + $this->assertEquals('name', $field->name); + $this->assertEquals('Name', $field->label); + $this->assertEquals('hh:mm a', $field->format); + } + + #[Test] + public function it_has_authorizations() + { + $field = Fields\Text::makeIf(true, 'name'); + $this->assertEquals([ + 'name' => 'name', + 'label' => 'Name', + 'type' => 'text', + ], $field->toArray()); + + $field = Fields\Text::makeIf(false, 'name'); + $this->assertEquals([], $field->toArray()); + } + + #[Test] + public function it_can_be_serialized() + { + $field = Fields\Text::make('name')->data('user.name'); + + $this->assertEquals([ + 'name' => 'name', + 'data' => 'user.name', + 'label' => 'Name', + 'type' => 'text', + ], $field->toArray()); + + $this->assertEquals('{"name":"name","label":"Name","type":"text","data":"user.name"}', $field->toJson()); + } +} diff --git a/tests/Html/Editor/Fields/TagsTest.php b/tests/Html/Editor/Fields/TagsTest.php new file mode 100644 index 0000000..da466e0 --- /dev/null +++ b/tests/Html/Editor/Fields/TagsTest.php @@ -0,0 +1,139 @@ +ajax('/tags'); + + $this->assertSame('/tags', $field->toArray()['ajax']); + } + + #[Test] + public function it_can_set_tags_display(): void + { + $field = new Tags; + $field->display('display'); + + $this->assertSame('display', $field->toArray()['display']); + } + + #[Test] + public function it_can_set_tags_escape_label_html(): void + { + $field = new Tags; + $field->escapeLabelHtml(true); + + $this->assertTrue($field->toArray()['escapeLabelHtml']); + } + + #[Test] + public function it_can_set_tags_i18n_props_directly(): void + { + $field = new Tags; + $field->addButton('Add Tag'); + $this->assertSame('Add Tag', $field->toArray()['i18n']['addButton']); + } + + #[Test] + public function it_can_set_tags_i18n(): void + { + $field = new Tags; + $field->i18n([ + 'addButton' => 'Add', + 'inputPlaceholder' => 'Input', + 'noResults' => 'No Results', + 'title' => 'Title', + 'placeholder' => 'Placeholder', + ]); + + $this->assertSame('Add', $field->toArray()['i18n']['addButton']); + $this->assertSame('Input', $field->toArray()['i18n']['inputPlaceholder']); + $this->assertSame('No Results', $field->toArray()['i18n']['noResults']); + $this->assertSame('Title', $field->toArray()['i18n']['title']); + $this->assertSame('Placeholder', $field->toArray()['i18n']['placeholder']); + + $field->addButton('Add Button') + ->inputPlaceholder('Input Placeholder') + ->noResults('No Results X') + ->title('Title X') + ->placeholder('Placeholder X'); + + $this->assertSame('Add Button', $field->toArray()['i18n']['addButton']); + $this->assertSame('Input Placeholder', $field->toArray()['i18n']['inputPlaceholder']); + $this->assertSame('No Results X', $field->toArray()['i18n']['noResults']); + $this->assertSame('Title X', $field->toArray()['i18n']['title']); + $this->assertSame('Placeholder X', $field->toArray()['i18n']['placeholder']); + } + + #[Test] + public function it_can_set_tags_type(): void + { + $field = new Tags; + + $this->assertSame('tags', $field->toArray()['type']); + } + + #[Test] + public function it_can_set_tags_limit(): void + { + $field = new Tags; + $field->limit(2); + + $this->assertSame(2, $field->toArray()['limit']); + } + + #[Test] + public function it_can_set_tags_multiple(): void + { + $field = new Tags; + $field->multiple(); + + $this->assertTrue($field->toArray()['multiple']); + } + + #[Test] + public function it_can_set_tags_options(): void + { + $field = new Tags; + $field->options(['tag1', 'tag2']); + + $this->assertSame(['tag1', 'tag2'], $field->toArray()['options']); + + $field->options([ + ['value' => 'tag1', 'label' => 'Tag 1'], + ['value' => 'tag2', 'label' => 'Tag 2'], + ]); + + $this->assertSame([ + ['value' => 'tag1', 'label' => 'Tag 1'], + ['value' => 'tag2', 'label' => 'Tag 2'], + ], $field->toArray()['options']); + } + + #[Test] + public function it_can_set_tags_separator(): void + { + $field = new Tags; + $field->separator(','); + + $this->assertSame(',', $field->toArray()['separator']); + } + + #[Test] + public function it_can_set_tags_unique(): void + { + $field = new Tags; + $field->unique(); + + $this->assertTrue($field->toArray()['unique']); + } +} diff --git a/tests/Html/Extensions/SearchPaneTest.php b/tests/Html/Extensions/SearchPaneTest.php new file mode 100644 index 0000000..48fd975 --- /dev/null +++ b/tests/Html/Extensions/SearchPaneTest.php @@ -0,0 +1,76 @@ +className('className') + ->header('header') + ->show() + ->name('name') + ->orthogonal('orthogonal') + ->hideTotal() + ->threshold(1) + ->hideCount() + ->filterChanged('filterChanged') + ->emptyMessage('emptyMessage') + ->dtOpts([]) + ->controls() + ->columns([]) + ->clear() + ->cascadePanes(); + + $this->assertInstanceOf(SearchPane::class, $pane); + $this->assertEquals('className', $pane->className); + $this->assertEquals('header', $pane->header); + $this->assertEquals(true, $pane->show); + $this->assertEquals('name', $pane->name); + $this->assertEquals('orthogonal', $pane->orthogonal); + $this->assertEquals(false, $pane->viewTotal); + $this->assertEquals(1, $pane->threshold); + $this->assertEquals(true, $pane->hideCount); + $this->assertEquals('filterChanged', $pane->filterChanged); + $this->assertEquals('emptyMessage', $pane->emptyMessage); + $this->assertEquals([], $pane->dtOpts); + $this->assertEquals(true, $pane->controls); + $this->assertEquals([], $pane->columns); + $this->assertEquals(true, $pane->clear); + $this->assertEquals(true, $pane->cascadePanes); + + $pane->viewTotal(); + $this->assertEquals(true, $pane->viewTotal); + } + + #[Test] + public function it_has_options() + { + $pane = SearchPane::make()->options([1, 2, 3]); + + $this->assertEquals([1, 2, 3], $pane->options); + $this->assertCount(3, $pane->options); + + $pane->modelOptions(User::class, 'name'); + $this->assertCount(20, $pane->options); + $this->assertIsArray($pane->options[0]); + $this->assertEquals(['value' => 1, 'label' => 'Record-1'], $pane->options[0]); + $this->assertEquals(['value' => 10, 'label' => 'Record-10'], $pane->options[9]); + + $pane->tableOptions('users', 'name'); + $this->assertCount(20, $pane->options); + $this->assertIsArray($pane->options[0]); + $this->assertEquals(['value' => 1, 'label' => 'Record-1'], $pane->options[0]); + $this->assertEquals(['value' => 10, 'label' => 'Record-10'], $pane->options[9]); + } +} diff --git a/tests/HtmlBuilderTest.php b/tests/HtmlBuilderTest.php deleted file mode 100644 index cdf28fc..0000000 --- a/tests/HtmlBuilderTest.php +++ /dev/null @@ -1,231 +0,0 @@ -getHtmlBuilder([ - 'class' => 'table', - 'id' => 'dataTableBuilder', - ]); - - $builder->html->shouldReceive('attributes')->times(10)->andReturn('id="foo"'); - - $builder->columns(['foo', 'bar' => ['data' => 'foo'], 'biz' => ['name' => 'baz']]) - ->addCheckbox(['id' => 'foo']) - ->addColumn(['name' => 'id', 'data' => 'id', 'title' => 'Id']) - ->addColumn(['data' => 'meh', 'title' => 'Muh']) - ->add(new Column(['name' => 'a', 'data' => 'a', 'title' => 'A'])) - ->addAction(['title' => 'Options']) - ->ajax('ajax-url') - ->parameters(['bFilter' => false]); - $table = $builder->table(['id' => 'foo'])->toHtml(); - $expected = '
    FooBarBizIdMuhAOptions
    '; - $this->assertEquals($expected, $table); - - $builder->view->shouldReceive('make')->times(2)->andReturn($builder->view); - $builder->config->shouldReceive('get')->times(2)->andReturn('datatables::script'); - $template = file_get_contents(__DIR__ . '/../src/resources/views/script.blade.php'); - $builder->view->shouldReceive('render')->times(2)->andReturn(trim($template)); - $builder->html->shouldReceive('attributes')->once()->andReturn(); - - $script = $builder->scripts()->toHtml(); - $expected = '' . "\n"; - $this->assertEquals($expected, $script); - - $expected = '$(function(){window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}=window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}||{};window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}["foo"]=$("#foo").DataTable({"serverSide":true,"processing":true,"ajax":"ajax-url","columns":[{"name":"foo","data":"foo","title":"Foo","orderable":true,"searchable":true},{"name":"foo","data":"foo","title":"Bar","orderable":true,"searchable":true},{"name":"baz","data":"biz","title":"Biz","orderable":true,"searchable":true},{"defaultContent":"","title":"","data":"checkbox","name":"checkbox","orderable":false,"searchable":false,"width":"10px","id":"foo"},{"name":"id","data":"id","title":"Id","orderable":true,"searchable":true},{"data":"meh","title":"Muh","orderable":true,"searchable":true,"name":"meh"},{"name":"a","data":"a","title":"A","orderable":true,"searchable":true},{"defaultContent":"","data":"action","name":"action","title":"Options","render":null,"orderable":false,"searchable":false}],"bFilter":false});});'; - $this->assertEquals($expected, $builder->generateScripts()->toHtml()); - } - - /** - * @return \Mockery\MockInterface|\Yajra\DataTables\Html\Builder - */ - protected function getHtmlBuilder($config = []) - { - $builder = app('datatables.html', $config); - - return $builder; - } - - public function test_generate_table_html_with_empty_footer() - { - $builder = $this->getHtmlBuilder([ - 'class' => 'table', - 'id' => 'dataTableBuilder', - ]); - $builder->html->shouldReceive('attributes')->times(8)->andReturn('id="foo"'); - - $builder->columns(['foo', 'bar' => ['data' => 'foo']]) - ->addCheckbox(['id' => 'foo']) - ->addColumn(['name' => 'id', 'data' => 'id', 'title' => 'Id']) - ->add(new Column(['name' => 'a', 'data' => 'a', 'title' => 'A'])) - ->addAction(['title' => 'Options']) - ->ajax('ajax-url') - ->parameters(['bFilter' => false]); - $table = $builder->table(['id' => 'foo'], true)->toHtml(); - $expected = '
    FooBarIdAOptions
    '; - $this->assertEquals($expected, $table); - - $builder->view->shouldReceive('make')->times(2)->andReturn($builder->view); - $builder->config->shouldReceive('get')->times(2)->andReturn('datatables::script'); - $template = file_get_contents(__DIR__ . '/../src/resources/views/script.blade.php'); - $builder->view->shouldReceive('render')->times(2)->andReturn(trim($template)); - $builder->html->shouldReceive('attributes')->once()->andReturn(); - - $script = $builder->scripts()->toHtml(); - $expected = '' . "\n"; - $this->assertEquals($expected, $script); - - $expected = '$(function(){window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}=window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}||{};window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}["foo"]=$("#foo").DataTable({"serverSide":true,"processing":true,"ajax":"ajax-url","columns":[{"name":"foo","data":"foo","title":"Foo","orderable":true,"searchable":true},{"name":"foo","data":"foo","title":"Bar","orderable":true,"searchable":true},{"defaultContent":"","title":"","data":"checkbox","name":"checkbox","orderable":false,"searchable":false,"width":"10px","id":"foo"},{"name":"id","data":"id","title":"Id","orderable":true,"searchable":true},{"name":"a","data":"a","title":"A","orderable":true,"searchable":true},{"defaultContent":"","data":"action","name":"action","title":"Options","render":null,"orderable":false,"searchable":false}],"bFilter":false});});'; - $this->assertEquals($expected, $builder->generateScripts()->toHtml()); - } - - public function test_generate_table_html_with_footer_content() - { - $builder = $this->getHtmlBuilder([ - 'class' => 'table', - 'id' => 'dataTableBuilder', - ]); - $builder->html->shouldReceive('attributes')->times(8)->andReturn('id="foo"'); - - $builder->columns(['foo', 'bar' => ['data' => 'foo']]) - ->addCheckbox(['id' => 'foo', 'footer' => 'test']) - ->addColumn(['name' => 'id', 'data' => 'id', 'title' => 'Id']) - ->add(new Column(['name' => 'a', 'data' => 'a', 'title' => 'A'])) - ->addAction(['title' => 'Options']) - ->ajax('ajax-url') - ->parameters(['bFilter' => false]); - $table = $builder->table(['id' => 'foo'], true)->toHtml(); - $expected = '
    FooBarIdAOptions
    test
    '; - $this->assertEquals($expected, $table); - - $builder->view->shouldReceive('make')->times(2)->andReturn($builder->view); - $builder->config->shouldReceive('get')->times(2)->andReturn('datatables::script'); - $template = file_get_contents(__DIR__ . '/../src/resources/views/script.blade.php'); - $builder->view->shouldReceive('render')->times(2)->andReturn(trim($template)); - $builder->html->shouldReceive('attributes')->once()->andReturn(); - - $script = $builder->scripts()->toHtml(); - $expected = '' . "\n"; - $this->assertEquals($expected, $script); - - $expected = '$(function(){window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}=window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}||{};window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}["foo"]=$("#foo").DataTable({"serverSide":true,"processing":true,"ajax":"ajax-url","columns":[{"name":"foo","data":"foo","title":"Foo","orderable":true,"searchable":true},{"name":"foo","data":"foo","title":"Bar","orderable":true,"searchable":true},{"defaultContent":"","title":"","data":"checkbox","name":"checkbox","orderable":false,"searchable":false,"width":"10px","id":"foo"},{"name":"id","data":"id","title":"Id","orderable":true,"searchable":true},{"name":"a","data":"a","title":"A","orderable":true,"searchable":true},{"defaultContent":"","data":"action","name":"action","title":"Options","render":null,"orderable":false,"searchable":false}],"bFilter":false});});'; - $this->assertEquals($expected, $builder->generateScripts()->toHtml()); - } - - public function test_generate_table_html_with_render_helpers() - { - $builder = $this->getHtmlBuilder([ - 'class' => 'table', - 'id' => 'dataTableBuilder', - ]); - - $builder->html->shouldReceive('attributes')->times(10)->andReturn('id="foo"'); - - $builder->columns(['foo', 'bar' => ['data' => 'foo'], 'biz' => ['name' => 'baz']]) - ->addCheckbox(['id' => 'foo']) - ->addColumn(['data' => '1.0000', 'title' => 'Num', 'render' => '$.fn.dataTable.render.number( ",", ".", 2, "" )']) - ->addColumn(['data' => '
    ', 'title' => 'Tex', 'render' => '$.fn.dataTable.render.text()']) - ->addAction(['title' => 'Options']) - ->ajax('ajax-url') - ->parameters(['bFilter' => false]); - $table = $builder->table(['id' => 'foo'])->toHtml(); - $expected = '
    FooBarBizNumTexOptions
    '; - $this->assertEquals($expected, $table); - - $builder->view->shouldReceive('make')->times(2)->andReturn($builder->view); - $builder->config->shouldReceive('get')->times(2)->andReturn('datatables::script'); - $template = file_get_contents(__DIR__ . '/../src/resources/views/script.blade.php'); - $builder->view->shouldReceive('render')->times(2)->andReturn(trim($template)); - $builder->html->shouldReceive('attributes')->once()->andReturn(); - - $script = $builder->scripts()->toHtml(); - $expected = '' . "\n"; - $this->assertEquals($expected, $script); - - $expected = '$(function(){window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}=window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}||{};window.{{ config(\'datatables-html.namespace\', \'LaravelDataTables\') }}["foo"]=$("#foo").DataTable({"serverSide":true,"processing":true,"ajax":"ajax-url","columns":[{"name":"foo","data":"foo","title":"Foo","orderable":true,"searchable":true},{"name":"foo","data":"foo","title":"Bar","orderable":true,"searchable":true},{"name":"baz","data":"biz","title":"Biz","orderable":true,"searchable":true},{"defaultContent":"","title":"","data":"checkbox","name":"checkbox","orderable":false,"searchable":false,"width":"10px","id":"foo"},{"data":"1.0000","title":"Num","render":"$.fn.dataTable.render.number( \",\", \".\", 2, \"\" )","orderable":true,"searchable":true,"name":"1.0000"},{"data":"","title":"Tex","render":"$.fn.dataTable.render.text()","orderable":true,"searchable":true,"name":""},{"defaultContent":"","data":"action","name":"action","title":"Options","render":null,"orderable":false,"searchable":false}],"bFilter":false});});'; - $this->assertEquals($expected, $builder->generateScripts()->toHtml()); - } - - public function test_setting_table_attribute() - { - $builder = $this->getHtmlBuilder(); - - $builder->setTableAttribute('attr', 'val'); - - $this->assertEquals('val', $builder->getTableAttribute('attr')); - } - - public function test_setting_table_id_attribute() - { - $builder = $this->getHtmlBuilder(); - - $builder->setTableId('val'); - - $this->assertEquals('val', $builder->getTableAttribute('id')); - } - - public function test_settings_multiple_table_attributes() - { - $builder = $this->getHtmlBuilder(); - - $builder->setTableAttribute(['prop1' => 'val1', 'prop2' => 'val2']); - - $this->assertEquals('val1', $builder->getTableAttribute('prop1')); - $this->assertEquals('val2', $builder->getTableAttribute('prop2')); - } - - public function test_getting_inexistent_table_attribute_throws() - { - $this->expectExceptionMessage('Table attribute \'boohoo\' does not exist.'); - - $builder = $this->getHtmlBuilder(); - - $builder->getTableAttribute('boohoo'); - } - - public function test_adding_table_class_attribute() - { - $builder = $this->getHtmlBuilder(); - - $builder->addTableClass('foo'); - $this->assertEquals('foo', $builder->getTableAttribute('class')); - - $builder->addTableClass(' foo bar '); - $this->assertEquals('foo bar', $builder->getTableAttribute('class')); - - $builder->addTableClass([' a-b ', 'foo c bar', 'key' => 'value']); - $this->assertEquals('foo bar a-b c value', $builder->getTableAttribute('class')); - } - - public function test_removing_table_class_attribute() - { - $builder = $this->getHtmlBuilder(); - $builder->setTableAttribute('class', ' foo bar a b c '); - - $builder->removeTableClass('bar'); - $this->assertEquals('foo a b c', $builder->getTableAttribute('class')); - - $builder->removeTableClass(' x c y '); - $this->assertEquals('foo a b', $builder->getTableAttribute('class')); - - $builder->removeTableClass(['a' => ' b ', ' foo bar ']); - $this->assertEquals('a', $builder->getTableAttribute('class')); - } - - /** - * @return \Yajra\DataTables\Factory - */ - protected function getDataTables() - { - $factory = new Factory; - - return $factory; - } -} diff --git a/tests/Models/Post.php b/tests/Models/Post.php new file mode 100644 index 0000000..49f0df8 --- /dev/null +++ b/tests/Models/Post.php @@ -0,0 +1,21 @@ +belongsTo(User::class); + } +} diff --git a/tests/Models/Role.php b/tests/Models/Role.php new file mode 100644 index 0000000..5a0b4bb --- /dev/null +++ b/tests/Models/Role.php @@ -0,0 +1,16 @@ +belongsToMany(User::class); + } +} diff --git a/tests/Models/User.php b/tests/Models/User.php new file mode 100644 index 0000000..81909d6 --- /dev/null +++ b/tests/Models/User.php @@ -0,0 +1,28 @@ +hasMany(Post::class); + } + + public function roles(): BelongsToMany + { + return $this->belongsToMany(Role::class); + } + + public function user(): MorphTo + { + return $this->morphTo(); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..09a82ee --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,129 @@ +set('app.key', 'base64:6pASQ5U2UYo+w6noM9hwOPeHJ5vGP+BNruyMtRA8FWY='); + + $this->migrateDatabase(); + $this->seedDatabase(); + $this->setupViewAndBladeDirectory(); + } + + protected function migrateDatabase(): void + { + /** @var \Illuminate\Database\Schema\Builder $schemaBuilder */ + $schemaBuilder = $this->app['db']->connection()->getSchemaBuilder(); + if (! $schemaBuilder->hasTable('users')) { + $schemaBuilder->create('users', function (Blueprint $table) { + $table->increments('id'); + $table->string('name'); + $table->string('email'); + $table->string('user_type')->nullable(); + $table->unsignedInteger('user_id')->nullable(); + $table->timestamps(); + }); + } + if (! $schemaBuilder->hasTable('posts')) { + $schemaBuilder->create('posts', function (Blueprint $table) { + $table->increments('id'); + $table->string('title'); + $table->unsignedInteger('user_id'); + $table->timestamps(); + $table->softDeletes(); + }); + } + if (! $schemaBuilder->hasTable('roles')) { + $schemaBuilder->create('roles', function (Blueprint $table) { + $table->increments('id'); + $table->string('role'); + $table->timestamps(); + }); + } + if (! $schemaBuilder->hasTable('role_user')) { + $schemaBuilder->create('role_user', function (Blueprint $table) { + $table->unsignedInteger('role_id'); + $table->unsignedInteger('user_id'); + $table->timestamps(); + }); + } + } + + protected function seedDatabase(): void + { + $adminRole = Role::create(['role' => 'Administrator']); + $userRole = Role::create(['role' => 'User']); + + collect(range(1, 20))->each(function ($i) use ($userRole) { + /** @var User $user */ + $user = User::query()->create([ + 'name' => 'Record-'.$i, + 'email' => 'Email-'.$i.'@example.com', + ]); + + collect(range(1, 3))->each(function ($i) use ($user) { + $user->posts()->create([ + 'title' => "User-{$user->id} Post-{$i}", + ]); + }); + + if ($i % 2) { + $user->roles()->attach(Role::all()); + } else { + $user->roles()->attach($userRole); + } + }); + } + + /** + * Set up the environment. + * + * @param \Illuminate\Foundation\Application $app + */ + protected function getEnvironmentSetUp($app): void + { + $app['config']->set('app.debug', true); + $app['config']->set('database.default', 'sqlite'); + $app['config']->set('database.connections.sqlite', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + } + + protected function getPackageProviders($app): array + { + return [ + LivewireServiceProvider::class, + DataTablesServiceProvider::class, + HtmlServiceProvider::class, + ]; + } + + protected function getHtmlBuilder(): Builder + { + return app(Builder::class); + } + + protected function setupViewAndBladeDirectory(): void + { + View::addLocation(__DIR__.'/TestComponents'); + Blade::componentNamespace('Yajra\\DataTables\\Html\\Tests\\TestComponents', 'test'); + } +} diff --git a/tests/TestComponents/TestInlineView.php b/tests/TestComponents/TestInlineView.php new file mode 100644 index 0000000..a7f419a --- /dev/null +++ b/tests/TestComponents/TestInlineView.php @@ -0,0 +1,15 @@ +Test Inline View

    + blade; + } +} diff --git a/tests/TestComponents/TestLivewire.php b/tests/TestComponents/TestLivewire.php new file mode 100644 index 0000000..36277b4 --- /dev/null +++ b/tests/TestComponents/TestLivewire.php @@ -0,0 +1,15 @@ +test livewire + blade; + } +} diff --git a/tests/TestComponents/TestView.php b/tests/TestComponents/TestView.php new file mode 100644 index 0000000..7651711 --- /dev/null +++ b/tests/TestComponents/TestView.php @@ -0,0 +1,14 @@ +Test blade file

    diff --git a/tests/helper.php b/tests/helper.php deleted file mode 100644 index 95fe360..0000000 --- a/tests/helper.php +++ /dev/null @@ -1,61 +0,0 @@ -shouldReceive('get')->andReturn($config); - - return new Builder( - $configMock, - m::mock('Illuminate\Contracts\View\Factory'), - m::mock('Collective\Html\HtmlBuilder') - ); - case 'config': - return new Config; - case 'view': - return m::mock('Illuminate\Contracts\View\Factory', function ($mock) { - $mock->shouldReceive('exists')->andReturn(false); - }); - } - - return new Factory(); -} - -function view($view = null, array $data = []) -{ - if (! $view) { - return new BladeView(); - } - - return (new BladeView())->exists($view); -} - -/** - * Blade View Stub. - */ -class BladeView -{ - public function exists($view) - { - return false; - } -} - -class Config -{ - public function get($key) - { - $keys = explode('.', $key); - $config = require __DIR__ . '/../src/config/config.php'; - $config['builders'] = Arr::add($config['builders'], 'Mockery_8_Illuminate_Database_Query_Builder', 'query'); - - return $config[$keys[1]]; - } -}