303 lines
8.6 KiB
JavaScript
303 lines
8.6 KiB
JavaScript
// Main JavaScript file for Edu-Space Admin
|
|
|
|
$(document).ready(function() {
|
|
// Initialize tooltips
|
|
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
|
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
|
return new bootstrap.Tooltip(tooltipTriggerEl);
|
|
});
|
|
|
|
// Initialize popovers
|
|
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
|
|
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
|
|
return new bootstrap.Popover(popoverTriggerEl);
|
|
});
|
|
|
|
// Auto-hide alerts after 5 seconds
|
|
setTimeout(function() {
|
|
$('.alert.fade').alert('close');
|
|
}, 5000);
|
|
|
|
// Confirm delete actions
|
|
$('.delete-confirm').on('click', function(e) {
|
|
if (!confirm('Are you sure you want to delete this item? This action cannot be undone.')) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// Form validation enhancements
|
|
$('form').on('submit', function() {
|
|
var form = $(this);
|
|
var submitBtn = form.find('button[type="submit"]');
|
|
|
|
// Show loading state
|
|
submitBtn.prop('disabled', true);
|
|
var originalText = submitBtn.html();
|
|
submitBtn.html('<i class="bi bi-hourglass-split me-2"></i>Loading...');
|
|
|
|
// Re-enable after 10 seconds in case of error
|
|
setTimeout(function() {
|
|
submitBtn.prop('disabled', false);
|
|
submitBtn.html(originalText);
|
|
}, 10000);
|
|
});
|
|
|
|
// Copy to clipboard functionality
|
|
$('.copy-to-clipboard').on('click', function() {
|
|
var text = $(this).data('text');
|
|
if (!text) {
|
|
text = $(this).text();
|
|
}
|
|
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
showToast('Copied to clipboard!', 'success');
|
|
}).catch(function() {
|
|
showToast('Failed to copy to clipboard', 'error');
|
|
});
|
|
});
|
|
|
|
// Quick search functionality
|
|
$('#quickSearch').on('input', function() {
|
|
var searchTerm = $(this).val().toLowerCase();
|
|
|
|
$('.searchable-item').each(function() {
|
|
var item = $(this);
|
|
var text = item.text().toLowerCase();
|
|
|
|
if (text.includes(searchTerm)) {
|
|
item.show();
|
|
} else {
|
|
item.hide();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Initialize datepickers
|
|
$('.datetimepicker').each(function() {
|
|
$(this).flatpickr({
|
|
enableTime: true,
|
|
dateFormat: "Y-m-d H:i",
|
|
time_24hr: true,
|
|
minDate: "today"
|
|
});
|
|
});
|
|
|
|
$('.datepicker').each(function() {
|
|
$(this).flatpickr({
|
|
dateFormat: "Y-m-d",
|
|
minDate: "today"
|
|
});
|
|
});
|
|
|
|
// Auto-save functionality for multi-step forms
|
|
$('.auto-save').on('change input', function() {
|
|
var form = $(this).closest('form');
|
|
var formData = form.serialize();
|
|
|
|
// Save to localStorage
|
|
localStorage.setItem('autosave_' + form.attr('id'), formData);
|
|
showToast('Draft saved automatically', 'info');
|
|
});
|
|
|
|
// Restore auto-saved data
|
|
$('form.auto-save-restore').each(function() {
|
|
var form = $(this);
|
|
var savedData = localStorage.getItem('autosave_' + form.attr('id'));
|
|
|
|
if (savedData) {
|
|
// Show restore prompt
|
|
if (confirm('Found unsaved changes. Would you like to restore them?')) {
|
|
var params = new URLSearchParams(savedData);
|
|
params.forEach(function(value, key) {
|
|
form.find('[name="' + key + '"]').val(value);
|
|
});
|
|
showToast('Draft restored', 'info');
|
|
}
|
|
}
|
|
});
|
|
|
|
// Print functionality
|
|
$('.btn-print').on('click', function() {
|
|
window.print();
|
|
});
|
|
|
|
// Export functionality
|
|
$('.btn-export').on('click', function() {
|
|
var format = $(this).data('format');
|
|
var url = $(this).data('url');
|
|
|
|
if (format === 'excel') {
|
|
window.open(url + '?export=excel', '_blank');
|
|
} else if (format === 'pdf') {
|
|
window.open(url + '?export=pdf', '_blank');
|
|
} else if (format === 'csv') {
|
|
window.open(url + '?export=csv', '_blank');
|
|
}
|
|
});
|
|
|
|
// Keyboard shortcuts
|
|
$(document).on('keydown', function(e) {
|
|
// Ctrl/Cmd + K for search
|
|
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
|
e.preventDefault();
|
|
$('#quickSearch').focus();
|
|
}
|
|
|
|
// Escape to close modals
|
|
if (e.key === 'Escape') {
|
|
$('.modal.show').modal('hide');
|
|
}
|
|
});
|
|
|
|
// Initialize tooltips dynamically for AI-generated content
|
|
initializeDynamicTooltips();
|
|
});
|
|
|
|
// Utility functions
|
|
|
|
function showToast(message, type = 'info') {
|
|
var toastHtml = `
|
|
<div class="toast align-items-center text-white bg-${type === 'error' ? 'danger' : type} border-0" role="alert">
|
|
<div class="d-flex">
|
|
<div class="toast-body">
|
|
${message}
|
|
</div>
|
|
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
var toastContainer = $('.toast-container');
|
|
var toastElement = $(toastHtml);
|
|
toastContainer.append(toastElement);
|
|
|
|
var toast = new bootstrap.Toast(toastElement[0]);
|
|
toast.show();
|
|
|
|
// Remove toast element after it's hidden
|
|
toastElement.on('hidden.bs.toast', function() {
|
|
$(this).remove();
|
|
});
|
|
}
|
|
|
|
function confirmAction(message, callback) {
|
|
if (confirm(message)) {
|
|
callback();
|
|
}
|
|
}
|
|
|
|
function formatDateTime(dateTimeString) {
|
|
var date = new Date(dateTimeString);
|
|
return date.toLocaleString();
|
|
}
|
|
|
|
function formatDate(dateString) {
|
|
var date = new Date(dateString);
|
|
return date.toLocaleDateString();
|
|
}
|
|
|
|
function formatTime(timeString) {
|
|
var date = new Date(timeString);
|
|
return date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
|
}
|
|
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
function initializeDynamicTooltips() {
|
|
// Initialize tooltips for dynamically generated content
|
|
$('[data-bs-toggle="tooltip"]:not([aria-describedby])').each(function() {
|
|
new bootstrap.Tooltip(this);
|
|
});
|
|
}
|
|
|
|
// API Helper functions
|
|
function apiCall(url, method = 'GET', data = null) {
|
|
return $.ajax({
|
|
url: url,
|
|
method: method,
|
|
data: data,
|
|
headers: {
|
|
'X-CSRFToken': csrfToken || ''
|
|
}
|
|
});
|
|
}
|
|
|
|
function handleApiError(xhr) {
|
|
if (xhr.responseJSON && xhr.responseJSON.message) {
|
|
showToast(xhr.responseJSON.message, 'error');
|
|
} else {
|
|
showToast('An error occurred. Please try again.', 'error');
|
|
}
|
|
}
|
|
|
|
// Form validation helpers
|
|
function validateForm(form) {
|
|
var isValid = true;
|
|
var errors = [];
|
|
|
|
form.find('[required]').each(function() {
|
|
var field = $(this);
|
|
if (!field.val()) {
|
|
isValid = false;
|
|
errors.push(field.attr('data-label') || field.attr('name'));
|
|
field.addClass('is-invalid');
|
|
} else {
|
|
field.removeClass('is-invalid');
|
|
}
|
|
});
|
|
|
|
if (!isValid) {
|
|
showToast('Please fill in the required fields: ' + errors.join(', '), 'error');
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
// Image preview functionality
|
|
function previewImage(input, previewElement) {
|
|
if (input.files && input.files[0]) {
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = function(e) {
|
|
previewElement.attr('src', e.target.result);
|
|
};
|
|
|
|
reader.readAsDataURL(input.files[0]);
|
|
}
|
|
}
|
|
|
|
// Export to CSV function
|
|
function exportToCSV(data, filename) {
|
|
var csv = '';
|
|
var headers = Object.keys(data[0]);
|
|
|
|
// Add headers
|
|
csv += headers.join(',') + '\n';
|
|
|
|
// Add data
|
|
data.forEach(function(row) {
|
|
headers.forEach(function(header, index) {
|
|
if (index > 0) csv += ',';
|
|
csv += '"' + (row[header] || '') + '"';
|
|
});
|
|
csv += '\n';
|
|
});
|
|
|
|
// Create download link
|
|
var hiddenElement = document.createElement('a');
|
|
hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
|
|
hiddenElement.target = '_blank';
|
|
hiddenElement.download = filename + '.csv';
|
|
hiddenElement.click();
|
|
} |