View file Cool JS v2.6/jcool-2.6.js

File size: 37.89Kb
/*!
 * CoolJS JavaScript Library v2.6
 * https://coolcms.ru/
 * https://vk.com/fastgrid
 *
 * Copyright Dmitry Kokorin
 * Released under the MIT license
 * https://coolcms.ru/license/
 *
 * Documentation: https://coolcms.ru/docs/5-cool_js
 * Date: 2018-01-20T17:24Z
 */

(function (w, d) {
	'use strict';
	if (!d.querySelectorAll) {
		alert('Ваш браузер устарел,пожалуйста,обновите браузер чтобы продолжить работу с сайтом');
		return;
	}

    /*
        префиксы для браузеров

        element.style[getPrefix(property)]
        @property - HTMLElement property
    */
	function getPrefix(a){
        const prefixes = ['Moz', 'Webkit', 'Ms'], div = d.createElement('div');
		let c = a.split('-'),f = '';
		if (c.length > 0) for (let i = 0; i < c.length; ++i) f += c[i].substring(0, 1).toUpperCase() + c[i].substring(1).toLowerCase();
        for(let i=0; i<prefixes.length; ++i){
            let s = prefixes[i] + f, m = prefixes[i] + f.substring(0, 1).toLowerCase() + f.substring(1);
            if (typeof div.style[m] != 'undefined') {
                div.remove();
                return m;
            } else if (typeof div.style[s] != 'undefined') {
                div.remove();
                return s;
            }
        }
        return f.substring(0, 1).toLowerCase() + f.substring(1);
	}

	/*
	    вспомогательная ф-ция для метода fadeIn

        getFadeIn(element)
        @element - HTMLElement
    */
	function getFadeIn(a) {
		let s = a.style,
			ani;
		if (s.display == 'block' && s[getPrefix('opacity')] === 1) return;
		s[getPrefix('opacity')] = 0;
		s.display = 'block';
		ani = requestAnimationFrame(animate);

		function animate() {
			if (s[getPrefix('opacity')] > 1) {
				s[getPrefix('opacity')] = 1;
				cancelAnimationFrame(ani);
			} else {
				s[getPrefix('opacity')] = +s[getPrefix('opacity')] + 0.1;
				cancelAnimationFrame(ani);
				ani = requestAnimationFrame(animate);
			}
		}
		return true;
	}

	/*
	    вспомогательная ф-ция для метода fadeOut

        getFadeOut(element)
        @element - HTMLElement
    */
	function getFadeOut(a) {
		let s = a.style,
			ani;
		if (s.display == 'none' || s[getPrefix('opacity')] === 0) return;
		ani = requestAnimationFrame(animate);

		function animate() {
			if (s[getPrefix('opacity')] < 0) {
				s.display = 'none';
				s[getPrefix('opacity')] = 0;
				cancelAnimationFrame(ani);
			} else {
				s[getPrefix('opacity')] = +s[getPrefix('opacity')] - 0.1;
				cancelAnimationFrame(ani);
				ani = requestAnimationFrame(animate);
			}
		}
		return true;
	}

	/*
	    вспомогательная ф-ция для метода scrollTo

        scroll to element - scrolling.scrollTo(element, duration)
        @element - HTMLElement
        @duration - integer ms

        scroll to position - scrolling.animateScroll(position, duration)
        @position - integer px
        @duration - integer ms
    */
	let scrolling = {
		scrollTo: function (anchor, duration) {
			let scroll = 0;
			do {
				scroll += anchor.offsetTop;
				anchor = anchor.offsetParent;
			} while (anchor);
			scroll = scroll >= 0 ? scroll : 1;
			if (w.event.preventDefault) w.event.preventDefault();
			w.event.returnValue = false;
			duration = duration || null;
			this.animateScroll(scroll, duration);
			return false;
		},
		animateScroll: function (pos, duration) {
			d.documentElement.scrollTop = w.scrollY + 1;
			let element = (d.documentElement && d.documentElement.scrollTop) ? d.documentElement : d.body,
				start = element.scrollTop,
				change = pos - start,
				currentTime = 0,
				increment = 20;
			duration = duration || 1000;
			let animateScroll = function () {
				currentTime += increment;
				let val = Math.easeInOutQuad(currentTime, start, change, duration);
				element.scrollTop = val;
				if (currentTime < duration) setTimeout(animateScroll, increment);
			};
			animateScroll();
		}
	};
	Math.easeInOutQuad = (t, b, c, d) => {
		t /= d / 2;
		if (t < 1) return c / 2 * t * t + b;
		t--;
		return -c / 2 * (t * (t - 2) - 1) + b;
	};

	/* основной класс */
	class App {

	    /*
            Конструктор класса

            @a - string or HTMLCollection
	    */
		constructor(a) {
			this.string = a || null;
			this.isString = typeof this.string == 'string';
			this.isObject = this.string == 'object';
			if(this.isString && /<[a-z]+><\/[a-z]+>/.test(a)){
			    let z=a.match(/[a-z]+/);
			    if (z.length < 1) return;
                this.element = d.createElement(z[0]);
			}else{
                this.element = this.isString ? (a.charAt(0) == '[' ? d.getElementsByName(a.substr(1).slice(0, -1)) : d.querySelectorAll(this.string)) : (this.string || null);
			}
		}

		/*
		    Добавляет класс элементам

		    @a - string class name
		*/
		addClass(a) {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].classList.add(a);
			} else {
				this.element.classList.add(a);
			}
			return this;
		}

		/*
		    Вставляет HTMLElement или HTMLCollection в конец элементов

    		@a - HTMLElement
		*/
		after(a){
			if (this.isString) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].appendChild(a);
			} else {
				this.element.appendChild(a);
			}
			return this;
		}

		/*
    		Вставляет произвольный текст или html-код в конец элементов

    		@a - textContent
		*/
		append(a) {
			if (this.isString) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].innerHTML = this.element[i].innerHTML + a;
			} else {
				this.element.innerHTML = this.element.innerHTML + a;
			}
			return this;
		}

		/*
    		Получает или устанавливает атрибуты элементов

    		@a - property
    		@b - value
		*/
		attr(a, b) {
			b = b || null;
			if (this.isString || this.isObject) {
				if (b) {
					for (let i = 0; i < this.element.length; ++i) this.element[i].setAttribute(a, b);
					return this;
				}
				return this.element[0].getAttribute(a);
			} else {
				return b ? (this.element.setAttribute(a, b), this) : this.element.getAttribute(a);
			}
		}

		/*
		    Вставляет HTMLElement или HTMLCollection в начало элементов

		    @a - HTMLElement
		*/
		before(a){
			if (this.isString) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].insertBefore(a,this.element[i].firstChild);
			} else {
				this.element.insertBefore(a,this.element.firstChild);
			}
			return this;
		}

		/* 
		    Убирает фокус с элемента
		*/
		blur() {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].blur();
			} else {
				this.element.blur();
			}
			return this;
		}

		/*
		    Меняет старый класс на новый у элементов

    		@a - old className
    		@b - new className
		*/
		changeClass(a, b) {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) {
					this.element[i].classList.remove(a);
					this.element[i].classList.add(b);
				}
			} else {
				this.element.classList.remove(a);
				this.element.classList.add(b);
			}
			return this;
		}

		/* 
		    Проверяет, отмечен ли чекбокс или радио-кнопка
		*/
		checked() {
			return (this.isString || this.isObject) ? (this.element[0].getAttribute('checked') == 'checked' ? true : false) : (this.element.getAttribute('checked') == 'checked' ? true : false);
		}

		/* 
		    Собирает дочерние элементы

		    @a - string selector
		    если параметр @a указан, будут найдены элементы с указанным селектором
		*/
		child(a) {
			let b = [];
			if(this.isString || this.isObject){
			    for (let i = 0; i < this.element.length; ++i){
			        let c = a ? this.element[i].querySelectorAll(a) : this.element[i].children;
			        for(let j = 0; j < c.length; ++j) b.push(c[i]);
			    }
			}else{
			    let c = a ? this.element.querySelectorAll(a) : this.element.children;
			    for(let j = 0; j < c.length; ++j) b.push(c[i]);
			}
			this.element = b;
			return this;
		}

		/*
		    Устанавливает css свойства

		    @a - object {property: value, ...}
		*/
		css(a) {
			a = a || {};
			for (let b in a) {
				if (this.isString || this.isObject) {
					for (let i = 0; i < this.element.length; ++i) this.element[i].style[getPrefix(b)] = a[b];
				} else {
					this.element.style[getPrefix(b)] = a[b];
				}
			}
			return this;
		}

		/*
		    Получает значение data-атрибута

		    @a - data-prop
		*/
		data(a) {
			return this.isString ? this.element[0].getAttribute('data-' + a) : this.element.getAttribute('data-' + a);
		}

		/*
    		Перебирает массив

    		@a - array
		*/
		each(a) {
			for (let i = 0; i < this.element.length; ++i) a.apply(this.element[i], arguments);
			return this;
		}

		/* 
		    Очищает содержимое элементов
		*/
		empty() {
			if (this.isString) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].innerHTML = '';
			} else {
				this.element.innerHTML = '';
			}
			return this;
		}

		/* 
		    Плавно показывает скрытые элементы
		*/
		fadeIn() {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) getFadeIn(this.element[i]);
			} else {
				getFadeIn(this.element);
			}
			return this;
		}

		/* 
		    Плавно скрывает элементы
		*/
		fadeOut() {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) getFadeOut(this.element[i]);
			} else {
				getFadeOut(this.element);
			}
			return this;
		}

		/* 
		    Перебирает HTMLInputElement типа file и возвращает массив найденных файлов
		*/
		files() {
			let a = [];
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i)
					for (let j = 0; j < this.element[i].files.length; ++j) a.push(this.element[i].files[j]);
				return a;
			} else {
				for (let i = 0; i < this.element.files; ++i) a.push(this.element.files[i]);
				return a;
			}
		}

		/* 
		    Устанавливает фокус на первый элемент
		*/
		focus() {
			if (this.isString || this.isObject) {
				this.element[0].focus();
			} else {
				this.element.focus();
			}
			return this;
		}

		/*
    		Проверяет наличие класса у элементов

    		@a - string className
    		@b - int index
		*/
		hasClass(a, b) {
		    b = b || 0;
			return (this.isString || this.isObject) ? this.element[b].classList.contains(a) : this.element.classList.contains(a);
		}

		/*
    		Получает или устанавливает высоту элементов

    		@a - int value px
    		@b - int index

    		для window и document высоту можно только получить
		*/
		height(a, b) {
			a = typeof a != 'undefined' ? a : null;
		    b = b || 0;
			if(this.string==w){
			    return w.innerHeight;
			}else if(this.string==d){
			    return d.innerHeight;
			}else if(this.isString || this.isObject){
			    if(a){
			        for(let i=0;i<this.element.length;++i) this.element[i].style.height=a;
			        return this;
			    }else{
			        return this.element[b].scrollHeight;
			    }
			}else{
			    return a?(this.element.style.height=a,this):this.element.scrollHeight;
			}
		}

		/* 
		    Скрывает элементы
		*/
		hide() {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].style.display = 'none';
			} else {
				this.element.style.display = 'none';
			}
			return this;
		}

		/*
		    Получает или устанавливает html-код элемента или произвольный текст

		    @a - textContent or function
    		@b - int index
		*/
		html(a, b) {
			a = typeof a != 'undefined' ? a : null;
		    b = b || 0;
			if (this.isString || this.isObject) {
				if (a) {
					for (let i = 0; i < this.element.length; ++i) this.element[i].innerHTML = typeof a == 'function' ? a() : a;
					return this;
				} else {
					return this.element[b].innerHTML;
				}
			} else {
				if (a) {
					this.element.innerHTML = typeof a == 'function' ? a() : a;
					return this;
				} else {
					return this.element.innerHTML;
				}
			}
		}

		/*
		    Вставляет HTMLElement в начало элемента

		    @a - HTMLElement
		*/
		insertBefore(a){
			if (this.isString) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].parentNode.insertBefore(a,firstChild);
			} else {
				this.element.parentNode.insertBefore(a,firstChild);
			}
			return this;
		}

		/*
		    Вставляет HTMLElement в конец элемента

		    @a - HTMLElement
		*/
		insertAfter(a){
			if (this.isString) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].parentNode.appendChild(a);
			} else {
				this.element.parentNode.appendChild(a);
			}
			return this;
		}

		/*
		    Собирает следующие элементы

		    @a - string className
		    если параметр @a указан будут найдены элементы с заданным селектором
		*/
		next() {
            let b = [];
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i){
                    if(a){
                        let c = this.element[i].parentNode.querySelectorAll(a);
                        for(let j = 0; j < c.length; ++j) if(c[j] == this.element[i].nextElementSibling) b.push(this.element[i].nextElementSibling);
                    }else{
                        b.push(this.element[i].nextElementSibling);
                    }
				}
			} else {
				if(a){
                    let c = this.element.parentNode.querySelectorAll(a);
                    for(let j = 0; j < c.length; ++j) if(c[j] == this.element.nextElementSibling) b.push(this.element.nextElementSibling);
				}else{
                    b.push(this.element.nextElementSibling);
				}
			}
			this.element = b;
			return this;
		}

		/*
		    Отключает обработчик событий

		    @a - event
		    @b - callback function
		*/
		off(a, b) {
			b = typeof b == 'function' ? b : null;
			if (this.isString || this.isObject) {
				let i = 0,
					j = this,
					t = w.setInterval(() => {
						if (i < j.element.length) {
							j.element[i].removeEventListener(a, b);
							++i;
						} else {
							w.clearInterval(t);
						}
					}, 20);
			} else {
				this.element.removeEventListener(a, b);
			}
			return this;
		}

		/* 
		    Получает координаты элемента
		*/
		offset() {
			return (this.isString || this.isObject) ? this.element[0].getBoundingClientRect() : this.element.getBoundingClientRect();
		}

		/*
    		Включает обработчик событий

    		@a - event
    		@b - если параметр @c является функцией - string selector, иначе function
    		@c - function
    		если параметр @c не является функцией или паремтр @b - функция, @c игнорируется

    		$(selector).on('eventName', function(){}) - Для статических элементов
    		$(document).on('eventName', 'selector', function(){}) - Для динамически созданных элементов
		*/
		on(a, b, c) {
			if (typeof c == 'function') {
				d.addEventListener(a, function (e) {
					let elem = d.querySelectorAll(b);
					for (let i = 0; i < elem.length; ++i)
						if (e.target == elem[i]) return c.apply(e.target, arguments);
				}, false);
			} else if (this.isString) {
				let i = 0,
					self = this,
					tmr = setInterval(() => {
						if (i < self.element.length) {
							self.element[i].addEventListener(a, function (e) {
								return b.apply(e.target, arguments);
							}, false);
							++i;
						} else {
							clearInterval(tmr);
						}
					}, 20);
			} else {
				this.string.addEventListener(a, function (e) {
					return b.apply(e.target, arguments);
				}, false);
			}
		}

		/*
		    Получает или изменяет внешний html код элементов

		    @a - string textContent or function
		    @b - int index
		*/
		outerHtml(a, b) {
			a = a || null;
			b = b || 0;
			if (this.isString || this.isObject) {
				if (a) {
					for (let i = 0; i < this.element.length; ++i) this.element[i].outerHTML = typeof a == 'function' ? a() : a;
					return this;
				} else {
					return this.element[b].outerHTML;
				}
			} else {
				if (a) {
					this.element.outerHTML = typeof a == 'function' ? a() : a;
					return this;
				} else {
					return this.element.outerHTML;
				}
			}
		}

		/*
		    Получает родительские элементы

		    @a - string className
		    если параметр @a указан будут найдены элементы с заданным селектором
		*/
		parent(a) {
            b = [];
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i){
                    if(a){
                        let c = this.element[i].parentNode.parentNode.querySelectorAll(a);
                        for(let j = 0; j < c.length; ++j) if(c[j] == this.element[i].parentNode) b.push(this.element[i].parentNode);
                    }else{
                        b.push(this.element[i].parentNode);
                    }
				}
			} else {
				if(a){
                    let c = this.element.parentNode.parentNode.querySelectorAll(a);
                    for(let j = 0; j < c.length; ++j) if(c[j] == this.element.parentNode) b.push(this.element.parentNode);
				}else{
                    b.push(this.element.parentNode);
				}
			}
			this.element = b;
			return this;
		}

		/*
		    Вставляет textContent или html код в начало элементов

		    @a - string textContent
		*/
		prepend(a) {
			if (this.isString) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].innerHTML = a + this.element[i].innerHTML;
			} else {
				this.element.innerHTML = a + this.element.innerHTML;
			}
			return this;
		}

		/*
		    Получает предыдущие элементы

		    @a - string className
		    если параметр @a указан будут найдены элементы с заданным селектором
		*/
		prev(a) {
            let b = [];
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i){
                    if(a){
                        let c = this.element[i].parentNode.querySelectorAll(a);
                        for(let j = 0; j < c.length; ++j) if(c[j] == this.element[i].previousElementSibling) b.push(this.element[i].previousElementSibling);
                    }else{
                        b.push(this.element[i].previousElementSibling);
                    }
				}
			} else {
				if(a){
                    let c = this.element.parentNode.querySelectorAll(a);
                    for(let j = 0; j < c.length; ++j) if(c[j] == this.element.previousElementSibling) b.push(this.element.previousElementSibling);
				}else{
                    b.push(this.element.previousElementSibling);
				}
			}
			this.element = b;
			return this;
		}

		/*
		    Выполняет функцию после загрузки DOM

		    @fn - function
		*/
		ready(fn) {
			if (this.string != d || !fn) return;
			d.addEventListener('DOMContentLoaded', fn, false);
			return true;
		}

		/* 
		    Удаляет элементы
		*/
		remove() {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].remove();
			} else {
				this.element.remove();
			}
			return this;
		}

		/*
		    Удаляет атрибуты элементов

		    @a - string attribute name
		*/
		removeAttr(a) {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].removeAttribute(a);
			} else {
				this.element.removeAttribute(a);
			}
			return this;
		}

		/* @a - string className */
		removeClass(a) {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].classList.remove(a);
			} else {
				this.element.classList.remove(a);
			}
			return this;
		}

		/*
		    Скролл к заданной позиции или к элементу

    		@a - int position or string selector
    		@b - int duration ms
    		@fn - callback function
		*/
		scrollTo(a, b, fn) {
			typeof a == 'number' ? scrolling.animateScroll(a, b) : scrolling.scrollTo(d.querySelector(a), b);
			return typeof fn == 'function' ? fn() : this;
		}

		/* 
		    Подготавливает данные для отправки через URL
		*/
		serialized() {
			let a = (this.isString || this.isObject) ? this.element[0].querySelectorAll('input,select,textarea') : this.element.querySelectorAll('input,select,textarea'),
				b = {};
			for (let i = 0; i < a.length; ++i) {
				if (a[i].type == 'file') {
					for (let j = 0; j < a[i].files.length; ++j) b[a[i].getAttribute('name') + j] = a[i].files[j];
				} else {
					b[a[i].getAttribute('name')] = a[i].value;
				}
			}
			return b;
		}

		/* 
		    Показывает скрытый элемент

            @a - значение свойства display, по умолчанию block
		*/
		show(a) {
			a = a || 'block';
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].style.display = a;
			} else {
				this.element.style.display = a;
			}
			return this;
		}

		/* 
		    Возвращает текущую прокрутку окна в px
		*/
		top() {
			return this.string == w ? w.scrollY : null;
		}

		/* @a - string className */
		toggleClass(a) {
			if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[i].classList.toggle(a);
			} else {
				this.element.classList.toggle(a);
			}
			return this;
		}

		/*
    		Вызывает событие

    		@a - event
    		@b - callback function
		*/
		trigger(a, b) {
			if (typeof a == 'undefined') return;
			if (this.string == w) {
				w.dispatchEvent(new Event(a));
			} else if (this.string == d) {
				d.dispatchEvent(new Event(a));
			} else if (this.isString || this.isObject) {
				for (let i = 0; i < this.element.length; ++i) this.element[0].dispatchEvent(new Event(a));
			} else {
				this.element.dispatchEvent(new Event(a));
			}
			if(typeof b == 'function') b();
			return this;
		}

		/*
		    Получает или устанавливает значение в HTMLInputElement

		    @a - value
		*/
		val(a) {
			a = typeof a != 'undefined' ? a : null;
			if (this.isString || this.isObject) {
				if (a||a==='') {
					for (let i = 0; i < this.element.length; ++i) this.element[i].value = a;
					return true;
				} else {
					return this.element[0].value;
				}
			} else {
				return a||a==='' ? (this.element.value = a, true) : this.element.value;
			}
		}

		/* 
		    Производит валидацию полей
		*/
		validated() {
			let b = (this.element[0] || this.element).querySelectorAll('input,select,textarea'),
				c = 0;
			for (let key in b) {
				if (isFinite(key)) {
					let k = b[key],
						valid = k.validity,
						error = k.getAttribute('error');
					if (k.required) {
						if (k.tagName === 'INPUT') {
							if (k.type === 'number') {
								if (k.min && valid.rangeUnderflow) {
									error = error || 'Минимальное значение поля ' + k.min;
									++c;
								}
								if (k.max && valid.rangeOverflow) {
									error = error || 'Максимальное значение поля ' + k.max;
									++c;
								}
							} else if (k.type === 'tel') {
							    let kv=k.value,kvl=kv.length;
								if ((kvl>7&&(kvl<11||kvl>12))||(kvl===11&&!/^8[8|9]{1}[\d]{2}[\d]{7}$/.test(kv))||(kvl===12&&!/^\+79[\d]{2}[\d]{7}$/.test(kv))){
									error = error || 'Некорректный номер телефона<br>пример: +79123456789,89123456789,88001234567 или 642531';
									++c;
								}
							} else if (k.type === 'email') {
								if (valid.typeDismatch) {
									error = error || 'Некорректный ввод email<br>пример: [email protected]';
									++c;
								}
							}
							if (k.pattern && valid.patternMismatch) {
								error = error || 'Проверьте правильность заполнения полей';
								++c;
							}
							if (valid.typeDismatch) {
								error = error || 'Некорректное значение "' + k.value + '"';
								++c;
							}
						}
						if (valid.valueMissing) {
							error = error || 'Обязательные поля не заполнены';
							++c;
						}
						if (c > 0) {
							d.querySelector('.modal_info').innerHTML = (error || 'Проверьте правильность заполнения полей');
							fn.modal({
								over: null,
								box: '.modal_event',
								close: 3
							});
							return false;
						}
					}
				}
			}
			return true;
		}
	}

	/* вспомогательный класс */
	class Set {

		/*
    		Выполняет Ajax запрос

    		@a - object settings
    		@b and @c - empty, ignored
		*/
		ajax(a, b, c) {
			c = new XMLHttpRequest(), b = {
				type: 'POST',
				url: null,
				success: null,
				json: true,
				error: null,
				files: null,
				callback: null,
				asinc: true,
				data: null
			};
			for (let f in b) b[f] = typeof a[f] != 'undefined' ? a[f] : b[f];
			a = null;
			c.open(b.type, b.url, b.asinc);
			c.onreadystatechange = function () {
				try {
					if (this.readyState !== 4 || this.status !== 200) return;
					if (b.success)
						if (b.json) {
							b.success(JSON.parse(this.responseText));
						} else {
							b.success(this.responseText);
						}
				} catch (e) {
					if (b.error) b.error(e);
				}
			};
			if (b.files) {
				c.send(this.formFiles(b.data));
			} else {
				c.send(this.form(b.data));
			}
			return typeof b.callback == 'function' ? b.callback() : this;
		}

		/*
		    Устанавливает фоновое изображение в элементе @a

    		@a - string selector or HTMLElement or HTMLElementCollection
    		@b - file
		*/
		bgImage(a, b) {
			if (b.type.match(/image.*/)) {
				let reader = new FileReader();
				reader.onload = function (e) {
					$(a).css({'background-image': 'url(' + e.target.result + ')'});
				};
				reader.readAsDataURL(b);
			}
		}

		/*
		    Копирует данные в буфер обмена. Внимание, копирование не будет произведено если для body указано свойство user-select: none

		    @a - string copy data
		*/
		copy(a) {
			if (!a || a == 'undefined') return false;
			let b, c = d.createElement('input');
			c.value = a;
			d.body.append(c);
			c.select();
			if (d.execCommand('copy')) {
				b = true;
			} else {
				b = false;
			}
			w.getSelection().removeAllRanges();
			c.remove();
			localStorage.setItem('clip', a);
			return b;
		}

		/*
		    Инициализирует счетчик чисел от 0 до заданного

		    @a - HTMLElement
		*/
		countPlus(a) {
			let b = {},
				c = 0,
				f = a.dataset;
			b.step = parseFloat(f.count / 100);
			setTimeout(function () {
				b.fn = setInterval(function () {
					if (c + b.step >= parseFloat(f.count)) {
						a.innerHTML = f.count;
						clearInterval(b.fn);
					}
					c += b.step;
					a.innerHTML = parseInt(c);
				}, f.duration / 100);
			}, f.delay);
		}

		/*
    		Собирает данные в объект FormData

    		@a - object data
    		@b - FormData
		*/
		form(a, b) {
			b = b || new FormData();
			for (let key in a)
				if (a.hasOwnProperty(key)) b.append(key, a[key]);
			return b;
		}

		/*
    		Собирает файлы в объект FormData

    		@a - array files
    		@b - FormData
		*/
		formFiles(a, b) {
			b = b || new FormData();
			for (let i = 0; i < a.length; ++i) b.append('file[' + i + ']', a[i]);
			return b;
		}

		/*
    		Создает изображение и добавляет его в конец элемента @a

    		@a - string selector or HTMLElement
    		@b - file
		*/
		image(a, b) {
			if (b.type.match(/image.*/)) {
				let reader = new FileReader();
				reader.onload = function (e) {
					let img = d.createElement('img');
					img.src = e.target.result;
					$(a).after(img);
				};
				reader.readAsDataURL(b);
			}
		}

		/*
    		Создает превью из файлов элемента @a, добавляет их в элемент @c и выводит информацию о файлах в элемент @b

    		@a - HTMLInputElement type file
    		@b - selector text element
    		@c - selector preview element
		*/
		imgPreview(a, b, c) {
			let f = a.files;
			if (f.length) {
				$(c).empty();
				[].forEach.call(f, function (file) {
					if (file.type.match(/image.*/)) {
						let reader = new FileReader();
						reader.onload = function (e) {
							var img = d.createElement('img');
							img.src = e.target.result;
							$(c).after(img);
						};
						reader.readAsDataURL(file);
					}
				});
				$(b).html(f.length == 1 ? f[0].name + ' (' + (f[0].size / 1024).toFixed(2) + ' Кб)' : 'Добавлено ' + f.length + ' файлов');
			} else {
				h.innerHTML('Выберите файл');
				$(c).html('Предпросмотр');
			}
			return this;
		}

		/*
		    Разбирает строку JSON

		    @a - json object
		*/
		json(a) {
			return JSON.parse(a);
		}

		/*
		    Превращает объекты в строку в формате JSON

		    @a - json object
		*/
		jstr(a) {
			return JSON.stringify(a);
		}

		/* 
		    Вывод данных в консоль для отладки
		*/
		log() {
			for (let i = 0; i < arguments.length; ++i) console.info(arguments[i]);
			return this;
		}

		/*
		    Производит манипуляции с модальными окнами

		    @a - object settings
		*/
		modal(a) {
			let b = {
					action: 'open',
					over: '.modal_overlay',
					box: null,
					old: null,
					new: null,
					close: null,
					callback: null
				};
			for (let c in b) b[c] = typeof a[c] != 'undefined' ? a[c] : b[c];
			a = null;
			if (b.action == 'open') {
				if (!b.box) return;
				if (b.over) $(b.over).fadeIn();
				$(b.box).fadeIn();
				if (b.close) {
					setTimeout(() => {
						if (b.over) $(b.over).fadeOut();
						$(b.box).fadeOut();
					}, b.close * 1000);
				}
			} else if (b.action == 'close') {
				$(b.over).fadeOut();
				$('.modal').each(function () {
					if (this.style.display == 'block') $(this).fadeOut();
				});
			} else if (b.action == 'change') {
				if (!b.old || !b.new) return;
				$(b.old).fadeOut();
				$(b.new).fadeIn();
			}
			return typeof b.callback == 'function' ? b.callback() : this;
		}

		/*
    		Имитирует сон скрипта

    		@a - int sleep time ms
    		@fn - callback function
		*/
		sleep(a, fn) {
			setTimeout(fn || function() {}, a);
			return this;
		}

		/*
    		Транслитерация введенных данных (ru => en)

    		@a - string data
    		@b - ignored
		*/
		translite(a, b) {
			let c = typeof b != 'undefined' ? {} : {
				'а': 'a',
				'б': 'b',
				'в': 'v',
				'г': 'g',
				'д': 'd',
				'е': 'e',
				'ж': 'g',
				'з': 'z',
				'и': 'i',
				'й': 'y',
				'к': 'k',
				'л': 'l',
				'м': 'm',
				'н': 'n',
				'о': 'o',
				'п': 'p',
				'р': 'r',
				'с': 's',
				'т': 't',
				'у': 'u',
				'ф': 'f',
				'ы': 'i',
				'э': 'e',
				'А': 'A',
				'Б': 'B',
				'В': 'V',
				'Г': 'G',
				'Д': 'D',
				'Е': 'E',
				'Ж': 'G',
				'З': 'Z',
				'И': 'I',
				'Й': 'Y',
				'К': 'K',
				'Л': 'L',
				'М': 'M',
				'Н': 'N',
				'О': 'O',
				'П': 'P',
				'Р': 'R',
				'С': 'S',
				'Т': 'T',
				'У': 'U',
				'Ф': 'F',
				'Ы': 'I',
				'Э': 'E',
				'ё': 'yo',
				'х': 'h',
				'ц': 'ts',
				'ч': 'ch',
				'ш': 'sh',
				'щ': 'shch',
				'ъ': '',
				'ь': '',
				'ю': 'yu',
				'я': 'ya',
				'Ё': 'YO',
				'Х': 'H',
				'Ц': 'TS',
				'Ч': 'CH',
				'Ш': 'SH',
				'Щ': 'SHCH',
				'Ъ': '',
				'Ь': '',
				'Ю': 'YU',
				'Я': 'YA',
				' ': '_',
				'  ': '_',
				'.': '_',
				'..': '_',
				',': '_',
				'?': '_',
				'??': '_',
				'!': '_',
				'!!': '_',
				'-': '_',
				'--': '_',
				'=': '_',
				'+': '_',
				'__': '_'
			};
			return a.replace(/[\s\S]/g, (x) => {
				if (c.hasOwnProperty(x)) return c[x];
				return x;
			});
		}

		/*
		    Открывает дополнительные вкладки или окна браузера с заданным URL

		    @a - object settings
		*/
		window(a) {
			let b = {
				width: w.screen.width,
				height: w.screen.height,
				url: null,
				x: w.screen.width / 2,
				y: w.screen.height / 2,
				callback: null,
				full: 0,
				tool: 0,
				status: 0,
				menu: 0,
				resize: 0,
				focus: true
			};
			for (let c in b) b[c] = typeof a[c] != 'undefined' ? a[c] : b[c];
			let e = w.open('/', 'White..', 'fullscreen=' + b.full + ',toolbar=' + b.tool + ',status=' + b.status + ',menubar=' + b.menu + ',resizable=' + b.resize + ',width=' + b.width + ',height=' + b.height);
			e.blur();
			if (b.url) e.location.href = b.url;
			e.moveTo(b.x, b.y);
			if (b.focus) e.focus();
			if (typeof b.callback == 'function') b.callback();
			return e;
		}
	}

	/* класс слайдера */
	class Slider {

		/*
		    Инициализация класса

		    @a - string selector or object HTMLCollection
		*/
		constructor(a) {
			this.string = a || null;
			this.box = typeof this.string == 'string' ? d.querySelectorAll(this.string) : (this.string || null);
		}

		/*
		    Инициализация слайдера

		    @a - object settings
		*/
		init(a) {
			if (!this.box.length) return;
			a = a || {};
			let b = {
					delay: 2000,
					dots: true,
					dots_list: [],
					autoplay: true,
					currentSlide: 0,
					interval: null,
					before: null,
					callback: null
				},
				self = this;
			for (let c in b) this[c] = typeof a[c] != 'undefined' ? a[c] : b[c];
			this.slides = d.querySelector(this.string).children;
			this.length = this.slides.length;
			if (this.dots === true) {
				let br = d.createElement('ul');
				br.className = 'slider_dots';
				for (let i = 0; i < this.length; ++i) {
					let brs = d.createElement('li');
					brs.setAttribute('data-slide', i);
					brs.className = 'slider_dot';
					br.appendChild(brs);
				}
				d.querySelector(this.string).parentNode.appendChild(br);
				this.dots_list = d.querySelector('.slider_dots').children;
			}
			this.slides[this.currentSlide].classList.add('slide_active');
			if (this.dots) this.dots_list[this.currentSlide].classList.add('dot_active');
			if (this.autoplay === true) this.start();
			return this;
		}

		/* 
		    Старт автоматического пролистывания
		*/
		start() {
			this.interval = w.setInterval(() => this.next(), this.delay);
		}

		/* 
		    Остановка автоматического пролистывания
		*/
		stop() {
			w.clearInterval(this.interval);
			this.interval = null;
		}

		/* 
		    Переход к предыдущему слайду
		*/
		prev() {
			if (!this.box.length) return;
			this.go(this.currentSlide - 1);
		}

		/* 
		    Переход к следующему слайду
		*/
		next() {
			if (!this.box.length) return;
			this.go(this.currentSlide + 1);
		}

		/*
		    Переход к заданному слайду

		    @n - int need slide
		*/
		go(n) {
			if (!this.box.length) return;
			if (typeof this.before == 'function') this.before();
			this.slides[this.currentSlide].classList.remove('slide_active');
			if (this.dots) this.dots_list[this.currentSlide].classList.remove('dot_active');
			this.currentSlide = parseInt((n + this.length) % this.length);
			this.slides[this.currentSlide].classList.add('slide_active');
			if (this.dots) this.dots_list[this.currentSlide].classList.add('dot_active');
			return typeof this.callback == 'function' ? this.callback() : this;
		}
	}

	/* Инициализация глобальных переменных */
	if(typeof $ != 'undefined'){
	    w.jCool = (a) => new App(a);
	}else{
	    w.$ = (a) => new App(a);
	}
	w.fn = new Set();
	w.sl = (a) => new Slider(a);
})(window, document);

/*!
 * CoolJS JavaScript Library v2.6
 * https://coolcms.ru/
 * https://vk.com/fastgrid
 *
 * Copyright Dmitry Kokorin
 * Released under the MIT license
 * https://coolcms.ru/license/
 *
 * Documentation: https://coolcms.ru/docs/5-cool_js
 * Date: 2018-01-20T17:24Z
 */