diff --git a/config/twill.php b/config/twill.php index 26644077e..d66899fc7 100644 --- a/config/twill.php +++ b/config/twill.php @@ -143,6 +143,8 @@ 'tags_table' => 'twill_tags', 'users_oauth_table' => 'twill_users_oauth', 'users_table' => 'twill_users', + 'permissions_table' => 'permissions', + 'roles_table' => 'roles', /* |-------------------------------------------------------------------------- diff --git a/docs/content/1_docs/13_custom-cms-pages/1_index.md b/docs/content/1_docs/13_custom-cms-pages/1_index.md index 44641239c..3d129bed9 100644 --- a/docs/content/1_docs/13_custom-cms-pages/1_index.md +++ b/docs/content/1_docs/13_custom-cms-pages/1_index.md @@ -26,9 +26,9 @@ return [ - Add a controller to handle the request ```php -// file: app/Http/Controllers/Admin/CustomPageController.php +// file: app/Http/Controllers/Twill/CustomPageController.php -namespace App\Http\Controllers\Admin; +namespace App\Http\Controllers\Twill; use A17\Twill\Http\Controllers\Admin\Controller; @@ -36,7 +36,7 @@ class CustomPageController extends Controller { public function show() { - return view('admin.customPage'); + return view('twill.customPage'); } } ``` @@ -44,7 +44,7 @@ class CustomPageController extends Controller - And create the view ```php -// file: resources/views/admin/customPage.blade.php +// file: resources/views/twill/customPage.blade.php @extends('twill::layouts.free') diff --git a/docs/content/1_docs/3_modules/12_nested-modules.md b/docs/content/1_docs/3_modules/12_nested-modules.md index 1000d745a..c4b689ba2 100644 --- a/docs/content/1_docs/3_modules/12_nested-modules.md +++ b/docs/content/1_docs/3_modules/12_nested-modules.md @@ -151,17 +151,17 @@ use A17\Twill\Services\Breadcrumbs\NestedBreadcrumbs; class IssueArticleController extends BaseModuleController { + protected $moduleName = 'issues.articles'; protected $modelName = 'IssueArticle'; protected function setUpController(): void { - $this->setModuleName('issues.articles'); if (request('issue')) { $this->setBreadcrumbs( NestedBreadcrumbs::make() ->forParent( parentModule: 'issues', - module: $this->modelName, + module: $this->moduleName, activeParentId: request('issue'), repository: \App\Repositories\IssueRepository::class ) diff --git a/docs/content/1_docs/3_modules/6_table-builder.md b/docs/content/1_docs/3_modules/6_table-builder.md index 064648d6e..e73acbc2b 100644 --- a/docs/content/1_docs/3_modules/6_table-builder.md +++ b/docs/content/1_docs/3_modules/6_table-builder.md @@ -172,9 +172,9 @@ unpublished. ##### NestedData -`NestedData::make()` +`NestedData::make()->...` -This field requires no additional methods, it shows information about the nested models. +Renders the `field` using the relationship of the same name. It shows information and a link about the nested model. ##### Languages diff --git a/docs/content/1_docs/4_form-fields/01_input.md b/docs/content/1_docs/4_form-fields/01_input.md index dd45621d5..555265b7a 100644 --- a/docs/content/1_docs/4_form-fields/01_input.md +++ b/docs/content/1_docs/4_form-fields/01_input.md @@ -37,6 +37,7 @@ Input::make() type="textarea" :rows="3" :translated="true" + direction="ltr" /> ``` @@ -62,7 +63,8 @@ Input::make() 'note' => 'Hint message goes here', 'placeholder' => 'Placeholder goes here', 'type' => 'textarea', - 'rows' => 3 + 'rows' => 3, + 'direction' => 'ltr' ]) ``` @@ -85,6 +87,7 @@ Input::make() | readonly | Sets the field as readonly | boolean | false | | default | Sets a default value if empty | string | | | mask | Set a mask using the alpinejs mask plugin | string | | +| direction | Set custom input direction (from `v3.1.0`) | ltr
rtl
auto | auto | Specific options for the "number" type: @@ -122,3 +125,13 @@ Schema::table('articles', function (Blueprint $table) { ``` When used in a [block](../5_block-editor), no migration is needed, as data contained in blocks, including componentBlocks, is stored in a separate table from the model, which is managed by Twill for you. + +## Manually setting input direction + +Introduced in `v3.1.0` + +For certain types of input it maybe useful to manually set the direction to left-to-right (`ltr`) or right-to-left (`rtl`) depending upon the expected text input. + +For example, maybe you have an Arabic translated page and need URL which mixes Arabic with an `ltr` domain name and TLD. In this case content entry maybe proving difficult for your CMS users with a `rtl` input; in which case you may find setting the direction to `ltr` beneficial. + +You may also simply just need a single Hebrew text entry in an otherwise `ltr` form. diff --git a/docs/content/1_docs/4_form-fields/02_wysiwyg.md b/docs/content/1_docs/4_form-fields/02_wysiwyg.md index e95d733b2..64e146acb 100644 --- a/docs/content/1_docs/4_form-fields/02_wysiwyg.md +++ b/docs/content/1_docs/4_form-fields/02_wysiwyg.md @@ -101,20 +101,21 @@ $wysiwygOptions = [ ``` -| Option | Description | Type/values | Default value | -|:---------------|:-------------------------------------------------------------------------------------------------------------------------|:-----------------|:--------------| -| name | Name of the field | string | | -| label | Label of the field | string | | -| type | Type of wysiwyg field | quill
tiptap | tiptap | -| toolbarOptions | Array of options/tools that will be displayed in the editor | | See above | -| editSource | Displays a button to view source code | boolean | false | -| hideCounter | Hide the character counter displayed at the bottom | boolean | false | -| limitHeight | Limit the editor height from growing beyond the viewport | boolean | false | -| translated | Defines if the field is translatable | boolean | false | -| maxlength | Max character count of the field | integer | | -| note | Hint message displayed above the field | string | | -| placeholder | Text displayed as a placeholder in the field | string | | -| required | Displays an indicator that this field is required
A backend validation rule is required to prevent users from saving | boolean | false | +| Option | Description | Type/values | Default value | +|:---------------|:-------------------------------------------------------------------------------------------------------------------------|:--------------------|:--------------| +| name | Name of the field | string | | +| label | Label of the field | string | | +| type | Type of wysiwyg field | quill
tiptap | tiptap | +| toolbarOptions | Array of options/tools that will be displayed in the editor | | See above | +| editSource | Displays a button to view source code | boolean | false | +| hideCounter | Hide the character counter displayed at the bottom | boolean | false | +| limitHeight | Limit the editor height from growing beyond the viewport | boolean | false | +| translated | Defines if the field is translatable | boolean | false | +| maxlength | Max character count of the field | integer | | +| note | Hint message displayed above the field | string | | +| placeholder | Text displayed as a placeholder in the field | string | | +| required | Displays an indicator that this field is required
A backend validation rule is required to prevent users from saving | boolean | false | +| direction | Set custom input direction (from `v3.1.0`) | ltr
rtl
auto | auto | Note that Quill outputs CSS classes in the HTML for certain toolbar modules (indent, font, align, etc.), and that the image module is not integrated with Twill's media library. It outputs the base64 representation of the uploaded image. It is not a recommended way of using and storing images, prefer using one or multiple `medias` form fields or blocks fields for flexible content. This will give you greater control over your frontend output. @@ -171,3 +172,9 @@ For regular fields on models you will have to manually call `parseInternalLinks` ```blade {{ \A17\Twill\Facades\TwillUtil::parseInternalLinks($item->description) }} ``` + +## Manually setting input direction + +Introduced in `v3.1.0` + +For certain types of input it maybe useful to manually set the direction to left-to-right (`ltr`) or right-to-left (`rtl`) depending upon the expected text input; for example you may need a single Hebrew text entry in an otherwise `ltr` form. diff --git a/docs/content/1_docs/4_form-fields/06_multi-select.md b/docs/content/1_docs/4_form-fields/06_multi-select.md index ed61942f7..e71efe692 100644 --- a/docs/content/1_docs/4_form-fields/06_multi-select.md +++ b/docs/content/1_docs/4_form-fields/06_multi-select.md @@ -168,7 +168,7 @@ In this case that it can be implemented as follows: - Create a Sectors [module](../3_modules/2_cli-generator.md) ``` -php artisan twill:module sectors +php artisan twill:make:module sectors ``` - Create a migration for a pivot table. diff --git a/docs/content/2_guides/1_page-builder-with-blade/4_creating-the-page-module.md b/docs/content/2_guides/1_page-builder-with-blade/4_creating-the-page-module.md index 22f5b8cde..e8616efde 100644 --- a/docs/content/2_guides/1_page-builder-with-blade/4_creating-the-page-module.md +++ b/docs/content/2_guides/1_page-builder-with-blade/4_creating-the-page-module.md @@ -1,6 +1,6 @@ # Creating the page module -Now that we area ready with the initial setup of Laravel and Twill we can start building our CMS. +Now that we are ready with the initial setup of Laravel and Twill we can start building our CMS. In Twill we use Modules. A module is a single "content type" and exists out of a few files: diff --git a/frontend/js/components/Previewer.vue b/frontend/js/components/Previewer.vue index 99442af53..c2269689a 100755 --- a/frontend/js/components/Previewer.vue +++ b/frontend/js/components/Previewer.vue @@ -70,6 +70,7 @@ components: { 'a17-iframe': A17PreviewerFrame }, + props: ['breakpointsConfig'], data: function () { return { loadedCurrent: false, @@ -77,7 +78,7 @@ activeBreakpoint: 1280, lastActiveBreakpoint: 1280, scrollPosition: 0, - breakpoints: [ + breakpoints: this.breakpointsConfig || [ { size: 1280, name: 'preview-desktop' @@ -115,11 +116,12 @@ methods: { open: function (previewId = 0) { const self = this + const desktopWidth = this.breakpoints.find(item => item.name === 'preview-desktop').size // reset previewer state this.loadedCurrent = false - this.activeBreakpoint = 1280 - this.lastActiveBreakpoint = 1280 + this.activeBreakpoint = desktopWidth || 1280 + this.lastActiveBreakpoint = desktopWidth || 1280 function initPreview () { if (self.$refs.overlay) self.$refs.overlay.open() diff --git a/frontend/js/components/dashboard/shortcutCreator.vue b/frontend/js/components/dashboard/shortcutCreator.vue index f78614bd2..a5de344d4 100755 --- a/frontend/js/components/dashboard/shortcutCreator.vue +++ b/frontend/js/components/dashboard/shortcutCreator.vue @@ -83,13 +83,19 @@ border-bottom: 1px solid $color__border; } + .shortcutCreator .wrapper--reverse { + @include breakpoint('medium+') { + flex-flow: row-reverse; + } + } + .shortcutCreator__listing { display: flex; flex-grow: 1; flex-flow: column nowrap; @include breakpoint('small+') { - flex-flow: row nowrap; + flex-flow: row wrap; } } diff --git a/frontend/js/mixins/input.js b/frontend/js/mixins/input.js index 2fb813dd8..8be4ea446 100755 --- a/frontend/js/mixins/input.js +++ b/frontend/js/mixins/input.js @@ -12,6 +12,10 @@ export default { type: String, default: '' }, + direction: { + type: String, + default: 'auto' + }, name: { default: '' }, diff --git a/frontend/js/mixins/locale.js b/frontend/js/mixins/locale.js index e12e639c3..d191648d0 100755 --- a/frontend/js/mixins/locale.js +++ b/frontend/js/mixins/locale.js @@ -41,6 +41,9 @@ export default { else return false }, dirLocale: function () { + if (this.direction && this.direction !== 'auto') { + return this.direction; + } return (this.isLocaleRTL ? 'rtl' : 'auto') }, displayedLocale: function () { diff --git a/migrations/optional/permissions-management/2020_04_20_000001_support_permission.php b/migrations/optional/permissions-management/2020_04_20_000001_support_permission.php index 8faf8e869..bc4048a8e 100644 --- a/migrations/optional/permissions-management/2020_04_20_000001_support_permission.php +++ b/migrations/optional/permissions-management/2020_04_20_000001_support_permission.php @@ -16,15 +16,18 @@ class SupportPermission extends Migration */ public function up() { - if (!Schema::hasTable('permissions') + $permissionsTableName = config('twill.permissions_table', 'permissions'); + $rolesTableName = config('twill.roles_table', 'roles'); + + if (!Schema::hasTable($permissionsTableName) && !Schema::hasTable('groups') - && !Schema::hasTable('roles') + && !Schema::hasTable($rolesTableName) && !Schema::hasTable('permission_twill_user') && !Schema::hasTable('group_twill_user') && !Schema::hasTable('group_permission') && !Schema::hasTable('permission_role') ) { - Schema::create('permissions', function (Blueprint $table) { + Schema::create($permissionsTableName, function (Blueprint $table) { createDefaultTableFields($table); $table->string('name'); $table->string('display_name')->nullable(); @@ -40,14 +43,14 @@ public function up() $table->boolean('is_everyone_group')->default(false); }); - Schema::create('roles', function (Blueprint $table) { + Schema::create($rolesTableName, function (Blueprint $table) { createDefaultTableFields($table); $table->string('name', 255)->nullable(); $table->boolean('in_everyone_group')->default(true); $table->integer('position')->unsigned()->nullable(); }); - Schema::create('permission_twill_user', function (Blueprint $table) { + Schema::create('permission_twill_user', function (Blueprint $table) use($permissionsTableName) { $table->bigInteger('twill_user_id')->unsigned()->nullable(); $table->foreign('twill_user_id') ->references('id') @@ -57,7 +60,7 @@ public function up() $table->bigInteger('permission_id')->unsigned()->nullable(); $table->foreign('permission_id') ->references('id') - ->on('permissions') + ->on($permissionsTableName) ->onDelete('cascade'); }); @@ -77,11 +80,11 @@ public function up() $table->integer('position')->unsigned()->nullable(); }); - Schema::create('group_permission', function (Blueprint $table) { + Schema::create('group_permission', function (Blueprint $table) use($permissionsTableName) { $table->bigInteger('permission_id')->unsigned()->nullable(); $table->foreign('permission_id') ->references('id') - ->on('permissions') + ->on($permissionsTableName) ->onDelete('cascade'); $table->bigInteger('group_id')->unsigned()->nullable(); @@ -91,17 +94,17 @@ public function up() ->onDelete('cascade'); }); - Schema::create('permission_role', function (Blueprint $table) { + Schema::create('permission_role', function (Blueprint $table) use($permissionsTableName, $rolesTableName) { $table->bigInteger('permission_id')->unsigned()->nullable(); $table->foreign('permission_id') ->references('id') - ->on('permissions') + ->on($permissionsTableName) ->onDelete('cascade'); $table->bigInteger('role_id')->unsigned()->nullable(); $table->foreign('role_id') ->references('id') - ->on('roles') + ->on($rolesTableName) ->onDelete('cascade'); }); @@ -118,13 +121,17 @@ public function up() */ public function down() { + $permissionsTableName = config('twill.permissions_table', 'permissions'); + $rolesTableName = config('twill.roles_table', 'roles'); + + Schema::dropIfExists('permission_twill_user'); Schema::dropIfExists('group_twill_user'); Schema::dropIfExists('group_permission'); Schema::dropIfExists('permission_role'); - Schema::dropIfExists('permissions'); + Schema::dropIfExists($permissionsTableName); Schema::dropIfExists('groups'); - Schema::dropIfExists('roles'); + Schema::dropIfExists($rolesTableName); } private function seedBasicPermissions() diff --git a/package-lock.json b/package-lock.json index 18801130d..e363dc73d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -113,12 +113,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -182,13 +183,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -309,9 +311,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" @@ -330,25 +332,25 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -478,30 +480,30 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -546,13 +548,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -560,9 +562,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1737,33 +1739,33 @@ } }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", - "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1772,13 +1774,13 @@ } }, "node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -13692,9 +13694,9 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -14151,12 +14153,13 @@ } }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -14200,13 +14203,14 @@ } }, "@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "requires": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -14296,9 +14300,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true }, "@babel/helper-explode-assignable-expression": { @@ -14311,22 +14315,22 @@ } }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -14423,24 +14427,24 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { @@ -14473,20 +14477,20 @@ } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==" + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", @@ -15268,42 +15272,42 @@ } }, "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", - "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -24127,9 +24131,9 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true }, "wrap-ansi": { diff --git a/src/Helpers/migrations_helpers.php b/src/Helpers/migrations_helpers.php index edc39c9ab..3801b7561 100644 --- a/src/Helpers/migrations_helpers.php +++ b/src/Helpers/migrations_helpers.php @@ -55,7 +55,7 @@ function createDefaultTranslationsTableFields($table, $tableNameSingular, $table $table->softDeletes(); $table->timestamps(); $table->string('locale', 7)->index(); - $table->boolean('active'); + $table->boolean('active')->default(false); $table->foreign("{$tableNameSingular}_id", "fk_{$tableNameSingular}_translations_{$tableNameSingular}_id")->references('id')->on($tableNamePlural)->onDelete('CASCADE'); $table->unique(["{$tableNameSingular}_id", 'locale'], "{$tableNameSingular}_id_locale_unique"); diff --git a/src/Models/AppSetting.php b/src/Models/AppSetting.php index 91e8f324d..bb8a4c6d7 100644 --- a/src/Models/AppSetting.php +++ b/src/Models/AppSetting.php @@ -26,6 +26,19 @@ class AppSetting extends Model private bool $didRegisterSettingsBlocks = false; + public static function booted() + { + self::saving(function (self $model) { + /* + * Here we remove the 'blocks' relation so that any developer hooking + * into the saved event on the AppSetting can still fetch the settings + * with the new values. The next time the setting facade is called to + * retrieve a setting, the blocks relation is hydrated again. + */ + $model->unsetRelation('blocks'); + }); + } + /** * @return array|array */ diff --git a/src/Models/Behaviors/HasMedias.php b/src/Models/Behaviors/HasMedias.php index a3814e9df..685d14305 100644 --- a/src/Models/Behaviors/HasMedias.php +++ b/src/Models/Behaviors/HasMedias.php @@ -44,20 +44,18 @@ public function medias() Media::class, 'mediable', config('twill.mediables_table', 'twill_mediables') - )->withPivot( - array_merge([ - 'crop', - 'role', - 'crop_w', - 'crop_h', - 'crop_x', - 'crop_y', - 'lqip_data', - 'ratio', - 'metadatas', - ], config('twill.media_library.translated_form_fields', false) ? ['locale'] : []) - ) - ->withTimestamps()->orderBy(config('twill.mediables_table', 'twill_mediables') . '.id', 'asc'); + )->withPivot([ + 'crop', + 'role', + 'crop_w', + 'crop_h', + 'crop_x', + 'crop_y', + 'lqip_data', + 'ratio', + 'metadatas', + 'locale', + ])->withTimestamps()->orderBy(config('twill.mediables_table', 'twill_mediables') . '.id', 'asc'); } private function findMedia($role, $crop = 'default') diff --git a/src/Models/Block.php b/src/Models/Block.php index 83cd4bab4..e1ddd0e5e 100644 --- a/src/Models/Block.php +++ b/src/Models/Block.php @@ -75,7 +75,7 @@ public function input(string $name): mixed return $this->content[$name] ?? null; } - public function translatedInput(string $name, bool $forceLocale = null): mixed + public function translatedInput(string $name, string $forceLocale = null): mixed { $value = $this->content[$name] ?? null; diff --git a/src/Models/Permission.php b/src/Models/Permission.php index 9c34b6ea5..743a39142 100644 --- a/src/Models/Permission.php +++ b/src/Models/Permission.php @@ -42,6 +42,12 @@ class Permission extends BaseModel 'is_default', ]; + public function __construct(array $attributes = []) + { + $this->table = config('twill.permissions_table', 'permissions'); + parent::__construct($attributes); + } + protected $appends = ['permissionable_module']; /** diff --git a/src/Models/Role.php b/src/Models/Role.php index 343256eb4..a3fa1c715 100644 --- a/src/Models/Role.php +++ b/src/Models/Role.php @@ -38,6 +38,12 @@ class Role extends BaseModel implements Sortable, TwillModelContract 'deleted_at' => 'datetime' ]; + public function __construct(array $attributes = []) + { + $this->table = config('twill.roles_table', 'roles'); + parent::__construct($attributes); + } + public function scopeAccessible($query): Builder { $currentUser = auth('twill_users')->user(); diff --git a/src/Repositories/Behaviors/HandleFieldsGroups.php b/src/Repositories/Behaviors/HandleFieldsGroups.php index c35ff27ff..f2f1f7d6c 100644 --- a/src/Repositories/Behaviors/HandleFieldsGroups.php +++ b/src/Repositories/Behaviors/HandleFieldsGroups.php @@ -119,7 +119,7 @@ protected function handleFieldsGroups($fields) $fields[$group] = null; } - Arr::forget($fields, $groupFields); + $fields = array_filter($fields, fn($key) => !in_array($key, $groupFields), ARRAY_FILTER_USE_KEY); } return $fields; diff --git a/src/Repositories/Behaviors/HandleMedias.php b/src/Repositories/Behaviors/HandleMedias.php index c2a716a95..4d38b58c1 100644 --- a/src/Repositories/Behaviors/HandleMedias.php +++ b/src/Repositories/Behaviors/HandleMedias.php @@ -206,6 +206,7 @@ public function afterDuplicateHandleMedias(TwillModelContract $original, TwillMo 'crop_x' => $media->pivot->crop_x, 'crop_y' => $media->pivot->crop_y, 'metadatas' => $media->pivot->metadatas, + 'locale' => $media->pivot->locale, ]; $newObject->medias()->attach($media->id, $newPushData); diff --git a/src/Services/Breadcrumbs/NestedBreadcrumbs.php b/src/Services/Breadcrumbs/NestedBreadcrumbs.php index 25372f2e4..2d07a33fb 100644 --- a/src/Services/Breadcrumbs/NestedBreadcrumbs.php +++ b/src/Services/Breadcrumbs/NestedBreadcrumbs.php @@ -13,6 +13,7 @@ class NestedBreadcrumbs extends Breadcrumbs private int $activeParentId; private string $titleKey; private string $label; + private string $routePrefix = ''; public function parentLabel(string $parentLabel): self { @@ -26,13 +27,15 @@ public function forParent( string $module, int $activeParentId, string $repository, - ?string $titleKey = 'title' + ?string $titleKey = 'title', + ?string $routePrefix = '', ): self { $this->module = $module; $this->parentModule = $parentModule; $this->parentRepository = $repository; $this->activeParentId = $activeParentId; $this->titleKey = $titleKey; + $this->routePrefix = $routePrefix; if (!$this->parentLabel) { $this->parentLabel(Str::title($parentModule)); @@ -61,16 +64,16 @@ public function toArray(): array BreadcrumbItem::make()->label($this->parentLabel) ->displayOnForm() ->displayOnListing() - ->url(moduleRoute($this->parentModule, '', 'index')), + ->url(moduleRoute($this->parentModule, $this->routePrefix, 'index')), BreadcrumbItem::make()->label($this->getActiveParentTitle()) ->displayOnForm() ->displayOnListing() - ->url(moduleRoute($this->parentModule, '', 'edit', $this->activeParentId)), + ->url(moduleRoute($this->parentModule, $this->routePrefix, 'edit', $this->activeParentId)), BreadcrumbItem::make()->label($this->label) ->displayOnListing(), BreadcrumbItem::make()->label($this->label) ->displayOnForm() - ->url(moduleRoute($this->module, '', 'index')), + ->url(moduleRoute($this->module, $this->routePrefix, 'index')), BreadcrumbItem::make()->label('Edit') ->displayOnForm(), ]; diff --git a/src/Services/Forms/Fields/Input.php b/src/Services/Forms/Fields/Input.php index 932aa409d..75137be44 100644 --- a/src/Services/Forms/Fields/Input.php +++ b/src/Services/Forms/Fields/Input.php @@ -7,6 +7,7 @@ use A17\Twill\Services\Forms\Fields\Traits\HasMin; use A17\Twill\Services\Forms\Fields\Traits\HasOnChange; use A17\Twill\Services\Forms\Fields\Traits\HasPlaceholder; +use A17\Twill\Services\Forms\Fields\Traits\HasDirection; use A17\Twill\Services\Forms\Fields\Traits\IsTranslatable; /** @@ -19,6 +20,7 @@ class Input extends BaseFormField use HasMax; use HasMaxlength; use HasPlaceholder; + use HasDirection; use HasOnChange; /** diff --git a/src/Services/Forms/Fields/Traits/HasDirection.php b/src/Services/Forms/Fields/Traits/HasDirection.php new file mode 100644 index 000000000..65cc22fe9 --- /dev/null +++ b/src/Services/Forms/Fields/Traits/HasDirection.php @@ -0,0 +1,18 @@ +direction = $direction === 'ltr' || $direction === 'rtl' ? $direction : 'auto'; + + return $this; + } +} diff --git a/src/Services/Forms/Fields/Wysiwyg.php b/src/Services/Forms/Fields/Wysiwyg.php index 985376788..e84e6e871 100644 --- a/src/Services/Forms/Fields/Wysiwyg.php +++ b/src/Services/Forms/Fields/Wysiwyg.php @@ -6,6 +6,7 @@ use A17\Twill\Services\Forms\Fields\Traits\HasMaxlength; use A17\Twill\Services\Forms\Fields\Traits\HasOnChange; use A17\Twill\Services\Forms\Fields\Traits\HasPlaceholder; +use A17\Twill\Services\Forms\Fields\Traits\HasDirection; use A17\Twill\Services\Forms\Fields\Traits\IsTranslatable; class Wysiwyg extends BaseFormField @@ -13,6 +14,7 @@ class Wysiwyg extends BaseFormField use IsTranslatable; use HasMaxlength; use HasPlaceholder; + use HasDirection; use HasOnChange; public bool $hideCounter = false; diff --git a/src/Services/Listings/Columns/NestedData.php b/src/Services/Listings/Columns/NestedData.php index 38143762b..9bd6a3507 100644 --- a/src/Services/Listings/Columns/NestedData.php +++ b/src/Services/Listings/Columns/NestedData.php @@ -9,13 +9,6 @@ class NestedData extends TableColumn { - public static function make(): static - { - $item = parent::make(); - $item->field('children'); - return $item; - } - public function sortable(bool $sortable = true): static { if ($sortable && $this->sortFunction === null) { diff --git a/src/Services/Settings/SettingsGroup.php b/src/Services/Settings/SettingsGroup.php index 63701a016..2707995b4 100644 --- a/src/Services/Settings/SettingsGroup.php +++ b/src/Services/Settings/SettingsGroup.php @@ -18,6 +18,8 @@ class SettingsGroup private ?Closure $availableWhen = null; + private AppSetting $appSetting; + public static function make(): self { return new self(); @@ -70,12 +72,9 @@ public function hasSection(string $sectionName): bool public function getSettingsModel(): AppSetting { - $settingsModel = AppSetting::where(['name' => $this->getName()])->first(); - if (!$settingsModel) { - $settingsModel = AppSetting::create(['name' => $this->getName()]); - } - - return $settingsModel; + return $this->appSetting ??= AppSetting::firstOrCreate([ + 'name' => $this->getName(), + ]); } /** diff --git a/src/TwillAppSettings.php b/src/TwillAppSettings.php index 32de3b73f..17efa6bef 100644 --- a/src/TwillAppSettings.php +++ b/src/TwillAppSettings.php @@ -105,7 +105,7 @@ public function getGroupDataForSectionAndName(string $group, string $section): B { $groupObject = $this->getGroupForGroupAndSectionName($group, $section); - return $groupObject->getSettingsModel()->blocks() + return $groupObject->getSettingsModel()->blocks ->where('editor_name', $section) ->where('parent_id', null) ->firstOrFail(); diff --git a/src/View/Components/Fields/Input.php b/src/View/Components/Fields/Input.php index d7f8e9ae7..64890cc37 100644 --- a/src/View/Components/Fields/Input.php +++ b/src/View/Components/Fields/Input.php @@ -21,6 +21,7 @@ public function __construct( // Component specific public string $type = 'text', public ?string $placeholder = '', + public ?string $direction = 'auto', public ?int $maxlength = null, public ?int $rows = null, public ?string $ref = null, diff --git a/src/View/Components/Fields/Wysiwyg.php b/src/View/Components/Fields/Wysiwyg.php index aa291a101..df20d382d 100644 --- a/src/View/Components/Fields/Wysiwyg.php +++ b/src/View/Components/Fields/Wysiwyg.php @@ -21,6 +21,7 @@ public function __construct( // Component specific public bool $hideCounter = false, public ?string $placeholder = null, + public ?string $direction = 'auto', public bool $editSource = false, public ?array $toolbarOptions = null, public ?int $maxlength = null, diff --git a/tests/integration/Controllers/Tables/NestedDataColumnTest.php b/tests/integration/Controllers/Tables/NestedDataColumnTest.php index 6ba206546..de847d673 100644 --- a/tests/integration/Controllers/Tables/NestedDataColumnTest.php +++ b/tests/integration/Controllers/Tables/NestedDataColumnTest.php @@ -19,7 +19,7 @@ public function setUp(): void public function testColumn(): void { - $column = NestedData::make()->title('Child'); + $column = NestedData::make()->field('children')->title('Child'); $this->assertEquals('0 children', $column->renderCell($this->parent)); } @@ -27,7 +27,7 @@ public function testColumn(): void public function testSingleChild(): void { $this->parent->children()->create(['title' => 'Child 1', 'published' => true]); - $column = NestedData::make()->title('Child'); + $column = NestedData::make()->field('children')->title('Child'); $this->assertEquals('1 child', $column->renderCell($this->parent)); } @@ -35,7 +35,7 @@ public function testMultipleChilden(): void { $this->parent->children()->create(['title' => 'Child 1', 'published' => true]); $this->parent->children()->create(['title' => 'Child 1', 'published' => true]); - $column = NestedData::make()->title('Child'); + $column = NestedData::make()->field('children')->title('Child'); $this->assertEquals('2 children', $column->renderCell($this->parent)); } } diff --git a/tests/integration/Settings/SettingsFacadeTest.php b/tests/integration/Settings/SettingsFacadeTest.php index 2e4ffb640..d677d1e7d 100644 --- a/tests/integration/Settings/SettingsFacadeTest.php +++ b/tests/integration/Settings/SettingsFacadeTest.php @@ -5,6 +5,7 @@ use A17\Twill\Exceptions\Settings\SettingsGroupDoesNotExistException; use A17\Twill\Exceptions\Settings\SettingsSectionDoesNotExistException; use A17\Twill\Facades\TwillAppSettings; +use A17\Twill\Models\AppSetting; use A17\Twill\Services\Settings\SettingsGroup; use A17\Twill\Tests\Integration\TestCase; @@ -66,6 +67,9 @@ public function setUp(): void ] ) ->assertStatus(200); + + /** @see AppSetting::booted() */ + $model->unsetRelation('blocks'); } public function testTranslatedSettingsGetter(): void diff --git a/views/layouts/form.blade.php b/views/layouts/form.blade.php index b8fd3001b..3c4d1fdca 100644 --- a/views/layouts/form.blade.php +++ b/views/layouts/form.blade.php @@ -155,7 +155,7 @@ - +