// QR Code Generator Application class QRGenerator { constructor() { this.currentType = 'url'; this.currentQRUrl = null; this.init(); } init() { this.bindEvents(); this.updateSizeDisplay(); this.setActiveTab('url'); } bindEvents() { // Tab switching document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('click', (e) => { const type = e.currentTarget.dataset.type; this.setActiveTab(type); }); }); // Size slider const sizeSlider = document.getElementById('qr-size'); sizeSlider.addEventListener('input', () => { this.updateSizeDisplay(); }); // Generate button document.getElementById('generate-btn').addEventListener('click', () => { this.generateQRCode(); }); // Download button document.getElementById('download-btn').addEventListener('click', () => { this.downloadQRCode(); }); // Real-time input changes this.bindInputEvents(); // Color changes - removed auto-generation // Users need to click "Generate QR Code" to apply color changes } bindInputEvents() { // Clear QR code when input changes, but don't auto-generate // URL input document.getElementById('url-input').addEventListener('input', () => { this.clearPreview(); }); // Text input document.getElementById('text-input').addEventListener('input', () => { this.clearPreview(); }); // Email inputs document.getElementById('email-input').addEventListener('input', () => { this.clearPreview(); }); document.getElementById('email-subject').addEventListener('input', () => { this.clearPreview(); }); document.getElementById('email-body').addEventListener('input', () => { this.clearPreview(); }); // Phone input document.getElementById('phone-input').addEventListener('input', () => { this.clearPreview(); }); // WiFi inputs document.getElementById('wifi-ssid').addEventListener('input', () => { this.clearPreview(); }); document.getElementById('wifi-password').addEventListener('input', () => { this.clearPreview(); }); document.getElementById('wifi-security').addEventListener('change', () => { this.clearPreview(); }); document.getElementById('wifi-hidden').addEventListener('change', () => { this.clearPreview(); }); // SMS inputs document.getElementById('sms-number').addEventListener('input', () => { this.clearPreview(); }); document.getElementById('sms-message').addEventListener('input', () => { this.clearPreview(); }); } setActiveTab(type) { this.currentType = type; // Update tab buttons document.querySelectorAll('.tab-btn').forEach(btn => { btn.classList.remove('active'); }); document.querySelector(`[data-type="${type}"]`).classList.add('active'); // Update content forms document.querySelectorAll('.content-form').forEach(form => { form.classList.remove('active'); }); document.getElementById(`${type}-form`).classList.add('active'); // Clear current QR code this.clearPreview(); } updateSizeDisplay() { const size = document.getElementById('qr-size').value; document.querySelector('.size-value').textContent = `${size}px`; } autoGenerate() { const content = this.getContentData(); if (content && content.trim()) { this.generateQRCode(); } else { this.clearPreview(); } } getContentData() { switch (this.currentType) { case 'url': return document.getElementById('url-input').value; case 'text': return document.getElementById('text-input').value; case 'email': const email = document.getElementById('email-input').value; const subject = document.getElementById('email-subject').value; const body = document.getElementById('email-body').value; if (!email) return ''; let mailto = `mailto:${email}`; const params = []; if (subject) params.push(`subject=${encodeURIComponent(subject)}`); if (body) params.push(`body=${encodeURIComponent(body)}`); if (params.length > 0) mailto += `?${params.join('&')}`; return mailto; case 'phone': const phone = document.getElementById('phone-input').value; return phone ? `tel:${phone}` : ''; case 'wifi': const ssid = document.getElementById('wifi-ssid').value; const password = document.getElementById('wifi-password').value; const security = document.getElementById('wifi-security').value; const hidden = document.getElementById('wifi-hidden').checked; if (!ssid) return ''; return `WIFI:T:${security};S:${ssid};P:${password};H:${hidden ? 'true' : 'false'};;`; case 'sms': const smsNumber = document.getElementById('sms-number').value; const smsMessage = document.getElementById('sms-message').value; if (!smsNumber) return ''; let sms = `sms:${smsNumber}`; if (smsMessage) sms += `?body=${encodeURIComponent(smsMessage)}`; return sms; default: return ''; } } async generateQRCode() { const content = this.getContentData(); if (!content || !content.trim()) { this.showToast('Please enter content to generate QR code', 'error'); return; } this.showLoading(true); try { const qrUrl = this.buildQRUrl(content); await this.displayQRCode(qrUrl); this.currentQRUrl = qrUrl; // Enable download button document.getElementById('download-btn').disabled = false; this.showToast('QR code generated successfully!', 'success'); } catch (error) { console.error('Error generating QR code:', error); this.showToast('Failed to generate QR code. Please try again.', 'error'); } finally { this.showLoading(false); } } buildQRUrl(content) { const size = document.getElementById('qr-size').value; const fgColor = document.getElementById('fg-color').value.replace('#', ''); const bgColor = document.getElementById('bg-color').value.replace('#', ''); const errorCorrection = document.getElementById('error-correction').value; const format = document.getElementById('output-format').value; const params = new URLSearchParams({ cht: 'qr', chs: `${size}x${size}`, chl: content, choe: 'UTF-8', chld: `${errorCorrection}|2`, icqrf: fgColor, icqrb: bgColor }); if (format === 'svg') { params.append('chof', '.svg'); } return `https://image-charts.com/chart?${params.toString()}`; } async displayQRCode(url) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { const preview = document.getElementById('qr-preview'); preview.innerHTML = ''; preview.appendChild(img); preview.classList.add('has-qr'); resolve(); }; img.onerror = () => { reject(new Error('Failed to load QR code image')); }; img.src = url; img.alt = 'Generated QR Code'; img.style.maxWidth = '100%'; img.style.height = 'auto'; }); } clearPreview() { const preview = document.getElementById('qr-preview'); preview.innerHTML = `

Enter content to generate QR code

`; preview.classList.remove('has-qr'); // Disable download button document.getElementById('download-btn').disabled = true; this.currentQRUrl = null; } async downloadQRCode() { if (!this.currentQRUrl) { this.showToast('No QR code to download', 'error'); return; } try { const format = document.getElementById('output-format').value; const response = await fetch(this.currentQRUrl); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `qrcode.${format}`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); this.showToast('QR code downloaded successfully!', 'success'); } catch (error) { console.error('Error downloading QR code:', error); this.showToast('Failed to download QR code', 'error'); } } showLoading(show) { const overlay = document.getElementById('loading-overlay'); if (show) { overlay.classList.add('show'); } else { overlay.classList.remove('show'); } } showToast(message, type = 'info') { const container = document.getElementById('toast-container'); const toast = document.createElement('div'); toast.className = `toast ${type}`; const icon = type === 'success' ? 'fas fa-check-circle' : type === 'error' ? 'fas fa-exclamation-circle' : 'fas fa-info-circle'; toast.innerHTML = ` ${message} `; container.appendChild(toast); // Auto remove after 3 seconds setTimeout(() => { if (toast.parentNode) { toast.parentNode.removeChild(toast); } }, 3000); } debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Validation methods isValidUrl(string) { try { new URL(string); return true; } catch (_) { return false; } } isValidEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } isValidPhone(phone) { const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/; return phoneRegex.test(phone.replace(/[\s\-\(\)]/g, '')); } // Enhanced validation for different content types validateContent() { const content = this.getContentData(); switch (this.currentType) { case 'url': if (content && !this.isValidUrl(content)) { this.showToast('Please enter a valid URL', 'error'); return false; } break; case 'email': const email = document.getElementById('email-input').value; if (email && !this.isValidEmail(email)) { this.showToast('Please enter a valid email address', 'error'); return false; } break; case 'phone': const phone = document.getElementById('phone-input').value; if (phone && !this.isValidPhone(phone)) { this.showToast('Please enter a valid phone number', 'error'); return false; } break; case 'sms': const smsPhone = document.getElementById('sms-number').value; if (smsPhone && !this.isValidPhone(smsPhone)) { this.showToast('Please enter a valid phone number', 'error'); return false; } break; } return true; } } // Utility functions function formatPhoneNumber(phone) { // Remove all non-digit characters except + const cleaned = phone.replace(/[^\d\+]/g, ''); return cleaned; } function escapeHtml(text) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>"']/g, m => map[m]); } // Initialize the application when DOM is loaded document.addEventListener('DOMContentLoaded', () => { const qrGenerator = new QRGenerator(); // Add some sample data for demonstration const urlInput = document.getElementById('url-input'); if (urlInput) { urlInput.placeholder = 'https://example.com'; } // Add keyboard shortcuts document.addEventListener('keydown', (e) => { // Ctrl/Cmd + Enter to generate if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); qrGenerator.generateQRCode(); } // Ctrl/Cmd + D to download if ((e.ctrlKey || e.metaKey) && e.key === 'd') { e.preventDefault(); if (!document.getElementById('download-btn').disabled) { qrGenerator.downloadQRCode(); } } }); // Add focus management for better accessibility document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); btn.click(); } }); }); // Add form validation on submit document.querySelectorAll('.form-input, .form-textarea').forEach(input => { input.addEventListener('blur', () => { qrGenerator.validateContent(); }); }); // Add drag and drop functionality for future logo upload feature const previewArea = document.getElementById('qr-preview'); previewArea.addEventListener('dragover', (e) => { e.preventDefault(); previewArea.style.borderColor = 'var(--primary-color)'; }); previewArea.addEventListener('dragleave', (e) => { e.preventDefault(); previewArea.style.borderColor = ''; }); // Add print functionality window.addEventListener('beforeprint', () => { document.body.classList.add('printing'); }); window.addEventListener('afterprint', () => { document.body.classList.remove('printing'); }); // Add service worker for offline functionality (future enhancement) if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js').catch(err => { console.log('Service worker registration failed:', err); }); } console.log('QR Generator initialized successfully!'); });