/** * HVAC TEC Tickets Interactive JavaScript * Handles all UI/UX interactions for the enhanced event form */ (function($) { 'use strict'; // Global state management window.HVACEventForm = { selectedOrganizers: [], selectedCategories: [], selectedVenue: null, richTextEditors: {}, init: function() { this.initRichTextEditor(); this.initToggleSwitches(); this.initFeaturedImageUploader(); this.initSearchableSelectors(); this.initModalForms(); this.bindEvents(); }, // Rich Text Editor Functionality initRichTextEditor: function() { const editorWrapper = document.getElementById('event-description-editor-wrapper'); if (!editorWrapper) return; const editor = document.getElementById('event-description-editor'); const hiddenTextarea = document.getElementById('event_description'); const toolbar = document.getElementById('event-description-toolbar'); if (!editor || !hiddenTextarea || !toolbar) return; // Initialize editor this.richTextEditors.description = { editor: editor, textarea: hiddenTextarea, toolbar: toolbar }; // Bind toolbar events $(toolbar).on('click', 'button', function(e) { e.preventDefault(); const command = $(this).data('command'); const value = $(this).data('value') || null; document.execCommand(command, false, value); HVACEventForm.updateToolbarState(); HVACEventForm.syncEditorContent(); }); // Sync content changes editor.addEventListener('input', () => { this.syncEditorContent(); }); editor.addEventListener('keyup', () => { this.updateToolbarState(); }); editor.addEventListener('mouseup', () => { this.updateToolbarState(); }); // Load existing content with XSS protection if (hiddenTextarea.value) { const cleanContent = DOMPurify.sanitize(hiddenTextarea.value, { ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li', 'a'], ALLOWED_ATTR: ['href', 'title'], ALLOW_DATA_ATTR: false }); editor.innerHTML = cleanContent; } }, syncEditorContent: function() { const editor = this.richTextEditors.description?.editor; const textarea = this.richTextEditors.description?.textarea; if (editor && textarea) { // Sanitize content before storing in textarea to prevent XSS const cleanContent = DOMPurify.sanitize(editor.innerHTML, { ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li', 'a'], ALLOWED_ATTR: ['href', 'title'], ALLOW_DATA_ATTR: false }); textarea.value = cleanContent; } }, updateToolbarState: function() { const toolbar = this.richTextEditors.description?.toolbar; if (!toolbar) return; $(toolbar).find('button').each(function() { const command = $(this).data('command'); if (document.queryCommandState(command)) { $(this).addClass('active'); } else { $(this).removeClass('active'); } }); }, // Toggle Switch Functionality initToggleSwitches: function() { // Virtual Event Toggle $(document).on('change', 'input[name="enable_virtual_event"]', function() { const isChecked = $(this).is(':checked'); $('.virtual-event-config').toggle(isChecked); }); // RSVP Toggle $(document).on('change', 'input[name="enable_rsvp"]', function() { const isChecked = $(this).is(':checked'); $('.rsvp-config').toggle(isChecked); }); // Ticketing Toggle (existing functionality) window.hvacToggleTicketFields = function(enabled) { $('.ticket-config-field').toggle(enabled); }; }, // Featured Image Uploader initFeaturedImageUploader: function() { const uploadArea = document.getElementById('upload-area'); const fileInput = document.getElementById('featured-image-file'); const preview = document.getElementById('featured-image-preview'); const uploader = document.getElementById('featured-image-uploader'); const img = document.getElementById('featured-image-img'); const changeBtn = document.getElementById('change-featured-image'); const removeBtn = document.getElementById('remove-featured-image'); if (!uploadArea || !fileInput) return; // Click to upload uploadArea.addEventListener('click', () => { fileInput.click(); }); // Drag and drop uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('dragover'); }); uploadArea.addEventListener('dragleave', () => { uploadArea.classList.remove('dragover'); }); uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); const files = e.dataTransfer.files; if (files.length > 0) { this.handleImageUpload(files[0]); } }); // File input change fileInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { this.handleImageUpload(e.target.files[0]); } }); // Change image button if (changeBtn) { changeBtn.addEventListener('click', () => { fileInput.click(); }); } // Remove image button if (removeBtn) { removeBtn.addEventListener('click', () => { this.removeFeaturedImage(); }); } }, handleImageUpload: function(file) { if (!file.type.startsWith('image/')) { alert('Please select a valid image file.'); return; } if (file.size > 5 * 1024 * 1024) { // 5MB limit alert('Image file size should be less than 5MB.'); return; } const reader = new FileReader(); reader.onload = (e) => { const img = document.getElementById('featured-image-img'); const preview = document.getElementById('featured-image-preview'); const uploader = document.getElementById('featured-image-uploader'); const hiddenInput = document.getElementById('featured-image-data'); img.src = e.target.result; preview.style.display = 'block'; uploader.style.display = 'none'; // Store image data for form submission if (hiddenInput) { hiddenInput.value = e.target.result; } }; reader.readAsDataURL(file); }, removeFeaturedImage: function() { const preview = document.getElementById('featured-image-preview'); const uploader = document.getElementById('featured-image-uploader'); const hiddenInput = document.getElementById('featured-image-data'); const fileInput = document.getElementById('featured-image-file'); preview.style.display = 'none'; uploader.style.display = 'block'; if (hiddenInput) hiddenInput.value = ''; if (fileInput) fileInput.value = ''; }, // Searchable Selector Components initSearchableSelectors: function() { this.initOrganizerSelector(); this.initCategoriesSelector(); this.initVenueSelector(); }, initOrganizerSelector: function() { const searchInput = document.getElementById('organizer-search-input'); const resultsContainer = document.getElementById('organizer-search-results'); const selectedContainer = document.getElementById('organizer-selected-items'); const dropdownToggle = searchInput?.parentElement?.querySelector('.dropdown-toggle'); if (!searchInput || !resultsContainer) return; // Search input events searchInput.addEventListener('focus', () => { this.loadOrganizerOptions(); resultsContainer.style.display = 'block'; }); searchInput.addEventListener('input', (e) => { this.filterOrganizerOptions(e.target.value); }); // Dropdown toggle if (dropdownToggle) { dropdownToggle.addEventListener('click', () => { if (resultsContainer.style.display === 'none') { this.loadOrganizerOptions(); resultsContainer.style.display = 'block'; searchInput.focus(); } else { resultsContainer.style.display = 'none'; } }); } // Click outside to close document.addEventListener('click', (e) => { if (!searchInput.parentElement.contains(e.target)) { resultsContainer.style.display = 'none'; } }); // Create new organizer button $(document).on('click', '#create-new-organizer .create-new-btn', () => { this.openModal('#new-organizer-modal'); }); }, initCategoriesSelector: function() { const searchInput = document.getElementById('categories-search-input'); const resultsContainer = document.getElementById('categories-search-results'); const dropdownToggle = searchInput?.parentElement?.querySelector('.dropdown-toggle'); if (!searchInput || !resultsContainer) return; searchInput.addEventListener('focus', () => { this.loadCategoriesOptions(); resultsContainer.style.display = 'block'; }); searchInput.addEventListener('input', (e) => { this.filterCategoriesOptions(e.target.value); }); if (dropdownToggle) { dropdownToggle.addEventListener('click', () => { if (resultsContainer.style.display === 'none') { this.loadCategoriesOptions(); resultsContainer.style.display = 'block'; searchInput.focus(); } else { resultsContainer.style.display = 'none'; } }); } document.addEventListener('click', (e) => { if (!searchInput.parentElement.contains(e.target)) { resultsContainer.style.display = 'none'; } }); $(document).on('click', '#create-new-category .create-new-btn', () => { this.openModal('#new-category-modal'); }); }, initVenueSelector: function() { const searchInput = document.getElementById('venue-search-input'); const resultsContainer = document.getElementById('venue-search-results'); const dropdownToggle = searchInput?.parentElement?.querySelector('.dropdown-toggle'); if (!searchInput || !resultsContainer) return; searchInput.addEventListener('focus', () => { this.loadVenueOptions(); resultsContainer.style.display = 'block'; }); searchInput.addEventListener('input', (e) => { this.filterVenueOptions(e.target.value); }); if (dropdownToggle) { dropdownToggle.addEventListener('click', () => { if (resultsContainer.style.display === 'none') { this.loadVenueOptions(); resultsContainer.style.display = 'block'; searchInput.focus(); } else { resultsContainer.style.display = 'none'; } }); } document.addEventListener('click', (e) => { if (!searchInput.parentElement.contains(e.target)) { resultsContainer.style.display = 'none'; } }); $(document).on('click', '.create-new-btn', () => { this.openModal('#new-venue-modal'); }); }, // Load options from server loadOrganizerOptions: function() { // Mock data for now - replace with AJAX call const mockOrganizers = [ { id: 1, name: 'John Smith', email: 'john@example.com' }, { id: 2, name: 'Jane Doe', email: 'jane@example.com' }, { id: 3, name: 'HVAC Training Institute', email: 'info@hvactraining.com' } ]; this.renderOrganizerOptions(mockOrganizers); }, loadCategoriesOptions: function() { const mockCategories = [ { id: 1, name: 'HVAC Basics', description: 'Fundamental HVAC concepts' }, { id: 2, name: 'Advanced Systems', description: 'Complex HVAC systems' }, { id: 3, name: 'Safety Training', description: 'Safety protocols and procedures' } ]; this.renderCategoriesOptions(mockCategories); }, loadVenueOptions: function() { const mockVenues = [ { id: 1, name: 'Training Center A', address: '123 Main St, City, ST' }, { id: 2, name: 'Conference Hall B', address: '456 Oak Ave, City, ST' }, { id: 3, name: 'Community Center', address: '789 Pine Rd, City, ST' } ]; this.renderVenueOptions(mockVenues); }, renderOrganizerOptions: function(organizers) { const resultsList = document.getElementById('organizer-results-list'); if (!resultsList) return; resultsList.innerHTML = ''; organizers.forEach(organizer => { const item = document.createElement('div'); item.className = 'search-result-item'; item.innerHTML = `${organizer.name}
${organizer.email}`; item.addEventListener('click', () => { this.selectOrganizer(organizer); }); resultsList.appendChild(item); }); }, renderCategoriesOptions: function(categories) { const resultsList = document.getElementById('categories-results-list'); if (!resultsList) return; resultsList.innerHTML = ''; categories.forEach(category => { const item = document.createElement('div'); item.className = 'search-result-item'; item.innerHTML = `${category.name}
${category.description}`; item.addEventListener('click', () => { this.selectCategory(category); }); resultsList.appendChild(item); }); }, renderVenueOptions: function(venues) { const resultsList = document.querySelector('#venue-search-results .results-list'); if (!resultsList) return; resultsList.innerHTML = ''; venues.forEach(venue => { const item = document.createElement('div'); item.className = 'search-result-item'; item.innerHTML = `${venue.name}
${venue.address}`; item.addEventListener('click', () => { this.selectVenue(venue); }); resultsList.appendChild(item); }); }, // Selection handlers selectOrganizer: function(organizer) { if (this.selectedOrganizers.length >= 3) { alert('You can only select up to 3 organizers.'); return; } if (this.selectedOrganizers.find(o => o.id === organizer.id)) { return; // Already selected } this.selectedOrganizers.push(organizer); this.renderSelectedOrganizers(); document.getElementById('organizer-search-results').style.display = 'none'; document.getElementById('organizer-search-input').value = ''; }, selectCategory: function(category) { if (this.selectedCategories.length >= 3) { alert('You can only select up to 3 categories.'); return; } if (this.selectedCategories.find(c => c.id === category.id)) { return; } this.selectedCategories.push(category); this.renderSelectedCategories(); document.getElementById('categories-search-results').style.display = 'none'; document.getElementById('categories-search-input').value = ''; }, selectVenue: function(venue) { this.selectedVenue = venue; document.getElementById('venue-search-input').value = venue.name; document.getElementById('venue-search-results').style.display = 'none'; }, renderSelectedOrganizers: function() { const container = document.getElementById('organizer-selected-items'); if (!container) return; container.innerHTML = ''; this.selectedOrganizers.forEach((organizer, index) => { const tag = document.createElement('div'); tag.className = 'selected-item'; tag.innerHTML = ` ${organizer.name} `; container.appendChild(tag); }); // Update hidden input const hiddenInput = document.getElementById('event_organizer'); if (hiddenInput) { hiddenInput.value = this.selectedOrganizers.map(o => o.id).join(','); } }, renderSelectedCategories: function() { const container = document.getElementById('categories-selected-items'); if (!container) return; container.innerHTML = ''; this.selectedCategories.forEach((category, index) => { const tag = document.createElement('div'); tag.className = 'selected-item'; tag.innerHTML = ` ${category.name} `; container.appendChild(tag); }); const hiddenInput = document.getElementById('event_categories'); if (hiddenInput) { hiddenInput.value = this.selectedCategories.map(c => c.id).join(','); } }, removeOrganizer: function(index) { this.selectedOrganizers.splice(index, 1); this.renderSelectedOrganizers(); }, removeCategory: function(index) { this.selectedCategories.splice(index, 1); this.renderSelectedCategories(); }, // Filter functions filterOrganizerOptions: function(query) { // In real implementation, this would make an AJAX call this.loadOrganizerOptions(); }, filterCategoriesOptions: function(query) { this.loadCategoriesOptions(); }, filterVenueOptions: function(query) { this.loadVenueOptions(); }, // Modal Management initModalForms: function() { // Modal close handlers $(document).on('click', '.hvac-modal-close, .hvac-modal-cancel', (e) => { this.closeModal($(e.target).closest('.hvac-modal')); }); // Save handlers $(document).on('click', '#save-new-organizer', () => { this.saveNewOrganizer(); }); $(document).on('click', '#save-new-category', () => { this.saveNewCategory(); }); $(document).on('click', '#save-new-venue', () => { this.saveNewVenue(); }); // Close on backdrop click $(document).on('click', '.hvac-modal', function(e) { if (e.target === this) { HVACEventForm.closeModal($(this)); } }); }, openModal: function(modalSelector) { $(modalSelector).fadeIn(300); // Focus first input setTimeout(() => { $(modalSelector).find('input:first').focus(); }, 300); }, closeModal: function(modal) { if (modal instanceof jQuery) { modal.fadeOut(300); // Clear form modal.find('form')[0]?.reset(); } else { $(modal).fadeOut(300); $(modal).find('form')[0]?.reset(); } }, saveNewOrganizer: function() { const form = document.getElementById('new-organizer-form'); const formData = new FormData(form); const name = formData.get('organizer_name'); if (!name.trim()) { alert('Organizer name is required.'); return; } // Create new organizer object const newOrganizer = { id: Date.now(), // Temporary ID name: name, email: formData.get('organizer_email') || '', organization: formData.get('organizer_organization') || '' }; // Add to selection this.selectOrganizer(newOrganizer); this.closeModal('#new-organizer-modal'); }, saveNewCategory: function() { const form = document.getElementById('new-category-form'); const formData = new FormData(form); const name = formData.get('category_name'); if (!name.trim()) { alert('Category name is required.'); return; } const newCategory = { id: Date.now(), name: name, description: formData.get('category_description') || '' }; this.selectCategory(newCategory); this.closeModal('#new-category-modal'); }, saveNewVenue: function() { const form = document.getElementById('new-venue-form'); const formData = new FormData(form); const name = formData.get('venue_name'); const address = formData.get('venue_address'); if (!name.trim() || !address.trim()) { alert('Venue name and address are required.'); return; } const newVenue = { id: Date.now(), name: name, address: address }; this.selectVenue(newVenue); this.closeModal('#new-venue-modal'); }, // Event binding bindEvents: function() { // Form submission $(document).on('submit', 'form', () => { this.syncEditorContent(); }); // Auto-save functionality (if needed) setInterval(() => { this.syncEditorContent(); }, 5000); } }; // Initialize when DOM is ready $(document).ready(function() { HVACEventForm.init(); }); })(jQuery);