$(function () { /** * SHIPPING STEP */ // Shipping address selection $(document).on('change', '#shipping-address [type=radio], #billing-address [type=radio]', function () { if (!$(this).val()) { // Only make fields with a name required. no-named fields are probably generated by chosen or other form plugins $("#new-address").slideDown().find('input[type=text],input[type=tel]').filter('[name]').not('[name="address2"],[name="company"]').prop('required', true); } else { $("#new-address").slideUp().find('input[type=text],input[type=tel]').prop('required', false); } }); $('.shipping input[type=radio]:checked, #billing-address input[type=radio]:checked').change(); // Reflect shipping method changes $(document).on('change', '.shipping .methods .rates input', function () { $('.summary .shipping .amount').text($(this).filter(":checked").next().find('.amount').text()); updateSummary(); }); // Shipping rates on locality or address change $('body').on('change', '.shipping [name*=locality], .shipping [name*=country], .shipping [name*=postal_code], .shipping [name*=city]', reload_rates); $(document).on('click', '.shipping [name*=existing_address]', reload_rates); if ($('form.shipping').length) reload_rates(); /** * BILLING STEP */ // Collapse billing address form on "same as shipping?" $(document).on('change', '[name="same_as_shipping"]', function () { // Don't make the address fields required if an existing address is selected if ($('#billing-address [type=radio]:checked').val() && $('#billing-address [type=radio]:checked').val() != 'new') { $('#billing-address .address').find('input[type=text],input[type=tel]').prop('required', false); return; } if ($(this).prop('checked')) { $('#billing-address #new-address > .address').slideUp().find('input[type=text],input[type=tel]').prop('required', false); } else { // Only make fields with a name required. no-named fields are probably generated by chosen or other form plugins $('#billing-address #new-address > .address').slideDown().find('input[type=text],input[type=tel]').filter('[name]').not('[name="address2"],[name="company"]').prop('required', true); } }); $('[name="same_as_shipping"]').change(); // Credit card highlighting $(document).on('keyup', '[id$="CreditCard"] .number [name$="number"], #PayPalPayFlow .number [name$="number"]', function () { var wrapper = $('.payment-method'), methods = wrapper.find('[data-prefix]'), regexes = wrapper.find('[data-regex]'), number = $(this).val(); methods.removeClass('active'); wrapper.removeClass('method-active'); if (number == '*') return false; regexes.each(function () { var re = new RegExp($(this).data('regex')); if (re.test(number)) { $(this).addClass('active') } }); if (methods.filter('[data-prefix].active').length > 0) { $('.payment-method').addClass('method-active'); } }); // If the credit card number field is empty or only digits // set the pattern to "[0-9]*" to invoke mobile keyboards. When // other characters are entered remove the digit pattern. var creditCardNumber = $('[id$="CreditCard"] .number [name$="number"]'); if (creditCardNumber.length > 0) { function checkPattern(input) { if (input.val().match(/^[0-9]*$/)) { input.attr('pattern', '[0-9]*'); } else { input.removeAttr('pattern'); } } checkPattern(creditCardNumber); creditCardNumber.on('touchstart focus blur keyup', function (e) { checkPattern($(this)); }); } // Payment method toggling $(document).on('click', '.payment-method ul input', function () { togglePaymentMethodExtras(this); }); if ($('form.billing').length) { togglePaymentMethodExtras($('form.billing').find('input[name="payment_method"]:checked')); } // Account balance handling $(document).on('click', '[name=use_account_balance]', function () { var remaining_balance = $('[data-remaining-balance]'); remaining_balance.slideToggle(); if (!$(this).prop('checked')) { var requires_address = $('form.billing').find('input[name="payment_method"]:checked').closest('li[data-requires-address]').data('requires-address'); if (!requires_address || requires_address === "True") { $('.payment-method, #billing-address').slideDown(); } } else if (parseFloat(remaining_balance.data('remaining-balance')) <= 0) { $('.payment-method, #billing-address').slideUp(); } // Stop required billing address fields when there is no balance if (parseFloat(remaining_balance.data('remaining-balance')) <= 0) { toggleBillingForm(false); } }); /** * REVIEW STEP */ // Show registration box $(document).on('change', '.create-account [type=checkbox]', function () { $('.account-password').slideToggle(); }); // Disabled submit button to prevent double submissions $(document).on('submit', '.checkout form.shipping, .checkout form.billing, .checkout form.review', function () { submitButton = $(this).find('[type=submit]'); if (submitButton.data('loading-text')) { submitButton.val(submitButton.data('loading-text')); } submitButton.addClass('loading').prop('disabled', true); }); }); var shipping_rates_timer; var ratesXhr = null; function getShippingRates(url, params) { // If you call this method multiple times within 333 milliseconds it will // wait 333 milliseconds after the last call and only call it once. // This eliminates getting rates multiple times for the same form changes. if (shipping_rates_timer) clearTimeout(shipping_rates_timer); shipping_rates_timer = setTimeout(function () { current_rate = $("[name*=shipping_rate]:checked").val(); var ratesContainer = $('.shipping .methods ul.rates'); ratesContainer.addClass('loading').find('input').prop('disabled', true); //cancel previous requests if (ratesXhr) { ratesXhr.abort() } ratesXhr = $.getJSON(url, params, function (data) { ratesXhr = null; template = _.template($('#shipping-rate-choice').html()); ratesContainer.empty(); $.each(data.rates, function (index, rate) { ratesContainer.append(template(rate)); }); // Select first rate if no rate currently selected if (current_rate && $("[name*=shipping_rate][value=" + current_rate + "]").length > 0) { $("[name*=shipping_rate][value=" + current_rate + "]").prop("checked", true); } else { $("[name*=shipping_rate]:first").prop("checked", true); } ratesContainer.find('input').trigger('change'); ratesContainer.removeClass('loading'); $('input[type=submit]').prop('disabled', false); if ($('.shipping [name*=shipping_rate]').length > 0) { $('.summary .shipping .amount').text($('.shipping [name*=shipping_rate]').filter(":checked").next().find('.amount').text()); updateSummary(); } }); }, 333); } function reload_rates() { if ($('.virtual-items').length > 0) { $('input[type=submit]').prop('disabled', false); return true; } $('input[type=submit]').prop('disabled', true); var url = '/api/shipping_rates/', existing_address = $('.shipping [name*=existing_address]:checked').val(), street_address = $('.shipping [name=address]'), locality_select = $('.shipping [name*=locality]'), country_select = $('.shipping [name*=country]'), postal_code = $('.shipping [name*=postal_code]'), city = $('.shipping [name*=city]'), params = {}; if (existing_address) { params['address_id'] = existing_address; } else { if (locality_select.not(':disabled').length && locality_select.val() != '') { params['locality_id'] = locality_select.val() } if (country_select.val() != '') params['country_id'] = country_select.val(); if (postal_code.val()) params['postal_code'] = postal_code.val(); if (street_address.val()) params['address'] = street_address.val(); if (city.val()) params['city'] = city.val(); } getShippingRates(url, params); } function updateSummary() { $('.summary').each(function () { total = 0; $(this).find('tr:not(.total,.vat) .amount').each(function () { total += $(this).text().toCents(); }); $(this).find('.total .amount').currency(total); }); } function togglePaymentMethodExtras(e) { var method = $(e); var method_name = method.val().toLowerCase(); $(".payment-method > div.payment-method-extras:not(." + method_name + "-extras)").slideUp(); $("." + method_name + "-extras").slideDown(function () { method.find("input").eq(0).focus(); }); var method_li = method.closest('li[data-requires-address]'); if (method_li) { var submit_button = $('[type=submit]'); if (method_li.data('hide-submit-button') === "True") { submit_button.hide(); } else { submit_button.show(); } } if (method_li) { if (method_li.data('requires-address') === "True") { toggleBillingForm(true); $('#billing-address').slideDown() } else { toggleBillingForm(false); $('#billing-address').slideUp() } } } function toggleBillingForm(set) { var fields = $('#billing-address #new-address > .address').find('input[type=text],input[type=tel]').filter('[name]').not('[name="address2"],[name="company"]'); fields.each(function () { var $this = $(this), datavar = 'abrequired'; // Is there an ab-required data? if (set === undefined && ($this.data(datavar) !== undefined) || set === true) { // There is, set the required prop to this value and remove the data $this.prop('required', $this.data(datavar)); $this.removeData(datavar); } else { // There isn't, set the datavar to the required prop and set required to false $this.data(datavar, $this.prop('required')); $this.prop('required', false); } }); }