$(function() { $('form.ajax').on('submit', function(e) { e.preventDefault(); e.stopImmediatePropagation(); var $form = $(this), $submitButton = $form.find('input[type=submit]'), ajaxFormConf = { delegation: true, beforeSerialize: function(jqForm, options) { window.doSubmit = true; clearFormErrors(jqForm[0]); toggleSubmitDisabled($submitButton); }, beforeSubmit: function() { $submitButton = $form.find('input[type=submit]'); toggleSubmitDisabled($submitButton); return window.doSubmit; }, error: function(data, statusText, xhr, $form) { $submitButton = $form.find('input[type=submit]'); // Form validation error. if (422 == data.status) { processFormErrors($form, $.parseJSON(data.responseText)); return; } toggleSubmitDisabled($submitButton); showMessage(lang("whoops")); }, success: function(data, statusText, xhr, $form) { var $submitButton = $form.find('input[type=submit]'); if (data.message) { showMessage(data.message); } switch (data.status) { case 'success': if (data.redirectUrl) { if(data.redirectData) { $.redirectPost(data.redirectUrl, data.redirectData); } else { document.location.href = data.redirectUrl; } } break; case 'error': if (data.messages) { processFormErrors($form, data.messages); return; } break; default: break; } toggleSubmitDisabled($submitButton); }, dataType: 'json' }; toggleSubmitDisabled($submitButton); if ($form.hasClass('payment-form') && !$('#pay_offline').is(":checked")) { clearFormErrors($('.payment-form')); Stripe.setPublishableKey($form.data('stripe-pub-key')); var noErrors = true, $cardNumber = $('.card-number'), $cardName = $('.card-name'), $cvcNumber = $('.card-cvc'), $expiryMonth = $('.card-expiry-month'), $expiryYear = $('.card-expiry-year'); if (!Stripe.validateCardNumber($cardNumber.val())) { showFormError($cardNumber, lang("credit_card_error")); noErrors = false; } if (!Stripe.validateCVC($cvcNumber.val())) { showFormError($cardNumber, lang("cvc_error")); noErrors = false; } if (!Stripe.validateExpiry($expiryMonth.val(), $expiryYear.val())) { showFormError($cardNumber, lang("expiry_error")); showFormError($expiryYear, ''); noErrors = false; } if (noErrors) { Stripe.card.createToken({ name: $cardName.val(), number: $cardNumber.val(), cvc: $cvcNumber.val(), exp_month: $expiryMonth.val(), exp_year: $expiryYear.val() }, function(status, response) { if (response.error) { clearFormErrors($('.payment-form')); if(response.error.param.length>0) showFormError($('*[data-stripe=' + response.error.param + ']', $('.payment-form')), response.error.message); else showMessage(response.error.message); toggleSubmitDisabled($submitButton); } else { var token = response.id; $form.append($('').val(token)); $form.ajaxSubmit(ajaxFormConf); } }); } else { showMessage(lang("card_validation_error")); toggleSubmitDisabled($submitButton); } } else { $form.ajaxSubmit(ajaxFormConf); } }); $('a').smoothScroll({ offset: -60 }); /* Scroll to top */ $(window).scroll(function() { if ($(this).scrollTop() > 100) { $('.totop').fadeIn(); } else { $('.totop').fadeOut(); } }); $('#organiserHead').on('click', function(e) { e.stopImmediatePropagation(); $('#organiser')[0].scrollIntoView(); }); $('#contact_organiser').on('click', function(e) { e.preventDefault(); $('.contact_form').slideToggle(); }); $('#mirror_buyer_info').on('click', function(e) { $('.ticket_holder_first_name').val($('#order_first_name').val()); $('.ticket_holder_last_name').val($('#order_last_name').val()); $('.ticket_holder_email').val($('#order_email').val()); }); $('.card-number').payment('formatCardNumber'); $('.card-cvc').payment('formatCardCVC'); $('#pay_offline').change(function () { $('.online_payment').toggle(!this.checked); $('.offline_payment').toggle(this.checked); // Disable CC form inputs to prevent Chrome trying to validate hidden fields $('.online_payment input, .online_payment select').attr('disabled', this.checked); }).change(); // Apply access code here to unlock hidden tickets $('#apply_access_code').click(function(e) { var $clicked = $(this); // Hide any previous errors $clicked.closest('.form-group') .removeClass('has-error'); var url = $clicked.closest('.has-access-codes').data('url'); var data = { 'access_code': $('#unlock_code').val(), '_token': $('input:hidden[name=_token]').val() }; $.post(url, data, function(response) { if (response.status === 'error') { // Show any access code errors $clicked.closest('.form-group').addClass('has-error'); showMessage(response.message); return; } $clicked.closest('.has-access-codes').before(response); $('#unlock_code').val(''); $clicked.closest('.has-access-codes').remove(); }); }); }); function processFormErrors($form, errors) { $.each(errors, function (index, error) { var selector = (index.indexOf(".") >= 0) ? '.' + index.replace(/\./g, "\\.") : ':input[name=' + index + ']'; var $input = $(selector, $form); if ($input.prop('type') === 'file') { $('#input-' + $input.prop('name')).append('
' + error + '
') .parent() .addClass('has-error'); } else { if($input.parent().hasClass('input-group')) { $input = $input.parent(); } $input.after('
' + error + '
') .parent() .addClass('has-error'); } }); var $submitButton = $form.find('input[type=submit]'); toggleSubmitDisabled($submitButton); } /** * Toggle a submit button disabled/enabled * * @param element $submitButton * @returns void */ function toggleSubmitDisabled($submitButton) { if ($submitButton.hasClass('disabled')) { $submitButton.attr('disabled', false) .removeClass('disabled') .val($submitButton.data('original-text')); return; } $submitButton.data('original-text', $submitButton.val()) .attr('disabled', true) .addClass('disabled') .val(lang("processing")); } /** * Clears given form of any error classes / messages * * @param {Element} $form * @returns {void} */ function clearFormErrors($form) { $($form) .find('.error.help-block') .remove(); $($form).find(':input') .parent() .removeClass('has-error'); $($form).find(':input') .parent().parent() .removeClass('has-error'); } function showFormError($formElement, message) { $formElement.after('
' + message + '
') .parent() .addClass('has-error'); } /** * Shows users a message. * Currently uses humane.js * * @param string message * @returns void */ function showMessage(message) { humane.log(message, { timeoutAfterMove: 3000, waitForMove: true }); } function hideMessage() { humane.remove(); } /** * Counts down to the given number of seconds * * @param element $element * @param int seconds * @returns void */ function setCountdown($element, seconds) { var endTime, mins, msLeft, time, twoMinWarningShown = false; function twoDigits(n) { return (n <= 9 ? "0" + n : n); } function updateTimer() { msLeft = endTime - (+new Date); if (msLeft < 1000) { alert(lang("time_run_out")); location.reload(); } else { if (msLeft < 120000 && !twoMinWarningShown) { showMessage(lang("just_2_minutes")); twoMinWarningShown = true; } time = new Date(msLeft); mins = time.getUTCMinutes(); $element.html('' + mins + ':' + twoDigits(time.getUTCSeconds()) + ''); setTimeout(updateTimer, time.getUTCMilliseconds() + 500); } } endTime = (+new Date) + 1000 * seconds + 500; updateTimer(); } $.extend( { redirectPost: function(location, args) { var form = ''; $.each( args, function( key, value ) { value = value.split('"').join('\"') form += ''; }); $('
' + form + '
').appendTo($(document.body)).submit(); } }); /*! * Smooth Scroll - v1.4.13 - 2013-11-02 * https://github.com/kswedberg/jquery-smooth-scroll * Copyright (c) 2013 Karl Swedberg * Licensed MIT (https://github.com/kswedberg/jquery-smooth-scroll/blob/master/LICENSE-MIT) */ (function(t) { function e(t) { return t.replace(/(:|\.)/g, "\\$1") } var l = "1.4.13", o = {}, s = {exclude: [], excludeWithin: [], offset: 0, direction: "top", scrollElement: null, scrollTarget: null, beforeScroll: function() { }, afterScroll: function() { }, easing: "swing", speed: 400, autoCoefficent: 2, preventDefault: !0}, n = function(e) { var l = [], o = !1, s = e.dir && "left" == e.dir ? "scrollLeft" : "scrollTop"; return this.each(function() { if (this != document && this != window) { var e = t(this); e[s]() > 0 ? l.push(this) : (e[s](1), o = e[s]() > 0, o && l.push(this), e[s](0)) } }), l.length || this.each(function() { "BODY" === this.nodeName && (l = [this]) }), "first" === e.el && l.length > 1 && (l = [l[0]]), l }; t.fn.extend({scrollable: function(t) { var e = n.call(this, {dir: t}); return this.pushStack(e) }, firstScrollable: function(t) { var e = n.call(this, {el: "first", dir: t}); return this.pushStack(e) }, smoothScroll: function(l, o) { if (l = l || {}, "options" === l) return o ? this.each(function() { var e = t(this), l = t.extend(e.data("ssOpts") || {}, o); t(this).data("ssOpts", l) }) : this.first().data("ssOpts"); var s = t.extend({}, t.fn.smoothScroll.defaults, l), n = t.smoothScroll.filterPath(location.pathname); return this.unbind("click.smoothscroll").bind("click.smoothscroll", function(l) { var o = this, r = t(this), i = t.extend({}, s, r.data("ssOpts") || {}), c = s.exclude, a = i.excludeWithin, f = 0, h = 0, u = !0, d = {}, p = location.hostname === o.hostname || !o.hostname, m = i.scrollTarget || (t.smoothScroll.filterPath(o.pathname) || n) === n, S = e(o.hash); if (i.scrollTarget || p && m && S) { for (; u && c.length > f; ) r.is(e(c[f++])) && (u = !1); for (; u && a.length > h; ) r.closest(a[h++]).length && (u = !1) } else u = !1; u && (i.preventDefault && l.preventDefault(), t.extend(d, i, {scrollTarget: i.scrollTarget || S, link: o}), t.smoothScroll(d)) }), this }}), t.smoothScroll = function(e, l) { if ("options" === e && "object" == typeof l) return t.extend(o, l); var s, n, r, i, c = 0, a = "offset", f = "scrollTop", h = {}, u = {}; "number" == typeof e ? (s = t.extend({link: null}, t.fn.smoothScroll.defaults, o), r = e) : (s = t.extend({link: null}, t.fn.smoothScroll.defaults, e || {}, o), s.scrollElement && (a = "position", "static" == s.scrollElement.css("position") && s.scrollElement.css("position", "relative"))), f = "left" == s.direction ? "scrollLeft" : f, s.scrollElement ? (n = s.scrollElement, /^(?:HTML|BODY)$/.test(n[0].nodeName) || (c = n[f]())) : n = t("html, body").firstScrollable(s.direction), s.beforeScroll.call(n, s), r = "number" == typeof e ? e : l || t(s.scrollTarget)[a]() && t(s.scrollTarget)[a]()[s.direction] || 0, h[f] = r + c + s.offset, i = s.speed, "auto" === i && (i = h[f] || n.scrollTop(), i /= s.autoCoefficent), u = {duration: i, easing: s.easing, complete: function() { s.afterScroll.call(s.link, s) }}, s.step && (u.step = s.step), n.length ? n.stop().animate(h, u) : s.afterScroll.call(s.link, s) }, t.smoothScroll.version = l, t.smoothScroll.filterPath = function(t) { return t.replace(/^\//, "").replace(/(?:index|default).[a-zA-Z]{3,4}$/, "").replace(/\/$/, "") }, t.fn.smoothScroll.defaults = s })(jQuery);