var EXPO = EXPO || {}; //isolated namespace //общий для всех страниц модуль Функционал общий для всех страниц if (EXPO.common){ console.warn('WARNING: EXPO.common is already defined!'); }else { EXPO.common = (function () { /** * private (visible inside this module only) variables */ /** * @type {Object} - module API interafce realization */ var that = {}; /** * helper for this.children * @param {HTMLElement} el * @param selector * @returns {*} */ var matches = function(el, selector) { return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector); }, $waiter; /** * @type {Object} default setting */ that.opt = {}; //свойства по умолчанию /** * registration and enter login Form validation mechanism * @param {*|jQuery|HTMLElement} obj - particualr form * @constructor */ var Validation = function(obj){ //поля над которыми проводится валидация this.fields = []; //флаг которые опдвтерждает отправку формы. если true то ошибок нет this.allIsClear = false; this.ajaxUrl = obj.getAttribute('action'); this.DOM = obj; this._initFields(); this._eventController(); }; Validation.prototype = { //связывает данные объекта с html кодом _eventController: function () { var self = this; if(this.DOM.addEventListener){ this.DOM.addEventListener("submit", function (event) { self.validate(); event.preventDefault(); return false; }, false); //Modern browsers }else if(this.DOM.attachEvent){ this.DOM.attachEvent('onsubmit', function (event) { self.validate(); event.preventDefault(); return false; }); //Old IE } }, //берет все поля с классом required _initFields: function () { //this.fields = this.DOM.querySelectorAll('.required input'); }, //проводит валидацию, выводит сообщение об ошибках validate: function () { var self = this, formData = $(self.DOM).serialize(), responseData, inputObj ={}, errBoxClass = 'err-message-box', DOMerrBox = self.DOM.querySelector('.'+errBoxClass), errBoxText = DOMerrBox.innerHTML, handler = function (data){ var $succesRegisterModal, mailVal; responseData = data; self.unHighlightFields(); if(responseData.success){ if(DOMerrBox){ EXPO.common.removeClass(DOMerrBox, 'active'); } if($(self.DOM).attr('id') == EXPO.common.opt.registerFormId){ $succesRegisterModal = $('#'+EXPO.common.opt.successRegisterId); mailVal = $.trim($('#id_email',self.DOM).val()); $('.'+EXPO.common.opt.resendLetterClass,$succesRegisterModal).attr('data-email',mailVal); $.fancybox.close(true); $.fancybox('#'+EXPO.common.opt.successRegisterId); }else{ if($(self.DOM).attr('id') == 'log_form'){ dataLayer.push({'event': 'logform'}); } if($(self.DOM).attr('id') == 'end-reg-form'){ dataLayer.push({'event': 'endregform'}); } window.location.reload(); } }else{ EXPO.common.removeClass(DOMerrBox, 'active'); inputObj ={}; self.fields = []; for(var prop in responseData.errors) { if (!responseData.errors.hasOwnProperty(prop)) continue; if(prop != '__all__'){ inputObj ={'name':prop, 'id':'id_'+prop, 'errorText':responseData.errors[prop]}; //inputObj.name = prop; //inputObj.id = 'id_'+prop; //inputObj.errorText = responseData.errors[prop]; self.fields.push(inputObj); }else{ if(DOMerrBox){ EXPO.common.addClass(DOMerrBox, 'active'); if(errBoxText.indexOf(responseData.errors[prop]) < 0) { DOMerrBox.insertAdjacentHTML('beforeend', responseData.errors[prop]+' '); } } } } self.highliteFields(); } $waiter.hide(); }; self.unHighlightFields(); $waiter.show(); EXPO.common.postRequest(formData, self.ajaxUrl,handler); }, //подсвечивает неправильно введенные поля, highliteFields: function () { var DOMfield, DOMfieldWrap; for(var i = 0; i < this.fields.length; i++){ DOMfield = this.DOM.querySelector('#'+ this.fields[i].id); DOMfieldWrap = DOMfield.parentNode; EXPO.common.addClass(DOMfieldWrap,'required'); EXPO.common.addClass(DOMfieldWrap,'err'); } }, unHighlightFields: function () { var DOMfield, DOMfieldWrap; for(var i = 0; i < this.fields.length; i++){ DOMfield = this.DOM.querySelector('#'+ this.fields[i].id); DOMfieldWrap = DOMfield.parentNode; EXPO.common.removeClass(DOMfieldWrap,'required'); EXPO.common.removeClass(DOMfieldWrap,'err'); } }, submit: function () { } }, subscriptionInput = function (width) { $('#id_subscription_country, #id_subscription_theme') .select2({ placeholder: $(this).attr('placeholder'), width: width }); $('#id_subscription_city').select2({ placeholder: $(this).attr('placeholder'), multiple: true, width: width, ajax: { url: "/city/get-city/", dataType: "json", quietMillis: 200, data: function(term, page){ return {term: term, page: page}; }, results: function (data) { var results = []; $.each(data, function(index, item){ results.push({ id: item.id, text: item.label }); }); return {results: results}; } }, initSelection : function(element, callback) { var id= $(element).val(); var text = $(element).attr('data-init-text'); callback({id: id, text:text}); } }); }; //dependences that.forms = []; $(function () { /** * registration and login form validation */ subscriptionInput('100%'); $('form.validate').each(function () { that.forms.push(new Validation(this)); }); /** * simple validation for all type of forms. * require that input is covered by tag */ $('form.simple-validate').on('submit', function(e){ e.preventDefault(); var $form = $(this), url = $form.attr('action'), id = $form.attr('id'), formData = $(this).serialize(), method = $form.attr("method"), callback = function (data) { if (data.success){ if (id == "advertise-form"){ dataLayer.push({'event': 'advertisingform'}); } if (id == "callback-form"){ dataLayer.push({'event': 'callbackform'}); } if (id == "subscribe-form" && data.redirect){ window.location.href = data.redirect_url; return } $.fancybox.close(); $(".error", $form).remove(); $(".required.err", $form).removeClass("required err"); $("input:text", $form).val(''); } else{ // delete previous error messages $(".error", $form).remove(); $(".required.err", $form).removeClass("required err"); $.each(data.errors, function (index, value) { var $input = $("#id_"+index, $form), $error = $("
").attr("class", "error").append(value); $input.parent().addClass('required err').prepend($error); }) } }; if(method == "post"){ $.post(url, formData, callback); }else{ $.get(url, formData, callback); } }); /** * registration form requires a special form of error messages */ // TODO: refactor same code $('form.simple-validate-register').on('submit', function(e){ e.preventDefault(); var $form = $(this), url = $form.attr('action'), formData = $(this).serialize(), method = $form.attr("method"), $succesRegisterModal = $("#pw-reg-complete"), $resend = $(".resend-letter", $succesRegisterModal), mailVal = $.trim($('#id_email',$form).val()), callback = function (data) { if (data.success){ dataLayer.push({'event': 'regform'}); $(".error", $form).remove(); $(".required.err", $form).removeClass("required err"); $("input:text", $form).val(''); $(".pwf-line .msg-help",$form).each(function () { var $this = $(this), defaultT = $this.attr("data-default"); if($.trim(defaultT) != ''){ $this.html('').text(defaultT); } }); $resend.attr('data-email',mailVal); $.fancybox.close(true); $.fancybox('#pw-reg-complete'); } else{ // delete previous error messages $(".error", $form).remove(); $(".required.err", $form).removeClass("required err"); $('.has_error', $form).removeClass('has_error'); $(".pwf-line .msg-help",$form).each(function () { var $this = $(this), defaultT = $this.attr("data-default"); if($.trim(defaultT) != ''){ $this.html('').text(defaultT).hide(); } }); $.each(data.errors, function (index, value) { var $input = $("#id_"+index, $form), $error = $("").attr("class", "error").append(value), $msg = $input.closest(".pwf-line").find(".msg-help"); $input.parent().addClass('required err'); $input.parents('.pwf-line').addClass('has_error'); $msg.attr("data-default", $msg.text()); $msg.text('').prepend($error); $msg.show(); }); } }; if(method == "post"){ $.post(url, formData, callback); }else{ $.get(url, formData, callback); } }); var timer; $('form.simple-validate-register').on('keyup', 'input', function (e) { e.preventDefault(); var $form = $(this).parents('form'); clearTimeout(timer); timer = setTimeout(function () { $.post($form.data('validate-url'), $form.serializeArray(), function (data) { if (data.success){ $form.find('button').prop('disabled', false); $(".error", $form).remove(); $(".required.err", $form).removeClass("required err"); $(".pwf-line .msg-help",$form).each(function () { var $this = $(this), defaultT = $this.attr("data-default"); if($.trim(defaultT) != ''){ $this.html('').text(defaultT); } }); //$resend.attr('data-email',mailVal); // $.fancybox.close(true); // $.fancybox('#pw-reg-complete'); } else{ $form.find('button').prop('disabled', true); // delete previous error messages $(".error", $form).remove(); $(".required.err", $form).removeClass("required err"); $('.has_error', $form).removeClass('has_error'); $(".pwf-line .msg-help",$form).each(function () { var $this = $(this), defaultT = $this.attr("data-default"); if($.trim(defaultT) != ''){ $this.html('').text(defaultT).hide(); } }); $.each(data.errors, function (index, value) { var $input = $("#id_"+index, $form), $error = $("").attr("class", "error").append(value), $msg = $input.closest(".pwf-line").find(".msg-help"); $input.parent().addClass('required err'); $input.parents('.pwf-line').addClass('has_error'); $msg.attr("data-default", $msg.text()); $msg.text('').prepend($error); $msg.show(); }); } }); }, 500); }); }); //private $(function () { /** * $.fancybox bug fix, caused because fancybox is loading near body tag end */ $.fancybox.helpers.overlay.overlay = $('').appendTo('body'); /* Нестандартное оформление для поля checkbox */ $.fn.customRadioCheck = function () { return $(this).each(function () { var $el = $(this); var type = $el.attr("type"); var $label = $el.closest("label"); var $customCheckbox = $el.wrap("").parent(); $label.addClass("custom-radio-check"); function setState () { if (type == 'radio') { var name = $el.attr('name'); var $radios = $('input[type="radio"]').filter('[name="' + name + '"]'); $radios.each(function () { var $container = $(this).closest('.custom-radio'); $container.removeClass('checked'); if ($(this).is(':checked')) { $container.addClass('checked'); } }); } else { if ($el.prop("checked")) { $customCheckbox.addClass("checked"); } else { $customCheckbox.removeClass("checked"); } } $el.trigger('blur'); } setState(); $el.on("change", setState); }); }; $("input[type='checkbox']:not(.default), input[type='radio']").customRadioCheck(); // add to calendar button click event functional //$.fancybox('#pw-reg-complete'); }); /** * very simple (probably in much need of improvement) Jquery plugin I've thrown together that will get you the value of an inline style property */ (function ($) { $.fn.inlineStyle = function (prop) { var styles = this.attr("style"), value; styles && styles.split(";").forEach(function (e) { var style = e.split(":"); if ($.trim(style[0]) === prop) { value = style[1]; } }); return value; }; }(jQuery)); /** * current module general initialization * @param {Object} options - options recieved from web page view */ that.init = function (options) { $.extend(this.opt, options); var self = this, addClass = this.opt.addCalendarClass, remClass = this.opt.removeCalendarClass, addText = this.opt.addCalendarText, remText = this.opt.removeCalendarText, validErrorClass = self.opt.staticValidation.errorClass, validContainerClass = self.opt.staticValidation.containerClass, $staticFields, blobClass = self.opt.staticValidation.blobClass; $(function () { $staticFields = $('.'+validErrorClass); $waiter = $('#wait-ajax:not(.absolute)').css({'z-index': '8031'}); $('body').on('click', '.' + addClass + ', .' + remClass, function(event) { addText = self.opt.addCalendarText; remText = self.opt.removeCalendarText; event.preventDefault(); var $this = $(this); var url = $this.attr('href'); $.get(url, function(data){ if (data.not_authorized){ $.fancybox.open('#'+self.opt.loginModalId); } else{ if(data.success){ if(data.in){ $this.removeClass(addClass).addClass(remClass).text(remText); } else{ $this.removeClass(remClass).addClass(addClass).text(addText); } } } }); }); /** * static validation (non Ajax) on form fields */ if($staticFields.length){ $staticFields.find('input:text').on('keyup', function () { if($.trim($(this).val()) != ''){ $(this).closest('.'+validErrorClass).removeClass(validErrorClass); }else{ $(this).closest('.'+validContainerClass).addClass(validErrorClass); } }) } /** * "http://" placeholder for social profiles form on user and company "edit profiles" pages */ for(var i = 0; i < self.opt.httpFormIds.length; i++){ var $instance = $('#'+self.opt.httpFormIds[i]); if($instance.length){ $('input:text', $instance).on('focus', function () { var $this = $(this), placeholder = self.opt.socialInputMask; if($.trim($this.val()) == ''){ $this.val(placeholder[0]); } }); $('input:text', $instance).on('keypress', function () { var $this = $(this), placeholder = self.opt.socialInputMask; if($.trim($this.val()) == ''){ $this.val(placeholder[0]); } }); $('input:text', $instance).on('blur', function () { var $this = $(this), placeholder = self.opt.socialInputMask; for(var i =0; i< placeholder.length; i++){ if($.trim($this.val()) == placeholder[i]){ $this.val(''); } } }); } } // seohide /** * setup SEOhide params */ $('.'+self.opt.seoLinksClass).each(function () { var hash = $(this).attr('data-hash'), url = $(this).attr('data-url'); EXPO.common.SEOhide.seoHrefs[hash] = url; }); /** * launch algorithm */ EXPO.common.SEOhide.decode(self.opt.dataKey); /** * resend a letter button controller */ $('.'+self.opt.resendLetterClass).on('click', function () { var email = $(this).attr('data-email'), url = self.opt.resendLetterUrl; $waiter.show(); EXPO.common.getRequest({'email':email},url, function (data) { $waiter.hide(); }); return false; }); /** * hide error icon on validated field when it is focused */ $('#'+self.opt.socialFormId).on('focus','.'+self.opt.requiredClass+'.'+self.opt.errorClass+' input:text',function () { $(this).closest('.'+self.opt.errorClass).addClass('disable-inner'); }); $('#'+self.opt.socialFormId).on('blur','.'+self.opt.requiredClass+'.'+self.opt.errorClass+' input:text',function () { $(this).closest('.'+self.opt.errorClass).removeClass('disable-inner'); }); }); //$(window).load(function () { // $waiter.detach().appendTo('body'); //}); }; that.hasClass = function (DOM, className) { if (DOM.classList) return DOM.classList.contains(className); else return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className); }; that.addClass = function (DOM, className) { if (!that.hasClass(DOM, className)) { if (DOM.classList) DOM.classList.add(className); else DOM.className += ' ' + className; } return DOM; }; that.removeClass = function (DOM, className) { var newClass = ' ' + DOM.className.replace(/[\t\r\n]/g, ' ') + ' '; if (that.hasClass(DOM, className)) { if (DOM.classList){ DOM.classList.remove(className); }else{ while (newClass.indexOf( ' ' + className + ' ') >= 0) { newClass = newClass.replace(' ' + className + ' ', ' '); } DOM.className = newClass.replace(/^\s+|\s+$/g, ' '); } } return DOM; }; //Jquery .closest analog for pure js that.closest = function(el, className) { var fn = function(className){ return that.hasClass(el, className); }; while (el) { if (fn(className)) return el; el = el.parentNode; } }; //JQUERY .children alternative ie 9+ that.children = function (elm, sel){ var ret = [], i = 0, l = elm.childNodes.length; for (var i; i < l; ++i){ if (matches(elm.childNodes[i], sel)){ ret.push(elm.childNodes[i]); } } return ret; }; // MEtHOD for make ajax GET Jquery.ajax.request and launch handler if exist or return data that.postRequest = function (dataToSend,url,handler) { if(!dataToSend){ dataToSend = ''; } $.ajax({ type: 'POST', url: url, data:dataToSend, success: function(data) { if(typeof handler == 'function'){ console.log('data recieved:'); console.log(data); console.log(JSON.stringify(data)); handler(data); } else{ return data; } } }); }; that.getRequest = function (dataToSend,url,handler) { if(!dataToSend){ dataToSend = ''; } $.ajax({ type: 'GET', url: url, data:dataToSend, success: function(data) { if(typeof handler == 'function'){ console.log('data recieved:'); console.log(data); console.log(JSON.stringify(data)); handler(data); } else{ return data; } } }); }; /** * prototype of a modal window - general for all * @param options * @constructor */ that.Modal = function (options) { var self = this; this.id; this.opt = options; this.DOMwrap = document.getElementById(options.id); this.DOM = this.DOMwrap.querySelector('.'+ options.wrapClass); $('.modal-close',this.DOM).on('click', function () { self.close(); }); $('.modals > *').on('click', function (ev) { if($(ev.target.parentNode).find(self.DOMwrap).length){ self.close(); } }); }; that.Modal.prototype = { /** * @param {string} selector * @public */ pullData: function (selector) { this.id = selector.substr(1); $(selector).show().siblings().hide(); this.refresh(); }, /** * open and show modal * @public */ open: function () { $(this.DOMwrap).fadeIn(); that.addClass(document.body, 'ov-hidden'); }, /** * close and hide modal window * @public */ close: function () { $(this.DOMwrap).fadeOut(); that.removeClass(document.body, 'ov-hidden'); }, /** * initialize modal window * @public */ refresh: function () { var self = this; self.DOM.style.width = self.opt.size[self.id].width +'px'; self.DOM.style.minHeight = self.opt.size[self.id].height +'px'; self.DOM.style.marginLeft = -(self.opt.size[self.id].width/2)+'px'; self.DOM.style.marginTop = -(self.opt.size[self.id].height/2)+'px'; } }; /** * implementation of well known algorithm SEOhie.js (http://goo.gl/MyuQl9) * hides external links or text from search engines * depends on Base64.js (http://goo.gl/iblGuK) * @public * @type {{seoContent: {}, seoHrefs: {}, decode: Function}} * @prop {object} seoContent - hashes to find proper content to hide * @prop {object} seoHrefs - hashes to find proper links to hide on page * @method decode - decode bas64-code to html */ that.SEOhide = { seoContent:{}, seoHrefs:{}, /** * @param dataKey - key to find hashes */ decode: function (dataKey) { var $elements = $('['+dataKey+']'); for(var i = 0, count = $elements.length; i < count; i++) { var $element = $elements.eq(i); var key = $element.attr("data-hash"); switch($element.data("type")) { case "href": $element.attr("href", Base64.decode(this.seoHrefs[key])); break; case "content": $element.replaceWith(Base64.decode(this.seoContent[key])); break; } } } }; /** * format raw text (for example textarea input data), replaces newline by tag