1/* global wpsc_vars */ 2 3class WPSCProduct { 4 constructor(productOutput) { 5 const addToCartForm = productOutput.querySelector('form.wp-cart-button-form'); 6 if (!addToCartForm) { 7 return; 8 } 9 10 this.addToCartForm = addToCartForm; 11 12 const basePriceEl = this.addToCartForm?.querySelector('input[name="price"]'); 13 this.basePrice = basePriceEl?.value; 14 this.variationInputs = this.addToCartForm?.querySelectorAll('.wp_cart_variation1_select, .wp_cart_variation2_select, .wp_cart_variation3_select'); 15 16 this.productBox = productOutput.querySelector('.wp_cart_product_display_bottom'); 17 18 this.currencySymbol = wpsc_vars.currencySymbol; 19 20 if (this.productBox) { 21 // This is a product display box shortcode, need to render the updated price when product variation changes. 22 this.showUpdatedPrice(true); 23 } 24 25 // check if ajax add to cart enabled. 26 if (wpsc_vars.ajaxAddToCartEnabled) { 27 new WPSCAddToCartForm(this.addToCartForm); 28 } 29 } 30 31 showUpdatedPrice(isInitial = false) { 32 let updatedPrice = parseFloat(this.basePrice); 33 34 this.variationInputs?.forEach(varInput => { 35 const selectedOptionEl = varInput.options[varInput.selectedIndex]; 36 37 const varPrice = selectedOptionEl?.getAttribute("data-price"); 38 if (varPrice) { 39 // Nothing to do if no variation price set. 40 updatedPrice += parseFloat(varPrice); 41 } 42 43 if (isInitial) { 44 varInput.addEventListener('change', () => { 45 this.showUpdatedPrice(); 46 }); 47 } 48 }); 49 50 const priceBox = this.productBox?.querySelector('.wp_cart_product_price'); 51 52 priceBox.innerText = this.getFormatterPriceStr(updatedPrice); 53 } 54 55 getFormatterPriceStr(price) { 56 price = parseFloat(price); 57 58 return this.currencySymbol + price.toFixed(2); 59 } 60} 61 62class WPSCAddToCartForm { 63 64 constructor(form) { 65 this.form = form; 66 67 this.submitBtn = form.querySelector('input[type="submit"]'); 68 if (!this.submitBtn) { 69 // Its an image type btn. 70 this.submitBtn = form.querySelector('input[type="image"].wp_cart_button'); 71 } 72 73 this.form.addEventListener('submit', this.onSubmit); 74 75 this.checkoutPageURL = wpsc_vars.checkoutPageURL; 76 } 77 78 getCarts() { 79 return document.querySelectorAll('.wpsc_shopping_cart_container'); 80 } 81 82 getCompactCarts() { 83 return document.querySelectorAll('.wpsps_compact_cart'); 84 } 85 86 getCompactCarts2() { 87 return document.querySelectorAll('.wspsc_compact_cart2'); 88 } 89 90 onSubmit = async (e) => { 91 e.preventDefault(); 92 93 this.disableSubmitBtn(true); 94 95 const formData = new FormData(this.form); 96 97 // Add the ajax action query param. 98 formData.append('action', 'wpsc_add_to_cart'); 99 100 formData.delete('addcart'); // Not required and also causes problem in firefox. 101 102 // To fetch updated cart output if required. 103 formData.append('getCart', this.getCarts().length); 104 formData.append('getCompactCart', this.getCompactCarts().length); 105 formData.append('getCompactCart2', this.getCompactCarts2().length); 106 107 try { 108 let response = await fetch(wpsc_vars?.ajaxUrl, { 109 method: 'POST', 110 body: formData, 111 }); 112 113 if (!response.ok) { 114 alert('Add to cart error!'); 115 console.log(response); 116 return; 117 } 118 119 response = await response.json(); 120 121 // console.log(response); 122 123 this.showResponse(response, true); 124 125 if (!response.success) { 126 throw Error(response.data.message); 127 } 128 129 // Redirect to check out page if enabled. 130 if (wpsc_vars.autoRedirectToCheckoutPage && this.checkoutPageURL) { 131 console.log('Redirecting to checkout page...') 132 window.location.href = this.checkoutPageURL; 133 return; 134 } 135 136 // Update the cart view if cart existing the same page. 137 this.showUpdatedCarts(response); 138 139 // Scroll to the cart anchor if available. 140 if (wpsc_vars.shoppingCartAnchor) { 141 const cartAnchor = document.querySelector('a[name="wpsc_cart_anchor"]'); 142 if (cartAnchor) { 143 cartAnchor.scrollIntoView({ 144 behavior: 'smooth' 145 }); 146 } 147 } 148 149 } catch (error) { 150 alert(error.message); 151 console.log(error.message); 152 } finally { 153 this.disableSubmitBtn(false); 154 } 155 } 156 157 disableSubmitBtn( state ){ 158 if(this.submitBtn){ 159 this.submitBtn.disabled = Boolean(state); 160 } 161 } 162 163 showResponse(response, showCartLink = true) { 164 if (response.data?.message) { 165 const respDiv = this.form.querySelector('.wpsc_add_cart_response_div'); 166 respDiv.innerHTML = ''; 167 168 const isSuccess = response.success; 169 const msg = response.data.message; 170 const msgFormatted = this.getFormattedMsg(msg, isSuccess); 171 172 respDiv.appendChild(msgFormatted); 173 174 const cartPageUrl = wpsc_vars.checkoutPageURL.trim(); 175 if (response.success && showCartLink && cartPageUrl) { 176 const cartLinkDiv = document.createElement('div'); 177 const cartLink = document.createElement('a'); 178 cartLink.innerText = wpsc_vars.addToCart.texts.cartLink.trim(); 179 cartLink.href = cartPageUrl; 180 181 cartLinkDiv.appendChild(cartLink); 182 respDiv.appendChild(cartLinkDiv); 183 } 184 185 respDiv.style.marginTop = '10px'; 186 } 187 } 188 189 getFormattedMsg(msg, isSuccess = true) { 190 const msgEl = document.createElement('div'); 191 if (isSuccess) { 192 msgEl.classList.add('wpsc-success-message'); 193 } else { 194 msgEl.classList.add('wpsc-error-message'); 195 } 196 197 msgEl.innerText = String(msg); 198 // msgEl.innerHTML = msg; 199 200 return msgEl; 201 } 202 203 showUpdatedCarts(response) { 204 const response_data = response.data; 205 206 // Update existing or show new cart.
207 this.getCarts().forEach((cart, i) => { 208 const cartContent = cart.querySelector('.shopping_cart'); 209 210 const newCartShortCodeOutput = response_data.cart_shortcode_output[i]; 211 if (! cartContent) { 212 // The cart hasn't rendered yet. (empty cart, or no product was added before) 213 this.renderCart(cart, newCartShortCodeOutput); 214 return; 215 } 216 217 // The cart has rendered already, just update it. 218 this.updateCart(cartContent, newCartShortCodeOutput); 219 }) 220 221 // Update compact cart 222 this.getCompactCarts().forEach((cart) => { 223 this.updateCompactCart(cart, response_data); 224 }) 225 226 // Update compact cart 2 227 this.getCompactCarts2().forEach((cart) => { 228 this.updateCompactCart2(cart, response_data); 229 }) 230 } 231 232 renderCart(cart, newCartShortCodeOutput) { 233 cart.innerHTML = newCartShortCodeOutput; 234 235 document.dispatchEvent(new CustomEvent('wpsc_after_render_cart_by_ajax', { 236 detail: { 237 cart: cart, 238 } 239 })); 240 241 cart.querySelectorAll("script").forEach(oldScript => { 242 const newScript = document.createElement("script"); 243 244 // For External script 245 // if (oldScript.src) { 246 // newScript.src = oldScript.src; 247 // } 248 249 // For Inline script 250 newScript.textContent = oldScript.textContent; 251 252 // Executes the script now 253 oldScript.replaceWith(newScript); 254 }); 255 256 document.dispatchEvent(new CustomEvent('wpsc_after_cart_shortcode_script_eval', { 257 detail: { 258 cart: cart, 259 }, 260 cancelable: true, 261 })); 262 263 } 264 265 updateCart(cartContent, cartOutput) { 266 const newCartShortCodeOutput = document.createElement('template'); 267 newCartShortCodeOutput.innerHTML = cartOutput.trim(); 268 269 const newCartTableBody = newCartShortCodeOutput.content.querySelector('table > tbody'); 270 271 const cartTableBody = cartContent.querySelector('table > tbody'); 272 273 const cartActionMsg = cartContent.querySelector('.wpsc_cart_action_msg'); 274 cartActionMsg?.remove(); 275 276 if (cartTableBody) { 277 cartTableBody.replaceWith(newCartTableBody); 278 } 279 } 280 281 updateCompactCart(cart, response_data) { 282 const newCartOutput = response_data.compact_cart_shortcode_output; 283 if (newCartOutput) { 284 const template = document.createElement('template'); 285 template.innerHTML = newCartOutput; 286 287 cart.replaceWith(template.content); 288 } 289 } 290 291 updateCompactCart2(cart, response_data) { 292 const newCartOutput = response_data.compact_cart2_shortcode_output; 293 if (newCartOutput) { 294 const template = document.createElement('template'); 295 template.innerHTML = newCartOutput; 296 297 cart.replaceWith(template.content); 298 } 299 } 300} 301 302 303document.addEventListener('DOMContentLoaded', function () { 304 const products = document.querySelectorAll('.wpsc_product'); 305 products.forEach((product) => { 306 new WPSCProduct(product); 307 }); 308})
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.