upskill-event-manager/assets/js/hvac-ux-enhancements.js
Ben Reed cdc5ea85f4 feat: Add comprehensive CSS, JavaScript and theme asset infrastructure
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
2025-08-11 16:20:31 -03:00

409 lines
No EOL
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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);