1/** 2 * WooCommerce quantity buttons. 3 * 4 * @since x.x.x 5 */ 6 7window.addEventListener( "load", function(e) { 8 astrawpWooQuantityButtons(); 9 quantityInput(); 10}); 11 12 13// Here we are selecting the node that will be observed for mutations. 14const astraminiCarttargetNodes = document.querySelectorAll(".ast-site-header-cart"); 15 16astraminiCarttargetNodes.forEach(function(astraminiCarttargetNode) { 17 if (astraminiCarttargetNode != null) { 18 const config = { attributes: false, childList: true, subtree: true }; 19 20 const astraMinicartObserver = () => { 21 astrawpWooQuantityButtons(); 22 quantityInput(); 23 }; 24 25 const observer = new MutationObserver(astraMinicartObserver); 26 observer.observe(astraminiCarttargetNode, config); 27 } 28}); 29 30/**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. 31 * Here plain JavaScript may not be able to trigger the wc_fragments_refreshed event in the same way, 32 * hence the need to use jQuery 33*/ 34jQuery( function( $ ) { 35 $( document.body ).on( 'wc_fragments_refreshed woosq_loaded', function() { 36 astrawpWooQuantityButtons(); 37 quantityInput(); 38 }); 39}); 40 41(function() { 42 // Delay the method override so that we do not interfere with the Metrix test. 43 setTimeout(() => { 44 var send = XMLHttpRequest.prototype.send 45 XMLHttpRequest.prototype.send = function() { 46 this.addEventListener('load', function() { 47 astrawpWooQuantityButtons(); 48 }) 49 return send.apply(this, arguments) 50 } 51 }, 2000); 52})(); 53 54/** 55 * Astra WooCommerce Quantity Buttons. 56 */ 57function astrawpWooQuantityButtons( $quantitySelector ) { 58 59 var $cart = document.querySelector( '.woocommerce div.product form.cart' ); 60 61 if ( ! $quantitySelector ) { 62 $quantitySelector = '.qty'; 63 } 64 65 $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)' ); 66 67 for ( var i = 0; i < $quantityBoxesWrap.length; i++ ) { 68 69 var e = $quantityBoxesWrap[i]; 70 71 var $quantityBoxes = e.querySelector( $quantitySelector ); 72 73 if ( $quantityBoxes && 'date' !== $quantityBoxes.getAttribute( 'type' ) && 'hidden' !== $quantityBoxes.getAttribute( 'type' ) ) { 74 75 // Add plus and minus icons. 76 $qty_parent = $quantityBoxes.parentElement; 77 78 // Remove existing plus and minus placeholders. 79 document.querySelectorAll( '.ast-qty-placeholder' )?.forEach( ( placeholder ) => placeholder?.remove() ); 80 81 $qty_parent.classList.add( 'buttons_added' ); 82 83 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>`; 84 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>`; 85 86 if ( 'vertical-icon' === astra_qty_btn.style_type ) { 87 $qty_parent.classList.add( 'ast-vertical-style-applied' ); 88 $quantityBoxes.classList.add( 'vertical-icons-applied' ); 89 $qty_parent.insertAdjacentHTML( 90 'beforeend', 91 minusBtn.replace( '%s', 'ast-vertical-icon' ) + plusBtn.replace( '%s', 'ast-vertical-icon' ) 92 ); 93 } else { 94 let styleTypeClass = ''; 95 if ( 'no-internal-border' === astra_qty_btn.style_type ) { 96 $quantityBoxes.classList.add( 'ast-no-internal-border' ); 97 styleTypeClass = 'no-internal-border'; 98 } 99 $qty_parent.insertAdjacentHTML( 'afterbegin', minusBtn.replace( '%s', styleTypeClass ) ); 100 $qty_parent.insertAdjacentHTML( 'beforeend', plusBtn.replace( '%s', styleTypeClass ) ); 101 } 102 $quantityEach = document.querySelectorAll( 'input' + $quantitySelector + ':not(.product-quantity)' ); 103 104 for ( var j = 0; j < $quantityEach.length; j++ ) { 105 106 var el = $quantityEach[j]; 107 108 var $min = el.getAttribute( 'min' ); 109 110 if ( $min && $min > 0 && parseFloat( el.value ) < $min ) { 111 el.value = $min; 112 } 113 } 114 115 // Quantity input. 116 let objbody = document.getElementsByTagName('BODY')[0]; 117 let cart = document.getElementsByClassName('cart')[0]; 118 119 if (objbody.classList.contains('single-product') && cart && !cart.classList.contains('grouped_form')) { 120 let quantityInput = document.querySelector('.woocommerce input[type=number].qty'); 121 // Check for single product page. 122 if (quantityInput) { 123 quantityInput.addEventListener('keyup', function () { 124 let qtyVal = quantityInput.value; 125 quantityInput.value = qtyVal; 126 }); 127 } 128 } 129 130 var plus_minus_obj = e.querySelectorAll( '.plus, .minus' ); 131 132 for ( var l = 0; l < plus_minus_obj.length; l++ ) { 133 134 var pm_el = plus_minus_obj[l]; 135 136 pm_el.addEventListener( "click", function(ev) { 137 138 139 // Quantity. 140 var $quantityBox; 141 142 $quantityBox = ev.target.parentElement.querySelector( $quantitySelector ); 143 144 // Get values. 145 var $currentQuantity = parseFloat( $quantityBox.value ), 146 $maxQuantity = parseFloat( $quantityBox.getAttribute( 'max' ) ), 147 $minQuantity = parseFloat( $quantityBox.getAttribute( 'min' ) ), 148 $step = parseFloat( $quantityBox.getAttribute( 'step' ) ), 149 checkStepInteger = Number.isInteger( $step ), 150 finalValue; 151 152 // Fallback default values on falsy values like '' and NaN. 153 if ( ! $currentQuantity ) { 154 $currentQuantity = 0; 155 } 156 if ( ! $maxQuantity ) { 157 $maxQuantity = ''; 158 } 159 160 if ( ! $minQuantity ) { 161 $minQuantity = 0; 162 } 163 if ( ! $step ) { 164 $step = 1; 165 } 166 167 // Change the value. 168 if ( ev.target.classList.contains( 'plus' ) ) { 169 170 if ( $maxQuantity && ( $maxQuantity === $currentQuantity || $currentQuantity > Number( $maxQuantity ) ) ) { 171 $quantityBox.value = $maxQuantity; 172 } else { 173 finalValue = $currentQuantity + parseFloat( $step ); 174 $quantityBox.value = checkStepInteger ? finalValue : ( finalValue ).toFixed(1); 175 } 176 177 } else { 178 179 if ( $minQuantity && ( $minQuantity === $currentQuantity || $currentQuantity < $minQuantity ) ) { 180 $quantityBox.value = $minQuantity; 181 } else if ( $currentQuantity > 0 ) { 182 finalValue = $currentQuantity - parseFloat( $step ); 183 $quantityBox.value = checkStepInteger ? finalValue : ( finalValue ).toFixed(1); 184 } 185 186 } 187 188 // Trigger the change event on the input. 189 var changeEvent = new Event('change', { bubbles: true }); 190 $quantityBox.dispatchEvent(changeEvent); 191 192 // Trigger change event. 193 var update_cart_btn = document.getElementsByName("update_cart"); 194 if (update_cart_btn.length > 0) { 195 for ( var btn = 0; btn < update_cart_btn.length; btn++ ) { 196 update_cart_btn[btn].disabled = false;
197 update_cart_btn[btn].click(); 198 } 199 } 200 201 const quantity = $quantityBox.value; 202 const itemHash = $quantityBox.getAttribute('name').replace(/cart\[([\w]+)\]\[qty\]/g, '$1'); 203 204 sendAjaxQuantityRequest(ev.currentTarget, quantity, itemHash) 205 206 }, false); 207 } 208 } 209 } 210} 211 212 213function sendAjaxQuantityRequest(currentTarget, quantity, itemHash ) { 214 215 // Send AJAX request from mini cart. 216 const miniCart = currentTarget.closest( '.woocommerce-mini-cart' ); 217 218 if ( miniCart && astra && astra.single_product_qty_ajax_nonce && astra.ajax_url ) { 219 220 let qtyNonce = astra.single_product_qty_ajax_nonce; 221 222 miniCart.classList.add('ajax-mini-cart-qty-loading'); 223 224 // Creating a XMLHttpRequest object. 225 let xhrRequest = new XMLHttpRequest(); 226 xhrRequest.open( 'POST', astra.ajax_url, true ); 227 228 // Send the proper header information along with the request 229 xhrRequest.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" ); 230 231 xhrRequest.send( 'action=astra_add_cart_single_product_quantity&hash=' + itemHash + '&quantity=' + quantity + '&qtyNonce=' + qtyNonce ); 232 233 xhrRequest.onload = function () { 234 if ( xhrRequest.readyState == XMLHttpRequest.DONE ) { // XMLHttpRequest.DONE == 4 235 if ( 200 <= xhrRequest.status || 400 <= xhrRequest.status ) { 236 // Trigger event so themes can refresh other areas. 237 var event = document.createEvent( 'HTMLEvents' ); 238 event.initEvent( 'wc_fragment_refresh', true, false ); 239 document.body.dispatchEvent(event); 240 241 setTimeout(() => { 242 miniCart.classList.remove('ajax-mini-cart-qty-loading'); 243 }, 500); 244 245 246 if ( typeof wc_add_to_cart_params === 'undefined' ) { 247 return; 248 } 249 } 250 } 251 }; 252 } 253 254} 255 256 257 258let typingTimer; //timer identifier 259let doneTypingInterval = 500; 260 261function quantityInput() { 262 const quantityInputContainer = document.querySelector('.woocommerce-mini-cart'); 263 264 if( quantityInputContainer ) { 265 const quantityInput = document.querySelectorAll('.input-text.qty'); 266 267 quantityInput.forEach( single => { 268 single.addEventListener('keyup', (e) => { 269 if ( e.key === 'Tab' || e.keyCode === 9 ) { 270 return; 271 } 272 clearTimeout(typingTimer); 273 if (single.value) { 274 typingTimer = setTimeout(() => { 275 const quantity = e.target.value; 276 const itemHash = e.target.getAttribute('name').replace(/cart\[([\w]+)\]\[qty\]/g, '$1'); 277 278 if( quantity ) { 279 sendAjaxQuantityRequest(e.target, quantity,itemHash); 280 } 281 }, doneTypingInterval); 282 } 283 }); 284 }); 285 } 286}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.