Skip to content

Commit 3dcef89

Browse files
committed
wip
1 parent 524debf commit 3dcef89

File tree

13 files changed

+192
-225
lines changed

13 files changed

+192
-225
lines changed

src/app/Http/Controllers/Operations/CreateOperation.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ protected function setupCreateDefaults()
5050

5151
if ($useModalForm) {
5252
$this->crud->removeButton('create');
53-
$this->crud->addButton('top', 'create', 'view', 'crud::buttons.create_modal_form', 'beginning');
53+
$this->crud->addButton('top', 'create', 'view', 'crud::buttons.create_in_modal', 'beginning');
5454
}
5555
});
5656
}
@@ -65,8 +65,8 @@ public function create()
6565
$this->crud->hasAccessOrFail('create');
6666

6767
// Apply cached form setup if this is an AJAX request from a modal
68-
if (request()->ajax() && request()->has('_form_id')) {
69-
\Backpack\CRUD\app\Library\Support\DataformCache::applyFromRequest($this->crud);
68+
if (request()->ajax() && request()->has('_modal_form_id')) {
69+
\Backpack\CRUD\app\Library\Support\DataformCache::applySetupClosure($this->crud);
7070
}
7171

7272
// prepare the fields you need to show
@@ -75,7 +75,7 @@ public function create()
7575
$this->data['title'] = $this->crud->getTitle() ?? trans('backpack::crud.add').' '.$this->crud->entity_name;
7676

7777
// return the ajax response for modal forms, or the normal view for normal requests
78-
return request()->ajax() ?
78+
return request()->ajax() && request()->has('_modal_form_id') ?
7979
view('crud::components.dataform.ajax_response', $this->data) :
8080
view($this->crud->getCreateView(), $this->data);
8181
}

src/app/Http/Controllers/Operations/UpdateOperation.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ protected function setupUpdateDefaults()
6060

6161
if ($useModalForm) {
6262
$this->crud->removeButton('update');
63-
$this->crud->addButton('line', 'update', 'view', 'crud::buttons.update_modal_form', 'end');
63+
$this->crud->addButton('line', 'update', 'view', 'crud::buttons.update_in_modal', 'end');
6464
}
6565
});
6666
}
@@ -79,8 +79,8 @@ public function edit($id)
7979
$id = $this->crud->getCurrentEntryId() ?? $id;
8080

8181
// Apply cached form setup if this is an AJAX request from a modal
82-
if (request()->ajax() && request()->has('_form_id')) {
83-
\Backpack\CRUD\app\Library\Support\DataformCache::applyFromRequest($this->crud);
82+
if (request()->ajax() && request()->has('_modal_form_id')) {
83+
\Backpack\CRUD\app\Library\Support\DataformCache::applySetupClosure($this->crud);
8484
}
8585

8686
// register any Model Events defined on fields
@@ -97,7 +97,7 @@ public function edit($id)
9797
$this->data['id'] = $id;
9898

9999
// load the view from /resources/views/vendor/backpack/crud/ if it exists, otherwise load the one in the package
100-
return request()->ajax() ?
100+
return request()->ajax() && request()->has('_modal_form_id') ?
101101
view('crud::components.dataform.ajax_response', $this->data) :
102102
view($this->crud->getEditView(), $this->data);
103103
}

src/app/Library/Support/DataformCache.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static function applyAndStoreSetupClosure(
7070
): bool {
7171
$instance = new self();
7272
// Apply the setup closure to the CrudPanel instance
73-
if ($instance->applySetupClosure($crud, $controllerClass, $setupClosure, $parentEntry)) {
73+
if ($instance->applyClosure($crud, $controllerClass, $setupClosure, $parentEntry)) {
7474
// Capture the resulting field configuration after setup
7575
$fieldsAfterSetup = [];
7676
foreach ($crud->fields() as $fieldName => $field) {
@@ -92,11 +92,11 @@ public static function applyAndStoreSetupClosure(
9292
* @param CrudPanel $crud The CRUD panel instance
9393
* @return bool Whether the operation was successful
9494
*/
95-
public static function applyFromRequest(CrudPanel $crud): bool
95+
public static function applySetupClosure(CrudPanel $crud): bool
9696
{
9797
$instance = new self();
98-
// Check if the request has a _form_id parameter
99-
$formId = request('_form_id');
98+
// Check if the request has a _modal_form_id parameter
99+
$formId = request('_modal_form_id');
100100

101101
if (! $formId) {
102102
return false;
@@ -114,7 +114,7 @@ public static function applyFromRequest(CrudPanel $crud): bool
114114
* @param mixed $entry The entry to pass to the setup closure
115115
* @return bool Whether the operation was successful
116116
*/
117-
public function applySetupClosure(CrudPanel $crud, string $controllerClass, \Closure $setupClosure, $entry = null): bool
117+
private function applyClosure(CrudPanel $crud, string $controllerClass, \Closure $setupClosure, $entry = null): bool
118118
{
119119
$originalSetup = $setupClosure;
120120
$modifiedSetup = function ($crud, $entry) use ($originalSetup, $controllerClass) {

src/app/View/Components/Dataform.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ private function getParentCrudEntry()
9797
*/
9898
public function render()
9999
{
100-
// Store the current form ID in the service container for form-aware old() helper
101-
app()->instance('backpack.current_form_id', $this->id);
100+
// Store the current form ID in the service container for form-aware old() helper
101+
app()->instance('backpack.current_form_modal_id', $this->id);
102102

103103
return view('crud::components.dataform.form', [
104104
'crud' => $this->crud,

src/app/View/Components/DataformModal.php

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use Backpack\CRUD\app\View\Components\Contracts\IsolatesOperationSetup;
66
use Closure;
77

8-
class DataformModal extends DataForm implements IsolatesOperationSetup
8+
class DataformModal extends Dataform implements IsolatesOperationSetup
99
{
1010
/**
1111
* Modal forms ALWAYS isolate their operation setup.
@@ -16,28 +16,11 @@ public function shouldIsolateOperationSetup(): bool
1616
return true;
1717
}
1818

19-
/**
20-
* Create a new component instance.
21-
*
22-
* @param string $controller The CRUD controller class name
23-
* @param string $operation The operation to use (create, update, etc.)
24-
* @param string|null $action Custom form action URL
25-
* @param string $method Form method (post, put, etc.)
26-
* @param bool $hasUploadFields Whether the form has upload fields
27-
* @param mixed|null $entry The model instance for update operations
28-
* @param Closure|null $setup A closure to customize the CRUD panel
29-
* @param string $formRouteOperation The operation to use for the form route (defaults to 'create')
30-
* @param string $id The ID for the form element (defaults to 'backpack-form')
31-
* @param bool $focusOnFirstField Whether to focus on the first field when form loads
32-
* @param string $title The title of the modal
33-
* @param string $classes CSS classes for the modal dialog
34-
* @param bool $refreshDatatable Whether to refresh the datatable after form submission
35-
*/
3619
public string $hashedFormId;
3720

3821
public function __construct(
3922
public string $controller,
40-
public ?string $route = null, // Accept route as an optional parameter
23+
public ?string $route = null,
4124
public string $id = 'backpack-form',
4225
public string $operation = 'create',
4326
public string $name = '',
@@ -60,12 +43,10 @@ public function __construct(
6043
\Backpack\CRUD\CrudManager::unsetActiveController();
6144
}
6245

63-
// Use the provided/resolved route instead of calling setupCrudPanel on every render
64-
// This avoids operation switching during page load when route is provided
65-
$action = $this->action ?? url($this->route);
46+
$this->action = $this->action ?? url($this->route);
6647

67-
// Generate the SAME hashed form ID that the DataForm component uses
68-
$this->hashedFormId = $this->id.md5($action.$this->operation.'post'.$this->controller);
48+
// Generate the SAME hashed form ID that the Dataform component uses
49+
$this->hashedFormId = $this->id.md5($action.$this->operation.'post'.$this->controller);
6950

7051
// Cache the setup closure if provided (for retrieval during AJAX request)
7152
if ($this->setup instanceof \Closure) {
@@ -76,7 +57,8 @@ public function __construct(
7657
// the CRUD panel on page load - the form will be loaded via AJAX
7758

7859
if ($this->entry && $this->operation === 'update') {
79-
$this->formRouteOperation = url($action.'/'.$this->entry->getKey().'/edit');
60+
// Use the resolved action (base route) to build the edit URL for the entry
61+
$this->formRouteOperation = url($this->action.'/'.$this->entry->getKey().'/edit');
8062
}
8163
}
8264

@@ -91,7 +73,7 @@ protected function cacheSetupClosure(): void
9173

9274
// Apply and cache the setup closure using the HASHED ID
9375
\Backpack\CRUD\app\Library\Support\DataformCache::applyAndStoreSetupClosure(
94-
$this->hashedFormId, // Use the hashed ID that matches what DataForm component generates
76+
$this->hashedFormId, // Use the hashed ID that matches what Dataform component generates
9577
$this->controller,
9678
$this->setup,
9779
null,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@if ($crud->hasAccess('create'))
2+
@php
3+
$controllerClass = get_class(app('request')->route()->getController());
4+
@endphp
5+
6+
{{-- Create button that opens modal form --}}
7+
<button
8+
type="button"
9+
class="btn btn-primary"
10+
data-bs-toggle="modal"
11+
data-bs-target="#createModal{{ md5($controllerClass.'create') }}"
12+
bp-button="create"
13+
data-style="zoom-in"
14+
>
15+
<i class="la la-plus"></i> <span>{{ trans('backpack::crud.add') }} {{ $crud->entity_name }}</span>
16+
</button>
17+
18+
{{-- Include the modal form component --}}
19+
<x-backpack::dataform-modal
20+
:controller="$controllerClass"
21+
operation="create"
22+
id="createModal{{ md5($controllerClass.'create') }}"
23+
:title="trans('backpack::crud.add') . ' ' . $crud->entity_name"
24+
:route="$crud->route"
25+
refresh-datatable="true"
26+
/>
27+
@endif
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
@if ($crud->hasAccess('update', $entry))
2+
@php
3+
$controllerClass = get_class(app('request')->route()->getController());
4+
@endphp
5+
6+
{{-- Update button that opens modal form --}}
7+
@if (!$crud->model->translationEnabled())
8+
<button
9+
type="button"
10+
class="btn btn-sm btn-link"
11+
data-bs-toggle="modal"
12+
data-bs-target="#updateModal{{ md5($controllerClass.'update'.$entry->getKey()) }}"
13+
bp-button="update"
14+
>
15+
<i class="la la-edit"></i> <span>{{ trans('backpack::crud.edit') }}</span>
16+
</button>
17+
@else
18+
{{-- Edit button group for translated models --}}
19+
<div class="btn-group">
20+
<button
21+
type="button"
22+
class="btn btn-sm btn-link pr-0"
23+
data-bs-toggle="modal"
24+
data-bs-target="#updateModal{{ md5($controllerClass.'update'.$entry->getKey()) }}"
25+
>
26+
<span><i class="la la-edit"></i> {{ trans('backpack::crud.edit') }}</span>
27+
</button>
28+
<a class="btn btn-sm btn-link dropdown-toggle text-primary pl-1" data-toggle="dropdown" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
29+
<span class="caret"></span>
30+
</a>
31+
<ul class="dropdown-menu dropdown-menu-right">
32+
<li class="dropdown-header">{{ trans('backpack::crud.edit_translations') }}:</li>
33+
@foreach ($crud->model->getAvailableLocales() as $key => $locale)
34+
<li><a class="dropdown-item" href="{{ url($crud->route.'/'.$entry->getKey().'/edit') }}?_locale={{ $key }}">{{ $locale }}</a></li>
35+
@endforeach
36+
</ul>
37+
</div>
38+
@endif
39+
40+
{{-- Include the modal form component --}}
41+
<x-backpack::dataform-modal
42+
:controller="$controllerClass"
43+
operation="update"
44+
:entry="$entry"
45+
id="updateModal{{ md5($controllerClass.'update'.$entry->getKey()) }}"
46+
:title="trans('backpack::crud.edit') . ' ' . $crud->entity_name"
47+
refresh-datatable="true"
48+
/>
49+
@endif

src/resources/views/crud/components/dataform/ajax_response.blade.php

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -40,75 +40,5 @@
4040
@stack('after_styles')
4141

4242
<script>
43-
// Define utility functions needed by field initialization scripts
44-
// These are normally included in form_content.blade.php but missing in AJAX context
45-
46-
/**
47-
* Initialize all fields with JavaScript based on their data-init-function attribute
48-
* @param {jQuery|HTMLElement} container
49-
*/
50-
function initializeFieldsWithJavascript(container) {
51-
var selector;
52-
if (container instanceof jQuery) {
53-
selector = container;
54-
} else {
55-
selector = $(container);
56-
}
57-
58-
selector.find("[data-init-function]").not("[data-initialized=true]").each(function () {
59-
var element = $(this);
60-
var functionName = element.data('init-function');
61-
62-
if (typeof window[functionName] === "function") {
63-
window[functionName](element);
64-
// mark the element as initialized, so that its function is never called again
65-
element.attr('data-initialized', 'true');
66-
}
67-
});
68-
}
69-
70-
/**
71-
* Auto-discover first focusable input
72-
* @param {jQuery} form
73-
* @return {jQuery}
74-
*/
75-
function getFirstFocusableField(form) {
76-
return form.find('input, select, textarea, button')
77-
.not('.close')
78-
.not('[disabled]')
79-
.filter(':visible:first');
80-
}
81-
82-
/**
83-
*
84-
* @param {jQuery} firstField
85-
*/
86-
function triggerFocusOnFirstInputField(firstField) {
87-
if (firstField.hasClass('select2-hidden-accessible')) {
88-
return handleFocusOnSelect2Field(firstField);
89-
}
90-
91-
firstField.trigger('focus');
92-
}
93-
94-
/**
95-
* 1- Make sure no other select2 input is open in other field to focus on the right one
96-
* 2- Check until select2 is initialized
97-
* 3- Open select2
98-
*
99-
* @param {jQuery} firstField
100-
*/
101-
function handleFocusOnSelect2Field(firstField){
102-
firstField.select2('focus');
103-
}
104-
105-
/*
106-
* Hacky fix for a bug in select2 with jQuery 3.6.0's new nested-focus "protection"
107-
* see: https://github.com/select2/select2/issues/5993
108-
* see: https://github.com/jquery/jquery/issues/4382
109-
*
110-
*/
111-
$(document).on('select2:open', () => {
112-
setTimeout(() => document.querySelector('.select2-container--open .select2-search__field').focus(), 100);
113-
});
43+
@include('crud::components.dataform.common_js')
11444
</script>

0 commit comments

Comments
 (0)