Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/CrudPanelManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ public function setupCrudPanel(string $controller, ?string $operation = null): C
$crud->setOperation($operation);

$primaryControllerRequest = $this->cruds[array_key_first($this->cruds)]->getRequest();
if (! $crud->isInitialized()) {
if (! $crud->isInitialized() || ! $this->isOperationInitialized($controller::class, $operation)) {
self::setActiveController($controller::class);
$crud->initialized = false;
self::setActiveController($controller::class);
$controller->initializeCrudPanel($primaryControllerRequest, $crud);
self::unsetActiveController();
Expand All @@ -81,6 +83,14 @@ public function setupCrudPanel(string $controller, ?string $operation = null): C
return $this->cruds[$controller::class];
}

/**
* Check if a specific operation has been initialized for a controller.
*/
public function isOperationInitialized(string $controller, string $operation): bool
{
return in_array($operation, $this->getInitializedOperations($controller), true);
}

/**
* Record that an operation has been initialized for a controller.
*
Expand Down
71 changes: 71 additions & 0 deletions src/app/View/Components/Dataform.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace Backpack\CRUD\app\View\Components;

use Backpack\CRUD\CrudManager;
use Illuminate\View\Component;

class Dataform extends Component
{
public $crud;

/**
* Create a new component instance.
*
* @param string $controller The CRUD controller class name
* @param string $operation The operation to use (create, update, etc.)
* @param string|null $action Custom form action URL
* @param string $method Form method (post, put, etc.)
*/
public function __construct(
public string $controller,
public string $id = 'backpack-form',
public string $operation = 'create',
public ?string $action = null,
public string $method = 'post',
public bool $hasUploadFields = false,
public $entry = null,

) {
// Get CRUD panel instance from the controller
if (CrudManager::hasCrudPanel($controller)) {
$previousOperation = CrudManager::getCrudPanel($controller)->getOperation();
}

$this->crud = CrudManager::setupCrudPanel($controller, $operation);

if (isset($previousOperation)) {
$this->crud->setOperation($previousOperation);
}

if ($this->entry && $this->operation === 'update') {
$this->action = $action ?? url($this->crud->route.'/'.$this->entry->getKey());
$this->method = 'put';
$this->crud->entry = $this->entry;
$this->crud->setOperationSetting('fields', $this->crud->getUpdateFields());
} else {
$this->action = $action ?? url($this->crud->route);
}
$this->hasUploadFields = $this->crud->hasUploadFields($operation, $this->entry?->getKey());
$this->id = $id.md5($this->action.$this->operation.$this->method.$this->controller);
}

/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render()
{
return view('crud::components.dataform.form', [
'crud' => $this->crud,
'saveAction' => $this->crud->getSaveAction(),
'id' => $this->id,
'operation' => $this->operation,
'action' => $this->action,
'method' => $this->method,
'hasUploadFields' => $this->hasUploadFields,
'entry' => $this->entry,
]);
}
}
52 changes: 52 additions & 0 deletions src/resources/views/crud/components/dataform/form.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<div class="backpack-form">
@include('crud::inc.grouped_errors', ['id' => $id])


<form method="post"
action="{{ $action }}"
id="{{ $id }}"
@if($hasUploadFields)
enctype="multipart/form-data"
@endif
>
{!! csrf_field() !!}



<input type="hidden" name="_form_id" value="{{ $id }}">
@if($method !== 'post')
@method($method)
@endif
{{-- Include the form fields --}}
@include('crud::form_content', ['fields' => $crud->fields(), 'action' => $operation, 'id' => $id])

{{-- This makes sure that all field assets are loaded. --}}
<div class="d-none" id="parentLoadedAssets">{{ json_encode(Basset::loaded()) }}</div>

@include('crud::inc.form_save_buttons')
</form>
</div>

@push('after_scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize the form fields after loading
if (typeof initializeFieldsWithJavascript === 'function') {
try {
initializeFieldsWithJavascript(document.querySelector('.backpack-form'));
} catch (e) {
console.error('Error initializing form fields:', e);
}
}

// Focus on first focusable field when form is loaded
const form = document.querySelector('.backpack-form form');
if (form) {
const firstField = form.querySelector('input:not([type=hidden]), select, textarea');
if (firstField) {
firstField.focus();
}
}
});
</script>
@endpush
2 changes: 1 addition & 1 deletion src/resources/views/crud/create.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<div class="{{ $crud->getCreateContentClass() }}">
{{-- Default box --}}

@include('crud::inc.grouped_errors')
@include('crud::inc.grouped_errors', ['id' => $id])

<form method="post"
action="{{ url($crud->route) }}"
Expand Down
4 changes: 2 additions & 2 deletions src/resources/views/crud/edit.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<div class="{{ $crud->getEditContentClass() }}">
{{-- Default box --}}

@include('crud::inc.grouped_errors')
@include('crud::inc.grouped_errors', ['id' => $id])

<form method="post"
action="{{ url($crud->route.'/'.$entry->getKey()) }}"
Expand All @@ -43,7 +43,7 @@

{{-- load the view from the application if it exists, otherwise load the one in the package --}}
@if(view()->exists('vendor.backpack.crud.form_content'))
@include('vendor.backpack.crud.form_content', ['fields' => $crud->fields(), 'action' => 'edit'])
@include('vendor.backpack.crud.form_content', ['fields' => $crud->fields(), 'action' => 'edit', 'id' => $id])
@else
@include('crud::form_content', ['fields' => $crud->fields(), 'action' => 'edit'])
@endif
Expand Down
12 changes: 8 additions & 4 deletions src/resources/views/crud/form_content.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@

{{-- Define blade stacks so css and js can be pushed from the fields to these sections. --}}

@section('after_styles')
@push('after_styles')

{{-- CRUD FORM CONTENT - crud_fields_styles stack --}}
@stack('crud_fields_styles')

@endsection
@endpush

@section('after_scripts')
@push('after_scripts')

{{-- CRUD FORM CONTENT - crud_fields_scripts stack --}}
@stack('crud_fields_scripts')
Expand Down Expand Up @@ -187,7 +187,10 @@ function preventUnload(event) {
@if ($crud->inlineErrorsEnabled() && session()->get('errors'))

window.errors = {!! json_encode(session()->get('errors')->getBags()) !!};
var submittedFormId = "{{ old('_form_id') }}";
var currentFormId = '{{ $id }}';

if (!submittedFormId || submittedFormId === currentFormId) {
$.each(errors, function(bag, errorMessages){
$.each(errorMessages, function (inputName, messages) {
var normalizedProperty = inputName.split('.').map(function(item, index){
Expand Down Expand Up @@ -231,6 +234,7 @@ function preventUnload(event) {
});
});
});
}
@endif

$("a[data-bs-toggle='tab']").click(function(){
Expand All @@ -245,4 +249,4 @@ function preventUnload(event) {
</script>

@include('crud::inc.form_fields_script')
@endsection
@endpush
2 changes: 2 additions & 0 deletions src/resources/views/crud/inc/form_fields_script.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* javascript manipulations, and makes it easy to do custom stuff
* too, by exposing the main components (name, wrapper, input).
*/
if (typeof CrudField === 'undefined') {
class CrudField {
constructor(name) {
this.name = name;
Expand Down Expand Up @@ -197,4 +198,5 @@ class CrudField {
// Create all fields from a given name list
fields: names => names.map(window.crud.field),
};
}
</script>
6 changes: 6 additions & 0 deletions src/resources/views/crud/inc/grouped_errors.blade.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{{-- Show the errors, if any --}}
@if ($crud->groupedErrorsEnabled() && session()->get('errors'))
@php
$submittedFormId = old('_form_id') ?? null;
$currentFormId = $id ?? null;
@endphp
@if (!$submittedFormId || $submittedFormId === $currentFormId)
<div class="alert alert-danger">
<ul class="list-unstyled">
@foreach(session()->get('errors')->getBags() as $bag => $errorMessages)
Expand All @@ -11,4 +16,5 @@
@endforeach
</ul>
</div>
@endif
@endif
18 changes: 18 additions & 0 deletions src/resources/views/crud/widgets/dataform.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@includeWhen(!empty($widget['wrapper']), backpack_view('widgets.inc.wrapper_start'))
<div class="{{ $widget['class'] ?? 'card' }}">
@if (isset($widget['content']['header']))
<div class="card-header">
<div class="card-title mb-0">{!! $widget['content']['header'] !!}</div>
</div>
@endif
<div class="card-body">

{!! $widget['content']['body'] ?? '' !!}

<div class="card-wrapper form-widget-wrapper">
<x-backpack::data-form :controller="$widget['controller']" />
</div>

</div>
</div>
@includeWhen(!empty($widget['wrapper']), backpack_view('widgets.inc.wrapper_end'))
Loading