public/javascripts/checkout.js in spree-0.7.1 vs public/javascripts/checkout.js in spree-0.8.0

- old
+ new

@@ -1,15 +1,41 @@ -var regions = new Array('billing', 'shipping', 'shipping_method', 'creditcard', 'confirm_order'); +//On page load +$(function() { + $('#checkout_same_address').sameAddress(); + $('span#bcountry select').change(function() { update_state('b'); }); + $('span#scountry select').change(function() { update_state('s'); }); + get_states(); + + // hook up the continue buttons for each section + for(var i=0; i < regions.length; i++) { + var section = regions[i]; + $('#continue_' + section).click(function() { eval( "continue_button(this);") }); + + // enter key should be same as continue button (don't submit form though) + $('#' + section + ' input').bind("keyup", section, function(e) { + if(e.keyCode == 13) { + continue_section(e.data); + } + }); + } + //disable submit + $(':submit').attr('disabled', 'disbled'); + + // hookup the radio buttons for registration + $('#choose_register').click(function() { $('div#new_user').show(); $('div#guest_user, div#existing_user').hide(); }); + $('#choose_existing').click(function() { $('div#existing_user').show(); $('div#guest_user, div#new_user').hide(); }); + $('#choose_guest').click(function() { $('div#guest_user').show(); $('div#existing_user, div#new_user').hide(); }); + var reg_choice = $('input[name=choose_registration]:checked').val(); + if(reg_choice) { + $('#choose_' + reg_choice).click(); + } else { + $('#choose_register').attr('checked', true); + } -/* -$(document).ajaxSend(function(event, request, settings) { - if (typeof(AUTH_TOKEN) == "undefined") return; - // settings.data is a serialized string like "foo=bar&baz=boink" (or null) - settings.data = settings.data || ""; - settings.data += (settings.data ? "&" : "") + "authenticity_token=" + encodeURIComponent(AUTH_TOKEN); -}); -*/ + // activate first region + shift_to_region(regions[0]); +}) jQuery.fn.sameAddress = function() { this.click(function() { if(!$(this).attr('checked')) { //Clear ship values? @@ -19,25 +45,12 @@ $("#billing input, #billing select").each(function() { $("#shipping #"+ $(this).attr('id').replace('bill', 'ship')).val($(this).val()); }) update_state('s'); }) -} +}; -//On page load -$(function() { - $('#checkout_presenter_same_address').sameAddress(); - $('span#bcountry select').change(function() { update_state('b'); }); - $('span#scountry select').change(function() { update_state('s'); }); - get_states(); - $('#validate_billing').click(function() { if(validate_section('billing')) { submit_billing(); }}); - $('#validate_shipping').click(function() { if(validate_section('shipping')) { submit_shipping(); }}); - $('#select_shipping_method').click(function() { submit_shipping_method(); }); - $('#confirm_payment').click(function() { if(validate_section('creditcard')) { confirm_payment(); }}); - $('form#checkout_form').submit(function() { return !($('div#confirm_order').hasClass('checkout_disabled')); }); -}) - //Initial state mapper on page load var state_mapper; var get_states = function() { $.getJSON('/states.js', function(json) { state_mapper = json; @@ -70,11 +83,10 @@ child.remove(); // better as parent-relative? parent.append(html); return html; }; - // TODO: better as sibling dummy state ? // Update the input method for address.state var update_state = function(region) { var country = $('span#' + region + 'country :only-child').val(); var states = state_mapper[country]; @@ -82,16 +94,17 @@ var replacement; if(states) { // recreate state selection list replacement = $(document.createElement('select')); - $.each(states, function(id,nm) { + var states_with_blank = [["",""]].concat(states); + $.each(states_with_blank, function(pos,id_nm) { var opt = $(document.createElement('option')) - .attr('value', id) - .html(nm); - replacement.append(opt) - if (id == hidden_element.val()) { opt.attr('selected', 'true') } + .attr('value', id_nm[0]) + .html(id_nm[1]); + replacement.append(opt); + if (id_nm[0] == hidden_element.val()) { opt.attr('selected', 'true') } // set this directly IFF the old value is still valid }); } else { // recreate an input box replacement = $(document.createElement('input')); @@ -105,57 +118,81 @@ // This is only needed if we want to preserve state when someone refreshes the checkout page // Or... if someone changes between countries with no given states replacement.change(function() { $('input#hidden_' + region + 'state').val($(this).val()); }); +}; + +var continue_button = function(button) { + continue_section(button.id.substring(9)); +}; + +var continue_section = function(section) { + // validate + if (!validate_section(section)) { return; }; + // submit + var success = eval("submit_" + section + "();"); + if (!success) { return; } + // move to next section + for(var i=0; i<regions.length; i++) { + if (regions[i] == section) { + if (i == (regions.length - 1)) { break; }; + shift_to_region(regions[i+1]); + } + } }; var validate_section = function(region) { + if(region == 'shipping_method') { return true; } var validator = $('form#checkout_form').validate(); var valid = true; - $('div#' + region + ' input, div#' + region + ' select, div#' + region + ' textarea').each(function() { + $('div#' + region + ' input:visible, div#' + region + ' select:visible, div#' + region + ' textarea:visible').each(function() { if(!validator.element(this)) { valid = false; } }); return valid; }; var shift_to_region = function(active) { - $('div#flash-errors').remove(); + if (active != regions[0]) { $('div#flash-errors').remove(); } var found = 0; for(var i=0; i<regions.length; i++) { if(!found) { if(active == regions[i]) { $('div#' + regions[i] + ' h2').unbind('click').css('cursor', 'default'); $('div#' + regions[i] + ' div.inner').show('fast'); - $('div#' + regions[i]).removeClass('checkout_disabled'); + $('div#' + regions[i]).removeClass('checkout_disabled').removeClass('disabled').removeClass('completed'); found = 1; } else { $('div#' + regions[i] + ' h2').unbind('click').css('cursor', 'pointer').click(function() {shift_to_region($(this).parent().attr('id'));}); $('div#' + regions[i] + ' div.inner').hide('fast'); + $('div#' + regions[i]).addClass('disabled').addClass('completed'); } } else { $('div#' + regions[i] + ' h2').unbind('click').css('cursor', 'default'); $('div#' + regions[i] + ' div.inner').hide('fast'); - $('div#' + regions[i]).addClass('checkout_disabled'); + $('div#' + regions[i]).addClass('checkout_disabled').addClass('disabled').removeClass('completed'); } } - if (active == 'confirm_order') { + if (active == 'confirmation') { $("input#final_answer").attr("value", "yes"); + $('#continue_confirmation').removeAttr('disabled', 'disabled'); + $('#post-final').removeAttr('disabled', 'disabled'); } else { // indicates order is ready to be processed (as opposed to simply updated) - $("input#final_answer").attr("value", ""); + $("input#final_answer").attr("value", ""); + // disable form submit + $(':submit').attr('disabled', 'disbled'); } return; }; var submit_billing = function() { - shift_to_region('shipping'); build_address('Billing Address', 'b'); - return; + return true; }; var build_address = function(title, region) { var address = '<h3>' + title + '</h3>'; address += $('p#' + region + 'fname input').val() + ' ' + $('p#' + region + 'lname input').val() + '<br />'; @@ -176,31 +213,32 @@ return; }; var submit_shipping = function() { $('div#methods :child').remove(); + $('div#shipping_method div.error').hide(); $('div#methods').append($(document.createElement('img')).attr('src', '/images/ajax_loader.gif').attr('id', 'shipping_loader')); // Save what we have so far and get the list of shipping methods via AJAX $.ajax({ type: "POST", - url: 'complete', + url: 'checkout', beforeSend : function (xhr) { xhr.setRequestHeader('Accept-Encoding', 'identity'); - }, + }, dataType: "json", data: $('#checkout_form').serialize(), success: function(json) { update_shipping_methods(json.available_methods); }, error: function (XMLHttpRequest, textStatus, errorThrown) { - // TODO - put some real error handling in here - $("#error").html(XMLHttpRequest.responseText); + $('div#methods :child').remove(); + $('div#shipping_method div.error').show(); + return false; } }); - shift_to_region('shipping_method'); build_address('Shipping Address', 's'); - return; + return true; }; var submit_shipping_method = function() { //TODO: Move to validate_section('shipping_method'), but must debug how to validate radio buttons var valid = false; @@ -211,29 +249,31 @@ }); if(valid) { // Save what we have so far and get the updated order totals via AJAX $.ajax({ type: "POST", - url: 'complete', + url: 'checkout', beforeSend : function (xhr) { xhr.setRequestHeader('Accept-Encoding', 'identity'); }, dataType: "json", data: $('#checkout_form').serialize(), success: function(json) { - update_confirmation(json.order); + update_confirmation(json); }, error: function (XMLHttpRequest, textStatus, errorThrown) { // TODO - put some real error handling in here - //$("#error").html(XMLHttpRequest.responseText); + //$("#error").html(XMLHttpRequest.responseText); + return false; } }); - shift_to_region('creditcard'); + return true; } else { var p = document.createElement('p'); $(p).append($(document.createElement('label')).addClass('error').html('Please select a shipping method').css('width', '300px').css('top', '0px')); $('div#methods').append(p); + return false; } }; var update_shipping_methods = function(methods) { $(methods).each( function(i) { @@ -244,29 +284,125 @@ .attr('id', this.id) .attr('type', 'radio') .attr('name', 'method_id') .val(this.id) .click(function() { $('div#methods input').attr('checked', ''); $(this).attr('checked', 'checked'); }); - if($(methods.length) == 1) { + if($(methods).length == 1) { i.attr('checked', 'checked'); } var l = $(document.createElement('label')) .attr('for', s) - .html(s) - .css('top', '-1px') - .css('width', '300px'); + .html(s); $('div#methods').append($(p).append(i).append(l)); }); $('div#methods input:first').attr('validate', 'required:true'); return; -} +}; var update_confirmation = function(order) { $('span#order_total').html(order.order_total); $('span#ship_amount').html(order.ship_amount); $('span#tax_amount').html(order.tax_amount); $('span#ship_method').html(order.ship_method); -} +}; -var confirm_payment = function() { - shift_to_region('confirm_order'); +var submit_registration = function() { + // no need to do any ajax, user is already logged in + if ($('div#already_logged_in:hidden').size() == 0) return true; + var register_method = $('input[name=choose_registration]:checked').val(); + + $('div#registration_error').removeClass('error').html(''); + + if (register_method == 'existing') { + ajax_login(); + } + else if (register_method == 'register') { + ajax_register(); + } + + return ($('div#registration_error').html() == ""); +}; + +var ajax_login = function() { + $.ajax({ + async: false, + type: "POST", + url: '/user_session', + beforeSend : function (xhr) { + xhr.setRequestHeader('Accept-Encoding', 'identity'); + }, + dataType: "json", + data: $('#checkout_form').serialize(), + success: function(result) { + if (result) { + $('div#already_logged_in').show(); + $('div#register_or_guest').hide(); + update_login(); + } else { + registration_error("Invalid username or password."); + }; + }, + error: function (XMLHttpRequest, textStatus, errorThrown) { + registration_error("Unable to perform login due to a server error."); + } + }); +}; + +var ajax_register = function() { + $.ajax({ + async: false, + type: "POST", + url: '/users', + beforeSend : function (xhr) { + xhr.setRequestHeader('Accept-Encoding', 'identity'); + }, + dataType: "json", + data: $('#checkout_form').serialize(), + success: function(result) { + if (result == true) { + $('div#already_logged_in').show(); + $('div#register_or_guest').hide(); + update_login(); + } else { + var error_msg = "Unable to register user"; + for (var i=0; i < result.length; i++) { + error_msg += "<br/>"; + error_msg += result[i][0] + ": " + result[i][1]; + } + registration_error(error_msg); + }; + }, + error: function (XMLHttpRequest, textStatus, errorThrown) { + registration_error("Unable to register due to a server error."); + } + }); +}; + +var registration_error = function(error_message) { + $('div#registration_error').addClass('error').html(error_message); +}; + +var submit_payment = function() { + return true; +}; + +var submit_confirmation = function() { + //$('form').submit(); + $('#post-final').click(); +}; + +// update login partial +var update_login = function() { + $.ajax({ + url: '/user_session/login_bar', + beforeSend : function (xhr) { + xhr.setRequestHeader('Accept-Encoding', 'identity'); + }, + dataType: "html", + success: function(result) { + $("div#login-bar").html(result); + }, + error: function (XMLHttpRequest, textStatus, errorThrown) { + // TODO (maybe do nothing) + } + }); };