var RegHelper =
{
options: {
container: '#registerMultiStepContainer',
stepId: 'registration-step-',
successTimeout: 100,
disabled: false,
geoDataContainer: '.ux-geo-form-fields-container',
lastStep: 0,
displaySteps: false,
focusOnZip: 1,
liveEmailCheck: true,
validateUsername: null,
validatePass: null,
slogans: {},
tracking: true,
hashTracking: false,
gendersMap: {},
showInProgressType: 'fullscreen',
tags: ''
}
,_validator: null
,registrationInProgressAnimation: null
,Validator: function ()
{
if (!this._validator)
{
this._validator = RegValidator;
}
return this._validator;
}
,step: function (step)
{
if (false === this.validateInputs (step)) {
return false;
}
this.Tracking (step);
var id = '#' + this.options.stepId + step;
if ($ (id).length > 0) { this.display (id); }
this.setActiveStep (step);
this.focus (step);
this.resetStepErrors ();
this.hashTracking (step);
return true;
}
,hashTracking: function (step)
{
if (step && this.options.hashTracking) {
var hash = Url.hash() || '';
var regex = new RegExp('(step\-\\d+)', 'ig');
var parts = hash.split(':').filter(function (element) {
return element.replace(regex, '');
});
var components = [step ? 'step-' + step : ''].concat(parts).filter(function (element) {
return !!element;
});
window.location.hash = components.join(':');
}
}
,enableHashTracking: function () {
this.options.hashTracking = true;
this.hashTracking(1);
}
,focus: function (step)
{
var element = $('#' + this.options.stepId + step).find ('input[type="text"],input[type="number"],input[type="tel"],input[type="email"]').filter(':first');
if ($(element).attr('name') === 'zip' && this.options.focusOnZip === 0) { return true; }
if (element.length) { element.focus (); }
}
,resetStepErrors: function () {
$('.infoError').remove ();
}
,validateInputs: function (step)
{
var fe = $('#' + this.options.stepId + parseInt(step-1) + " :input");
for (var i = 0; i < fe.length; i++)
{
var name = $(fe[i]).attr('name') || '';
name.replace (/[^a-z]/ig, '');
if (!name) { return; }
name = name.replace (/[^a-z]/ig, '');
if (name.match (/birth*/g)) { name = 'birthdate'; }
if (name.match (/consent*/g)) { name = 'consents'; }
var method = 'RegHelper.validate' + this.capitalize (name);
if (eval ('typeof ' + method) === 'function' && eval (method + "();") === false) {
$(fe[i]).focus (); // focus on error
this.trackErrors(step, name);
return false;
}
}
return true;
},
capitalize: function (name) { var string = ''+name; return string.charAt(0).toUpperCase() + string.slice(1); },
validateConsents: function () { return this.Validator().checkDisclaimers (); },
validateBirthdate: function () { return this.Validator().checkBirthdate (); },
validateAge: function () { return this.Validator().checkAge (); },
validatePassword: function () {
if (this.options.validatePass !== null) { this.Validator().validatePass = this.options.validatePass; }
return this.Validator().checkPassword ();
},
validateUsername: function () {
if (this.options.validateUsername !== null) {
this.Validator().validateUsername = this.options.validateUsername;
}
return this.Validator().checkUsername ();
}
/**
* Since we always have country rendered, we'll use it as a trigger to "validate" other geo-fields
* - basically, we're not validating geo stuff, so this is just a hack
*
*/
,validateCountry: function () {
return validateGeoFields(this.GeoFieldsHelper, this.form());
}
,display: function (id)
{
$ (this.options.container + ' ul li').hide ();
$ (id).show ();
}
,form: function () { return $(this.options.container + ' form'); }
,complete: function () {
var form = this.form ();
if (this.options.disabled) { return false; }
this.disable ();
var data = form.serializeArray ();
var async_original = async.url;
async.url = async.url + '?' + this.appendGA ();
// append geo-position data before dispatching registration request
if (typeof GeoLocationAPI === 'object') {
data = $.extend (data, { geoposition: GeoLocationAPI.data() });
}
// add co-reg-tracking data
if ($('input[name="xrnme"]').length) {
data.push({ name: 'xrnme', value: $('input:hidden[name="xrnme"]').val() });
}
var self = this;
async.request.post ('c=register&a=land&' + $.param (data), null, 1, 1,
function (response) {
self.completeSuccess (response);
},
function (response) {
self.rollback (response);
self.completeError (response);
}
);
async.url = async_original;
return false;
}
,rollback: function (response) {
// placeholder for rollback method, not used actually
if (typeof SecureKeyHelper === 'undefined') {
Lazy.load({ path: 'SecureKeyHelper'});
}
SecureKeyHelper.run();
}
,appendGA: function ()
{
if (typeof (_gat) === 'object') {
var gaTracker = _gat._getTrackerByName ();
var gaLinker = gaTracker._getLinkerUrl ('');
return gaLinker.substring (1);
}
if (typeof(ga) == 'function') {
var uaClientId = null;
ga(function(tracker) { uaClientId = tracker.get('clientId'); });
if (uaClientId) { return '_ga=' + uaClientId; }
}
return '';
}
,completeSuccess: function (response)
{
var self = this;
var review_pending = response.data && response.data['review-pending'] ? response.data['review-pending'] : false;
if (review_pending) {
self.redirectOnComplete(review_pending);
return false;
}
if (isset (response.messages) && isset(response.messages[1])) { $('#btnCompleteInProgress .info').html (response.messages[1]).css ({'background-image': 'none', 'padding-left': '0'}); }
if (isset (response.data)) { setTimeout (function () { self.redirectOnComplete (response.data); }, self.options.successTimeout); }
}
,completeError: function (response)
{
if (isset (response.errors)) {
this.enable ();
// re-enable validator
this.Validator().disabled = false;
}
}
,redirectOnComplete: function (location) {
window.location = location;
}
,disable: function ()
{
$('button.last').attr('disabled', 'disabled').hide ();
this.registrationInProgressAnimation?.show();
this.options.disabled = true;
}
,enable: function ()
{
$('button.last').attr('disabled', false).show ();
this.registrationInProgressAnimation?.hide();
this.options.disabled = false;
},
handleNonRequiredFields: function ()
{
if ($('.not-required-change').length < 1) { return; }
$('.not-required-change').bind ('click', function () {
$('.enter-' + $(this).attr('for') + ' INPUT').removeClass ('entry-not-required');
$(this).parent().remove();
});
}
,stepsHandles: function ()
{
if ($('.stepsHandles').length > 0) {
// todo: disable far-reaching steps
var self = this;
$('.handle', '.stepsHandles').on ('click', function () {
if (!$(this).hasClass ('indicator'))
{
self.step ($('a', $(this)).data ('step-id'));
}
});
}
}
,setActiveStep: function (id)
{
if ($('.stepsHandles').length > 0)
{
this.setCompletedSteps(id);
var classname = 'active';
$('.handle').not('.completed').removeClass(classname);
$('#handle-' + id).addClass (classname);
this.setSlogan (id);
}
}
,setCompletedSteps: function(step) {
var classname = 'completed active';
for (var i = 1; i < step; i++) {
$('#handle-' + i).addClass(classname);
}
}
,setSlogan: function (id) {
$('.slogan', this.options.container).text (this.options.slogans[id] || '');
}
,validEmail: false
,validateEmail: function () {
return this.validEmail ? true : this.Validator().checkEmail ();
}
,appendEmailListener: function ()
{
if (!this.options.liveEmailCheck) { return; }
var self = this;
var element = $('input[name="email"]', this.form()); // target just emails within this specific form(s)
element.on ('change', function () {
self.validEmail = false;
$('#email-error').remove ();
var value = $(this).val ();
if (value) {
async.request.get ('c=utils&a=email&email=' + encodeURIComponent (value), null, null, null, function (response) {
self.validEmail = true;
}, function (response) {
var note = $('
', { id: "email-error", html: response.errors[0] || '' });
note.addClass ('error');
element.after (note);
});
}
});
}
,progressBar: function ()
{
if (typeof ProgressBar !== 'object') { return; }
var Bar = ProgressBar || '';
if (typeof Bar === 'object') {
if ($(Bar.options.container).length > 0) {
Bar.run ();
this.options.matchesTimeout = Bar.getDuration ();
}
}
}
,fixEmailType: function () {
var $element = $('INPUT.enter-email');
if ($element.length > 0) {
$element.prop ('type', 'email');
}
}
,init: function (options)
{
this.setOptions (options);
this.setSteps ();
var self = this;
var form = this.form ();
Lazy.load({ path: 'RegistrationInProgressAnimation.min' });
self.registrationInProgressAnimation = new RegistrationInProgressAnimation({
type: self.options.showInProgressType,
form: form,
text: $(self.options.container).data('text-processing') || 'Processing',
});
this.handleNonRequiredFields ();
this.fixNumberInputs ();
CoRegs.initXRoffer();
this.hashTracking ('');
// Prevention for double click bug
var buttons = form.find('button');
buttons.click(function() {
disabledButtonsAfter(true, 0);
disabledButtonsAfter(false, 500);
});
function disabledButtonsAfter(disabled, time) {
setTimeout(function() { buttons.prop('disabled', disabled); }, time);
}
form.attr ('autocomplete', '');
form.submit (function () {
// return value: "false" prevents execution
var ret = false;
$(self.options.container + ' ul li:visible').each (function () {
var step = parseInt ($(this).data ('step-id') + 1);
if (step <= self.options.lastStep) {
self.step (step);
} else {
if (self.step (step)) { ret = self.complete (); }
}
});
return ret;
});
// GeoFieldsHelper
if (typeof GeoFieldsHelper === 'function') {
this.GeoFieldsHelper = new GeoFieldsHelper({
});
this.GeoFieldsHelper.run();
}
this.stepsHandles ();
this.appendEmailListener ();
this.fixEmailType();
new MatchingGenderHelper().run();
new AffiliatesGendersHelper().run();
}
,Tracking: function (step) {
var self = this;
if (this.options.tracking && typeof(uaSend) === 'function') {
var action = '/register/' + this.options.lastStep + '/' + (step - 1);
$('select,input', '.stepContent:visible').each (function () {
var name = $(this).attr ('name');
var type = $(this).attr ('type') || '';
if (type !== 'hidden' && (name === 'zip' || name === 'city')) {
action += '/';
if (self.getElement (name).attr ('data-replaced')) { action += 'zip-'; }
action += name;
}
});
var gender = $('.radioIam input:checked').parent().text().trim();
// bundle and send pageview data
GA.send ('pageview', $.extend({ page: action }, gender ? { dimension2: gender } : {}));
// Track ga event elements
$('[data-ga-event]').on('click', function() {
RegHelper.sendGaEvent(this.dataset.gaEvent);
});
}
/** GA4 Implementation >>> */
var step_type = '';
$('select,input', '.stepContent:visible').each (function () {
var name = $(this).attr ('name');
var type = $(this).attr ('type') || '';
if (type !== 'hidden') {
if (step_type != '') {
step_type += '-';
}
step_type += name;
}
});
Ga4.send('sign_up_interaction', {
'step_type': step_type,
'step_number': (step - 1),
'total_steps': this.options.lastStep,
});
/** <<< GA4 Implementation */
}
,trackErrors: function (step, name) {
if (this.options.tracking && typeof(uaSend) === 'function' && step && name) {
var eventCategory = '/register/' + this.options.lastStep + '/' + (step - 1);
var value = $('[name="' + name + '"]', this.form()).val();
var eventAction = name + (value ? '-invalid' : '-empty');
var eventLabel = value;
var page = false;
switch (name) {
case 'password':
// no break
case 'email':
var eventLabel = ''; // reset value/eventLabel in case of email, and continue with the rest...
// no break
case 'zip':
// no break
case 'username':
page = [eventCategory, eventAction].join('/');
break;
default:
break;
}
if (page) {
GA.send ('pageview', {'page': page});
GA.send ('event', {'eventCategory': eventCategory, 'eventAction': eventAction, 'eventLabel': eventLabel});
}
Ga4.send('signup_error', {
'message': eventAction
});
}
}
,setSteps: function () {
var steps = $('.stepContent');
steps.each (function (index) {
var id = parseInt (index + 1);
$(this).parent ().attr ('data-step-id', id);
$(this).addClass ('step-content-' + id);
});
this.options.lastStep = steps.length;
this.setLastButton ();
}
,setLastButton: function () {
$('button', '#' + this.options.stepId + this.options.lastStep).addClass ('last');
}
,fixNumberInputs: function () {
$('input[type="number"]', this.form ()).each (function () {
var input = $(this);
var min = parseInt (input.attr('min'));
input.bind ('change', function () {
var value = parseInt (input.val ());
if (value < min) { input.val (min); }
});
});
}
,getCurrentStep: function() {
var step = $(this.options.container).find('[id^=registration-step-]:visible');
return parseInt( step.attr('data-step-id') );
}
,sendGaEvent: function(eventAction) {
var eventCategory = '/register/' + this.options.lastStep + '/' + this.getCurrentStep();
var page = [eventCategory, eventAction].join('/');
GA.send ('pageview', {'page': page});
GA.send ('event', {'eventCategory': eventCategory, 'eventAction': eventAction, 'eventLabel': ''});
}
};
RegHelper = $.extend ({}, Register_Base, RegHelper);
/**
* Google Analytics Helper
*
* @author Zoran Mihailovic
* @type function
*/
var GA = function () {
/**
* Send pageview to GA (universal analytics)
* @author Pawel Miroslawski
* @param {String} event
* @param {Object} args
* @returns {Boolean} bool
*/
var send = function (event, args) {
$.extend (args, { 'hitType': event });
if (typeof (uaSend) == 'function') { uaSend(args); return true; }
return false;
};
return {
send: send
};
}();
/**
* System Detection Helper
*
* @author Zoran Mihailovic
* @type function
*/
var System = function () {
var detected = null;
var detect = function () {
if (!detected) {
var sys = $('html').attr ('class').match (/sys\-(([a-z])\d+)/i) || [];
detected = {
server: sys[1] || ''
,scope: sys[2] || ''
};
}
return detected;
};
var server = function () {
return detect () ? detected.server : '';
};
var scope = function () {
return detect () ? detected.scope : '';
};
return {
server: server,
scope: scope,
get: detect
};
}();
/**
* HP Form helper for rendering genders as a single drop-down menu (X seeking Y)
*/
var GendersSingleDropdownHelper = function (options) {
var params = options || {};
var target = params.target || '[name="genders"]';
var attach = function () {
$(target).on ('change', function () {
var $element = $(this).find (":selected");
var fields = ['gender', 'looking'];
for (var i in fields) {
var name = fields[i];
$('[name="' + name + '"]').val ($element.data (name)).trigger ('change');
}
});
};
var run = function () {
if ($(target).length > 0) {
attach ();
}
};
return {
run: run
};
};
/**
* Affiliates genders helper
* - for default mobile form: draft version
* - listens to affiliate & gender values from request and automagically sets genders
*/
var AffiliatesGendersHelper = function () {
var affiliate, gender, looking;
var genders = {};
var data = $('.ux-genders-data').data('genders') || {};
var relations = $('.ux-genders-data').data('relations') || {};
var collectGenders = function () {
$.each(data, function (key, val) {
genders[data[key].toLowerCase()] = parseInt(key);
});
};
var parseRequest = function () {
affiliate = Url.param('aff_id') || '';
var name = (Url.param('gender') || '').toLowerCase();
// extract gender from gender (literal) or gender_id (numeric)
gender = name
? genders[name]
: (genders[(data[Url.param('gender_id')] || '').toLowerCase()] || false);
if (gender) {
// process looking some day
}
};
var processRequest = function () {
var ELEMENTS = {
gender: gender,
gender_id: gender
};
$.each(ELEMENTS, function (key, gendervalue) {
$('[name="' + key + '"]').filter(function (index, element) {
switch (element.nodeName) {
case 'INPUT':
var $element = $(element);
var type = $element.prop('type');
// special case of "genders" drop-down
$genders = $('[name="genders"]');
// let process this one first if it matches the case
if (type === 'hidden' && $genders.length > 0) {
var looking = relations[gender] || false;
if (gender && looking) {
var value = [gender, looking].join('-');
$target = $('option[value="' + value + '"]', $genders);
if ($target.length > 0) {
$('option', $genders).removeAttr('selected');
$target.attr('selected', true);
$genders.val(value).trigger('change');
// update actual gender & loooking values with reverse values...
$('[name="gender"]').val(gender).trigger('change');
$('[name="looking"]').val(looking).trigger('change');
}
}
} else {
$element.removeAttr('checked');
var value = parseInt($(element).val());
if (value === gendervalue) {
$element.attr('checked', true).trigger('click');
}
}
break;
case 'SELECT':
var gendersArray = Object.values(genders);
if ($.inArray(gendervalue, gendersArray) > -1) {
var $element = $(element);
var $options = $("option", $element);
$options.removeAttr('selected');
$.each($options, function (index, option) {
var $option = $(option);
var value = parseInt($(option).val());
if (value === gendervalue) {
$element.val(gendervalue).attr('selected', true).trigger('change');
}
});
}
break;
default:
break;
}
});
});
};
var enabled = function () {
// var environment = $('BODY').data('environment') || '';
// return $.inArray(environment, ['development', 'staging']) >= 0;
return true;
};
var run = function() {
if (enabled()) {
collectGenders();
parseRequest();
if (affiliate && gender) {
processRequest();
}
}
}
return {
run: run
};
};
/**
* Use genders (radios) as next step buttons based on "autodetection" of next button on given step
*
*/
var GendersButtons = function() {
var bind = function() {
$elements = $('input[type="radio"]', '.genderItem');
if ($elements.length > 0) {
$elements.each(function (index, element) {
var $element = $(element);
var $parent = $element.closest('.stepContent').parent();
var $button = $('button.next', $parent);
if ($button.length === 0) {
var step = parseInt($parent.data('step-id') + 1) || false;
$element.on('click', function (e) {
RegHelper.step(step);
})
}
});
}
};
var run = function() {
bind();
};
return {
run: run
}
};
var MatchingGenderHelper = function (options) {
var settings = $.extend({
container: '#registerMultiStepContainer', // feature scope / container
datasource: '.ux-genders-data', // where's the genders data stored in html
resetOnNoMatch: false // what to do if there's no match/relation for selected gender? leave `looking` value as is by default
}, options);
var $placeholder = $(settings.datasource);
var $container = $(settings.container);
var data = $placeholder.data('genders') || {};
var relations = $placeholder.data('relations') || {};
var getElementByName = function(name) {
return $('[name="' + name + '"]', $container);
};
var sources = ['gender', 'gender_id'];
var targets = ['looking', 'looking_id'];
var bind = function () {
// filter targets
targets = targets.filter(function (value) {
return getElementByName(value).length > 0;
});
$.each(sources, function (index, value) {
var $element = $('[name="' + value + '"]');
if ($element.length > 0) {
var nodeName = $element.prop('nodeName');
switch (nodeName) {
case 'INPUT':
var event = 'click';
var targetHandler = function (targetValue) {
processInputNode(targetValue);
};
break;
case 'SELECT':
// no break
default:
var event = 'change';
var targetHandler = function (targetValue) {
if (targetValue || settings.resetOnNoMatch) {
$.each(targets, function (index, value) {
$target = getElementByName(value);
$target.val(targetValue);
});
}
};
break;
}
if (typeof checkBoxFixer === 'function' && nodeName === 'INPUT') {
$.each($element, function () {
$(this).closest('label').attr('data-match', relations[parseInt($(this).val())] || false);
});
$element.closest('label').on('click', function (i, e) {
var targetValue = $(this).data('match');
processInputNode(targetValue);
});
} else {
$element.on(event, function (e) {
targetHandler(relations[parseInt($(this).val())] || false);
});
}
}
});
};
var processInputNode = function(targetValue, node) {
if (targetValue || settings.resetOnNoMatch) {
$.each(targets, function (index, value) {
$target = getElementByName(value);
$.each($target, function () {
var $this = $(this);
$this.removeAttr('checked');
var value = parseInt($this.val());
if (value === targetValue) {
$this.attr('checked', true);
if (!$this.hasClass('ux-gender-button')) {
$this.trigger('click');
}
}
});
});
}
}
var run = function () {
bind();
};
return {
run: run
};
};
$(function () {
new GendersButtons().run();
});