1/* 2 * One Page Checkout JS: add/remove items from a One Page Checkout page via Ajax 3 */ 4jQuery(document).ready(function($){ 5 6 var response_messages = ''; 7 var timeout; 8 var delay = 500; 9 10 var $checkout = $( '.checkout' ); 11 var $body = $( 'body' ); 12 /** 13 * Review Order Template Item Management (Removal & Quantity Adjustment) 14 */ 15 16 // Quantity buttons 17 $checkout.on( 'change input', '#order_review .opc_cart_item div.quantity input.qty', function(e) { 18 19 var input = $(this), 20 selectors = '.checkout #order_review .opc_cart_item div.quantity input.qty'; 21 22 clearTimeout(timeout); 23 24 timeout = setTimeout(function() { 25 26 var data = { 27 quantity: input.val(), 28 add_to_cart: parseInt( input.closest( '.opc_cart_item' ).data( 'add_to_cart' ) ), 29 update_key: input.closest( '.opc_cart_item' ).data( 'update_key' ), 30 nonce: wcopc.wcopc_nonce, 31 }; 32 33 if ( data['quantity'] == 0 ) { 34 data['action'] = 'pp_remove_from_cart'; 35 } else { 36 data['action'] = 'pp_update_add_in_cart'; 37 } 38 39 input.ajax_add_remove_product( data, e, selectors ); 40 41 }, delay ); 42 43 e.preventDefault(); 44 45 } ); 46 47 // Remove buttons 48 $checkout.on( 'click', '#order_review .opc_cart_item a.remove', function(e) { 49 50 var data = { 51 action: 'pp_remove_from_cart', 52 add_to_cart: parseInt( $(this).closest( '.opc_cart_item' ).data( 'add_to_cart' ) ), 53 update_key: $(this).closest( '.opc_cart_item' ).data( 'update_key' ), 54 nonce: wcopc.wcopc_nonce, 55 }, 56 selectors = '.checkout #order_review .opc_cart_item a.remove'; 57 58 $(this).ajax_add_remove_product( data, e, selectors ); 59 60 e.preventDefault(); 61 62 } ); 63 64 /** 65 * Single Product Template 66 */ 67 68 /* Add/remove products with button element or a tags */ 69 $( '#opc-product-selection button.single_add_to_cart_button, .wcopc-product-single button.single_add_to_cart_button' ).on( 'click', function(e) { 70 71 var is_variable = $(this).closest( '.variations_form' ).find( 'input[name="variation_id"]' ).length === 1, 72 is_grouped = $(this).siblings( '.group_table' ).length >= 1, 73 add_to_cart_id = $(this).closest( '.cart' ).find( '[name="add-to-cart"]' ).val(), 74 has_quantity = $(this).closest( '.cart' ).find( 'input[name="quantity"]' ).length === 1, 75 data = { 76 action: 'pp_add_to_cart', 77 nonce: wcopc.wcopc_nonce, 78 input_data: $(this).closest( '.product-quantity, .wcopc-product-single form' ).find( 'input[name!="variation_id"][name!="product_id"][name!="add-to-cart"][name!="quantity"], select, textarea' ).serialize(), 79 }, 80 selectors = '#opc-product-selection button.single_add_to_cart_button, .wcopc-product-single button.single_add_to_cart_button'; 81 82 if ( is_grouped ) { 83 84 data.add_to_cart = []; 85 86 $(this).siblings( '.group_table' ).find( 'input[name^="quantity"]' ).each( function( index, value ) { 87 88 if ( ( ! $( this ).is( ':checkbox' ) && $( this ).val() > 0 ) || ( $( this ).is( ':checkbox' ) && $( this ).is( ':checked' ) ) ) { 89 90 var product_id = parseInt( $( this ).attr( 'name' ).match( /quantity\[(\d+)\]/ )[1] ), 91 quantity = parseInt( $( this ).val() ); 92 93 data.add_to_cart.push({ 94 'product_id': product_id, 95 'quantity': quantity, 96 }); 97 } 98 }); 99 100 data.add_to_cart.forEach(function(add_to_cart_data) { 101 102 data.add_to_cart = parseInt( add_to_cart_data.product_id ); 103 data.quantity = parseInt( add_to_cart_data.quantity ); 104 105 $(this).ajax_add_remove_product( data, e, selectors, false ); 106 }); 107 108 } else { 109 110 data.add_to_cart = parseInt( add_to_cart_id ); 111 112 if ( is_variable ) { 113 data.variation_id = parseInt( $(this).closest( '.variations_form' ).find( 'input[name="variation_id"]' ).val() ); 114 } 115 116 // The quantity input field might be missing if a product is sold individually or has only 1 unit of stock remaining 117 if ( has_quantity ) { 118 data.quantity = parseInt( $(this).closest( '.cart' ).find( 'input[name="quantity"]' ).val() ); 119 } 120 121 $(this).ajax_add_remove_product( data, e, selectors ); 122 } 123 124 e.preventDefault(); 125 } ); 126 127 /** 128 * Other Templates 129 */ 130 131 /* Add/remove products with number input type */ 132 $( '#opc-product-selection input[type="number"][data-add_to_cart]' ).on( 'change input', function(e) { 133 var input = $(this), 134 selectors = '#opc-product-selection input[type="number"][data-add_to_cart]'; 135 136 clearTimeout(timeout); 137 138 timeout = setTimeout(function() { 139 140 var data = { 141 quantity: input.val(), 142 add_to_cart: parseInt( input.data( 'add_to_cart' ) ), 143 input_data: input.closest( '.product-quantity' ).find( 'input[name!="product_id"], select, textarea' ).serialize(), 144 nonce: wcopc.wcopc_nonce, 145 }; 146 147 if ( data['quantity'] == 0 ) { 148 data['action'] = 'pp_remove_from_cart'; 149 } else { 150 data['action'] = 'pp_update_add_in_cart'; 151 } 152 153 input.ajax_add_remove_product( data, e, selectors ); 154 155 }, delay ); 156 157 e.preventDefault(); 158 159 } ); 160 161 /* Add/remove products with radio or checkbox inputs */ 162 $( '#opc-product-selection input[type="radio"][data-add_to_cart], #opc-product-selection input[type="checkbox"][data-add_to_cart]' ).on( 'change', function(e) { 163 164 var input = $(this), 165 selectors = '#opc-product-selection input[type="radio"][data-add_to_cart], #opc-product-selection input[type="checkbox"][data-add_to_cart]'; 166 167 clearTimeout(timeout); 168 169 timeout = setTimeout(function() { 170 171 var data = { 172 add_to_cart: parseInt( input.data( 'add_to_cart' ) ), 173 nonce: wcopc.wcopc_nonce 174 }; 175 176 if ( input.is( ':checked' ) ) { 177 178 if ( input.prop( 'type' ) == 'radio' ) { 179 180 data.empty_cart = 'true'; 181 $( 'input[data-add_to_cart]' ).prop( 'checked', false ); 182 input.prop( 'checked', true ); 183 $( '.selected' ).removeClass( 'selected' ); 184 } 185 186 data.action = 'pp_add_to_cart'; 187 input.parents( '.product-item' ).addClass( 'selected' ); 188 189 } else { 190 191 data.action = 'pp_remove_from_cart'; 192 input.parents( '.product-item' ).removeClass( 'selected' ); 193 194 } 195 196 input.ajax_add_remove_product( data, e, selectors ); 197 198 }, delay ); 199 200 } ); 201 202 /* Add/remove products with button element or a tags */ 203 $( '#opc-product-selection a[data-add_to_cart], #opc-product-selection button[data-add_to_cart]' ).on( 'click', function(e) { 204 205 var data = { 206 add_to_cart: parseInt( $(this).data( 'add_to_cart' ) ), 207 nonce: wcopc.wcopc_nonce, 208 input_data: $(this).closest( '.product-quantity' ).find( 'input[name!="product_id"], select, textarea' ).serialize(), 209 }, 210 selectors = '#opc-product-selection a[data-add_to_cart], #opc-product-selection button[data-add_to_cart]'; 211 212 // Toggle button on or off 213 if ( ! $(this).parents( '.product-item' ).hasClass( 'selected' ) ) { 214 data.action = 'pp_add_to_cart'; 215 $(this).parents( '.product-item' ).addClass( 'selected' ); 216 } else { 217 data.action = 'pp_remove_from_cart'; 218 $(this).parents( '.product-item' ).removeClass( 'selected' ); 219 } 220 221 $(this).ajax_add_remove_product( data, e, selectors ); 222 } ); 223 224 /* Add products from any Easy Pricing Table template */ 225 $( 'a.ptp-button, a.ptp-dg5-button, a.ptp-dg6-button, a.ptp-dg7-button, a.ptp-fancy-button, a.btn.sign-up, .ptp-stylish-pricing_button a, .ptp-design4-col > a' ).on( 'click',function(e) { 226
227 var productParams = getUrlsParams($(this)[0].search.substring(1)), 228 selectors = 'a.ptp-button, a.ptp-dg5-button, a.ptp-dg6-button, a.ptp-dg7-button, a.ptp-fancy-button, a.btn.sign-up, .ptp-stylish-pricing_button a, .ptp-design4-col > a'; 229 230 var data = { 231 action: 'pp_add_to_cart', 232 add_to_cart: productParams['add-to-cart'], 233 empty_cart: 'true', 234 nonce: wcopc.wcopc_nonce 235 }; 236 237 delete productParams['add-to-cart']; 238 data.input_data = $.param( productParams ); 239 240 $( this ).ajax_add_remove_product( data, e, selectors ); 241 } ); 242 243 // Set response messages when the checkout is fully updated (because it would remove them if we set them before that) 244 $body.on( 'updated_checkout', function(){ 245 if ( response_messages.length > 0 ) { 246 var $opc_messages = $( '#opc-messages' ); 247 248 $opc_messages.prepend( response_messages ); 249 250 if ( 'yes' === wcopc.autoscroll && ! $opc_messages.visible() ){ 251 $( 'html, body' ).animate( { 252 scrollTop: ($opc_messages.offset().top - 150 ) 253 }, 500 ); 254 } 255 256 response_messages = ''; 257 } 258 }); 259 260 /* Function to add or remove product from cart via an ajax call */ 261 $.fn.ajax_add_remove_product = function( data, e, selectors, async_ajax ) { 262 263 // Default to synchonus Ajax, but for Grouped products, use async 264 async_ajax = ( typeof async_ajax !== 'undefined' ) ? async_ajax : true; 265 266 // Guard against race conditions by disabling the inputs 267 $(selectors).attr('disabled', 'disabled'); 268 269 // Custom event for devs to hook into before posting of products for processing 270 $('body').trigger( 'opc_add_remove_product', [ data, e, selectors ] ); 271 272 // Read from opc_add_remove_product trigger above and maybe avoid the AJAX add to cart call. 273 if ( data.invalid === true ) { 274 $( selectors ).removeAttr( 'disabled' ); 275 return; 276 } 277 278 $.ajax({ 279 type: 'POST', 280 url: wcopc.ajax_url, 281 data: data, 282 async: async_ajax, 283 dataType: 'json', 284 success: function( response, status, xhr ) { 285 286 var fragments; 287 288 try { 289 290 if ( response === '-1' ) { 291 throw 'invalid response'; 292 } 293 294 if (xhr.getResponseHeader('Content-Type') == 'application/json') { 295 response = $.parseJSON(response); 296 } 297 298 // Get fragments 299 fragments = response.fragments; 300 301 var inputs = $( '#opc-product-selection [data-add_to_cart]' ); 302 303 inputs.each( function( index, value ) { 304 305 var product_id = $(this).data( 'add_to_cart' ), 306 in_cart = false; 307 308 $.each( response.products_in_cart, function( cart_item_id, cart_item_data ) { 309 if ( ( product_id == cart_item_id || product_id == cart_item_data.product_id ) ) { 310 in_cart = true; 311 } 312 } ); 313 314 if ( $(this).prop( 'type' ) == 'number' ) { 315 316 if ( in_cart ) { 317 $(this).val( response.products_in_cart[ product_id ].quantity ).data( 'cart_quantity', response.products_in_cart[ product_id ].quantity ); 318 } else { 319 $(this).val(0).data( 'cart_quantity', 0 ); 320 } 321 322 } else if ( $(this).is( 'a, button' ) ) { 323 324 if ( in_cart ) { 325 $(this).parents( '.product-item' ).addClass( 'selected' ); 326 } else { 327 $(this).parents( '.product-item' ).removeClass( 'selected' ); 328 } 329 330 } else { 331 332 if ( in_cart ) { 333 $(this).prop( 'checked', true ); 334 } else { 335 $(this).prop( 'checked', false ); 336 $(this).parents( '.product-item' ).removeClass( 'selected' ); 337 } 338 } 339 340 } ); 341 342 // Store messages for use when checkout has finished updating 343 response_messages = response.messages; 344 345 } catch ( err ) { 346 347 if ( 'undefined' == typeof response.messages ) { 348 response_messages = wcopc.ajax_error_notice; 349 } else { 350 response_messages = response.messages; 351 } 352 353 var $opc_messages = $( '#opc-messages' ); 354 $opc_messages.prepend( response.messages ); 355 356 $( 'html, body' ).animate( { 357 scrollTop: ( $opc_messages.offset().top - 50 ) 358 }, 500); 359 } 360 361 $( '#opc-messages .woocommerce-error, #opc-messages .woocommerce-message, #opc-messages .woocommerce-info' ).remove(); 362 363 // remove 'loading' class that Flatsome theme adds 364 $('button.single_add_to_cart_button').removeClass('loading'); 365 366 // Custom event for devs to hook into after products have been processed 367 $body.trigger( 'after_opc_add_remove_product', [ data, response ] ); 368 369 // Tell WooCommerce to update totals 370 $body.trigger( 'update_checkout' ); 371 372 // Block fragments class 373 if ( fragments ) { 374 $.each( fragments, function( key, value ) { 375 $( key ).addClass( 'updating' ); 376 }); 377 } 378 379 // Block fragments 380 var $updating = $( '.updating' ); 381 $updating.fadeTo( '400', '0.6' ).block({ 382 message: null, 383 overlayCSS: { 384 opacity: 0.6 385 } 386 }); 387 388 // Replace fragments 389 if ( fragments ) { 390 $.each( fragments, function( key, value ) { 391 $( key ).replaceWith( value ); 392 }); 393 } 394 395 // Unblock 396 $updating.stop( true ).css( 'opacity', '1' ).unblock(); 397 398 // It is now safe to change the cart again 399 $(selectors).removeAttr('disabled'); 400 401 } } ); 402 403 e.preventDefault(); 404 }; 405
406 /* Only display the place order button when a product has been selected */ 407 showHidePlaceOrder(); 408 409 /* Append "Complete Order" anchor and "data-add_to_cart" attribute to single-product template buttons */ 410 initSingleProductTemplateButtons(); 411 412 /* Init custom order-review template quantity buttons */ 413 initOrderReviewQtyButtons(); 414 415 $body.on( 'updated_checkout',function() { 416 showHidePlaceOrder(); 417 418 /* Init custom order-review template quantity buttons */ 419 initOrderReviewQtyButtons(); 420 421 /* Check the create account fields are correctly displayed when subscriptions are part of the cart/order after ajax update */ 422 create_account_toggle(); 423 } ); 424 425 function initOrderReviewQtyButtons() { 426 427 $( '#order_review.opc_order_review div.quantity:not(.buttons_added)' ).addClass( 'buttons_added' ).append( '<input type="button" value="+" class="plus" />' ).prepend( '<input type="button" value="-" class="minus" />' ); 428 } 429 430 function showHidePlaceOrder() { 431 432 if ( $( '#order_review tbody' ).children().length>0 ) { 433 /* Stop animations from other plugins and show immediately.*/ 434 $( '#place_order' ).stop(); 435 $( '#place_order' ).animate( { opacity: 'show', height: 'show', padding: 'show' }, 0 ); 436 $( '#payment .payment_methods').show(); 437 } else { 438 /* Stop animations from other plugins and hide immediately*/ 439 $( '#place_order' ).stop(); 440 $( '#place_order' ).animate( { opacity: 'hide', height: 'hide', padding: 'hide' }, 0 ); 441 $( '#payment .payment_methods').hide(); 442 } 443 } 444 445 function initSingleProductTemplateButtons() { 446 447 $( '#opc-product-selection button.single_add_to_cart_button' ).each( function() { 448 449 $(this).after( wcopc.wcopc_complete_order_prompt ); 450 $(this).attr( 'data-add_to_cart', $(this).closest( '.cart' ).find( '[name="add-to-cart"]' ).val() ); 451 $(this).data( 'add_to_cart', $(this).closest( '.cart' ).find( '[name="add-to-cart"]' ).val() ); 452 } ); 453 454 } 455 456 function getUrlsParams( queryString ){ 457 458 var match, 459 pl = /\+/g, // Regex for replacing addition symbol with a space 460 search = /([^&=]+)=?([^&]*)/g, 461 decode = function (s) { return decodeURIComponent(s.replace(pl, ' ')); }; 462 463 urlParams = {}; 464 465 while ( match = search.exec( queryString ) ) { 466 urlParams[ decode( match[1] ) ] = decode( match[2] ); 467 } 468 469 return urlParams; 470 } 471 472 function create_account_toggle() { 473 474 if ( $('.opc_order_review').length ) { 475 476 var $p_create_account = $( 'p.create-account' ); 477 var $dif_create_account = $( 'div.create-account' ); 478 var create_account_p_original_visibility = $p_create_account.is( ":visible" ); 479 var create_account_div_original_visibility = $dif_create_account.is( ":visible" ); 480 481 if ( $( '.opc_order_review tfoot .recurring-totals' ).children().length>0 ) { 482 483 // Hide create account option checkbox container if it was visible 484 if ( create_account_p_original_visibility ) { 485 $p_create_account.hide(); 486 } 487 488 // And to be safe ensure the checkbox is checked 489 $( '#createaccount' ).prop( 'checked', true ); 490 491 // If the fields weren't visible to begin with lets show them 492 if ( ! create_account_div_original_visibility ) { 493 $dif_create_account.show(); //show div 494 } 495 } else { 496 497 // If visible originally - lets make sure its visible once again 498 if ( 'no' === wc_checkout_params.wcopc_option_guest_checkout ) { 499 $p_create_account.hide(); 500 $dif_create_account.show(); 501 $( '#createaccount' ).prop( 'checked', true ); 502 } else { 503 $p_create_account.show(); 504 $dif_create_account.hide(); 505 $( '#createaccount' ).prop( 'checked', false ); 506 } 507 } 508 } 509 } 510 511} ); 512 513/*! jQuery visible 1.1.0 teamdf.com/jquery-plugins | teamdf.com/jquery-plugins/license */ 514(function(d){d.fn.visible=function(e,i){var a=d(this).eq(0),f=a.get(0),c=d(window),g=c.scrollTop();c=g+c.height();var b=a.offset().top,h=b+a.height();a=e===true?h:b;b=e===true?b:h;return!!(i===true?f.offsetWidth*f.offsetHeight:true)&&b<=c&&a>=g}})(jQuery);
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.