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
		
			
				
	
	
		
			219 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| UAGBTabs = {
 | |
| 	init( $selector ) {
 | |
| 		const tabsWrap = document.querySelectorAll( $selector );
 | |
| 		if ( ! tabsWrap ) {
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		for ( let i = 0; i < tabsWrap.length; i++ ) {
 | |
| 			UAGBTabs.addEvents( tabsWrap[ i ], $selector );
 | |
| 		}
 | |
| 	},
 | |
| 	addEvents( tabsWrap, $selector ) {
 | |
| 		// Tabs wrap has two child elements, one is tabs list (.uagb-tabs__panel) and another is tabs body (.uagb-tabs__body-wrap).
 | |
| 		const tabsWrapChildren = tabsWrap.children;
 | |
| 
 | |
| 		// Verify if tabsWrapChildren has two child elements.
 | |
| 		if ( 2 !== tabsWrapChildren.length ) {
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		const tabActive = tabsWrap.getAttribute( 'data-tab-active' );
 | |
| 
 | |
| 		// Select tabs list (.uagb-tabs__panel) from tabsWrapChildren.
 | |
| 		const tabLi = tabsWrapChildren[0].querySelectorAll( 'li.uagb-tab' );
 | |
| 
 | |
| 		// Select tabs body (.uagb-tabs__body-wrap) from tabsWrapChildren and children will be tab body container (.uagb-tabs__body-container).
 | |
| 		const tabBody = tabsWrapChildren[1].children;
 | |
| 
 | |
| 		for ( let i = 0; i < tabBody.length; i++ ) {
 | |
| 			tabBody[ i ].setAttribute( 'tabindex', '0' );
 | |
| 			tabBody[ i ].setAttribute( 'role', 'tabpanel' );
 | |
| 		};
 | |
| 
 | |
| 		// Set initial active class to Tabs body.
 | |
| 		tabBody[ tabActive ].classList.add( 'uagb-tabs-body__active' );
 | |
| 
 | |
| 		// Set initial active class to Tabs li.
 | |
| 		tabLi[ tabActive ].classList.add( 'uagb-tabs__active' );
 | |
| 
 | |
| 		for ( let i = 0; i < tabLi.length; i++ ) {
 | |
| 			const tabsAnchor = tabLi[ i ].getElementsByTagName( 'a' )[ 0 ];
 | |
| 
 | |
| 			// Set initial li ids.
 | |
| 			tabLi[ i ].setAttribute( 'id', 'uagb-tabs__tab' + i );
 | |
| 
 | |
| 			// Set initial aria attributes true for anchor tags.
 | |
| 			tabsAnchor.setAttribute( 'aria-selected', true );
 | |
| 			// Selected tab gets tabindex="0".
 | |
| 			tabsAnchor.setAttribute( 'tabindex', '0' );
 | |
| 
 | |
| 			if ( ! tabLi[ i ].classList.contains( 'uagb-tabs__active' ) ) {
 | |
| 				// Set aria attributes for anchor tags as false where needed.
 | |
| 				tabsAnchor.setAttribute( 'aria-selected', false );
 | |
| 				// Other non selected tabs get tabindex="-1".
 | |
| 				tabsAnchor.setAttribute( 'tabindex', '-1' ); 
 | |
| 			}
 | |
| 
 | |
| 			// Set initial data attribute for anchor tags.
 | |
| 			tabsAnchor.setAttribute( 'data-tab', i );
 | |
| 
 | |
| 			tabsAnchor.mainWrapClass = $selector;
 | |
| 			// Add Click event listener
 | |
| 			tabsAnchor.addEventListener( 'click', function ( e ) {
 | |
| 				UAGBTabs.tabClickEvent( e, this, this.parentElement );
 | |
| 			} );
 | |
| 		}
 | |
| 
 | |
| 		// Enable arrow navigation between tabs in the tab list
 | |
| 		const tabsRole = tabsWrapChildren[0].querySelectorAll( '.uagb-tab a[role="tab"]' );
 | |
| 		
 | |
| 		tabsRole.forEach( tab => {
 | |
| 			tab.addEventListener( 'keydown', function ( e ) {
 | |
| 				let newIndex;
 | |
| 				const currentIndex = Array.prototype.indexOf.call( tabsRole, e.target );
 | |
| 
 | |
| 				if ( e.key === 'ArrowRight' ) {
 | |
| 					// Move to the next tab, loop back to the first if at the last
 | |
| 					newIndex = ( currentIndex + 1 ) % tabsRole.length;
 | |
| 					tabsRole[newIndex].focus();
 | |
| 					tabsRole[currentIndex].setAttribute( 'aria-selected', 'false' );
 | |
| 					tabsRole[newIndex].setAttribute( 'aria-selected', 'true' );
 | |
| 					UAGBTabs.tabClickEvent( e, tabsRole[newIndex], tabsRole[newIndex].parentElement );
 | |
| 					e.preventDefault();
 | |
| 				} else if ( e.key === 'ArrowLeft' ) {
 | |
| 					// Move to the previous tab, loop to the last if at the first
 | |
| 					newIndex = ( currentIndex - 1 + tabsRole.length ) % tabsRole.length;
 | |
| 					tabsRole[newIndex].focus();
 | |
| 					tabsRole[currentIndex].setAttribute( 'aria-selected', 'false' );
 | |
| 					tabsRole[newIndex].setAttribute( 'aria-selected', 'true' );
 | |
| 					UAGBTabs.tabClickEvent( e, tabsRole[newIndex], tabsRole[newIndex].parentElement );
 | |
| 					e.preventDefault();
 | |
| 				}
 | |
| 			} );
 | |
| 		} );
 | |
| 	},
 | |
| 	tabClickEvent( e, tabName, selectedLi ) {
 | |
| 		e.preventDefault();
 | |
| 
 | |
| 		const tabId = tabName.getAttribute( 'data-tab' );
 | |
| 		const tabPanel = selectedLi.closest( '.uagb-tabs__panel' );
 | |
| 
 | |
| 		const tabContainer = tabName.closest( '.uagb-tabs__wrap' );
 | |
| 
 | |
| 		const tabBodyWrap = tabContainer.querySelector( '.uagb-tabs__body-wrap' );
 | |
| 		
 | |
| 		const tabBodyChildren = tabBodyWrap.children;
 | |
| 		const tabSelectedBody = UAGBTabs.getChildrenWithClass( tabBodyChildren, 'uagb-inner-tab-' + tabId );
 | |
| 
 | |
| 		const allLi = tabPanel.querySelectorAll( 'a.uagb-tabs-list' );
 | |
| 
 | |
| 		// Remove old li active class.
 | |
| 		tabPanel.querySelector( '.uagb-tabs__active' )?.classList.remove( 'uagb-tabs__active' );
 | |
| 
 | |
| 		//Remove old tab body active class.
 | |
| 		UAGBTabs.getChildrenWithClass( tabBodyChildren, 'uagb-tabs-body__active' )?.classList.remove( 'uagb-tabs-body__active' );
 | |
| 
 | |
| 		// Set aria-selected attribute as false for old active tab.
 | |
| 		for ( let i = 0; i < allLi.length; i++ ) {
 | |
| 			allLi[ i ].setAttribute( 'aria-selected', false );
 | |
| 			// Other non selected tabs get tabindex="-1".
 | |
| 			allLi[i].setAttribute( 'tabindex', '-1' ); 
 | |
| 		}
 | |
| 
 | |
| 		// Set selected li active class.
 | |
| 		selectedLi.classList.add( 'uagb-tabs__active' );
 | |
| 
 | |
| 		// Set aria-selected attribute as true for new active tab.
 | |
| 		tabName.setAttribute( 'aria-selected', true );
 | |
| 
 | |
| 		// Selected tab gets tabindex="0".
 | |
| 		tabName.setAttribute( 'tabindex', '0' );
 | |
| 
 | |
| 		// Set selected tab body active class.
 | |
| 		tabSelectedBody?.classList.add( 'uagb-tabs-body__active' );
 | |
| 
 | |
| 		// Set aria-hidden attribute false for selected tab body.
 | |
| 		tabSelectedBody?.setAttribute( 'aria-hidden', false );
 | |
| 
 | |
| 		// Set aria-hidden attribute true for all unselected tab body.
 | |
| 		for ( let i = 0; i < tabBodyChildren.length; i++ ) {
 | |
| 			// If tabBodyChildren[i] has .uagb-inner-tab-' + tabId + ' then continue.
 | |
| 			if ( tabBodyChildren[ i ].classList.contains( 'uagb-inner-tab-' + tabId ) ) {
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			tabBodyChildren[ i ].setAttribute( 'aria-hidden', true );
 | |
| 		}
 | |
| 	},
 | |
| 	anchorTabId( $selector ) {
 | |
| 		const tabsHash = window.location.hash;
 | |
| 
 | |
| 		if ( '' !== tabsHash && /^#uagb-tabs__tab\d$/.test( tabsHash ) ) {
 | |
| 			const mainWrapClass = $selector;
 | |
| 			const tabId = escape( tabsHash.substring( 1 ) );
 | |
| 			const selectedLi = document.querySelector( '#' + tabId );
 | |
| 			const topPos = selectedLi.getBoundingClientRect().top + window.pageYOffset;
 | |
| 			window.scrollTo( {
 | |
| 				top: topPos,
 | |
| 				behavior: 'smooth',
 | |
| 			} );
 | |
| 			const tabNum = selectedLi.querySelector( 'a.uagb-tabs-list' ).getAttribute( 'data-tab' );
 | |
| 			const listPanel = selectedLi.closest( '.uagb-tabs__panel' );
 | |
| 			const tabSelectedBody = document.querySelector(
 | |
| 				mainWrapClass + ' > .uagb-tabs__body-wrap > .uagb-inner-tab-' + tabNum
 | |
| 			);
 | |
| 			const tabUnselectedBody = document.querySelectorAll(
 | |
| 				mainWrapClass +
 | |
| 					' > .uagb-tabs__body-wrap > .uagb-tabs__body-container:not(.uagb-inner-tab-' +
 | |
| 					tabNum +
 | |
| 					')'
 | |
| 			);
 | |
| 			const allLi = selectedLi.querySelectorAll( 'a.uagb-tabs-list' );
 | |
| 			const selectedAnchor = selectedLi.querySelector( 'a.uagb-tabs-list' );
 | |
| 
 | |
| 			// Remove old li active class.
 | |
| 			listPanel.querySelector( '.uagb-tabs__active' ).classList.remove( 'uagb-tabs__active' );
 | |
| 
 | |
| 			// Remove old tab body active class.
 | |
| 			document
 | |
| 				.querySelector( mainWrapClass + ' > .uagb-tabs__body-wrap > .uagb-tabs-body__active' )
 | |
| 				.classList.remove( 'uagb-tabs-body__active' );
 | |
| 
 | |
| 			// Set aria-selected attribute as false for old active tab.
 | |
| 			for ( let i = 0; i < allLi.length; i++ ) {
 | |
| 				allLi[ i ].setAttribute( 'tabindex', '-1' );  // Old active tab gets tabindex="-1".
 | |
| 				allLi[ i ].setAttribute( 'aria-selected', false );
 | |
| 			}
 | |
| 
 | |
| 			// Set selected li active class.
 | |
| 			selectedLi.classList.add( 'uagb-tabs__active' );
 | |
| 
 | |
| 			// Set aria-selected attribute as true for new active tab.
 | |
| 			selectedAnchor.setAttribute( 'aria-selected', true );
 | |
| 
 | |
| 			selectedAnchor.setAttribute( 'tabindex', '0' );  // New active tab gets tabindex="0".
 | |
| 
 | |
| 			// Set selected tab body active class.
 | |
| 			tabSelectedBody.classList.add( 'uagb-tabs-body__active' );
 | |
| 
 | |
| 			// Set aria-hidden attribute false for selected tab body.
 | |
| 			tabSelectedBody.setAttribute( 'aria-hidden', false );
 | |
| 
 | |
| 			// Set aria-hidden attribute true for all unselected tab body.
 | |
| 			for ( let i = 0; i < tabUnselectedBody.length; i++ ) {
 | |
| 				tabUnselectedBody[ i ].setAttribute( 'aria-hidden', true );
 | |
| 			}
 | |
| 		}
 | |
| 	},
 | |
| 	getChildrenWithClass( children, className ) {
 | |
| 		let child = null;
 | |
| 		for ( let i = 0; i < children.length; i++ ) {
 | |
| 			if ( children[ i ].classList.contains( className ) ) {
 | |
| 				child = children[ i ];
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		return child;
 | |
| 	}
 | |
| };
 |