Add massive collection of CSS, JavaScript and theme assets that were previously excluded: **CSS Files (681 total):** - HVAC plugin-specific styles (hvac-*.css): 34 files including dashboard, certificates, registration, mobile nav, accessibility fixes, animations, and welcome popup - Theme framework files (Astra, builder systems, layouts): 200+ files - Plugin compatibility styles (WooCommerce, WPForms, Elementor, Contact Form 7): 150+ files - WordPress core and editor styles: 50+ files - Responsive and RTL language support: 200+ files **JavaScript Files (400+ total):** - HVAC plugin functionality (hvac-*.js): 27 files including menu systems, dashboard enhancements, profile sharing, mobile responsive features, accessibility, and animations - Framework and library files: jQuery plugins, GSAP, AOS, Swiper, Chart.js, Lottie, Isotope - Plugin compatibility scripts: WPForms, WooCommerce, Elementor, Contact Form 7, LifterLMS - WordPress core functionality: customizer, admin, block editor compatibility - Third-party integrations: Stripe, SMTP, analytics, search functionality **Assets:** - Certificate background images and logos - Comprehensive theme styling infrastructure - Mobile-responsive design systems - Cross-browser compatibility assets - Performance-optimized minified versions **Updated .gitignore:** - Fixed asset directory whitelisting patterns to properly include CSS/JS/images - Added proper directory structure recognition (!/assets/css/, !/assets/js/, etc.) - Maintains security by excluding sensitive files while including essential assets This commit provides the complete frontend infrastructure needed for: - Full theme functionality and styling - Plugin feature implementations - Mobile responsiveness and accessibility - Cross-browser compatibility - Performance optimization - Developer workflow support
409 lines
No EOL
14 KiB
JavaScript
409 lines
No EOL
14 KiB
JavaScript
/**
|
||
* HVAC Community Events: UX Enhancements JavaScript
|
||
*
|
||
* Modern user experience enhancements including toast notifications,
|
||
* loading states, and improved error handling.
|
||
*
|
||
* @version 1.0.0
|
||
*/
|
||
|
||
(function($) {
|
||
'use strict';
|
||
|
||
/**
|
||
* Toast Notification System
|
||
*/
|
||
const HVACToast = {
|
||
container: null,
|
||
|
||
init: function() {
|
||
// Create toast container if it doesn't exist
|
||
if (!this.container) {
|
||
this.container = $('<div class="hvac-toast-container"></div>');
|
||
$('body').append(this.container);
|
||
}
|
||
},
|
||
|
||
show: function(message, type = 'info', title = '', duration = 5000) {
|
||
this.init();
|
||
|
||
const toastId = 'hvac-toast-' + Date.now();
|
||
const toast = $(`
|
||
<div class="hvac-toast ${type}" id="${toastId}">
|
||
<div class="hvac-toast-icon"></div>
|
||
<div class="hvac-toast-content">
|
||
${title ? `<div class="hvac-toast-title">${title}</div>` : ''}
|
||
<div class="hvac-toast-message">${message}</div>
|
||
</div>
|
||
<button class="hvac-toast-close" type="button" aria-label="Close notification">×</button>
|
||
</div>
|
||
`);
|
||
|
||
// Add event listeners
|
||
toast.find('.hvac-toast-close').on('click', () => this.hide(toastId));
|
||
|
||
// Add to container and show
|
||
this.container.append(toast);
|
||
|
||
// Trigger show animation
|
||
setTimeout(() => toast.addClass('show'), 10);
|
||
|
||
// Auto-hide after duration
|
||
if (duration > 0) {
|
||
setTimeout(() => this.hide(toastId), duration);
|
||
}
|
||
|
||
return toastId;
|
||
},
|
||
|
||
hide: function(toastId) {
|
||
const toast = $('#' + toastId);
|
||
if (toast.length) {
|
||
toast.addClass('hiding');
|
||
setTimeout(() => toast.remove(), 300);
|
||
}
|
||
},
|
||
|
||
success: function(message, title = 'Success', duration = 4000) {
|
||
return this.show(message, 'success', title, duration);
|
||
},
|
||
|
||
error: function(message, title = 'Error', duration = 7000) {
|
||
return this.show(message, 'error', title, duration);
|
||
},
|
||
|
||
warning: function(message, title = 'Warning', duration = 6000) {
|
||
return this.show(message, 'warning', title, duration);
|
||
},
|
||
|
||
info: function(message, title = '', duration = 5000) {
|
||
return this.show(message, 'info', title, duration);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Loading State Manager
|
||
*/
|
||
const HVACLoading = {
|
||
overlay: null,
|
||
|
||
showOverlay: function(message = 'Loading...') {
|
||
this.hideOverlay(); // Remove existing overlay
|
||
|
||
this.overlay = $(`
|
||
<div class="hvac-loading-overlay">
|
||
<div class="hvac-loading">
|
||
<div class="hvac-spinner large"></div>
|
||
<span>${message}</span>
|
||
</div>
|
||
</div>
|
||
`);
|
||
|
||
$('body').append(this.overlay);
|
||
},
|
||
|
||
hideOverlay: function() {
|
||
if (this.overlay) {
|
||
this.overlay.remove();
|
||
this.overlay = null;
|
||
}
|
||
},
|
||
|
||
showButton: function(button, text = 'Loading...') {
|
||
const $btn = $(button);
|
||
$btn.addClass('loading').prop('disabled', true);
|
||
$btn.data('original-text', $btn.text());
|
||
if (text) {
|
||
$btn.attr('aria-label', text);
|
||
}
|
||
},
|
||
|
||
hideButton: function(button) {
|
||
const $btn = $(button);
|
||
$btn.removeClass('loading').prop('disabled', false);
|
||
const originalText = $btn.data('original-text');
|
||
if (originalText) {
|
||
$btn.text(originalText).removeData('original-text');
|
||
}
|
||
$btn.removeAttr('aria-label');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Enhanced AJAX Handler
|
||
*/
|
||
const HVACAjax = {
|
||
request: function(options) {
|
||
const defaults = {
|
||
type: 'POST',
|
||
dataType: 'json',
|
||
timeout: 30000,
|
||
showLoading: true,
|
||
loadingMessage: 'Processing...',
|
||
showToasts: true,
|
||
beforeSend: function() {
|
||
if (options.showLoading && options.button) {
|
||
HVACLoading.showButton(options.button, options.loadingMessage);
|
||
} else if (options.showLoading && options.showOverlay) {
|
||
HVACLoading.showOverlay(options.loadingMessage);
|
||
}
|
||
},
|
||
complete: function() {
|
||
if (options.showLoading && options.button) {
|
||
HVACLoading.hideButton(options.button);
|
||
} else if (options.showLoading && options.showOverlay) {
|
||
HVACLoading.hideOverlay();
|
||
}
|
||
},
|
||
success: function(response) {
|
||
if (options.showToasts) {
|
||
if (response.success) {
|
||
const message = response.data?.message || 'Operation completed successfully';
|
||
HVACToast.success(message);
|
||
} else {
|
||
const message = response.data?.message || 'Operation failed';
|
||
HVACToast.error(message);
|
||
}
|
||
}
|
||
},
|
||
error: function(xhr, status, error) {
|
||
console.error('AJAX Error:', {xhr, status, error});
|
||
|
||
if (options.showToasts) {
|
||
let message = 'An unexpected error occurred. Please try again.';
|
||
|
||
if (status === 'timeout') {
|
||
message = 'Request timed out. Please check your connection and try again.';
|
||
} else if (status === 'abort') {
|
||
message = 'Request was cancelled.';
|
||
} else if (xhr.status === 403) {
|
||
message = 'You do not have permission to perform this action.';
|
||
} else if (xhr.status === 404) {
|
||
message = 'The requested resource was not found.';
|
||
} else if (xhr.status >= 500) {
|
||
message = 'Server error. Please try again later.';
|
||
}
|
||
|
||
HVACToast.error(message, 'Connection Error');
|
||
}
|
||
}
|
||
};
|
||
|
||
const settings = $.extend({}, defaults, options);
|
||
return $.ajax(settings);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Form Validation Enhancement
|
||
*/
|
||
const HVACValidation = {
|
||
validateField: function(field, rules = []) {
|
||
const $field = $(field);
|
||
const value = $field.val().trim();
|
||
let isValid = true;
|
||
let errorMessage = '';
|
||
|
||
// Remove existing error states
|
||
$field.removeClass('error');
|
||
$field.siblings('.hvac-field-error').remove();
|
||
|
||
// Check rules
|
||
for (const rule of rules) {
|
||
if (rule.required && !value) {
|
||
isValid = false;
|
||
errorMessage = rule.message || 'This field is required';
|
||
break;
|
||
}
|
||
|
||
if (rule.minLength && value.length < rule.minLength) {
|
||
isValid = false;
|
||
errorMessage = rule.message || `Must be at least ${rule.minLength} characters`;
|
||
break;
|
||
}
|
||
|
||
if (rule.pattern && !rule.pattern.test(value)) {
|
||
isValid = false;
|
||
errorMessage = rule.message || 'Invalid format';
|
||
break;
|
||
}
|
||
|
||
if (rule.custom && typeof rule.custom === 'function') {
|
||
const result = rule.custom(value);
|
||
if (result !== true) {
|
||
isValid = false;
|
||
errorMessage = result || 'Invalid value';
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!isValid) {
|
||
$field.addClass('error');
|
||
$field.after(`<div class="hvac-field-error">${errorMessage}</div>`);
|
||
}
|
||
|
||
return isValid;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Mobile Navigation Enhancement
|
||
*/
|
||
const HVACMobile = {
|
||
init: function() {
|
||
this.setupMobileNav();
|
||
this.setupTouchOptimizations();
|
||
},
|
||
|
||
setupMobileNav: function() {
|
||
// Create mobile navigation if not exists
|
||
$('.hvac-dashboard-nav').each(function() {
|
||
const $nav = $(this);
|
||
if ($nav.siblings('.hvac-mobile-nav-container').length === 0) {
|
||
const mobileNav = $(`
|
||
<div class="hvac-mobile-nav-container">
|
||
<button class="hvac-mobile-nav-toggle" type="button" aria-expanded="false">
|
||
<span class="hvac-sr-only">Toggle navigation</span>
|
||
Navigation Menu
|
||
</button>
|
||
<nav class="hvac-mobile-nav">
|
||
<ul></ul>
|
||
</nav>
|
||
</div>
|
||
`);
|
||
|
||
// Copy nav items to mobile menu
|
||
const $mobileList = mobileNav.find('ul');
|
||
$nav.find('a').each(function() {
|
||
const $link = $(this).clone();
|
||
$mobileList.append($('<li>').append($link));
|
||
});
|
||
|
||
$nav.before(mobileNav);
|
||
|
||
// Add toggle functionality
|
||
mobileNav.find('.hvac-mobile-nav-toggle').on('click', function() {
|
||
const $toggle = $(this);
|
||
const $menu = $toggle.siblings('.hvac-mobile-nav');
|
||
const isOpen = $menu.hasClass('open');
|
||
|
||
$toggle.toggleClass('active').attr('aria-expanded', !isOpen);
|
||
$menu.toggleClass('open');
|
||
});
|
||
}
|
||
});
|
||
},
|
||
|
||
setupTouchOptimizations: function() {
|
||
// Add touch-friendly classes
|
||
$('button, .hvac-btn, input[type="submit"]').addClass('hvac-touch-target');
|
||
|
||
// Prevent double-tap zoom on buttons
|
||
$('button, .hvac-btn').on('touchend', function(e) {
|
||
e.preventDefault();
|
||
$(this).trigger('click');
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Accessibility Enhancements
|
||
*/
|
||
const HVACAccessibility = {
|
||
init: function() {
|
||
this.setupKeyboardNavigation();
|
||
this.setupAriaLabels();
|
||
},
|
||
|
||
setupKeyboardNavigation: function() {
|
||
// Escape key to close modals/overlays
|
||
$(document).on('keydown', function(e) {
|
||
if (e.key === 'Escape') {
|
||
// Close any open mobile nav
|
||
$('.hvac-mobile-nav.open').removeClass('open');
|
||
$('.hvac-mobile-nav-toggle.active').removeClass('active').attr('aria-expanded', 'false');
|
||
|
||
// Hide loading overlay
|
||
HVACLoading.hideOverlay();
|
||
}
|
||
});
|
||
},
|
||
|
||
setupAriaLabels: function() {
|
||
// Add missing aria-labels to buttons without text
|
||
$('button:not([aria-label])').each(function() {
|
||
const $btn = $(this);
|
||
const text = $btn.text().trim();
|
||
if (!text) {
|
||
const title = $btn.attr('title');
|
||
if (title) {
|
||
$btn.attr('aria-label', title);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Replace all alert() calls with toast notifications
|
||
*/
|
||
function replaceAlerts() {
|
||
// Override the global alert function
|
||
window.hvacOriginalAlert = window.alert;
|
||
window.alert = function(message) {
|
||
// Determine type based on message content
|
||
const lowerMessage = message.toLowerCase();
|
||
if (lowerMessage.includes('success') || lowerMessage.includes('sent') || lowerMessage.includes('saved')) {
|
||
HVACToast.success(message);
|
||
} else if (lowerMessage.includes('error') || lowerMessage.includes('failed') || lowerMessage.includes('fail')) {
|
||
HVACToast.error(message);
|
||
} else {
|
||
HVACToast.info(message);
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Initialize everything when document is ready
|
||
*/
|
||
$(document).ready(function() {
|
||
// Initialize all modules
|
||
HVACToast.init();
|
||
HVACMobile.init();
|
||
HVACAccessibility.init();
|
||
|
||
// Replace alert functions
|
||
replaceAlerts();
|
||
|
||
// Make modules globally available
|
||
window.HVACToast = HVACToast;
|
||
window.HVACLoading = HVACLoading;
|
||
window.HVACAjax = HVACAjax;
|
||
window.HVACValidation = HVACValidation;
|
||
|
||
// Auto-enhance existing forms
|
||
$('form').each(function() {
|
||
const $form = $(this);
|
||
|
||
// Add loading states to submit buttons
|
||
$form.on('submit', function() {
|
||
const $submitBtn = $form.find('input[type="submit"], button[type="submit"]').first();
|
||
if ($submitBtn.length) {
|
||
HVACLoading.showButton($submitBtn);
|
||
}
|
||
});
|
||
});
|
||
|
||
// Add responsive table wrapper
|
||
$('table').each(function() {
|
||
const $table = $(this);
|
||
if (!$table.parent().hasClass('hvac-table-responsive')) {
|
||
$table.wrap('<div class="hvac-table-responsive"></div>');
|
||
}
|
||
});
|
||
|
||
console.log('HVAC UX Enhancements initialized');
|
||
});
|
||
|
||
})(jQuery); |