]> _ Git - bastide-resah.git/commitdiff
wip #6857
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Wed, 10 Apr 2024 17:54:44 +0000 (19:54 +0200)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Wed, 10 Apr 2024 17:54:44 +0000 (19:54 +0200)
128 files changed:
app/Models/Client.php [new file with mode: 0644]
app/Models/User.php
app/Providers/AuthServiceProvider.php
config/auth.php
resources/views/vendor/backpack/base/auth/emails/password.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/auth/login.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/auth/passwords/email.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/auth/passwords/reset.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/auth/register.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/blank.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/dashboard.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/alerts.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/breadcrumbs.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/footer.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/full_screen_loader.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/getting_started.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/head.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/main_header.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/menu.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/menu_user_dropdown.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/scripts.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/sidebar.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/sidebar_content.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/topbar_left_content.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/topbar_right_content.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/inc/widgets.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/layouts/plain.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/layouts/top_left.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/my_account.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/alert.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/card.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/div.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/inc/wrapper_end.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/inc/wrapper_start.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/jumbotron.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/progress.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/progress_white.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/script.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/style.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/base/widgets/view.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/buttons/create.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/buttons/delete.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/buttons/reorder.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/buttons/show.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/buttons/update.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/boolean.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/check.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/closure.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/custom_html.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/date.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/datetime.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/email.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/enum.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/image.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/inc/bulk_actions_checkbox.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/inc/details_row_button.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/inc/wrapper_end.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/inc/wrapper_start.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/json.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/model_function.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/model_function_attribute.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/multidimensional_array.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/number.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/phone.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/radio.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/relationship_count.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/row_number.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/select.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/select_from_array.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/select_multiple.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/text.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/textarea.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/upload_multiple.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/columns/view.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/create.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/details_row.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/edit.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/boolean.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/checkbox.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/checklist.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/checklist_dependency.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/color.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/custom_html.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/date.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/datetime.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/email.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/enum.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/hidden.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/inc/attributes.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/inc/translatable_icon.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/inc/wrapper_end.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/inc/wrapper_start.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/month.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/number.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/password.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/radio.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/range.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/select.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/select_from_array.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/select_grouped.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/select_multiple.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/summernote.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/switch.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/text.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/textarea.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/time.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/upload.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/upload_multiple.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/url.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/view.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/fields/week.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/form_content.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/ajax_error_frame.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/button_stack.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/datatables_logic.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/details_row_logic.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/export_buttons.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/filters_navbar.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/form_fields_script.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/form_save_buttons.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/grouped_errors.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/show_fields.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/show_tabbed_fields.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/show_tabbed_table.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/inc/show_table.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/list.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/reorder.blade.php [new file with mode: 0644]
resources/views/vendor/backpack/crud/show.blade.php [new file with mode: 0644]

diff --git a/app/Models/Client.php b/app/Models/Client.php
new file mode 100644 (file)
index 0000000..a92e944
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Models;
+
+use Cubist\Backpack\Magic\Models\CubistMagicAuthenticatable;
+
+class Client extends CubistMagicAuthenticatable
+{
+    public function setFields()
+    {
+        parent::setFields();
+
+    }
+}
index 4d7f70f568fe2e9eff23fa12f309a10bf1e74e3c..1187a8da53c55dae3d7bc21026722152d404c563 100644 (file)
@@ -2,44 +2,10 @@
 
 namespace App\Models;
 
-// use Illuminate\Contracts\Auth\MustVerifyEmail;
-use Illuminate\Database\Eloquent\Factories\HasFactory;
-use Illuminate\Foundation\Auth\User as Authenticatable;
-use Illuminate\Notifications\Notifiable;
-use Laravel\Sanctum\HasApiTokens;
+use Cubist\Backpack\Magic\Models\CubistMagicAuthenticatable;
 
-class User extends Authenticatable
-{
-    use HasApiTokens, HasFactory, Notifiable;
-
-    /**
-     * The attributes that are mass assignable.
-     *
-     * @var array<int, string>
-     */
-    protected $fillable = [
-        'name',
-        'email',
-        'password',
-    ];
 
-    /**
-     * The attributes that should be hidden for serialization.
-     *
-     * @var array<int, string>
-     */
-    protected $hidden = [
-        'password',
-        'remember_token',
-    ];
+class User extends CubistMagicAuthenticatable
+{
 
-    /**
-     * The attributes that should be cast.
-     *
-     * @var array<string, string>
-     */
-    protected $casts = [
-        'email_verified_at' => 'datetime',
-        'password' => 'hashed',
-    ];
 }
index 54756cd1cbd4cfb4d774c1c1fdd8d5c120982d8c..a969f628e8f1670bdab8dc6a61cf2c8e40a2810c 100644 (file)
@@ -4,6 +4,7 @@ namespace App\Providers;
 
 // use Illuminate\Support\Facades\Gate;
 use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
+use Illuminate\Support\Facades\Gate;
 
 class AuthServiceProvider extends ServiceProvider
 {
@@ -19,8 +20,12 @@ class AuthServiceProvider extends ServiceProvider
     /**
      * Register any authentication / authorization services.
      */
-    public function boot(): void
+    public function boot()
     {
-        //
+        $this->registerPolicies();
+        Gate::before(function ($user, $ability) {
+            return $user->hasRole('superadmin') ? true : null;
+        });
+
     }
 }
index d2651cb7d1790d9e23e45d1cd12db9ce9c2c742e..8b1abfe6cc67b5d4f6be42af589ca62494191eb1 100644 (file)
@@ -65,6 +65,11 @@ return [
             'model' => App\Models\User::class,
         ],
 
+        'backpack' => [
+            'driver' => 'eloquent',
+            'model' => App\Models\User::class,
+        ],
+
         // 'users' => [
         //     'driver' => 'database',
         //     'table' => 'users',
diff --git a/resources/views/vendor/backpack/base/auth/emails/password.blade.php b/resources/views/vendor/backpack/base/auth/emails/password.blade.php
new file mode 100644 (file)
index 0000000..c167c7f
--- /dev/null
@@ -0,0 +1 @@
+{{ trans('backpack::base.click_here_to_reset') }}: <a href="{{ $link = backpack_url('password/reset', $token).'?email='.urlencode($user->getEmailForPasswordReset()) }}"> {{ $link }} </a>
diff --git a/resources/views/vendor/backpack/base/auth/login.blade.php b/resources/views/vendor/backpack/base/auth/login.blade.php
new file mode 100644 (file)
index 0000000..b47df68
--- /dev/null
@@ -0,0 +1,68 @@
+@extends(backpack_view('layouts.plain'))
+
+@section('content')
+    <div class="row justify-content-center">
+        <div class="col-12 col-md-8 col-lg-4">
+            <h3 class="text-center mb-4">{{ trans('backpack::base.login') }}</h3>
+            <div class="card">
+                <div class="card-body">
+                    <form class="col-md-12 p-t-10" role="form" method="POST" action="{{ route('backpack.auth.login') }}">
+                        {!! csrf_field() !!}
+
+                        <div class="form-group">
+                            <label class="control-label" for="{{ $username }}">{{ config('backpack.base.authentication_column_name') }}</label>
+
+                            <div>
+                                <input type="text" class="form-control{{ $errors->has($username) ? ' is-invalid' : '' }}" name="{{ $username }}" value="{{ old($username) }}" id="{{ $username }}">
+
+                                @if ($errors->has($username))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first($username) }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <label class="control-label" for="password">{{ trans('backpack::base.password') }}</label>
+
+                            <div>
+                                <input type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" id="password">
+
+                                @if ($errors->has('password'))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first('password') }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <div>
+                                <div class="checkbox">
+                                    <label>
+                                        <input type="checkbox" name="remember"> {{ trans('backpack::base.remember_me') }}
+                                    </label>
+                                </div>
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <div>
+                                <button type="submit" class="btn btn-block btn-primary">
+                                    {{ trans('backpack::base.login') }}
+                                </button>
+                            </div>
+                        </div>
+                    </form>
+                </div>
+            </div>
+            @if (backpack_users_have_email() && backpack_email_column() == 'email' && config('backpack.base.setup_password_recovery_routes', true))
+                <div class="text-center"><a href="{{ route('backpack.auth.password.reset') }}">{{ trans('backpack::base.forgot_your_password') }}</a></div>
+            @endif
+            @if (config('backpack.base.registration_open'))
+                <div class="text-center"><a href="{{ route('backpack.auth.register') }}">{{ trans('backpack::base.register') }}</a></div>
+            @endif
+        </div>
+    </div>
+@endsection
diff --git a/resources/views/vendor/backpack/base/auth/passwords/email.blade.php b/resources/views/vendor/backpack/base/auth/passwords/email.blade.php
new file mode 100644 (file)
index 0000000..6054f43
--- /dev/null
@@ -0,0 +1,64 @@
+@extends(backpack_view('layouts.plain'))
+
+{{-- Main Content --}}
+@section('content')
+    <div class="row justify-content-center">
+        <div class="col-12 col-md-9 col-lg-6">
+            <h3 class="text-center mb-4">{{ trans('backpack::base.reset_password') }}</h3>
+            <div class="nav-steps-wrapper">
+                <ul class="nav nav-tabs">
+                  <li class="nav-item active"><a class="nav-link active" href="#tab_1" data-toggle="tab"><strong>{{ trans('backpack::base.step') }} 1.</strong> {{ trans('backpack::base.confirm_email') }}</a></li>
+                  <li class="nav-item"><a class="nav-link disabled text-muted"><strong>{{ trans('backpack::base.step') }} 2.</strong> {{ trans('backpack::base.choose_new_password') }}</a></li>
+                </ul>
+            </div>
+            <div class="nav-tabs-custom">
+                <div class="tab-content">
+                  <div class="tab-pane active" id="tab_1">
+                    @if (session('status'))
+                        <div class="alert alert-success mt-3">
+                            {{ session('status') }}
+                        </div>
+                    @else
+                    <form class="col-md-12 p-t-10" role="form" method="POST" action="{{ route('backpack.auth.password.email') }}">
+                        {!! csrf_field() !!}
+
+                        <div class="form-group">
+                            <label class="control-label" for="email">{{ trans('backpack::base.email_address') }}</label>
+
+                            <div>
+                                <input type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" id="email" value="{{ old('email') }}">
+
+                                @if ($errors->has('email'))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first('email') }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group mb-3">
+                            <div>
+                                <button type="submit" class="btn btn-block btn-primary">
+                                    {{ trans('backpack::base.send_reset_link') }}
+                                </button>
+                            </div>
+                        </div>
+                    </form>
+                    @endif
+                    <div class="clearfix"></div>
+                  </div>
+                  {{-- /.tab-pane --}}
+                </div>
+                {{-- /.tab-content --}}
+              </div>
+
+              <div class="text-center mt-4">
+                <a href="{{ route('backpack.auth.login') }}">{{ trans('backpack::base.login') }}</a>
+
+                @if (config('backpack.base.registration_open'))
+                / <a href="{{ route('backpack.auth.register') }}">{{ trans('backpack::base.register') }}</a>
+                @endif
+              </div>
+        </div>
+    </div>
+@endsection
diff --git a/resources/views/vendor/backpack/base/auth/passwords/reset.blade.php b/resources/views/vendor/backpack/base/auth/passwords/reset.blade.php
new file mode 100644 (file)
index 0000000..8f83034
--- /dev/null
@@ -0,0 +1,83 @@
+@extends(backpack_view('layouts.plain'))
+
+@section('content')
+    <div class="row justify-content-center">
+        <div class="col-12 col-md-9 col-lg-6">
+            <h3 class="text-center mb-4">{{ trans('backpack::base.reset_password') }}</h3>
+            <div class="nav-steps-wrapper">
+                <ul class="nav nav-tabs">
+                      <li class="nav-item"><a class="nav-link disabled text-muted"><strong>{{ trans('backpack::base.step') }} 1.</strong> {{ trans('backpack::base.confirm_email') }}</a></li>
+                      <li class="nav-item active"><a class="nav-link active"><strong>{{ trans('backpack::base.step') }} 2.</strong> {{ trans('backpack::base.choose_new_password') }}</a></li>
+                </ul>
+            </div>
+            <div class="nav-tabs-custom">
+                <div class="tab-content">
+                  <div class="tab-pane active" id="tab_1">
+                    @if (session('status'))
+                        <div class="alert alert-success">
+                            {{ session('status') }}
+                        </div>
+                    @endif
+                    <form class="col-md-12 p-t-10" role="form" method="POST" action="{{ route('backpack.auth.password.reset') }}">
+                        {!! csrf_field() !!}
+
+                        <input type="hidden" name="token" value="{{ $token }}">
+
+                        <div class="form-group">
+                            <label class="control-label" for="email">{{ trans('backpack::base.email_address') }}</label>
+
+                            <div>
+                                <input type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" id="email" value="{{ $email ?? old('email') }}">
+
+                                @if ($errors->has('email'))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first('email') }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <label class="control-label" for="password">{{ trans('backpack::base.new_password') }}</label>
+
+                            <div>
+                                <input type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" id="password">
+
+                                @if ($errors->has('password'))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first('password') }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <label class="control-label" for="password_confirmation">{{ trans('backpack::base.confirm_new_password') }}</label>
+                            <div>
+                                <input type="password" class="form-control{{ $errors->has('password_confirmation') ? ' is-invalid' : '' }}" name="password_confirmation" id="password_confirmation">
+
+                                @if ($errors->has('password_confirmation'))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first('password_confirmation') }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group mb-3">
+                            <div>
+                                <button type="submit" class="btn btn-block btn-primary">
+                                    {{ trans('backpack::base.change_password') }}
+                                </button>
+                            </div>
+                        </div>
+                    </form>
+                    <div class="clearfix"></div>
+                  </div>
+                  {{-- /.tab-pane --}}
+                </div>
+                {{-- /.tab-content --}}
+              </div>
+        </div>
+    </div>
+@endsection
diff --git a/resources/views/vendor/backpack/base/auth/register.blade.php b/resources/views/vendor/backpack/base/auth/register.blade.php
new file mode 100644 (file)
index 0000000..0555f8e
--- /dev/null
@@ -0,0 +1,84 @@
+@extends(backpack_view('layouts.plain'))
+
+@section('content')
+    <div class="row justify-content-center">
+        <div class="col-12 col-md-8 col-lg-4">
+            <h3 class="text-center mb-4">{{ trans('backpack::base.register') }}</h3>
+            <div class="card">
+                <div class="card-body">
+                    <form class="col-md-12 p-t-10" role="form" method="POST" action="{{ route('backpack.auth.register') }}">
+                        {!! csrf_field() !!}
+
+                        <div class="form-group">
+                            <label class="control-label" for="name">{{ trans('backpack::base.name') }}</label>
+
+                            <div>
+                                <input type="text" class="form-control{{ $errors->has('name') ? ' is-invalid' : '' }}" name="name" id="name" value="{{ old('name') }}">
+
+                                @if ($errors->has('name'))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first('name') }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <label class="control-label" for="{{ backpack_authentication_column() }}">{{ config('backpack.base.authentication_column_name') }}</label>
+
+                            <div>
+                                <input type="{{ backpack_authentication_column()==backpack_email_column()?'email':'text'}}" class="form-control{{ $errors->has(backpack_authentication_column()) ? ' is-invalid' : '' }}" name="{{ backpack_authentication_column() }}" id="{{ backpack_authentication_column() }}" value="{{ old(backpack_authentication_column()) }}">
+
+                                @if ($errors->has(backpack_authentication_column()))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first(backpack_authentication_column()) }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <label class="control-label" for="password">{{ trans('backpack::base.password') }}</label>
+
+                            <div>
+                                <input type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" id="password">
+
+                                @if ($errors->has('password'))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first('password') }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <label class="control-label" for="password_confirmation">{{ trans('backpack::base.confirm_password') }}</label>
+
+                            <div>
+                                <input type="password" class="form-control{{ $errors->has('password_confirmation') ? ' is-invalid' : '' }}" name="password_confirmation" id="password_confirmation">
+
+                                @if ($errors->has('password_confirmation'))
+                                    <span class="invalid-feedback">
+                                        <strong>{{ $errors->first('password_confirmation') }}</strong>
+                                    </span>
+                                @endif
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <div>
+                                <button type="submit" class="btn btn-block btn-primary">
+                                    {{ trans('backpack::base.register') }}
+                                </button>
+                            </div>
+                        </div>
+                    </form>
+                </div>
+            </div>
+            @if (backpack_users_have_email() && backpack_email_column() == 'email' && config('backpack.base.setup_password_recovery_routes', true))
+                <div class="text-center"><a href="{{ route('backpack.auth.password.reset') }}">{{ trans('backpack::base.forgot_your_password') }}</a></div>
+            @endif
+            <div class="text-center"><a href="{{ route('backpack.auth.login') }}">{{ trans('backpack::base.login') }}</a></div>
+        </div>
+    </div>
+@endsection
diff --git a/resources/views/vendor/backpack/base/blank.blade.php b/resources/views/vendor/backpack/base/blank.blade.php
new file mode 100644 (file)
index 0000000..892031b
--- /dev/null
@@ -0,0 +1,33 @@
+@extends(backpack_view('layouts.top_left'))
+
+@php
+       // Merge widgets that were fluently declared with widgets declared without the fluent syntax: 
+       // - $data['widgets']['before_content']
+       // - $data['widgets']['after_content']
+       if (isset($widgets)) {
+               foreach ($widgets as $section => $widgetSection) {
+                       foreach ($widgetSection as $key => $widget) {
+                               \Backpack\CRUD\app\Library\Widget::add($widget)->section($section);
+                       }
+               }
+       }
+@endphp
+
+@section('before_breadcrumbs_widgets')
+       @include(backpack_view('inc.widgets'), [ 'widgets' => app('widgets')->where('section', 'before_breadcrumbs')->toArray() ])
+@endsection
+
+@section('after_breadcrumbs_widgets')
+       @include(backpack_view('inc.widgets'), [ 'widgets' => app('widgets')->where('section', 'after_breadcrumbs')->toArray() ])
+@endsection
+
+@section('before_content_widgets')
+       @include(backpack_view('inc.widgets'), [ 'widgets' => app('widgets')->where('section', 'before_content')->toArray() ])
+@endsection
+
+@section('content')
+@endsection
+
+@section('after_content_widgets')
+       @include(backpack_view('inc.widgets'), [ 'widgets' => app('widgets')->where('section', 'after_content')->toArray() ])
+@endsection
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/dashboard.blade.php b/resources/views/vendor/backpack/base/dashboard.blade.php
new file mode 100644 (file)
index 0000000..b20efb1
--- /dev/null
@@ -0,0 +1,21 @@
+@extends(backpack_view('blank'))
+
+@php
+    if (config('backpack.base.show_getting_started')) {
+        $widgets['before_content'][] = [
+            'type'        => 'view',
+            'view'        => 'backpack::inc.getting_started',
+        ];
+    } else {
+        $widgets['before_content'][] = [
+            'type'        => 'jumbotron',
+            'heading'     => trans('backpack::base.welcome'),
+            'content'     => trans('backpack::base.use_sidebar'),
+            'button_link' => backpack_url('logout'),
+            'button_text' => trans('backpack::base.logout'),
+        ];
+    }
+@endphp
+
+@section('content')
+@endsection
diff --git a/resources/views/vendor/backpack/base/inc/alerts.blade.php b/resources/views/vendor/backpack/base/inc/alerts.blade.php
new file mode 100644 (file)
index 0000000..6c26336
--- /dev/null
@@ -0,0 +1,47 @@
+{{-- Bootstrap Notifications using Prologue Alerts & PNotify JS --}}
+<script type="text/javascript">
+    // This is intentionaly run after dom loads so this way we can avoid showing duplicate alerts
+    // when the user is beeing redirected by persistent table, that happens before this event triggers.
+    document.onreadystatechange = function() {
+        if (document.readyState == "interactive") {
+            Noty.overrideDefaults({
+                layout: 'topRight',
+                theme: 'backstrap',
+                timeout: 2500,
+                closeWith: ['click', 'button'],
+            });
+
+            // get alerts from the alert bag
+            var $alerts_from_php = {{ Illuminate\Support\Js::from(\Alert::getMessages()) }};
+
+            // get the alerts from the localstorage
+            var $alerts_from_localstorage = JSON.parse(localStorage.getItem('backpack_alerts')) ?
+                JSON.parse(localStorage.getItem('backpack_alerts')) : {};
+
+            // merge both php alerts and localstorage alerts
+            Object.entries($alerts_from_php).forEach(function(type) {
+                if (typeof $alerts_from_localstorage[type[0]] !== 'undefined') {
+                    type[1].forEach(function(msg) {
+                        $alerts_from_localstorage[type[0]].push(msg);
+                    });
+                } else {
+                    $alerts_from_localstorage[type[0]] = type[1];
+                }
+            });
+
+            for (var type in $alerts_from_localstorage) {
+                let messages = new Set($alerts_from_localstorage[type]);
+
+                messages.forEach(function(text) {
+                    let alert = {};
+                    alert['type'] = type;
+                    alert['text'] = text;
+                    new Noty(alert).show()
+                });
+            }
+
+            // in the end, remove backpack alerts from localStorage
+            localStorage.removeItem('backpack_alerts');
+        }
+    };
+</script>
diff --git a/resources/views/vendor/backpack/base/inc/breadcrumbs.blade.php b/resources/views/vendor/backpack/base/inc/breadcrumbs.blade.php
new file mode 100644 (file)
index 0000000..05e449d
--- /dev/null
@@ -0,0 +1,13 @@
+@if (config('backpack.base.breadcrumbs') && isset($breadcrumbs) && is_array($breadcrumbs) && count($breadcrumbs))
+       <nav aria-label="breadcrumb" class="d-none d-lg-block">
+         <ol class="breadcrumb bg-transparent p-0 {{ config('backpack.base.html_direction') == 'rtl' ? 'justify-content-start' : 'justify-content-end' }}">
+               @foreach ($breadcrumbs as $label => $link)
+                       @if ($link)
+                           <li class="breadcrumb-item text-capitalize"><a href="{{ $link }}">{{ $label }}</a></li>
+                       @else
+                           <li class="breadcrumb-item text-capitalize active" aria-current="page">{{ $label }}</li>
+                       @endif
+               @endforeach
+         </ol>
+       </nav>
+@endif
diff --git a/resources/views/vendor/backpack/base/inc/footer.blade.php b/resources/views/vendor/backpack/base/inc/footer.blade.php
new file mode 100644 (file)
index 0000000..b8b9300
--- /dev/null
@@ -0,0 +1,10 @@
+@if (config('backpack.base.show_powered_by') || config('backpack.base.developer_link'))
+    <div class="text-muted ml-auto mr-auto">
+      @if (config('backpack.base.developer_link') && config('backpack.base.developer_name'))
+      {{ trans('backpack::base.handcrafted_by') }} <a target="_blank" rel="noopener" href="{{ config('backpack.base.developer_link') }}">{{ config('backpack.base.developer_name') }}</a>.
+      @endif
+      @if (config('backpack.base.show_powered_by'))
+      {{ trans('backpack::base.powered_by') }} <a target="_blank" rel="noopener" href="http://backpackforlaravel.com?ref=panel_footer_link">Backpack for Laravel</a>.
+      @endif
+    </div>
+@endif
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/inc/full_screen_loader.blade.php b/resources/views/vendor/backpack/base/inc/full_screen_loader.blade.php
new file mode 100644 (file)
index 0000000..00f4bee
--- /dev/null
@@ -0,0 +1,136 @@
+@push('after_styles')
+  <style>
+    .loading_modal_dialog {
+      position: fixed;
+      z-index: 999;
+      height: 2em;
+      width: 2em;
+      overflow: visible;
+      margin: auto;
+      top: 0;
+      left: 0;
+      bottom: 0;
+      right: 0;
+      display:none;
+      -webkit-user-select: none;  /* Chrome all / Safari all */
+      -moz-user-select: none;     /* Firefox all */
+      -ms-user-select: none;      /* IE 10+ */
+      user-select: none;          /* Likely future */
+    }
+    .loading_modal_dialog:before {
+      content: '';
+      display: block;
+      position: fixed;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background-color: rgba(0,0,0,0.3);
+    }
+    .loading_modal_dialog:after {
+      content: 'teste';
+    }
+
+    /* :not(:required) hides these rules from IE9 and below */
+    .loading_modal_dialog:not(:required) {
+      /* hide "loading..." text */
+      font: 0/0 a;
+      color: transparent;
+      text-shadow: none;
+      background-color: transparent;
+      border: 0;
+    }
+
+    .loading_modal_dialog:not(:required):after {
+      content: '';
+      display: block;
+      font-size: 10px;
+      width: 0.5em;
+      height: 0.5em;
+      margin-top: -0.5em;
+      -webkit-animation: spinner 1500ms infinite linear;
+      -moz-animation: spinner 1500ms infinite linear;
+      -ms-animation: spinner 1500ms infinite linear;
+      -o-animation: spinner 1500ms infinite linear;
+      animation: spinner 1500ms infinite linear;
+      border-radius: 0.5em;
+      -webkit-box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.5) -1.5em 0 0 0, rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
+      box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) -1.5em 0 0 0, rgba(0, 0, 0, 0.75) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
+    }
+
+    /* Animation */
+
+    @-webkit-keyframes spinner {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -moz-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        -o-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -moz-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        -o-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+    @-moz-keyframes spinner {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -moz-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        -o-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -moz-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        -o-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+    @-o-keyframes spinner {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -moz-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        -o-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -moz-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        -o-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+    @keyframes spinner {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -moz-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        -o-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -moz-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        -o-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+  </style>
+@endpush
+
+@push('after_scripts')
+  <script>
+    jQuery(document).ready(function($) {
+        $( "body" ).prepend('<div class="loading_modal_dialog"></div>');
+    });
+  </script>
+@endpush
diff --git a/resources/views/vendor/backpack/base/inc/getting_started.blade.php b/resources/views/vendor/backpack/base/inc/getting_started.blade.php
new file mode 100644 (file)
index 0000000..a90c5b8
--- /dev/null
@@ -0,0 +1,127 @@
+<div class="card">
+  <div class="card-body">
+
+    <h3>Getting Started</h3>
+    <p>If it's your first time using Backpack, we heavily recommend you follow the steps below:</p>
+
+    <div id="accordion" role="tablist">
+      <div class="card mb-1">
+        <div class="card-header bg-light" id="headingOne" role="tab">
+          <h5 class="mb-0"><a data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne" class="collapsed text-dark"><span class="badge badge-warning mr-2 mt-n2">1</span>Create your first CRUD <small class="float-right mt-2">1-5 min</small></a></h5>
+        </div>
+        <div class="collapse" id="collapseOne" role="tabpanel" aria-labelledby="headingOne" data-parent="#accordion" style="">
+          <div class="card-body">
+            <p>You've already got a model, <code class="text-primary bg-light p-1 rounded">App\Models\User</code>... all Laravel projects do. So <strong>let's create a page to administer users</strong>. We want the admin to Create, Read, Update and Delete them. In Backpack, we call that a <a href="https://backpackforlaravel.com/docs/5.x/crud-basics?ref=getting-started-widget" target="blank">CRUD</a>. And you can easily generate one for an existing Eloquent model, by running:</p>
+            <p>
+              <strong><code class="text-primary bg-light p-1 rounded">php artisan backpack:crud user</code></strong>
+            </p>
+            <p>Run that in your terminal and <strong>choose <code class="text-primary bg-light p-1 rounded">field</code> when asked which <a href="https://backpackforlaravel.com/docs/5.x/crud-operation-create#validation?ref=getting-started-widget"
+              target="_blank">validation type</a> you'd like</strong>. You can now click on the new sidebar item (or <a href="{{ backpack_url('user') }}">here</a>) and you'll be able to see the entries in the <code class="text-primary bg-light p-1 rounded">users</code> table. Now... even though most generated CRUDs work out-of-the-box, they probably won't be <i>exactly</i> what you need. But that's where Backpack shines, in how easy it is to customize.</p>
+
+            <p>To dig a little deeper, <a href="#" data-toggle="collapse" data-target="#customizeUsersCRUD" aria-expanded="true" aria-controls="customizeUsersCRUD">let's make a few changes to the Users CRUD <i class="la la-angle-double-right"></i></a></p>
+
+            <div class="collapse" id="customizeUsersCRUD">
+              <p><strong>1. When Listing, let's remove the "password" column</strong> - no point in showing the hash. To do that, go to <code class="text-primary bg-light p-1 rounded">UserCrudController::setupListOperation()</code> and remove the line saying <code class="text-primary bg-light p-1 rounded">CRUD::column('password');</code> - easy-peasy, right?</p>
+              <p><strong>2. On Create & Update, let's add validation to forms</strong>. There are <a href="https://backpackforlaravel.com/docs/5.x/crud-operation-create#validation?ref=getting-started-widget" target="_blank">multiple ways to add validation</a> but we've already chosen the simplest, <a href="https://backpackforlaravel.com/docs/5.x/crud-operation-create#validating-fields-using-field-attributes?ref=getting-started-widget" target="_blank">validation using field attributes</a>. Let's go to <code class="text-primary bg-light p-1 rounded">setupCreateOperation()</code> and specify our validation rules directly on the fields:
+                <p>
+                  <pre class="language-php rounded"><code class="language-php p-1">
+    CRUD::field('name')->validationRules('required|min:5');
+    CRUD::field('email')->validationRules('required|email|unique:users,email');
+    CRUD::field('password')->validationRules('required');
+                  </code></pre>
+                </p>
+              <p><strong>3. On Create, let's hash the password.</strong> Currently, if we create a new User, it'll work. But if you look in the database... you'll notice the password is stored in plain text. We don't want that - we want it hashed. There are <a href="https://backpackforlaravel.com/docs/5.x/crud-operation-create#use-events-in-your-setup-method?ref=getting-started-widget" target="_blank">multiple ways to achieve this too</a>. Let's use Model Events inside <code class="text-primary bg-light p-1 rounded">setupCreateOperation()</code>. Here's how our method could look, when we also tap into the <code class="text-primary bg-light p-1 rounded">creating</code> event, to hash the password:</p>
+              <p>
+                <pre class="language-php rounded"><code class="language-php p-1">
+      protected function setupCreateOperation()
+      {
+          CRUD::field('name')->validationRules('required|min:5');
+          CRUD::field('email')->validationRules('required|email|unique:users,email');
+          CRUD::field('password')->validationRules('required');
+
+          \App\Models\User::creating(function ($entry) {
+              $entry->password = \Hash::make($entry->password);
+          });
+      }
+                </code></pre>
+              </p>
+              <p><strong>4. On Update, let's not require the password</strong>. It should only be needed if an admin wants to change it, right? That means the validation rules will be different for "password". But then again... the rules will also be different for "email" (because on Update, we need to pass the ID to the unique rule in Laravel). Since 2/3 rules are different, let's just delete what was inside <code class="text-primary bg-light p-1 rounded">setupUpdateOperation()</code> and code it from scratch:</p>
+              <p>
+                <pre class="language-php rounded"><code class="language-php p-1">
+      protected function setupUpdateOperation()
+      {
+          CRUD::field('name')->validationRules('required|min:5');
+          CRUD::field('email')->validationRules('required|email|unique:users,email,'.CRUD::getCurrentEntryId());
+          CRUD::field('password')->hint('Type a password to change it.');
+
+          \App\Models\User::updating(function ($entry) {
+              if (request('password') == null) {
+                  $entry->password = $entry->getOriginal('password');
+              } else {
+                  $entry->password = \Hash::make(request('password'));
+              }
+          });
+      }
+                </code></pre>
+              </p>
+              <p>
+                That's it. You have a working Users CRUD. Plus, you've already learned some advanced techniques, like <a href="https://backpackforlaravel.com/docs/5.x/crud-operation-create#use-events-in-your-setup-method?ref=getting-started-widget" target="_blank">using Model events inside CrudController</a>. Of course, this only scratches the surface of what Backpack can do. To really understand how it works, and how you can best use Backpack's features, <strong>we heavily recommend you move on to the next step, and learn the basics.</strong>
+              </p>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="card mb-1">
+        <div class="card-header bg-light" id="headingTwo" role="tab">
+          <h5 class="mb-0"><a class="collapsed text-dark" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"><span class="badge badge-warning mr-2 mt-n2">2</span>Learn the basics <small class="float-right mt-2">20-30 min</small></a></h5>
+        </div>
+        <div class="collapse" id="collapseTwo" role="tabpanel" aria-labelledby="headingTwo" data-parent="#accordion" style="">
+          <div class="card-body">
+            <p>So you've created your first CRUD? Excellent. Now it's time to understand <i>how it works</i> and <i>what else you can do</i>. Time to learn the basics - how to build and customize admin panels using Backpack. Please follow one of the courses below, depending on how you prefer to learn:</p>
+            <ul>
+              <li><strong><a target="_blank" href="https://backpackforlaravel.com/docs/5.x/getting-started-videos?ref=getting-started-widget">Video Course</a></strong> - 31 minutes</li>
+              <li><strong><a target="_blank" href="https://backpackforlaravel.com/docs/5.x/getting-started-basics?ref=getting-started-widget">Text Course</a></strong> - 20 minutes</li>
+              <li><strong><a target="_blank" href="https://backpackforlaravel.com/getting-started-emails?ref=getting-started-widget">Email Course</a></strong> - 1 email per day, for 4 days, 5 minutes each</li>
+            </ul>
+          </div>
+        </div>
+      </div>
+      <div class="card mb-1">
+        <div class="card-header bg-light" id="headingThree" role="tab">
+          <h5 class="mb-0"><a class="collapsed text-dark" data-toggle="collapse" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree"><span class="badge badge-warning mr-2 mt-n2">4</span>Subscribe or purchase <small class="float-right mt-2">1-3 min</small></a></h5>
+        </div>
+        <div class="collapse" id="collapseThree" role="tabpanel" aria-labelledby="headingThree" data-parent="#accordion" style="">
+          <div class="card-body">
+            <p>If you decide to use Backpack, please <strong><a target="_blank" href="https://backpackforlaravel.com/register?ref=getting-started-widget">create a Backpack account</a> and stay subscribed to the Security Newsletter</strong> (1-2 emails per year). That way, we can let you know if your admin panel becomes vulnerable in any way.</p>
+            <p>Of course, if you like our free & open-source core, you might also enjoy our premium add-ons:</p>
+            <ul>
+              <li><strong><a target="_blank" href="https://backpackforlaravel.com/products/pro-for-unlimited-projects?ref=getting-started-widget">PRO</a></strong> - adds 28 fields, 10 filters, 6 columns, 5 operations, 1 widget</li>
+              <li><strong><a target="_blank" href="https://backpackforlaravel.com/products/devtools?ref=getting-started-widget">DevTools</a></strong> - easily generate Laravel migrations and models, from a web interface</li>
+              <li><strong><a target="_blank" href="https://backpackforlaravel.com/products/figma-template?ref=getting-started-widget">FigmaTemplate</a></strong> - create designs and mockups that are easy to implement in Backpack</li>
+              <li><strong><a target="_blank" href="https://backpackforlaravel.com/products/editable-columns?ref=getting-started-widget">EditableColumns</a></strong> - let your admins make quick edits, right from the table view</li>
+            </ul>
+          </div>
+        </div>
+      </div>
+      <div class="card mb-1">
+        <div class="card-header bg-light" id="headingThree" role="tab">
+          <h5 class="mb-0"><a class="collapsed text-dark" data-toggle="collapse" href="#collapseFour" aria-expanded="false" aria-controls="collapseFour"><span class="badge badge-warning mr-2 mt-n2">4</span>Hide this notice <small class="float-right mt-2">1 min</small></a></h5>
+        </div>
+        <div class="collapse" id="collapseFour" role="tabpanel" aria-labelledby="headingThree" data-parent="#accordion" style="">
+          <div class="card-body">Go to your <code class="text-primary bg-light p-1 rounded">config/backpack/base.php</code> and change <code class="text-primary bg-light p-1 rounded">show_getting_started</code> to <code class="text-primary bg-light p-1 rounded">false</code>.</div>
+        </div>
+      </div>
+    </div>
+
+    <p class="mt-3 mb-0"><small>* this card is only visible on <i>localhost</i>. Follow the last step to hide it from <i>localhost</i> too.</small></p>
+  </div>
+</div>
+
+@push('after_styles')
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/base16/dracula.min.css">
+@endpush
+
+@push('after_scripts')
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
+  <script>hljs.highlightAll();</script>
+@endpush
diff --git a/resources/views/vendor/backpack/base/inc/head.blade.php b/resources/views/vendor/backpack/base/inc/head.blade.php
new file mode 100644 (file)
index 0000000..b9c255c
--- /dev/null
@@ -0,0 +1,32 @@
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
+    @if (config('backpack.base.meta_robots_content'))<meta name="robots" content="{{ config('backpack.base.meta_robots_content', 'noindex, nofollow') }}"> @endif
+
+    <meta name="csrf-token" content="{{ csrf_token() }}" /> {{-- Encrypted CSRF token for Laravel, in order for Ajax requests to work --}}
+    <title>{{ isset($title) ? $title.' :: '.config('backpack.base.project_name') : config('backpack.base.project_name') }}</title>
+
+    @yield('before_styles')
+    @stack('before_styles')
+
+    @foreach(config('backpack.base.styles', []) as $path)
+        <link rel="stylesheet" type="text/css" href="{{ asset($path).'?v='.config('backpack.base.cachebusting_string') }}">
+    @endforeach
+
+    @foreach(config('backpack.base.mix_styles', []) as $path => $manifest)
+        <link rel="stylesheet" type="text/css" href="{{ mix($path, $manifest) }}">
+    @endforeach
+
+    @if(!empty(config('backpack.base.vite_styles', [])))
+        @vite(config('backpack.base.vite_styles', []))
+    @endif
+    
+    @yield('after_styles')
+    @stack('after_styles')
+
+    {{-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --}}
+    {{-- WARNING: Respond.js doesn't work if you view the page via file:// --}}
+    <!--[if lt IE 9]>
+    <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
+    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+    <![endif]-->
diff --git a/resources/views/vendor/backpack/base/inc/main_header.blade.php b/resources/views/vendor/backpack/base/inc/main_header.blade.php
new file mode 100644 (file)
index 0000000..d38619d
--- /dev/null
@@ -0,0 +1,14 @@
+<header class="{{ config('backpack.base.header_class') }}">
+  {{-- Logo --}}
+  <button class="navbar-toggler sidebar-toggler d-lg-none mr-auto ml-3" type="button" data-toggle="sidebar-show" aria-label="{{ trans('backpack::base.toggle_navigation')}}">
+    <span class="navbar-toggler-icon"></span>
+  </button>
+  <a class="navbar-brand" href="{{ url(config('backpack.base.home_link')) }}" title="{{ config('backpack.base.project_name') }}">
+    {!! config('backpack.base.project_logo') !!}
+  </a>
+  <button class="navbar-toggler sidebar-toggler d-md-down-none" type="button" data-toggle="sidebar-lg-show" aria-label="{{ trans('backpack::base.toggle_navigation')}}">
+    <span class="navbar-toggler-icon"></span>
+  </button>
+
+  @include(backpack_view('inc.menu'))
+</header>
diff --git a/resources/views/vendor/backpack/base/inc/menu.blade.php b/resources/views/vendor/backpack/base/inc/menu.blade.php
new file mode 100644 (file)
index 0000000..d62a034
--- /dev/null
@@ -0,0 +1,32 @@
+{{-- =================================================== --}}
+{{-- ========== Top menu items (ordered left) ========== --}}
+{{-- =================================================== --}}
+<ul class="nav navbar-nav d-md-down-none">
+
+    @if (backpack_auth()->check())
+        {{-- Topbar. Contains the left part --}}
+        @include(backpack_view('inc.topbar_left_content'))
+    @endif
+
+</ul>
+{{-- ========== End of top menu left items ========== --}}
+
+
+
+{{-- ========================================================= --}}
+{{-- ========= Top menu right items (ordered right) ========== --}}
+{{-- ========================================================= --}}
+<ul class="nav navbar-nav ml-auto @if(config('backpack.base.html_direction') == 'rtl') mr-0 @endif">
+    @if (backpack_auth()->guest())
+        <li class="nav-item"><a class="nav-link" href="{{ route('backpack.auth.login') }}">{{ trans('backpack::base.login') }}</a>
+        </li>
+        @if (config('backpack.base.registration_open'))
+            <li class="nav-item"><a class="nav-link" href="{{ route('backpack.auth.register') }}">{{ trans('backpack::base.register') }}</a></li>
+        @endif
+    @else
+        {{-- Topbar. Contains the right part --}}
+        @include(backpack_view('inc.topbar_right_content'))
+        @include(backpack_view('inc.menu_user_dropdown'))
+    @endif
+</ul>
+{{-- ========== End of top menu right items ========== --}}
diff --git a/resources/views/vendor/backpack/base/inc/menu_user_dropdown.blade.php b/resources/views/vendor/backpack/base/inc/menu_user_dropdown.blade.php
new file mode 100644 (file)
index 0000000..fe64f2b
--- /dev/null
@@ -0,0 +1,13 @@
+<li class="nav-item dropdown pr-4">
+  <a class="nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" style="position: relative;width: 35px;height: 35px;margin: 0 10px;">
+    <img class="img-avatar" src="{{ backpack_avatar_url(backpack_auth()->user()) }}" alt="{{ backpack_auth()->user()->name }}" onerror="this.style.display='none'" style="margin: 0;position: absolute;left: 0;z-index: 1;">
+    <span class="backpack-avatar-menu-container" style="position: absolute;left: 0;width: 100%;background-color: #00a65a;border-radius: 50%;color: #FFF;line-height: 35px;font-size: 85%;font-weight: 300;">
+      {{backpack_user()->getAttribute('name') ? mb_substr(backpack_user()->name, 0, 1, 'UTF-8') : 'A'}}
+    </span>
+  </a>
+  <div class="dropdown-menu {{ config('backpack.base.html_direction') == 'rtl' ? 'dropdown-menu-left' : 'dropdown-menu-right' }} mr-4 pb-1 pt-1">
+    <a class="dropdown-item" href="{{ route('backpack.account.info') }}"><i class="la la-user"></i> {{ trans('backpack::base.my_account') }}</a>
+    <div class="dropdown-divider"></div>
+    <a class="dropdown-item" href="{{ backpack_url('logout') }}"><i class="la la-lock"></i> {{ trans('backpack::base.logout') }}</a>
+  </div>
+</li>
diff --git a/resources/views/vendor/backpack/base/inc/scripts.blade.php b/resources/views/vendor/backpack/base/inc/scripts.blade.php
new file mode 100644 (file)
index 0000000..0d5ee1f
--- /dev/null
@@ -0,0 +1,69 @@
+@foreach(config('backpack.base.scripts', []) as $path)
+    <script type="text/javascript" src="{{ asset($path).'?v='.config('backpack.base.cachebusting_string') }}"></script>
+@endforeach
+
+@foreach(config('backpack.base.mix_scripts', []) as $path => $manifest)
+    <script type="text/javascript" src="{{ mix($path, $manifest) }}"></script>
+@endforeach
+
+@if(!empty(config('backpack.base.vite_scripts', [])))
+    @vite(config('backpack.base.vite_scripts', []))
+@endif
+
+@include('backpack::inc.alerts')
+
+{{-- page script --}}
+<script type="text/javascript">
+    // To make Pace works on Ajax calls
+    $(document).ajaxStart(function() { Pace.restart(); });
+
+    // polyfill for `startsWith` from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
+    if (!String.prototype.startsWith) {
+    Object.defineProperty(String.prototype, 'startsWith', {
+        value: function(search, rawPos) {
+            var pos = rawPos > 0 ? rawPos|0 : 0;
+            return this.substring(pos, pos + search.length) === search;
+        }
+    });
+    }
+
+
+
+    // polyfill for entries and keys from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#polyfill
+    if (!Object.keys) Object.keys = function(o) {
+        if (o !== Object(o))
+            throw new TypeError('Object.keys called on a non-object');
+        var k=[],p;
+        for (p in o) if (Object.prototype.hasOwnProperty.call(o,p)) k.push(p);
+        return k;
+    }
+
+    if (!Object.entries) {
+        Object.entries = function( obj ){
+            var ownProps = Object.keys( obj ),
+                i = ownProps.length,
+                resArray = new Array(i); // preallocate the Array
+            while (i--)
+            resArray[i] = [ownProps[i], obj[ownProps[i]]];
+            return resArray;
+        };
+    }
+
+    // Ajax calls should always have the CSRF token attached to them, otherwise they won't work
+    $.ajaxSetup({
+        headers: {
+            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
+        }
+    });
+
+    {{-- Enable deep link to tab --}}
+    var activeTab = $('[href="' + location.hash.replace("#", "#tab_") + '"]');
+    location.hash && activeTab && activeTab.tab('show');
+    $('.nav-tabs a').on('shown.bs.tab', function (e) {
+        location.hash = e.target.hash.replace("#tab_", "#");
+    });
+</script>
+
+@if(config('app.debug'))
+    @include('crud::inc.ajax_error_frame')
+@endif
diff --git a/resources/views/vendor/backpack/base/inc/sidebar.blade.php b/resources/views/vendor/backpack/base/inc/sidebar.blade.php
new file mode 100644 (file)
index 0000000..93e4c0d
--- /dev/null
@@ -0,0 +1,94 @@
+@if (backpack_auth()->check())
+    {{-- Left side column. contains the sidebar --}}
+    <div class="{{ config('backpack.base.sidebar_class') }}">
+      {{-- sidebar: style can be found in sidebar.less --}}
+      <nav class="sidebar-nav overflow-hidden">
+        {{-- sidebar menu: : style can be found in sidebar.less --}}
+        <ul class="nav">
+          {{-- <li class="nav-title">{{ trans('backpack::base.administration') }}</li> --}}
+          {{-- ================================================ --}}
+          {{-- ==== Recommended place for admin menu items ==== --}}
+          {{-- ================================================ --}}
+
+          @include(backpack_view('inc.sidebar_content'))
+
+          {{-- ======================================= --}}
+          {{-- <li class="divider"></li> --}}
+          {{-- <li class="nav-title">Entries</li> --}}
+        </ul>
+      </nav>
+      {{-- /.sidebar --}}
+    </div>
+@endif
+
+@push('before_scripts')
+  <script type="text/javascript">
+    // Save default sidebar class
+    let sidebarClass = (document.body.className.match(/sidebar-(sm|md|lg|xl)-show/) || ['sidebar-lg-show'])[0];
+    let sidebarTransition = function(value) {
+        document.querySelector('.app-body > .sidebar').style.transition = value || '';
+    };
+
+    // Recover sidebar state
+    let sessionState = sessionStorage.getItem('sidebar-collapsed');
+    if (sessionState) {
+      // disable the transition animation temporarily, so that if you're browsing across
+      // pages with the sidebar closed, the sidebar does not flicker into the view
+      sidebarTransition("none");
+      document.body.classList.toggle(sidebarClass, sessionState === '1');
+
+      // re-enable the transition, so that if the user clicks the hamburger menu, it does have a nice transition
+      setTimeout(sidebarTransition, 100);
+    }
+  </script>
+@endpush
+
+@push('after_scripts')
+  <script>
+      // Store sidebar state
+      document.querySelectorAll('.sidebar-toggler').forEach(function(toggler) {
+        toggler.addEventListener('click', function() {
+          sessionStorage.setItem('sidebar-collapsed', Number(!document.body.classList.contains(sidebarClass)))
+          // wait for the sidebar animation to end (250ms) and then update the table headers because datatables uses a cached version
+          // and dont update this values if there are dom changes after the table is draw. The sidebar toggling makes
+          // the table change width, so the headers need to be adjusted accordingly.
+          setTimeout(function() {
+            if(typeof crud !== "undefined" && crud.table) {
+              crud.table.fixedHeader.adjust();
+            }
+          }, 300);
+        })
+      });
+      // Set active state on menu element
+      var full_url = "{{ Request::fullUrl() }}";
+      var $navLinks = $(".sidebar-nav li a, .app-header li a");
+
+      // First look for an exact match including the search string
+      var $curentPageLink = $navLinks.filter(
+          function() { return $(this).attr('href') === full_url; }
+      );
+
+      // If not found, look for the link that starts with the url
+      if(!$curentPageLink.length > 0){
+          $curentPageLink = $navLinks.filter( function() {
+            if ($(this).attr('href').startsWith(full_url)) {
+              return true;
+            }
+
+            if (full_url.startsWith($(this).attr('href'))) {
+              return true;
+            }
+
+            return false;
+          });
+      }
+
+      // for the found links that can be considered current, make sure
+      // - the parent item is open
+      $curentPageLink.parents('li').addClass('open');
+      // - the actual element is active
+      $curentPageLink.each(function() {
+        $(this).addClass('active');
+      });
+  </script>
+@endpush
diff --git a/resources/views/vendor/backpack/base/inc/sidebar_content.blade.php b/resources/views/vendor/backpack/base/inc/sidebar_content.blade.php
new file mode 100644 (file)
index 0000000..1526d56
--- /dev/null
@@ -0,0 +1,2 @@
+{{-- This file is used to store sidebar items, inside the Backpack admin panel --}}
+<li class="nav-item"><a class="nav-link" href="{{ backpack_url('dashboard') }}"><i class="la la-home nav-icon"></i> {{ trans('backpack::base.dashboard') }}</a></li>
diff --git a/resources/views/vendor/backpack/base/inc/topbar_left_content.blade.php b/resources/views/vendor/backpack/base/inc/topbar_left_content.blade.php
new file mode 100644 (file)
index 0000000..25c09f7
--- /dev/null
@@ -0,0 +1,5 @@
+{{-- This file is used to store topbar (left) items --}}
+
+{{-- <li class="nav-item px-3"><a class="nav-link" href="#">Dashboard</a></li>
+<li class="nav-item px-3"><a class="nav-link" href="#">Users</a></li>
+<li class="nav-item px-3"><a class="nav-link" href="#">Settings</a></li> --}}
diff --git a/resources/views/vendor/backpack/base/inc/topbar_right_content.blade.php b/resources/views/vendor/backpack/base/inc/topbar_right_content.blade.php
new file mode 100644 (file)
index 0000000..9012de1
--- /dev/null
@@ -0,0 +1,6 @@
+{{-- This file is used to store topbar (right) items --}}
+
+
+{{-- <li class="nav-item d-md-down-none"><a class="nav-link" href="#"><i class="la la-bell"></i><span class="badge badge-pill badge-danger">5</span></a></li>
+<li class="nav-item d-md-down-none"><a class="nav-link" href="#"><i class="la la-list"></i></a></li>
+<li class="nav-item d-md-down-none"><a class="nav-link" href="#"><i class="la la-map"></i></a></li> --}}
diff --git a/resources/views/vendor/backpack/base/inc/widgets.blade.php b/resources/views/vendor/backpack/base/inc/widgets.blade.php
new file mode 100644 (file)
index 0000000..33b138f
--- /dev/null
@@ -0,0 +1,13 @@
+@if (!empty($widgets))
+       @foreach ($widgets as $currentWidget)
+
+               @if (is_array($currentWidget))
+                       @php
+                               $currentWidget = \Backpack\CRUD\app\Library\Widget::add($currentWidget);
+                       @endphp
+               @endif
+
+               @include($currentWidget->getFinalViewPath(), ['widget' => $currentWidget->toArray()])
+
+       @endforeach
+@endif
diff --git a/resources/views/vendor/backpack/base/layouts/plain.blade.php b/resources/views/vendor/backpack/base/layouts/plain.blade.php
new file mode 100644 (file)
index 0000000..f05906d
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="{{ app()->getLocale() }}" dir="{{ config('backpack.base.html_direction') }}">
+<head>
+    @include(backpack_view('inc.head'))
+</head>
+<body class="app flex-row align-items-center">
+
+  @yield('header')
+
+  <div class="container">
+  @yield('content')
+  </div>
+
+  <footer class="app-footer sticky-footer">
+    @include('backpack::inc.footer')
+  </footer>
+
+  @yield('before_scripts')
+  @stack('before_scripts')
+
+  @include(backpack_view('inc.scripts'))
+
+  @yield('after_scripts')
+  @stack('after_scripts')
+
+</body>
+</html>
diff --git a/resources/views/vendor/backpack/base/layouts/top_left.blade.php b/resources/views/vendor/backpack/base/layouts/top_left.blade.php
new file mode 100644 (file)
index 0000000..ba03b61
--- /dev/null
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+
+<html lang="{{ app()->getLocale() }}" dir="{{ config('backpack.base.html_direction') }}">
+
+<head>
+  @include(backpack_view('inc.head'))
+
+</head>
+
+<body class="{{ config('backpack.base.body_class') }}">
+
+  @include(backpack_view('inc.main_header'))
+
+  <div class="app-body">
+
+    @include(backpack_view('inc.sidebar'))
+
+    <main class="main pt-2">
+
+       @yield('before_breadcrumbs_widgets')
+
+       @includeWhen(isset($breadcrumbs), backpack_view('inc.breadcrumbs'))
+
+       @yield('after_breadcrumbs_widgets')
+
+       @yield('header')
+
+        <div class="container-fluid animated fadeIn">
+
+          @yield('before_content_widgets')
+
+          @yield('content')
+          
+          @yield('after_content_widgets')
+
+        </div>
+
+    </main>
+
+  </div>{{-- ./app-body --}}
+
+  <footer class="{{ config('backpack.base.footer_class') }}">
+    @include(backpack_view('inc.footer'))
+  </footer>
+
+  @yield('before_scripts')
+  @stack('before_scripts')
+
+  @include(backpack_view('inc.scripts'))
+
+  @yield('after_scripts')
+  @stack('after_scripts')
+</body>
+</html>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/my_account.blade.php b/resources/views/vendor/backpack/base/my_account.blade.php
new file mode 100644 (file)
index 0000000..92e3e62
--- /dev/null
@@ -0,0 +1,147 @@
+@extends(backpack_view('blank'))
+
+@section('after_styles')
+    <style media="screen">
+        .backpack-profile-form .required::after {
+            content: ' *';
+            color: red;
+        }
+    </style>
+@endsection
+
+@php
+  $breadcrumbs = [
+      trans('backpack::crud.admin') => url(config('backpack.base.route_prefix'), 'dashboard'),
+      trans('backpack::base.my_account') => false,
+  ];
+@endphp
+
+@section('header')
+    <section class="content-header">
+        <div class="container-fluid mb-3">
+            <h1>{{ trans('backpack::base.my_account') }}</h1>
+        </div>
+    </section>
+@endsection
+
+@section('content')
+    <div class="row">
+
+        @if (session('success'))
+        <div class="col-lg-8">
+            <div class="alert alert-success">
+                {{ session('success') }}
+            </div>
+        </div>
+        @endif
+
+        @if ($errors->count())
+        <div class="col-lg-8">
+            <div class="alert alert-danger">
+                <ul class="mb-1">
+                    @foreach ($errors->all() as $e)
+                    <li>{{ $e }}</li>
+                    @endforeach
+                </ul>
+            </div>
+        </div>
+        @endif
+
+        {{-- UPDATE INFO FORM --}}
+        <div class="col-lg-8">
+            <form class="form" action="{{ route('backpack.account.info.store') }}" method="post">
+
+                {!! csrf_field() !!}
+
+                <div class="card padding-10">
+
+                    <div class="card-header">
+                        {{ trans('backpack::base.update_account_info') }}
+                    </div>
+
+                    <div class="card-body backpack-profile-form bold-labels">
+                        <div class="row">
+                            <div class="col-md-6 form-group">
+                                @php
+                                    $label = trans('backpack::base.name');
+                                    $field = 'name';
+                                @endphp
+                                <label class="required">{{ $label }}</label>
+                                <input required class="form-control" type="text" name="{{ $field }}" value="{{ old($field) ? old($field) : $user->$field }}">
+                            </div>
+
+                            <div class="col-md-6 form-group">
+                                @php
+                                    $label = config('backpack.base.authentication_column_name');
+                                    $field = backpack_authentication_column();
+                                @endphp
+                                <label class="required">{{ $label }}</label>
+                                <input required class="form-control" type="{{ backpack_authentication_column()==backpack_email_column()?'email':'text' }}" name="{{ $field }}" value="{{ old($field) ? old($field) : $user->$field }}">
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="card-footer">
+                        <button type="submit" class="btn btn-success"><i class="la la-save"></i> {{ trans('backpack::base.save') }}</button>
+                        <a href="{{ backpack_url() }}" class="btn">{{ trans('backpack::base.cancel') }}</a>
+                    </div>
+                </div>
+
+            </form>
+        </div>
+
+        {{-- CHANGE PASSWORD FORM --}}
+        <div class="col-lg-8">
+            <form class="form" action="{{ route('backpack.account.password') }}" method="post">
+
+                {!! csrf_field() !!}
+
+                <div class="card padding-10">
+
+                    <div class="card-header">
+                        {{ trans('backpack::base.change_password') }}
+                    </div>
+
+                    <div class="card-body backpack-profile-form bold-labels">
+                        <div class="row">
+                            <div class="col-md-4 form-group">
+                                @php
+                                    $label = trans('backpack::base.old_password');
+                                    $field = 'old_password';
+                                @endphp
+                                <label class="required">{{ $label }}</label>
+                                <input autocomplete="new-password" required class="form-control" type="password" name="{{ $field }}" id="{{ $field }}" value="">
+                            </div>
+
+                            <div class="col-md-4 form-group">
+                                @php
+                                    $label = trans('backpack::base.new_password');
+                                    $field = 'new_password';
+                                @endphp
+                                <label class="required">{{ $label }}</label>
+                                <input autocomplete="new-password" required class="form-control" type="password" name="{{ $field }}" id="{{ $field }}" value="">
+                            </div>
+
+                            <div class="col-md-4 form-group">
+                                @php
+                                    $label = trans('backpack::base.confirm_password');
+                                    $field = 'confirm_password';
+                                @endphp
+                                <label class="required">{{ $label }}</label>
+                                <input autocomplete="new-password" required class="form-control" type="password" name="{{ $field }}" id="{{ $field }}" value="">
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="card-footer">
+                            <button type="submit" class="btn btn-success"><i class="la la-save"></i> {{ trans('backpack::base.change_password') }}</button>
+                            <a href="{{ backpack_url() }}" class="btn">{{ trans('backpack::base.cancel') }}</a>
+                    </div>
+
+                </div>
+
+            </form>
+        </div>
+
+    </div>
+@endsection
diff --git a/resources/views/vendor/backpack/base/widgets/alert.blade.php b/resources/views/vendor/backpack/base/widgets/alert.blade.php
new file mode 100644 (file)
index 0000000..1a8fb3e
--- /dev/null
@@ -0,0 +1,19 @@
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_start')
+
+<div class="{{ $widget['class'] ?? 'alert alert-primary' }}" role="alert">
+
+       @if (isset($widget['close_button']) && $widget['close_button']) 
+       <button class="close" type="button" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
+       @endif
+
+       @if (isset($widget['heading']))
+       <h4 class="alert-heading">{!! $widget['heading'] !!}</h4>
+       @endif
+
+       @if (isset($widget['content']))
+       <p>{!! $widget['content'] !!}</p>
+       @endif
+
+</div>
+
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/widgets/card.blade.php b/resources/views/vendor/backpack/base/widgets/card.blade.php
new file mode 100644 (file)
index 0000000..b59d93e
--- /dev/null
@@ -0,0 +1,15 @@
+@php
+       // preserve backwards compatibility with Widgets in Backpack 4.0
+       $widget['wrapper']['class'] = $widget['wrapper']['class'] ?? $widget['wrapperClass'] ?? 'col-sm-6 col-md-4';
+@endphp
+
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_start')
+       <div class="{{ $widget['class'] ?? 'card' }}">
+               @if (isset($widget['content']))
+                       @if (isset($widget['content']['header']))
+                               <div class="card-header">{!! $widget['content']['header'] !!}</div>
+                       @endif
+                       <div class="card-body">{!! $widget['content']['body'] !!}</div>
+               @endif
+       </div>
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/widgets/div.blade.php b/resources/views/vendor/backpack/base/widgets/div.blade.php
new file mode 100644 (file)
index 0000000..f8ff200
--- /dev/null
@@ -0,0 +1,19 @@
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_start')
+
+<div 
+       @if (count($widget) > 2)
+           @foreach ($widget as $attribute => $value)
+               @if (is_string($attribute) && $attribute!='content' && $attribute!='type')
+                   {{ $attribute }}="{{ $value }}"
+               @endif
+           @endforeach
+       @endif
+       >
+
+       @if (isset($widget['content']))
+               @include('backpack::inc.widgets', [ 'widgets' => $widget['content'] ])
+       @endif
+
+</div>
+
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/widgets/inc/wrapper_end.blade.php b/resources/views/vendor/backpack/base/widgets/inc/wrapper_end.blade.php
new file mode 100644 (file)
index 0000000..33ca6a9
--- /dev/null
@@ -0,0 +1 @@
+</{{ $widget['wrapper']['element'] ?? 'div' }}>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/widgets/inc/wrapper_start.blade.php b/resources/views/vendor/backpack/base/widgets/inc/wrapper_start.blade.php
new file mode 100644 (file)
index 0000000..19fe366
--- /dev/null
@@ -0,0 +1,16 @@
+@php
+       $widget['wrapper']['element'] = $widget['wrapper']['element'] ?? 'div';
+       $widget['wrapper']['class'] = $widget['wrapper']['class'] ?? "col-sm-6 col-md-4";
+
+    // each wrapper attribute can be a callback or a string
+    // for those that are callbacks, run the callbacks to get the final string to use
+    foreach($widget['wrapper'] as $attribute => $value) {
+        $widget['wrapper'][$attribute] = (!is_string($value) && is_callable($value) ? $value() : $value) ?? '';
+    }
+@endphp
+
+<{{ $widget['wrapper']['element'] ?? 'div' }}
+@foreach(Arr::where($widget['wrapper'],function($value, $key) { return $key != 'element'; }) as $element => $value)
+    {{$element}}="{{$value}}"
+@endforeach
+>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/widgets/jumbotron.blade.php b/resources/views/vendor/backpack/base/widgets/jumbotron.blade.php
new file mode 100644 (file)
index 0000000..bc594a2
--- /dev/null
@@ -0,0 +1,25 @@
+@php
+       // preserve backwards compatibility with Widgets in Backpack 4.0
+       if (isset($widget['wrapperClass'])) {
+               $widget['wrapper']['class'] = $widget['wrapperClass'];
+       }
+@endphp
+
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_start')
+       <div class="jumbotron mb-2">
+
+         @if (isset($widget['heading']))
+         <h1 class="display-3">{!! $widget['heading'] !!}</h1>
+         @endif
+
+         @if (isset($widget['content']))
+         <p>{!! $widget['content'] !!}</p>
+         @endif
+
+         @if (isset($widget['button_link']))
+         <p class="lead">
+           <a class="btn btn-primary" href="{{ $widget['button_link'] }}" role="button">{{ $widget['button_text'] }}</a>
+         </p>
+         @endif
+       </div>
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/widgets/progress.blade.php b/resources/views/vendor/backpack/base/widgets/progress.blade.php
new file mode 100644 (file)
index 0000000..98fdbb7
--- /dev/null
@@ -0,0 +1,34 @@
+@php
+  // defaults; backwards compatibility with Backpack 4.0 widgets
+  $widget['wrapper']['class'] = $widget['wrapper']['class'] ?? $widget['wrapperClass'] ?? 'col-sm-6 col-lg-3';
+@endphp
+
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_start')
+  <div class="{{ $widget['class'] ?? 'card text-white bg-primary' }}">
+    <div class="card-body">
+      @if (isset($widget['value']))
+      <div class="text-value">{!! $widget['value'] !!}</div>
+      @endif
+
+      @if (isset($widget['description']))
+      <div>{!! $widget['description'] !!}</div>
+      @endif
+      
+      @if (isset($widget['progress']))
+      <div class="progress progress-white progress-xs my-2">
+        <div class="progress-bar" role="progressbar" style="width: {{ $widget['progress']  }}%" aria-valuenow="{{ $widget['progress']  }}" aria-valuemin="0" aria-valuemax="100"></div>
+      </div>
+      @endif
+      
+      @if (isset($widget['hint']))
+      <small class="text-muted">{!! $widget['hint'] !!}</small>
+      @endif
+    </div>
+    
+    @if (isset($widget['footer_link']))
+    <div class="card-footer px-3 py-2">
+      <a class="btn-block text-muted d-flex justify-content-between align-items-center" href="{{ $widget['footer_link'] ?? '#' }}"><span class="small font-weight-bold">{{ $widget['footer_text'] ?? 'View more' }}</span><i class="la la-angle-right"></i></a>
+    </div>
+    @endif
+  </div>
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/widgets/progress_white.blade.php b/resources/views/vendor/backpack/base/widgets/progress_white.blade.php
new file mode 100644 (file)
index 0000000..c96c26d
--- /dev/null
@@ -0,0 +1,34 @@
+@php
+  // defaults; backwards compatibility with Backpack 4.0 widgets
+  $widget['wrapper']['class'] = $widget['wrapper']['class'] ?? $widget['wrapperClass'] ?? 'col-sm-6 col-lg-3';
+@endphp
+
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_start')
+  <div class="{{ $widget['class'] ?? 'card' }}">
+    <div class="card-body">
+      @if (isset($widget['value']))
+      <div class="text-value">{!! $widget['value'] !!}</div>
+      @endif
+
+      @if (isset($widget['description']))
+      <div>{!! $widget['description'] !!}</div>
+      @endif
+      
+      @if (isset($widget['progress']))
+      <div class="progress progress-xs my-2">
+        <div class="{{ $widget['progressClass'] ?? 'progress-bar bg-info' }}" role="progressbar" style="width: {{ $widget['progress']  }}%" aria-valuenow="{{ $widget['progress']  }}" aria-valuemin="0" aria-valuemax="100"></div>
+      </div>
+      @endif
+      
+      @if (isset($widget['hint']))
+      <small class="text-muted">{!! $widget['hint'] !!}</small>
+      @endif
+    </div>
+
+    @if (isset($widget['footer_link']))
+    <div class="card-footer px-3 py-2">
+      <a class="btn-block text-muted d-flex justify-content-between align-items-center" href="{{ $widget['footer_link'] ?? '#' }}"><span class="small font-weight-bold">{{ $widget['footer_text'] ?? 'View more' }}</span><i class="la la-angle-right"></i></a>
+    </div>
+    @endif
+  </div>
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/base/widgets/script.blade.php b/resources/views/vendor/backpack/base/widgets/script.blade.php
new file mode 100644 (file)
index 0000000..3c2dfe6
--- /dev/null
@@ -0,0 +1,12 @@
+@php
+    $src = asset($widget['src'] ?? $widget['content'] ?? $widget['path']);
+    $attributes = collect($widget)->except(['name', 'section', 'type', 'stack', 'src', 'content', 'path'])
+@endphp
+
+@push($widget['stack'] ?? 'after_scripts')
+    <script src="{{ $src }}"
+        @foreach($attributes as $key => $value)
+        {{ $key }}{!! $value === true || $value === '' ? '' : "=\"$value\"" !!}
+        @endforeach
+    ></script>
+@endpush
diff --git a/resources/views/vendor/backpack/base/widgets/style.blade.php b/resources/views/vendor/backpack/base/widgets/style.blade.php
new file mode 100644 (file)
index 0000000..93d09a6
--- /dev/null
@@ -0,0 +1,14 @@
+@php
+    $widget['rel'] = $widget['rel'] ?? 'stylesheet';
+
+    $href = asset($widget['href'] ?? $widget['content'] ?? $widget['path']);
+    $attributes = collect($widget)->except(['name', 'section', 'type', 'stack', 'href', 'content', 'path'])
+@endphp
+
+@push($widget['stack'] ?? 'after_styles')
+    <link href="{{ $href }}" type="text/css"
+        @foreach($attributes as $key => $value)
+        {{ $key }}{!! $value === true || $value === '' ? '' : "=\"$value\"" !!}
+        @endforeach
+    />
+@endpush
diff --git a/resources/views/vendor/backpack/base/widgets/view.blade.php b/resources/views/vendor/backpack/base/widgets/view.blade.php
new file mode 100644 (file)
index 0000000..b496fcf
--- /dev/null
@@ -0,0 +1,6 @@
+{{-- view field --}}
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_start')
+       
+       @include($widget['view'], ['widget' => $widget])
+
+@includeWhen(!empty($widget['wrapper']), 'backpack::widgets.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/buttons/create.blade.php b/resources/views/vendor/backpack/crud/buttons/create.blade.php
new file mode 100644 (file)
index 0000000..d69e2f3
--- /dev/null
@@ -0,0 +1,3 @@
+@if ($crud->hasAccess('create'))
+       <a href="{{ url($crud->route.'/create') }}" class="btn btn-primary" data-style="zoom-in"><span class="ladda-label"><i class="la la-plus"></i> {{ trans('backpack::crud.add') }} {{ $crud->entity_name }}</span></a>
+@endif
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/buttons/delete.blade.php b/resources/views/vendor/backpack/crud/buttons/delete.blade.php
new file mode 100644 (file)
index 0000000..1bff031
--- /dev/null
@@ -0,0 +1,97 @@
+@if ($crud->hasAccess('delete'))
+       <a href="javascript:void(0)" onclick="deleteEntry(this)" data-route="{{ url($crud->route.'/'.$entry->getKey()) }}" class="btn btn-sm btn-link" data-button-type="delete"><i class="la la-trash"></i> {{ trans('backpack::crud.delete') }}</a>
+@endif
+
+{{-- Button Javascript --}}
+{{-- - used right away in AJAX operations (ex: List) --}}
+{{-- - pushed to the end of the page, after jQuery is loaded, for non-AJAX operations (ex: Show) --}}
+@loadOnce('delete_button_script')
+@push('after_scripts') @if (request()->ajax()) @endpush @endif
+<script>
+
+       if (typeof deleteEntry != 'function') {
+         $("[data-button-type=delete]").unbind('click');
+
+         function deleteEntry(button) {
+               // ask for confirmation before deleting an item
+               // e.preventDefault();
+               var route = $(button).attr('data-route');
+
+               swal({
+                 title: "{!! trans('backpack::base.warning') !!}",
+                 text: "{!! trans('backpack::crud.delete_confirm') !!}",
+                 icon: "warning",
+                 buttons: ["{!! trans('backpack::crud.cancel') !!}", "{!! trans('backpack::crud.delete') !!}"],
+                 dangerMode: true,
+               }).then((value) => {
+                       if (value) {
+                               $.ajax({
+                             url: route,
+                             type: 'DELETE',
+                             success: function(result) {
+                                 if (result == 1) {
+                                                 // Redraw the table
+                                                 if (typeof crud != 'undefined' && typeof crud.table != 'undefined') {
+                                                         // Move to previous page in case of deleting the only item in table
+                                                         if(crud.table.rows().count() === 1) {
+                                                           crud.table.page("previous");
+                                                         }
+
+                                                         crud.table.draw(false);
+                                                 }
+
+                                         // Show a success notification bubble
+                                     new Noty({
+                                   type: "success",
+                                   text: "{!! '<strong>'.trans('backpack::crud.delete_confirmation_title').'</strong><br>'.trans('backpack::crud.delete_confirmation_message') !!}"
+                                 }).show();
+
+                                     // Hide the modal, if any
+                                     $('.modal').modal('hide');
+                                 } else {
+                                     // if the result is an array, it means 
+                                     // we have notification bubbles to show
+                                         if (result instanceof Object) {
+                                               // trigger one or more bubble notifications 
+                                               Object.entries(result).forEach(function(entry, index) {
+                                                 var type = entry[0];
+                                                 entry[1].forEach(function(message, i) {
+                                                         new Noty({
+                                                   type: type,
+                                                   text: message
+                                                 }).show();
+                                                 });
+                                               });
+                                         } else {// Show an error alert
+                                             swal({
+                                               title: "{!! trans('backpack::crud.delete_confirmation_not_title') !!}",
+                                   text: "{!! trans('backpack::crud.delete_confirmation_not_message') !!}",
+                                               icon: "error",
+                                               timer: 4000,
+                                               buttons: false,
+                                             });
+                                         }                                       
+                                 }
+                             },
+                             error: function(result) {
+                                 // Show an alert with the result
+                                 swal({
+                               title: "{!! trans('backpack::crud.delete_confirmation_not_title') !!}",
+                        text: "{!! trans('backpack::crud.delete_confirmation_not_message') !!}",
+                               icon: "error",
+                               timer: 4000,
+                               buttons: false,
+                             });
+                             }
+                         });
+                       }
+               });
+
+      }
+       }
+
+       // make it so that the function above is run after each DataTable draw event
+       // crud.addFunctionToDataTablesDrawEventQueue('deleteEntry');
+</script>
+@if (!request()->ajax()) @endpush @endif
+@endLoadOnce
diff --git a/resources/views/vendor/backpack/crud/buttons/reorder.blade.php b/resources/views/vendor/backpack/crud/buttons/reorder.blade.php
new file mode 100644 (file)
index 0000000..7b3933b
--- /dev/null
@@ -0,0 +1,3 @@
+@if ($crud->get('reorder.enabled') && $crud->hasAccess('reorder'))
+  <a href="{{ url($crud->route.'/reorder') }}" class="btn btn-outline-primary" data-style="zoom-in"><span class="ladda-label"><i class="la la-arrows"></i> {{ trans('backpack::crud.reorder') }} {{ $crud->entity_name_plural }}</span></a>
+@endif
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/buttons/show.blade.php b/resources/views/vendor/backpack/crud/buttons/show.blade.php
new file mode 100644 (file)
index 0000000..d907463
--- /dev/null
@@ -0,0 +1,24 @@
+@if ($crud->hasAccess('show'))
+       @if (!$crud->model->translationEnabled())
+
+       {{-- Single edit button --}}
+       <a href="{{ url($crud->route.'/'.$entry->getKey().'/show') }}" class="btn btn-sm btn-link"><i class="la la-eye"></i> {{ trans('backpack::crud.preview') }}</a>
+
+       @else
+
+       {{-- Edit button group --}}
+       <div class="btn-group">
+         <a href="{{ url($crud->route.'/'.$entry->getKey().'/show') }}" class="btn btn-sm btn-link pr-0"><i class="la la-eye"></i> {{ trans('backpack::crud.preview') }}</a>
+         <a class="btn btn-sm btn-link dropdown-toggle text-primary pl-1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+           <span class="caret"></span>
+         </a>
+         <ul class="dropdown-menu dropdown-menu-right">
+           <li class="dropdown-header">{{ trans('backpack::crud.preview') }}:</li>
+               @foreach ($crud->model->getAvailableLocales() as $key => $locale)
+                       <a class="dropdown-item" href="{{ url($crud->route.'/'.$entry->getKey().'/show') }}?_locale={{ $key }}">{{ $locale }}</a>
+               @endforeach
+         </ul>
+       </div>
+
+       @endif
+@endif
diff --git a/resources/views/vendor/backpack/crud/buttons/update.blade.php b/resources/views/vendor/backpack/crud/buttons/update.blade.php
new file mode 100644 (file)
index 0000000..fb0dbc0
--- /dev/null
@@ -0,0 +1,24 @@
+@if ($crud->hasAccess('update'))
+       @if (!$crud->model->translationEnabled())
+
+       {{-- Single edit button --}}
+       <a href="{{ url($crud->route.'/'.$entry->getKey().'/edit') }}" class="btn btn-sm btn-link"><i class="la la-edit"></i> {{ trans('backpack::crud.edit') }}</a>
+
+       @else
+
+       {{-- Edit button group --}}
+       <div class="btn-group">
+         <a href="{{ url($crud->route.'/'.$entry->getKey().'/edit') }}" class="btn btn-sm btn-link pr-0"><i class="la la-edit"></i> {{ trans('backpack::crud.edit') }}</a>
+         <a class="btn btn-sm btn-link dropdown-toggle text-primary pl-1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+           <span class="caret"></span>
+         </a>
+         <ul class="dropdown-menu dropdown-menu-right">
+           <li class="dropdown-header">{{ trans('backpack::crud.edit_translations') }}:</li>
+               @foreach ($crud->model->getAvailableLocales() as $key => $locale)
+                       <a class="dropdown-item" href="{{ url($crud->route.'/'.$entry->getKey().'/edit') }}?_locale={{ $key }}">{{ $locale }}</a>
+               @endforeach
+         </ul>
+       </div>
+
+       @endif
+@endif
diff --git a/resources/views/vendor/backpack/crud/columns/boolean.blade.php b/resources/views/vendor/backpack/crud/columns/boolean.blade.php
new file mode 100644 (file)
index 0000000..6f41660
--- /dev/null
@@ -0,0 +1,41 @@
+{{-- converts 1/true or 0/false to yes/no/lang --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if (in_array($column['value'], [true, 1, '1'])) {
+        $related_key = 1;
+        if ( isset( $column['options'][1] ) ) {
+            $column['text'] = $column['options'][1];
+            $column['escaped'] = false;
+        } else {
+            $column['text'] = Lang::has('backpack::crud.yes') ? trans('backpack::crud.yes') : 'Yes';
+        }
+    } else {
+        $related_key = 0;
+        if ( isset( $column['options'][0] ) ) {
+            $column['text'] = $column['options'][0];
+            $column['escaped'] = false;
+        } else {
+            $column['text'] = Lang::has('backpack::crud.no') ? trans('backpack::crud.no') : 'No';
+        }
+    }
+
+    $column['text'] = $column['prefix'].$column['text'].$column['suffix'];
+@endphp
+
+<span data-order="{{ $column['value'] }}">
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/check.blade.php b/resources/views/vendor/backpack/crud/columns/check.blade.php
new file mode 100644 (file)
index 0000000..9832b1b
--- /dev/null
@@ -0,0 +1,35 @@
+{{-- checkbox with loose false/null/0 checking --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    $column['icon'] = $column['value'] != false
+        ? ($column['icons']['checked'] ?? 'la-check-circle')
+        : ($column['icons']['unchecked'] ?? 'la-circle');
+
+    $column['text'] = $column['value'] != false
+        ? ($column['labels']['checked'] ?? trans('backpack::crud.yes'))
+        : ($column['labels']['unchecked'] ?? trans('backpack::crud.no'));
+
+    $column['text'] = $column['prefix'].$column['text'].$column['suffix'];
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+    <i class="la {{ $column['icon'] }}"></i>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
+
+<span class="sr-only">
+    @if($column['escaped'])
+        {{ $column['text'] }}
+    @else
+        {!! $column['text'] !!}
+    @endif
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/closure.blade.php b/resources/views/vendor/backpack/crud/columns/closure.blade.php
new file mode 100644 (file)
index 0000000..d568834
--- /dev/null
@@ -0,0 +1,26 @@
+{{-- closure function column type --}}
+@php
+    $column['value'] = $column['value'] ?? $column['function'];
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].$column['value'].$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/custom_html.blade.php b/resources/views/vendor/backpack/crud/columns/custom_html.blade.php
new file mode 100644 (file)
index 0000000..03519c7
--- /dev/null
@@ -0,0 +1,25 @@
+{{-- custom html --}}
+@php
+    $column['escaped'] = $column['escaped'] ?? false;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].$column['value'].$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/date.blade.php b/resources/views/vendor/backpack/crud/columns/date.blade.php
new file mode 100644 (file)
index 0000000..60ac0c9
--- /dev/null
@@ -0,0 +1,31 @@
+{{-- localized date using nesbot carbon --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['format'] = $column['format'] ?? config('backpack.base.default_date_format');
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $date = \Carbon\Carbon::parse($column['value'])
+            ->locale(App::getLocale())
+            ->isoFormat($column['format']);
+
+        $column['text'] = $column['prefix'].$date.$column['suffix'];
+    }
+@endphp
+
+<span data-order="{{ $column['value'] ?? '' }}">
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/datetime.blade.php b/resources/views/vendor/backpack/crud/columns/datetime.blade.php
new file mode 100644 (file)
index 0000000..7350d81
--- /dev/null
@@ -0,0 +1,31 @@
+{{-- localized datetime using carbon --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['format'] = $column['format'] ?? config('backpack.base.default_datetime_format');
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $date = \Carbon\Carbon::parse($column['value'])
+            ->locale(App::getLocale())
+            ->isoFormat($column['format']);
+
+        $column['text'] = $column['prefix'].$date.$column['suffix'];
+    }
+@endphp
+
+<span data-order="{{ $column['value'] ?? '' }}">
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/email.blade.php b/resources/views/vendor/backpack/crud/columns/email.blade.php
new file mode 100644 (file)
index 0000000..08715c6
--- /dev/null
@@ -0,0 +1,30 @@
+{{-- email link --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['limit'] = $column['limit'] ?? 32;
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].Str::limit(strip_tags($column['value']), $column['limit'], "…").$column['suffix'];
+    }
+
+    $column['wrapper']['element'] = $column['wrapper']['element'] ?? 'a';
+    $column['wrapper']['href'] = $column['wrapper']['href'] ?? 'mailto:'.$column['value'];
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/enum.blade.php b/resources/views/vendor/backpack/crud/columns/enum.blade.php
new file mode 100644 (file)
index 0000000..1f8a78c
--- /dev/null
@@ -0,0 +1,19 @@
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    if(function_exists('enum_exists') && !empty($column['value']))  {
+        if($column['value'] instanceof \UnitEnum) {
+            $column['value'] = isset($column['enum_function']) ? $column['value']->{$column['enum_function']}() : ($column['value'] instanceof \BackedEnum ? $column['value']->value : $column['value']->name);
+        }else{
+            if(isset($column['enum_class'])) {
+                $enumClassReflection = new \ReflectionEnum($column['enum_class']);
+                if ($enumClassReflection->hasConstant($column['value'])) {
+                    $enumClass = $enumClassReflection->getConstant($column['value']);
+                }
+                
+                $column['value'] = isset($column['enum_function']) ? $enumClass->{$column['enum_function']}() : $column['value'];
+            }
+        }
+    }
+@endphp
+
+@include(isset($column['options']) ? 'crud::columns.select_from_array' : 'crud::columns.text')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/columns/image.blade.php b/resources/views/vendor/backpack/crud/columns/image.blade.php
new file mode 100644 (file)
index 0000000..6ab2ce0
--- /dev/null
@@ -0,0 +1,53 @@
+{{-- image column type --}}
+@php
+  $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+
+  if($column['value']) {
+    $column['height'] = $column['height'] ?? "25px";
+    $column['width'] = $column['width'] ?? "auto";
+    $column['radius'] = $column['radius'] ?? "3px";
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['temporary'] = $column['temporary'] ?? false;
+    $column['expiration'] = $column['expiration'] ?? 1;
+
+    if($column['value'] instanceof \Closure) {
+      $column['value'] = $column['value']($entry);
+    }
+
+    if (is_array($column['value'])) {
+      $column['value'] = json_encode($column['value']);
+    }
+
+    if (preg_match('/^data\:image\//', $column['value'])) { // base64_image
+      $href = $src = $column['value'];
+    } elseif (isset($column['disk'])) { // image from a different disk (like s3 bucket)
+
+      if (!empty($column['temporary'])) {
+          $href = $src = Storage::disk($column['disk'])->temporaryUrl($column['prefix'].$column['value'], now()->addMinutes((int) $column['expiration']));
+      } else {
+          $href = $src = Storage::disk($column['disk'])->url($column['prefix'].$column['value']);
+      }
+
+    } else { // plain-old image, from a local disk
+      $href = $src = asset($column['prefix'] . $column['value']);
+    }
+
+    $column['wrapper']['element'] = $column['wrapper']['element'] ?? 'a';
+    $column['wrapper']['href'] = $column['wrapper']['href'] ?? $href;
+    $column['wrapper']['target'] = $column['wrapper']['target'] ?? '_blank';
+  }
+@endphp
+
+<span>
+  @if(empty($column['value']))
+    {{ $column['default'] ?? '-' }}
+  @else
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        <img src="{{ $src }}" style="
+        max-height: {{ $column['height'] }};
+        width: {{ $column['width'] }};
+        border-radius: {{ $column['radius'] }};"
+        />
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+  @endif
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/inc/bulk_actions_checkbox.blade.php b/resources/views/vendor/backpack/crud/columns/inc/bulk_actions_checkbox.blade.php
new file mode 100644 (file)
index 0000000..e16f3bb
--- /dev/null
@@ -0,0 +1,127 @@
+@if (!isset($entry))
+    <span class="crud_bulk_actions_checkbox">
+        <input type="checkbox" class="crud_bulk_actions_general_checkbox">
+    </span>
+@else
+    <span class="crud_bulk_actions_checkbox">
+        <input type="checkbox" class="crud_bulk_actions_line_checkbox" data-primary-key-value="{{ $entry->getKey() }}">
+    </span>
+
+    @loadOnce('bpFieldInitCheckboxScript')
+    <script>
+    if (typeof addOrRemoveCrudCheckedItem !== 'function') {
+        function addOrRemoveCrudCheckedItem(element) {
+            crud.lastCheckedItem = false;
+
+            document.querySelectorAll('input.crud_bulk_actions_line_checkbox').forEach(checkbox => checkbox.onclick = e => {
+                e.stopPropagation();
+
+                let checked = checkbox.checked;
+                let primaryKeyValue = checkbox.dataset.primaryKeyValue;
+
+                crud.checkedItems ??= [];
+                
+                if (checked) {
+                    // add item to crud.checkedItems variable
+                    crud.checkedItems.push(primaryKeyValue);
+
+                    // if shift has been pressed, also select all elements
+                    // between the last checked item and this one
+                    if (crud.lastCheckedItem && e.shiftKey) {
+                        let getNodeindex = elm => [...elm.parentNode.children].indexOf(elm);
+                        let first = document.querySelector(`input.crud_bulk_actions_line_checkbox[data-primary-key-value="${crud.lastCheckedItem}"]`).closest('tr');
+                        let last = document.querySelector(`input.crud_bulk_actions_line_checkbox[data-primary-key-value="${primaryKeyValue}"]`).closest('tr');
+                        let firstIndex = getNodeindex(first);
+                        let lastIndex = getNodeindex(last)
+                        
+                        while(first !== last) {
+                            first = firstIndex < lastIndex ? first.nextElementSibling : first.previousElementSibling;
+                            first.querySelector('input.crud_bulk_actions_line_checkbox:not(:checked)')?.click();
+                        }
+                    }
+
+                    // remember that this one was the last checked item
+                    crud.lastCheckedItem = primaryKeyValue;
+                } else {
+                    // remove item from crud.checkedItems variable
+                    let index = crud.checkedItems.indexOf(primaryKeyValue);
+                    if (index > -1) crud.checkedItems.splice(index, 1);
+                }
+
+                // if no items are selected, disable all bulk buttons
+                enableOrDisableBulkButtons();
+            });
+        }
+    }
+
+    if (typeof markCheckboxAsCheckedIfPreviouslySelected !== 'function') {
+        function markCheckboxAsCheckedIfPreviouslySelected() {
+            let checkedItems = crud.checkedItems ?? [];
+            let pageChanged = localStorage.getItem('page_changed') ?? false;
+            let tableUrl = crud.table.ajax.url();
+            let hasFilterApplied = false;
+
+            if (tableUrl.indexOf('?') > -1) {
+                if (tableUrl.substring(tableUrl.indexOf('?') + 1).length > 0) {
+                    hasFilterApplied = true;
+                }
+            }
+
+            // if it was not a page change, we check if datatables have any search, or the url have any parameters.
+            // if you have filtered entries, and then remove the filters we are sure the entries are in the table.
+            // we don't remove them in that case.
+            if (! pageChanged && (crud.table.search().length !== 0 || hasFilterApplied)) {
+                crud.checkedItems = [];
+            }
+            document
+                .querySelectorAll('input.crud_bulk_actions_line_checkbox[data-primary-key-value]')
+                .forEach(function(elem) {
+                    let checked = checkedItems.length && checkedItems.indexOf(elem.dataset.primaryKeyValue) > -1;
+                    elem.checked = checked;
+                    if (checked && crud.checkedItems.indexOf(elem.dataset.primaryKeyValue) === -1) {
+                        crud.checkedItems.push(elem.dataset.primaryKeyValue);
+                    }
+                });
+            
+            localStorage.removeItem('page_changed');
+        }
+    }
+
+    if (typeof addBulkActionMainCheckboxesFunctionality !== 'function') {
+        function addBulkActionMainCheckboxesFunctionality() {
+            let mainCheckboxes = Array.from(document.querySelectorAll('input.crud_bulk_actions_general_checkbox'));
+            let rowCheckboxes = Array.from(document.querySelectorAll('input.crud_bulk_actions_line_checkbox'));
+
+            mainCheckboxes.forEach(checkbox => {
+                // set initial checked status
+                checkbox.checked = document.querySelectorAll('input.crud_bulk_actions_line_checkbox:not(:checked)').length === 0;
+
+                // when the crud_bulk_actions_general_checkbox is selected, toggle all visible checkboxes
+                checkbox.onclick = event => {
+                    rowCheckboxes.filter(elem => checkbox.checked !== elem.checked).forEach(elem => elem.click());
+                    
+                    // make sure the other checkbox has the same checked status
+                    mainCheckboxes.forEach(elem => elem.checked = checkbox.checked);
+
+                    event.stopPropagation();
+                }
+            });
+
+            // Stop propagation of href on the first column
+            document.querySelectorAll('table td.dtr-control a').forEach(link => link.onclick = e => e.stopPropagation());
+        }
+    }
+
+    if (typeof enableOrDisableBulkButtons !== 'function') {
+        function enableOrDisableBulkButtons() {
+            document.querySelectorAll('.bulk-button').forEach(btn => btn.classList.toggle('disabled', !crud.checkedItems?.length));
+        }
+    }
+
+    crud.addFunctionToDataTablesDrawEventQueue('addOrRemoveCrudCheckedItem');
+    crud.addFunctionToDataTablesDrawEventQueue('markCheckboxAsCheckedIfPreviouslySelected');
+    crud.addFunctionToDataTablesDrawEventQueue('addBulkActionMainCheckboxesFunctionality');
+    crud.addFunctionToDataTablesDrawEventQueue('enableOrDisableBulkButtons');
+    </script>
+    @endLoadOnce
+@endif
diff --git a/resources/views/vendor/backpack/crud/columns/inc/details_row_button.blade.php b/resources/views/vendor/backpack/crud/columns/inc/details_row_button.blade.php
new file mode 100644 (file)
index 0000000..0239c5b
--- /dev/null
@@ -0,0 +1,4 @@
+{{-- expand/minimize button column --}}
+<span class="details-control text-center cursor-pointer m-r-5">
+    <i class="la la-plus-square details-row-button cursor-pointer" data-entry-id="{{ $entry->getKey() }}"></i>
+</span>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/columns/inc/wrapper_end.blade.php b/resources/views/vendor/backpack/crud/columns/inc/wrapper_end.blade.php
new file mode 100644 (file)
index 0000000..a853676
--- /dev/null
@@ -0,0 +1,12 @@
+@php
+    // this is made available by columns like select and select_multiple
+    $related_key = $related_key ?? null;
+
+    // define the wrapper element
+    $wrapperElement = $column['wrapper']['element'] ?? 'a';
+    if(!is_string($wrapperElement) && $wrapperElement instanceof \Closure) {
+        $wrapperElement = $wrapperElement($crud, $column, $entry, $related_key);
+    }
+@endphp
+
+</{{ $wrapperElement }}>
diff --git a/resources/views/vendor/backpack/crud/columns/inc/wrapper_start.blade.php b/resources/views/vendor/backpack/crud/columns/inc/wrapper_start.blade.php
new file mode 100644 (file)
index 0000000..69270e9
--- /dev/null
@@ -0,0 +1,16 @@
+@php
+    // this is made available by columns like select and select_multiple
+    $related_key = $related_key ?? null;
+
+    // each wrapper attribute can be a callback or a string
+    // for those that are callbacks, run the callbacks to get the final string to use
+    foreach($column['wrapper'] as $attribute => $value) {
+        $column['wrapper'][$attribute] = !is_string($value) && $value instanceof \Closure ? $value($crud, $column, $entry, $related_key) : $value ?? '';
+    }
+@endphp
+
+<{{ $column['wrapper']['element'] ?? 'a' }}
+@foreach(Arr::except($column['wrapper'], 'element') as $element => $value)
+    {{$element}}="{{$value}}"
+@endforeach
+>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/columns/json.blade.php b/resources/views/vendor/backpack/crud/columns/json.blade.php
new file mode 100644 (file)
index 0000000..a4485d0
--- /dev/null
@@ -0,0 +1,29 @@
+{{-- json --}}
+@php
+    $column['value'] = $column['value'] ?? $entry->{$column['name']};
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['wrapper']['element'] = $column['wrapper']['element'] ?? 'pre';
+    $column['text'] = $column['default'] ?? '-';
+
+    if(is_string($column['value'])) {
+        $column['value'] = json_decode($column['value'], true);
+    }
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].json_encode($column['value'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).$column['suffix'];
+    }
+@endphp
+
+@includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+@if($column['escaped'])
+{{ $column['text'] }}
+@else
+{!! $column['text'] !!}
+@endif
+@includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/columns/model_function.blade.php b/resources/views/vendor/backpack/crud/columns/model_function.blade.php
new file mode 100644 (file)
index 0000000..042a14e
--- /dev/null
@@ -0,0 +1,27 @@
+{{-- custom return value --}}
+@php
+    $column['value'] = $column['value'] ?? $entry->{$column['function_name']}(...($column['function_parameters'] ?? []));
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['limit'] = $column['limit'] ?? 32;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].Str::limit($column['value'], $column['limit'], "…").$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/model_function_attribute.blade.php b/resources/views/vendor/backpack/crud/columns/model_function_attribute.blade.php
new file mode 100644 (file)
index 0000000..394491c
--- /dev/null
@@ -0,0 +1,27 @@
+{{-- custom return value via attribute --}}
+@php
+    $column['value'] = $column['value'] ?? $entry->{$column['function_name']}(...($column['function_parameters'] ?? []))->{$column['attribute']} ?? '';
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['limit'] = $column['limit'] ?? 32;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].Str::limit($column['value'], $column['limit'], "…").$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/multidimensional_array.blade.php b/resources/views/vendor/backpack/crud/columns/multidimensional_array.blade.php
new file mode 100644 (file)
index 0000000..a0260a9
--- /dev/null
@@ -0,0 +1,55 @@
+{{-- enumerate the values in an array --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $list = [];
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    // if the isn't using attribute casting, decode it
+    if (is_string($column['value'])) {
+        $column['value'] = json_decode($column['value']);
+    }
+
+    if (is_array($column['value']) && count($column['value'])) {
+        foreach ($column['value'] as $item) {
+            if (isset($item->{$column['visible_key']})) {
+                $list[$column['visible_key']][] = $item->{$column['visible_key']};
+            } elseif (is_array($item) && isset($item[$column['visible_key']])) {
+                $list[$column['visible_key']][] = $item[$column['visible_key']];
+            }
+        }
+    }
+
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+@endphp
+
+<span>
+    @if(!empty($list))
+        {{ $column['prefix'] }}
+        @foreach($list[$column['visible_key']] as $key => $text)
+            @php
+                $column['text'] = $text;
+                $related_key = $key;
+            @endphp
+
+            <span class="d-inline-flex">
+                @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+                    @if($column['escaped'])
+                        {{ $column['text'] }}
+                    @else
+                        {!! $column['text'] !!}
+                    @endif
+                @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+            
+                @if(!$loop->last), @endif
+            </span>
+        @endforeach
+        {{ $column['suffix'] }}
+    @else
+        {{ $column['default'] ?? '-' }}
+    @endif
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/number.blade.php b/resources/views/vendor/backpack/crud/columns/number.blade.php
new file mode 100644 (file)
index 0000000..5b61fea
--- /dev/null
@@ -0,0 +1,30 @@
+{{-- regular object attribute --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['decimals'] = $column['decimals'] ?? 0;
+    $column['dec_point'] = $column['dec_point'] ?? '.';
+    $column['thousands_sep'] = $column['thousands_sep'] ?? ',';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+    
+    if (!is_null($column['value'])) {
+        $column['value'] = number_format($column['value'], $column['decimals'], $column['dec_point'], $column['thousands_sep']);
+        $column['text'] = $column['prefix'].$column['value'].$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/phone.blade.php b/resources/views/vendor/backpack/crud/columns/phone.blade.php
new file mode 100644 (file)
index 0000000..434ea67
--- /dev/null
@@ -0,0 +1,30 @@
+{{-- telephone link --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['limit'] = $column['limit'] ?? 32;
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].Str::limit(strip_tags($column['value']), $column['limit'], "…").$column['suffix'];
+    }
+
+    $column['wrapper']['element'] = $column['wrapper']['element'] ?? 'a';
+    $column['wrapper']['href'] = $column['wrapper']['href'] ?? 'tel:'.$column['value'];
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/radio.blade.php b/resources/views/vendor/backpack/crud/columns/radio.blade.php
new file mode 100644 (file)
index 0000000..a919599
--- /dev/null
@@ -0,0 +1,28 @@
+{{-- radio --}}
+@php
+    $column['key'] = $column['key'] ?? $column['name'];
+    $column['value'] = $column['value'] ?? data_get($entry, $column['key']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['value'] = $column['options'][$column['value']] ?? '';
+        $column['text'] = $column['prefix'].$column['value'].$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/relationship_count.blade.php b/resources/views/vendor/backpack/crud/columns/relationship_count.blade.php
new file mode 100644 (file)
index 0000000..e8e3727
--- /dev/null
@@ -0,0 +1,26 @@
+{{-- relationship_count (works for n-n relationships) --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? ' items';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].count($column['value']).$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/row_number.blade.php b/resources/views/vendor/backpack/crud/columns/row_number.blade.php
new file mode 100644 (file)
index 0000000..719263f
--- /dev/null
@@ -0,0 +1,27 @@
+{{-- row number --}}
+@php
+    $column['value'] = $column['value'] ?? $rowNumber;
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['limit'] = $column['limit'] ?? 32;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].Str::limit(strip_tags($column['value']), $column['limit'], "…").$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/select.blade.php b/resources/views/vendor/backpack/crud/columns/select.blade.php
new file mode 100644 (file)
index 0000000..2b3ccf3
--- /dev/null
@@ -0,0 +1,43 @@
+{{-- single relationships (1-1, 1-n) --}}
+@php
+    $column['attribute'] = $column['attribute'] ?? (new $column['model'])->identifiableAttribute();
+    $column['value'] = $column['value'] ?? $crud->getRelatedEntriesAttributes($entry, $column['entity'], $column['attribute']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['limit'] = $column['limit'] ?? 32;
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    foreach ($column['value'] as &$value) {
+        $value = Str::limit($value, $column['limit'], '…');
+    }
+@endphp
+
+<span>
+    @if(count($column['value']))
+        {{ $column['prefix'] }}
+        @foreach($column['value'] as $key => $text)
+            @php
+                $related_key = $key;
+            @endphp
+
+            <span class="d-inline-flex">
+                @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+                    @if($column['escaped'])
+                        {{ $text }}
+                    @else
+                        {!! $text !!}
+                    @endif
+                @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+
+                @if(!$loop->last), @endif
+            </span>
+        @endforeach
+        {{ $column['suffix'] }}
+    @else
+        {{ $column['default'] ?? '-' }}
+    @endif
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/select_from_array.blade.php b/resources/views/vendor/backpack/crud/columns/select_from_array.blade.php
new file mode 100644 (file)
index 0000000..1d8a498
--- /dev/null
@@ -0,0 +1,50 @@
+{{-- select_from_array column --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    $list = [];
+    if ($column['value'] !== null) {
+        if (is_array($column['value'])) {
+            foreach ($column['value'] as $key => $value) {
+                if (! is_null($value)) {
+                    $list[$key] = $column['options'][$value] ?? $value;
+                }
+            }
+        } else {
+            $list[$column['value']] = $column['options'][$column['value']] ?? $column['value'];
+        }
+    }
+@endphp
+
+<span>
+    @if(!empty($list))
+        {{ $column['prefix'] }}
+        @foreach($list as $key => $text)
+            @php
+                $related_key = $key;
+            @endphp
+
+            <span class="d-inline-flex">
+                @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+                    @if($column['escaped'])
+                        {{ $text }}
+                    @else
+                        {!! $text !!}
+                    @endif
+                @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+
+                @if(!$loop->last), @endif
+            </span>
+        @endforeach
+        {{ $column['suffix'] }}
+    @else
+        {{ $column['default'] ?? '-' }}
+    @endif
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/select_multiple.blade.php b/resources/views/vendor/backpack/crud/columns/select_multiple.blade.php
new file mode 100644 (file)
index 0000000..0ad4d2c
--- /dev/null
@@ -0,0 +1,50 @@
+{{-- relationships with pivot table (n-n) --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name'], []);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['limit'] = $column['limit'] ?? 32;
+    $column['attribute'] = $column['attribute'] ?? (new $column['model'])->identifiableAttribute();
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if($column['value'] !== null && !$column['value']->isEmpty()) {
+        $related_key = $column['value']->first()->getKeyName();
+        $column['value'] = $column['value']->pluck($column['attribute'], $related_key);
+    }
+
+    $column['value'] = $column['value']
+        ->map(function($value) use ($column) {
+            return Str::limit($value, $column['limit'], '…');
+        })
+        ->toArray();
+@endphp
+
+<span>
+    @if(!empty($column['value']))
+        {{ $column['prefix'] }}
+        @foreach($column['value'] as $key => $text)
+            @php
+                $related_key = $key;
+            @endphp
+
+            <span class="d-inline-flex">
+                @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+                    @if($column['escaped'])
+                        {{ $text }}
+                    @else
+                        {!! $text !!}
+                    @endif
+                @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+
+                @if(!$loop->last), @endif
+            </span>
+        @endforeach
+        {{ $column['suffix'] }}
+    @else
+        {{ $column['default'] ?? '-' }}
+    @endif
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/text.blade.php b/resources/views/vendor/backpack/crud/columns/text.blade.php
new file mode 100644 (file)
index 0000000..8654aca
--- /dev/null
@@ -0,0 +1,31 @@
+{{-- regular object attribute --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['limit'] = $column['limit'] ?? 32;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(is_array($column['value'])) {
+        $column['value'] = json_encode($column['value']);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].Str::limit($column['value'], $column['limit'], '…').$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/textarea.blade.php b/resources/views/vendor/backpack/crud/columns/textarea.blade.php
new file mode 100644 (file)
index 0000000..be8d1a2
--- /dev/null
@@ -0,0 +1,26 @@
+{{-- regular object attribute --}}
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['text'] = $column['default'] ?? '-';
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+
+    if(!empty($column['value'])) {
+        $column['text'] = $column['prefix'].$column['value'].$column['suffix'];
+    }
+@endphp
+
+<span>
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+        @if($column['escaped'])
+            {{ $column['text'] }}
+        @else
+            {!! $column['text'] !!}
+        @endif
+    @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/upload_multiple.blade.php b/resources/views/vendor/backpack/crud/columns/upload_multiple.blade.php
new file mode 100644 (file)
index 0000000..662465a
--- /dev/null
@@ -0,0 +1,43 @@
+@php
+    $column['value'] = $column['value'] ?? data_get($entry, $column['name']);
+    $column['prefix'] = $column['prefix'] ?? '';
+    $column['suffix'] = $column['suffix'] ?? '';
+    $column['disk'] = $column['disk'] ?? null;
+    $column['escaped'] = $column['escaped'] ?? true;
+    $column['wrapper']['element'] = $column['wrapper']['element'] ?? 'a';
+    $column['wrapper']['target'] = $column['wrapper']['target'] ?? '_blank';
+    $column_wrapper_href = $column['wrapper']['href'] ?? 
+    function($file_path, $disk, $prefix) use ($column) { 
+        if (is_null($disk)) {
+            return $prefix.$file_path;
+        }
+        if (isset($column['temporary'])) {
+            return asset(\Storage::disk($disk)->temporaryUrl($file_path, Carbon\Carbon::now()->addMinutes($column['temporary'])));
+        }
+        return asset(\Storage::disk($disk)->url($file_path));
+    };
+
+    if($column['value'] instanceof \Closure) {
+        $column['value'] = $column['value']($entry);
+    }
+@endphp
+
+<span>
+    @if ($column['value'] && count($column['value']))
+        @foreach ($column['value'] as $file_path)
+        @php
+            $column['wrapper']['href'] = $column_wrapper_href instanceof \Closure ? $column_wrapper_href($file_path, $column['disk'], $column['prefix']) : $column_wrapper_href;
+            $text = $column['prefix'].$file_path.$column['suffix'];
+        @endphp
+            @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+            @if($column['escaped'])
+                - {{ $text }} <br/>
+            @else
+                - {!! $text !!} <br/>
+            @endif
+        @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
+        @endforeach
+    @else
+        {{ $column['default'] ?? '-' }}
+    @endif
+</span>
diff --git a/resources/views/vendor/backpack/crud/columns/view.blade.php b/resources/views/vendor/backpack/crud/columns/view.blade.php
new file mode 100644 (file)
index 0000000..1947abe
--- /dev/null
@@ -0,0 +1,3 @@
+@includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start')
+    @include($column['view'])
+@includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/create.blade.php b/resources/views/vendor/backpack/crud/create.blade.php
new file mode 100644 (file)
index 0000000..576223c
--- /dev/null
@@ -0,0 +1,56 @@
+@extends(backpack_view('blank'))
+
+@php
+  $defaultBreadcrumbs = [
+    trans('backpack::crud.admin') => url(config('backpack.base.route_prefix'), 'dashboard'),
+    $crud->entity_name_plural => url($crud->route),
+    trans('backpack::crud.add') => false,
+  ];
+
+  // if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs
+  $breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs;
+@endphp
+
+@section('header')
+       <section class="container-fluid">
+         <h2>
+        <span class="text-capitalize">{!! $crud->getHeading() ?? $crud->entity_name_plural !!}</span>
+        <small>{!! $crud->getSubheading() ?? trans('backpack::crud.add').' '.$crud->entity_name !!}.</small>
+
+        @if ($crud->hasAccess('list'))
+          <small><a href="{{ url($crud->route) }}" class="d-print-none font-sm"><i class="la la-angle-double-{{ config('backpack.base.html_direction') == 'rtl' ? 'right' : 'left' }}"></i> {{ trans('backpack::crud.back_to_all') }} <span>{{ $crud->entity_name_plural }}</span></a></small>
+        @endif
+         </h2>
+       </section>
+@endsection
+
+@section('content')
+
+<div class="row">
+       <div class="{{ $crud->getCreateContentClass() }}">
+               {{-- Default box --}}
+
+               @include('crud::inc.grouped_errors')
+
+                 <form method="post"
+                               action="{{ url($crud->route) }}"
+                               @if ($crud->hasUploadFields('create'))
+                               enctype="multipart/form-data"
+                               @endif
+                               >
+                         {!! csrf_field() !!}
+                     {{-- 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' => 'create' ])
+                     @else
+                       @include('crud::form_content', [ 'fields' => $crud->fields(), 'action' => 'create' ])
+                     @endif
+                {{-- This makes sure that all field assets are loaded. --}}
+                <div class="d-none" id="parentLoadedAssets">{{ json_encode(Assets::loaded()) }}</div>
+                 @include('crud::inc.form_save_buttons')
+                 </form>
+       </div>
+</div>
+
+@endsection
+
diff --git a/resources/views/vendor/backpack/crud/details_row.blade.php b/resources/views/vendor/backpack/crud/details_row.blade.php
new file mode 100644 (file)
index 0000000..d8e65e7
--- /dev/null
@@ -0,0 +1,8 @@
+<div class="m-t-10 m-b-10 p-l-10 p-r-10 p-t-10 p-b-10">
+       <div class="row">
+               <div class="col-md-12">
+                       {{ trans('backpack::crud.details_row') }}
+               </div>
+       </div>
+</div>
+<div class="clearfix"></div>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/edit.blade.php b/resources/views/vendor/backpack/crud/edit.blade.php
new file mode 100644 (file)
index 0000000..08f5036
--- /dev/null
@@ -0,0 +1,71 @@
+@extends(backpack_view('blank'))
+
+@php
+  $defaultBreadcrumbs = [
+    trans('backpack::crud.admin') => backpack_url('dashboard'),
+    $crud->entity_name_plural => url($crud->route),
+    trans('backpack::crud.edit') => false,
+  ];
+
+  // if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs
+  $breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs;
+@endphp
+
+@section('header')
+       <section class="container-fluid">
+         <h2>
+        <span class="text-capitalize">{!! $crud->getHeading() ?? $crud->entity_name_plural !!}</span>
+        <small>{!! $crud->getSubheading() ?? trans('backpack::crud.edit').' '.$crud->entity_name !!}.</small>
+
+        @if ($crud->hasAccess('list'))
+          <small><a href="{{ url($crud->route) }}" class="d-print-none font-sm"><i class="la la-angle-double-{{ config('backpack.base.html_direction') == 'rtl' ? 'right' : 'left' }}"></i> {{ trans('backpack::crud.back_to_all') }} <span>{{ $crud->entity_name_plural }}</span></a></small>
+        @endif
+         </h2>
+       </section>
+@endsection
+
+@section('content')
+<div class="row">
+       <div class="{{ $crud->getEditContentClass() }}">
+               {{-- Default box --}}
+
+               @include('crud::inc.grouped_errors')
+
+                 <form method="post"
+                               action="{{ url($crud->route.'/'.$entry->getKey()) }}"
+                               @if ($crud->hasUploadFields('update', $entry->getKey()))
+                               enctype="multipart/form-data"
+                               @endif
+                               >
+                 {!! csrf_field() !!}
+                 {!! method_field('PUT') !!}
+
+                       @if ($crud->model->translationEnabled())
+                   <div class="mb-2 text-right">
+                       {{-- Single button --}}
+                               <div class="btn-group">
+                                 <button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                                   {{trans('backpack::crud.language')}}: {{ $crud->model->getAvailableLocales()[request()->input('_locale')?request()->input('_locale'):App::getLocale()] }} &nbsp; <span class="caret"></span>
+                                 </button>
+                                 <ul class="dropdown-menu">
+                                       @foreach ($crud->model->getAvailableLocales() as $key => $locale)
+                                               <a class="dropdown-item" href="{{ url($crud->route.'/'.$entry->getKey().'/edit') }}?_locale={{ $key }}">{{ $locale }}</a>
+                                       @endforeach
+                                 </ul>
+                               </div>
+                   </div>
+                   @endif
+                     {{-- 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'])
+                     @else
+                       @include('crud::form_content', ['fields' => $crud->fields(), 'action' => 'edit'])
+              @endif
+              {{-- This makes sure that all field assets are loaded. --}}
+            <div class="d-none" id="parentLoadedAssets">{{ json_encode(Assets::loaded()) }}</div>
+            @include('crud::inc.form_save_buttons')
+                 </form>
+       </div>
+</div>
+@endsection
+
diff --git a/resources/views/vendor/backpack/crud/fields/boolean.blade.php b/resources/views/vendor/backpack/crud/fields/boolean.blade.php
new file mode 100644 (file)
index 0000000..6714f31
--- /dev/null
@@ -0,0 +1 @@
+@include('crud::fields.checkbox')
diff --git a/resources/views/vendor/backpack/crud/fields/checkbox.blade.php b/resources/views/vendor/backpack/crud/fields/checkbox.blade.php
new file mode 100644 (file)
index 0000000..d953642
--- /dev/null
@@ -0,0 +1,79 @@
+{{-- checkbox field --}}
+
+@php
+  $field['value'] = old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '';
+@endphp
+@include('crud::fields.inc.wrapper_start')
+    @include('crud::fields.inc.translatable_icon')
+        <input type="hidden" name="{{ $field['name'] }}" value="{{ $field['value'] }}">
+         <input type="checkbox"
+          data-init-function="bpFieldInitCheckbox"
+
+          @if ((bool)$field['value'])
+                 checked="checked"
+          @endif
+
+          @if (isset($field['attributes']))
+              @foreach ($field['attributes'] as $attribute => $value)
+                       {{ $attribute }}="{{ $value }}"
+                 @endforeach
+          @endif
+          >
+       <label class="font-weight-normal mb-0">{!! $field['label'] !!}</label>
+
+        {{-- HINT --}}
+        @if (isset($field['hint']))
+            <p class="help-block">{!! $field['hint'] !!}</p>
+        @endif
+@include('crud::fields.inc.wrapper_end')
+
+{{-- ########################################## --}}
+{{-- Extra CSS and JS for this particular field --}}
+{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}}
+
+    {{-- FIELD JS - will be loaded in the after_scripts section --}}
+    @push('crud_fields_scripts')
+        @loadOnce('bpFieldInitCheckbox')
+        <script>
+            function bpFieldInitCheckbox(element) {
+                var hidden_element = element.siblings('input[type=hidden]');
+                var id = 'checkbox_'+Math.floor(Math.random() * 1000000);
+
+                // make sure the value is a boolean (so it will pass validation)
+                if (hidden_element.val() === '') hidden_element.val(0).trigger('change');
+
+                // set unique IDs so that labels are correlated with inputs
+                element.attr('id', id);
+                element.siblings('label').attr('for', id);
+
+                // set the default checked/unchecked state
+                // if the field has been loaded with javascript
+                if (hidden_element.val() != 0) {
+                  element.prop('checked', 'checked');
+                } else {
+                  element.prop('checked', false);
+                }
+
+                hidden_element.on('CrudField:disable', function(e) {
+                  element.prop('disabled', true);
+                });
+                hidden_element.on('CrudField:enable', function(e) {
+                  element.removeAttr('disabled');
+                });
+
+                // when the checkbox is clicked
+                // set the correct value on the hidden input
+                element.change(function() {
+                  if (element.is(":checked")) {
+                    hidden_element.val(1).trigger('change');
+                  } else {
+                    hidden_element.val(0).trigger('change');
+                  }
+                })
+            }
+        </script>
+        @endLoadOnce
+    @endpush
+
+{{-- End of Extra CSS and JS --}}
+{{-- ########################################## --}}
diff --git a/resources/views/vendor/backpack/crud/fields/checklist.blade.php b/resources/views/vendor/backpack/crud/fields/checklist.blade.php
new file mode 100644 (file)
index 0000000..57456fb
--- /dev/null
@@ -0,0 +1,106 @@
+{{-- checklist --}}
+@php
+  $key_attribute = (new $field['model'])->getKeyName();
+  $field['attribute'] = $field['attribute'] ?? (new $field['model'])->identifiableAttribute();
+  $field['number_of_columns'] = $field['number_of_columns'] ?? 3;
+
+  // calculate the checklist options
+  if (!isset($field['options'])) {
+      $field['options'] = $field['model']::all()->pluck($field['attribute'], $key_attribute)->toArray();
+  } else {
+      $field['options'] = call_user_func($field['options'], $field['model']::query());
+  }
+
+  // calculate the value of the hidden input
+  $field['value'] = old_empty_or_null($field['name'], []) ??  $field['value'] ?? $field['default'] ?? [];
+  if(!empty($field['value'])) {
+      if (is_a($field['value'], \Illuminate\Support\Collection::class)) {
+          $field['value'] = ($field['value'])->pluck($key_attribute)->toArray();
+      } elseif (is_string($field['value'])){
+        $field['value'] = json_decode($field['value']);
+      }
+  }
+
+  // define the init-function on the wrapper
+  $field['wrapper']['data-init-function'] =  $field['wrapper']['data-init-function'] ?? 'bpFieldInitChecklist';
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    <input type="hidden" value='@json($field['value'])' name="{{ $field['name'] }}">
+
+    <div class="row">
+        @foreach ($field['options'] as $key => $option)
+            <div class="col-sm-{{ intval(12/$field['number_of_columns']) }}">
+                <div class="checkbox">
+                  <label class="font-weight-normal">
+                    <input type="checkbox" value="{{ $key }}"> {{ $option }}
+                  </label>
+                </div>
+            </div>
+        @endforeach
+    </div>
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
+
+
+{{-- ########################################## --}}
+{{-- Extra CSS and JS for this particular field --}}
+{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}}
+    {{-- FIELD JS - will be loaded in the after_scripts section --}}
+    @push('crud_fields_scripts')
+        @loadOnce('bpFieldInitChecklist')
+        <script>
+            function bpFieldInitChecklist(element) {
+                var hidden_input = element.find('input[type=hidden]');
+                var selected_options = JSON.parse(hidden_input.val() || '[]');
+                var checkboxes = element.find('input[type=checkbox]');
+                var container = element.find('.row');
+
+                // set the default checked/unchecked states on checklist options
+                checkboxes.each(function(key, option) {
+                  var id = $(this).val();
+
+                  if (selected_options.map(String).includes(id)) {
+                    $(this).prop('checked', 'checked');
+                  } else {
+                    $(this).prop('checked', false);
+                  }
+                });
+
+                // when a checkbox is clicked
+                // set the correct value on the hidden input
+                checkboxes.click(function() {
+                  var newValue = [];
+
+                  checkboxes.each(function() {
+                    if ($(this).is(':checked')) {
+                      var id = $(this).val();
+                      newValue.push(id);
+                    }
+                  });
+
+                  hidden_input.val(JSON.stringify(newValue)).trigger('change');
+
+                });
+
+                hidden_input.on('CrudField:disable', function(e) {
+                      checkboxes.attr('disabled', 'disabled');
+                  });
+
+                hidden_input.on('CrudField:enable', function(e) {
+                    checkboxes.removeAttr('disabled');
+                });
+
+            }
+        </script>
+        @endLoadOnce
+    @endpush
+{{-- End of Extra CSS and JS --}}
+{{-- ########################################## --}}
diff --git a/resources/views/vendor/backpack/crud/fields/checklist_dependency.blade.php b/resources/views/vendor/backpack/crud/fields/checklist_dependency.blade.php
new file mode 100644 (file)
index 0000000..f4c057d
--- /dev/null
@@ -0,0 +1,316 @@
+{{-- dependencyJson --}}
+@php
+  $field['wrapper'] = $field['wrapper'] ?? $field['wrapperAttributes'] ?? [];
+  $field['wrapper']['class'] = $field['wrapper']['class'] ?? 'form-group col-sm-12';
+  $field['wrapper']['class'] = $field['wrapper']['class'].' checklist_dependency';
+  $field['wrapper']['data-entity'] = $field['wrapper']['data-entity'] ?? $field['field_unique_name'];
+  $field['wrapper']['data-init-function'] = $field['wrapper']['init-function'] ?? 'bpFieldInitChecklistDependencyElement';
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+
+    <label>{!! $field['label'] !!}</label>
+    <?php
+        $entity_model = $crud->getModel();
+
+    //short name for dependency fields
+    $primary_dependency = $field['subfields']['primary'];
+    $secondary_dependency = $field['subfields']['secondary'];
+
+    //all items with relation
+    $dependencies = $primary_dependency['model']::with($primary_dependency['entity_secondary'])->get();
+
+    $dependencyArray = [];
+
+    //convert dependency array to simple matrix ( primary id as key and array with secondaries id )
+    foreach ($dependencies as $primary) {
+        $dependencyArray[$primary->id] = [];
+        foreach ($primary->{$primary_dependency['entity_secondary']} as $secondary) {
+            $dependencyArray[$primary->id][] = $secondary->id;
+        }
+    }
+
+    $old_primary_dependency = old_empty_or_null($primary_dependency['name'], false) ?? false;
+    $old_secondary_dependency = old_empty_or_null($secondary_dependency['name'], false) ?? false;
+
+    //for update form, get initial state of the entity
+    if (isset($id) && $id) {
+        //get entity with relations for primary dependency
+        $entity_dependencies = $entity_model->with($primary_dependency['entity'])
+        ->with($primary_dependency['entity'].'.'.$primary_dependency['entity_secondary'])
+        ->find($id);
+
+        $secondaries_from_primary = [];
+
+        //convert relation in array
+        $primary_array = $entity_dependencies->{$primary_dependency['entity']}->toArray();
+
+        $secondary_ids = [];
+        //create secondary dependency from primary relation, used to check what checkbox must be checked from second checklist
+        if ($old_primary_dependency) {
+            foreach ($old_primary_dependency as $primary_item) {
+                foreach ($dependencyArray[$primary_item] as $second_item) {
+                    $secondary_ids[$second_item] = $second_item;
+                }
+            }
+        } else { //create dependencies from relation if not from validate error
+            foreach ($primary_array as $primary_item) {
+                foreach ($primary_item[$secondary_dependency['entity']] as $second_item) {
+                    $secondary_ids[$second_item['id']] = $second_item['id'];
+                }
+            }
+        }
+    }
+
+    //json encode of dependency matrix
+    $dependencyJson = json_encode($dependencyArray);
+    ?>
+
+    <div class="container">
+
+      <div class="row">
+          <div class="col-sm-12">
+              <label>{!! $primary_dependency['label'] !!}</label>
+              @include('crud::fields.inc.translatable_icon', ['field' => $primary_dependency])
+          </div>
+      </div>
+
+      <div class="row">
+
+          <div class="hidden_fields_primary" data-name = "{{ $primary_dependency['name'] }}">
+          <input type="hidden" bp-field-name="{{$primary_dependency['name']}}" name="{{$primary_dependency['name']}}" value="" />
+          @if(isset($field['value']))
+              @if($old_primary_dependency)
+                  @foreach($old_primary_dependency as $item )
+                  <input type="hidden" class="primary_hidden" name="{{ $primary_dependency['name'] }}[]" value="{{ $item }}">
+                  @endforeach
+              @else
+                  @foreach( $field['value'][0]->pluck('id', 'id')->toArray() as $item )
+                  <input type="hidden" class="primary_hidden" name="{{ $primary_dependency['name'] }}[]" value="{{ $item }}">
+                  @endforeach
+              @endif
+            @endif
+          </div>
+
+      @foreach ($primary_dependency['model']::all() as $connected_entity_entry)
+          <div class="col-sm-{{ isset($primary_dependency['number_columns']) ? intval(12/$primary_dependency['number_columns']) : '4'}}">
+              <div class="checkbox">
+                  <label class="font-weight-normal">
+                      <input type="checkbox"
+                          data-id = "{{ $connected_entity_entry->id }}"
+                          class = 'primary_list'
+                          @foreach ($primary_dependency as $attribute => $value)
+                              @if (is_string($attribute) && $attribute != 'value')
+                                  @if ($attribute=='name')
+                                  {{ $attribute }}="{{ $value }}_show[]"
+                                  @else
+                                  {{ $attribute }}="{{ $value }}"
+                                  @endif
+                              @endif
+                          @endforeach
+                          value="{{ $connected_entity_entry->id }}"
+
+                          @if( ( isset($field['value']) && is_array($field['value']) && in_array($connected_entity_entry->id, $field['value'][0]->pluck('id', 'id')->toArray())) || $old_primary_dependency && in_array($connected_entity_entry->id, $old_primary_dependency))
+                          checked = "checked"
+                          @endif >
+                          {{ $connected_entity_entry->{$primary_dependency['attribute']} }}
+                  </label>
+              </div>
+          </div>
+      @endforeach
+      </div>
+
+      <div class="row">
+          <div class="col-sm-12">
+              <label>{!! $secondary_dependency['label'] !!}</label>
+              @include('crud::fields.inc.translatable_icon', ['field' => $secondary_dependency])
+          </div>
+      </div>
+
+      <div class="row">
+          <div class="hidden_fields_secondary" data-name="{{ $secondary_dependency['name'] }}">
+            <input type="hidden" bp-field-name="{{$secondary_dependency['name']}}" name="{{$secondary_dependency['name']}}" value="" />
+            @if(isset($field['value']))
+              @if($old_secondary_dependency)
+                @foreach($old_secondary_dependency as $item )
+                  <input type="hidden" class="secondary_hidden" name="{{ $secondary_dependency['name'] }}[]" value="{{ $item }}">
+                @endforeach
+              @else
+                @foreach( $field['value'][1]->pluck('id', 'id')->toArray() as $item )
+                  <input type="hidden" class="secondary_hidden" name="{{ $secondary_dependency['name'] }}[]" value="{{ $item }}">
+                @endforeach
+              @endif
+            @endif
+          </div>
+
+          @foreach ($secondary_dependency['model']::all() as $connected_entity_entry)
+              <div class="col-sm-{{ isset($secondary_dependency['number_columns']) ? intval(12/$secondary_dependency['number_columns']) : '4'}}">
+                  <div class="checkbox">
+                      <label class="font-weight-normal">
+                      <input type="checkbox"
+                          class = 'secondary_list'
+                          data-id = "{{ $connected_entity_entry->id }}"
+                          @foreach ($secondary_dependency as $attribute => $value)
+                              @if (is_string($attribute) && $attribute != 'value')
+                                @if ($attribute=='name')
+                                  {{ $attribute }}="{{ $value }}_show[]"
+                                @else
+                                  {{ $attribute }}="{{ $value }}"
+                                @endif
+                              @endif
+                          @endforeach
+                           value="{{ $connected_entity_entry->id }}"
+
+                          @if( ( isset($field['value']) && is_array($field['value']) && (  in_array($connected_entity_entry->id, $field['value'][1]->pluck('id', 'id')->toArray()) || isset( $secondary_ids[$connected_entity_entry->id])) || $old_secondary_dependency && in_array($connected_entity_entry->id, $old_secondary_dependency)))
+                               checked = "checked"
+                               @if(isset( $secondary_ids[$connected_entity_entry->id]))
+                                disabled = disabled
+                               @endif
+                          @endif > {{ $connected_entity_entry->{$secondary_dependency['attribute']} }}
+                      </label>
+                  </div>
+              </div>
+          @endforeach
+      </div>
+    </div>{{-- /.container --}}
+
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+
+@include('crud::fields.inc.wrapper_end')
+
+{{-- ########################################## --}}
+{{-- Extra CSS and JS for this particular field --}}
+{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}}
+
+@push('crud_fields_scripts')
+    <script>
+        var  {{ $field['field_unique_name'] }} = {!! $dependencyJson !!};
+    </script>
+@endpush
+
+{{-- FIELD JS - will be loaded in the after_scripts section --}}
+@push('crud_fields_scripts')
+  {{-- include checklist_dependency js --}}
+  @loadOnce('bpFieldInitChecklistDependencyElement')
+    <script>
+      function bpFieldInitChecklistDependencyElement(element) {
+
+          var unique_name = element.data('entity');
+          var dependencyJson = window[unique_name];
+          var thisField = element;
+          var handleCheckInput = function(el, field, dependencyJson) {
+            let idCurrent = el.data('id');
+            //add hidden field with this value
+            let nameInput = field.find('.hidden_fields_primary').data('name');
+            if(field.find('input.primary_hidden[value="'+idCurrent+'"]').length === 0) {
+              let inputToAdd = $('<input type="hidden" class="primary_hidden" name="'+nameInput+'[]" value="'+idCurrent+'">');
+
+              field.find('.hidden_fields_primary').append(inputToAdd);
+              field.find('.hidden_fields_primary').find('input.primary_hidden[value="'+idCurrent+'"]').trigger('change');
+            }
+            $.each(dependencyJson[idCurrent], function(key, value){
+              //check and disable secondies checkbox
+              field.find('input.secondary_list[value="'+value+'"]').prop( "checked", true );
+              field.find('input.secondary_list[value="'+value+'"]').prop( "disabled", true );
+              field.find('input.secondary_list[value="'+value+'"]').attr('forced-select', 'true');
+              //remove hidden fields with secondary dependency if was set
+              var hidden = field.find('input.secondary_hidden[value="'+value+'"]');
+              if(hidden)
+                hidden.remove();
+            });
+          };
+          
+          thisField.find('div.hidden_fields_primary').children('input').first().on('CrudField:disable', function(e) {
+              let input = $(e.target);
+              input.parent().parent().find('input[type=checkbox]').attr('disabled', 'disabled');
+              input.siblings('input').attr('disabled','disabled');
+          });
+
+          thisField.find('div.hidden_fields_primary').children('input').first().on('CrudField:enable', function(e) {
+              let input = $(e.target);
+              input.parent().parent().find('input[type=checkbox]').not('[forced-select]').removeAttr('disabled');
+              input.siblings('input').removeAttr('disabled');
+          });
+
+          thisField.find('div.hidden_fields_secondary').children('input').first().on('CrudField:disable', function(e) {
+              let input = $(e.target);
+              input.parent().parent().find('input[type=checkbox]').attr('disabled', 'disabled');
+              input.siblings('input').attr('disabled','disabled');
+          });
+
+          thisField.find('div.hidden_fields_secondary').children('input').first().on('CrudField:enable', function(e) {
+              let input = $(e.target);
+              input.parent().parent().find('input[type=checkbox]').not('[forced-select]').removeAttr('disabled');
+              input.siblings('input').removeAttr('disabled');
+          });
+
+          thisField.find('.primary_list').each(function() {
+            var checkbox = $(this);
+            // re-check the secondary boxes in case the primary is re-checked from old.
+            if(checkbox.is(':checked')){
+               handleCheckInput(checkbox, thisField, dependencyJson);
+            }
+            // register the change event to handle subsquent checkbox state changes.
+            checkbox.change(function(){
+              if(checkbox.is(':checked')){
+                handleCheckInput(checkbox, thisField, dependencyJson);
+              }else{
+                let idCurrent = checkbox.data('id');
+                //remove hidden field with this value.
+                thisField.find('input.primary_hidden[value="'+idCurrent+'"]').remove();
+
+                // uncheck and active secondary checkboxs if are not in other selected primary.
+                var secondary = dependencyJson[idCurrent];
+
+                var selected = [];
+                thisField.find('input.primary_hidden').each(function (index, input){
+                  selected.push( $(this).val() );
+                });
+
+                $.each(secondary, function(index, secondaryItem){
+                  var ok = 1;
+
+                  $.each(selected, function(index2, selectedItem){
+                    if( dependencyJson[selectedItem].indexOf(secondaryItem) != -1 ){
+                      ok =0;
+                    }
+                  });
+
+                  if(ok){
+                    thisField.find('input.secondary_list[value="'+secondaryItem+'"]').prop('checked', false);
+                    thisField.find('input.secondary_list[value="'+secondaryItem+'"]').prop('disabled', false);
+                    thisField.find('input.secondary_list[value="'+secondaryItem+'"]').removeAttr('forced-select');
+                  }
+                });
+
+              }
+              });
+          });
+
+
+          thisField.find('.secondary_list').click(function(){
+
+            var idCurrent = $(this).data('id');
+            if($(this).is(':checked')){
+              //add hidden field with this value
+              var nameInput = thisField.find('.hidden_fields_secondary').data('name');
+              var inputToAdd = $('<input type="hidden" class="secondary_hidden" name="'+nameInput+'[]" value="'+idCurrent+'">');
+
+              thisField.find('.hidden_fields_secondary').append(inputToAdd);
+
+            }else{
+              //remove hidden field with this value
+              thisField.find('input.secondary_hidden[value="'+idCurrent+'"]').remove();
+            }
+          });
+
+      }
+    </script>
+  @endLoadOnce
+@endpush
+{{-- End of Extra CSS and JS --}}
+{{-- ########################################## --}}
diff --git a/resources/views/vendor/backpack/crud/fields/color.blade.php b/resources/views/vendor/backpack/crud/fields/color.blade.php
new file mode 100644 (file)
index 0000000..a667e87
--- /dev/null
@@ -0,0 +1,21 @@
+{{-- html5 color input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="color"
+            name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+       >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/custom_html.blade.php b/resources/views/vendor/backpack/crud/fields/custom_html.blade.php
new file mode 100644 (file)
index 0000000..666ff6b
--- /dev/null
@@ -0,0 +1,4 @@
+{{-- used for heading, separators, etc --}}
+@includeWhen(!isset($field['wrapper']) || $field['wrapper'] !== false, 'crud::fields.inc.wrapper_start')
+       {!! $field['value'] !!}
+@includeWhen(!isset($field['wrapper']) || $field['wrapper'] !== false, 'crud::fields.inc.wrapper_end')
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/fields/date.blade.php b/resources/views/vendor/backpack/crud/fields/date.blade.php
new file mode 100644 (file)
index 0000000..7d68928
--- /dev/null
@@ -0,0 +1,30 @@
+{{-- html5 date input --}}
+
+<?php
+// if the column has been cast to Carbon or Date (using attribute casting)
+// get the value as a date string
+if (isset($field['value']) && ($field['value'] instanceof \Carbon\CarbonInterface)) {
+    $field['value'] = $field['value']->toDateString();
+}
+?>
+
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="date"
+            name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+        >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/datetime.blade.php b/resources/views/vendor/backpack/crud/fields/datetime.blade.php
new file mode 100644 (file)
index 0000000..2356c09
--- /dev/null
@@ -0,0 +1,34 @@
+{{-- html5 datetime input --}}
+
+@php
+// if the column has been cast to Carbon or Date (using attribute casting)
+// get the value as a date string
+if (isset($field['value']) && ($field['value'] instanceof \Carbon\CarbonInterface)) {
+    $field['value'] = $field['value']->toDateTimeString();
+}
+
+$timestamp = strtotime(old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '');
+
+$value = $timestamp ? date('Y-m-d\TH:i:s', $timestamp) : '';
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="datetime-local"
+            name="{{ $field['name'] }}"
+            value="{{ $value }}"
+            @include('crud::fields.inc.attributes')
+        >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+    
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/email.blade.php b/resources/views/vendor/backpack/crud/fields/email.blade.php
new file mode 100644 (file)
index 0000000..7b83c8a
--- /dev/null
@@ -0,0 +1,21 @@
+{{-- text input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="email"
+            name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+       >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/enum.blade.php b/resources/views/vendor/backpack/crud/fields/enum.blade.php
new file mode 100644 (file)
index 0000000..6d53f31
--- /dev/null
@@ -0,0 +1,91 @@
+{{-- enum --}}
+@php
+    $entity_model = $field['model'] ?? $field['baseModel'] ?? $crud->model;
+
+    $field['value'] = old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '';
+
+    $possible_values = (function() use ($entity_model, $field) {
+        $fieldName = $field['baseFieldName'] ?? $field['name'];
+        // if developer provided the options, use them, no ned to guess.
+        if(isset($field['options'])) {
+            return $field['options'];
+        }
+
+        // if we are in a PHP version where PHP enums are not available, it can only be a database enum
+        if(! function_exists('enum_exists')) {
+            $options = $entity_model::getPossibleEnumValues($fieldName);
+            return array_combine($options, $options);
+        }
+
+        // developer can provide the enum class so that we extract the available options from it
+        $enumClassReflection = isset($field['enum_class']) ? new \ReflectionEnum($field['enum_class']) : false;
+
+        if(! $enumClassReflection) {
+            // check for model casting
+            $possibleEnumCast = (new $entity_model)->getCasts()[$fieldName] ?? false;
+            if($possibleEnumCast && class_exists($possibleEnumCast)) {
+                $enumClassReflection = new \ReflectionEnum($possibleEnumCast);
+            }
+        }
+
+        if($enumClassReflection) {
+            $options = array_map(function($item) use ($enumClassReflection) {
+                return $enumClassReflection->isBacked() ? [$item->getBackingValue() => $item->name] : $item->name;
+            },$enumClassReflection->getCases());
+            $options = is_multidimensional_array($options) ? array_replace(...$options) : array_combine($options, $options);
+        }
+
+        if(isset($field['enum_function']) && isset($options)) {
+            $options = array_map(function($item) use ($field, $enumClassReflection) {
+                if ($enumClassReflection->hasConstant($item)) {
+                    return $enumClassReflection->getConstant($item)->{$field['enum_function']}();
+                }
+                return $item;
+            }, $options);
+            return $options;
+        }
+
+        // if we have the enum options return them
+        if(isset($options)) {
+            return $options;
+        }
+
+        // no enum options, can only be database enum
+        $options = $entity_model::getPossibleEnumValues($field['name']);
+        return array_combine($options, $options);
+    })();
+
+
+    if(function_exists('enum_exists') && !empty($field['value']) && $field['value'] instanceof \UnitEnum)  {
+        $field['value'] = $field['value'] instanceof \BackedEnum ? $field['value']->value : $field['value']->name;
+    }
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+    <select
+        name="{{ $field['name'] }}"
+        @include('crud::fields.inc.attributes')
+        >
+
+        @if ($entity_model::isColumnNullable($field['name']))
+            <option value="">-</option>
+        @endif
+
+            @if (count($possible_values))
+                @foreach ($possible_values as $key => $possible_value)
+                    <option value="{{ $key }}"
+                        @if ($field['value']==$key)
+                            selected
+                        @endif
+                    >{{ $possible_value }}</option>
+                @endforeach
+            @endif
+    </select>
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/hidden.blade.php b/resources/views/vendor/backpack/crud/fields/hidden.blade.php
new file mode 100644 (file)
index 0000000..e07bf41
--- /dev/null
@@ -0,0 +1,15 @@
+@php
+       // if not otherwise specified, the hidden input should take up no space in the form
+  $field['wrapper'] = $field['wrapper'] ?? $field['wrapperAttributes'] ?? [];
+  $field['wrapper']['class'] = $field['wrapper']['class'] ?? "hidden";
+@endphp
+
+{{-- hidden input --}}
+@include('crud::fields.inc.wrapper_start')
+  <input
+       type="hidden"
+    name="{{ $field['name'] }}"
+    value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+    @include('crud::fields.inc.attributes')
+       >
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/inc/attributes.blade.php b/resources/views/vendor/backpack/crud/fields/inc/attributes.blade.php
new file mode 100644 (file)
index 0000000..480d786
--- /dev/null
@@ -0,0 +1,10 @@
+@php
+    $field['attributes'] = $field['attributes'] ?? [];
+    $field['attributes']['class'] = $field['attributes']['class'] ?? $default_class ?? 'form-control';
+@endphp
+
+@foreach ($field['attributes'] as $attribute => $value)
+       @if (is_string($attribute))
+    {{ $attribute }}="{{ $value }}"
+    @endif
+@endforeach
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/fields/inc/translatable_icon.blade.php b/resources/views/vendor/backpack/crud/fields/inc/translatable_icon.blade.php
new file mode 100644 (file)
index 0000000..2745a7c
--- /dev/null
@@ -0,0 +1,20 @@
+@php
+    // if field name is array we check if any of the arrayed fields is translatable
+    $translatable = false;
+    if($crud->model->translationEnabled()) {
+        foreach((array) $field['name'] as $field_name){
+            if($crud->model->isTranslatableAttribute($field_name)) {
+                $translatable = true;
+            }
+        }
+        // if the field is a fake one (value is stored in a JSON column instead of a direct db column)
+        // and that JSON column is translatable, then the field itself should be translatable
+        if(isset($field['store_in']) && $crud->model->isTranslatableAttribute($field['store_in'])) {
+                $translatable = true;
+        }
+    }
+
+@endphp
+@if ($translatable && config('backpack.crud.show_translatable_field_icon'))
+    <i class="la la-flag-checkered pull-{{ config('backpack.crud.translatable_field_icon_position') }}" style="margin-top: 3px;" title="This field is translatable."></i>
+@endif
diff --git a/resources/views/vendor/backpack/crud/fields/inc/wrapper_end.blade.php b/resources/views/vendor/backpack/crud/fields/inc/wrapper_end.blade.php
new file mode 100644 (file)
index 0000000..45cc546
--- /dev/null
@@ -0,0 +1 @@
+</{{ $field['wrapper']['element'] ?? 'div' }}>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/fields/inc/wrapper_start.blade.php b/resources/views/vendor/backpack/crud/fields/inc/wrapper_start.blade.php
new file mode 100644 (file)
index 0000000..6b45def
--- /dev/null
@@ -0,0 +1,34 @@
+@php
+       $field['wrapper'] = $field['wrapper'] ?? $field['wrapperAttributes'] ?? [];
+
+    // each wrapper attribute can be a callback or a string
+    // for those that are callbacks, run the callbacks to get the final string to use
+    foreach($field['wrapper'] as $attributeKey => $value) {
+        $field['wrapper'][$attributeKey] = !is_string($value) && $value instanceof \Closure ? $value($crud, $field, $entry ?? null) : $value ?? '';
+    }
+       // if the field is required in any of the crud validators (FormRequest, controller validation or field validation) 
+       // we add an astherisc for it. Case it's a subfield, that check is done upstream in repeatable_row. 
+       // the reason for that is that here the field name is already the repeatable name: parent[row][fieldName]
+       if(!isset($field['parentFieldName']) || !$field['parentFieldName']) {
+               $fieldName = is_array($field['name']) ? current($field['name']) : $field['name'];
+               $required = (isset($action) && $crud->isRequired($fieldName)) ? ' required' : '';
+       }
+       
+       // if the developer has intentionally set the required attribute on the field
+       // forget whatever is in the FormRequest, do what the developer wants
+       // subfields also get here with `showAsterisk` already set.
+       $required = isset($field['showAsterisk']) ? ($field['showAsterisk'] ? ' required' : '') : ($required ?? '');
+       
+       $field['wrapper']['class'] = $field['wrapper']['class'] ?? "form-group col-sm-12";
+       $field['wrapper']['class'] = $field['wrapper']['class'].$required;
+       $field['wrapper']['element'] = $field['wrapper']['element'] ?? 'div';
+       $field['wrapper']['bp-field-wrapper'] = 'true';
+       $field['wrapper']['bp-field-name'] = square_brackets_to_dots(implode(',', (array)$field['name']));
+       $field['wrapper']['bp-field-type'] = $field['type'];
+@endphp
+
+<{{ $field['wrapper']['element'] }}
+       @foreach($field['wrapper'] as $attribute => $value)
+           {{ $attribute }}="{{ $value }}"
+       @endforeach
+>
diff --git a/resources/views/vendor/backpack/crud/fields/month.blade.php b/resources/views/vendor/backpack/crud/fields/month.blade.php
new file mode 100644 (file)
index 0000000..aa16e82
--- /dev/null
@@ -0,0 +1,21 @@
+{{-- html5 month input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="month"
+            name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+        >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/number.blade.php b/resources/views/vendor/backpack/crud/fields/number.blade.php
new file mode 100644 (file)
index 0000000..6553444
--- /dev/null
@@ -0,0 +1,22 @@
+{{-- number input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+               type="number"
+               name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+               >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/password.blade.php b/resources/views/vendor/backpack/crud/fields/password.blade.php
new file mode 100644 (file)
index 0000000..82b953b
--- /dev/null
@@ -0,0 +1,28 @@
+{{-- password --}}
+
+@php
+    // autocomplete off, if not otherwise specified
+    if (!isset($field['attributes']['autocomplete'])) {
+        $field['attributes']['autocomplete'] = "off";
+    }
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="password"
+            name="{{ $field['name'] }}"
+            @include('crud::fields.inc.attributes')
+       >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/radio.blade.php b/resources/views/vendor/backpack/crud/fields/radio.blade.php
new file mode 100644 (file)
index 0000000..55d2c37
--- /dev/null
@@ -0,0 +1,92 @@
+{{-- radio --}}
+@php
+    $optionValue = old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '';
+
+    // check if attribute is casted, if it is, we get back un-casted values
+    if(Arr::get($crud->model->getCasts(), $field['name']) === 'boolean') {
+        $optionValue = (int) $optionValue;
+    }
+
+    // if the class isn't overwritten, use 'radio'
+    if (!isset($field['attributes']['class'])) {
+        $field['attributes']['class'] = 'radio';
+    }
+
+    $field['wrapper'] = $field['wrapper'] ?? $field['wrapperAttributes'] ?? [];
+    $field['wrapper']['data-init-function'] = $field['wrapper']['data-init-function'] ?? 'bpFieldInitRadioElement';
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+
+
+        <label class="d-block">{!! $field['label'] !!}</label>
+        @include('crud::fields.inc.translatable_icon')
+
+
+    <input type="hidden" value="{{ $optionValue }}" name="{{$field['name']}}" />
+
+    @if( isset($field['options']) && $field['options'] = (array)$field['options'] )
+
+        @foreach ($field['options'] as $value => $label )
+
+            <div class="form-check {{ isset($field['inline']) && $field['inline'] ? 'form-check-inline' : '' }}">
+                <input  type="radio"
+                        class="form-check-input"
+                        value="{{$value}}"
+                        @include('crud::fields.inc.attributes')
+                        >
+                <label class="{{ isset($field['inline']) && $field['inline'] ? 'radio-inline' : '' }} form-check-label font-weight-normal">{!! $label !!}</label>
+            </div>
+
+        @endforeach
+
+    @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+
+@include('crud::fields.inc.wrapper_end')
+
+    {{-- FIELD JS - will be loaded in the after_scripts section --}}
+    @push('crud_fields_scripts')
+    @loadOnce('bpFieldInitRadioElement')
+    <script>
+        function bpFieldInitRadioElement(element) {
+            var hiddenInput = element.find('input[type=hidden]');
+            var value = hiddenInput.val();
+            var id = 'radio_'+Math.floor(Math.random() * 1000000);
+
+            // set unique IDs so that labels are correlated with inputs
+            element.find('.form-check input[type=radio]').each(function(index, item) {
+                $(this).attr('id', id+index);
+                $(this).siblings('label').attr('for', id+index);
+            });
+
+            hiddenInput.on('CrudField:disable', function(e) {
+                element.find('.form-check input[type=radio]').each(function(index, item) {
+                    $(this).prop('disabled', true);
+                });
+            });
+
+            hiddenInput.on('CrudField:enable', function(e) {
+                element.find('.form-check input[type=radio]').each(function(index, item) {
+                    $(this).removeAttr('disabled');
+                });
+            });
+
+            // when one radio input is selected
+            element.find('input[type=radio]').change(function(event) {
+                // the value gets updated in the hidden input and the 'change' event is fired
+                hiddenInput.val($(this).val()).change();
+                // all other radios get unchecked
+                element.find('input[type=radio]').not(this).prop('checked', false);
+            });
+
+            // select the right radios
+            element.find('input[type=radio][value="'+value+'"]').prop('checked', true);
+        }
+    </script>
+    @endLoadOnce
+    @endpush
diff --git a/resources/views/vendor/backpack/crud/fields/range.blade.php b/resources/views/vendor/backpack/crud/fields/range.blade.php
new file mode 100644 (file)
index 0000000..a156b1c
--- /dev/null
@@ -0,0 +1,16 @@
+{{-- html5 range input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+    <input
+        type="range"
+        name="{{ $field['name'] }}"
+        value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+        @include('crud::fields.inc.attributes')
+        >
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/select.blade.php b/resources/views/vendor/backpack/crud/fields/select.blade.php
new file mode 100644 (file)
index 0000000..1d29847
--- /dev/null
@@ -0,0 +1,53 @@
+{{-- select --}}
+@php
+       $current_value = old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '';
+    $entity_model = $crud->getRelationModel($field['entity'],  - 1);
+    $field['allows_null'] = $field['allows_null'] ?? $entity_model::isColumnNullable($field['name']);
+
+    //if it's part of a relationship here we have the full related model, we want the key.
+    if (is_object($current_value) && is_subclass_of(get_class($current_value), 'Illuminate\Database\Eloquent\Model') ) {
+        $current_value = $current_value->getKey();
+    }
+
+    if (!isset($field['options'])) {
+        $options = $field['model']::all();
+    } else {
+        $options = call_user_func($field['options'], $field['model']::query());
+    }
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <select
+            name="{{ $field['name'] }}"
+            @include('crud::fields.inc.attributes')
+            >
+
+            @if ($field['allows_null'])
+                <option value="">-</option>
+            @endif
+
+            @if (count($options))
+                @foreach ($options as $connected_entity_entry)
+                    @if($current_value == $connected_entity_entry->getKey())
+                        <option value="{{ $connected_entity_entry->getKey() }}" selected>{{ $connected_entity_entry->{$field['attribute']} }}</option>
+                    @else
+                        <option value="{{ $connected_entity_entry->getKey() }}">{{ $connected_entity_entry->{$field['attribute']} }}</option>
+                    @endif
+                @endforeach
+            @endif
+        </select>
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/select_from_array.blade.php b/resources/views/vendor/backpack/crud/fields/select_from_array.blade.php
new file mode 100644 (file)
index 0000000..170f44c
--- /dev/null
@@ -0,0 +1,36 @@
+@php
+    $field['allows_null'] = $field['allows_null'] ?? $crud->model::isColumnNullable($field['name']);
+    $field['value'] = old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '';
+    $field['multiple'] = $field['allows_multiple'] ?? $field['multiple'] ?? false;
+@endphp
+{{-- select from array --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+    @if($field['multiple'])<input type="hidden" name="{{ $field['name'] }}" value="" @if(in_array('disabled', $field['attributes'] ?? [])) disabled @endif />@endif
+    <select
+        name="{{ $field['name'] }}@if ($field['multiple'])[]@endif"
+        @include('crud::fields.inc.attributes')
+        @if ($field['multiple'])multiple bp-field-main-input @endif
+        >
+
+        @if ($field['allows_null'] && !$field['multiple'])
+            <option value="">-</option>
+        @endif
+
+        @if (count($field['options']))
+            @foreach ($field['options'] as $key => $value)
+                @if($key == $field['value'] || (is_array($field['value']) && in_array($key, $field['value'])))
+                    <option value="{{ $key }}" selected>{{ $value }}</option>
+                @else
+                    <option value="{{ $key }}">{{ $value }}</option>
+                @endif
+            @endforeach
+        @endif
+    </select>
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/select_grouped.blade.php b/resources/views/vendor/backpack/crud/fields/select_grouped.blade.php
new file mode 100644 (file)
index 0000000..db8976a
--- /dev/null
@@ -0,0 +1,65 @@
+{{-- select_grouped --}}
+@php
+    $current_value = old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '';
+    $field['allows_null'] = $field['allows_null'] ?? $field['model']::isColumnNullable($field['name']);
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+    @php
+        $related_model = $field['model'];
+        $group_by_model = (new $related_model)->{$field['group_by']}()->getRelated();
+        $categories = $group_by_model::with($field['group_by_relationship_back'])->get();
+
+        if (isset($field['model'])) {
+            $categorylessEntries = $related_model::doesnthave($field['group_by'])->get();
+        }
+    @endphp
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <select
+            name="{{ $field['name'] }}"
+            @include('crud::fields.inc.attributes', ['default_class' =>  'form-control'])
+            >
+
+                @if ($field['allows_null'])
+                    <option value="">-</option>
+                @endif
+
+                @if (isset($field['model']) && isset($field['group_by']))
+                    @foreach ($categories as $category)
+                        <optgroup label="{{ $category->{$field['group_by_attribute']} }}">
+                            @foreach ($category->{$field['group_by_relationship_back']} as $subEntry)
+                                <option value="{{ $subEntry->getKey() }}"
+                                    @if ( ( old($field['name']) && old($field['name']) == $subEntry->getKey() ) || (isset($field['value']) && $subEntry->getKey()==$field['value']))
+                                        selected
+                                    @endif
+                                >{{ $subEntry->{$field['attribute']} }}</option>
+                            @endforeach
+                        </optgroup>
+                    @endforeach
+
+                    @if ($categorylessEntries->count())
+                        <optgroup label="-">
+                            @foreach ($categorylessEntries as $subEntry)
+
+                                @if($current_value == $subEntry->getKey())
+                                    <option value="{{ $subEntry->getKey() }}" selected>{{ $subEntry->{$field['attribute']} }}</option>
+                                @else
+                                    <option value="{{ $subEntry->getKey() }}">{{ $subEntry->{$field['attribute']} }}</option>
+                                @endif
+                            @endforeach
+                        </optgroup>
+                    @endif
+                @endif
+        </select>
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/select_multiple.blade.php b/resources/views/vendor/backpack/crud/fields/select_multiple.blade.php
new file mode 100644 (file)
index 0000000..96d801f
--- /dev/null
@@ -0,0 +1,48 @@
+{{-- select multiple --}}
+@php
+    if (!isset($field['options'])) {
+        $options = $field['model']::all();
+    } else {
+        $options = call_user_func($field['options'], $field['model']::query());
+    }
+    $field['allows_null'] = $field['allows_null'] ?? true;
+
+    $field['value'] = old_empty_or_null($field['name'], collect()) ??  $field['value'] ?? $field['default'] ?? collect();
+
+    if (is_a($field['value'], \Illuminate\Support\Collection::class)) {
+        $field['value'] = $field['value']->pluck(app($field['model'])->getKeyName())->toArray();
+    }
+    
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+    {{-- To make sure a value gets submitted even if the "select multiple" is empty, we need a hidden input --}}
+    <input type="hidden" name="{{ $field['name'] }}" value="" @if(in_array('disabled', $field['attributes'] ?? [])) disabled @endif />
+    <select
+       class="form-control"
+        name="{{ $field['name'] }}[]"
+        @include('crud::fields.inc.attributes')
+        bp-field-main-input
+       multiple>
+
+       @if (count($options))
+               @foreach ($options as $option)
+                               @if(in_array($option->getKey(), $field['value']))
+                                       <option value="{{ $option->getKey() }}" selected>{{ $option->{$field['attribute']} }}</option>
+                               @else
+                                       <option value="{{ $option->getKey() }}">{{ $option->{$field['attribute']} }}</option>
+                               @endif
+               @endforeach
+       @endif
+
+       </select>
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/summernote.blade.php b/resources/views/vendor/backpack/crud/fields/summernote.blade.php
new file mode 100644 (file)
index 0000000..92fc8de
--- /dev/null
@@ -0,0 +1,75 @@
+{{-- summernote editor --}}
+@php
+    // make sure that the options array is defined
+    // and at the very least, dialogsInBody is true;
+    // that's needed for modals to show above the overlay in Bootstrap 4
+    $field['options'] = array_merge(['dialogsInBody' => true, 'tooltip' => false], $field['options'] ?? []);
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+    <textarea
+        name="{{ $field['name'] }}"
+        data-init-function="bpFieldInitSummernoteElement"
+        data-options="{{ json_encode($field['options']) }}"
+        bp-field-main-input
+        @include('crud::fields.inc.attributes', ['default_class' =>  'form-control summernote'])
+        >{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}</textarea>
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
+
+
+{{-- ########################################## --}}
+{{-- Extra CSS and JS for this particular field --}}
+{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}}
+
+    {{-- FIELD CSS - will be loaded in the after_styles section --}}
+@push('crud_fields_styles')
+    {{-- include summernote css --}}
+    @loadOnce('packages/summernote/dist/summernote-bs4.css')
+    @loadOnce('summernoteCss')
+    <style type="text/css">
+        .note-editor.note-frame .note-status-output, .note-editor.note-airframe .note-status-output {
+                height: auto;
+        }
+    </style>
+    @endLoadOnce
+@endpush
+{{-- FIELD JS - will be loaded in the after_scripts section --}}
+@push('crud_fields_scripts')
+    {{-- include summernote js --}}
+    @loadOnce('packages/summernote/dist/summernote-bs4.min.js')
+    @loadOnce('bpFieldInitSummernoteElement')
+    <script>
+        function bpFieldInitSummernoteElement(element) {
+             var summernoteOptions = element.data('options');
+
+            let summernotCallbacks = { 
+                onChange: function(contents, $editable) {
+                    element.val(contents).trigger('change');
+                }
+            }
+
+            element.on('CrudField:disable', function(e) {
+                element.summernote('disable');
+            });
+
+            element.on('CrudField:enable', function(e) {
+                element.summernote('enable');
+            });
+            
+            summernoteOptions['callbacks'] = summernotCallbacks;
+            
+            element.summernote(summernoteOptions); 
+        }
+    </script>
+    @endLoadOnce
+@endpush
+
+{{-- End of Extra CSS and JS --}}
+{{-- ########################################## --}}
diff --git a/resources/views/vendor/backpack/crud/fields/switch.blade.php b/resources/views/vendor/backpack/crud/fields/switch.blade.php
new file mode 100644 (file)
index 0000000..80e4e18
--- /dev/null
@@ -0,0 +1,96 @@
+{{-- switch field --}}
+@php
+    $field['value'] = old_empty_or_null($field['name'], '') ?? $field['value'] ?? $field['default'] ?? '0';
+    $field['onLabel'] = $field['onLabel'] ?? '';
+    $field['offLabel'] = $field['offLabel'] ?? '';
+    $field['color'] = $field['color'] ?? 'primary';
+@endphp
+
+{{-- Wrapper --}}
+@include('crud::fields.inc.wrapper_start')
+
+    {{-- Translatable icon --}}
+    @include('crud::fields.inc.translatable_icon')
+
+    <div class="d-inline-flex">
+        {{-- Switch --}}
+        <label class="switch switch-sm switch-label switch-pill switch-{{ $field['color'] }} mb-0" style="--bg-color: {{ $field['color'] }};">
+            <input
+                type="hidden"
+                name="{{ $field['name'] }}"
+                value="{{ (int) $field['value'] }}" />
+            <input
+                type="checkbox"
+                data-init-function="bpFieldInitSwitch"
+                {{ (bool) $field['value'] ? 'checked' : '' }}
+                class="switch-input" />
+            <span
+                class="switch-slider"
+                data-checked="{{ $field['onLabel'] ?? '' }}"
+                data-unchecked="{{ $field['offLabel'] ?? '' }}">
+            </span>
+        </label>
+
+        {{-- Label --}}
+        <label class="font-weight-normal mb-0 ml-2">{!! $field['label'] !!}</label>
+    </div>
+
+    {{-- Label for the required * --}}
+    <label class="d-inline-flex m-0">&nbsp;</label>
+
+    {{-- Hint --}}
+    @isset($field['hint'])
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endisset
+@include('crud::fields.inc.wrapper_end')
+
+{{-- ########################################## --}}
+{{-- Extra CSS and JS for this particular field --}}
+{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}}
+
+{{-- FIELD JS - will be loaded in the after_scripts section --}}
+@push('crud_fields_scripts')
+    @loadOnce('bpFieldInitSwitchScript')
+    <script>
+        function bpFieldInitSwitch($element) {
+            let element = $element[0];
+            let hiddenElement = element.previousElementSibling;
+            let id = `switch_${hiddenElement.name}_${Math.random() * 1e18}`;
+
+            // set unique IDs so that labels are correlated with inputs
+            element.setAttribute('id', id);
+            element.parentElement.nextElementSibling.setAttribute('for', id);
+
+            // set the default checked/unchecked state
+            // if the field has been loaded with javascript
+            hiddenElement.value !== '0'
+                ? element.setAttribute('checked', true)
+                : element.removeAttribute('checked');
+
+            // JS Field API
+            $(hiddenElement).on('CrudField:disable', () => element.setAttribute('disabled', true));
+            $(hiddenElement).on('CrudField:enable', () => element.removeAttribute('disabled'));
+
+            // when the checkbox is clicked
+            // set the correct value on the hidden input
+            $element.on('change', () => {
+                hiddenElement.value = element.checked ? 1 : 0;
+                hiddenElement.dispatchEvent(new Event('change'));
+            });
+        }
+    </script>
+    @endLoadOnce
+@endpush
+
+@push('crud_fields_styles')
+    @loadOnce('bpFieldInitSwitchStyle')
+    <style>
+        .switch-input:checked+.switch-slider {
+            background-color: var(--bg-color);
+        }
+    </style>
+    @endLoadOnce
+@endpush
+
+{{-- End of Extra CSS and JS --}}
+{{-- ########################################## --}}
diff --git a/resources/views/vendor/backpack/crud/fields/text.blade.php b/resources/views/vendor/backpack/crud/fields/text.blade.php
new file mode 100644 (file)
index 0000000..83c3ee8
--- /dev/null
@@ -0,0 +1,22 @@
+{{-- text input --}}
+
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="text"
+            name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+        >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/textarea.blade.php b/resources/views/vendor/backpack/crud/fields/textarea.blade.php
new file mode 100644 (file)
index 0000000..7f4eae1
--- /dev/null
@@ -0,0 +1,15 @@
+{{-- textarea --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+    <textarea
+       name="{{ $field['name'] }}"
+        @include('crud::fields.inc.attributes')
+
+       >{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}</textarea>
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/time.blade.php b/resources/views/vendor/backpack/crud/fields/time.blade.php
new file mode 100644 (file)
index 0000000..9bda26f
--- /dev/null
@@ -0,0 +1,21 @@
+{{-- html5 time input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="time"
+            name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+       >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/upload.blade.php b/resources/views/vendor/backpack/crud/fields/upload.blade.php
new file mode 100644 (file)
index 0000000..bbfcb91
--- /dev/null
@@ -0,0 +1,193 @@
+@php
+    $field['wrapper'] = $field['wrapper'] ?? $field['wrapperAttributes'] ?? [];
+    $field['wrapper']['data-init-function'] = $field['wrapper']['data-init-function'] ?? 'bpFieldInitUploadElement';
+    $field['wrapper']['data-field-name'] = $field['wrapper']['data-field-name'] ?? $field['name'];
+@endphp
+
+{{-- text input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+       {{-- Show the file name and a "Clear" button on EDIT form. --}}
+    @if (!empty($field['value']))
+    <div class="existing-file">
+        @if (isset($field['disk']))
+        @if (isset($field['temporary']))
+            <a target="_blank" href="{{ (asset(\Storage::disk($field['disk'])->temporaryUrl(Arr::get($field, 'prefix', '').$field['value'], Carbon\Carbon::now()->addMinutes($field['temporary'])))) }}">
+        @else
+            <a target="_blank" href="{{ (asset(\Storage::disk($field['disk'])->url(Arr::get($field, 'prefix', '').$field['value']))) }}">
+        @endif
+        @else
+            <a target="_blank" href="{{ (asset(Arr::get($field, 'prefix', '').$field['value'])) }}">
+        @endif
+            {{ $field['value'] }}
+        </a>
+       <a href="#" class="file_clear_button btn btn-light btn-sm float-right" title="Clear file"><i class="la la-remove"></i></a>
+       <div class="clearfix"></div>
+    </div>
+    @endif
+
+       {{-- Show the file picker on CREATE form. --}}
+    <div class="backstrap-file {{ isset($field['value']) && $field['value']!=null?'d-none':'' }}">
+        <input
+            type="file"
+            name="{{ $field['name'] }}"
+            @include('crud::fields.inc.attributes', ['default_class' => isset($field['value']) && $field['value']!=null?'file_input backstrap-file-input':'file_input backstrap-file-input'])
+        >
+        <label class="backstrap-file-label" for="customFile"></label>
+    </div>
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
+
+
+
+{{-- ########################################## --}}
+{{-- Extra CSS and JS for this particular field --}}
+{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}}
+
+@push('crud_fields_styles')
+  @loadOnce('upload_field_styles')
+    <style type="text/css">
+        .existing-file {
+            border: 1px solid rgba(0,40,100,.12);
+            border-radius: 5px;
+            padding-left: 10px;
+            vertical-align: middle;
+        }
+        .existing-file a {
+            padding-top: 5px;
+            display: inline-block;
+            font-size: 0.9em;
+        }
+        .backstrap-file {
+          position: relative;
+          display: inline-block;
+          width: 100%;
+          height: calc(1.5em + 0.75rem + 2px);
+          margin-bottom: 0;
+        }
+
+        .backstrap-file-input {
+          position: relative;
+          z-index: 2;
+          width: 100%;
+          height: calc(1.5em + 0.75rem + 2px);
+          margin: 0;
+          opacity: 0;
+        }
+
+        .backstrap-file-input:focus ~ .backstrap-file-label {
+          border-color: #acc5ea;
+          box-shadow: 0 0 0 0rem rgba(70, 127, 208, 0.25);
+        }
+
+        .backstrap-file-input:disabled ~ .backstrap-file-label {
+          background-color: #e4e7ea;
+        }
+
+        .backstrap-file-input:lang(en) ~ .backstrap-file-label::after {
+          content: "Browse";
+        }
+
+        .backstrap-file-input ~ .backstrap-file-label[data-browse]::after {
+          content: attr(data-browse);
+        }
+
+        .backstrap-file-label {
+          position: absolute;
+          top: 0;
+          right: 0;
+          left: 0;
+          z-index: 1;
+          height: calc(1.5em + 0.75rem + 2px);
+          padding: 0.375rem 0.75rem;
+          font-weight: 400;
+          line-height: 1.5;
+          color: #5c6873;
+          background-color: #fff;
+          border: 1px solid #e4e7ea;
+          border-radius: 0.25rem;
+          font-weight: 400!important;
+        }
+
+        .backstrap-file-label::after {
+          position: absolute;
+          top: 0;
+          right: 0;
+          bottom: 0;
+          z-index: 3;
+          display: block;
+          height: calc(1.5em + 0.75rem);
+          padding: 0.375rem 0.75rem;
+          line-height: 1.5;
+          color: #5c6873;
+          content: "Browse";
+          background-color: #f0f3f9;
+          border-left: inherit;
+          border-radius: 0 0.25rem 0.25rem 0;
+        }
+    </style>
+  @endLoadOnce
+@endpush
+
+@push('crud_fields_scripts')
+  @loadOnce('bpFieldInitUploadElement')
+    <script>
+        function bpFieldInitUploadElement(element) {
+            var fileInput = element.find(".file_input");
+            var fileClearButton = element.find(".file_clear_button");
+            var fieldName = element.attr('data-field-name');
+            var inputWrapper = element.find(".backstrap-file");
+            var inputLabel = element.find(".backstrap-file-label");
+
+            fileClearButton.click(function(e) {
+                e.preventDefault();
+                $(this).parent().addClass('d-none');
+
+                fileInput.parent().removeClass('d-none');
+                fileInput.attr("value", "").replaceWith(fileInput.clone(true));
+
+                // redo the selector, so we can use the same fileInput variable going forward
+                fileInput = element.find(".file_input");
+
+                // add a hidden input with the same name, so that the setXAttribute method is triggered
+                $("<input type='hidden' name='"+fieldName+"' value=''>").insertAfter(fileInput);
+            });
+
+            fileInput.change(function() {
+                var path = $(this).val();
+                var path = path.replace("C:\\fakepath\\", "");
+                inputLabel.html(path);
+                // remove the hidden input, so that the setXAttribute method is no longer triggered
+                $(this).next("input[type=hidden]").remove();
+            });
+
+            element.on('CrudField:disable', function(e) {
+              element.children('.backstrap-file').find('input').prop('disabled', 'disabled');
+              
+              let $deleteButton = element.children('.existing-file').children('a.file_clear_button');
+              
+              if($deleteButton.length > 0) {
+                $deleteButton.on('click.prevent', function(e) {
+                    e.stopImmediatePropagation();
+                    return false;
+                  });
+                  // make the event we just registered, the first to be triggered
+                  $._data($deleteButton.get(0), "events").click.reverse();
+              }
+          });
+
+          element.on('CrudField:enable', function(e) {
+            element.children('.backstrap-file').find('input').removeAttr('disabled');
+            element.children('.existing-file').children('a.file_clear_button').unbind('click.prevent');
+          });
+
+        }
+    </script>
+  @endLoadOnce
+@endpush
diff --git a/resources/views/vendor/backpack/crud/fields/upload_multiple.blade.php b/resources/views/vendor/backpack/crud/fields/upload_multiple.blade.php
new file mode 100644 (file)
index 0000000..313b515
--- /dev/null
@@ -0,0 +1,204 @@
+@php
+    $field['wrapper'] = $field['wrapper'] ?? $field['wrapperAttributes'] ?? [];
+    $field['wrapper']['data-init-function'] = $field['wrapper']['data-init-function'] ?? 'bpFieldInitUploadMultipleElement';
+    $field['wrapper']['data-field-name'] = $field['wrapper']['data-field-name'] ?? $field['name'];
+@endphp
+
+{{-- upload multiple input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+       {{-- Show the file name and a "Clear" button on EDIT form. --}}
+       @if (isset($field['value']))
+       @php
+               if (is_string($field['value'])) {
+                       $values = json_decode($field['value'], true) ?? [];
+               } else {
+                       $values = $field['value'];
+               }
+       @endphp
+       @if (count($values))
+    <div class="well well-sm existing-file">
+       @foreach($values as $key => $file_path)
+               <div class="file-preview">
+                       @if (isset($field['temporary']))
+                           <a target="_blank" href="{{ isset($field['disk'])?asset(\Storage::disk($field['disk'])->temporaryUrl($file_path, Carbon\Carbon::now()->addMinutes($field['temporary']))):asset($file_path) }}">{{ $file_path }}</a>
+                       @else
+                           <a target="_blank" href="{{ isset($field['disk'])?asset(\Storage::disk($field['disk'])->url($file_path)):asset($file_path) }}">{{ $file_path }}</a>
+                       @endif
+                       <a href="#" class="btn btn-light btn-sm float-right file-clear-button" title="Clear file" data-filename="{{ $file_path }}"><i class="la la-remove"></i></a>
+                       <div class="clearfix"></div>
+               </div>
+       @endforeach
+    </div>
+    @endif
+    @endif
+       {{-- Show the file picker on CREATE form. --}}
+       <input name="{{ $field['name'] }}[]" type="hidden" value="">
+       <div class="backstrap-file mt-2">
+               <input
+               type="file"
+               name="{{ $field['name'] }}[]"
+               @include('crud::fields.inc.attributes', ['default_class' =>  isset($field['value']) && $field['value']!=null?'file_input backstrap-file-input':'file_input backstrap-file-input'])
+               multiple
+           >
+        <label class="backstrap-file-label" for="customFile"></label>
+    </div>
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+
+       @include('crud::fields.inc.wrapper_end')
+
+{{-- ########################################## --}}
+{{-- Extra CSS and JS for this particular field --}}
+       @push('crud_fields_styles')
+       @loadOnce('upload_field_styles')
+       <style type="text/css">
+               .existing-file {
+                       border: 1px solid rgba(0,40,100,.12);
+                       border-radius: 5px;
+                       padding-left: 10px;
+                       vertical-align: middle;
+               }
+               .existing-file a {
+                       padding-top: 5px;
+                       display: inline-block;
+                       font-size: 0.9em;
+               }
+               .backstrap-file {
+                       position: relative;
+                       display: inline-block;
+                       width: 100%;
+                       height: calc(1.5em + 0.75rem + 2px);
+                       margin-bottom: 0;
+               }
+
+               .backstrap-file-input {
+                       position: relative;
+                       z-index: 2;
+                       width: 100%;
+                       height: calc(1.5em + 0.75rem + 2px);
+                       margin: 0;
+                       opacity: 0;
+               }
+
+               .backstrap-file-input:focus ~ .backstrap-file-label {
+                       border-color: #acc5ea;
+                       box-shadow: 0 0 0 0rem rgba(70, 127, 208, 0.25);
+               }
+
+               .backstrap-file-input:disabled ~ .backstrap-file-label {
+                       background-color: #e4e7ea;
+               }
+
+               .backstrap-file-input:lang(en) ~ .backstrap-file-label::after {
+                       content: "Browse";
+               }
+
+               .backstrap-file-input ~ .backstrap-file-label[data-browse]::after {
+                       content: attr(data-browse);
+               }
+
+               .backstrap-file-label {
+                       position: absolute;
+                       top: 0;
+                       right: 0;
+                       left: 0;
+                       z-index: 1;
+                       height: calc(1.5em + 0.75rem + 2px);
+                       padding: 0.375rem 0.75rem;
+                       font-weight: 400;
+                       line-height: 1.5;
+                       color: #5c6873;
+                       background-color: #fff;
+                       border: 1px solid #e4e7ea;
+                       border-radius: 0.25rem;
+                       font-weight: 400!important;
+               }
+
+               .backstrap-file-label::after {
+                       position: absolute;
+                       top: 0;
+                       right: 0;
+                       bottom: 0;
+                       z-index: 3;
+                       display: block;
+                       height: calc(1.5em + 0.75rem);
+                       padding: 0.375rem 0.75rem;
+                       line-height: 1.5;
+                       color: #5c6873;
+                       content: "Browse";
+                       background-color: #f0f3f9;
+                       border-left: inherit;
+                       border-radius: 0 0.25rem 0.25rem 0;
+               }
+       </style>
+       @endLoadOnce
+       @endpush
+    @push('crud_fields_scripts')
+       @loadOnce('bpFieldInitUploadMultipleElement')
+        <script>
+               function bpFieldInitUploadMultipleElement(element) {
+                       var fieldName = element.attr('data-field-name');
+                       var clearFileButton = element.find(".file-clear-button");
+                       var fileInput = element.find("input[type=file]");
+                       var inputLabel = element.find("label.backstrap-file-label");
+
+                       clearFileButton.click(function(e) {
+                               e.preventDefault();
+                               var container = $(this).parent().parent();
+                               var parent = $(this).parent();
+                               // remove the filename and button
+                               parent.remove();
+                               // if the file container is empty, remove it
+                               if ($.trim(container.html())=='') {
+                                               //$('<input type="hidden" name="'+fieldName+'[]" value="">').insertBefore(fileInput);
+                                       container.remove();
+                               }
+                               $("<input type='hidden' name='clear_"+fieldName+"[]' value='"+$(this).data('filename')+"'>").insertAfter(fileInput);
+                       });
+
+                       fileInput.change(function() {
+                       inputLabel.html("{{trans('backpack::crud.upload_multiple_files_selected')}}");
+                                       let selectedFiles = [];
+
+                                       Array.from($(this)[0].files).forEach(file => {
+                                               selectedFiles.push({name: file.name, type: file.type})
+                                       });
+
+                                       element.find('input').first().val(JSON.stringify(selectedFiles)).trigger('change');
+                               // remove the hidden input, so that the setXAttribute method is no longer triggered
+                                       $(this).next("input[type=hidden]:not([name='clear_"+fieldName+"[]'])").remove();
+                       });
+
+                               element.find('input').on('CrudField:disable', function(e) {
+                                       element.children('.backstrap-file').find('input').prop('disabled', 'disabled');
+                                       element.children('.existing-file').find('.file-preview').each(function(i, el) {
+
+                                               let $deleteButton = $(el).find('a.file-clear-button');
+
+                                               if(deleteButton.length > 0) {
+                                                       $deleteButton.on('click.prevent', function(e) {
+                                                               e.stopImmediatePropagation();
+                                                               return false;
+                                                       });
+                                                       // make the event we just registered, the first to be triggered
+                                                       $._data($deleteButton.get(0), "events").click.reverse();
+                                               }
+                                       });
+                               });
+
+                               element.on('CrudField:enable', function(e) {
+                                       element.children('.backstrap-file').find('input').removeAttr('disabled');
+                                       element.children('.existing-file').find('.file-preview').each(function(i, el) {
+                                               $(el).find('a.file-clear-button').unbind('click.prevent');
+                                       });
+                               });
+               }
+        </script>
+        @endLoadOnce
+    @endpush
diff --git a/resources/views/vendor/backpack/crud/fields/url.blade.php b/resources/views/vendor/backpack/crud/fields/url.blade.php
new file mode 100644 (file)
index 0000000..f509837
--- /dev/null
@@ -0,0 +1,21 @@
+{{-- html5 url input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+    
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="url"
+            name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+       >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+    
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/view.blade.php b/resources/views/vendor/backpack/crud/fields/view.blade.php
new file mode 100644 (file)
index 0000000..c327968
--- /dev/null
@@ -0,0 +1,4 @@
+{{-- view field --}}
+@includeWhen(!isset($field['wrapper']) || $field['wrapper'] !== false, 'crud::fields.inc.wrapper_start')
+  @include($field['view'], ['crud' => $crud, 'entry' => $entry ?? null, 'field' => $field])
+@includeWhen(!isset($field['wrapper']) || $field['wrapper'] !== false, 'crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/fields/week.blade.php b/resources/views/vendor/backpack/crud/fields/week.blade.php
new file mode 100644 (file)
index 0000000..ba94757
--- /dev/null
@@ -0,0 +1,21 @@
+{{-- html5 week input --}}
+@include('crud::fields.inc.wrapper_start')
+    <label>{!! $field['label'] !!}</label>
+    @include('crud::fields.inc.translatable_icon')
+
+    @if(isset($field['prefix']) || isset($field['suffix'])) <div class="input-group"> @endif
+        @if(isset($field['prefix'])) <div class="input-group-prepend"><span class="input-group-text">{!! $field['prefix'] !!}</span></div> @endif
+        <input
+            type="week"
+            name="{{ $field['name'] }}"
+            value="{{ old_empty_or_null($field['name'], '') ??  $field['value'] ?? $field['default'] ?? '' }}"
+            @include('crud::fields.inc.attributes')
+        >
+        @if(isset($field['suffix'])) <div class="input-group-append"><span class="input-group-text">{!! $field['suffix'] !!}</span></div> @endif
+    @if(isset($field['prefix']) || isset($field['suffix'])) </div> @endif
+
+    {{-- HINT --}}
+    @if (isset($field['hint']))
+        <p class="help-block">{!! $field['hint'] !!}</p>
+    @endif
+@include('crud::fields.inc.wrapper_end')
diff --git a/resources/views/vendor/backpack/crud/form_content.blade.php b/resources/views/vendor/backpack/crud/form_content.blade.php
new file mode 100644 (file)
index 0000000..73655a2
--- /dev/null
@@ -0,0 +1,233 @@
+<input type="hidden" name="_http_referrer" value={{ session('referrer_url_override') ?? old('_http_referrer') ?? \URL::previous() ?? url($crud->route) }}>
+
+{{-- See if we're using tabs --}}
+@if ($crud->tabsEnabled() && count($crud->getTabs()))
+    @include('crud::inc.show_tabbed_fields')
+    <input type="hidden" name="_current_tab" value="{{ Str::slug($crud->getTabs()[0]) }}" />
+@else
+  <div class="card">
+    <div class="card-body row">
+      @include('crud::inc.show_fields', ['fields' => $crud->fields()])
+    </div>
+  </div>
+@endif
+
+
+{{-- Define blade stacks so css and js can be pushed from the fields to these sections. --}}
+
+@section('after_styles')
+
+    {{-- CRUD FORM CONTENT - crud_fields_styles stack --}}
+    @stack('crud_fields_styles')
+
+@endsection
+
+@section('after_scripts')
+
+    {{-- CRUD FORM CONTENT - crud_fields_scripts stack --}}
+    @stack('crud_fields_scripts')
+
+    <script>
+    function initializeFieldsWithJavascript(container) {
+      var selector;
+      if (container instanceof jQuery) {
+        selector = container;
+      } else {
+        selector = $(container);
+      }
+      selector.find("[data-init-function]").not("[data-initialized=true]").each(function () {
+        var element = $(this);
+        var functionName = element.data('init-function');
+
+        if (typeof window[functionName] === "function") {
+          window[functionName](element);
+
+          // mark the element as initialized, so that its function is never called again
+          element.attr('data-initialized', 'true');
+        }
+      });
+    }
+
+    /**
+     * Auto-discover first focusable input
+     * @param {jQuery} form
+     * @return {jQuery}
+     */
+    function getFirstFocusableField(form) {
+        return form.find('input, select, textarea, button')
+            .not('.close')
+            .not('[disabled]')
+            .filter(':visible:first');
+    }
+
+    /**
+     *
+     * @param {jQuery} firstField
+     */
+    function triggerFocusOnFirstInputField(firstField) {
+        if (firstField.hasClass('select2-hidden-accessible')) {
+            return handleFocusOnSelect2Field(firstField);
+        }
+
+        firstField.trigger('focus');
+    }
+
+    /**
+     * 1- Make sure no other select2 input is open in other field to focus on the right one
+     * 2- Check until select2 is initialized
+     * 3- Open select2
+     *
+     * @param {jQuery} firstField
+     */
+    function handleFocusOnSelect2Field(firstField){
+        firstField.select2('focus');
+    }
+
+    /*
+    * Hacky fix for a bug in select2 with jQuery 3.6.0's new nested-focus "protection"
+    * see: https://github.com/select2/select2/issues/5993
+    * see: https://github.com/jquery/jquery/issues/4382
+    *
+    */
+    $(document).on('select2:open', () => {
+        setTimeout(() => document.querySelector('.select2-container--open .select2-search__field').focus(), 100);
+    });
+
+    jQuery('document').ready(function($){
+
+      // trigger the javascript for all fields that have their js defined in a separate method
+      initializeFieldsWithJavascript('form');
+
+      // Retrieves the current form data
+      function getFormData() {
+        return new URLSearchParams(new FormData(document.querySelector("main form"))).toString();
+      }
+
+      // Prevents unloading of page if form data was changed
+      function preventUnload(event) {
+        if (initData !== getFormData()) {
+          // Cancel the event as stated by the standard.
+          event.preventDefault();
+          // Older browsers supported custom message
+          event.returnValue = '';
+        }
+      }
+
+      @if($crud->getOperationSetting('warnBeforeLeaving'))
+      const initData = getFormData();
+      window.addEventListener('beforeunload', preventUnload);
+      @endif
+
+      // Save button has multiple actions: save and exit, save and edit, save and new
+      var saveActions = $('#saveActions')
+      crudForm        = saveActions.parents('form')
+
+      // Ctrl+S and Cmd+S trigger Save button click
+      $(document).keydown(function(e) {
+          if ((e.which == '115' || e.which == '83' ) && (e.ctrlKey || e.metaKey))
+          {
+              e.preventDefault();
+              $("button[type=submit]").trigger('click');
+              return false;
+          }
+          return true;
+      });
+
+      // prevent duplicate entries on double-clicking the submit form
+      crudForm.submit(function (event) {
+        window.removeEventListener('beforeunload', preventUnload);
+        $("button[type=submit]").prop('disabled', true);
+      });
+
+      // Place the focus on the first element in the form
+      @if( $crud->getAutoFocusOnFirstField() )
+        @php
+          $focusField = Arr::first($fields, function($field) {
+              return isset($field['auto_focus']) && $field['auto_focus'] == true;
+          });
+        @endphp
+
+        let focusField;
+
+        @if ($focusField)
+          @php
+            $focusFieldName = isset($focusField['value']) && is_iterable($focusField['value']) ? $focusField['name'] . '[]' : $focusField['name'];
+          @endphp
+            focusField = $('[name="{{ $focusFieldName }}"]').eq(0);
+        @else
+            focusField = getFirstFocusableField($('form'));
+        @endif
+
+        const fieldOffset = focusField.offset().top;
+        const scrollTolerance = $(window).height() / 2;
+
+        triggerFocusOnFirstInputField(focusField);
+
+        if( fieldOffset > scrollTolerance ){
+            $('html, body').animate({scrollTop: (fieldOffset - 30)});
+        }
+      @endif
+
+      // Add inline errors to the DOM
+      @if ($crud->inlineErrorsEnabled() && session()->get('errors'))
+
+        window.errors = {!! json_encode(session()->get('errors')->getBags()) !!};
+
+        $.each(errors, function(bag, errorMessages){
+          $.each(errorMessages,  function (inputName, messages) {
+            var normalizedProperty = inputName.split('.').map(function(item, index){
+                    return index === 0 ? item : '['+item+']';
+                }).join('');
+
+            var field = $('[name="' + normalizedProperty + '[]"]').length ?
+                        $('[name="' + normalizedProperty + '[]"]') :
+                        $('[name="' + normalizedProperty + '"]'),
+                        container = field.closest('.form-group');
+
+            // iterate the inputs to add invalid classes to fields and red text to the field container.
+            container.find('input, textarea, select').each(function() {
+                let containerField = $(this);
+                // add the invalid class to the field.
+                containerField.addClass('is-invalid');
+                // get field container
+                let container = containerField.closest('.form-group');
+
+                // TODO: `repeatable-group` should be deprecated in future version as a BC in favor of a more generic class `no-error-display`
+                if(!container.hasClass('repeatable-group') && !container.hasClass('no-error-display')){
+                  container.addClass('text-danger');
+                }
+            });
+
+            $.each(messages, function(key, msg){
+                // highlight the input that errored
+                var row = $('<div class="invalid-feedback d-block">' + msg + '</div>');
+
+                // TODO: `repeatable-group` should be deprecated in future version as a BC in favor of a more generic class `no-error-display`
+                if(!container.hasClass('repeatable-group') && !container.hasClass('no-error-display')){
+                  row.appendTo(container);
+                }
+
+
+                // highlight its parent tab
+                @if ($crud->tabsEnabled())
+                var tab_id = $(container).closest('[role="tabpanel"]').attr('id');
+                $("#form_tabs [aria-controls="+tab_id+"]").addClass('text-danger');
+                @endif
+            });
+        });
+      });
+      @endif
+
+      $("a[data-toggle='tab']").click(function(){
+          currentTabName = $(this).attr('tab_name');
+          $("input[name='_current_tab']").val(currentTabName);
+      });
+
+      if (window.location.hash) {
+          $("input[name='_current_tab']").val(window.location.hash.substr(1));
+      }
+      });
+    </script>
+
+    @include('crud::inc.form_fields_script')
+@endsection
diff --git a/resources/views/vendor/backpack/crud/inc/ajax_error_frame.blade.php b/resources/views/vendor/backpack/crud/inc/ajax_error_frame.blade.php
new file mode 100644 (file)
index 0000000..9ab1d87
--- /dev/null
@@ -0,0 +1,60 @@
+<script>
+$(document).ajaxComplete((e, result, settings) => {
+    if(result.responseJSON?.exception !== undefined) {
+        $.ajax({...settings, accepts: "text/html", backpackExceptionHandler: true});
+    }
+    else if(settings.backpackExceptionHandler) {
+        Noty.closeAll();
+        showErrorFrame(result.responseText);
+    }
+});
+
+const showErrorFrame = html => {
+    let page = document.createElement('html');
+    page.innerHTML = html;
+    page.querySelectorAll('a').forEach(a => a.setAttribute('target', '_top'));
+
+    let modal = document.getElementById('ajax-error-frame');
+
+    if (typeof modal !== 'undefined' && modal !== null) {
+        modal.innerHTML = '';
+    } else {
+        modal = document.createElement('div');
+        modal.id = 'ajax-error-frame';
+        modal.style.position = 'fixed';
+        modal.style.width = '100vw';
+        modal.style.height = '100vh';
+        modal.style.padding = '5vh 5vw';
+        modal.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
+        modal.style.zIndex = 200000;
+    }
+
+    let iframe = document.createElement('iframe');
+    iframe.style.backgroundColor = '#17161A';
+    iframe.style.borderRadius = '5px';
+    iframe.style.width = '100%';
+    iframe.style.height = '100%';
+    iframe.style.border = '0';
+    iframe.style.boxShadow = '0 0 4rem';
+    modal.appendChild(iframe);
+
+    document.body.prepend(modal);
+    document.body.style.overflow = 'hidden';
+    iframe.contentWindow.document.open();
+    iframe.contentWindow.document.write(page.outerHTML);
+    iframe.contentWindow.document.close();
+
+    // Close on click
+    modal.addEventListener('click', () => hideErrorFrame(modal));
+
+    // Close on escape key press
+    modal.setAttribute('tabindex', 0);
+    modal.addEventListener('keydown', e => e.key === 'Escape' && hideErrorFrame(modal));
+    modal.focus();
+}
+
+const hideErrorFrame = modal => {
+    modal.outerHTML = '';
+    document.body.style.overflow = 'visible';
+}
+</script>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/inc/button_stack.blade.php b/resources/views/vendor/backpack/crud/inc/button_stack.blade.php
new file mode 100644 (file)
index 0000000..c1fb4f4
--- /dev/null
@@ -0,0 +1,5 @@
+@if ($crud->buttons()->where('stack', $stack)->count())
+       @foreach ($crud->buttons()->where('stack', $stack) as $button)
+         {!! $button->getHtml($entry ?? null) !!}
+       @endforeach
+@endif
diff --git a/resources/views/vendor/backpack/crud/inc/datatables_logic.blade.php b/resources/views/vendor/backpack/crud/inc/datatables_logic.blade.php
new file mode 100644 (file)
index 0000000..c5710bf
--- /dev/null
@@ -0,0 +1,424 @@
+ @php
+    // as it is possible that we can be redirected with persistent table we save the alerts in a variable
+    // and flush them from session, so we will get them later from localStorage.
+    $backpack_alerts = \Alert::getMessages();
+    \Alert::flush();
+ @endphp
+
+  {{-- DATA TABLES SCRIPT --}}
+  <script type="text/javascript" src="{{ asset('packages/datatables.net/js/jquery.dataTables.min.js') }}"></script>
+  <script type="text/javascript" src="{{ asset('packages/datatables.net-bs4/js/dataTables.bootstrap4.min.js') }}"></script>
+  <script type="text/javascript" src="{{ asset('packages/datatables.net-responsive/js/dataTables.responsive.min.js') }}"></script>
+  <script type="text/javascript" src="{{ asset('packages/datatables.net-responsive-bs4/js/responsive.bootstrap4.min.js') }}"></script>
+  <script type="text/javascript" src="{{ asset('packages/datatables.net-fixedheader/js/dataTables.fixedHeader.min.js') }}"></script>
+  <script type="text/javascript" src="{{ asset('packages/datatables.net-fixedheader-bs4/js/fixedHeader.bootstrap4.min.js') }}"></script>
+
+  <script>
+    // here we will check if the cached dataTables paginator length is conformable with current paginator settings.
+    // datatables caches the ajax responses with pageLength in LocalStorage so when changing this
+    // settings in controller users get unexpected results. To avoid that we will reset
+    // the table cache when both lengths don't match.
+    let $dtCachedInfo = JSON.parse(localStorage.getItem('DataTables_crudTable_/{{$crud->getRoute()}}'))
+        ? JSON.parse(localStorage.getItem('DataTables_crudTable_/{{$crud->getRoute()}}')) : [];
+    var $dtDefaultPageLength = {{ $crud->getDefaultPageLength() }};
+    let $dtStoredPageLength = localStorage.getItem('DataTables_crudTable_/{{$crud->getRoute()}}_pageLength');
+
+    if(!$dtStoredPageLength && $dtCachedInfo.length !== 0 && $dtCachedInfo.length !== $dtDefaultPageLength) {
+        localStorage.removeItem('DataTables_crudTable_/{{$crud->getRoute()}}');
+    }
+
+    // in this page we allways pass the alerts to localStorage because we can be redirected with
+    // persistent table, and this way we guarantee non-duplicate alerts.
+    $oldAlerts = JSON.parse(localStorage.getItem('backpack_alerts'))
+        ? JSON.parse(localStorage.getItem('backpack_alerts')) : {};
+
+    $newAlerts = @json($backpack_alerts);
+
+    Object.entries($newAlerts).forEach(function(type) {
+        if(typeof $oldAlerts[type[0]] !== 'undefined') {
+            type[1].forEach(function(msg) {
+                $oldAlerts[type[0]].push(msg);
+            });
+        } else {
+            $oldAlerts[type[0]] = type[1];
+        }
+    });
+
+    // always store the alerts in localStorage for this page
+    localStorage.setItem('backpack_alerts', JSON.stringify($oldAlerts));
+
+    @if ($crud->getPersistentTable())
+
+        var saved_list_url = localStorage.getItem('{{ Str::slug($crud->getRoute()) }}_list_url');
+
+        //check if saved url has any parameter or is empty after clearing filters.
+        if (saved_list_url && saved_list_url.indexOf('?') < 1) {
+            var saved_list_url = false;
+        } else {
+            var persistentUrl = saved_list_url+'&persistent-table=true';
+        }
+
+    var arr = window.location.href.split('?');
+    // check if url has parameters.
+    if (arr.length > 1 && arr[1] !== '') {
+        // IT HAS! Check if it is our own persistence redirect.
+        if (window.location.search.indexOf('persistent-table=true') < 1) {
+            // IF NOT: we don't want to redirect the user.
+            saved_list_url = false;
+        }
+    }
+
+    @if($crud->getPersistentTableDuration())
+        var saved_list_url_time = localStorage.getItem('{{ Str::slug($crud->getRoute()) }}_list_url_time');
+
+        if (saved_list_url_time) {
+            var $current_date = new Date();
+            var $saved_time = new Date(parseInt(saved_list_url_time));
+            $saved_time.setMinutes($saved_time.getMinutes() + {{$crud->getPersistentTableDuration()}});
+
+            // if the save time is not expired we force the filter redirection.
+            if($saved_time > $current_date) {
+                if (saved_list_url && persistentUrl!=window.location.href) {
+                    window.location.href = persistentUrl;
+                }
+            } else {
+                // persistent table expired, let's not redirect the user
+                saved_list_url = false;
+            }
+        }
+
+    @endif
+        if (saved_list_url && persistentUrl!=window.location.href) {
+            // finally redirect the user.
+            window.location.href = persistentUrl;
+        }
+    @endif
+
+    window.crud = {
+      exportButtons: JSON.parse('{!! json_encode($crud->get('list.export_buttons')) !!}'),
+      functionsToRunOnDataTablesDrawEvent: [],
+      addFunctionToDataTablesDrawEventQueue: function (functionName) {
+          if (this.functionsToRunOnDataTablesDrawEvent.indexOf(functionName) == -1) {
+          this.functionsToRunOnDataTablesDrawEvent.push(functionName);
+        }
+      },
+      responsiveToggle: function(dt) {
+          $(dt.table().header()).find('th').toggleClass('all');
+          dt.responsive.rebuild();
+          dt.responsive.recalc();
+      },
+      executeFunctionByName: function(str, args) {
+        var arr = str.split('.');
+        var fn = window[ arr[0] ];
+
+        for (var i = 1; i < arr.length; i++)
+        { fn = fn[ arr[i] ]; }
+        fn.apply(window, args);
+      },
+      updateUrl : function (url) {
+        let urlStart = "{{ url($crud->route) }}";
+        let urlEnd = url.replace(urlStart, '');
+        urlEnd = urlEnd.replace('/search', '');
+        let newUrl = urlStart + urlEnd;
+        let tmpUrl = newUrl.split("?")[0],
+        params_arr = [],
+        queryString = (newUrl.indexOf("?") !== -1) ? newUrl.split("?")[1] : false;
+
+        // exclude the persistent-table parameter from url
+        if (queryString !== false) {
+            params_arr = queryString.split("&");
+            for (let i = params_arr.length - 1; i >= 0; i--) {
+                let param = params_arr[i].split("=")[0];
+                if (param === 'persistent-table') {
+                    params_arr.splice(i, 1);
+                }
+            }
+            newUrl = params_arr.length ? tmpUrl + "?" + params_arr.join("&") : tmpUrl;
+        }
+        window.history.pushState({}, '', newUrl);
+        localStorage.setItem('{{ Str::slug($crud->getRoute()) }}_list_url', newUrl);
+      },
+      dataTableConfiguration: {
+        bInfo: {{ var_export($crud->getOperationSetting('showEntryCount') ?? true) }},
+        @if ($crud->getResponsiveTable())
+        responsive: {
+            details: {
+                display: $.fn.dataTable.Responsive.display.modal( {
+                    header: function ( row ) {
+                        // show the content of the first column
+                        // as the modal header
+                        // var data = row.data();
+                        // return data[0];
+                        return '';
+                    }
+                } ),
+                renderer: function ( api, rowIdx, columns ) {
+
+                  var data = $.map( columns, function ( col, i ) {
+                      var columnHeading = crud.table.columns().header()[col.columnIndex];
+
+                      // hide columns that have VisibleInModal false
+                      if ($(columnHeading).attr('data-visible-in-modal') == 'false') {
+                        return '';
+                      }
+
+                      return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
+                                '<td style="vertical-align:top; border:none;"><strong>'+col.title.trim()+':'+'<strong></td> '+
+                                '<td style="padding-left:10px;padding-bottom:10px; border:none;">'+col.data+'</td>'+
+                              '</tr>';
+                  } ).join('');
+
+                  return data ?
+                      $('<table class="table table-striped mb-0">').append( '<tbody>' + data + '</tbody>' ) :
+                      false;
+                },
+            }
+        },
+        fixedHeader: true,
+        @else
+        responsive: false,
+        scrollX: true,
+        @endif
+
+        @if ($crud->getPersistentTable())
+        stateSave: true,
+        /*
+            if developer forced field into table 'visibleInTable => true' we make sure when saving datatables state
+            that it reflects the developer decision.
+        */
+
+        stateSaveParams: function(settings, data) {
+
+            localStorage.setItem('{{ Str::slug($crud->getRoute()) }}_list_url_time', data.time);
+
+            data.columns.forEach(function(item, index) {
+                var columnHeading = crud.table.columns().header()[index];
+                if ($(columnHeading).attr('data-visible-in-table') == 'true') {
+                    return item.visible = true;
+                }
+            });
+        },
+        @if($crud->getPersistentTableDuration())
+        stateLoadParams: function(settings, data) {
+            var $saved_time = new Date(data.time);
+            var $current_date = new Date();
+
+            $saved_time.setMinutes($saved_time.getMinutes() + {{$crud->getPersistentTableDuration()}});
+
+            //if the save time as expired we force datatabled to clear localStorage
+            if($saved_time < $current_date) {
+                if (localStorage.getItem('{{ Str::slug($crud->getRoute())}}_list_url')) {
+                    localStorage.removeItem('{{ Str::slug($crud->getRoute()) }}_list_url');
+                }
+                if (localStorage.getItem('{{ Str::slug($crud->getRoute())}}_list_url_time')) {
+                    localStorage.removeItem('{{ Str::slug($crud->getRoute()) }}_list_url_time');
+                }
+               return false;
+            }
+        },
+        @endif
+        @endif
+        autoWidth: false,
+        pageLength: $dtDefaultPageLength,
+        lengthMenu: @json($crud->getPageLengthMenu()),
+        /* Disable initial sort */
+        aaSorting: [],
+        language: {
+              "emptyTable":     "{{ trans('backpack::crud.emptyTable') }}",
+              "info":           "{{ trans('backpack::crud.info') }}",
+              "infoEmpty":      "{{ trans('backpack::crud.infoEmpty') }}",
+              "infoFiltered":   "{{ trans('backpack::crud.infoFiltered') }}",
+              "infoPostFix":    "{{ trans('backpack::crud.infoPostFix') }}",
+              "thousands":      "{{ trans('backpack::crud.thousands') }}",
+              "lengthMenu":     "{{ trans('backpack::crud.lengthMenu') }}",
+              "loadingRecords": "{{ trans('backpack::crud.loadingRecords') }}",
+              "processing":     "<img src='{{ asset('packages/backpack/base/img/spinner.svg') }}' alt='{{ trans('backpack::crud.processing') }}'>",
+              "search": "_INPUT_",
+              "searchPlaceholder": "{{ trans('backpack::crud.search') }}...",
+              "zeroRecords":    "{{ trans('backpack::crud.zeroRecords') }}",
+              "paginate": {
+                  "first":      "{{ trans('backpack::crud.paginate.first') }}",
+                  "last":       "{{ trans('backpack::crud.paginate.last') }}",
+                  "next":       ">",
+                  "previous":   "<"
+              },
+              "aria": {
+                  "sortAscending":  "{{ trans('backpack::crud.aria.sortAscending') }}",
+                  "sortDescending": "{{ trans('backpack::crud.aria.sortDescending') }}"
+              },
+              "buttons": {
+                  "copy":   "{{ trans('backpack::crud.export.copy') }}",
+                  "excel":  "{{ trans('backpack::crud.export.excel') }}",
+                  "csv":    "{{ trans('backpack::crud.export.csv') }}",
+                  "pdf":    "{{ trans('backpack::crud.export.pdf') }}",
+                  "print":  "{{ trans('backpack::crud.export.print') }}",
+                  "colvis": "{{ trans('backpack::crud.export.column_visibility') }}"
+              },
+          },
+          processing: true,
+          serverSide: true,
+          @if($crud->getOperationSetting('showEntryCount') === false)
+            pagingType: "simple",
+          @endif
+          searching: @json($crud->getOperationSetting('searchableTable') ?? true),
+          ajax: {
+              "url": "{!! url($crud->route.'/search').'?'.Request::getQueryString() !!}",
+              "type": "POST",
+              "data": {
+                "totalEntryCount": "{{$crud->getOperationSetting('totalEntryCount') ?? false}}"
+            },
+          },
+          dom:
+            "<'row hidden'<'col-sm-6'i><'col-sm-6 d-print-none'f>>" +
+            "<'row'<'col-sm-12'tr>>" +
+            "<'row mt-2 d-print-none '<'col-sm-12 col-md-4'l><'col-sm-0 col-md-4 text-center'B><'col-sm-12 col-md-4 'p>>",
+      }
+  }
+  </script>
+  @include('crud::inc.export_buttons')
+
+  <script type="text/javascript">
+    jQuery(document).ready(function($) {
+
+      window.crud.table = $("#crudTable").DataTable(window.crud.dataTableConfiguration);
+
+      window.crud.updateUrl(location.href);
+
+      // move search bar
+      $("#crudTable_filter").appendTo($('#datatable_search_stack' ));
+      $("#crudTable_filter input").removeClass('form-control-sm');
+
+      // move "showing x out of y" info to header
+      @if($crud->getSubheading())
+      $('#crudTable_info').hide();
+      @else
+      $("#datatable_info_stack").html($('#crudTable_info')).css('display','inline-flex').addClass('animated fadeIn');
+      @endif
+
+      @if($crud->getOperationSetting('resetButton') ?? true)
+        // create the reset button
+        var crudTableResetButton = '<a href="{{url($crud->route)}}" class="ml-1" id="crudTable_reset_button">{{ trans('backpack::crud.reset') }}</a>';
+
+        $('#datatable_info_stack').append(crudTableResetButton);
+
+          // when clicking in reset button we clear the localStorage for datatables.
+        $('#crudTable_reset_button').on('click', function() {
+
+          //clear the filters
+          if (localStorage.getItem('{{ Str::slug($crud->getRoute())}}_list_url')) {
+              localStorage.removeItem('{{ Str::slug($crud->getRoute()) }}_list_url');
+          }
+          if (localStorage.getItem('{{ Str::slug($crud->getRoute())}}_list_url_time')) {
+              localStorage.removeItem('{{ Str::slug($crud->getRoute()) }}_list_url_time');
+          }
+
+          //clear the table sorting/ordering/visibility
+          if(localStorage.getItem('DataTables_crudTable_/{{ $crud->getRoute() }}')) {
+              localStorage.removeItem('DataTables_crudTable_/{{ $crud->getRoute() }}');
+          }
+        });
+      @endif
+
+      // move the bottom buttons before pagination
+      $("#bottom_buttons").insertBefore($('#crudTable_wrapper .row:last-child' ));
+
+      // override ajax error message
+      $.fn.dataTable.ext.errMode = 'none';
+      $('#crudTable').on('error.dt', function(e, settings, techNote, message) {
+          new Noty({
+              type: "error",
+              text: "<strong>{{ trans('backpack::crud.ajax_error_title') }}</strong><br>{{ trans('backpack::crud.ajax_error_text') }}"
+          }).show();
+      });
+
+        // when changing page length in datatables, save it into localStorage
+        // so in next requests we know if the length changed by user
+        // or by developer in the controller.
+        $('#crudTable').on( 'length.dt', function ( e, settings, len ) {
+            localStorage.setItem('DataTables_crudTable_/{{$crud->getRoute()}}_pageLength', len);
+        });
+
+        // make sure AJAX requests include XSRF token
+        $.ajaxPrefilter(function(options, originalOptions, xhr) {
+            var token = $('meta[name="csrf_token"]').attr('content');
+
+            if (token) {
+                return xhr.setRequestHeader('X-XSRF-TOKEN', token);
+            }
+        });
+
+
+        $('#crudTable').on( 'page.dt', function () {
+            localStorage.setItem('page_changed', true);
+        });
+
+      // on DataTable draw event run all functions in the queue
+      // (eg. delete and details_row buttons add functions to this queue)
+      $('#crudTable').on( 'draw.dt',   function () {
+         crud.functionsToRunOnDataTablesDrawEvent.forEach(function(functionName) {
+            crud.executeFunctionByName(functionName);
+         });
+         if ($('#crudTable').data('has-line-buttons-as-dropdown')) {
+          formatActionColumnAsDropdown();
+         }
+      }).dataTable();
+
+      // when datatables-colvis (column visibility) is toggled
+      // rebuild the datatable using the datatable-responsive plugin
+      $('#crudTable').on( 'column-visibility.dt',   function (event) {
+         crud.table.responsive.rebuild();
+      } ).dataTable();
+
+      @if ($crud->getResponsiveTable())
+        // when columns are hidden by reponsive plugin,
+        // the table should have the has-hidden-columns class
+        crud.table.on( 'responsive-resize', function ( e, datatable, columns ) {
+            if (crud.table.responsive.hasHidden()) {
+              $("#crudTable").removeClass('has-hidden-columns').addClass('has-hidden-columns');
+             } else {
+              $("#crudTable").removeClass('has-hidden-columns');
+             }
+        } );
+      @else
+        // make sure the column headings have the same width as the actual columns
+        // after the user manually resizes the window
+        var resizeTimer;
+        function resizeCrudTableColumnWidths() {
+          clearTimeout(resizeTimer);
+          resizeTimer = setTimeout(function() {
+            // Run code here, resizing has "stopped"
+            crud.table.columns.adjust();
+          }, 250);
+        }
+        $(window).on('resize', function(e) {
+          resizeCrudTableColumnWidths();
+        });
+        $('.sidebar-toggler').click(function() {
+          resizeCrudTableColumnWidths();
+        });
+      @endif
+
+    });
+
+    function formatActionColumnAsDropdown() {
+        // Get action column
+        const actionColumnIndex = $('#crudTable').find('th[data-action-column=true]').index();
+        if (actionColumnIndex !== -1) {
+            $('#crudTable tr').each(function (i, tr) {
+                const actionCell = $(tr).find('td').eq(actionColumnIndex);
+                const actionButtons = $(actionCell).find('a.btn.btn-link');
+                // Wrap the cell with the component needed for the dropdown
+                actionCell.wrapInner('<div class="nav-item dropdown"></div>');
+                actionCell.wrapInner('<div class="dropdown-menu dropdown-menu-left"></div>');
+                // Prepare buttons as dropdown items
+                actionButtons.map((index, action) => {
+                    $(action).addClass('dropdown-item').removeClass('btn btn-sm btn-link');
+                    $(action).find('i').addClass('me-2 text-primary');
+                });
+                actionCell.prepend('<a class="btn btn-sm px-2 py-1 btn-outline-primary dropdown-toggle actions-buttons-column" href="#" data-toggle="dropdown" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">{{ trans('backpack::crud.actions') }}</a>');
+            });
+        }
+    }
+  </script>
+
+  @include('crud::inc.details_row_logic')
diff --git a/resources/views/vendor/backpack/crud/inc/details_row_logic.blade.php b/resources/views/vendor/backpack/crud/inc/details_row_logic.blade.php
new file mode 100644 (file)
index 0000000..f335e57
--- /dev/null
@@ -0,0 +1,56 @@
+  @if ($crud->get('list.detailsRow'))
+  <script>
+    if (typeof registerDetailsRowButtonAction != 'function') {
+      function registerDetailsRowButtonAction() {
+            // Remove any previously registered event handlers from draw.dt event callback
+            $('#crudTable tbody').off('click', 'td .details-row-button');
+
+            // Make sure the ajaxDatatables rows also have the correct classes
+            $('#crudTable tbody td .details-row-button').parent('td')
+              .removeClass('details-control').addClass('details-control')
+              .removeClass('text-center').addClass('text-center')
+              .removeClass('cursor-pointer').addClass('cursor-pointer');
+
+            // Add event listener for opening and closing details
+            $('#crudTable tbody td .details-control').on('click', function (e) {
+              e.stopPropagation();
+
+                var tr = $(this).closest('tr');
+                var btn = $(this).find('.details-row-button');
+                var row = crud.table.row( tr );
+
+                if (row.child.isShown()) {
+                    // This row is already open - close it
+                    btn.removeClass('la-minus-square-o').addClass('la-plus-square-o');
+                    $('div.table_row_slider', row.child()).slideUp( function () {
+                        row.child.hide();
+                        tr.removeClass('shown');
+                    } );
+                } else {
+                    // Open this row
+                    btn.removeClass('la-plus-square-o').addClass('la-minus-square-o');
+                    // Get the details with ajax
+                    $.ajax({
+                      url: '{{ url($crud->route) }}/'+btn.data('entry-id')+'/details',
+                      type: 'GET',
+                    })
+                    .done(function(data) {
+                      row.child("<div class='table_row_slider'>" + data + "</div>", 'no-padding').show();
+                      tr.addClass('shown');
+                      $('div.table_row_slider', row.child()).slideDown();
+                    })
+                    .fail(function(data) {
+                      row.child("<div class='table_row_slider'>{{ trans('backpack::crud.details_row_loading_error') }}</div>").show();
+                      tr.addClass('shown');
+                      $('div.table_row_slider', row.child()).slideDown();
+                    });
+                }
+            } );
+          }
+      }
+
+    // make it so that the function above is run after each DataTable draw event
+    // otherwise details_row buttons wouldn't work on subsequent pages (page 2, page 17, etc)
+    crud.addFunctionToDataTablesDrawEventQueue('registerDetailsRowButtonAction');
+  </script>
+@endif
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/inc/export_buttons.blade.php b/resources/views/vendor/backpack/crud/inc/export_buttons.blade.php
new file mode 100644 (file)
index 0000000..4ad9567
--- /dev/null
@@ -0,0 +1,154 @@
+@if ($crud->exportButtons())
+  <script src="https://cdn.datatables.net/buttons/1.5.6/js/dataTables.buttons.min.js" type="text/javascript"></script>
+  <script src="https://cdn.datatables.net/buttons/1.5.6/js/buttons.bootstrap4.min.js" type="text/javascript"></script>
+  <script src="//cdnjs.cloudflare.com/ajax/libs/jszip/2.5.0/jszip.min.js" type="text/javascript"></script>
+  <script src="//cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.18/pdfmake.min.js" type="text/javascript"></script>
+  <script src="//cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.18/vfs_fonts.js" type="text/javascript"></script>
+  <script src="//cdn.datatables.net/buttons/1.5.6/js/buttons.html5.min.js" type="text/javascript"></script>
+  <script src="//cdn.datatables.net/buttons/1.5.6/js/buttons.print.min.js" type="text/javascript"></script>
+  <script src="//cdn.datatables.net/buttons/1.5.6/js/buttons.colVis.min.js" type="text/javascript"></script>
+  <script>
+    let dataTablesExportStrip = text => {
+        if ( typeof text !== 'string' ) {
+            return text;
+        }
+
+        return text
+            .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
+            .replace(/<!\-\-.*?\-\->/g, '')
+            .replace(/<[^>]*>/g, '')
+            .replace(/^\s+|\s+$/g, '')
+            .replace(/\s+([,.;:!\?])/g, '$1')
+            .replace(/\s+/g, ' ')
+            .replace(/[\n|\r]/g, ' ');
+    };
+
+    let dataTablesExportFormat = {
+        body: (data, row, column, node) => 
+            node.querySelector('input[type*="text"]')?.value ??
+            node.querySelector('input[type*="checkbox"]:not(.crud_bulk_actions_line_checkbox)')?.checked ??
+            node.querySelector('select')?.selectedOptions[0]?.value ??
+            dataTablesExportStrip(data),
+    };
+
+    window.crud.dataTableConfiguration.buttons = [
+        @if($crud->get('list.showExportButton'))
+        {
+            extend: 'collection',
+            text: '<i class="la la-download"></i> {{ trans('backpack::crud.export.export') }}',
+            dropup: true,
+            buttons: [
+                {
+                    name: 'copyHtml5',
+                    extend: 'copyHtml5',
+                    exportOptions: {
+                        columns: function ( idx, data, node ) {
+                            var $column = crud.table.column( idx );
+                                return  ($column.visible() && $(node).attr('data-visible-in-export') != 'false') || $(node).attr('data-force-export') == 'true';
+                        },
+                        format: dataTablesExportFormat,
+                    },
+                    action: function(e, dt, button, config) {
+                        crud.responsiveToggle(dt);
+                        $.fn.DataTable.ext.buttons.copyHtml5.action.call(this, e, dt, button, config);
+                        crud.responsiveToggle(dt);
+                    }
+                },
+                {
+                    name: 'excelHtml5',
+                    extend: 'excelHtml5',
+                    exportOptions: {
+                        columns: function ( idx, data, node ) {
+                            var $column = crud.table.column( idx );
+                                return  ($column.visible() && $(node).attr('data-visible-in-export') != 'false') || $(node).attr('data-force-export') == 'true';
+                        },
+                        format: dataTablesExportFormat,
+                    },
+                    action: function(e, dt, button, config) {
+                        crud.responsiveToggle(dt);
+                        $.fn.DataTable.ext.buttons.excelHtml5.action.call(this, e, dt, button, config);
+                        crud.responsiveToggle(dt);
+                    }
+                },
+                {
+                    name: 'csvHtml5',
+                    extend: 'csvHtml5',
+                    exportOptions: {
+                        columns: function ( idx, data, node ) {
+                            var $column = crud.table.column( idx );
+                                return  ($column.visible() && $(node).attr('data-visible-in-export') != 'false') || $(node).attr('data-force-export') == 'true';
+                        },
+                        format: dataTablesExportFormat,
+                    },
+                    action: function(e, dt, button, config) {
+                        crud.responsiveToggle(dt);
+                        $.fn.DataTable.ext.buttons.csvHtml5.action.call(this, e, dt, button, config);
+                        crud.responsiveToggle(dt);
+                    }
+                },
+                {
+                    name: 'pdfHtml5',
+                    extend: 'pdfHtml5',
+                    exportOptions: {
+                        columns: function ( idx, data, node ) {
+                            var $column = crud.table.column( idx );
+                                return  ($column.visible() && $(node).attr('data-visible-in-export') != 'false') || $(node).attr('data-force-export') == 'true';
+                        },
+                        format: dataTablesExportFormat,
+                    },
+                    orientation: 'landscape',
+                    action: function(e, dt, button, config) {
+                        crud.responsiveToggle(dt);
+                        $.fn.DataTable.ext.buttons.pdfHtml5.action.call(this, e, dt, button, config);
+                        crud.responsiveToggle(dt);
+                    }
+                },
+                {
+                    name: 'print',
+                    extend: 'print',
+                    exportOptions: {
+                        columns: function ( idx, data, node ) {
+                            var $column = crud.table.column( idx );
+                                return  ($column.visible() && $(node).attr('data-visible-in-export') != 'false') || $(node).attr('data-force-export') == 'true';
+                        },
+                        format: dataTablesExportFormat,
+                    },
+                    action: function(e, dt, button, config) {
+                        crud.responsiveToggle(dt);
+                        $.fn.DataTable.ext.buttons.print.action.call(this, e, dt, button, config);
+                        crud.responsiveToggle(dt);
+                    }
+                }
+            ]
+        }
+        @endif
+        @if($crud->get('list.showTableColumnPicker'))
+        ,{
+            extend: 'colvis',
+            text: '<i class="la la-eye-slash"></i> {{ trans('backpack::crud.export.column_visibility') }}',
+            columns: function ( idx, data, node ) {
+                return $(node).attr('data-visible-in-table') == 'false' && $(node).attr('data-can-be-visible-in-table') == 'true';
+            },
+            dropup: true
+        }
+        @endif
+    ];
+
+    // move the datatable buttons in the top-right corner and make them smaller
+    function moveExportButtonsToTopRight() {
+      crud.table.buttons().each(function(button) {
+        if (button.node.className.indexOf('buttons-columnVisibility') == -1 && button.node.nodeName=='BUTTON')
+        {
+          button.node.className = button.node.className + " btn-sm";
+        }
+      })
+      $(".dt-buttons").appendTo($('#datatable_button_stack' ));
+      $('.dt-buttons').addClass('d-xs-block')
+                      .addClass('d-sm-inline-block')
+                      .addClass('d-md-inline-block')
+                      .addClass('d-lg-inline-block');
+    }
+
+    crud.addFunctionToDataTablesDrawEventQueue('moveExportButtonsToTopRight');
+  </script>
+@endif
diff --git a/resources/views/vendor/backpack/crud/inc/filters_navbar.blade.php b/resources/views/vendor/backpack/crud/inc/filters_navbar.blade.php
new file mode 100644 (file)
index 0000000..f3f5f4f
--- /dev/null
@@ -0,0 +1,109 @@
+<nav class="navbar navbar-expand-lg navbar-filters mb-0 pb-0 pt-0">
+      {{-- Brand and toggle get grouped for better mobile display --}}
+      <a class="nav-item d-none d-lg-block"><span class="la la-filter"></span></a>
+      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#bp-filters-navbar" aria-controls="bp-filters-navbar" aria-expanded="false" aria-label="{{ trans('backpack::crud.toggle_filters') }}">
+        <span class="la la-filter"></span> {{ trans('backpack::crud.filters') }}
+      </button>
+
+      {{-- Collect the nav links, forms, and other content for toggling --}}
+      <div class="collapse navbar-collapse" id="bp-filters-navbar">
+        <ul class="nav navbar-nav">
+          {{-- THE ACTUAL FILTERS --}}
+                       @foreach ($crud->filters() as $filter)
+                               @includeFirst($filter->getNamespacedViewWithFallbacks())
+                       @endforeach
+          <li class="nav-item"><a href="#" id="remove_filters_button" class="nav-link {{ count(Request::input()) != 0 ? '' : 'invisible' }}"><i class="la la-eraser"></i> {{ trans('backpack::crud.remove_filters') }}</a></li>
+        </ul>
+      </div>{{-- /.navbar-collapse --}}
+  </nav>
+
+@push('crud_list_scripts')
+       <script src="{{ asset('packages/URI.js/URI.min.js') }}" type="text/javascript"></script>
+    <script>
+      function addOrUpdateUriParameter(uri, parameter, value) {
+            var new_url = normalizeAmpersand(uri);
+
+            new_url = URI(new_url).normalizeQuery();
+
+            // this param is only needed in datatables persistent url redirector
+            // not when applying filters so we remove it.
+            if (new_url.hasQuery('persistent-table')) {
+                new_url.removeQuery('persistent-table');
+            }
+
+            if (new_url.hasQuery(parameter)) {
+              new_url.removeQuery(parameter);
+            }
+
+            if (value !== '' && value != null) {
+              new_url = new_url.addQuery(parameter, value);
+            }
+
+            $('#remove_filters_button').toggleClass('invisible', !new_url.query());
+
+        return new_url.toString();
+
+      }
+
+      function updateDatatablesOnFilterChange(filterName, filterValue, update_url = false) {
+        // behaviour for ajax table
+        var current_url = crud.table.ajax.url();
+        var new_url = addOrUpdateUriParameter(current_url, filterName, filterValue);
+
+        new_url = normalizeAmpersand(new_url);
+
+        // add filter to URL
+        crud.updateUrl(new_url);
+        crud.table.ajax.url(new_url);
+
+        // when we are clearing ALL filters, we would not update the table url here, because this is done PER filter
+        // and we have a function that will do this update for us after all filters had been cleared.
+        if(update_url) {
+          // replace the datatables ajax url with new_url and reload it
+          crud.table.ajax.url(new_url).load();
+        }
+
+        return new_url;
+      }
+
+
+      function normalizeAmpersand(string) {
+        return string.replace(/&amp;/g, "&").replace(/amp%3B/g, "");
+      }
+
+      // button to remove all filters
+      jQuery(document).ready(function($) {
+       $("#remove_filters_button").click(function(e) {
+               e.preventDefault();
+
+                       // behaviour for ajax table
+                       var new_url = '{{ url($crud->route.'/search') }}';
+                       var ajax_table = $("#crudTable").DataTable();
+
+                               // replace the datatables ajax url with new_url and reload it
+                               ajax_table.ajax.url(new_url).load();
+
+                               // clear all filters
+                               $(".navbar-filters li[filter-name]").trigger('filter:clear');
+
+          // remove filters from URL
+          crud.updateUrl(new_url);
+       });
+
+        // hide the Remove filters button when no filter is active
+        $(".navbar-filters li[filter-name]").on('filter:clear', function() {
+          var anyActiveFilters = false;
+          $(".navbar-filters li[filter-name]").each(function () {
+            if ($(this).hasClass('active')) {
+              anyActiveFilters = true;
+              // console.log('ACTIVE FILTER');
+            }
+          });
+
+          if (anyActiveFilters == false) {
+            $('#remove_filters_button').addClass('invisible');
+          }
+        });
+      });
+    </script>
+@endpush
diff --git a/resources/views/vendor/backpack/crud/inc/form_fields_script.blade.php b/resources/views/vendor/backpack/crud/inc/form_fields_script.blade.php
new file mode 100644 (file)
index 0000000..adb4d46
--- /dev/null
@@ -0,0 +1,188 @@
+<script>
+    /**
+     * A front-end representation of a Backpack field, with its main components.
+     *
+     * Makes it dead-simple for the developer to perform the most common
+     * javascript manipulations, and makes it easy to do custom stuff
+     * too, by exposing the main components (name, wrapper, input).
+     */
+    class CrudField {
+        constructor(name) {
+            this.name = name;
+            // get the current input
+            this.$input = this.activeInput;
+            // get the field wraper
+            this.wrapper = this.inputWrapper;
+
+            // in case `bp-field-main-input` is specified on a field input, use that one as input
+            this.$input = this.mainInput;
+
+            // Validate that the wrapper has been found
+            if (this.wrapper.length === 0) {
+                console.error(`CrudField error! Could not select WRAPPER for "${this.name}"`);
+            }
+
+            // Validate that the field has been found
+            if(this.$input.length === 0) {
+                console.error(`CrudField error! Could not select INPUT for "${this.name}"`);
+            }
+
+            this.input = this.$input[0];
+            this.type = this.wrapper.attr('bp-field-type');
+
+            return this;
+
+        }
+
+        get activeInput() {
+            // get the input/textarea/select that has that field name
+            this.$input = $(`input[name="${this.name}"], textarea[name="${this.name}"], select[name="${this.name}"], select[name="${this.name}[]"]`);
+            let possibleInput = this.$input.length === 1 ? this.$input : this.$input.filter(function() { return $(this).closest('[id=inline-create-dialog]').length });
+            return possibleInput.length === 1 ? possibleInput : this.$input.first();
+        }
+
+        get mainInput() {
+            let input = this.wrapper.find('[bp-field-main-input]').first();
+
+            // if a bp-field-main-input has been specified by developer, that's it, use that one
+            if (input.length !== 0) {
+                return input;
+            }
+
+            // otherwise, try to find the input using other selectors
+            if (this.$input.length === 0) {
+                // try searching for the field with the corresponding bp-field-name
+                input = this.wrapper.find(`input[bp-field-name="${this.name}"], textarea[bp-field-name="${this.name}"], select[bp-field-name="${this.name}"], select[bp-field-name="${this.name}[]"]`).first();
+
+                // if not input found yet, just get the first input in that wrapper
+                if (input.length === 0) {
+                    input = this.wrapper.find('input, textarea, select').first();
+                }
+
+                return input;
+            }
+
+            return this.$input;
+
+        }
+
+        get value() {
+            return this.$input.val();
+        }
+
+        get inputWrapper() {
+            let wrapper = this.$input.closest('[bp-field-wrapper]');
+            if (wrapper.length === 0) {
+                wrapper = $(`[bp-field-name="${this.name}"][bp-field-wrapper]`).first();
+            }
+            return wrapper;
+        }
+
+        onChange(closure) {
+            const bindedClosure = closure.bind(this);
+            const fieldChanged = (event, values) => bindedClosure(this, event, values);
+
+            if(this.isSubfield) {
+                window.crud.subfieldsCallbacks[this.parent.name] ??= [];
+                window.crud.subfieldsCallbacks[this.parent.name].push({ closure, field: this });
+                this.wrapper.trigger('CrudField:subfieldCallbacksUpdated');
+                return this;
+            }
+
+            if(['INPUT', 'TEXTAREA'].includes(this.input?.nodeName)) {
+                this.input?.addEventListener('input', fieldChanged, false);
+            }
+            this.$input.change(fieldChanged);
+
+            return this;
+        }
+
+        change() {
+            if(this.isSubfield) {
+                window.crud.subfieldsCallbacks[this.parent.name]?.forEach(callback => callback.triggerChange = true);
+            } else {
+                this.$input.trigger('change');
+            }
+
+            return this;
+        }
+
+        show(value = true) {
+            this.wrapper.toggleClass('d-none', !value);
+            this.$input.trigger(`CrudField:${value ? 'show' : 'hide'}`);
+            return this;
+        }
+
+        hide(value = true) {
+            return this.show(!value);
+        }
+
+        enable(value = true) {
+            this.$input.attr('disabled', !value && 'disabled');
+            this.$input.trigger(`CrudField:${value ? 'enable' : 'disable'}`);
+            return this;
+        }
+
+        disable(value = true) {
+            return this.enable(!value);
+        }
+
+        require(value = true) {
+            this.wrapper.toggleClass('required', value);
+            this.$input.trigger(`CrudField:${value ? 'require' : 'unrequire'}`);
+            return this;
+        }
+
+        unrequire(value = true) {
+            return this.require(!value);
+        }
+
+        check(value = true) {
+            this.wrapper.find('input[type=checkbox]').prop('checked', value).trigger('change');
+            return this;
+        }
+
+        uncheck(value = true) {
+            return this.check(!value);
+        }
+
+        subfield(name, rowNumber = false) {
+            let subfield = new CrudField(this.name);
+            subfield.name = name;
+
+            if(!rowNumber) {
+                subfield.isSubfield = true;
+                subfield.subfieldHolder = this.name; // deprecated
+                subfield.parent = this;
+            } else {
+                subfield.rowNumber = rowNumber;
+                subfield.wrapper = $(`[data-repeatable-identifier="${this.name}"][data-row-number="${rowNumber}"]`).find(`[bp-field-wrapper][bp-field-name$="${name}"]`);
+                subfield.$input = subfield.wrapper.find(`[data-repeatable-input-name$="${name}"][bp-field-main-input]`);
+                // if no bp-field-main-input has been declared in the field itself,
+                // assume it's the first input in that wrapper, whatever it is
+                if (subfield.$input.length == 0) {
+                    subfield.$input = subfield.wrapper.find(`input[data-repeatable-input-name$="${name}"], textarea[data-repeatable-input-name$="${name}"], select[data-repeatable-input-name$="${name}"]`).first();
+                }
+
+                subfield.input = subfield.$input[0];
+            }
+            return subfield;
+        }
+    }
+
+    /**
+     * Window functions that help the developer easily select one or more fields.
+     */
+    window.crud = {
+        ...window.crud,
+
+        // Subfields callbacks holder
+        subfieldsCallbacks: [],
+
+        // Create a field from a given name
+        field: name => new CrudField(name),
+
+        // Create all fields from a given name list
+        fields: names => names.map(window.crud.field),
+    };
+</script>
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/inc/form_save_buttons.blade.php b/resources/views/vendor/backpack/crud/inc/form_save_buttons.blade.php
new file mode 100644 (file)
index 0000000..1eaee4b
--- /dev/null
@@ -0,0 +1,189 @@
+@if(isset($saveAction['active']) && !is_null($saveAction['active']['value']))
+    <div id="saveActions" class="form-group">
+
+        <input type="hidden" name="_save_action" value="{{ $saveAction['active']['value'] }}">
+        @if(!empty($saveAction['options']))
+            <div class="btn-group" role="group">
+        @endif
+
+        <button type="submit" class="btn btn-success">
+            <span class="la la-save" role="presentation" aria-hidden="true"></span> &nbsp;
+            <span data-value="{{ $saveAction['active']['value'] }}">{{ $saveAction['active']['label'] }}</span>
+        </button>
+
+        <div class="btn-group" role="group">
+            @if(!empty($saveAction['options']))
+                <button id="bpSaveButtonsGroup" type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="caret"></span><span class="sr-only">&#x25BC;</span></button>
+                <div class="dropdown-menu" aria-labelledby="bpSaveButtonsGroup">
+                @foreach( $saveAction['options'] as $value => $label)
+                    <button type="button" class="dropdown-item" data-value="{{ $value }}">{{$label}}</button>
+                @endforeach
+                </div>
+            @endif
+        </div>
+
+        @if(!empty($saveAction['options']))
+            </div>
+        @endif
+
+        @if(!$crud->hasOperationSetting('showCancelButton') || $crud->getOperationSetting('showCancelButton') == true)
+            <a href="{{ $crud->hasAccess('list') ? url($crud->route) : url()->previous() }}" class="btn btn-default"><span class="la la-ban"></span> &nbsp;{{ trans('backpack::crud.cancel') }}</a>
+        @endif
+
+        @if ($crud->get('update.showDeleteButton') && $crud->get('delete.configuration') && $crud->hasAccess('delete'))
+            <button onclick="confirmAndDeleteEntry()" type="button" class="btn btn-danger float-right"><i class="la la-trash-alt"></i> {{ trans('backpack::crud.delete') }}</button>
+        @endif
+    </div>
+@endif
+
+@push('after_scripts')
+<script>
+
+    // this function checks if form is valid.
+    function checkFormValidity(form) {
+        // the condition checks if `checkValidity` is defined in the form (browser compatibility)
+        if (form[0].checkValidity) {
+            return form[0].checkValidity();
+        }
+        return false;
+    }
+
+    // this function checks if any of the inputs has errors and report them on page.
+    // we use it to report the errors after form validation fails and making the error fields visible
+    function reportValidity(form) {
+        // the condition checks if `reportValidity` is defined in the form (browser compatibility)
+        if (form[0].reportValidity) {
+            // hide the save actions drop down if open
+            $('#saveActions').find('.dropdown-menu').removeClass('show');
+            // validate and display form errors
+            form[0].reportValidity();
+        }
+    }
+
+    function changeTabIfNeededAndDisplayErrors(form) {
+        // we get the first erroed field
+        var $firstErrorField = form.find(":invalid").first();
+        // we find the closest tab
+        var $closestTab = $($firstErrorField).closest('.tab-pane');
+        // if we found the tab we will change to that tab before reporting validity of form
+        if($closestTab.length) {
+            var id = $closestTab.attr('id');
+                // switch tabs
+                $('.nav a[href="#' + id + '"]').tab('show');
+        }
+        reportValidity(form);
+    }
+
+    // make all submit buttons trigger HTML5 validation
+    jQuery(document).ready(function($) {
+
+        var selector = $('#bpSaveButtonsGroup').next();
+        var form = $(selector).closest('form');
+        var saveActionField = $('[name="_save_action"]');
+        var $defaultSubmitButton = $(form).find(':submit');
+        // this is the main submit button, the default save action.
+        $($defaultSubmitButton).on('click', function(e) {
+            e.preventDefault();
+            $saveAction = $(this).children('span').eq(1);
+            // if form is valid just submit it
+            if(checkFormValidity(form)) {
+                saveActionField.val( $saveAction.attr('data-value') );
+                form[0].requestSubmit();
+            }else{
+                // navigate to the tab where the first error happens 
+                changeTabIfNeededAndDisplayErrors(form);
+            }
+        });
+
+        //this is for the anchors AKA other non-default save actions.
+        $(selector).find('button').each(function() {
+            $(this).click(function(e) {
+                //we check if form is valid
+                if (checkFormValidity(form)) {
+                    //if everything is validated we proceed with the submission
+                    var saveAction = $(this).data('value');
+                    saveActionField.val( saveAction );
+                    form[0].requestSubmit();
+                }else{
+                    // navigate to the tab where the first error happens 
+                    changeTabIfNeededAndDisplayErrors(form);
+                }
+                e.stopPropagation();
+            });
+        });
+    });
+
+</script>
+
+@if ($crud->get('update.showDeleteButton') && $crud->get('delete.configuration') && $crud->hasAccess('delete'))
+<script>
+    function confirmAndDeleteEntry() {
+        // Ask for confirmation before deleting an item
+        swal({
+            title: "{!! trans('backpack::base.warning') !!}",
+            text: "{!! trans('backpack::crud.delete_confirm') !!}",
+            icon: "warning",
+            buttons: ["{!! trans('backpack::crud.cancel') !!}", "{!! trans('backpack::crud.delete') !!}"],
+            dangerMode: true,
+        }).then((value) => {
+            if (value) {
+                $.ajax({
+                    url: '{{ url($crud->route.'/'.$entry->getKey()) }}',
+                    type: 'DELETE',
+                    success: function(result) {
+                        if (result !== '1') {
+                            // if the result is an array, it means
+                            // we have notification bubbles to show
+                            if (result instanceof Object) {
+                                // trigger one or more bubble notifications
+                                Object.entries(result).forEach(function(entry) {
+                                    var type = entry[0];
+                                    entry[1].forEach(function(message, i) {
+                                        new Noty({
+                                            type: type,
+                                            text: message
+                                        }).show();
+                                    });
+                                });
+                            } else { // Show an error alert
+                                swal({
+                                    title: "{!! trans('backpack::crud.delete_confirmation_not_title') !!}",
+                                    text: "{!! trans('backpack::crud.delete_confirmation_not_message') !!}",
+                                    icon: "error",
+                                    timer: 4000,
+                                    buttons: false,
+                                });
+                            }
+                        }
+                        // All is good, show a success message!
+                        swal({
+                            title: "{!! trans('backpack::crud.delete_confirmation_title') !!}",
+                            text: "{!! trans('backpack::crud.delete_confirmation_message') !!}",
+                            icon: "success",
+                            buttons: false,
+                            closeOnClickOutside: false,
+                            closeOnEsc: false,
+                        });
+
+                        // Redirect in 1 sec so that admins get to see the success message
+                        setTimeout(function () {
+                            window.location.href = '{{ is_bool($crud->get('update.showDeleteButton')) ? url($crud->route) : (string) $crud->get('update.showDeleteButton') }}';
+                        }, 1000);
+                    },
+                    error: function() {
+                        // Show an alert with the result
+                        swal({
+                            title: "{!! trans('backpack::crud.delete_confirmation_not_title') !!}",
+                            text: "{!! trans('backpack::crud.delete_confirmation_not_message') !!}",
+                            icon: "error",
+                            timer: 4000,
+                            buttons: false,
+                        });
+                    }
+                });
+            }
+        });
+    }
+</script>
+@endif
+@endpush
diff --git a/resources/views/vendor/backpack/crud/inc/grouped_errors.blade.php b/resources/views/vendor/backpack/crud/inc/grouped_errors.blade.php
new file mode 100644 (file)
index 0000000..139cf9d
--- /dev/null
@@ -0,0 +1,14 @@
+{{-- Show the errors, if any --}}
+@if ($crud->groupedErrorsEnabled() && session()->get('errors'))
+    <div class="alert alert-danger pb-0">
+        <ul class="list-unstyled">
+            @foreach(session()->get('errors')->getBags() as $bag => $errorMessages)
+                @foreach($errorMessages->getMessages() as $errorMessageForInput)
+                    @foreach($errorMessageForInput as $message)
+                        <li><i class="la la-info-circle"></i> {{ $message }}</li>
+                    @endforeach
+                @endforeach
+            @endforeach
+        </ul>
+    </div>
+@endif
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/inc/show_fields.blade.php b/resources/views/vendor/backpack/crud/inc/show_fields.blade.php
new file mode 100644 (file)
index 0000000..74a05da
--- /dev/null
@@ -0,0 +1,5 @@
+{{-- Show the inputs --}}
+@foreach ($fields as $field)
+    @include($crud->getFirstFieldView($field['type'], $field['view_namespace'] ?? false), $field)
+@endforeach
+
diff --git a/resources/views/vendor/backpack/crud/inc/show_tabbed_fields.blade.php b/resources/views/vendor/backpack/crud/inc/show_tabbed_fields.blade.php
new file mode 100644 (file)
index 0000000..a1439b8
--- /dev/null
@@ -0,0 +1,86 @@
+@php
+    $horizontalTabs = $crud->getTabsType()=='horizontal' ? true : false;
+    $tabWithError = (function() use ($crud) {
+        if(! session()->get('errors')) {
+            return false;
+        }
+        foreach(session()->get('errors')->getBags() as $bag => $errorMessages) {
+            foreach($errorMessages->getMessages() as $fieldName => $messages) {
+                if(array_key_exists($fieldName, $crud->getCurrentFields()) && array_key_exists('tab', $crud->getCurrentFields()[$fieldName])) {
+                    return $crud->getCurrentFields()[$fieldName]['tab'];
+                }
+            }
+        }
+        return false;
+    })();
+@endphp
+
+@if ($crud->getFieldsWithoutATab()->filter(function ($value, $key) { return $value['type'] != 'hidden'; })->count())
+<div class="card">
+    <div class="card-body row">
+    @include('crud::inc.show_fields', ['fields' => $crud->getFieldsWithoutATab()])
+    </div>
+</div>
+@else
+    @include('crud::inc.show_fields', ['fields' => $crud->getFieldsWithoutATab()])
+@endif
+
+<div class="tab-container {{ $horizontalTabs ? '' : 'container'}} mb-2">
+
+    <div class="nav-tabs-custom {{ $horizontalTabs ? '' : 'row'}}" id="form_tabs">
+        <ul class="nav {{ $horizontalTabs ? 'nav-tabs' : 'flex-column nav-pills'}} {{ $horizontalTabs ? '' : 'col-md-3' }}" role="tablist">
+            @foreach ($crud->getTabs() as $k => $tab)
+                <li role="presentation" class="nav-item">
+                    <a href="#tab_{{ Str::slug($tab) }}"
+                        aria-controls="tab_{{ Str::slug($tab) }}"
+                        role="tab"
+                        tab_name="{{ Str::slug($tab) }}"
+                        data-toggle="tab"
+                        class="nav-link {{ isset($tabWithError) && $tabWithError ? ($tab == $tabWithError ? 'active' : '') : ($k == 0 ? 'active' : '') }}"
+                        >{{ $tab }}</a>
+                </li>
+            @endforeach
+        </ul>
+
+        <div class="tab-content p-0 {{$horizontalTabs ? '' : 'col-md-9'}}">
+
+            @foreach ($crud->getTabs() as $k => $tabLabel)
+            <div role="tabpanel" class="tab-pane {{ isset($tabWithError) && $tabWithError ? ($tabLabel == $tabWithError ? ' active' : '') : ($k == 0 ? ' active' : '') }}" id="tab_{{ Str::slug($tabLabel) }}">
+
+                <div class="row">
+                    @include('crud::inc.show_fields', ['fields' => $crud->getTabItems($tabLabel, 'fields')])
+                </div>
+            </div>
+            @endforeach
+
+        </div>
+    </div>
+</div>
+
+@push('crud_fields_styles')
+    <style>
+        .nav-tabs-custom {
+            box-shadow: none;
+        }
+        .nav-tabs-custom > .nav-tabs.nav-stacked > li {
+            margin-right: 0;
+        }
+
+        .tab-pane .form-group h1:first-child,
+        .tab-pane .form-group h2:first-child,
+        .tab-pane .form-group h3:first-child {
+            margin-top: 0;
+        }
+
+        /*
+            when select2 is multiple and it's not on the first displayed tab the placeholder would
+            not display correctly because the element was not "visible" on the page (hidden by tab)
+            thus getting `0px` width. This makes sure that the placeholder element is always 100% width
+            by preventing the select2 inline style (0px) from applying using !important
+        */
+        .select2-search__field {
+            width: 100% !important;
+        }
+    </style>
+@endpush
+
diff --git a/resources/views/vendor/backpack/crud/inc/show_tabbed_table.blade.php b/resources/views/vendor/backpack/crud/inc/show_tabbed_table.blade.php
new file mode 100644 (file)
index 0000000..1d0e874
--- /dev/null
@@ -0,0 +1,47 @@
+@php
+    $horizontalTabs = $crud->getTabsType() == 'horizontal';
+    $columnsWithoutTab = $crud->getElementsWithoutATab($crud->columns());
+    $columnsWithTabs = $crud->getUniqueTabNames('columns');
+@endphp
+
+@if($columnsWithoutTab->filter(function ($value, $key) { return $value['type'] != 'hidden'; })->count())
+    <div class="card">
+        @include('crud::inc.show_table', ['columns' => $columnsWithoutTab, 'displayActionsColumn' => false])
+    </div>
+@else
+    @include('crud::inc.show_table', ['columns' => $columnsWithoutTab])
+@endif
+
+<div class="tab-container {{ $horizontalTabs ? '' : 'container'}} mb-2">
+
+    <div class="nav-tabs-custom {{ $horizontalTabs ? '' : 'row'}}" id="form_tabs">
+        <ul class="nav {{ $horizontalTabs ? 'nav-tabs' : 'flex-column nav-pills'}} {{ $horizontalTabs ? '' : 'col-md-3' }}" role="tablist">
+            @foreach ($columnsWithTabs as $k => $tabLabel)
+                <li role="presentation" class="nav-item">
+                    <a href="#tab_{{ Str::slug($tabLabel) }}"
+                       aria-controls="tab_{{ Str::slug($tabLabel) }}"
+                       role="tab"
+                       tab_name="{{ Str::slug($tabLabel) }}"
+                       data-toggle="tab"
+                       class="nav-link {{ $k === 0 ? 'active' : '' }}"
+                    >{{ $tabLabel }}</a>
+                </li>
+            @endforeach
+        </ul>
+
+        <div class="tab-content p-0 {{ $horizontalTabs ? '' : 'col-md-9' }}">
+            @foreach ($columnsWithTabs as $k => $tabLabel)
+                <div role="tabpanel" class="tab-pane p-0 border-none {{ $k === 0 ? 'active' : '' }}" id="tab_{{ Str::slug($tabLabel) }}">
+                    @include('crud::inc.show_table', ['columns' => $crud->getTabItems($tabLabel, 'columns'), 'displayActionsColumn' => false])
+                </div>
+            @endforeach
+        </div>
+        {{-- Display action column--}}
+        @if($crud->buttons()->where('stack', 'line')->count())
+            <div class="text-center mt-4 {{ $horizontalTabs ? '' : 'offset-md-3 col-md-9' }}">
+                <p class="mb-0"><strong>{{ trans('backpack::crud.actions') }}:</strong></p>
+                <p>@include('crud::inc.button_stack', ['stack' => 'line'])</p>
+            </div>
+        @endif
+    </div>
+</div>
diff --git a/resources/views/vendor/backpack/crud/inc/show_table.blade.php b/resources/views/vendor/backpack/crud/inc/show_table.blade.php
new file mode 100644 (file)
index 0000000..b290788
--- /dev/null
@@ -0,0 +1,39 @@
+@if(count($columns))
+    <table class="table table-striped m-0 p-0">
+        <tbody>
+        @foreach($columns as $column)
+            <tr>
+                <td @if($loop->index === 0) class="border-top-0" @endif>
+                    <strong>{!! $column['label'] !!}:</strong>
+                </td>
+                <td @if($loop->index === 0) class="border-top-0" @endif>
+                    @php
+                        // create a list of paths to column blade views
+                        // including the configured view_namespaces
+                        $columnPaths = array_map(function($item) use ($column) {
+                            return $item.'.'.$column['type'];
+                        }, \Backpack\CRUD\ViewNamespaces::getFor('columns'));
+
+                        // but always fall back to the stock 'text' column
+                        // if a view doesn't exist
+                        if (!in_array('crud::columns.text', $columnPaths)) {
+                            $columnPaths[] = 'crud::columns.text';
+                        }
+                    @endphp
+                    @includeFirst($columnPaths)
+                </td>
+            </tr>
+        @endforeach
+        @if($crud->buttons()->where('stack', 'line')->count() && ($displayActionsColumn ?? true))
+            <tr>
+                <td>
+                    <strong>{{ trans('backpack::crud.actions') }}</strong>
+                </td>
+                <td>
+                    @include('crud::inc.button_stack', ['stack' => 'line'])
+                </td>
+            </tr>
+        @endif
+        </tbody>
+    </table>
+@endif
\ No newline at end of file
diff --git a/resources/views/vendor/backpack/crud/list.blade.php b/resources/views/vendor/backpack/crud/list.blade.php
new file mode 100644 (file)
index 0000000..7dccdb5
--- /dev/null
@@ -0,0 +1,170 @@
+@extends(backpack_view('blank'))
+
+@php
+  $defaultBreadcrumbs = [
+    trans('backpack::crud.admin') => url(config('backpack.base.route_prefix'), 'dashboard'),
+    $crud->entity_name_plural => url($crud->route),
+    trans('backpack::crud.list') => false,
+  ];
+
+  // if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs
+  $breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs;
+@endphp
+
+@section('header')
+  <div class="container-fluid">
+    <h2>
+      <span class="text-capitalize">{!! $crud->getHeading() ?? $crud->entity_name_plural !!}</span>
+      <small id="datatable_info_stack">{!! $crud->getSubheading() ?? '' !!}</small>
+    </h2>
+  </div>
+@endsection
+
+@section('content')
+  {{-- Default box --}}
+  <div class="row">
+
+    {{-- THE ACTUAL CONTENT --}}
+    <div class="{{ $crud->getListContentClass() }}">
+
+        <div class="row mb-0">
+          <div class="col-sm-6">
+            @if ( $crud->buttons()->where('stack', 'top')->count() ||  $crud->exportButtons())
+              <div class="d-print-none {{ $crud->hasAccess('create')?'with-border':'' }}">
+
+                @include('crud::inc.button_stack', ['stack' => 'top'])
+
+              </div>
+            @endif
+          </div>
+          <div class="col-sm-6">
+            <div id="datatable_search_stack" class="mt-sm-0 mt-2 d-print-none"></div>
+          </div>
+        </div>
+
+        {{-- Backpack List Filters --}}
+        @if ($crud->filtersEnabled())
+          @include('crud::inc.filters_navbar')
+        @endif
+
+        <table
+          id="crudTable"
+          class="bg-white table table-striped table-hover nowrap rounded shadow-xs border-xs mt-2"
+          data-responsive-table="{{ (int) $crud->getOperationSetting('responsiveTable') }}"
+          data-has-details-row="{{ (int) $crud->getOperationSetting('detailsRow') }}"
+          data-has-bulk-actions="{{ (int) $crud->getOperationSetting('bulkActions') }}"
+          data-has-line-buttons-as-dropdown="{{ (int) $crud->getOperationSetting('lineButtonsAsDropdown') }}"
+          cellspacing="0">
+            <thead>
+              <tr>
+                {{-- Table columns --}}
+                @foreach ($crud->columns() as $column)
+                  <th
+                    data-orderable="{{ var_export($column['orderable'], true) }}"
+                    data-priority="{{ $column['priority'] }}"
+                    data-column-name="{{ $column['name'] }}"
+                    {{--
+                    data-visible-in-table => if developer forced field in table with 'visibleInTable => true'
+                    data-visible => regular visibility of the field
+                    data-can-be-visible-in-table => prevents the column to be loaded into the table (export-only)
+                    data-visible-in-modal => if column apears on responsive modal
+                    data-visible-in-export => if this field is exportable
+                    data-force-export => force export even if field are hidden
+                    --}}
+
+                    {{-- If it is an export field only, we are done. --}}
+                    @if(isset($column['exportOnlyField']) && $column['exportOnlyField'] === true)
+                      data-visible="false"
+                      data-visible-in-table="false"
+                      data-can-be-visible-in-table="false"
+                      data-visible-in-modal="false"
+                      data-visible-in-export="true"
+                      data-force-export="true"
+                    @else
+                      data-visible-in-table="{{var_export($column['visibleInTable'] ?? false)}}"
+                      data-visible="{{var_export($column['visibleInTable'] ?? true)}}"
+                      data-can-be-visible-in-table="true"
+                      data-visible-in-modal="{{var_export($column['visibleInModal'] ?? true)}}"
+                      @if(isset($column['visibleInExport']))
+                         @if($column['visibleInExport'] === false)
+                           data-visible-in-export="false"
+                           data-force-export="false"
+                         @else
+                           data-visible-in-export="true"
+                           data-force-export="true"
+                         @endif
+                       @else
+                         data-visible-in-export="true"
+                         data-force-export="false"
+                       @endif
+                    @endif
+                  >
+                    {{-- Bulk checkbox --}}
+                    @if($loop->first && $crud->getOperationSetting('bulkActions'))
+                      {!! View::make('crud::columns.inc.bulk_actions_checkbox')->render() !!}
+                    @endif
+                    {!! $column['label'] !!}
+                  </th>
+                @endforeach
+
+                @if ( $crud->buttons()->where('stack', 'line')->count() )
+                  <th data-orderable="false"
+                      data-priority="{{ $crud->getActionsColumnPriority() }}"
+                      data-visible-in-export="false"
+                      data-action-column="true"
+                      >{{ trans('backpack::crud.actions') }}</th>
+                @endif
+              </tr>
+            </thead>
+            <tbody>
+            </tbody>
+            <tfoot>
+              <tr>
+                {{-- Table columns --}}
+                @foreach ($crud->columns() as $column)
+                  <th>
+                    {{-- Bulk checkbox --}}
+                    @if($loop->first && $crud->getOperationSetting('bulkActions'))
+                      {!! View::make('crud::columns.inc.bulk_actions_checkbox')->render() !!}
+                    @endif
+                    {!! $column['label'] !!}
+                  </th>
+                @endforeach
+
+                @if ( $crud->buttons()->where('stack', 'line')->count() )
+                  <th>{{ trans('backpack::crud.actions') }}</th>
+                @endif
+              </tr>
+            </tfoot>
+          </table>
+
+          @if ( $crud->buttons()->where('stack', 'bottom')->count() )
+          <div id="bottom_buttons" class="d-print-none text-center text-sm-left">
+            @include('crud::inc.button_stack', ['stack' => 'bottom'])
+
+            <div id="datatable_button_stack" class="float-right text-right hidden-xs"></div>
+          </div>
+          @endif
+
+    </div>
+
+  </div>
+
+@endsection
+
+@section('after_styles')
+  {{-- DATA TABLES --}}
+  <link rel="stylesheet" type="text/css" href="{{ asset('packages/datatables.net-bs4/css/dataTables.bootstrap4.min.css') }}">
+  <link rel="stylesheet" type="text/css" href="{{ asset('packages/datatables.net-fixedheader-bs4/css/fixedHeader.bootstrap4.min.css') }}">
+  <link rel="stylesheet" type="text/css" href="{{ asset('packages/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css') }}">
+
+  {{-- CRUD LIST CONTENT - crud_list_styles stack --}}
+  @stack('crud_list_styles')
+@endsection
+
+@section('after_scripts')
+  @include('crud::inc.datatables_logic')
+
+  {{-- CRUD LIST CONTENT - crud_list_scripts stack --}}
+  @stack('crud_list_scripts')
+@endsection
diff --git a/resources/views/vendor/backpack/crud/reorder.blade.php b/resources/views/vendor/backpack/crud/reorder.blade.php
new file mode 100644 (file)
index 0000000..033dafb
--- /dev/null
@@ -0,0 +1,297 @@
+@extends(backpack_view('blank'))
+
+@php
+    $defaultBreadcrumbs = [
+      trans('backpack::crud.admin') => url(config('backpack.base.route_prefix'), 'dashboard'),
+      $crud->entity_name_plural => url($crud->route),
+      trans('backpack::crud.reorder') => false,
+    ];
+
+    // if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs
+    $breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs;
+@endphp
+
+@section('header')
+    <div class="container-fluid">
+        <h2>
+            <span class="text-capitalize">{!! $crud->getHeading() ?? $crud->entity_name_plural !!}</span>
+            <small>{!! $crud->getSubheading() ?? trans('backpack::crud.reorder').' '.$crud->entity_name_plural !!}.</small>
+
+            @if ($crud->hasAccess('list'))
+                <small><a href="{{ url($crud->route) }}" class="d-print-none font-sm"><i class="la la-angle-double-left"></i> {{ trans('backpack::crud.back_to_all') }} <span>{{ $crud->entity_name_plural }}</span></a></small>
+            @endif
+        </h2>
+    </div>
+@endsection
+
+@section('content')
+    <?php
+    function tree_element($entry, $key, $all_entries, $crud)
+    {
+        if (! isset($entry->tree_element_shown)) {
+            // mark the element as shown
+            $all_entries[$key]->tree_element_shown = true;
+            $entry->tree_element_shown = true;
+
+            // show the tree element
+            echo '<li id="list_'.$entry->getKey().'">';
+            echo '<div><span class="disclose"><span></span></span>'.object_get($entry, $crud->get('reorder.label')).'</div>';
+
+            // see if this element has any children
+            $children = [];
+            foreach ($all_entries as $key => $subentry) {
+                if ($subentry->parent_id == $entry->getKey()) {
+                    $children[] = $subentry;
+                }
+            }
+
+            $children = collect($children)->sortBy('lft');
+
+            // if it does have children, show them
+            if (count($children)) {
+                echo '<ol>';
+                foreach ($children as $key => $child) {
+                    $children[$key] = tree_element($child, $child->getKey(), $all_entries, $crud);
+                }
+                echo '</ol>';
+            }
+            echo '</li>';
+        }
+
+        return $entry;
+    }
+
+    ?>
+
+    <div class="row mt-4">
+        <div class="{{ $crud->getReorderContentClass() }}">
+            <div class="card p-4">
+                <p>{{ trans('backpack::crud.reorder_text') }}</p>
+
+                <ol class="sortable mt-0">
+                    <?php
+                    $all_entries = collect($entries->all())->sortBy('lft')->keyBy($crud->getModel()->getKeyName());
+    $root_entries = $all_entries->filter(function ($item) {
+        return $item->parent_id == 0;
+    });
+    foreach ($root_entries as $key => $entry) {
+        $root_entries[$key] = tree_element($entry, $key, $all_entries, $crud);
+    }
+    ?>
+                </ol>
+
+            </div>{{-- /.card --}}
+
+            <button id="toArray" class="btn btn-success" data-style="zoom-in"><i class="la la-save"></i> {{ trans('backpack::crud.save') }}</button>
+        </div>
+    </div>
+@endsection
+
+
+@section('after_styles')
+    <style>
+        .ui-sortable .placeholder {
+            outline: 1px dashed #4183C4;
+            /*-webkit-border-radius: 3px;
+            -moz-border-radius: 3px;
+            border-radius: 3px;
+            margin: -1px;*/
+        }
+
+        .ui-sortable .mjs-nestedSortable-error {
+            background: #fbe3e4;
+            border-color: transparent;
+        }
+
+        .ui-sortable ol {
+            margin: 0;
+            padding: 0;
+            padding-left: 30px;
+        }
+
+        ol.sortable, ol.sortable ol {
+            margin: 0 0 0 25px;
+            padding: 0;
+            list-style-type: none;
+        }
+
+        ol.sortable {
+            margin: 2em 0;
+        }
+
+        .sortable li {
+            margin: 5px 0 0 0;
+            padding: 0;
+        }
+
+        .sortable li div  {
+            border: 1px solid #ddd;
+            -webkit-border-radius: 3px;
+            -moz-border-radius: 3px;
+            border-radius: 3px;
+            padding: 6px;
+            margin: 0;
+            cursor: move;
+            background-color: #f4f4f4;
+            color: #444;
+            border-color: #00acd6;
+        }
+
+        .sortable li.mjs-nestedSortable-branch div {
+            /*background-color: #00c0ef;*/
+            /*border-color: #00acd6;*/
+        }
+
+        .sortable li.mjs-nestedSortable-leaf div {
+            /*background-color: #00c0ef;*/
+            border: 1px solid #ddd;
+        }
+
+        li.mjs-nestedSortable-collapsed.mjs-nestedSortable-hovering div {
+            border-color: #999;
+            background: #fafafa;
+        }
+
+        .ui-sortable .disclose {
+            cursor: pointer;
+            width: 10px;
+            display: none;
+        }
+
+        .sortable li.mjs-nestedSortable-collapsed > ol {
+            display: none;
+        }
+
+        .sortable li.mjs-nestedSortable-branch > div > .disclose {
+            display: inline-block;
+        }
+
+        .sortable li.mjs-nestedSortable-collapsed > div > .disclose > span:before {
+            content: '+ ';
+        }
+
+        .sortable li.mjs-nestedSortable-expanded > div > .disclose > span:before {
+            content: '- ';
+        }
+
+        .ui-sortable h1 {
+            font-size: 2em;
+            margin-bottom: 0;
+        }
+
+        .ui-sortable h2 {
+            font-size: 1.2em;
+            font-weight: normal;
+            font-style: italic;
+            margin-top: .2em;
+            margin-bottom: 1.5em;
+        }
+
+        .ui-sortable h3 {
+            font-size: 1em;
+            margin: 1em 0 .3em;;
+        }
+
+        .ui-sortable p, .ui-sortable ol, .ui-sortable ul, .ui-sortable pre, .ui-sortable form {
+            margin-top: 0;
+            margin-bottom: 1em;
+        }
+
+        .ui-sortable dl {
+            margin: 0;
+        }
+
+        .ui-sortable dd {
+            margin: 0;
+            padding: 0 0 0 1.5em;
+        }
+
+        .ui-sortable code {
+            background: #e5e5e5;
+        }
+
+        .ui-sortable input {
+            vertical-align: text-bottom;
+        }
+
+        .ui-sortable .notice {
+            color: #c33;
+        }
+    </style>
+@endsection
+
+@section('after_scripts')
+    <script src="{{ asset('packages/jquery-ui-dist/jquery-ui.min.js') }}" type="text/javascript" ></script>
+    <script src="{{ asset('packages/nestedSortable/jquery.mjs.nestedSortable2.js') }}" type="text/javascript" ></script>
+
+    <script type="text/javascript">
+        jQuery(document).ready(function($) {
+            var isRtl = Boolean("{{ (config('backpack.base.html_direction') === 'rtl') ? true : false }}");
+            if(isRtl) {
+                $( " <style> .ui-sortable ol {margin: 0;padding: 0;padding-right: 30px;}ol.sortable, ol.sortable ol {margin: 0 25px 0 0;padding: 0;list-style-type: none;}.ui-sortable dd {margin: 0;padding: 0 1.5em 0 0;}</style>" ).appendTo( "head" )
+            }
+            // initialize the nested sortable plugin
+            $('.sortable').nestedSortable({
+                forcePlaceholderSize: true,
+                handle: 'div',
+                helper: 'clone',
+                items: 'li',
+                opacity: .6,
+                placeholder: 'placeholder',
+                revert: 250,
+                tabSize: 25,
+                rtl: isRtl,
+                tolerance: 'pointer',
+                toleranceElement: '> div',
+                maxLevels: {{ $crud->get('reorder.max_level') ?? 3 }},
+                isTree: true,
+                expandOnHover: 700,
+                startCollapsed: false
+            });
+
+            $('.disclose').on('click', function() {
+                $(this).closest('li').toggleClass('mjs-nestedSortable-collapsed').toggleClass('mjs-nestedSortable-expanded');
+            });
+
+            $('#toArray').click(function(e){
+                // get the current tree order
+                arraied = $('ol.sortable').nestedSortable('toArray', {startDepthCount: 0, expression: /(.+)_(.+)/ });
+
+                // log it
+                //console.log(arraied);
+
+                // send it with POST
+                $.ajax({
+                    url: '{{ url(Request::path()) }}',
+                    type: 'POST',
+                    data: { tree: JSON.stringify(arraied) },
+                })
+                    .done(function() {
+                        new Noty({
+                            type: "success",
+                            text: "<strong>{{ trans('backpack::crud.reorder_success_title') }}</strong><br>{{ trans('backpack::crud.reorder_success_message') }}"
+                        }).show();
+                    })
+                    .fail(function() {
+                        new Noty({
+                            type: "error",
+                            text: "<strong>{{ trans('backpack::crud.reorder_error_title') }}</strong><br>{{ trans('backpack::crud.reorder_error_message') }}"
+                        }).show();
+                    })
+                    .always(function() {
+                        console.log("complete");
+                    });
+
+            });
+
+            $.ajaxPrefilter(function(options, originalOptions, xhr) {
+                var token = $('meta[name="csrf_token"]').attr('content');
+
+                if (token) {
+                    return xhr.setRequestHeader('X-XSRF-TOKEN', token);
+                }
+            });
+
+        });
+    </script>
+@endsection
diff --git a/resources/views/vendor/backpack/crud/show.blade.php b/resources/views/vendor/backpack/crud/show.blade.php
new file mode 100644 (file)
index 0000000..ae80388
--- /dev/null
@@ -0,0 +1,62 @@
+@extends(backpack_view('blank'))
+
+@php
+    $defaultBreadcrumbs = [
+      trans('backpack::crud.admin') => url(config('backpack.base.route_prefix'), 'dashboard'),
+      $crud->entity_name_plural => url($crud->route),
+      trans('backpack::crud.preview') => false,
+    ];
+
+    // if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs
+    $breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs;
+@endphp
+
+@section('header')
+    <section class="container-fluid d-print-none">
+        <a href="javascript: window.print();" class="btn float-right"><i class="la la-print"></i></a>
+        <h2>
+            <span class="text-capitalize">{!! $crud->getHeading() ?? $crud->entity_name_plural !!}</span>
+            <small>{!! $crud->getSubheading() ?? mb_ucfirst(trans('backpack::crud.preview')).' '.$crud->entity_name !!}.</small>
+            @if ($crud->hasAccess('list'))
+                <small class=""><a href="{{ url($crud->route) }}" class="font-sm"><i class="la la-angle-double-left"></i> {{ trans('backpack::crud.back_to_all') }} <span>{{ $crud->entity_name_plural }}</span></a></small>
+            @endif
+        </h2>
+    </section>
+@endsection
+
+@section('content')
+    <div class="row">
+        <div class="{{ $crud->getShowContentClass() }}">
+
+            {{-- Default box --}}
+            <div>
+                @if ($crud->model->translationEnabled())
+                    <div class="row">
+                        <div class="col-md-12 mb-2">
+                            {{-- Change translation button group --}}
+                            <div class="btn-group float-right">
+                                <button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                                    {{trans('backpack::crud.language')}}: {{ $crud->model->getAvailableLocales()[request()->input('_locale')?request()->input('_locale'):App::getLocale()] }} &nbsp; <span class="caret"></span>
+                                </button>
+                                <ul class="dropdown-menu">
+                                    @foreach ($crud->model->getAvailableLocales() as $key => $locale)
+                                        <a class="dropdown-item" href="{{ url($crud->route.'/'.$entry->getKey().'/show') }}?_locale={{ $key }}">{{ $locale }}</a>
+                                    @endforeach
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                @endif
+
+                @if($crud->tabsEnabled() && count($crud->getUniqueTabNames('columns')))
+                    @include('crud::inc.show_tabbed_table')
+                @else
+                    <div class="card no-padding no-border mb-0">
+                        @include('crud::inc.show_table', ['columns' => $crud->columns()])
+                    </div>
+                @endif
+            </div>
+
+        </div>
+    </div>
+@endsection