/** * HVAC Announcements View Handler * Handles modal popup for viewing announcements * * @package HVAC_Community_Events */ jQuery(document).ready(function($) { 'use strict'; // Cache DOM elements var $modal = $('#announcement-modal'); var $modalContent = $modal.find('.modal-body'); var $modalClose = $modal.find('.modal-close'); var isLoading = false; // Handle announcement link clicks $(document).on('click', '.announcement-link', function(e) { e.preventDefault(); if (isLoading) { return; } var announcementId = $(this).data('id'); if (!announcementId) { console.error('No announcement ID found'); return; } openAnnouncementModal(announcementId); }); // Handle modal close button $modalClose.on('click', function() { closeModal(); }); // Close modal when clicking outside $modal.on('click', function(e) { if (e.target === this) { closeModal(); } }); // Close modal with ESC key $(document).on('keydown', function(e) { if (e.key === 'Escape' && $modal.is(':visible')) { closeModal(); } }); /** * Open announcement in modal */ function openAnnouncementModal(announcementId) { isLoading = true; // Show modal with loading state $modalContent.html(''); $modal.fadeIn(300); // Prevent body scroll $('body').addClass('modal-open'); // Make AJAX request to get announcement content $.ajax({ url: hvac_ajax.ajax_url, type: 'POST', data: { action: 'hvac_view_announcement', id: announcementId, nonce: hvac_ajax.nonce }, success: function(response) { if (response.success && response.data.content) { $modalContent.html(response.data.content); // Focus on modal for accessibility $modal.attr('aria-hidden', 'false'); $modalContent.focus(); } else { var errorMsg = response.data || 'Failed to load announcement'; $modalContent.html(''); } }, error: function(xhr, status, error) { console.error('AJAX error:', error); $modalContent.html(''); }, complete: function() { isLoading = false; } }); } /** * Close modal */ function closeModal() { $modal.fadeOut(300, function() { $modalContent.empty(); $('body').removeClass('modal-open'); $modal.attr('aria-hidden', 'true'); }); } /** * Handle Load More button for timeline */ $(document).on('click', '.load-more-announcements', function(e) { e.preventDefault(); var $button = $(this); var currentPage = parseInt($button.data('page')); var maxPages = parseInt($button.data('max')); if (currentPage > maxPages) { return; } $button.prop('disabled', true).text('Loading...'); $.ajax({ url: hvac_ajax.ajax_url, type: 'POST', data: { action: 'hvac_get_announcements', page: currentPage, per_page: 10, status: 'publish', nonce: hvac_ajax.nonce }, success: function(response) { if (response.success && response.data.announcements) { var announcements = response.data.announcements; var $timeline = $('.timeline-wrapper'); // Append new announcements to timeline announcements.forEach(function(announcement) { var html = buildAnnouncementItem(announcement); $timeline.append(html); }); // Update button if (currentPage >= maxPages) { $button.parent().remove(); } else { $button.data('page', currentPage + 1); $button.prop('disabled', false).text('Load More Announcements'); } } }, error: function() { $button.prop('disabled', false).text('Load More Announcements'); alert('Error loading more announcements. Please try again.'); } }); }); /** * Build announcement item HTML */ function buildAnnouncementItem(announcement) { var html = '
'; html += '
'; html += '
'; html += '
'; html += '

'; // Ensure ID is numeric to prevent attribute injection html += ''; html += escapeHtml(announcement.title); html += ''; html += '

'; html += '
'; html += '' + formatDate(announcement.date) + ''; html += '' + escapeHtml(announcement.author) + ''; html += '
'; html += '
'; if (announcement.featured_image) { html += '
'; // Safely build image element var imgSrc = String(announcement.featured_image || '').replace(/"/g, '"'); html += ''; html += '
'; } if (announcement.excerpt) { // Excerpt is pre-sanitized server-side with wp_kses_post, safe to insert as HTML html += '
' + announcement.excerpt + '
'; } if (announcement.categories && announcement.categories.length > 0) { html += '
'; announcement.categories.forEach(function(category) { html += '' + escapeHtml(category) + ''; }); html += '
'; } html += '
'; html += '
'; return html; } /** * Format date string */ function formatDate(dateString) { var date = new Date(dateString); var options = { year: 'numeric', month: 'long', day: 'numeric' }; return date.toLocaleDateString('en-US', options); } /** * Escape HTML for security */ function escapeHtml(text) { var map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>"']/g, function(m) { return map[m]; }); } });