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
		
			
				
	
	
		
			279 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			279 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * WooCommerce quantity buttons.
 | |
|  *
 | |
|  * @since x.x.x
 | |
|  */
 | |
| 
 | |
| window.addEventListener( "load", function(e) {
 | |
|     astrawpWooQuantityButtons();
 | |
|     quantityInput();
 | |
| });
 | |
| 
 | |
| 
 | |
| // Here we are selecting the node that will be observed for mutations.
 | |
| const astraminiCarttargetNodes = document.querySelectorAll(".ast-site-header-cart");
 | |
| 
 | |
| astraminiCarttargetNodes.forEach(function(astraminiCarttargetNode) {
 | |
|     if (astraminiCarttargetNode != null) {
 | |
|         const config = { attributes: false, childList: true, subtree: true };
 | |
|     
 | |
|         const astraMinicartObserver = () => {
 | |
|             astrawpWooQuantityButtons();
 | |
|             quantityInput();
 | |
|         };
 | |
|     
 | |
|         const observer = new MutationObserver(astraMinicartObserver);
 | |
|         observer.observe(astraminiCarttargetNode, config);
 | |
|     }
 | |
| });
 | |
| 
 | |
| /**This comment explains that in order to refresh the wc_fragments_refreshed event when an AJAX call is made, jQuery is used to update the quantity button.
 | |
|  * Here plain JavaScript may not be able to trigger the wc_fragments_refreshed event in the same way,
 | |
|  * hence the need to use jQuery
 | |
| */
 | |
| jQuery( function( $ ) {
 | |
|     $( document.body ).on( 'wc_fragments_refreshed', function() {
 | |
|         astrawpWooQuantityButtons();
 | |
|         quantityInput();
 | |
|     });
 | |
| });
 | |
| 
 | |
| (function() {
 | |
|     // Delay the method override so that we do not interfere with the Metrix test.
 | |
|     setTimeout(() => {
 | |
|         var send = XMLHttpRequest.prototype.send
 | |
|         XMLHttpRequest.prototype.send = function() {
 | |
|             this.addEventListener('load', function() {
 | |
|                 astrawpWooQuantityButtons();
 | |
|             })
 | |
|             return send.apply(this, arguments)
 | |
|         }
 | |
|     }, 2000);
 | |
| })();
 | |
| 
 | |
| /**
 | |
|  * Astra WooCommerce Quantity Buttons.
 | |
|  */
 | |
| function astrawpWooQuantityButtons( $quantitySelector ) {
 | |
| 
 | |
|     var $cart = document.querySelector( '.woocommerce div.product form.cart' );
 | |
| 
 | |
|     if ( ! $quantitySelector ) {
 | |
|         $quantitySelector = '.qty';
 | |
|     }
 | |
| 
 | |
|     $quantityBoxesWrap = document.querySelectorAll( 'div.quantity:not(.elementor-widget-woocommerce-cart .quantity):not(.buttons_added), td.quantity:not(.elementor-widget-woocommerce-cart .quantity):not(.buttons_added)' );
 | |
| 
 | |
|     for ( var i = 0; i < $quantityBoxesWrap.length; i++ ) {
 | |
| 
 | |
|         var e = $quantityBoxesWrap[i];
 | |
| 
 | |
|         var $quantityBoxes = e.querySelector( $quantitySelector );
 | |
| 
 | |
|         if ( $quantityBoxes && 'date' !== $quantityBoxes.getAttribute( 'type' ) && 'hidden' !== $quantityBoxes.getAttribute( 'type' ) ) {
 | |
| 
 | |
|             // Add plus and minus icons.
 | |
|             $qty_parent = $quantityBoxes.parentElement;
 | |
|             $qty_parent.classList.add( 'buttons_added' );
 | |
| 
 | |
|             const minusBtn = `<span class="screen-reader-text">${ astra_qty_btn.minus_qty }</span><a href="javascript:void(0)" id="minus_qty-${ i }" class="minus %s">-</a>`;
 | |
|             const plusBtn = `<span class="screen-reader-text">${ astra_qty_btn.plus_qty }</span><a href="javascript:void(0)" id="plus_qty-${ i }" class="plus %s">+</a>`;
 | |
| 
 | |
|             if ( 'vertical-icon' === astra_qty_btn.style_type ) {
 | |
|                 $qty_parent.classList.add( 'ast-vertical-style-applied' );
 | |
|                 $quantityBoxes.classList.add( 'vertical-icons-applied' );
 | |
|                 $qty_parent.insertAdjacentHTML(
 | |
|                     'beforeend',
 | |
|                     minusBtn.replace( '%s', 'ast-vertical-icon' ) + plusBtn.replace( '%s', 'ast-vertical-icon' )
 | |
|                 );
 | |
|             } else {
 | |
|                 let styleTypeClass = '';
 | |
|                 if ( 'no-internal-border' === astra_qty_btn.style_type ) {
 | |
|                     $quantityBoxes.classList.add( 'ast-no-internal-border' );
 | |
|                     styleTypeClass = 'no-internal-border';
 | |
|                 }
 | |
|                 $qty_parent.insertAdjacentHTML( 'afterbegin', minusBtn.replace( '%s', styleTypeClass ) );
 | |
|                 $qty_parent.insertAdjacentHTML( 'beforeend', plusBtn.replace( '%s', styleTypeClass ) );
 | |
|             }
 | |
|             $quantityEach = document.querySelectorAll( 'input' + $quantitySelector + ':not(.product-quantity)' );
 | |
| 
 | |
|             for ( var j = 0; j < $quantityEach.length; j++ ) {
 | |
| 
 | |
|                 var el = $quantityEach[j];
 | |
| 
 | |
|                 var $min = el.getAttribute( 'min' );
 | |
| 
 | |
|                 if ( $min && $min > 0 && parseFloat( el.value ) < $min ) {
 | |
|                     el.value = $min;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Quantity input.
 | |
|             let objbody = document.getElementsByTagName('BODY')[0];
 | |
|             let cart = document.getElementsByClassName('cart')[0];
 | |
| 
 | |
|             if (objbody.classList.contains('single-product') && !cart.classList.contains('grouped_form')) {
 | |
|                 let quantityInput = document.querySelector('.woocommerce input[type=number].qty');
 | |
|                 // Check for single product page.
 | |
|                 if (quantityInput) {
 | |
|                     quantityInput.addEventListener('keyup', function () {
 | |
|                         let qtyVal = quantityInput.value;
 | |
|                         quantityInput.value = qtyVal;
 | |
|                     });
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             var plus_minus_obj = e.querySelectorAll( '.plus, .minus' );
 | |
| 
 | |
|             for ( var l = 0; l < plus_minus_obj.length; l++ ) {
 | |
| 
 | |
|                 var pm_el = plus_minus_obj[l];
 | |
| 
 | |
|                 pm_el.addEventListener( "click", function(ev) {
 | |
| 
 | |
| 
 | |
|                     // Quantity.
 | |
|                     var $quantityBox;
 | |
| 
 | |
|                     $quantityBox = ev.target.parentElement.querySelector( $quantitySelector );
 | |
| 
 | |
|                     // Get values.
 | |
|                     var $currentQuantity = parseFloat( $quantityBox.value ),
 | |
|                     $maxQuantity = parseFloat( $quantityBox.getAttribute( 'max' ) ),
 | |
|                     $minQuantity = parseFloat( $quantityBox.getAttribute( 'min' ) ),
 | |
|                     $step = parseFloat( $quantityBox.getAttribute( 'step' ) ),
 | |
|                     checkStepInteger = Number.isInteger( $step ),
 | |
|                     finalValue;
 | |
| 
 | |
|                     // Fallback default values on falsy values like '' and NaN.
 | |
|                     if ( ! $currentQuantity ) {
 | |
|                         $currentQuantity = 0;
 | |
|                     }
 | |
|                     if ( ! $maxQuantity ) {
 | |
|                         $maxQuantity = '';
 | |
|                     }
 | |
| 
 | |
|                     if ( ! $minQuantity ) {
 | |
|                         $minQuantity = 0;
 | |
|                     }
 | |
|                     if ( ! $step ) {
 | |
|                         $step = 1;
 | |
|                     }
 | |
| 
 | |
|                     // Change the value.
 | |
|                     if ( ev.target.classList.contains( 'plus' ) ) {
 | |
| 
 | |
|                         if ( $maxQuantity && ( $maxQuantity === $currentQuantity || $currentQuantity > Number( $maxQuantity ) ) ) {
 | |
|                             $quantityBox.value = $maxQuantity;
 | |
|                         } else {
 | |
|                             finalValue = $currentQuantity + parseFloat( $step );
 | |
|                             $quantityBox.value = checkStepInteger ? finalValue : ( finalValue ).toFixed(1);
 | |
|                         }
 | |
| 
 | |
|                     } else {
 | |
| 
 | |
|                         if ( $minQuantity && ( $minQuantity === $currentQuantity || $currentQuantity < $minQuantity ) ) {
 | |
|                             $quantityBox.value = $minQuantity;
 | |
|                         } else if ( $currentQuantity > 0 ) {
 | |
|                             finalValue = $currentQuantity - parseFloat( $step );
 | |
|                             $quantityBox.value = checkStepInteger ? finalValue : ( finalValue ).toFixed(1);
 | |
|                         }
 | |
| 
 | |
|                     }
 | |
| 
 | |
|                     // Trigger the change event on the input.
 | |
|                     var changeEvent = new Event('change', { bubbles: true });
 | |
|                     $quantityBox.dispatchEvent(changeEvent);
 | |
| 
 | |
|                     // Trigger change event.
 | |
|                     var update_cart_btn = document.getElementsByName("update_cart");
 | |
|                     if (update_cart_btn.length > 0) {
 | |
|                         for ( var btn = 0; btn < update_cart_btn.length; btn++ ) {
 | |
|                             update_cart_btn[btn].disabled = false;
 | |
|                             update_cart_btn[btn].click();
 | |
|                         }
 | |
|                     }
 | |
|                     
 | |
|                     const quantity = $quantityBox.value;
 | |
|                     const itemHash = $quantityBox.getAttribute('name').replace(/cart\[([\w]+)\]\[qty\]/g, '$1');
 | |
| 
 | |
|                     sendAjaxQuantityRequest(ev.currentTarget, quantity, itemHash)
 | |
| 
 | |
|                 }, false);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| function sendAjaxQuantityRequest(currentTarget, quantity, itemHash ) {
 | |
| 
 | |
|     // Send AJAX request from mini cart.
 | |
|     const miniCart = currentTarget.closest( '.woocommerce-mini-cart' );
 | |
| 
 | |
|     if ( miniCart && astra && astra.single_product_qty_ajax_nonce && astra.ajax_url ) {
 | |
| 
 | |
|         let qtyNonce = astra.single_product_qty_ajax_nonce;
 | |
| 
 | |
|         miniCart.classList.add('ajax-mini-cart-qty-loading');
 | |
| 
 | |
|         // Creating a XMLHttpRequest object.
 | |
|         let xhrRequest = new XMLHttpRequest();
 | |
|         xhrRequest.open( 'POST', astra.ajax_url, true );
 | |
| 
 | |
|         // Send the proper header information along with the request
 | |
|         xhrRequest.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
 | |
| 
 | |
|         xhrRequest.send( 'action=astra_add_cart_single_product_quantity&hash=' + itemHash + '&quantity=' + quantity + '&qtyNonce=' + qtyNonce );
 | |
| 
 | |
|         xhrRequest.onload = function () {
 | |
|             if ( xhrRequest.readyState == XMLHttpRequest.DONE ) {   // XMLHttpRequest.DONE == 4
 | |
|                 if ( 200 <= xhrRequest.status || 400 <= xhrRequest.status ) {
 | |
|                     // Trigger event so themes can refresh other areas.
 | |
|                     var event = document.createEvent( 'HTMLEvents' );
 | |
|                     event.initEvent( 'wc_fragment_refresh', true, false );
 | |
|                     document.body.dispatchEvent(event);
 | |
| 
 | |
|                     setTimeout(() => {
 | |
|                         miniCart.classList.remove('ajax-mini-cart-qty-loading');
 | |
|                     }, 500);
 | |
|                    
 | |
| 
 | |
|                     if ( typeof wc_add_to_cart_params === 'undefined' ) {
 | |
|                         return;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| let typingTimer; //timer identifier
 | |
| let doneTypingInterval = 500;
 | |
| 
 | |
| function quantityInput() {
 | |
|     const quantityInputContainer = document.querySelector('.woocommerce-mini-cart');
 | |
| 
 | |
|     if( quantityInputContainer ) {
 | |
|         const quantityInput = document.querySelectorAll('.input-text.qty');
 | |
| 
 | |
|         quantityInput.forEach( single => {
 | |
|             single.addEventListener('keyup', (e) => {
 | |
|                 clearTimeout(typingTimer);
 | |
|                 if (single.value) {
 | |
|                     typingTimer = setTimeout(() => {
 | |
|                         const quantity = e.target.value;
 | |
|                         const itemHash = e.target.getAttribute('name').replace(/cart\[([\w]+)\]\[qty\]/g, '$1');
 | |
| 
 | |
|                         if( quantity ) {
 | |
|                             sendAjaxQuantityRequest(e.target, quantity,itemHash);
 | |
|                         }
 | |
|                     }, doneTypingInterval);
 | |
|                 }
 | |
|             });
 | |
|         });
 | |
|     }
 | |
| } |