128 lines
5.0 KiB
JavaScript
128 lines
5.0 KiB
JavaScript
$(document).ready(function() {
|
|
/**
|
|
* Global AJAX Form Handler
|
|
* Intercepts forms with class .ajax-form and handles them via AJAX.
|
|
*/
|
|
$(document).on('submit', 'form.ajax-form', function(e) {
|
|
e.preventDefault();
|
|
|
|
const $form = $(this);
|
|
const $submitBtn = $form.find('button[type="submit"]');
|
|
const originalBtnHtml = $submitBtn.html();
|
|
const actionUrl = $form.attr('action');
|
|
const method = $form.attr('method') || 'POST';
|
|
|
|
// CKEditor 5 Sync
|
|
$form.find('textarea').each(function() {
|
|
if (this.ckeditorInstance) {
|
|
this.ckeditorInstance.updateSourceElement();
|
|
}
|
|
});
|
|
|
|
// 1. Loading state
|
|
$submitBtn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-2"></span> ' + ( $submitBtn.data('loading-text') || 'Saving...' ));
|
|
|
|
// 2. Perform Request
|
|
const formData = new FormData(this);
|
|
|
|
// Allow page-specific code to modify formData before sending
|
|
// (e.g. appending FilePond files)
|
|
$form.trigger('ajaxForm:beforeSend', [formData]);
|
|
|
|
$.ajax({
|
|
url: actionUrl,
|
|
method: method,
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
dataType: 'json',
|
|
headers: {
|
|
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
|
},
|
|
success: function(response) {
|
|
// Notif (Allow skipping global alert)
|
|
if ($form.data('alert') !== false) {
|
|
const swalInstance = window.StandardSwal || Swal;
|
|
swalInstance.fire({
|
|
icon: 'success',
|
|
title: 'Success!',
|
|
text: response.message || 'Data saved successfully.',
|
|
timer: 1500,
|
|
showConfirmButton: false
|
|
});
|
|
}
|
|
|
|
// 3. UI Updates
|
|
// Close active modal if exists
|
|
const $modal = $form.closest('.modal');
|
|
if ($modal.length) {
|
|
const modalInstance = bootstrap.Modal.getInstance($modal[0]);
|
|
if (modalInstance) {
|
|
modalInstance.hide();
|
|
} else {
|
|
// Fallback jQuery hide if instance not found
|
|
$($modal[0]).modal('hide');
|
|
}
|
|
|
|
// Robust Cleanup: Ensure backdrop is removed and scrolling is restored
|
|
// This fixes the common Bootstrap bug where backdrop stays stuck
|
|
setTimeout(() => {
|
|
$('.modal-backdrop').remove();
|
|
$('body').removeClass('modal-open').css({
|
|
'overflow': '',
|
|
'padding-right': ''
|
|
});
|
|
}, 400);
|
|
}
|
|
|
|
// Refresh DataTable if window.reloadDataTable is defined
|
|
if (typeof window.reloadDataTable === 'function') {
|
|
window.reloadDataTable();
|
|
}
|
|
|
|
// Reset form if it's not an update form (optional based on data-reset attribute)
|
|
if ($form.data('reset') !== false && !$form.find('input[name="_method"][value="PUT"]').length) {
|
|
$form[0].reset();
|
|
// Reset Choices.js if present
|
|
$form.find('select').each(function() {
|
|
if (this.choices) this.choices.setChoiceByValue('');
|
|
});
|
|
}
|
|
|
|
// Trigger custom event for specific page logic
|
|
$form.trigger('ajaxForm:success', [response]);
|
|
},
|
|
error: function(xhr) {
|
|
let errorMsg = 'Something went wrong.';
|
|
|
|
if (xhr.status === 422) {
|
|
const errors = xhr.responseJSON.errors;
|
|
errorMsg = '<ul class="text-start mb-0">';
|
|
Object.values(errors).flat().forEach(err => {
|
|
errorMsg += `<li>${err}</li>`;
|
|
});
|
|
errorMsg += '</ul>';
|
|
} else if (xhr.responseJSON && xhr.responseJSON.message) {
|
|
errorMsg = xhr.responseJSON.message;
|
|
}
|
|
|
|
if ($form.data('alert') !== false) {
|
|
const swalInstance = window.StandardSwal || Swal;
|
|
swalInstance.fire({
|
|
icon: 'error',
|
|
title: 'Validation Error',
|
|
html: errorMsg,
|
|
confirmButtonText: 'Understood'
|
|
});
|
|
}
|
|
|
|
$form.trigger('ajaxForm:error', [xhr]);
|
|
},
|
|
complete: function() {
|
|
// Restore button
|
|
$submitBtn.prop('disabled', false).html(originalBtnHtml);
|
|
}
|
|
});
|
|
});
|
|
});
|