Sindbad~EG File Manager
// Church Attendance Management System - JavaScript Functions
// Global variables
let notificationTimeout;
// Initialize application
document.addEventListener('DOMContentLoaded', function() {
initializeApp();
});
function initializeApp() {
// Initialize mobile menu
initializeMobileMenu();
// Initialize form validations
initializeFormValidations();
// Initialize tooltips
initializeTooltips();
// Initialize auto-save functionality
initializeAutoSave();
// Initialize keyboard shortcuts
initializeKeyboardShortcuts();
}
// Mobile menu functionality
function initializeMobileMenu() {
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
const sidebar = document.getElementById('sidebar');
if (mobileMenuBtn && sidebar) {
mobileMenuBtn.addEventListener('click', function() {
sidebar.classList.toggle('sidebar-closed');
});
// Close sidebar when clicking outside on mobile
document.addEventListener('click', function(e) {
if (window.innerWidth < 768 &&
!sidebar.contains(e.target) &&
!mobileMenuBtn.contains(e.target)) {
sidebar.classList.add('sidebar-closed');
}
});
}
}
// Form validation
function initializeFormValidations() {
const forms = document.querySelectorAll('form[data-validate]');
forms.forEach(form => {
form.addEventListener('submit', function(e) {
if (!validateForm(this)) {
e.preventDefault();
return false;
}
});
});
}
function validateForm(form) {
let isValid = true;
const requiredFields = form.querySelectorAll('[required]');
requiredFields.forEach(field => {
if (!field.value.trim()) {
showFieldError(field, 'This field is required');
isValid = false;
} else {
clearFieldError(field);
}
});
// Email validation
const emailFields = form.querySelectorAll('input[type="email"]');
emailFields.forEach(field => {
if (field.value && !isValidEmail(field.value)) {
showFieldError(field, 'Please enter a valid email address');
isValid = false;
}
});
// Phone validation
const phoneFields = form.querySelectorAll('input[type="tel"]');
phoneFields.forEach(field => {
if (field.value && !isValidPhone(field.value)) {
showFieldError(field, 'Please enter a valid phone number');
isValid = false;
}
});
return isValid;
}
function showFieldError(field, message) {
clearFieldError(field);
field.classList.add('border-red-500');
const errorDiv = document.createElement('div');
errorDiv.className = 'text-red-500 text-sm mt-1 field-error';
errorDiv.textContent = message;
field.parentNode.appendChild(errorDiv);
}
function clearFieldError(field) {
field.classList.remove('border-red-500');
const errorDiv = field.parentNode.querySelector('.field-error');
if (errorDiv) {
errorDiv.remove();
}
}
// Utility functions
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function isValidPhone(phone) {
const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/;
return phoneRegex.test(phone.replace(/\D/g, ''));
}
// Notification system
function showNotification(message, type = 'info', duration = 5000) {
// Clear existing notification
const existingNotification = document.querySelector('.notification');
if (existingNotification) {
existingNotification.remove();
}
const notification = document.createElement('div');
notification.className = `notification px-6 py-4 rounded-lg shadow-lg text-white ${getNotificationClass(type)}`;
const icon = getNotificationIcon(type);
notification.innerHTML = `
<div class="flex items-center">
<i class="${icon} mr-3"></i>
<span>${message}</span>
<button onclick="this.parentElement.parentElement.remove()" class="ml-4 text-white hover:text-gray-200">
<i class="fas fa-times"></i>
</button>
</div>
`;
document.body.appendChild(notification);
// Auto-remove notification
if (duration > 0) {
setTimeout(() => {
if (notification.parentNode) {
notification.remove();
}
}, duration);
}
}
function getNotificationClass(type) {
switch (type) {
case 'success': return 'bg-green-500';
case 'error': return 'bg-red-500';
case 'warning': return 'bg-yellow-500';
default: return 'bg-blue-500';
}
}
function getNotificationIcon(type) {
switch (type) {
case 'success': return 'fas fa-check-circle';
case 'error': return 'fas fa-exclamation-circle';
case 'warning': return 'fas fa-exclamation-triangle';
default: return 'fas fa-info-circle';
}
}
// Loading overlay
function showLoading(message = 'Loading...') {
const overlay = document.createElement('div');
overlay.id = 'loadingOverlay';
overlay.className = 'loading-overlay';
overlay.innerHTML = `
<div class="text-center">
<div class="spinner mx-auto mb-4"></div>
<p class="text-gray-600">${message}</p>
</div>
`;
document.body.appendChild(overlay);
}
function hideLoading() {
const overlay = document.getElementById('loadingOverlay');
if (overlay) {
overlay.remove();
}
}
// Auto-save functionality
function initializeAutoSave() {
const autoSaveForms = document.querySelectorAll('[data-autosave]');
autoSaveForms.forEach(form => {
const inputs = form.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
input.addEventListener('change', function() {
autoSaveForm(form);
});
});
});
}
function autoSaveForm(form) {
const formData = new FormData(form);
const data = Object.fromEntries(formData);
// Save to localStorage
const formId = form.id || 'autosave_form';
localStorage.setItem(`autosave_${formId}`, JSON.stringify(data));
// Show auto-save indicator
showAutoSaveIndicator();
}
function loadAutoSavedData(formId) {
const savedData = localStorage.getItem(`autosave_${formId}`);
if (savedData) {
const data = JSON.parse(savedData);
const form = document.getElementById(formId);
if (form) {
Object.keys(data).forEach(key => {
const field = form.querySelector(`[name="${key}"]`);
if (field) {
field.value = data[key];
}
});
}
}
}
function clearAutoSavedData(formId) {
localStorage.removeItem(`autosave_${formId}`);
}
function showAutoSaveIndicator() {
const indicator = document.getElementById('autoSaveIndicator') || createAutoSaveIndicator();
indicator.textContent = 'Saved';
indicator.className = 'text-green-600 text-sm';
setTimeout(() => {
indicator.textContent = '';
}, 2000);
}
function createAutoSaveIndicator() {
const indicator = document.createElement('div');
indicator.id = 'autoSaveIndicator';
indicator.className = 'fixed top-4 right-4 z-50';
document.body.appendChild(indicator);
return indicator;
}
// Keyboard shortcuts
function initializeKeyboardShortcuts() {
document.addEventListener('keydown', function(e) {
// Ctrl/Cmd + S for save
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault();
const saveBtn = document.querySelector('[type="submit"], .btn-save');
if (saveBtn) {
saveBtn.click();
}
}
// Escape to close modals
if (e.key === 'Escape') {
const modals = document.querySelectorAll('.modal:not(.hidden)');
modals.forEach(modal => {
const closeBtn = modal.querySelector('.modal-close, [onclick*="close"]');
if (closeBtn) {
closeBtn.click();
}
});
}
});
}
// Tooltip functionality
function initializeTooltips() {
const tooltipElements = document.querySelectorAll('[data-tooltip]');
tooltipElements.forEach(element => {
element.addEventListener('mouseenter', showTooltip);
element.addEventListener('mouseleave', hideTooltip);
});
}
function showTooltip(e) {
const element = e.target;
const tooltipText = element.getAttribute('data-tooltip');
if (!tooltipText) return;
const tooltip = document.createElement('div');
tooltip.id = 'tooltip';
tooltip.className = 'absolute bg-gray-800 text-white px-2 py-1 rounded text-sm z-50';
tooltip.textContent = tooltipText;
document.body.appendChild(tooltip);
const rect = element.getBoundingClientRect();
tooltip.style.left = rect.left + (rect.width / 2) - (tooltip.offsetWidth / 2) + 'px';
tooltip.style.top = rect.top - tooltip.offsetHeight - 5 + 'px';
}
function hideTooltip() {
const tooltip = document.getElementById('tooltip');
if (tooltip) {
tooltip.remove();
}
}
// Data table functionality
function initializeDataTable(tableId, options = {}) {
const table = document.getElementById(tableId);
if (!table) return;
// Add sorting functionality
const headers = table.querySelectorAll('th[data-sort]');
headers.forEach(header => {
header.style.cursor = 'pointer';
header.addEventListener('click', function() {
sortTable(table, this.getAttribute('data-sort'));
});
});
// Add search functionality
if (options.searchable) {
addTableSearch(table);
}
}
function sortTable(table, column) {
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
const sortedRows = rows.sort((a, b) => {
const aValue = a.querySelector(`[data-sort="${column}"]`)?.textContent || '';
const bValue = b.querySelector(`[data-sort="${column}"]`)?.textContent || '';
return aValue.localeCompare(bValue);
});
// Clear tbody and append sorted rows
tbody.innerHTML = '';
sortedRows.forEach(row => tbody.appendChild(row));
}
function addTableSearch(table) {
const searchInput = document.createElement('input');
searchInput.type = 'text';
searchInput.placeholder = 'Search table...';
searchInput.className = 'mb-4 px-3 py-2 border border-gray-300 rounded-md';
table.parentNode.insertBefore(searchInput, table);
searchInput.addEventListener('input', function() {
filterTable(table, this.value);
});
}
function filterTable(table, searchTerm) {
const rows = table.querySelectorAll('tbody tr');
rows.forEach(row => {
const text = row.textContent.toLowerCase();
const matches = text.includes(searchTerm.toLowerCase());
row.style.display = matches ? '' : 'none';
});
}
// Export functionality
function exportTableToCSV(tableId, filename = 'export.csv') {
const table = document.getElementById(tableId);
if (!table) return;
const rows = Array.from(table.querySelectorAll('tr'));
const csvContent = rows.map(row => {
const cells = Array.from(row.querySelectorAll('th, td'));
return cells.map(cell => `"${cell.textContent.replace(/"/g, '""')}"`).join(',');
}).join('\n');
downloadFile(csvContent, filename, 'text/csv');
}
function downloadFile(content, filename, mimeType) {
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
// Print functionality
function printElement(elementId) {
const element = document.getElementById(elementId);
if (!element) return;
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<html>
<head>
<title>Print</title>
<link href="https://cdn.tailwindcss.com" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<style>
body { font-family: Arial, sans-serif; }
@media print { .no-print { display: none !important; } }
</style>
</head>
<body>
${element.innerHTML}
</body>
</html>
`);
printWindow.document.close();
printWindow.focus();
printWindow.print();
printWindow.close();
}
// Date formatting utilities
function formatDate(dateString, format = 'MMM d, yyyy') {
const date = new Date(dateString);
const options = {
year: 'numeric',
month: 'short',
day: 'numeric'
};
return date.toLocaleDateString('en-US', options);
}
function formatDateTime(dateString) {
const date = new Date(dateString);
const dateOptions = {
year: 'numeric',
month: 'short',
day: 'numeric'
};
const timeOptions = {
hour: 'numeric',
minute: '2-digit',
hour12: true
};
return date.toLocaleDateString('en-US', dateOptions) + ' ' +
date.toLocaleTimeString('en-US', timeOptions);
}
// Confirmation dialogs
function confirmAction(message, callback) {
if (confirm(message)) {
callback();
}
}
// AJAX helper functions
function makeRequest(url, options = {}) {
const defaultOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
}
};
const config = { ...defaultOptions, ...options };
return fetch(url, config)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.catch(error => {
console.error('Request failed:', error);
showNotification('Request failed. Please try again.', 'error');
throw error;
});
}
// Form submission with loading state
function submitFormWithLoading(form, loadingMessage = 'Submitting...') {
const submitBtn = form.querySelector('[type="submit"]');
const originalText = submitBtn.textContent;
submitBtn.disabled = true;
submitBtn.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i>${loadingMessage}`;
// Reset button after 10 seconds as fallback
setTimeout(() => {
submitBtn.disabled = false;
submitBtn.textContent = originalText;
}, 10000);
}
// Initialize common functionality when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
// Auto-format phone numbers
const phoneInputs = document.querySelectorAll('input[type="tel"]');
phoneInputs.forEach(input => {
input.addEventListener('input', function(e) {
let value = e.target.value.replace(/\D/g, '');
if (value.length >= 10) {
value = value.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
}
e.target.value = value;
});
});
// Auto-submit forms on Enter key (for search forms)
const searchForms = document.querySelectorAll('form[data-auto-submit]');
searchForms.forEach(form => {
form.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
form.submit();
}
});
});
});
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists