window.$ = window.jQuery; var animateObj = null let userInteracted = false; // refresh page if (sessionStorage.getItem('need-refresh')) { sessionStorage.removeItem('need-refresh'); window.location.reload(); } function scrollAnimate() { if (animateObj) { clearTimeout(animateObj) } animateObj = setTimeout(function () { if ($(".form-group.is-invalid").length > 0) { $('html, body').animate({ scrollTop: $(".form-group.is-invalid").eq(0).offset().top - 50 }, 500); } }, 100) } // ------------- -------------------validateForm----------------------------------------------// /** * Validate whole form. Requires `this` to be set to form object * @param {jQuery.event} event - Event to be canceled if form is invalid. * @returns {boolean} - Flag to indicate if form is valid */ function validateForm(event) { var valid = true; $(this).find('input, select, textarea').each(function () { if ($(this).is(':hidden')) { if ($(this).attr('required') && !$(this).val()) { this.setCustomValidity("Required field."); valid = false; } else { this.setCustomValidity(""); } return; } if (!this.validity.valid) { $(this).trigger('invalid', this.validity); valid = false; } }); if ($(this).is(':checkbox')) { var checkboxes = $(this).closest('.multi-selection').find('input[type="checkbox"]'); validateMultiSelection($(this)); valid = validateMultiSelection($(this)) && valid; } if (!valid && event) { event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); } return valid; } function validateMultiSelection(event) { var valid = true; var multiSelection = $('.multi-selection:not(.disabled)'); if (event) { multiSelection = event.closest('.multi-selection'); } multiSelection.each(function () { var self = $(this); if (self.find('input:checked').length === 0) { self.closest('.form-group').addClass('is-invalid multi-selection-invalid'); valid = false; } else { self.closest('.form-group').removeClass('is-invalid multi-selection-invalid'); } }); return valid; } /** * Remove all validation. Should be called every time before revalidating form * @param {element} form - Form to be cleared * @returns {void} */ function clearForm(form, selfObj) { if (typeof selfObj !== 'undefined') { selfObj.removeClass('is-invalid'); // bootstrap-select selfObj.parents('.form-group').find('.bootstrap-select').removeClass('is-invalid'); selfObj.parents('.form-group').removeClass('is-invalid multi-selection-invalid') } else { $(form).find('.form-control.is-invalid').removeClass('is-invalid multi-selection-invalid'); } } function initClientSideValidation() { $('form input, form select, form textarea').on('invalid', function (e, data) { e.preventDefault(); this.setCustomValidity(''); if (!this.validity.valid) { var validationMessage = this.validationMessage; $(this).addClass('is-invalid'); // bootstrap-select $(this).parents('.form-group').find('.bootstrap-select').addClass('is-invalid'); if ( this.validity.patternMismatch && $(this).data('pattern-mismatch') ) { validationMessage = $(this).data('pattern-mismatch'); } if ( (this.validity.rangeOverflow || this.validity.rangeUnderflow) && $(this).data('range-error') ) { validationMessage = $(this).data('range-error'); } if ( (this.validity.tooLong || this.validity.tooShort) && $(this).data('range-error') ) { validationMessage = $(this).data('range-error'); } if ( this.validity.valueMissing && $(this).data('missing-error') ) { validationMessage = $(this).data('missing-error'); } $(this) .parents('.form-group').addClass('is-invalid') $(this) .parents('.form-group') .find('.invalid-feedback') .text(validationMessage); } if (!userInteracted) { validateMultiSelection() scrollAnimate() } userInteracted = false; }); $('form').on('submit', function (e) { scrollAnimate() window.addEventListener('unload', function () { sessionStorage.setItem('need-refresh', 'true'); }); return validateForm.call(this, e) && validateMultiSelection(); }); $('form select').on('change', function (e) { clearForm($(this).parents('form'), $(this)); if ($(this).hasClass('selectpicker')) { $(this).selectpicker('refresh'); } userInteracted = true; return validateForm.call(this, e); }); $('form input:not(.tel-input-status),form textarea').bind( 'input propertychange change', function (e) { clearForm($(this).parents('form'), $(this)); userInteracted = true; return validateForm.call(this, e); } ); $('form button[type="submit"], form input[type="submit"]').on( 'click', function () { // clear all errors when trying to submit the form clearForm($(this).parents('form')); } ); } function customValidateForm(form, event) { if (typeof form !== 'undefined') { return validateForm.call(form, event || null); } } // ------------- -------------------intlTelInputPhone----------------------------------------------// /** * * @param {HTMLElement|js} input - The element to create the carousel for. * @param {HTMLElement|jQuery} errorMsg - error label JQ Object * @param {HTMLElement|jQuery} phoneObj - * @param {String} defaultCountryCode - * @param {Array} countrieLists - * */ function intlTelInputPhone( parentClass, defaultCountryCode, countrieLists ) { var countryCode = defaultCountryCode ? defaultCountryCode : 'hk'; var Countries = ['us', 'gb', 'hk', 'cn', 'ph']; if (countrieLists != undefined) { Countries = countrieLists; if (countrieLists == []) { Countries = undefined; } } var input = $(parentClass + ' .tel-input-status'); var errorMsg = $(parentClass + ' .invalid-feedback'); var phoneObj = $(parentClass + ' .tel-phone-input'); var errorMap = ''; try { var errorMap = input.attr('data-error'); } catch (e) { } var autoValidate = null; // here, the index maps to the error code returned from getValidationError - see readme // initialise plugin var iti = window.intlTelInput(input[0], { onlyCountries: Countries, showFlags: false, initialCountry: countryCode, separateDialCode: true, countrySearch: false, allowDropdown: false, validationNumberType: "MOBILE", utilsScript: "https://cloud.e.lululemon.com/telInput-utils.js", // utilsScript: "https://cdn.jsdelivr.net/npm/intl-tel-input@23.8.0/build/js/utils.js", }); var reset = function () { input.parents('.form-group').removeClass('is-invalid'); input.removeClass('is-invalid'); errorMsg.removeClass('active'); errorMsg.html(''); }; function formatIntlTelInput() { if (typeof intlTelInputUtils !== 'undefined') { // utils are lazy loaded, so must check var currentText = iti.getNumber(intlTelInputUtils.numberFormat.E164); if (typeof currentText === 'string') { // sometimes the currentText is an object :) iti.setNumber(currentText); // will autoformat because of formatOnDisplay=true } } } function validate() { reset(); var inputValue = input.val().trim(); // Check if there's input if (inputValue) { if (iti.isValidNumberPrecise()) { input.attr('data-status', true); inputValue = inputValue.replace(/\D/g, ''); phoneObj.val(inputValue); } else { input.parents('.form-group').addClass('is-invalid'); input.addClass('is-invalid'); errorMsg.addClass('active'); var errorCode = iti.getValidationError(); errorMsg.html(errorMap); input.attr('data-status', false); } } else { // If no input, simply mark as valid input.attr('data-status', true); phoneObj.val(''); // Clear the phoneObj value input.removeClass('is-invalid'); errorMsg.removeClass('active'); event.preventDefault(); } formatIntlTelInput(); } // on blur: validate input[0].addEventListener('blur', function () { validate() }); // on keyup / change flag: reset input[0].addEventListener('keyup', function () { if (autoValidate != null) { clearTimeout(autoValidate) } autoValidate = setTimeout(function () { validate() }, 200) }); input.on('validate', function () { validate() }); $('body').on('setNumber', function () { var phoneNumber = $('.tel-input-status').attr('data-phoneNumber') if (phoneNumber != '') { var regex = /^\+\d+\s+/; phoneNumber = phoneNumber.replace(regex, '').trim(); $('.tel-input-status').val(phoneNumber) } }) } $(function () { if ($('.phoneNumberbox').length > 0) { intlTelInputPhone('.phoneNumberbox', $('input[name="PC_Location"]').val(), [$('input[name="PC_Location"]').val()]); $('body').trigger('setNumber') } // ------------------------------------- radio--------------------------------------------// $('.option input[type="radio"]').on('change', function () { var option = $(this).parent(); var options = $(this).closest('.options'); options.find('.option.checked input').prop('checked', false) options.find('.option.checked').removeClass('checked') option.addClass('checked') $(this).prop('checked') }) // ------------------------------------- checkbox--------------------------------------------// $('.option input[type="checkbox"]').on('change', function () { var option = $(this).parent(); option.removeClass('disabled') if (!option.hasClass('checked')) { option.addClass('checked') $(this).prop('checked') } else { option.removeClass('checked') $(this).prop('checked', false) option.addClass('disabled') } }) $('.option').on('mouseout', function () { $(this).removeClass('disabled') }); // ------------- -------------------Birthday----------------------------------------------// var backspacePressed = false; $('input.Birthday').on('keydown', function (e) { if (e.which === 8) { // Check if backspace is pressed backspacePressed = true; } else { backspacePressed = false; } }); $('input.Birthday').on('input', function () { if (backspacePressed) { return; } var input = $(this).val().replace(/\D/g, ''); // Remove non-numeric characters if (input.length >= 2) { input = input.substring(0, 2) + '/' + input.substring(2, 4); } $(this).val(input); }) // ------------- -------------------Measurement----------------------------------------------// function resetMeasurementOption() { var genderChecked = $('.option input[name="PC_Gender"]:checked'); // Remove 'checked' class from gender options $('.option input[name="PC_Gender"]').each(function () { $(this).closest('.option').removeClass('checked'); }); // Add 'checked' class to checked gender options genderChecked.each(function () { $(this).closest('.option').addClass('checked'); }); // Determine if both genders are checked var bothChecked = genderChecked.length === 2; $('.measurement').each(function () { var self = $(this); self.find('.single-option-box').removeClass('is-invalid multi-selection-invalid'); // Show all measurements if both genders are checked if (bothChecked || self.hasClass(genderChecked.val())) { self.find('.multi-selection').removeClass('disabled'); self.removeClass('tw-hidden'); } else { self.find('.multi-selection').addClass('disabled'); self.addClass('tw-hidden'); } }); } // Initial call to set the correct visibility resetMeasurementOption(); // Event listener for changes $('.option input[name="PC_Gender"]').on('change', function () { resetMeasurementOption(); }); // Initialize client-side validation initClientSideValidation(); if ($(window).width() < 768) { $('.options').each(function () { var maxWidth = 0; $(this).find('.option').each(function () { var width = $(this).outerWidth(); if (width > maxWidth) { maxWidth = width; } }) $(this).find('.option').css({ width: maxWidth }) }); } })